Move setting of LD_LIBRARY_PATH closer to invocation of cppunittester
[LibreOffice.git] / canvas / source / tools / surface.cxx
blobc197f6d251a5741bdd3094127bc4f4c347ecee09
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <sal/config.h>
22 #include <basegfx/matrix/b2dhommatrixtools.hxx>
23 #include <basegfx/polygon/b2dpolygonclipper.hxx>
24 #include <comphelper/scopeguard.hxx>
25 #include <utility>
27 #include "surface.hxx"
29 namespace canvas
31 Surface::Surface( PageManagerSharedPtr rPageManager,
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)
43 Surface::~Surface()
45 if(mpFragment)
46 mpPageManager->free(mpFragment);
49 void Surface::setColorBufferDirty()
51 mbIsDirty=true;
54 basegfx::B2DRectangle Surface::getUVCoords() const
56 ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize());
57 ::basegfx::B2IPoint aDestOffset;
58 if( mpFragment )
59 aDestOffset = mpFragment->getPos();
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() );
68 return ::basegfx::B2DRectangle( ox/pw,
69 oy/ph,
70 (ox+sx)/pw,
71 (oy+sy)/ph );
74 basegfx::B2DRectangle Surface::getUVCoords( const ::basegfx::B2IPoint& rPos,
75 const ::basegfx::B2ISize& rSize ) const
77 ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize());
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() );
86 return ::basegfx::B2DRectangle( ox/pw,
87 oy/ph,
88 (ox+sx)/pw,
89 (oy+sy)/ph );
92 bool Surface::draw( double fAlpha,
93 const ::basegfx::B2DPoint& rPos,
94 const ::basegfx::B2DHomMatrix& rTransform )
96 std::shared_ptr<IRenderModule> pRenderModule(mpPageManager->getRenderModule());
98 RenderModuleGuard aGuard( pRenderModule );
100 prepareRendering();
102 // convert size to normalized device coordinates
103 const ::basegfx::B2DRectangle aUV( getUVCoords() );
105 const double u1(aUV.getMinX());
106 const double v1(aUV.getMinY());
107 const double u2(aUV.getMaxX());
108 const double v2(aUV.getMaxY());
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
117 basegfx::B2DHomMatrix aTransform(basegfx::utils::createTranslateB2DHomMatrix(
118 maSourceOffset.getX(), maSourceOffset.getY()));
119 aTransform = aTransform * rTransform;
120 aTransform.translate(rPos);
123 ######################################
124 ######################################
125 ######################################
130 2 | 3
131 x------------x
132 | | |
133 | | |
134 ------|-----O------|------>X
135 -1 | | | +1
136 | | |
137 x------------x
138 1 | 0
142 ######################################
143 ######################################
144 ######################################
147 const ::basegfx::B2DPoint p0(aTransform * ::basegfx::B2DPoint(maSize.getWidth(),maSize.getHeight()));
148 const ::basegfx::B2DPoint p1(aTransform * ::basegfx::B2DPoint(0.0,maSize.getHeight()));
149 const ::basegfx::B2DPoint p2(aTransform * ::basegfx::B2DPoint(0.0,0.0));
150 const ::basegfx::B2DPoint p3(aTransform * ::basegfx::B2DPoint(maSize.getWidth(),0.0));
152 canvas::Vertex vertex;
153 vertex.r = 1.0f;
154 vertex.g = 1.0f;
155 vertex.b = 1.0f;
156 vertex.a = static_cast<float>(fAlpha);
157 vertex.z = 0.0f;
160 pRenderModule->beginPrimitive( canvas::IRenderModule::PrimitiveType::Quad );
162 // issue an endPrimitive() when leaving the scope
163 const ::comphelper::ScopeGuard aScopeGuard(
164 [&pRenderModule]() mutable { pRenderModule->endPrimitive(); } );
166 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2);
167 vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY());
168 pRenderModule->pushVertex(vertex);
170 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2);
171 vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY());
172 pRenderModule->pushVertex(vertex);
174 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1);
175 vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY());
176 pRenderModule->pushVertex(vertex);
178 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1);
179 vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY());
180 pRenderModule->pushVertex(vertex);
183 return !(pRenderModule->isError());
186 bool Surface::drawRectangularArea(
187 double fAlpha,
188 const ::basegfx::B2DPoint& rPos,
189 const ::basegfx::B2DRectangle& rArea,
190 const ::basegfx::B2DHomMatrix& rTransform )
192 if( rArea.isEmpty() )
193 return true; // immediate exit for empty area
195 std::shared_ptr<IRenderModule> pRenderModule(mpPageManager->getRenderModule());
197 RenderModuleGuard aGuard( pRenderModule );
199 prepareRendering();
201 // these positions are relative to the texture
202 ::basegfx::B2IPoint aPos1(
203 ::basegfx::fround(rArea.getMinimum().getX()),
204 ::basegfx::fround(rArea.getMinimum().getY()));
205 ::basegfx::B2IPoint aPos2(
206 ::basegfx::fround(rArea.getMaximum().getX()),
207 ::basegfx::fround(rArea.getMaximum().getY()) );
209 // clip the positions to the area this surface covers
210 aPos1.setX(std::max(aPos1.getX(), maSourceOffset.getX()));
211 aPos1.setY(std::max(aPos1.getY(), maSourceOffset.getY()));
212 aPos2.setX(std::min(aPos2.getX(), maSourceOffset.getX() + maSize.getWidth()));
213 aPos2.setY(std::min(aPos2.getY(), maSourceOffset.getY() + maSize.getHeight()));
215 // if the resulting area is empty, return immediately
216 ::basegfx::B2IVector aSize(aPos2 - aPos1);
217 if(aSize.getX() <= 0 || aSize.getY() <= 0)
218 return true;
220 ::basegfx::B2IPoint aDestOffset;
221 if( mpFragment )
222 aDestOffset = mpFragment->getPos();
224 // convert size to normalized device coordinates
225 const ::basegfx::B2DRectangle aUV(
226 getUVCoords(aPos1 - maSourceOffset + aDestOffset,
227 basegfx::B2ISize(aSize.getX(), aSize.getY())) );
228 const double u1(aUV.getMinX());
229 const double v1(aUV.getMinY());
230 const double u2(aUV.getMaxX());
231 const double v2(aUV.getMaxY());
233 // concatenate transforms
234 // 1) offset of surface subarea
235 // 2) surface transform
236 // 3) translation to output position [rPos]
237 basegfx::B2DHomMatrix aTransform(basegfx::utils::createTranslateB2DHomMatrix(aPos1.getX(), aPos1.getY()));
238 aTransform = aTransform * rTransform;
239 aTransform.translate(rPos);
243 ######################################
244 ######################################
245 ######################################
250 2 | 3
251 x------------x
252 | | |
253 | | |
254 ------|-----O------|------>X
255 -1 | | | +1
256 | | |
257 x------------x
258 1 | 0
262 ######################################
263 ######################################
264 ######################################
267 const ::basegfx::B2DPoint p0(aTransform * ::basegfx::B2DPoint(aSize.getX(),aSize.getY()));
268 const ::basegfx::B2DPoint p1(aTransform * ::basegfx::B2DPoint(0.0, aSize.getY()));
269 const ::basegfx::B2DPoint p2(aTransform * ::basegfx::B2DPoint(0.0, 0.0));
270 const ::basegfx::B2DPoint p3(aTransform * ::basegfx::B2DPoint(aSize.getX(),0.0));
272 canvas::Vertex vertex;
273 vertex.r = 1.0f;
274 vertex.g = 1.0f;
275 vertex.b = 1.0f;
276 vertex.a = static_cast<float>(fAlpha);
277 vertex.z = 0.0f;
280 pRenderModule->beginPrimitive( canvas::IRenderModule::PrimitiveType::Quad );
282 // issue an endPrimitive() when leaving the scope
283 const ::comphelper::ScopeGuard aScopeGuard(
284 [&pRenderModule]() mutable { pRenderModule->endPrimitive(); } );
286 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2);
287 vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY());
288 pRenderModule->pushVertex(vertex);
290 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2);
291 vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY());
292 pRenderModule->pushVertex(vertex);
294 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1);
295 vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY());
296 pRenderModule->pushVertex(vertex);
298 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1);
299 vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY());
300 pRenderModule->pushVertex(vertex);
303 return !(pRenderModule->isError());
306 bool Surface::drawWithClip( double fAlpha,
307 const ::basegfx::B2DPoint& rPos,
308 const ::basegfx::B2DPolygon& rClipPoly,
309 const ::basegfx::B2DHomMatrix& rTransform )
311 std::shared_ptr<IRenderModule> pRenderModule(mpPageManager->getRenderModule());
313 RenderModuleGuard aGuard( pRenderModule );
315 prepareRendering();
317 // untransformed surface rectangle, relative to the whole
318 // image (note: this surface might actually only be a tile of
319 // the whole image, with non-zero maSourceOffset)
320 const double x1(maSourceOffset.getX());
321 const double y1(maSourceOffset.getY());
322 const double w(maSize.getWidth());
323 const double h(maSize.getHeight());
324 const double x2(x1+w);
325 const double y2(y1+h);
326 const ::basegfx::B2DRectangle aSurfaceClipRect(x1,y1,x2,y2);
328 // concatenate transforms
329 // we use 'fround' here to avoid rounding errors. the vertices will
330 // be transformed by the overall transform and uv coordinates will
331 // be calculated from the result, and this is why we need to use
332 // integer coordinates here...
333 basegfx::B2DHomMatrix aTransform = rTransform;
334 aTransform.translate(rPos);
337 ######################################
338 ######################################
339 ######################################
344 2 | 3
345 x------------x
346 | | |
347 | | |
348 ------|-----O------|------>X
349 -1 | | | +1
350 | | |
351 x------------x
352 1 | 0
356 ######################################
357 ######################################
358 ######################################
361 // uv coordinates that map the surface rectangle
362 // to the destination rectangle.
363 const ::basegfx::B2DRectangle aUV( getUVCoords() );
365 basegfx::B2DPolygon rTriangleList(basegfx::utils::clipTriangleListOnRange(rClipPoly,
366 aSurfaceClipRect));
368 // Push vertices to backend renderer
369 if(const sal_uInt32 nVertexCount = rTriangleList.count())
371 canvas::Vertex vertex;
372 vertex.r = 1.0f;
373 vertex.g = 1.0f;
374 vertex.b = 1.0f;
375 vertex.a = static_cast<float>(fAlpha);
376 vertex.z = 0.0f;
378 pRenderModule->beginPrimitive( canvas::IRenderModule::PrimitiveType::Triangle );
380 // issue an endPrimitive() when leaving the scope
381 const ::comphelper::ScopeGuard aScopeGuard(
382 [&pRenderModule]() mutable { pRenderModule->endPrimitive(); } );
384 for(sal_uInt32 nIndex=0; nIndex<nVertexCount; ++nIndex)
386 const basegfx::B2DPoint &aPoint = rTriangleList.getB2DPoint(nIndex);
387 basegfx::B2DPoint aTransformedPoint(aTransform * aPoint);
388 const double tu(((aPoint.getX()-aSurfaceClipRect.getMinX())*aUV.getWidth()/w)+aUV.getMinX());
389 const double tv(((aPoint.getY()-aSurfaceClipRect.getMinY())*aUV.getHeight()/h)+aUV.getMinY());
390 vertex.u=static_cast<float>(tu);
391 vertex.v=static_cast<float>(tv);
392 vertex.x=static_cast<float>(aTransformedPoint.getX());
393 vertex.y=static_cast<float>(aTransformedPoint.getY());
394 pRenderModule->pushVertex(vertex);
398 return !(pRenderModule->isError());
401 void Surface::prepareRendering()
403 mpPageManager->validatePages();
405 // clients requested to draw from this surface, therefore one
406 // of the above implemented concrete rendering operations
407 // was triggered. we therefore need to ask the pagemanager
408 // to allocate some space for the fragment we're dedicated to.
409 if(!mpFragment)
411 mpFragment = mpPageManager->allocateSpace(maSize);
412 if( mpFragment )
414 mpFragment->setColorBuffer(mpColorBuffer);
415 mpFragment->setSourceOffset(maSourceOffset);
419 if( mpFragment )
421 // now we need to 'select' the fragment, which will in turn
422 // pull information from the image on demand.
423 // in case this fragment is still not located on any of the
424 // available pages ['naked'], we force the page manager to
425 // do it now, no way to defer this any longer...
426 if(!(mpFragment->select(mbIsDirty)))
427 mpPageManager->nakedFragment(mpFragment);
430 mbIsDirty=false;
434 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */