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 
26 #include "surface.hxx"
27 
28 namespace canvas
29 {
30  Surface::Surface( const PageManagerSharedPtr& rPageManager,
31  const std::shared_ptr<IColorBuffer>& rColorBuffer,
32  const ::basegfx::B2IPoint& rPos,
33  const ::basegfx::B2ISize& rSize ) :
34  mpColorBuffer(rColorBuffer),
35  mpPageManager(rPageManager),
36  mpFragment(),
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
203  ::basegfx::B2IPoint aPos1(
204  ::basegfx::fround(rArea.getMinimum().getX()),
205  ::basegfx::fround(rArea.getMinimum().getY()));
206  ::basegfx::B2IPoint aPos2(
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: */
sal_Int32 nIndex
PageManagerSharedPtr mpPageManager
Definition: surface.hxx:115
std::shared_ptr< IColorBuffer > mpColorBuffer
Definition: surface.hxx:111
basegfx::B2DRectangle getUVCoords() const
Definition: surface.cxx:54
::basegfx::B2ISize maSize
Definition: surface.hxx:129
void setY(sal_Int32 fY)
void setColorBufferDirty()
Definition: surface.cxx:49
double getX() const
#define max(a, b)
Definition: dx_winstuff.hxx:46
::basegfx::B2IPoint maSourceOffset
Definition: surface.hxx:123
double getY() const
#define min(a, b)
Definition: dx_winstuff.hxx:49
bool draw(double fAlpha, const ::basegfx::B2DPoint &rPos, const ::basegfx::B2DHomMatrix &rTransform)
Render the surface content to screen.
Definition: surface.cxx:92
B2IRange fround(const B2DRange &rRange)
std::shared_ptr< PageManager > PageManagerSharedPtr
Definition: pagemanager.hxx:73
sal_Int32 getX() const
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:308
sal_Int32 w
B2DPolygon clipTriangleListOnRange(const B2DPolygon &rCandidate, const B2DRange &rRange)
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:187
PageManagerSharedPtr mpPageManager
FragmentSharedPtr mpFragment
Definition: surface.hxx:117
Surface(const PageManagerSharedPtr &rPageManager, const std::shared_ptr< IColorBuffer > &rColorBuffer, const ::basegfx::B2IPoint &rPos, const ::basegfx::B2ISize &rSize)
Definition: surface.cxx:30
void prepareRendering()
Definition: surface.cxx:404
Little RAII wrapper for guarding access to IRenderModule interface.
sal_Int32 getY() const
void translate(double fX, double fY)
void setX(sal_Int32 fX)
B2DHomMatrix createTranslateB2DHomMatrix(double fTranslateX, double fTranslateY)
sal_Int32 h
::basegfx::B2IVector maSize
Definition: dx_9rm.cxx:116
sal_uInt32 count() const
basegfx::B2DPoint const & getB2DPoint(sal_uInt32 nIndex) const