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.getX() );
62 const double ph( aPageSize.getY() );
63 const double ox( aDestOffset.getX() );
64 const double oy( aDestOffset.getY() );
65 const double sx( maSize.getX() );
66 const double sy( maSize.getY() );
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.getX() );
80 const double ph( aPageSize.getY() );
81 const double ox( rPos.getX() );
82 const double oy( rPos.getY() );
83 const double sx( rSize.getX() );
84 const double sy( rSize.getY() );
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.getX(),maSize.getY()));
149 const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0,maSize.getY()));
150 const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0,0.0));
151 const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(maSize.getX(),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.getX()));
214 aPos2.setY(std::min(aPos2.getY(),maSourceOffset.getY()+maSize.getY()));
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 aSize) );
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.getX());
325 const double h(maSize.getY());
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 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::B2IVector 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