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