Branch data Line data Source code
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 : :
21 : : #include "surface.hxx"
22 : : #include <basegfx/polygon/b2dpolygonclipper.hxx>
23 : : #include <basegfx/matrix/b2dhommatrixtools.hxx>
24 : : #include <comphelper/scopeguard.hxx>
25 : : #include <boost/bind.hpp>
26 : :
27 : : namespace canvas
28 : : {
29 : :
30 : : //////////////////////////////////////////////////////////////////////////////////
31 : : // Surface::Surface
32 : : //////////////////////////////////////////////////////////////////////////////////
33 : :
34 : 0 : Surface::Surface( const PageManagerSharedPtr& rPageManager,
35 : : const IColorBufferSharedPtr& rColorBuffer,
36 : : const ::basegfx::B2IPoint& rPos,
37 : : const ::basegfx::B2ISize& rSize ) :
38 : : mpColorBuffer(rColorBuffer),
39 : : mpPageManager(rPageManager),
40 : : mpFragment(),
41 : : maSourceOffset(rPos),
42 : : maSize(rSize),
43 [ # # ][ # # ]: 0 : mbIsDirty(true)
44 : : {
45 : 0 : }
46 : :
47 : : //////////////////////////////////////////////////////////////////////////////////
48 : : // Surface::~Surface
49 : : //////////////////////////////////////////////////////////////////////////////////
50 : :
51 [ # # ][ # # ]: 0 : Surface::~Surface()
52 : : {
53 [ # # ]: 0 : if(mpFragment)
54 [ # # ]: 0 : mpPageManager->free(mpFragment);
55 : 0 : }
56 : :
57 : : //////////////////////////////////////////////////////////////////////////////////
58 : : // Surface::getUVCoords
59 : : //////////////////////////////////////////////////////////////////////////////////
60 : :
61 : 0 : void Surface::setColorBufferDirty()
62 : : {
63 : 0 : mbIsDirty=true;
64 : 0 : }
65 : :
66 : : //////////////////////////////////////////////////////////////////////////////////
67 : : // Surface::getUVCoords
68 : : //////////////////////////////////////////////////////////////////////////////////
69 : :
70 : 0 : basegfx::B2DRectangle Surface::getUVCoords() const
71 : : {
72 [ # # ]: 0 : ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize());
73 : 0 : ::basegfx::B2IPoint aDestOffset;
74 [ # # ]: 0 : if( mpFragment )
75 [ # # ]: 0 : aDestOffset = mpFragment->getPos();
76 : :
77 : 0 : const double pw( aPageSize.getX() );
78 : 0 : const double ph( aPageSize.getY() );
79 : 0 : const double ox( aDestOffset.getX() );
80 : 0 : const double oy( aDestOffset.getY() );
81 : 0 : const double sx( maSize.getX() );
82 : 0 : const double sy( maSize.getY() );
83 : :
84 : : return ::basegfx::B2DRectangle( ox/pw,
85 : : oy/ph,
86 : : (ox+sx)/pw,
87 [ # # ]: 0 : (oy+sy)/ph );
88 : : }
89 : :
90 : : //////////////////////////////////////////////////////////////////////////////////
91 : : // Surface::getUVCoords
92 : : //////////////////////////////////////////////////////////////////////////////////
93 : :
94 : 0 : basegfx::B2DRectangle Surface::getUVCoords( const ::basegfx::B2IPoint& rPos,
95 : : const ::basegfx::B2ISize& rSize ) const
96 : : {
97 [ # # ]: 0 : ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize());
98 : :
99 : 0 : const double pw( aPageSize.getX() );
100 : 0 : const double ph( aPageSize.getY() );
101 : 0 : const double ox( rPos.getX() );
102 : 0 : const double oy( rPos.getY() );
103 : 0 : const double sx( rSize.getX() );
104 : 0 : const double sy( rSize.getY() );
105 : :
106 : : return ::basegfx::B2DRectangle( ox/pw,
107 : : oy/ph,
108 : : (ox+sx)/pw,
109 [ # # ]: 0 : (oy+sy)/ph );
110 : : }
111 : :
112 : : //////////////////////////////////////////////////////////////////////////////////
113 : : // Surface::draw
114 : : //////////////////////////////////////////////////////////////////////////////////
115 : :
116 : 0 : bool Surface::draw( double fAlpha,
117 : : const ::basegfx::B2DPoint& rPos,
118 : : const ::basegfx::B2DHomMatrix& rTransform )
119 : : {
120 [ # # ]: 0 : IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule());
121 : :
122 [ # # ]: 0 : RenderModuleGuard aGuard( pRenderModule );
123 : :
124 [ # # ]: 0 : prepareRendering();
125 : :
126 : : // convert size to normalized device coordinates
127 [ # # ]: 0 : const ::basegfx::B2DRectangle& rUV( getUVCoords() );
128 : :
129 [ # # ]: 0 : const double u1(rUV.getMinX());
130 [ # # ]: 0 : const double v1(rUV.getMinY());
131 [ # # ]: 0 : const double u2(rUV.getMaxX());
132 [ # # ]: 0 : const double v2(rUV.getMaxY());
133 : :
134 : : // concat transforms
135 : : // 1) offset of surface subarea
136 : : // 2) surface transform
137 : : // 3) translation to output position [rPos]
138 : : // 4) scale to normalized device coordinates
139 : : // 5) flip y-axis
140 : : // 6) translate to account for viewport transform
141 : : basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(
142 [ # # ]: 0 : maSourceOffset.getX(), maSourceOffset.getY()));
143 [ # # ][ # # ]: 0 : aTransform = aTransform * rTransform;
[ # # ]
144 : 0 : aTransform.translate(::basegfx::fround(rPos.getX()),
145 [ # # ]: 0 : ::basegfx::fround(rPos.getY()));
146 : :
147 : : /*
148 : : ######################################
149 : : ######################################
150 : : ######################################
151 : :
152 : : Y
153 : : ^+1
154 : : |
155 : : 2 | 3
156 : : x------------x
157 : : | | |
158 : : | | |
159 : : ------|-----O------|------>X
160 : : -1 | | | +1
161 : : | | |
162 : : x------------x
163 : : 1 | 0
164 : : |
165 : : |-1
166 : :
167 : : ######################################
168 : : ######################################
169 : : ######################################
170 : : */
171 : :
172 [ # # ]: 0 : const ::basegfx::B2DPoint& p0(aTransform * ::basegfx::B2DPoint(maSize.getX(),maSize.getY()));
173 [ # # ]: 0 : const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0,maSize.getY()));
174 [ # # ]: 0 : const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0,0.0));
175 [ # # ]: 0 : const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(maSize.getX(),0.0));
176 : :
177 : : canvas::Vertex vertex;
178 : 0 : vertex.r = 1.0f;
179 : 0 : vertex.g = 1.0f;
180 : 0 : vertex.b = 1.0f;
181 : 0 : vertex.a = static_cast<float>(fAlpha);
182 : 0 : vertex.z = 0.0f;
183 : :
184 : : {
185 [ # # ]: 0 : pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_QUAD );
186 : :
187 : : // issue an endPrimitive() when leaving the scope
188 : : const ::comphelper::ScopeGuard aScopeGuard(
189 : : boost::bind( &::canvas::IRenderModule::endPrimitive,
190 [ # # ][ # # ]: 0 : ::boost::ref(pRenderModule) ) );
[ # # ]
191 : :
192 : 0 : vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2);
193 : 0 : vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY());
194 [ # # ]: 0 : pRenderModule->pushVertex(vertex);
195 : :
196 : 0 : vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2);
197 : 0 : vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY());
198 [ # # ]: 0 : pRenderModule->pushVertex(vertex);
199 : :
200 : 0 : vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1);
201 : 0 : vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY());
202 [ # # ]: 0 : pRenderModule->pushVertex(vertex);
203 : :
204 : 0 : vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1);
205 : 0 : vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY());
206 [ # # ][ # # ]: 0 : pRenderModule->pushVertex(vertex);
207 : : }
208 : :
209 [ # # ][ # # ]: 0 : return !(pRenderModule->isError());
[ # # ][ # # ]
210 : : }
211 : :
212 : : //////////////////////////////////////////////////////////////////////////////////
213 : : // Surface::drawRectangularArea
214 : : //////////////////////////////////////////////////////////////////////////////////
215 : :
216 : 0 : bool Surface::drawRectangularArea(
217 : : double fAlpha,
218 : : const ::basegfx::B2DPoint& rPos,
219 : : const ::basegfx::B2DRectangle& rArea,
220 : : const ::basegfx::B2DHomMatrix& rTransform )
221 : : {
222 [ # # ][ # # ]: 0 : if( rArea.isEmpty() )
223 : 0 : return true; // immediate exit for empty area
224 : :
225 [ # # ]: 0 : IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule());
226 : :
227 [ # # ]: 0 : RenderModuleGuard aGuard( pRenderModule );
228 : :
229 [ # # ]: 0 : prepareRendering();
230 : :
231 : : // these positions are relative to the texture
232 : : ::basegfx::B2IPoint aPos1(
233 : : ::basegfx::fround(rArea.getMinimum().getX()),
234 [ # # ][ # # ]: 0 : ::basegfx::fround(rArea.getMinimum().getY()));
235 : : ::basegfx::B2IPoint aPos2(
236 : : ::basegfx::fround(rArea.getMaximum().getX()),
237 [ # # ][ # # ]: 0 : ::basegfx::fround(rArea.getMaximum().getY()) );
238 : :
239 : : // clip the positions to the area this surface covers
240 [ # # ]: 0 : aPos1.setX(::std::max(aPos1.getX(),maSourceOffset.getX()));
241 [ # # ]: 0 : aPos1.setY(::std::max(aPos1.getY(),maSourceOffset.getY()));
242 [ # # ]: 0 : aPos2.setX(::std::min(aPos2.getX(),maSourceOffset.getX()+maSize.getX()));
243 [ # # ]: 0 : aPos2.setY(::std::min(aPos2.getY(),maSourceOffset.getY()+maSize.getY()));
244 : :
245 : : // if the resulting area is empty, return immediately
246 [ # # ]: 0 : ::basegfx::B2IVector aSize(aPos2 - aPos1);
247 [ # # ][ # # ]: 0 : if(aSize.getX() <= 0 || aSize.getY() <= 0)
[ # # ]
248 : 0 : return true;
249 : :
250 : 0 : ::basegfx::B2IPoint aDestOffset;
251 [ # # ]: 0 : if( mpFragment )
252 [ # # ]: 0 : aDestOffset = mpFragment->getPos();
253 : :
254 : : // convert size to normalized device coordinates
255 : : const ::basegfx::B2DRectangle& rUV(
256 : : getUVCoords(aPos1 - maSourceOffset + aDestOffset,
257 [ # # ][ # # ]: 0 : aSize) );
[ # # ]
258 [ # # ]: 0 : const double u1(rUV.getMinX());
259 [ # # ]: 0 : const double v1(rUV.getMinY());
260 [ # # ]: 0 : const double u2(rUV.getMaxX());
261 [ # # ]: 0 : const double v2(rUV.getMaxY());
262 : :
263 : : // concatenate transforms
264 : : // 1) offset of surface subarea
265 : : // 2) surface transform
266 : : // 3) translation to output position [rPos]
267 [ # # ]: 0 : basegfx::B2DHomMatrix aTransform(basegfx::tools::createTranslateB2DHomMatrix(aPos1.getX(), aPos1.getY()));
268 [ # # ][ # # ]: 0 : aTransform = aTransform * rTransform;
[ # # ]
269 : 0 : aTransform.translate(::basegfx::fround(rPos.getX()),
270 [ # # ]: 0 : ::basegfx::fround(rPos.getY()));
271 : :
272 : :
273 : : /*
274 : : ######################################
275 : : ######################################
276 : : ######################################
277 : :
278 : : Y
279 : : ^+1
280 : : |
281 : : 2 | 3
282 : : x------------x
283 : : | | |
284 : : | | |
285 : : ------|-----O------|------>X
286 : : -1 | | | +1
287 : : | | |
288 : : x------------x
289 : : 1 | 0
290 : : |
291 : : |-1
292 : :
293 : : ######################################
294 : : ######################################
295 : : ######################################
296 : : */
297 : :
298 [ # # ]: 0 : const ::basegfx::B2DPoint& p0(aTransform * ::basegfx::B2DPoint(aSize.getX(),aSize.getY()));
299 [ # # ]: 0 : const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0, aSize.getY()));
300 [ # # ]: 0 : const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0, 0.0));
301 [ # # ]: 0 : const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(aSize.getX(),0.0));
302 : :
303 : : canvas::Vertex vertex;
304 : 0 : vertex.r = 1.0f;
305 : 0 : vertex.g = 1.0f;
306 : 0 : vertex.b = 1.0f;
307 : 0 : vertex.a = static_cast<float>(fAlpha);
308 : 0 : vertex.z = 0.0f;
309 : :
310 : : {
311 [ # # ]: 0 : pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_QUAD );
312 : :
313 : : // issue an endPrimitive() when leaving the scope
314 : : const ::comphelper::ScopeGuard aScopeGuard(
315 : : boost::bind( &::canvas::IRenderModule::endPrimitive,
316 [ # # ][ # # ]: 0 : ::boost::ref(pRenderModule) ) );
[ # # ]
317 : :
318 : 0 : vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2);
319 : 0 : vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY());
320 [ # # ]: 0 : pRenderModule->pushVertex(vertex);
321 : :
322 : 0 : vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2);
323 : 0 : vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY());
324 [ # # ]: 0 : pRenderModule->pushVertex(vertex);
325 : :
326 : 0 : vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1);
327 : 0 : vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY());
328 [ # # ]: 0 : pRenderModule->pushVertex(vertex);
329 : :
330 : 0 : vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1);
331 : 0 : vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY());
332 [ # # ][ # # ]: 0 : pRenderModule->pushVertex(vertex);
333 : : }
334 : :
335 [ # # ][ # # ]: 0 : return !(pRenderModule->isError());
[ # # ][ # # ]
336 : : }
337 : :
338 : : //////////////////////////////////////////////////////////////////////////////////
339 : : // Surface::drawWithClip
340 : : //////////////////////////////////////////////////////////////////////////////////
341 : :
342 : 0 : bool Surface::drawWithClip( double fAlpha,
343 : : const ::basegfx::B2DPoint& rPos,
344 : : const ::basegfx::B2DPolygon& rClipPoly,
345 : : const ::basegfx::B2DHomMatrix& rTransform )
346 : : {
347 [ # # ]: 0 : IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule());
348 : :
349 [ # # ]: 0 : RenderModuleGuard aGuard( pRenderModule );
350 : :
351 [ # # ]: 0 : prepareRendering();
352 : :
353 : : // untransformed surface rectangle, relative to the whole
354 : : // image (note: this surface might actually only be a tile of
355 : : // the whole image, with non-zero maSourceOffset)
356 : 0 : const double x1(maSourceOffset.getX());
357 : 0 : const double y1(maSourceOffset.getY());
358 : 0 : const double w(maSize.getX());
359 : 0 : const double h(maSize.getY());
360 : 0 : const double x2(x1+w);
361 : 0 : const double y2(y1+h);
362 [ # # ]: 0 : const ::basegfx::B2DRectangle aSurfaceClipRect(x1,y1,x2,y2);
363 : :
364 : : // concatenate transforms
365 : : // we use 'fround' here to avoid rounding errors. the vertices will
366 : : // be transformed by the overall transform and uv coordinates will
367 : : // be calculated from the result, and this is why we need to use
368 : : // integer coordinates here...
369 [ # # ]: 0 : basegfx::B2DHomMatrix aTransform;
370 [ # # ][ # # ]: 0 : aTransform = aTransform * rTransform;
[ # # ]
371 : 0 : aTransform.translate(::basegfx::fround(rPos.getX()),
372 [ # # ]: 0 : ::basegfx::fround(rPos.getY()));
373 : :
374 : : /*
375 : : ######################################
376 : : ######################################
377 : : ######################################
378 : :
379 : : Y
380 : : ^+1
381 : : |
382 : : 2 | 3
383 : : x------------x
384 : : | | |
385 : : | | |
386 : : ------|-----O------|------>X
387 : : -1 | | | +1
388 : : | | |
389 : : x------------x
390 : : 1 | 0
391 : : |
392 : : |-1
393 : :
394 : : ######################################
395 : : ######################################
396 : : ######################################
397 : : */
398 : :
399 : : // uv coordinates that map the surface rectangle
400 : : // to the destination rectangle.
401 [ # # ]: 0 : const ::basegfx::B2DRectangle& rUV( getUVCoords() );
402 : :
403 : : basegfx::B2DPolygon rTriangleList(basegfx::tools::clipTriangleListOnRange(rClipPoly,
404 [ # # ]: 0 : aSurfaceClipRect));
405 : :
406 : : // Push vertices to backend renderer
407 [ # # ][ # # ]: 0 : if(const sal_uInt32 nVertexCount = rTriangleList.count())
408 : : {
409 : : canvas::Vertex vertex;
410 : 0 : vertex.r = 1.0f;
411 : 0 : vertex.g = 1.0f;
412 : 0 : vertex.b = 1.0f;
413 : 0 : vertex.a = static_cast<float>(fAlpha);
414 : 0 : vertex.z = 0.0f;
415 : :
416 : : #if defined(TRIANGLE_LOG) && defined(DBG_UTIL)
417 : : OSL_TRACE( "Surface::draw(): numvertices %d numtriangles %d\n",
418 : : nVertexCount,
419 : : nVertexCount/3 );
420 : : #endif
421 : :
422 [ # # ]: 0 : pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_TRIANGLE );
423 : :
424 : : // issue an endPrimitive() when leaving the scope
425 : : const ::comphelper::ScopeGuard aScopeGuard(
426 : : boost::bind( &::canvas::IRenderModule::endPrimitive,
427 [ # # ][ # # ]: 0 : ::boost::ref(pRenderModule) ) );
[ # # ]
428 : :
429 [ # # ]: 0 : for(sal_uInt32 nIndex=0; nIndex<nVertexCount; ++nIndex)
430 : : {
431 [ # # ]: 0 : const basegfx::B2DPoint &aPoint = rTriangleList.getB2DPoint(nIndex);
432 [ # # ]: 0 : basegfx::B2DPoint aTransformedPoint(aTransform * aPoint);
433 [ # # ][ # # ]: 0 : const double tu(((aPoint.getX()-aSurfaceClipRect.getMinX())*rUV.getWidth()/w)+rUV.getMinX());
[ # # ]
434 [ # # ][ # # ]: 0 : const double tv(((aPoint.getY()-aSurfaceClipRect.getMinY())*rUV.getHeight()/h)+rUV.getMinY());
[ # # ]
435 : 0 : vertex.u=static_cast<float>(tu);
436 : 0 : vertex.v=static_cast<float>(tv);
437 : 0 : vertex.x=static_cast<float>(aTransformedPoint.getX());
438 : 0 : vertex.y=static_cast<float>(aTransformedPoint.getY());
439 [ # # ]: 0 : pRenderModule->pushVertex(vertex);
440 [ # # ]: 0 : }
441 : : }
442 : :
443 [ # # ][ # # ]: 0 : return !(pRenderModule->isError());
[ # # ][ # # ]
[ # # ]
444 : : }
445 : :
446 : : //////////////////////////////////////////////////////////////////////////////////
447 : : // Surface::prepareRendering
448 : : //////////////////////////////////////////////////////////////////////////////////
449 : :
450 : 0 : void Surface::prepareRendering()
451 : : {
452 : 0 : mpPageManager->validatePages();
453 : :
454 : : // clients requested to draw from this surface, therefore one
455 : : // of the above implemented concrete rendering operations
456 : : // was triggered. we therefore need to ask the pagemanager
457 : : // to allocate some space for the fragment we're dedicated to.
458 [ # # ]: 0 : if(!(mpFragment))
459 : : {
460 [ # # ]: 0 : mpFragment = mpPageManager->allocateSpace(maSize);
461 [ # # ]: 0 : if( mpFragment )
462 : : {
463 : 0 : mpFragment->setColorBuffer(mpColorBuffer);
464 : 0 : mpFragment->setSourceOffset(maSourceOffset);
465 : : }
466 : : }
467 : :
468 [ # # ]: 0 : if( mpFragment )
469 : : {
470 : : // now we need to 'select' the fragment, which will in turn
471 : : // pull informations from the image on demand.
472 : : // in case this fragment is still not located on any of the
473 : : // available pages ['naked'], we force the page manager to
474 : : // do it now, no way to defer this any longer...
475 [ # # ]: 0 : if(!(mpFragment->select(mbIsDirty)))
476 : 0 : mpPageManager->nakedFragment(mpFragment);
477 : :
478 : : }
479 : 0 : mbIsDirty=false;
480 : 0 : }
481 [ + - ][ + - ]: 861 : }
482 : :
483 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|