Update ooo320-m1
[ooovba.git] / canvas / source / tools / canvascustomspritehelper.cxx
blob65b01a64f289c63acfe583fddf41e0a0f80776aa
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: canvascustomspritehelper.cxx,v $
10 * $Revision: 1.6 $
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 <canvas/debug.hxx>
35 #include <tools/diagnose_ex.h>
36 #include <canvas/verbosetrace.hxx>
37 #include <canvas/canvastools.hxx>
39 #include <rtl/math.hxx>
41 #include <basegfx/matrix/b2dhommatrix.hxx>
42 #include <basegfx/point/b2dpoint.hxx>
43 #include <basegfx/tools/canvastools.hxx>
44 #include <basegfx/polygon/b2dpolygon.hxx>
45 #include <basegfx/polygon/b2dpolygontools.hxx>
46 #include <basegfx/polygon/b2dpolypolygontools.hxx>
47 #include <basegfx/numeric/ftools.hxx>
49 #include <canvas/base/canvascustomspritehelper.hxx>
51 using namespace ::com::sun::star;
54 namespace canvas
56 bool CanvasCustomSpriteHelper::updateClipState( const Sprite::Reference& rSprite )
58 if( !mxClipPoly.is() )
60 // empty clip polygon -> everything is visible now
61 maCurrClipBounds.reset();
62 mbIsCurrClipRectangle = true;
64 else
66 const sal_Int32 nNumClipPolygons( mxClipPoly->getNumberOfPolygons() );
68 // clip is not empty - determine actual update area
69 ::basegfx::B2DPolyPolygon aClipPath(
70 polyPolygonFromXPolyPolygon2D( mxClipPoly ) );
72 // apply sprite transformation also to clip!
73 aClipPath.transform( maTransform );
75 // clip which is about to be set, expressed as a
76 // b2drectangle
77 const ::basegfx::B2DRectangle& rClipBounds(
78 ::basegfx::tools::getRange( aClipPath ) );
80 const ::basegfx::B2DRectangle aBounds( 0.0, 0.0,
81 maSize.getX(),
82 maSize.getY() );
84 // rectangular area which is actually covered by the sprite.
85 // coordinates are relative to the sprite origin.
86 ::basegfx::B2DRectangle aSpriteRectPixel;
87 ::canvas::tools::calcTransformedRectBounds( aSpriteRectPixel,
88 aBounds,
89 maTransform );
91 // aClipBoundsA = new clip bound rect, intersected
92 // with sprite area
93 ::basegfx::B2DRectangle aClipBoundsA(rClipBounds);
94 aClipBoundsA.intersect( aSpriteRectPixel );
96 if( nNumClipPolygons != 1 )
98 // clip cannot be a single rectangle -> cannot
99 // optimize update
100 mbIsCurrClipRectangle = false;
101 maCurrClipBounds = aClipBoundsA;
103 else
105 // new clip could be a single rectangle - check
106 // that now:
107 const bool bNewClipIsRect(
108 ::basegfx::tools::isRectangle( aClipPath.getB2DPolygon(0) ) );
110 // both new and old clip are truly rectangles
111 // - can now take the optimized path
112 const bool bUseOptimizedUpdate( bNewClipIsRect &&
113 mbIsCurrClipRectangle );
115 const ::basegfx::B2DRectangle aOldBounds( maCurrClipBounds );
117 // store new current clip type
118 maCurrClipBounds = aClipBoundsA;
119 mbIsCurrClipRectangle = bNewClipIsRect;
121 if( mbActive &&
122 bUseOptimizedUpdate )
124 // aClipBoundsB = maCurrClipBounds, i.e. last
125 // clip, intersected with sprite area
126 typedef ::std::vector< ::basegfx::B2DRectangle > VectorOfRects;
127 VectorOfRects aClipDifferences;
129 // get all rectangles covered by exactly one
130 // of the polygons (aka XOR)
131 ::basegfx::computeSetDifference(aClipDifferences,
132 aClipBoundsA,
133 aOldBounds);
135 // aClipDifferences now contains the final
136 // update areas, coordinates are still relative
137 // to the sprite origin. before submitting
138 // this area to 'updateSprite()' we need to
139 // translate this area to the final position,
140 // coordinates need to be relative to the
141 // spritecanvas.
142 VectorOfRects::const_iterator aCurr( aClipDifferences.begin() );
143 const VectorOfRects::const_iterator aEnd( aClipDifferences.end() );
144 while( aCurr != aEnd )
146 mpSpriteCanvas->updateSprite(
147 rSprite,
148 maPosition,
149 ::basegfx::B2DRectangle(
150 maPosition + aCurr->getMinimum(),
151 maPosition + aCurr->getMaximum() ) );
152 ++aCurr;
155 // update calls all done
156 return true;
161 // caller needs to perform update calls
162 return false;
165 CanvasCustomSpriteHelper::CanvasCustomSpriteHelper() :
166 mpSpriteCanvas(),
167 maCurrClipBounds(),
168 maPosition(),
169 maSize(),
170 maTransform(),
171 mxClipPoly(),
172 mfPriority(0.0),
173 mfAlpha(0.0),
174 mbActive(false),
175 mbIsCurrClipRectangle(true),
176 mbIsContentFullyOpaque( false ),
177 mbAlphaDirty( true ),
178 mbPositionDirty( true ),
179 mbTransformDirty( true ),
180 mbClipDirty( true ),
181 mbPrioDirty( true ),
182 mbVisibilityDirty( true )
186 void CanvasCustomSpriteHelper::init( const geometry::RealSize2D& rSpriteSize,
187 const SpriteSurface::Reference& rOwningSpriteCanvas )
189 ENSURE_OR_THROW( rOwningSpriteCanvas.get(),
190 "CanvasCustomSpriteHelper::init(): Invalid owning sprite canvas" );
192 mpSpriteCanvas = rOwningSpriteCanvas;
193 maSize.setX( ::std::max( 1.0,
194 ceil( rSpriteSize.Width ) ) ); // round up to nearest int,
195 // enforce sprite to have at
196 // least (1,1) pixel size
197 maSize.setY( ::std::max( 1.0,
198 ceil( rSpriteSize.Height ) ) );
201 void CanvasCustomSpriteHelper::disposing()
203 mpSpriteCanvas.clear();
206 void CanvasCustomSpriteHelper::clearingContent( const Sprite::Reference& /*rSprite*/ )
208 // about to clear content to fully transparent
209 mbIsContentFullyOpaque = false;
212 void CanvasCustomSpriteHelper::checkDrawBitmap( const Sprite::Reference& rSprite,
213 const uno::Reference< rendering::XBitmap >& xBitmap,
214 const rendering::ViewState& viewState,
215 const rendering::RenderState& renderState )
217 // check whether bitmap is non-alpha, and whether its
218 // transformed size covers the whole sprite.
219 if( !xBitmap->hasAlpha() )
221 const geometry::IntegerSize2D& rInputSize(
222 xBitmap->getSize() );
223 const ::basegfx::B2DSize& rOurSize(
224 rSprite->getSizePixel() );
226 ::basegfx::B2DHomMatrix aTransform;
227 if( tools::isInside(
228 ::basegfx::B2DRectangle( 0.0,0.0,
229 rOurSize.getX(),
230 rOurSize.getY() ),
231 ::basegfx::B2DRectangle( 0.0,0.0,
232 rInputSize.Width,
233 rInputSize.Height ),
234 ::canvas::tools::mergeViewAndRenderTransform(aTransform,
235 viewState,
236 renderState) ) )
238 // bitmap is opaque and will fully cover the sprite,
239 // set flag appropriately
240 mbIsContentFullyOpaque = true;
245 void CanvasCustomSpriteHelper::setAlpha( const Sprite::Reference& rSprite,
246 double alpha )
248 if( !mpSpriteCanvas.get() )
249 return; // we're disposed
251 if( alpha != mfAlpha )
253 mfAlpha = alpha;
255 if( mbActive )
257 mpSpriteCanvas->updateSprite( rSprite,
258 maPosition,
259 getUpdateArea() );
262 mbAlphaDirty = true;
266 void CanvasCustomSpriteHelper::move( const Sprite::Reference& rSprite,
267 const geometry::RealPoint2D& aNewPos,
268 const rendering::ViewState& viewState,
269 const rendering::RenderState& renderState )
271 if( !mpSpriteCanvas.get() )
272 return; // we're disposed
274 ::basegfx::B2DHomMatrix aTransform;
275 ::canvas::tools::mergeViewAndRenderTransform(aTransform,
276 viewState,
277 renderState);
279 // convert position to device pixel
280 ::basegfx::B2DPoint aPoint(
281 ::basegfx::unotools::b2DPointFromRealPoint2D(aNewPos) );
282 aPoint *= aTransform;
284 if( aPoint != maPosition )
286 const ::basegfx::B2DRectangle& rBounds( getFullSpriteRect() );
288 if( mbActive )
290 mpSpriteCanvas->moveSprite( rSprite,
291 rBounds.getMinimum(),
292 rBounds.getMinimum() - maPosition + aPoint,
293 rBounds.getRange() );
296 maPosition = aPoint;
297 mbPositionDirty = true;
301 void CanvasCustomSpriteHelper::transform( const Sprite::Reference& rSprite,
302 const geometry::AffineMatrix2D& aTransformation )
304 ::basegfx::B2DHomMatrix aMatrix;
305 ::basegfx::unotools::homMatrixFromAffineMatrix(aMatrix,
306 aTransformation);
308 if( maTransform != aMatrix )
310 // retrieve bounds before and after transformation change.
311 const ::basegfx::B2DRectangle& rPrevBounds( getUpdateArea() );
313 maTransform = aMatrix;
315 if( !updateClipState( rSprite ) &&
316 mbActive )
318 mpSpriteCanvas->updateSprite( rSprite,
319 maPosition,
320 rPrevBounds );
321 mpSpriteCanvas->updateSprite( rSprite,
322 maPosition,
323 getUpdateArea() );
326 mbTransformDirty = true;
330 void CanvasCustomSpriteHelper::clip( const Sprite::Reference& rSprite,
331 const uno::Reference< rendering::XPolyPolygon2D >& xClip )
333 // NULL xClip explicitely allowed here (to clear clipping)
335 // retrieve bounds before and after clip change.
336 const ::basegfx::B2DRectangle& rPrevBounds( getUpdateArea() );
338 mxClipPoly = xClip;
340 if( !updateClipState( rSprite ) &&
341 mbActive )
343 mpSpriteCanvas->updateSprite( rSprite,
344 maPosition,
345 rPrevBounds );
346 mpSpriteCanvas->updateSprite( rSprite,
347 maPosition,
348 getUpdateArea() );
351 mbClipDirty = true;
354 void CanvasCustomSpriteHelper::setPriority( const Sprite::Reference& rSprite,
355 double nPriority )
357 if( !mpSpriteCanvas.get() )
358 return; // we're disposed
360 if( nPriority != mfPriority )
362 mfPriority = nPriority;
364 if( mbActive )
366 mpSpriteCanvas->updateSprite( rSprite,
367 maPosition,
368 getUpdateArea() );
371 mbPrioDirty = true;
375 void CanvasCustomSpriteHelper::show( const Sprite::Reference& rSprite )
377 if( !mpSpriteCanvas.get() )
378 return; // we're disposed
380 if( !mbActive )
382 mpSpriteCanvas->showSprite( rSprite );
383 mbActive = true;
385 // TODO(P1): if clip is the NULL clip (nothing visible),
386 // also save us the update call.
388 if( mfAlpha != 0.0 )
390 mpSpriteCanvas->updateSprite( rSprite,
391 maPosition,
392 getUpdateArea() );
395 mbVisibilityDirty = true;
399 void CanvasCustomSpriteHelper::hide( const Sprite::Reference& rSprite )
401 if( !mpSpriteCanvas.get() )
402 return; // we're disposed
404 if( mbActive )
406 mpSpriteCanvas->hideSprite( rSprite );
407 mbActive = false;
409 // TODO(P1): if clip is the NULL clip (nothing visible),
410 // also save us the update call.
412 if( mfAlpha != 0.0 )
414 mpSpriteCanvas->updateSprite( rSprite,
415 maPosition,
416 getUpdateArea() );
419 mbVisibilityDirty = true;
423 // Sprite interface
424 bool CanvasCustomSpriteHelper::isAreaUpdateOpaque( const ::basegfx::B2DRange& rUpdateArea ) const
426 if( !mbIsCurrClipRectangle ||
427 !mbIsContentFullyOpaque ||
428 !::rtl::math::approxEqual(mfAlpha, 1.0) )
430 // sprite either transparent, or clip rect does not
431 // represent exact bounds -> update might not be fully
432 // opaque
433 return false;
435 else
437 // make sure sprite rect fully covers update area -
438 // although the update area originates from the sprite,
439 // it's by no means guaranteed that it's limited to this
440 // sprite's update area - after all, other sprites might
441 // have been merged, or this sprite is moving.
442 return getUpdateArea().isInside( rUpdateArea );
446 ::basegfx::B2DPoint CanvasCustomSpriteHelper::getPosPixel() const
448 return maPosition;
451 ::basegfx::B2DVector CanvasCustomSpriteHelper::getSizePixel() const
453 return maSize;
456 ::basegfx::B2DRange CanvasCustomSpriteHelper::getUpdateArea( const ::basegfx::B2DRange& rBounds ) const
458 // Internal! Only call with locked object mutex!
459 ::basegfx::B2DHomMatrix aTransform( maTransform );
460 aTransform.translate( maPosition.getX(),
461 maPosition.getY() );
463 // transform bounds at origin, as the sprite transformation is
464 // formulated that way
465 ::basegfx::B2DRectangle aTransformedBounds;
466 return ::canvas::tools::calcTransformedRectBounds( aTransformedBounds,
467 rBounds,
468 aTransform );
471 ::basegfx::B2DRange CanvasCustomSpriteHelper::getUpdateArea() const
473 // Internal! Only call with locked object mutex!
475 // return effective sprite rect, i.e. take active clip into
476 // account
477 if( maCurrClipBounds.isEmpty() )
478 return getUpdateArea( ::basegfx::B2DRectangle( 0.0, 0.0,
479 maSize.getX(),
480 maSize.getY() ) );
481 else
482 return ::basegfx::B2DRectangle(
483 maPosition + maCurrClipBounds.getMinimum(),
484 maPosition + maCurrClipBounds.getMaximum() );
487 double CanvasCustomSpriteHelper::getPriority() const
489 return mfPriority;
492 ::basegfx::B2DRange CanvasCustomSpriteHelper::getFullSpriteRect() const
494 // Internal! Only call with locked object mutex!
495 return getUpdateArea( ::basegfx::B2DRectangle( 0.0, 0.0,
496 maSize.getX(),
497 maSize.getY() ) );