xref: /AOO41X/main/canvas/source/tools/canvascustomspritehelper.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
1*cdf0e10cSrcweir /*************************************************************************
2*cdf0e10cSrcweir  *
3*cdf0e10cSrcweir  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4*cdf0e10cSrcweir  *
5*cdf0e10cSrcweir  * Copyright 2000, 2010 Oracle and/or its affiliates.
6*cdf0e10cSrcweir  *
7*cdf0e10cSrcweir  * OpenOffice.org - a multi-platform office productivity suite
8*cdf0e10cSrcweir  *
9*cdf0e10cSrcweir  * This file is part of OpenOffice.org.
10*cdf0e10cSrcweir  *
11*cdf0e10cSrcweir  * OpenOffice.org is free software: you can redistribute it and/or modify
12*cdf0e10cSrcweir  * it under the terms of the GNU Lesser General Public License version 3
13*cdf0e10cSrcweir  * only, as published by the Free Software Foundation.
14*cdf0e10cSrcweir  *
15*cdf0e10cSrcweir  * OpenOffice.org is distributed in the hope that it will be useful,
16*cdf0e10cSrcweir  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*cdf0e10cSrcweir  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*cdf0e10cSrcweir  * GNU Lesser General Public License version 3 for more details
19*cdf0e10cSrcweir  * (a copy is included in the LICENSE file that accompanied this code).
20*cdf0e10cSrcweir  *
21*cdf0e10cSrcweir  * You should have received a copy of the GNU Lesser General Public License
22*cdf0e10cSrcweir  * version 3 along with OpenOffice.org.  If not, see
23*cdf0e10cSrcweir  * <http://www.openoffice.org/license.html>
24*cdf0e10cSrcweir  * for a copy of the LGPLv3 License.
25*cdf0e10cSrcweir  *
26*cdf0e10cSrcweir  ************************************************************************/
27*cdf0e10cSrcweir 
28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
29*cdf0e10cSrcweir #include "precompiled_canvas.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include <canvas/debug.hxx>
32*cdf0e10cSrcweir #include <tools/diagnose_ex.h>
33*cdf0e10cSrcweir #include <canvas/verbosetrace.hxx>
34*cdf0e10cSrcweir #include <canvas/canvastools.hxx>
35*cdf0e10cSrcweir 
36*cdf0e10cSrcweir #include <rtl/math.hxx>
37*cdf0e10cSrcweir 
38*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx>
39*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx>
40*cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx>
41*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
42*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
43*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx>
44*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx>
45*cdf0e10cSrcweir 
46*cdf0e10cSrcweir #include <canvas/base/canvascustomspritehelper.hxx>
47*cdf0e10cSrcweir 
48*cdf0e10cSrcweir using namespace ::com::sun::star;
49*cdf0e10cSrcweir 
50*cdf0e10cSrcweir 
51*cdf0e10cSrcweir namespace canvas
52*cdf0e10cSrcweir {
53*cdf0e10cSrcweir     bool CanvasCustomSpriteHelper::updateClipState( const Sprite::Reference& rSprite )
54*cdf0e10cSrcweir     {
55*cdf0e10cSrcweir         if( !mxClipPoly.is() )
56*cdf0e10cSrcweir         {
57*cdf0e10cSrcweir             // empty clip polygon -> everything is visible now
58*cdf0e10cSrcweir             maCurrClipBounds.reset();
59*cdf0e10cSrcweir             mbIsCurrClipRectangle = true;
60*cdf0e10cSrcweir         }
61*cdf0e10cSrcweir         else
62*cdf0e10cSrcweir         {
63*cdf0e10cSrcweir             const sal_Int32 nNumClipPolygons( mxClipPoly->getNumberOfPolygons() );
64*cdf0e10cSrcweir 
65*cdf0e10cSrcweir             // clip is not empty - determine actual update area
66*cdf0e10cSrcweir             ::basegfx::B2DPolyPolygon aClipPath(
67*cdf0e10cSrcweir                 polyPolygonFromXPolyPolygon2D( mxClipPoly ) );
68*cdf0e10cSrcweir 
69*cdf0e10cSrcweir             // apply sprite transformation also to clip!
70*cdf0e10cSrcweir             aClipPath.transform( maTransform );
71*cdf0e10cSrcweir 
72*cdf0e10cSrcweir             // clip which is about to be set, expressed as a
73*cdf0e10cSrcweir             // b2drectangle
74*cdf0e10cSrcweir             const ::basegfx::B2DRectangle& rClipBounds(
75*cdf0e10cSrcweir                 ::basegfx::tools::getRange( aClipPath ) );
76*cdf0e10cSrcweir 
77*cdf0e10cSrcweir             const ::basegfx::B2DRectangle aBounds( 0.0, 0.0,
78*cdf0e10cSrcweir                                                    maSize.getX(),
79*cdf0e10cSrcweir                                                    maSize.getY() );
80*cdf0e10cSrcweir 
81*cdf0e10cSrcweir             // rectangular area which is actually covered by the sprite.
82*cdf0e10cSrcweir             // coordinates are relative to the sprite origin.
83*cdf0e10cSrcweir             ::basegfx::B2DRectangle aSpriteRectPixel;
84*cdf0e10cSrcweir             ::canvas::tools::calcTransformedRectBounds( aSpriteRectPixel,
85*cdf0e10cSrcweir                                                         aBounds,
86*cdf0e10cSrcweir                                                         maTransform );
87*cdf0e10cSrcweir 
88*cdf0e10cSrcweir             // aClipBoundsA = new clip bound rect, intersected
89*cdf0e10cSrcweir             // with sprite area
90*cdf0e10cSrcweir             ::basegfx::B2DRectangle aClipBoundsA(rClipBounds);
91*cdf0e10cSrcweir             aClipBoundsA.intersect( aSpriteRectPixel );
92*cdf0e10cSrcweir 
93*cdf0e10cSrcweir             if( nNumClipPolygons != 1 )
94*cdf0e10cSrcweir             {
95*cdf0e10cSrcweir                 // clip cannot be a single rectangle -> cannot
96*cdf0e10cSrcweir                 // optimize update
97*cdf0e10cSrcweir                 mbIsCurrClipRectangle = false;
98*cdf0e10cSrcweir                 maCurrClipBounds = aClipBoundsA;
99*cdf0e10cSrcweir             }
100*cdf0e10cSrcweir             else
101*cdf0e10cSrcweir             {
102*cdf0e10cSrcweir                 // new clip could be a single rectangle - check
103*cdf0e10cSrcweir                 // that now:
104*cdf0e10cSrcweir                 const bool bNewClipIsRect(
105*cdf0e10cSrcweir                     ::basegfx::tools::isRectangle( aClipPath.getB2DPolygon(0) ) );
106*cdf0e10cSrcweir 
107*cdf0e10cSrcweir                 // both new and old clip are truly rectangles
108*cdf0e10cSrcweir                 // - can now take the optimized path
109*cdf0e10cSrcweir                 const bool bUseOptimizedUpdate( bNewClipIsRect &&
110*cdf0e10cSrcweir                                                 mbIsCurrClipRectangle );
111*cdf0e10cSrcweir 
112*cdf0e10cSrcweir                 const ::basegfx::B2DRectangle aOldBounds( maCurrClipBounds );
113*cdf0e10cSrcweir 
114*cdf0e10cSrcweir                 // store new current clip type
115*cdf0e10cSrcweir                 maCurrClipBounds = aClipBoundsA;
116*cdf0e10cSrcweir                 mbIsCurrClipRectangle = bNewClipIsRect;
117*cdf0e10cSrcweir 
118*cdf0e10cSrcweir                 if( mbActive &&
119*cdf0e10cSrcweir                     bUseOptimizedUpdate  )
120*cdf0e10cSrcweir                 {
121*cdf0e10cSrcweir                     // aClipBoundsB = maCurrClipBounds, i.e. last
122*cdf0e10cSrcweir                     // clip, intersected with sprite area
123*cdf0e10cSrcweir                     typedef ::std::vector< ::basegfx::B2DRectangle > VectorOfRects;
124*cdf0e10cSrcweir                     VectorOfRects aClipDifferences;
125*cdf0e10cSrcweir 
126*cdf0e10cSrcweir                     // get all rectangles covered by exactly one
127*cdf0e10cSrcweir                     // of the polygons (aka XOR)
128*cdf0e10cSrcweir                     ::basegfx::computeSetDifference(aClipDifferences,
129*cdf0e10cSrcweir                                                     aClipBoundsA,
130*cdf0e10cSrcweir                                                     aOldBounds);
131*cdf0e10cSrcweir 
132*cdf0e10cSrcweir                     // aClipDifferences now contains the final
133*cdf0e10cSrcweir                     // update areas, coordinates are still relative
134*cdf0e10cSrcweir                     // to the sprite origin. before submitting
135*cdf0e10cSrcweir                     // this area to 'updateSprite()' we need to
136*cdf0e10cSrcweir                     // translate this area to the final position,
137*cdf0e10cSrcweir                     // coordinates need to be relative to the
138*cdf0e10cSrcweir                     // spritecanvas.
139*cdf0e10cSrcweir                     VectorOfRects::const_iterator 		aCurr( aClipDifferences.begin() );
140*cdf0e10cSrcweir                     const VectorOfRects::const_iterator aEnd( aClipDifferences.end() );
141*cdf0e10cSrcweir                     while( aCurr != aEnd )
142*cdf0e10cSrcweir                     {
143*cdf0e10cSrcweir                         mpSpriteCanvas->updateSprite(
144*cdf0e10cSrcweir                             rSprite,
145*cdf0e10cSrcweir                             maPosition,
146*cdf0e10cSrcweir                             ::basegfx::B2DRectangle(
147*cdf0e10cSrcweir                                 maPosition + aCurr->getMinimum(),
148*cdf0e10cSrcweir                                 maPosition + aCurr->getMaximum() ) );
149*cdf0e10cSrcweir                         ++aCurr;
150*cdf0e10cSrcweir                     }
151*cdf0e10cSrcweir 
152*cdf0e10cSrcweir                     // update calls all done
153*cdf0e10cSrcweir                     return true;
154*cdf0e10cSrcweir                 }
155*cdf0e10cSrcweir             }
156*cdf0e10cSrcweir         }
157*cdf0e10cSrcweir 
158*cdf0e10cSrcweir         // caller needs to perform update calls
159*cdf0e10cSrcweir         return false;
160*cdf0e10cSrcweir     }
161*cdf0e10cSrcweir 
162*cdf0e10cSrcweir     CanvasCustomSpriteHelper::CanvasCustomSpriteHelper() :
163*cdf0e10cSrcweir         mpSpriteCanvas(),
164*cdf0e10cSrcweir         maCurrClipBounds(),
165*cdf0e10cSrcweir         maPosition(),
166*cdf0e10cSrcweir         maSize(),
167*cdf0e10cSrcweir         maTransform(),
168*cdf0e10cSrcweir         mxClipPoly(),
169*cdf0e10cSrcweir         mfPriority(0.0),
170*cdf0e10cSrcweir         mfAlpha(0.0),
171*cdf0e10cSrcweir         mbActive(false),
172*cdf0e10cSrcweir         mbIsCurrClipRectangle(true),
173*cdf0e10cSrcweir         mbIsContentFullyOpaque( false ),
174*cdf0e10cSrcweir         mbAlphaDirty( true ),
175*cdf0e10cSrcweir         mbPositionDirty( true ),
176*cdf0e10cSrcweir         mbTransformDirty( true ),
177*cdf0e10cSrcweir         mbClipDirty( true ),
178*cdf0e10cSrcweir         mbPrioDirty( true ),
179*cdf0e10cSrcweir         mbVisibilityDirty( true )
180*cdf0e10cSrcweir     {
181*cdf0e10cSrcweir     }
182*cdf0e10cSrcweir 
183*cdf0e10cSrcweir     void CanvasCustomSpriteHelper::init( const geometry::RealSize2D& 		rSpriteSize,
184*cdf0e10cSrcweir                                          const SpriteSurface::Reference&	rOwningSpriteCanvas )
185*cdf0e10cSrcweir     {
186*cdf0e10cSrcweir         ENSURE_OR_THROW( rOwningSpriteCanvas.get(),
187*cdf0e10cSrcweir                           "CanvasCustomSpriteHelper::init(): Invalid owning sprite canvas" );
188*cdf0e10cSrcweir 
189*cdf0e10cSrcweir         mpSpriteCanvas = rOwningSpriteCanvas;
190*cdf0e10cSrcweir         maSize.setX( ::std::max( 1.0,
191*cdf0e10cSrcweir                                  ceil( rSpriteSize.Width ) ) ); // round up to nearest int,
192*cdf0e10cSrcweir                 											 	// enforce sprite to have at
193*cdf0e10cSrcweir                 											 	// least (1,1) pixel size
194*cdf0e10cSrcweir         maSize.setY( ::std::max( 1.0,
195*cdf0e10cSrcweir                                  ceil( rSpriteSize.Height ) ) );
196*cdf0e10cSrcweir     }
197*cdf0e10cSrcweir 
198*cdf0e10cSrcweir     void CanvasCustomSpriteHelper::disposing()
199*cdf0e10cSrcweir     {
200*cdf0e10cSrcweir         mpSpriteCanvas.clear();
201*cdf0e10cSrcweir     }
202*cdf0e10cSrcweir 
203*cdf0e10cSrcweir     void CanvasCustomSpriteHelper::clearingContent( const Sprite::Reference& /*rSprite*/ )
204*cdf0e10cSrcweir     {
205*cdf0e10cSrcweir         // about to clear content to fully transparent
206*cdf0e10cSrcweir         mbIsContentFullyOpaque = false;
207*cdf0e10cSrcweir     }
208*cdf0e10cSrcweir 
209*cdf0e10cSrcweir     void CanvasCustomSpriteHelper::checkDrawBitmap( const Sprite::Reference& 					rSprite,
210*cdf0e10cSrcweir                                                     const uno::Reference< rendering::XBitmap >&	xBitmap,
211*cdf0e10cSrcweir                                                     const rendering::ViewState& 				viewState,
212*cdf0e10cSrcweir                                                     const rendering::RenderState& 				renderState )
213*cdf0e10cSrcweir     {
214*cdf0e10cSrcweir         // check whether bitmap is non-alpha, and whether its
215*cdf0e10cSrcweir         // transformed size covers the whole sprite.
216*cdf0e10cSrcweir         if( !xBitmap->hasAlpha() )
217*cdf0e10cSrcweir         {
218*cdf0e10cSrcweir             const geometry::IntegerSize2D& rInputSize(
219*cdf0e10cSrcweir                 xBitmap->getSize() );
220*cdf0e10cSrcweir             const ::basegfx::B2DSize& rOurSize(
221*cdf0e10cSrcweir                 rSprite->getSizePixel() );
222*cdf0e10cSrcweir 
223*cdf0e10cSrcweir             ::basegfx::B2DHomMatrix aTransform;
224*cdf0e10cSrcweir             if( tools::isInside(
225*cdf0e10cSrcweir                     ::basegfx::B2DRectangle( 0.0,0.0,
226*cdf0e10cSrcweir                                              rOurSize.getX(),
227*cdf0e10cSrcweir                                              rOurSize.getY() ),
228*cdf0e10cSrcweir                     ::basegfx::B2DRectangle( 0.0,0.0,
229*cdf0e10cSrcweir                                              rInputSize.Width,
230*cdf0e10cSrcweir                                              rInputSize.Height ),
231*cdf0e10cSrcweir                     ::canvas::tools::mergeViewAndRenderTransform(aTransform,
232*cdf0e10cSrcweir                                                                  viewState,
233*cdf0e10cSrcweir                                                                  renderState) ) )
234*cdf0e10cSrcweir             {
235*cdf0e10cSrcweir                 // bitmap is opaque and will fully cover the sprite,
236*cdf0e10cSrcweir                 // set flag appropriately
237*cdf0e10cSrcweir                 mbIsContentFullyOpaque = true;
238*cdf0e10cSrcweir             }
239*cdf0e10cSrcweir         }
240*cdf0e10cSrcweir     }
241*cdf0e10cSrcweir 
242*cdf0e10cSrcweir     void CanvasCustomSpriteHelper::setAlpha( const Sprite::Reference&	rSprite,
243*cdf0e10cSrcweir                                              double 					alpha )
244*cdf0e10cSrcweir     {
245*cdf0e10cSrcweir         if( !mpSpriteCanvas.get() )
246*cdf0e10cSrcweir             return; // we're disposed
247*cdf0e10cSrcweir 
248*cdf0e10cSrcweir         if( alpha != mfAlpha )
249*cdf0e10cSrcweir         {
250*cdf0e10cSrcweir             mfAlpha = alpha;
251*cdf0e10cSrcweir 
252*cdf0e10cSrcweir             if( mbActive )
253*cdf0e10cSrcweir             {
254*cdf0e10cSrcweir                 mpSpriteCanvas->updateSprite( rSprite,
255*cdf0e10cSrcweir                                               maPosition,
256*cdf0e10cSrcweir                                               getUpdateArea() );
257*cdf0e10cSrcweir             }
258*cdf0e10cSrcweir 
259*cdf0e10cSrcweir             mbAlphaDirty = true;
260*cdf0e10cSrcweir         }
261*cdf0e10cSrcweir     }
262*cdf0e10cSrcweir 
263*cdf0e10cSrcweir     void CanvasCustomSpriteHelper::move( const Sprite::Reference&		rSprite,
264*cdf0e10cSrcweir                                          const geometry::RealPoint2D&  	aNewPos,
265*cdf0e10cSrcweir                                          const rendering::ViewState&   	viewState,
266*cdf0e10cSrcweir                                          const rendering::RenderState& 	renderState )
267*cdf0e10cSrcweir     {
268*cdf0e10cSrcweir         if( !mpSpriteCanvas.get() )
269*cdf0e10cSrcweir             return; // we're disposed
270*cdf0e10cSrcweir 
271*cdf0e10cSrcweir         ::basegfx::B2DHomMatrix aTransform;
272*cdf0e10cSrcweir         ::canvas::tools::mergeViewAndRenderTransform(aTransform,
273*cdf0e10cSrcweir                                                      viewState,
274*cdf0e10cSrcweir                                                      renderState);
275*cdf0e10cSrcweir 
276*cdf0e10cSrcweir         // convert position to device pixel
277*cdf0e10cSrcweir         ::basegfx::B2DPoint aPoint(
278*cdf0e10cSrcweir             ::basegfx::unotools::b2DPointFromRealPoint2D(aNewPos) );
279*cdf0e10cSrcweir         aPoint *= aTransform;
280*cdf0e10cSrcweir 
281*cdf0e10cSrcweir         if( aPoint != maPosition )
282*cdf0e10cSrcweir         {
283*cdf0e10cSrcweir             const ::basegfx::B2DRectangle& 	rBounds( getFullSpriteRect() );
284*cdf0e10cSrcweir 
285*cdf0e10cSrcweir             if( mbActive )
286*cdf0e10cSrcweir             {
287*cdf0e10cSrcweir                 mpSpriteCanvas->moveSprite( rSprite,
288*cdf0e10cSrcweir                                             rBounds.getMinimum(),
289*cdf0e10cSrcweir                                             rBounds.getMinimum() - maPosition + aPoint,
290*cdf0e10cSrcweir                                             rBounds.getRange() );
291*cdf0e10cSrcweir             }
292*cdf0e10cSrcweir 
293*cdf0e10cSrcweir             maPosition = aPoint;
294*cdf0e10cSrcweir             mbPositionDirty = true;
295*cdf0e10cSrcweir         }
296*cdf0e10cSrcweir     }
297*cdf0e10cSrcweir 
298*cdf0e10cSrcweir     void CanvasCustomSpriteHelper::transform( const Sprite::Reference&			rSprite,
299*cdf0e10cSrcweir                                               const geometry::AffineMatrix2D&	aTransformation )
300*cdf0e10cSrcweir     {
301*cdf0e10cSrcweir         ::basegfx::B2DHomMatrix aMatrix;
302*cdf0e10cSrcweir 		::basegfx::unotools::homMatrixFromAffineMatrix(aMatrix,
303*cdf0e10cSrcweir                                                        aTransformation);
304*cdf0e10cSrcweir 
305*cdf0e10cSrcweir         if( maTransform != aMatrix )
306*cdf0e10cSrcweir         {
307*cdf0e10cSrcweir             // retrieve bounds before and after transformation change.
308*cdf0e10cSrcweir             const ::basegfx::B2DRectangle& rPrevBounds( getUpdateArea() );
309*cdf0e10cSrcweir 
310*cdf0e10cSrcweir             maTransform = aMatrix;
311*cdf0e10cSrcweir 
312*cdf0e10cSrcweir             if( !updateClipState( rSprite ) &&
313*cdf0e10cSrcweir                 mbActive )
314*cdf0e10cSrcweir             {
315*cdf0e10cSrcweir                 mpSpriteCanvas->updateSprite( rSprite,
316*cdf0e10cSrcweir                                               maPosition,
317*cdf0e10cSrcweir                                               rPrevBounds );
318*cdf0e10cSrcweir                 mpSpriteCanvas->updateSprite( rSprite,
319*cdf0e10cSrcweir                                               maPosition,
320*cdf0e10cSrcweir                                               getUpdateArea() );
321*cdf0e10cSrcweir             }
322*cdf0e10cSrcweir 
323*cdf0e10cSrcweir             mbTransformDirty = true;
324*cdf0e10cSrcweir         }
325*cdf0e10cSrcweir     }
326*cdf0e10cSrcweir 
327*cdf0e10cSrcweir     void CanvasCustomSpriteHelper::clip( const Sprite::Reference&							rSprite,
328*cdf0e10cSrcweir                                          const uno::Reference< rendering::XPolyPolygon2D >& xClip )
329*cdf0e10cSrcweir     {
330*cdf0e10cSrcweir         // NULL xClip explicitely allowed here (to clear clipping)
331*cdf0e10cSrcweir 
332*cdf0e10cSrcweir         // retrieve bounds before and after clip change.
333*cdf0e10cSrcweir         const ::basegfx::B2DRectangle& rPrevBounds( getUpdateArea() );
334*cdf0e10cSrcweir 
335*cdf0e10cSrcweir         mxClipPoly = xClip;
336*cdf0e10cSrcweir 
337*cdf0e10cSrcweir         if( !updateClipState( rSprite ) &&
338*cdf0e10cSrcweir             mbActive )
339*cdf0e10cSrcweir         {
340*cdf0e10cSrcweir             mpSpriteCanvas->updateSprite( rSprite,
341*cdf0e10cSrcweir                                           maPosition,
342*cdf0e10cSrcweir                                           rPrevBounds );
343*cdf0e10cSrcweir             mpSpriteCanvas->updateSprite( rSprite,
344*cdf0e10cSrcweir                                           maPosition,
345*cdf0e10cSrcweir                                           getUpdateArea() );
346*cdf0e10cSrcweir         }
347*cdf0e10cSrcweir 
348*cdf0e10cSrcweir         mbClipDirty = true;
349*cdf0e10cSrcweir     }
350*cdf0e10cSrcweir 
351*cdf0e10cSrcweir     void CanvasCustomSpriteHelper::setPriority( const Sprite::Reference&	rSprite,
352*cdf0e10cSrcweir                                                 double 						nPriority )
353*cdf0e10cSrcweir     {
354*cdf0e10cSrcweir         if( !mpSpriteCanvas.get() )
355*cdf0e10cSrcweir             return; // we're disposed
356*cdf0e10cSrcweir 
357*cdf0e10cSrcweir         if( nPriority != mfPriority )
358*cdf0e10cSrcweir         {
359*cdf0e10cSrcweir             mfPriority = nPriority;
360*cdf0e10cSrcweir 
361*cdf0e10cSrcweir             if( mbActive )
362*cdf0e10cSrcweir             {
363*cdf0e10cSrcweir                 mpSpriteCanvas->updateSprite( rSprite,
364*cdf0e10cSrcweir                                               maPosition,
365*cdf0e10cSrcweir                                               getUpdateArea() );
366*cdf0e10cSrcweir             }
367*cdf0e10cSrcweir 
368*cdf0e10cSrcweir             mbPrioDirty = true;
369*cdf0e10cSrcweir         }
370*cdf0e10cSrcweir     }
371*cdf0e10cSrcweir 
372*cdf0e10cSrcweir     void CanvasCustomSpriteHelper::show( const Sprite::Reference& rSprite )
373*cdf0e10cSrcweir     {
374*cdf0e10cSrcweir         if( !mpSpriteCanvas.get() )
375*cdf0e10cSrcweir             return; // we're disposed
376*cdf0e10cSrcweir 
377*cdf0e10cSrcweir         if( !mbActive )
378*cdf0e10cSrcweir         {
379*cdf0e10cSrcweir             mpSpriteCanvas->showSprite( rSprite );
380*cdf0e10cSrcweir             mbActive = true;
381*cdf0e10cSrcweir 
382*cdf0e10cSrcweir             // TODO(P1): if clip is the NULL clip (nothing visible),
383*cdf0e10cSrcweir             // also save us the update call.
384*cdf0e10cSrcweir 
385*cdf0e10cSrcweir             if( mfAlpha != 0.0 )
386*cdf0e10cSrcweir             {
387*cdf0e10cSrcweir                 mpSpriteCanvas->updateSprite( rSprite,
388*cdf0e10cSrcweir                                               maPosition,
389*cdf0e10cSrcweir                                               getUpdateArea() );
390*cdf0e10cSrcweir             }
391*cdf0e10cSrcweir 
392*cdf0e10cSrcweir             mbVisibilityDirty = true;
393*cdf0e10cSrcweir         }
394*cdf0e10cSrcweir     }
395*cdf0e10cSrcweir 
396*cdf0e10cSrcweir     void CanvasCustomSpriteHelper::hide( const Sprite::Reference& rSprite )
397*cdf0e10cSrcweir     {
398*cdf0e10cSrcweir         if( !mpSpriteCanvas.get() )
399*cdf0e10cSrcweir             return; // we're disposed
400*cdf0e10cSrcweir 
401*cdf0e10cSrcweir         if( mbActive )
402*cdf0e10cSrcweir         {
403*cdf0e10cSrcweir             mpSpriteCanvas->hideSprite( rSprite );
404*cdf0e10cSrcweir             mbActive = false;
405*cdf0e10cSrcweir 
406*cdf0e10cSrcweir             // TODO(P1): if clip is the NULL clip (nothing visible),
407*cdf0e10cSrcweir             // also save us the update call.
408*cdf0e10cSrcweir 
409*cdf0e10cSrcweir             if( mfAlpha != 0.0 )
410*cdf0e10cSrcweir             {
411*cdf0e10cSrcweir                 mpSpriteCanvas->updateSprite( rSprite,
412*cdf0e10cSrcweir                                               maPosition,
413*cdf0e10cSrcweir                                               getUpdateArea() );
414*cdf0e10cSrcweir             }
415*cdf0e10cSrcweir 
416*cdf0e10cSrcweir             mbVisibilityDirty = true;
417*cdf0e10cSrcweir         }
418*cdf0e10cSrcweir     }
419*cdf0e10cSrcweir 
420*cdf0e10cSrcweir     // Sprite interface
421*cdf0e10cSrcweir     bool CanvasCustomSpriteHelper::isAreaUpdateOpaque( const ::basegfx::B2DRange& rUpdateArea ) const
422*cdf0e10cSrcweir     {
423*cdf0e10cSrcweir         if( !mbIsCurrClipRectangle ||
424*cdf0e10cSrcweir             !mbIsContentFullyOpaque ||
425*cdf0e10cSrcweir             !::rtl::math::approxEqual(mfAlpha, 1.0) )
426*cdf0e10cSrcweir         {
427*cdf0e10cSrcweir             // sprite either transparent, or clip rect does not
428*cdf0e10cSrcweir             // represent exact bounds -> update might not be fully
429*cdf0e10cSrcweir             // opaque
430*cdf0e10cSrcweir             return false;
431*cdf0e10cSrcweir         }
432*cdf0e10cSrcweir         else
433*cdf0e10cSrcweir         {
434*cdf0e10cSrcweir             // make sure sprite rect fully covers update area -
435*cdf0e10cSrcweir             // although the update area originates from the sprite,
436*cdf0e10cSrcweir             // it's by no means guaranteed that it's limited to this
437*cdf0e10cSrcweir             // sprite's update area - after all, other sprites might
438*cdf0e10cSrcweir             // have been merged, or this sprite is moving.
439*cdf0e10cSrcweir             return getUpdateArea().isInside( rUpdateArea );
440*cdf0e10cSrcweir         }
441*cdf0e10cSrcweir     }
442*cdf0e10cSrcweir 
443*cdf0e10cSrcweir     ::basegfx::B2DPoint CanvasCustomSpriteHelper::getPosPixel() const
444*cdf0e10cSrcweir     {
445*cdf0e10cSrcweir         return maPosition;
446*cdf0e10cSrcweir     }
447*cdf0e10cSrcweir 
448*cdf0e10cSrcweir     ::basegfx::B2DVector CanvasCustomSpriteHelper::getSizePixel() const
449*cdf0e10cSrcweir     {
450*cdf0e10cSrcweir         return maSize;
451*cdf0e10cSrcweir     }
452*cdf0e10cSrcweir 
453*cdf0e10cSrcweir     ::basegfx::B2DRange CanvasCustomSpriteHelper::getUpdateArea( const ::basegfx::B2DRange& rBounds ) const
454*cdf0e10cSrcweir     {
455*cdf0e10cSrcweir         // Internal! Only call with locked object mutex!
456*cdf0e10cSrcweir         ::basegfx::B2DHomMatrix aTransform( maTransform );
457*cdf0e10cSrcweir         aTransform.translate( maPosition.getX(),
458*cdf0e10cSrcweir                               maPosition.getY() );
459*cdf0e10cSrcweir 
460*cdf0e10cSrcweir         // transform bounds at origin, as the sprite transformation is
461*cdf0e10cSrcweir         // formulated that way
462*cdf0e10cSrcweir         ::basegfx::B2DRectangle aTransformedBounds;
463*cdf0e10cSrcweir         return ::canvas::tools::calcTransformedRectBounds( aTransformedBounds,
464*cdf0e10cSrcweir                                                            rBounds,
465*cdf0e10cSrcweir                                                            aTransform );
466*cdf0e10cSrcweir     }
467*cdf0e10cSrcweir 
468*cdf0e10cSrcweir     ::basegfx::B2DRange CanvasCustomSpriteHelper::getUpdateArea() const
469*cdf0e10cSrcweir     {
470*cdf0e10cSrcweir         // Internal! Only call with locked object mutex!
471*cdf0e10cSrcweir 
472*cdf0e10cSrcweir         // return effective sprite rect, i.e. take active clip into
473*cdf0e10cSrcweir         // account
474*cdf0e10cSrcweir         if( maCurrClipBounds.isEmpty() )
475*cdf0e10cSrcweir             return getUpdateArea( ::basegfx::B2DRectangle( 0.0, 0.0,
476*cdf0e10cSrcweir                                                            maSize.getX(),
477*cdf0e10cSrcweir                                                            maSize.getY() ) );
478*cdf0e10cSrcweir         else
479*cdf0e10cSrcweir             return ::basegfx::B2DRectangle(
480*cdf0e10cSrcweir                 maPosition + maCurrClipBounds.getMinimum(),
481*cdf0e10cSrcweir                 maPosition + maCurrClipBounds.getMaximum() );
482*cdf0e10cSrcweir     }
483*cdf0e10cSrcweir 
484*cdf0e10cSrcweir     double CanvasCustomSpriteHelper::getPriority() const
485*cdf0e10cSrcweir     {
486*cdf0e10cSrcweir         return mfPriority;
487*cdf0e10cSrcweir     }
488*cdf0e10cSrcweir 
489*cdf0e10cSrcweir     ::basegfx::B2DRange CanvasCustomSpriteHelper::getFullSpriteRect() const
490*cdf0e10cSrcweir     {
491*cdf0e10cSrcweir         // Internal! Only call with locked object mutex!
492*cdf0e10cSrcweir         return getUpdateArea( ::basegfx::B2DRectangle( 0.0, 0.0,
493*cdf0e10cSrcweir                                                        maSize.getX(),
494*cdf0e10cSrcweir                                                        maSize.getY() ) );
495*cdf0e10cSrcweir     }
496*cdf0e10cSrcweir }
497