125ea7f45SAndrew Rist /************************************************************** 2cdf0e10cSrcweir * 325ea7f45SAndrew Rist * Licensed to the Apache Software Foundation (ASF) under one 425ea7f45SAndrew Rist * or more contributor license agreements. See the NOTICE file 525ea7f45SAndrew Rist * distributed with this work for additional information 625ea7f45SAndrew Rist * regarding copyright ownership. The ASF licenses this file 725ea7f45SAndrew Rist * to you under the Apache License, Version 2.0 (the 825ea7f45SAndrew Rist * "License"); you may not use this file except in compliance 925ea7f45SAndrew Rist * with the License. You may obtain a copy of the License at 1025ea7f45SAndrew Rist * 1125ea7f45SAndrew Rist * http://www.apache.org/licenses/LICENSE-2.0 1225ea7f45SAndrew Rist * 1325ea7f45SAndrew Rist * Unless required by applicable law or agreed to in writing, 1425ea7f45SAndrew Rist * software distributed under the License is distributed on an 1525ea7f45SAndrew Rist * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 1625ea7f45SAndrew Rist * KIND, either express or implied. See the License for the 1725ea7f45SAndrew Rist * specific language governing permissions and limitations 1825ea7f45SAndrew Rist * under the License. 1925ea7f45SAndrew Rist * 2025ea7f45SAndrew Rist *************************************************************/ 2125ea7f45SAndrew Rist 2225ea7f45SAndrew 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 { 326*6d53c851Smseidel // NULL xClip explicitly 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