LibreOffice Module canvas (master) 1
surface.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 */
19
20#include <sal/config.h>
21
25#include <utility>
26
27#include "surface.hxx"
28
29namespace canvas
30{
32 std::shared_ptr<IColorBuffer> xColorBuffer,
33 const ::basegfx::B2IPoint& rPos,
34 const ::basegfx::B2ISize& rSize ) :
35 mpColorBuffer(std::move(xColorBuffer)),
36 mpPageManager(std::move(rPageManager)),
37 maSourceOffset(rPos),
38 maSize(rSize),
39 mbIsDirty(true)
40 {
41 }
42
44 {
45 if(mpFragment)
47 }
48
50 {
51 mbIsDirty=true;
52 }
53
55 {
56 ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize());
57 ::basegfx::B2IPoint aDestOffset;
58 if( mpFragment )
59 aDestOffset = mpFragment->getPos();
60
61 const double pw( aPageSize.getWidth() );
62 const double ph( aPageSize.getHeight() );
63 const double ox( aDestOffset.getX() );
64 const double oy( aDestOffset.getY() );
65 const double sx( maSize.getWidth() );
66 const double sy( maSize.getHeight() );
67
68 return ::basegfx::B2DRectangle( ox/pw,
69 oy/ph,
70 (ox+sx)/pw,
71 (oy+sy)/ph );
72 }
73
74 basegfx::B2DRectangle Surface::getUVCoords( const ::basegfx::B2IPoint& rPos,
75 const ::basegfx::B2ISize& rSize ) const
76 {
77 ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize());
78
79 const double pw( aPageSize.getWidth() );
80 const double ph( aPageSize.getHeight() );
81 const double ox( rPos.getX() );
82 const double oy( rPos.getY() );
83 const double sx( rSize.getWidth() );
84 const double sy( rSize.getHeight() );
85
86 return ::basegfx::B2DRectangle( ox/pw,
87 oy/ph,
88 (ox+sx)/pw,
89 (oy+sy)/ph );
90 }
91
92 bool Surface::draw( double fAlpha,
93 const ::basegfx::B2DPoint& rPos,
94 const ::basegfx::B2DHomMatrix& rTransform )
95 {
96 std::shared_ptr<IRenderModule> pRenderModule(mpPageManager->getRenderModule());
97
98 RenderModuleGuard aGuard( pRenderModule );
99
101
102 // convert size to normalized device coordinates
103 const ::basegfx::B2DRectangle& rUV( getUVCoords() );
104
105 const double u1(rUV.getMinX());
106 const double v1(rUV.getMinY());
107 const double u2(rUV.getMaxX());
108 const double v2(rUV.getMaxY());
109
110 // concat transforms
111 // 1) offset of surface subarea
112 // 2) surface transform
113 // 3) translation to output position [rPos]
114 // 4) scale to normalized device coordinates
115 // 5) flip y-axis
116 // 6) translate to account for viewport transform
119 aTransform = aTransform * rTransform;
120 aTransform.translate(::basegfx::fround(rPos.getX()),
121 ::basegfx::fround(rPos.getY()));
122
123 /*
124 ######################################
125 ######################################
126 ######################################
127
128 Y
129 ^+1
130 |
131 2 | 3
132 x------------x
133 | | |
134 | | |
135 ------|-----O------|------>X
136 -1 | | | +1
137 | | |
138 x------------x
139 1 | 0
140 |
141 |-1
142
143 ######################################
144 ######################################
145 ######################################
146 */
147
148 const ::basegfx::B2DPoint& p0(aTransform * ::basegfx::B2DPoint(maSize.getWidth(),maSize.getHeight()));
149 const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0,maSize.getHeight()));
150 const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0,0.0));
151 const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(maSize.getWidth(),0.0));
152
153 canvas::Vertex vertex;
154 vertex.r = 1.0f;
155 vertex.g = 1.0f;
156 vertex.b = 1.0f;
157 vertex.a = static_cast<float>(fAlpha);
158 vertex.z = 0.0f;
159
160 {
161 pRenderModule->beginPrimitive( canvas::IRenderModule::PrimitiveType::Quad );
162
163 // issue an endPrimitive() when leaving the scope
164 const ::comphelper::ScopeGuard aScopeGuard(
165 [&pRenderModule]() mutable { pRenderModule->endPrimitive(); } );
166
167 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2);
168 vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY());
169 pRenderModule->pushVertex(vertex);
170
171 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2);
172 vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY());
173 pRenderModule->pushVertex(vertex);
174
175 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1);
176 vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY());
177 pRenderModule->pushVertex(vertex);
178
179 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1);
180 vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY());
181 pRenderModule->pushVertex(vertex);
182 }
183
184 return !(pRenderModule->isError());
185 }
186
188 double fAlpha,
189 const ::basegfx::B2DPoint& rPos,
190 const ::basegfx::B2DRectangle& rArea,
191 const ::basegfx::B2DHomMatrix& rTransform )
192 {
193 if( rArea.isEmpty() )
194 return true; // immediate exit for empty area
195
196 std::shared_ptr<IRenderModule> pRenderModule(mpPageManager->getRenderModule());
197
198 RenderModuleGuard aGuard( pRenderModule );
199
201
202 // these positions are relative to the texture
204 ::basegfx::fround(rArea.getMinimum().getX()),
205 ::basegfx::fround(rArea.getMinimum().getY()));
207 ::basegfx::fround(rArea.getMaximum().getX()),
208 ::basegfx::fround(rArea.getMaximum().getY()) );
209
210 // clip the positions to the area this surface covers
211 aPos1.setX(std::max(aPos1.getX(), maSourceOffset.getX()));
212 aPos1.setY(std::max(aPos1.getY(), maSourceOffset.getY()));
213 aPos2.setX(std::min(aPos2.getX(), maSourceOffset.getX() + maSize.getWidth()));
214 aPos2.setY(std::min(aPos2.getY(), maSourceOffset.getY() + maSize.getHeight()));
215
216 // if the resulting area is empty, return immediately
217 ::basegfx::B2IVector aSize(aPos2 - aPos1);
218 if(aSize.getX() <= 0 || aSize.getY() <= 0)
219 return true;
220
221 ::basegfx::B2IPoint aDestOffset;
222 if( mpFragment )
223 aDestOffset = mpFragment->getPos();
224
225 // convert size to normalized device coordinates
226 const ::basegfx::B2DRectangle& rUV(
227 getUVCoords(aPos1 - maSourceOffset + aDestOffset,
228 basegfx::B2ISize(aSize.getX(), aSize.getY())) );
229 const double u1(rUV.getMinX());
230 const double v1(rUV.getMinY());
231 const double u2(rUV.getMaxX());
232 const double v2(rUV.getMaxY());
233
234 // concatenate transforms
235 // 1) offset of surface subarea
236 // 2) surface transform
237 // 3) translation to output position [rPos]
239 aTransform = aTransform * rTransform;
240 aTransform.translate(::basegfx::fround(rPos.getX()),
241 ::basegfx::fround(rPos.getY()));
242
243
244 /*
245 ######################################
246 ######################################
247 ######################################
248
249 Y
250 ^+1
251 |
252 2 | 3
253 x------------x
254 | | |
255 | | |
256 ------|-----O------|------>X
257 -1 | | | +1
258 | | |
259 x------------x
260 1 | 0
261 |
262 |-1
263
264 ######################################
265 ######################################
266 ######################################
267 */
268
269 const ::basegfx::B2DPoint& p0(aTransform * ::basegfx::B2DPoint(aSize.getX(),aSize.getY()));
270 const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0, aSize.getY()));
271 const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0, 0.0));
272 const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(aSize.getX(),0.0));
273
274 canvas::Vertex vertex;
275 vertex.r = 1.0f;
276 vertex.g = 1.0f;
277 vertex.b = 1.0f;
278 vertex.a = static_cast<float>(fAlpha);
279 vertex.z = 0.0f;
280
281 {
282 pRenderModule->beginPrimitive( canvas::IRenderModule::PrimitiveType::Quad );
283
284 // issue an endPrimitive() when leaving the scope
285 const ::comphelper::ScopeGuard aScopeGuard(
286 [&pRenderModule]() mutable { pRenderModule->endPrimitive(); } );
287
288 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2);
289 vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY());
290 pRenderModule->pushVertex(vertex);
291
292 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2);
293 vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY());
294 pRenderModule->pushVertex(vertex);
295
296 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1);
297 vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY());
298 pRenderModule->pushVertex(vertex);
299
300 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1);
301 vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY());
302 pRenderModule->pushVertex(vertex);
303 }
304
305 return !(pRenderModule->isError());
306 }
307
308 bool Surface::drawWithClip( double fAlpha,
309 const ::basegfx::B2DPoint& rPos,
310 const ::basegfx::B2DPolygon& rClipPoly,
311 const ::basegfx::B2DHomMatrix& rTransform )
312 {
313 std::shared_ptr<IRenderModule> pRenderModule(mpPageManager->getRenderModule());
314
315 RenderModuleGuard aGuard( pRenderModule );
316
318
319 // untransformed surface rectangle, relative to the whole
320 // image (note: this surface might actually only be a tile of
321 // the whole image, with non-zero maSourceOffset)
322 const double x1(maSourceOffset.getX());
323 const double y1(maSourceOffset.getY());
324 const double w(maSize.getWidth());
325 const double h(maSize.getHeight());
326 const double x2(x1+w);
327 const double y2(y1+h);
328 const ::basegfx::B2DRectangle aSurfaceClipRect(x1,y1,x2,y2);
329
330 // concatenate transforms
331 // we use 'fround' here to avoid rounding errors. the vertices will
332 // be transformed by the overall transform and uv coordinates will
333 // be calculated from the result, and this is why we need to use
334 // integer coordinates here...
335 basegfx::B2DHomMatrix aTransform = rTransform;
336 aTransform.translate(::basegfx::fround(rPos.getX()),
337 ::basegfx::fround(rPos.getY()));
338
339 /*
340 ######################################
341 ######################################
342 ######################################
343
344 Y
345 ^+1
346 |
347 2 | 3
348 x------------x
349 | | |
350 | | |
351 ------|-----O------|------>X
352 -1 | | | +1
353 | | |
354 x------------x
355 1 | 0
356 |
357 |-1
358
359 ######################################
360 ######################################
361 ######################################
362 */
363
364 // uv coordinates that map the surface rectangle
365 // to the destination rectangle.
366 const ::basegfx::B2DRectangle& rUV( getUVCoords() );
367
369 aSurfaceClipRect));
370
371 // Push vertices to backend renderer
372 if(const sal_uInt32 nVertexCount = rTriangleList.count())
373 {
374 canvas::Vertex vertex;
375 vertex.r = 1.0f;
376 vertex.g = 1.0f;
377 vertex.b = 1.0f;
378 vertex.a = static_cast<float>(fAlpha);
379 vertex.z = 0.0f;
380
381 pRenderModule->beginPrimitive( canvas::IRenderModule::PrimitiveType::Triangle );
382
383 // issue an endPrimitive() when leaving the scope
384 const ::comphelper::ScopeGuard aScopeGuard(
385 [&pRenderModule]() mutable { pRenderModule->endPrimitive(); } );
386
387 for(sal_uInt32 nIndex=0; nIndex<nVertexCount; ++nIndex)
388 {
389 const basegfx::B2DPoint &aPoint = rTriangleList.getB2DPoint(nIndex);
390 basegfx::B2DPoint aTransformedPoint(aTransform * aPoint);
391 const double tu(((aPoint.getX()-aSurfaceClipRect.getMinX())*rUV.getWidth()/w)+rUV.getMinX());
392 const double tv(((aPoint.getY()-aSurfaceClipRect.getMinY())*rUV.getHeight()/h)+rUV.getMinY());
393 vertex.u=static_cast<float>(tu);
394 vertex.v=static_cast<float>(tv);
395 vertex.x=static_cast<float>(aTransformedPoint.getX());
396 vertex.y=static_cast<float>(aTransformedPoint.getY());
397 pRenderModule->pushVertex(vertex);
398 }
399 }
400
401 return !(pRenderModule->isError());
402 }
403
405 {
406 mpPageManager->validatePages();
407
408 // clients requested to draw from this surface, therefore one
409 // of the above implemented concrete rendering operations
410 // was triggered. we therefore need to ask the pagemanager
411 // to allocate some space for the fragment we're dedicated to.
412 if(!mpFragment)
413 {
414 mpFragment = mpPageManager->allocateSpace(maSize);
415 if( mpFragment )
416 {
417 mpFragment->setColorBuffer(mpColorBuffer);
418 mpFragment->setSourceOffset(maSourceOffset);
419 }
420 }
421
422 if( mpFragment )
423 {
424 // now we need to 'select' the fragment, which will in turn
425 // pull information from the image on demand.
426 // in case this fragment is still not located on any of the
427 // available pages ['naked'], we force the page manager to
428 // do it now, no way to defer this any longer...
429 if(!(mpFragment->select(mbIsDirty)))
430 mpPageManager->nakedFragment(mpFragment);
431
432 }
433 mbIsDirty=false;
434 }
435}
436
437/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
void translate(double fX, double fY)
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const
sal_uInt32 count() const
TYPE getWidth() const
TYPE getHeight() const
TYPE getX() const
void setY(TYPE fY)
TYPE getY() const
void setX(TYPE fX)
Little RAII wrapper for guarding access to IRenderModule interface.
void setColorBufferDirty()
Definition: surface.cxx:49
Surface(PageManagerSharedPtr xPageManager, std::shared_ptr< IColorBuffer > xColorBuffer, const ::basegfx::B2IPoint &rPos, const ::basegfx::B2ISize &rSize)
Definition: surface.cxx:31
bool drawRectangularArea(double fAlpha, const ::basegfx::B2DPoint &rPos, const ::basegfx::B2DRectangle &rArea, const ::basegfx::B2DHomMatrix &rTransform)
Render the surface content to screen.
Definition: surface.cxx:184
PageManagerSharedPtr mpPageManager
Definition: surface.hxx:114
std::shared_ptr< IColorBuffer > mpColorBuffer
Definition: surface.hxx:110
basegfx::B2DRectangle getUVCoords() const
Definition: surface.cxx:54
::basegfx::B2IPoint maSourceOffset
Definition: surface.hxx:122
::basegfx::B2ISize maSize
Definition: surface.hxx:128
void prepareRendering()
Definition: surface.cxx:395
bool drawWithClip(double fAlpha, const ::basegfx::B2DPoint &rPos, const ::basegfx::B2DPolygon &rClipPoly, const ::basegfx::B2DHomMatrix &rTransform)
Render the surface content to screen.
Definition: surface.cxx:302
FragmentSharedPtr mpFragment
Definition: surface.hxx:116
bool draw(double fAlpha, const ::basegfx::B2DPoint &rPos, const ::basegfx::B2DHomMatrix &rTransform)
Render the surface content to screen.
Definition: surface.cxx:92
::basegfx::B2ISize maSize
Definition: dx_9rm.cxx:116
#define max(a, b)
Definition: dx_winstuff.hxx:43
sal_Int32 nIndex
B2DPolygon clipTriangleListOnRange(const B2DPolygon &rCandidate, const B2DRange &rRange)
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
std::shared_ptr< PageManager > PageManagerSharedPtr
Definition: pagemanager.hxx:73
sal_Int32 h
sal_Int32 w
PageManagerSharedPtr mpPageManager