1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: canvascustomspritehelper.cxx,v $
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
;
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;
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
77 const ::basegfx::B2DRectangle
& rClipBounds(
78 ::basegfx::tools::getRange( aClipPath
) );
80 const ::basegfx::B2DRectangle
aBounds( 0.0, 0.0,
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
,
91 // aClipBoundsA = new clip bound rect, intersected
93 ::basegfx::B2DRectangle
aClipBoundsA(rClipBounds
);
94 aClipBoundsA
.intersect( aSpriteRectPixel
);
96 if( nNumClipPolygons
!= 1 )
98 // clip cannot be a single rectangle -> cannot
100 mbIsCurrClipRectangle
= false;
101 maCurrClipBounds
= aClipBoundsA
;
105 // new clip could be a single rectangle - check
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
;
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
,
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
142 VectorOfRects::const_iterator
aCurr( aClipDifferences
.begin() );
143 const VectorOfRects::const_iterator
aEnd( aClipDifferences
.end() );
144 while( aCurr
!= aEnd
)
146 mpSpriteCanvas
->updateSprite(
149 ::basegfx::B2DRectangle(
150 maPosition
+ aCurr
->getMinimum(),
151 maPosition
+ aCurr
->getMaximum() ) );
155 // update calls all done
161 // caller needs to perform update calls
165 CanvasCustomSpriteHelper::CanvasCustomSpriteHelper() :
175 mbIsCurrClipRectangle(true),
176 mbIsContentFullyOpaque( false ),
177 mbAlphaDirty( true ),
178 mbPositionDirty( true ),
179 mbTransformDirty( 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
;
228 ::basegfx::B2DRectangle( 0.0,0.0,
231 ::basegfx::B2DRectangle( 0.0,0.0,
234 ::canvas::tools::mergeViewAndRenderTransform(aTransform
,
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
,
248 if( !mpSpriteCanvas
.get() )
249 return; // we're disposed
251 if( alpha
!= mfAlpha
)
257 mpSpriteCanvas
->updateSprite( rSprite
,
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
,
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() );
290 mpSpriteCanvas
->moveSprite( rSprite
,
291 rBounds
.getMinimum(),
292 rBounds
.getMinimum() - maPosition
+ aPoint
,
293 rBounds
.getRange() );
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
,
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
) &&
318 mpSpriteCanvas
->updateSprite( rSprite
,
321 mpSpriteCanvas
->updateSprite( rSprite
,
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() );
340 if( !updateClipState( rSprite
) &&
343 mpSpriteCanvas
->updateSprite( rSprite
,
346 mpSpriteCanvas
->updateSprite( rSprite
,
354 void CanvasCustomSpriteHelper::setPriority( const Sprite::Reference
& rSprite
,
357 if( !mpSpriteCanvas
.get() )
358 return; // we're disposed
360 if( nPriority
!= mfPriority
)
362 mfPriority
= nPriority
;
366 mpSpriteCanvas
->updateSprite( rSprite
,
375 void CanvasCustomSpriteHelper::show( const Sprite::Reference
& rSprite
)
377 if( !mpSpriteCanvas
.get() )
378 return; // we're disposed
382 mpSpriteCanvas
->showSprite( rSprite
);
385 // TODO(P1): if clip is the NULL clip (nothing visible),
386 // also save us the update call.
390 mpSpriteCanvas
->updateSprite( rSprite
,
395 mbVisibilityDirty
= true;
399 void CanvasCustomSpriteHelper::hide( const Sprite::Reference
& rSprite
)
401 if( !mpSpriteCanvas
.get() )
402 return; // we're disposed
406 mpSpriteCanvas
->hideSprite( rSprite
);
409 // TODO(P1): if clip is the NULL clip (nothing visible),
410 // also save us the update call.
414 mpSpriteCanvas
->updateSprite( rSprite
,
419 mbVisibilityDirty
= true;
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
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
451 ::basegfx::B2DVector
CanvasCustomSpriteHelper::getSizePixel() const
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(),
463 // transform bounds at origin, as the sprite transformation is
464 // formulated that way
465 ::basegfx::B2DRectangle aTransformedBounds
;
466 return ::canvas::tools::calcTransformedRectBounds( aTransformedBounds
,
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
477 if( maCurrClipBounds
.isEmpty() )
478 return getUpdateArea( ::basegfx::B2DRectangle( 0.0, 0.0,
482 return ::basegfx::B2DRectangle(
483 maPosition
+ maCurrClipBounds
.getMinimum(),
484 maPosition
+ maCurrClipBounds
.getMaximum() );
487 double CanvasCustomSpriteHelper::getPriority() const
492 ::basegfx::B2DRange
CanvasCustomSpriteHelper::getFullSpriteRect() const
494 // Internal! Only call with locked object mutex!
495 return getUpdateArea( ::basegfx::B2DRectangle( 0.0, 0.0,