merge the formfield patch from ooo-build
[ooovba.git] / canvas / source / tools / surface.cxx
blobea18d99991af742a26108cf13bf78a840b470651
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: surface.cxx,v $
10 * $Revision: 1.6.16.1 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_canvas.hxx"
34 #include "surface.hxx"
35 #include <basegfx/polygon/b2dpolygonclipper.hxx>
36 #include <comphelper/scopeguard.hxx>
37 #include <boost/bind.hpp>
39 namespace canvas
42 //////////////////////////////////////////////////////////////////////////////////
43 // Surface::Surface
44 //////////////////////////////////////////////////////////////////////////////////
46 Surface::Surface( const PageManagerSharedPtr& rPageManager,
47 const IColorBufferSharedPtr& rColorBuffer,
48 const ::basegfx::B2IPoint& rPos,
49 const ::basegfx::B2ISize& rSize ) :
50 mpColorBuffer(rColorBuffer),
51 mpPageManager(rPageManager),
52 mpFragment(),
53 maSourceOffset(rPos),
54 maSize(rSize),
55 mbIsDirty(true)
59 //////////////////////////////////////////////////////////////////////////////////
60 // Surface::~Surface
61 //////////////////////////////////////////////////////////////////////////////////
63 Surface::~Surface()
65 if(mpFragment)
66 mpPageManager->free(mpFragment);
69 //////////////////////////////////////////////////////////////////////////////////
70 // Surface::getUVCoords
71 //////////////////////////////////////////////////////////////////////////////////
73 void Surface::setColorBufferDirty()
75 mbIsDirty=true;
78 //////////////////////////////////////////////////////////////////////////////////
79 // Surface::getUVCoords
80 //////////////////////////////////////////////////////////////////////////////////
82 basegfx::B2DRectangle Surface::getUVCoords() const
84 ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize());
85 ::basegfx::B2IPoint aDestOffset;
86 if( mpFragment )
87 aDestOffset = mpFragment->getPos();
89 const double pw( aPageSize.getX() );
90 const double ph( aPageSize.getY() );
91 const double ox( aDestOffset.getX() );
92 const double oy( aDestOffset.getY() );
93 const double sx( maSize.getX() );
94 const double sy( maSize.getY() );
96 return ::basegfx::B2DRectangle( ox/pw,
97 oy/ph,
98 (ox+sx)/pw,
99 (oy+sy)/ph );
102 //////////////////////////////////////////////////////////////////////////////////
103 // Surface::getUVCoords
104 //////////////////////////////////////////////////////////////////////////////////
106 basegfx::B2DRectangle Surface::getUVCoords( const ::basegfx::B2IPoint& rPos,
107 const ::basegfx::B2ISize& rSize ) const
109 ::basegfx::B2ISize aPageSize(mpPageManager->getPageSize());
111 const double pw( aPageSize.getX() );
112 const double ph( aPageSize.getY() );
113 const double ox( rPos.getX() );
114 const double oy( rPos.getY() );
115 const double sx( rSize.getX() );
116 const double sy( rSize.getY() );
118 return ::basegfx::B2DRectangle( ox/pw,
119 oy/ph,
120 (ox+sx)/pw,
121 (oy+sy)/ph );
124 //////////////////////////////////////////////////////////////////////////////////
125 // Surface::draw
126 //////////////////////////////////////////////////////////////////////////////////
128 bool Surface::draw( double fAlpha,
129 const ::basegfx::B2DPoint& rPos,
130 const ::basegfx::B2DHomMatrix& rTransform )
132 IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule());
134 RenderModuleGuard aGuard( pRenderModule );
136 prepareRendering();
138 // convert size to normalized device coordinates
139 const ::basegfx::B2DRectangle& rUV( getUVCoords() );
141 const double u1(rUV.getMinX());
142 const double v1(rUV.getMinY());
143 const double u2(rUV.getMaxX());
144 const double v2(rUV.getMaxY());
146 // concat transforms
147 // 1) offset of surface subarea
148 // 2) surface transform
149 // 3) translation to output position [rPos]
150 // 4) scale to normalized device coordinates
151 // 5) flip y-axis
152 // 6) translate to account for viewport transform
153 ::basegfx::B2DHomMatrix aTransform;
154 aTransform.translate(maSourceOffset.getX(),
155 maSourceOffset.getY());
156 aTransform = aTransform * rTransform;
157 aTransform.translate(::basegfx::fround(rPos.getX()),
158 ::basegfx::fround(rPos.getY()));
161 ######################################
162 ######################################
163 ######################################
168 2 | 3
169 x------------x
170 | | |
171 | | |
172 ------|-----O------|------>X
173 -1 | | | +1
174 | | |
175 x------------x
176 1 | 0
180 ######################################
181 ######################################
182 ######################################
185 const ::basegfx::B2DPoint& p0(aTransform * ::basegfx::B2DPoint(maSize.getX(),maSize.getY()));
186 const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0,maSize.getY()));
187 const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0,0.0));
188 const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(maSize.getX(),0.0));
190 canvas::Vertex vertex;
191 vertex.r = 1.0f;
192 vertex.g = 1.0f;
193 vertex.b = 1.0f;
194 vertex.a = static_cast<float>(fAlpha);
195 vertex.z = 0.0f;
198 pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_QUAD );
200 // issue an endPrimitive() when leaving the scope
201 const ::comphelper::ScopeGuard aScopeGuard(
202 boost::bind( &::canvas::IRenderModule::endPrimitive,
203 ::boost::ref(pRenderModule) ) );
205 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2);
206 vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY());
207 pRenderModule->pushVertex(vertex);
209 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2);
210 vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY());
211 pRenderModule->pushVertex(vertex);
213 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1);
214 vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY());
215 pRenderModule->pushVertex(vertex);
217 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1);
218 vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY());
219 pRenderModule->pushVertex(vertex);
222 return !(pRenderModule->isError());
225 //////////////////////////////////////////////////////////////////////////////////
226 // Surface::drawRectangularArea
227 //////////////////////////////////////////////////////////////////////////////////
229 bool Surface::drawRectangularArea(
230 double fAlpha,
231 const ::basegfx::B2DPoint& rPos,
232 const ::basegfx::B2DRectangle& rArea,
233 const ::basegfx::B2DHomMatrix& rTransform )
235 if( rArea.isEmpty() )
236 return true; // immediate exit for empty area
238 IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule());
240 RenderModuleGuard aGuard( pRenderModule );
242 prepareRendering();
244 // these positions are relative to the texture
245 ::basegfx::B2IPoint aPos1(
246 ::basegfx::fround(rArea.getMinimum().getX()),
247 ::basegfx::fround(rArea.getMinimum().getY()));
248 ::basegfx::B2IPoint aPos2(
249 ::basegfx::fround(rArea.getMaximum().getX()),
250 ::basegfx::fround(rArea.getMaximum().getY()) );
252 // clip the positions to the area this surface covers
253 aPos1.setX(::std::max(aPos1.getX(),maSourceOffset.getX()));
254 aPos1.setY(::std::max(aPos1.getY(),maSourceOffset.getY()));
255 aPos2.setX(::std::min(aPos2.getX(),maSourceOffset.getX()+maSize.getX()));
256 aPos2.setY(::std::min(aPos2.getY(),maSourceOffset.getY()+maSize.getY()));
258 // if the resulting area is empty, return immediately
259 ::basegfx::B2IVector aSize(aPos2 - aPos1);
260 if(aSize.getX() <= 0 || aSize.getY() <= 0)
261 return true;
263 ::basegfx::B2IPoint aDestOffset;
264 if( mpFragment )
265 aDestOffset = mpFragment->getPos();
267 // convert size to normalized device coordinates
268 const ::basegfx::B2DRectangle& rUV(
269 getUVCoords(aPos1 - maSourceOffset + aDestOffset,
270 aSize) );
271 const double u1(rUV.getMinX());
272 const double v1(rUV.getMinY());
273 const double u2(rUV.getMaxX());
274 const double v2(rUV.getMaxY());
276 // concatenate transforms
277 // 1) offset of surface subarea
278 // 2) surface transform
279 // 3) translation to output position [rPos]
280 ::basegfx::B2DHomMatrix aTransform;
281 aTransform.translate(aPos1.getX(),aPos1.getY());
282 aTransform = aTransform * rTransform;
283 aTransform.translate(::basegfx::fround(rPos.getX()),
284 ::basegfx::fround(rPos.getY()));
288 ######################################
289 ######################################
290 ######################################
295 2 | 3
296 x------------x
297 | | |
298 | | |
299 ------|-----O------|------>X
300 -1 | | | +1
301 | | |
302 x------------x
303 1 | 0
307 ######################################
308 ######################################
309 ######################################
312 const ::basegfx::B2DPoint& p0(aTransform * ::basegfx::B2DPoint(aSize.getX(),aSize.getY()));
313 const ::basegfx::B2DPoint& p1(aTransform * ::basegfx::B2DPoint(0.0, aSize.getY()));
314 const ::basegfx::B2DPoint& p2(aTransform * ::basegfx::B2DPoint(0.0, 0.0));
315 const ::basegfx::B2DPoint& p3(aTransform * ::basegfx::B2DPoint(aSize.getX(),0.0));
317 canvas::Vertex vertex;
318 vertex.r = 1.0f;
319 vertex.g = 1.0f;
320 vertex.b = 1.0f;
321 vertex.a = static_cast<float>(fAlpha);
322 vertex.z = 0.0f;
325 pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_QUAD );
327 // issue an endPrimitive() when leaving the scope
328 const ::comphelper::ScopeGuard aScopeGuard(
329 boost::bind( &::canvas::IRenderModule::endPrimitive,
330 ::boost::ref(pRenderModule) ) );
332 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v2);
333 vertex.x=static_cast<float>(p0.getX()); vertex.y=static_cast<float>(p0.getY());
334 pRenderModule->pushVertex(vertex);
336 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v2);
337 vertex.x=static_cast<float>(p1.getX()); vertex.y=static_cast<float>(p1.getY());
338 pRenderModule->pushVertex(vertex);
340 vertex.u=static_cast<float>(u1); vertex.v=static_cast<float>(v1);
341 vertex.x=static_cast<float>(p2.getX()); vertex.y=static_cast<float>(p2.getY());
342 pRenderModule->pushVertex(vertex);
344 vertex.u=static_cast<float>(u2); vertex.v=static_cast<float>(v1);
345 vertex.x=static_cast<float>(p3.getX()); vertex.y=static_cast<float>(p3.getY());
346 pRenderModule->pushVertex(vertex);
349 return !(pRenderModule->isError());
352 //////////////////////////////////////////////////////////////////////////////////
353 // Surface::drawWithClip
354 //////////////////////////////////////////////////////////////////////////////////
356 bool Surface::drawWithClip( double fAlpha,
357 const ::basegfx::B2DPoint& rPos,
358 const ::basegfx::B2DPolygon& rClipPoly,
359 const ::basegfx::B2DHomMatrix& rTransform )
361 IRenderModuleSharedPtr pRenderModule(mpPageManager->getRenderModule());
363 RenderModuleGuard aGuard( pRenderModule );
365 prepareRendering();
367 // untransformed surface rectangle, relative to the whole
368 // image (note: this surface might actually only be a tile of
369 // the whole image, with non-zero maSourceOffset)
370 const double x1(maSourceOffset.getX());
371 const double y1(maSourceOffset.getY());
372 const double w(maSize.getX());
373 const double h(maSize.getY());
374 const double x2(x1+w);
375 const double y2(y1+h);
376 const ::basegfx::B2DRectangle aSurfaceClipRect(x1,y1,x2,y2);
378 // concatenate transforms
379 // we use 'fround' here to avoid rounding errors. the vertices will
380 // be transformed by the overall transform and uv coordinates will
381 // be calculated from the result, and this is why we need to use
382 // integer coordinates here...
383 ::basegfx::B2DHomMatrix aTransform;
384 aTransform = aTransform * rTransform;
385 aTransform.translate(::basegfx::fround(rPos.getX()),
386 ::basegfx::fround(rPos.getY()));
389 ######################################
390 ######################################
391 ######################################
396 2 | 3
397 x------------x
398 | | |
399 | | |
400 ------|-----O------|------>X
401 -1 | | | +1
402 | | |
403 x------------x
404 1 | 0
408 ######################################
409 ######################################
410 ######################################
413 // uv coordinates that map the surface rectangle
414 // to the destination rectangle.
415 const ::basegfx::B2DRectangle& rUV( getUVCoords() );
417 basegfx::B2DPolygon rTriangleList(basegfx::tools::clipTriangleListOnRange(rClipPoly,
418 aSurfaceClipRect));
420 // Push vertices to backend renderer
421 if(const sal_uInt32 nVertexCount = rTriangleList.count())
423 canvas::Vertex vertex;
424 vertex.r = 1.0f;
425 vertex.g = 1.0f;
426 vertex.b = 1.0f;
427 vertex.a = static_cast<float>(fAlpha);
428 vertex.z = 0.0f;
430 #if defined(TRIANGLE_LOG) && defined(DBG_UTIL)
431 OSL_TRACE( "Surface::draw(): numvertices %d numtriangles %d\n",
432 nVertexCount,
433 nVertexCount/3 );
434 #endif
436 pRenderModule->beginPrimitive( canvas::IRenderModule::PRIMITIVE_TYPE_TRIANGLE );
438 // issue an endPrimitive() when leaving the scope
439 const ::comphelper::ScopeGuard aScopeGuard(
440 boost::bind( &::canvas::IRenderModule::endPrimitive,
441 ::boost::ref(pRenderModule) ) );
443 for(sal_uInt32 nIndex=0; nIndex<nVertexCount; ++nIndex)
445 const basegfx::B2DPoint &aPoint = rTriangleList.getB2DPoint(nIndex);
446 basegfx::B2DPoint aTransformedPoint(aTransform * aPoint);
447 const double tu(((aPoint.getX()-aSurfaceClipRect.getMinX())*rUV.getWidth()/w)+rUV.getMinX());
448 const double tv(((aPoint.getY()-aSurfaceClipRect.getMinY())*rUV.getHeight()/h)+rUV.getMinY());
449 vertex.u=static_cast<float>(tu);
450 vertex.v=static_cast<float>(tv);
451 vertex.x=static_cast<float>(aTransformedPoint.getX());
452 vertex.y=static_cast<float>(aTransformedPoint.getY());
453 pRenderModule->pushVertex(vertex);
457 return !(pRenderModule->isError());
460 //////////////////////////////////////////////////////////////////////////////////
461 // Surface::prepareRendering
462 //////////////////////////////////////////////////////////////////////////////////
464 void Surface::prepareRendering()
466 mpPageManager->validatePages();
468 // clients requested to draw from this surface, therefore one
469 // of the above implemented concrete rendering operations
470 // was triggered. we therefore need to ask the pagemanager
471 // to allocate some space for the fragment we're dedicated to.
472 if(!(mpFragment))
474 mpFragment = mpPageManager->allocateSpace(maSize);
475 if( mpFragment )
477 mpFragment->setColorBuffer(mpColorBuffer);
478 mpFragment->setSourceOffset(maSourceOffset);
482 if( mpFragment )
484 // now we need to 'select' the fragment, which will in turn
485 // pull informations from the image on demand.
486 // in case this fragment is still not located on any of the
487 // available pages ['naked'], we force the page manager to
488 // do it now, no way to defer this any longer...
489 if(!(mpFragment->select(mbIsDirty)))
490 mpPageManager->nakedFragment(mpFragment);
493 mbIsDirty=false;
496 //////////////////////////////////////////////////////////////////////////////////
497 // End of file
498 //////////////////////////////////////////////////////////////////////////////////