LCOV - code coverage report
Current view: top level - libreoffice/canvas/source/tools - canvascustomspritehelper.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 0 158 0.0 %
Date: 2012-12-27 Functions: 0 20 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10