1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_slideshow.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir // must be first 32*cdf0e10cSrcweir #include <canvas/debug.hxx> 33*cdf0e10cSrcweir #include <tools/diagnose_ex.h> 34*cdf0e10cSrcweir 35*cdf0e10cSrcweir #include <math.h> 36*cdf0e10cSrcweir 37*cdf0e10cSrcweir #include <rtl/logfile.hxx> 38*cdf0e10cSrcweir #include <rtl/math.hxx> 39*cdf0e10cSrcweir 40*cdf0e10cSrcweir #include <com/sun/star/rendering/XCanvas.hpp> 41*cdf0e10cSrcweir #include <com/sun/star/rendering/XIntegerBitmap.hpp> 42*cdf0e10cSrcweir #include <com/sun/star/rendering/PanoseLetterForm.hpp> 43*cdf0e10cSrcweir #include <com/sun/star/awt/FontSlant.hpp> 44*cdf0e10cSrcweir 45*cdf0e10cSrcweir #include <cppuhelper/exc_hlp.hxx> 46*cdf0e10cSrcweir #include <comphelper/anytostring.hxx> 47*cdf0e10cSrcweir 48*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 49*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 50*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 51*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrixtools.hxx> 52*cdf0e10cSrcweir 53*cdf0e10cSrcweir #include <canvas/verbosetrace.hxx> 54*cdf0e10cSrcweir #include <canvas/canvastools.hxx> 55*cdf0e10cSrcweir #include <cppcanvas/vclfactory.hxx> 56*cdf0e10cSrcweir #include <cppcanvas/basegfxfactory.hxx> 57*cdf0e10cSrcweir 58*cdf0e10cSrcweir #include "viewshape.hxx" 59*cdf0e10cSrcweir #include "tools.hxx" 60*cdf0e10cSrcweir 61*cdf0e10cSrcweir #include <boost/bind.hpp> 62*cdf0e10cSrcweir 63*cdf0e10cSrcweir 64*cdf0e10cSrcweir using namespace ::com::sun::star; 65*cdf0e10cSrcweir 66*cdf0e10cSrcweir namespace slideshow 67*cdf0e10cSrcweir { 68*cdf0e10cSrcweir namespace internal 69*cdf0e10cSrcweir { 70*cdf0e10cSrcweir 71*cdf0e10cSrcweir // TODO(F2): Provide sensible setup for mtf-related attributes (fill mode, 72*cdf0e10cSrcweir // char rotation etc.). Do that via mtf argument at this object 73*cdf0e10cSrcweir 74*cdf0e10cSrcweir bool ViewShape::prefetch( RendererCacheEntry& io_rCacheEntry, 75*cdf0e10cSrcweir const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas, 76*cdf0e10cSrcweir const GDIMetaFileSharedPtr& rMtf, 77*cdf0e10cSrcweir const ShapeAttributeLayerSharedPtr& rAttr ) const 78*cdf0e10cSrcweir { 79*cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::prefetch()" ); 80*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( rMtf, 81*cdf0e10cSrcweir "ViewShape::prefetch(): no valid metafile!" ); 82*cdf0e10cSrcweir 83*cdf0e10cSrcweir if( rMtf != io_rCacheEntry.mpMtf || 84*cdf0e10cSrcweir rDestinationCanvas != io_rCacheEntry.getDestinationCanvas() ) 85*cdf0e10cSrcweir { 86*cdf0e10cSrcweir // buffered renderer invalid, re-create 87*cdf0e10cSrcweir ::cppcanvas::Renderer::Parameters aParms; 88*cdf0e10cSrcweir 89*cdf0e10cSrcweir // rendering attribute override parameter struct. For 90*cdf0e10cSrcweir // every valid attribute, the corresponding struct 91*cdf0e10cSrcweir // member is filled, which in the metafile renderer 92*cdf0e10cSrcweir // forces rendering with the given attribute. 93*cdf0e10cSrcweir if( rAttr ) 94*cdf0e10cSrcweir { 95*cdf0e10cSrcweir if( rAttr->isFillColorValid() ) 96*cdf0e10cSrcweir { 97*cdf0e10cSrcweir // convert RGBColor to RGBA32 integer. Note 98*cdf0e10cSrcweir // that getIntegerColor() also truncates 99*cdf0e10cSrcweir // out-of-range values appropriately 100*cdf0e10cSrcweir aParms.maFillColor = 101*cdf0e10cSrcweir rAttr->getFillColor().getIntegerColor(); 102*cdf0e10cSrcweir } 103*cdf0e10cSrcweir if( rAttr->isLineColorValid() ) 104*cdf0e10cSrcweir { 105*cdf0e10cSrcweir // convert RGBColor to RGBA32 integer. Note 106*cdf0e10cSrcweir // that getIntegerColor() also truncates 107*cdf0e10cSrcweir // out-of-range values appropriately 108*cdf0e10cSrcweir aParms.maLineColor = 109*cdf0e10cSrcweir rAttr->getLineColor().getIntegerColor(); 110*cdf0e10cSrcweir } 111*cdf0e10cSrcweir if( rAttr->isCharColorValid() ) 112*cdf0e10cSrcweir { 113*cdf0e10cSrcweir // convert RGBColor to RGBA32 integer. Note 114*cdf0e10cSrcweir // that getIntegerColor() also truncates 115*cdf0e10cSrcweir // out-of-range values appropriately 116*cdf0e10cSrcweir aParms.maTextColor = 117*cdf0e10cSrcweir rAttr->getCharColor().getIntegerColor(); 118*cdf0e10cSrcweir } 119*cdf0e10cSrcweir if( rAttr->isDimColorValid() ) 120*cdf0e10cSrcweir { 121*cdf0e10cSrcweir // convert RGBColor to RGBA32 integer. Note 122*cdf0e10cSrcweir // that getIntegerColor() also truncates 123*cdf0e10cSrcweir // out-of-range values appropriately 124*cdf0e10cSrcweir 125*cdf0e10cSrcweir // dim color overrides all other colors 126*cdf0e10cSrcweir aParms.maFillColor = 127*cdf0e10cSrcweir aParms.maLineColor = 128*cdf0e10cSrcweir aParms.maTextColor = 129*cdf0e10cSrcweir rAttr->getDimColor().getIntegerColor(); 130*cdf0e10cSrcweir } 131*cdf0e10cSrcweir if( rAttr->isFontFamilyValid() ) 132*cdf0e10cSrcweir { 133*cdf0e10cSrcweir aParms.maFontName = 134*cdf0e10cSrcweir rAttr->getFontFamily(); 135*cdf0e10cSrcweir } 136*cdf0e10cSrcweir if( rAttr->isCharScaleValid() ) 137*cdf0e10cSrcweir { 138*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 139*cdf0e10cSrcweir 140*cdf0e10cSrcweir // enlarge text by given scale factor. Do that 141*cdf0e10cSrcweir // with the middle of the shape as the center 142*cdf0e10cSrcweir // of scaling. 143*cdf0e10cSrcweir aMatrix.translate( -0.5, -0.5 ); 144*cdf0e10cSrcweir aMatrix.scale( rAttr->getCharScale(), 145*cdf0e10cSrcweir rAttr->getCharScale() ); 146*cdf0e10cSrcweir aMatrix.translate( 0.5, 0.5 ); 147*cdf0e10cSrcweir 148*cdf0e10cSrcweir aParms.maTextTransformation = aMatrix; 149*cdf0e10cSrcweir } 150*cdf0e10cSrcweir if( rAttr->isCharWeightValid() ) 151*cdf0e10cSrcweir { 152*cdf0e10cSrcweir aParms.maFontWeight = 153*cdf0e10cSrcweir static_cast< sal_Int8 >( 154*cdf0e10cSrcweir ::basegfx::fround( 155*cdf0e10cSrcweir ::std::max( 0.0, 156*cdf0e10cSrcweir ::std::min( 11.0, 157*cdf0e10cSrcweir rAttr->getCharWeight() / 20.0 ) ) ) ); 158*cdf0e10cSrcweir } 159*cdf0e10cSrcweir if( rAttr->isCharPostureValid() ) 160*cdf0e10cSrcweir { 161*cdf0e10cSrcweir aParms.maFontLetterForm = 162*cdf0e10cSrcweir rAttr->getCharPosture() == awt::FontSlant_NONE ? 163*cdf0e10cSrcweir rendering::PanoseLetterForm::ANYTHING : 164*cdf0e10cSrcweir rendering::PanoseLetterForm::OBLIQUE_CONTACT; 165*cdf0e10cSrcweir } 166*cdf0e10cSrcweir if( rAttr->isUnderlineModeValid() ) 167*cdf0e10cSrcweir { 168*cdf0e10cSrcweir aParms.maFontUnderline = 169*cdf0e10cSrcweir rAttr->getUnderlineMode(); 170*cdf0e10cSrcweir } 171*cdf0e10cSrcweir } 172*cdf0e10cSrcweir 173*cdf0e10cSrcweir io_rCacheEntry.mpRenderer = ::cppcanvas::VCLFactory::getInstance().createRenderer( rDestinationCanvas, 174*cdf0e10cSrcweir *rMtf.get(), 175*cdf0e10cSrcweir aParms ); 176*cdf0e10cSrcweir 177*cdf0e10cSrcweir io_rCacheEntry.mpMtf = rMtf; 178*cdf0e10cSrcweir io_rCacheEntry.mpDestinationCanvas = rDestinationCanvas; 179*cdf0e10cSrcweir 180*cdf0e10cSrcweir // also invalidate alpha compositing bitmap (created 181*cdf0e10cSrcweir // new renderer, which possibly generates different 182*cdf0e10cSrcweir // output). Do NOT invalidate, if we're incidentally 183*cdf0e10cSrcweir // rendering INTO it. 184*cdf0e10cSrcweir if( rDestinationCanvas != io_rCacheEntry.mpLastBitmapCanvas ) 185*cdf0e10cSrcweir { 186*cdf0e10cSrcweir io_rCacheEntry.mpLastBitmapCanvas.reset(); 187*cdf0e10cSrcweir io_rCacheEntry.mpLastBitmap.reset(); 188*cdf0e10cSrcweir } 189*cdf0e10cSrcweir } 190*cdf0e10cSrcweir 191*cdf0e10cSrcweir return io_rCacheEntry.mpRenderer; 192*cdf0e10cSrcweir } 193*cdf0e10cSrcweir 194*cdf0e10cSrcweir bool ViewShape::draw( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas, 195*cdf0e10cSrcweir const GDIMetaFileSharedPtr& rMtf, 196*cdf0e10cSrcweir const ShapeAttributeLayerSharedPtr& rAttr, 197*cdf0e10cSrcweir const ::basegfx::B2DHomMatrix& rTransform, 198*cdf0e10cSrcweir const ::basegfx::B2DPolyPolygon* pClip, 199*cdf0e10cSrcweir const VectorOfDocTreeNodes& rSubsets ) const 200*cdf0e10cSrcweir { 201*cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::draw()" ); 202*cdf0e10cSrcweir 203*cdf0e10cSrcweir ::cppcanvas::RendererSharedPtr pRenderer( 204*cdf0e10cSrcweir getRenderer( rDestinationCanvas, rMtf, rAttr ) ); 205*cdf0e10cSrcweir 206*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( pRenderer, "ViewShape::draw(): Invalid renderer" ); 207*cdf0e10cSrcweir 208*cdf0e10cSrcweir pRenderer->setTransformation( rTransform ); 209*cdf0e10cSrcweir #if defined(VERBOSE) && OSL_DEBUG_LEVEL > 0 210*cdf0e10cSrcweir rendering::RenderState aRenderState; 211*cdf0e10cSrcweir ::canvas::tools::initRenderState(aRenderState); 212*cdf0e10cSrcweir ::canvas::tools::setRenderStateTransform(aRenderState, 213*cdf0e10cSrcweir rTransform); 214*cdf0e10cSrcweir aRenderState.DeviceColor.realloc(4); 215*cdf0e10cSrcweir aRenderState.DeviceColor[0] = 1.0; 216*cdf0e10cSrcweir aRenderState.DeviceColor[1] = 0.0; 217*cdf0e10cSrcweir aRenderState.DeviceColor[2] = 0.0; 218*cdf0e10cSrcweir aRenderState.DeviceColor[3] = 1.0; 219*cdf0e10cSrcweir 220*cdf0e10cSrcweir try 221*cdf0e10cSrcweir { 222*cdf0e10cSrcweir rDestinationCanvas->getUNOCanvas()->drawLine( geometry::RealPoint2D(0.0,0.0), 223*cdf0e10cSrcweir geometry::RealPoint2D(1.0,1.0), 224*cdf0e10cSrcweir rDestinationCanvas->getViewState(), 225*cdf0e10cSrcweir aRenderState ); 226*cdf0e10cSrcweir rDestinationCanvas->getUNOCanvas()->drawLine( geometry::RealPoint2D(1.0,0.0), 227*cdf0e10cSrcweir geometry::RealPoint2D(0.0,1.0), 228*cdf0e10cSrcweir rDestinationCanvas->getViewState(), 229*cdf0e10cSrcweir aRenderState ); 230*cdf0e10cSrcweir } 231*cdf0e10cSrcweir catch( uno::Exception& ) 232*cdf0e10cSrcweir { 233*cdf0e10cSrcweir DBG_UNHANDLED_EXCEPTION(); 234*cdf0e10cSrcweir } 235*cdf0e10cSrcweir #endif 236*cdf0e10cSrcweir if( pClip ) 237*cdf0e10cSrcweir pRenderer->setClip( *pClip ); 238*cdf0e10cSrcweir else 239*cdf0e10cSrcweir pRenderer->setClip(); 240*cdf0e10cSrcweir 241*cdf0e10cSrcweir if( rSubsets.empty() ) 242*cdf0e10cSrcweir { 243*cdf0e10cSrcweir return pRenderer->draw(); 244*cdf0e10cSrcweir } 245*cdf0e10cSrcweir else 246*cdf0e10cSrcweir { 247*cdf0e10cSrcweir // render subsets of whole metafile 248*cdf0e10cSrcweir // -------------------------------- 249*cdf0e10cSrcweir 250*cdf0e10cSrcweir bool bRet(true); 251*cdf0e10cSrcweir VectorOfDocTreeNodes::const_iterator aIter( rSubsets.begin() ); 252*cdf0e10cSrcweir const VectorOfDocTreeNodes::const_iterator aEnd ( rSubsets.end() ); 253*cdf0e10cSrcweir while( aIter != aEnd ) 254*cdf0e10cSrcweir { 255*cdf0e10cSrcweir if( !pRenderer->drawSubset( aIter->getStartIndex(), 256*cdf0e10cSrcweir aIter->getEndIndex() ) ) 257*cdf0e10cSrcweir bRet = false; 258*cdf0e10cSrcweir 259*cdf0e10cSrcweir ++aIter; 260*cdf0e10cSrcweir } 261*cdf0e10cSrcweir 262*cdf0e10cSrcweir return bRet; 263*cdf0e10cSrcweir } 264*cdf0e10cSrcweir } 265*cdf0e10cSrcweir 266*cdf0e10cSrcweir namespace 267*cdf0e10cSrcweir { 268*cdf0e10cSrcweir /// Convert untransformed shape update area to device pixel. 269*cdf0e10cSrcweir ::basegfx::B2DRectangle shapeArea2AreaPixel( const ::basegfx::B2DHomMatrix& rCanvasTransformation, 270*cdf0e10cSrcweir const ::basegfx::B2DRectangle& rUntransformedArea ) 271*cdf0e10cSrcweir { 272*cdf0e10cSrcweir // convert area to pixel, and add anti-aliasing border 273*cdf0e10cSrcweir 274*cdf0e10cSrcweir // TODO(P1): Should the view transform some 275*cdf0e10cSrcweir // day contain rotation/shear, transforming 276*cdf0e10cSrcweir // the original bounds with the total 277*cdf0e10cSrcweir // transformation might result in smaller 278*cdf0e10cSrcweir // overall bounds. 279*cdf0e10cSrcweir 280*cdf0e10cSrcweir ::basegfx::B2DRectangle aBoundsPixel; 281*cdf0e10cSrcweir ::canvas::tools::calcTransformedRectBounds( aBoundsPixel, 282*cdf0e10cSrcweir rUntransformedArea, 283*cdf0e10cSrcweir rCanvasTransformation ); 284*cdf0e10cSrcweir 285*cdf0e10cSrcweir // add antialiasing border around the shape (AA 286*cdf0e10cSrcweir // touches pixel _outside_ the nominal bound rect) 287*cdf0e10cSrcweir aBoundsPixel.grow( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE ); 288*cdf0e10cSrcweir 289*cdf0e10cSrcweir return aBoundsPixel; 290*cdf0e10cSrcweir } 291*cdf0e10cSrcweir 292*cdf0e10cSrcweir /// Convert shape unit rect to device pixel. 293*cdf0e10cSrcweir ::basegfx::B2DRectangle calcUpdateAreaPixel( const ::basegfx::B2DRectangle& rUnitBounds, 294*cdf0e10cSrcweir const ::basegfx::B2DHomMatrix& rShapeTransformation, 295*cdf0e10cSrcweir const ::basegfx::B2DHomMatrix& rCanvasTransformation, 296*cdf0e10cSrcweir const ShapeAttributeLayerSharedPtr& pAttr ) 297*cdf0e10cSrcweir { 298*cdf0e10cSrcweir // calc update area for whole shape (including 299*cdf0e10cSrcweir // character scaling) 300*cdf0e10cSrcweir return shapeArea2AreaPixel( rCanvasTransformation, 301*cdf0e10cSrcweir getShapeUpdateArea( rUnitBounds, 302*cdf0e10cSrcweir rShapeTransformation, 303*cdf0e10cSrcweir pAttr ) ); 304*cdf0e10cSrcweir } 305*cdf0e10cSrcweir } 306*cdf0e10cSrcweir 307*cdf0e10cSrcweir bool ViewShape::renderSprite( const ViewLayerSharedPtr& rViewLayer, 308*cdf0e10cSrcweir const GDIMetaFileSharedPtr& rMtf, 309*cdf0e10cSrcweir const ::basegfx::B2DRectangle& rOrigBounds, 310*cdf0e10cSrcweir const ::basegfx::B2DRectangle& rBounds, 311*cdf0e10cSrcweir const ::basegfx::B2DRectangle& rUnitBounds, 312*cdf0e10cSrcweir int nUpdateFlags, 313*cdf0e10cSrcweir const ShapeAttributeLayerSharedPtr& pAttr, 314*cdf0e10cSrcweir const VectorOfDocTreeNodes& rSubsets, 315*cdf0e10cSrcweir double nPrio, 316*cdf0e10cSrcweir bool bIsVisible ) const 317*cdf0e10cSrcweir { 318*cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::renderSprite()" ); 319*cdf0e10cSrcweir 320*cdf0e10cSrcweir // TODO(P1): For multiple views, it might pay off to reorg Shape and ViewShape, 321*cdf0e10cSrcweir // in that all the common setup steps here are refactored to Shape (would then 322*cdf0e10cSrcweir // have to be performed only _once_ per Shape paint). 323*cdf0e10cSrcweir 324*cdf0e10cSrcweir if( !bIsVisible || 325*cdf0e10cSrcweir rUnitBounds.isEmpty() || 326*cdf0e10cSrcweir rOrigBounds.isEmpty() || 327*cdf0e10cSrcweir rBounds.isEmpty() ) 328*cdf0e10cSrcweir { 329*cdf0e10cSrcweir // shape is invisible or has zero size, no need to 330*cdf0e10cSrcweir // update anything. 331*cdf0e10cSrcweir if( mpSprite ) 332*cdf0e10cSrcweir mpSprite->hide(); 333*cdf0e10cSrcweir 334*cdf0e10cSrcweir return true; 335*cdf0e10cSrcweir } 336*cdf0e10cSrcweir 337*cdf0e10cSrcweir 338*cdf0e10cSrcweir // calc sprite position, size and content transformation 339*cdf0e10cSrcweir // ===================================================== 340*cdf0e10cSrcweir 341*cdf0e10cSrcweir // the shape transformation for a sprite is always a 342*cdf0e10cSrcweir // simple scale-up to the nominal shape size. Everything 343*cdf0e10cSrcweir // else is handled via the sprite transformation 344*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aNonTranslationalShapeTransformation; 345*cdf0e10cSrcweir aNonTranslationalShapeTransformation.scale( rOrigBounds.getWidth(), 346*cdf0e10cSrcweir rOrigBounds.getHeight() ); 347*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aShapeTransformation( aNonTranslationalShapeTransformation ); 348*cdf0e10cSrcweir aShapeTransformation.translate( rOrigBounds.getMinX(), 349*cdf0e10cSrcweir rOrigBounds.getMinY() ); 350*cdf0e10cSrcweir 351*cdf0e10cSrcweir const ::basegfx::B2DHomMatrix& rCanvasTransform( 352*cdf0e10cSrcweir rViewLayer->getSpriteTransformation() ); 353*cdf0e10cSrcweir 354*cdf0e10cSrcweir // area actually needed for the sprite 355*cdf0e10cSrcweir const ::basegfx::B2DRectangle& rSpriteBoundsPixel( 356*cdf0e10cSrcweir calcUpdateAreaPixel( rUnitBounds, 357*cdf0e10cSrcweir aShapeTransformation, 358*cdf0e10cSrcweir rCanvasTransform, 359*cdf0e10cSrcweir pAttr ) ); 360*cdf0e10cSrcweir 361*cdf0e10cSrcweir // actual area for the shape (without subsetting, but 362*cdf0e10cSrcweir // including char scaling) 363*cdf0e10cSrcweir const ::basegfx::B2DRectangle& rShapeBoundsPixel( 364*cdf0e10cSrcweir calcUpdateAreaPixel( ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0), 365*cdf0e10cSrcweir aShapeTransformation, 366*cdf0e10cSrcweir rCanvasTransform, 367*cdf0e10cSrcweir pAttr ) ); 368*cdf0e10cSrcweir 369*cdf0e10cSrcweir // nominal area for the shape (without subsetting, without 370*cdf0e10cSrcweir // char scaling). NOTE: to cancel the shape translation, 371*cdf0e10cSrcweir // contained in rSpriteBoundsPixel, this is _without_ any 372*cdf0e10cSrcweir // translational component (fixed along with #121921#). 373*cdf0e10cSrcweir ::basegfx::B2DRectangle aLogShapeBounds; 374*cdf0e10cSrcweir const ::basegfx::B2DRectangle& rNominalShapeBoundsPixel( 375*cdf0e10cSrcweir shapeArea2AreaPixel( rCanvasTransform, 376*cdf0e10cSrcweir ::canvas::tools::calcTransformedRectBounds( 377*cdf0e10cSrcweir aLogShapeBounds, 378*cdf0e10cSrcweir ::basegfx::B2DRectangle(0.0,0.0,1.0,1.0), 379*cdf0e10cSrcweir aNonTranslationalShapeTransformation ) ) ); 380*cdf0e10cSrcweir 381*cdf0e10cSrcweir // create (or resize) sprite with sprite's pixel size, if 382*cdf0e10cSrcweir // not done already 383*cdf0e10cSrcweir const ::basegfx::B2DSize& rSpriteSizePixel(rSpriteBoundsPixel.getRange()); 384*cdf0e10cSrcweir if( !mpSprite ) 385*cdf0e10cSrcweir { 386*cdf0e10cSrcweir mpSprite.reset( 387*cdf0e10cSrcweir new AnimatedSprite( mpViewLayer, 388*cdf0e10cSrcweir rSpriteSizePixel, 389*cdf0e10cSrcweir nPrio )); 390*cdf0e10cSrcweir } 391*cdf0e10cSrcweir else 392*cdf0e10cSrcweir { 393*cdf0e10cSrcweir // TODO(F2): when the sprite _actually_ gets resized, 394*cdf0e10cSrcweir // content needs a repaint! 395*cdf0e10cSrcweir mpSprite->resize( rSpriteSizePixel ); 396*cdf0e10cSrcweir } 397*cdf0e10cSrcweir 398*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( mpSprite, "ViewShape::renderSprite(): No sprite" ); 399*cdf0e10cSrcweir 400*cdf0e10cSrcweir VERBOSE_TRACE( "ViewShape::renderSprite(): Rendering sprite 0x%X", 401*cdf0e10cSrcweir mpSprite.get() ); 402*cdf0e10cSrcweir 403*cdf0e10cSrcweir 404*cdf0e10cSrcweir // always show the sprite (might have been hidden before) 405*cdf0e10cSrcweir mpSprite->show(); 406*cdf0e10cSrcweir 407*cdf0e10cSrcweir // determine center of sprite output position in pixel 408*cdf0e10cSrcweir // (assumption here: all shape transformations have the 409*cdf0e10cSrcweir // shape center as the pivot point). From that, subtract 410*cdf0e10cSrcweir // distance of rSpriteBoundsPixel's left, top edge from 411*cdf0e10cSrcweir // rShapeBoundsPixel's center. This moves the sprite at 412*cdf0e10cSrcweir // the appropriate output position within the virtual 413*cdf0e10cSrcweir // rShapeBoundsPixel area. 414*cdf0e10cSrcweir ::basegfx::B2DPoint aSpritePosPixel( rBounds.getCenter() ); 415*cdf0e10cSrcweir aSpritePosPixel *= rCanvasTransform; 416*cdf0e10cSrcweir aSpritePosPixel -= rShapeBoundsPixel.getCenter() - rSpriteBoundsPixel.getMinimum(); 417*cdf0e10cSrcweir 418*cdf0e10cSrcweir // the difference between rShapeBoundsPixel and 419*cdf0e10cSrcweir // rSpriteBoundsPixel upper, left corner is: the offset we 420*cdf0e10cSrcweir // have to move sprite output to the right, top (to make 421*cdf0e10cSrcweir // the desired subset content visible at all) 422*cdf0e10cSrcweir const ::basegfx::B2DSize& rSpriteCorrectionOffset( 423*cdf0e10cSrcweir rSpriteBoundsPixel.getMinimum() - rNominalShapeBoundsPixel.getMinimum() ); 424*cdf0e10cSrcweir 425*cdf0e10cSrcweir // offset added top, left for anti-aliasing (otherwise, 426*cdf0e10cSrcweir // shapes fully filling the sprite will have anti-aliased 427*cdf0e10cSrcweir // pixel cut off) 428*cdf0e10cSrcweir const ::basegfx::B2DSize aAAOffset( 429*cdf0e10cSrcweir ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE, 430*cdf0e10cSrcweir ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE ); 431*cdf0e10cSrcweir 432*cdf0e10cSrcweir // set pixel output offset to sprite: we always leave 433*cdf0e10cSrcweir // ANTIALIASING_EXTRA_SIZE room atop and to the left, and, 434*cdf0e10cSrcweir // what's more, for subsetted shapes, we _have_ to cancel 435*cdf0e10cSrcweir // the effect of the shape renderer outputting the subset 436*cdf0e10cSrcweir // at its absolute position inside the shape, instead of 437*cdf0e10cSrcweir // at the origin. 438*cdf0e10cSrcweir // NOTE: As for now, sprites are always positioned on 439*cdf0e10cSrcweir // integer pixel positions on screen, have to round to 440*cdf0e10cSrcweir // nearest integer here, too (fixed along with #121921#) 441*cdf0e10cSrcweir mpSprite->setPixelOffset( 442*cdf0e10cSrcweir aAAOffset - ::basegfx::B2DSize( 443*cdf0e10cSrcweir ::basegfx::fround( rSpriteCorrectionOffset.getX() ), 444*cdf0e10cSrcweir ::basegfx::fround( rSpriteCorrectionOffset.getY() ) ) ); 445*cdf0e10cSrcweir 446*cdf0e10cSrcweir // always set sprite position and transformation, since 447*cdf0e10cSrcweir // they do not relate directly to the update flags 448*cdf0e10cSrcweir // (e.g. sprite position changes when sprite size changes) 449*cdf0e10cSrcweir mpSprite->movePixel( aSpritePosPixel ); 450*cdf0e10cSrcweir mpSprite->transform( getSpriteTransformation( rSpriteSizePixel, 451*cdf0e10cSrcweir rOrigBounds.getRange(), 452*cdf0e10cSrcweir pAttr ) ); 453*cdf0e10cSrcweir 454*cdf0e10cSrcweir 455*cdf0e10cSrcweir // process flags 456*cdf0e10cSrcweir // ============= 457*cdf0e10cSrcweir 458*cdf0e10cSrcweir bool bRedrawRequired( mbForceUpdate || (nUpdateFlags & FORCE) ); 459*cdf0e10cSrcweir 460*cdf0e10cSrcweir if( mbForceUpdate || (nUpdateFlags & ALPHA) ) 461*cdf0e10cSrcweir { 462*cdf0e10cSrcweir mpSprite->setAlpha( (pAttr && pAttr->isAlphaValid()) ? 463*cdf0e10cSrcweir ::basegfx::clamp(pAttr->getAlpha(), 464*cdf0e10cSrcweir 0.0, 465*cdf0e10cSrcweir 1.0) : 466*cdf0e10cSrcweir 1.0 ); 467*cdf0e10cSrcweir } 468*cdf0e10cSrcweir if( mbForceUpdate || (nUpdateFlags & CLIP) ) 469*cdf0e10cSrcweir { 470*cdf0e10cSrcweir if( pAttr && pAttr->isClipValid() ) 471*cdf0e10cSrcweir { 472*cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aClipPoly( pAttr->getClip() ); 473*cdf0e10cSrcweir 474*cdf0e10cSrcweir // extract linear part of canvas view transformation 475*cdf0e10cSrcweir // (linear means: without translational components) 476*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aViewTransform( 477*cdf0e10cSrcweir mpViewLayer->getTransformation() ); 478*cdf0e10cSrcweir aViewTransform.set( 0, 2, 0.0 ); 479*cdf0e10cSrcweir aViewTransform.set( 1, 2, 0.0 ); 480*cdf0e10cSrcweir 481*cdf0e10cSrcweir // make the clip 2*ANTIALIASING_EXTRA_SIZE larger 482*cdf0e10cSrcweir // such that it's again centered over the sprite. 483*cdf0e10cSrcweir aViewTransform.scale(rSpriteSizePixel.getX()/ 484*cdf0e10cSrcweir (rSpriteSizePixel.getX()-2*::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE), 485*cdf0e10cSrcweir rSpriteSizePixel.getY()/ 486*cdf0e10cSrcweir (rSpriteSizePixel.getY()-2*::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE)); 487*cdf0e10cSrcweir 488*cdf0e10cSrcweir // transform clip polygon from view to device 489*cdf0e10cSrcweir // coordinate space 490*cdf0e10cSrcweir aClipPoly.transform( aViewTransform ); 491*cdf0e10cSrcweir 492*cdf0e10cSrcweir mpSprite->clip( aClipPoly ); 493*cdf0e10cSrcweir } 494*cdf0e10cSrcweir else 495*cdf0e10cSrcweir mpSprite->clip(); 496*cdf0e10cSrcweir } 497*cdf0e10cSrcweir if( mbForceUpdate || (nUpdateFlags & CONTENT) ) 498*cdf0e10cSrcweir { 499*cdf0e10cSrcweir bRedrawRequired = true; 500*cdf0e10cSrcweir 501*cdf0e10cSrcweir // TODO(P1): maybe provide some appearance change methods at 502*cdf0e10cSrcweir // the Renderer interface 503*cdf0e10cSrcweir 504*cdf0e10cSrcweir // force the renderer to be regenerated below, for the 505*cdf0e10cSrcweir // different attributes to take effect 506*cdf0e10cSrcweir invalidateRenderer(); 507*cdf0e10cSrcweir } 508*cdf0e10cSrcweir 509*cdf0e10cSrcweir mbForceUpdate = false; 510*cdf0e10cSrcweir 511*cdf0e10cSrcweir if( !bRedrawRequired ) 512*cdf0e10cSrcweir return true; 513*cdf0e10cSrcweir 514*cdf0e10cSrcweir 515*cdf0e10cSrcweir // sprite needs repaint - output to sprite canvas 516*cdf0e10cSrcweir // ============================================== 517*cdf0e10cSrcweir 518*cdf0e10cSrcweir ::cppcanvas::CanvasSharedPtr pContentCanvas( mpSprite->getContentCanvas() ); 519*cdf0e10cSrcweir 520*cdf0e10cSrcweir return draw( pContentCanvas, 521*cdf0e10cSrcweir rMtf, 522*cdf0e10cSrcweir pAttr, 523*cdf0e10cSrcweir aShapeTransformation, 524*cdf0e10cSrcweir NULL, // clipping is done via Sprite::clip() 525*cdf0e10cSrcweir rSubsets ); 526*cdf0e10cSrcweir } 527*cdf0e10cSrcweir 528*cdf0e10cSrcweir bool ViewShape::render( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas, 529*cdf0e10cSrcweir const GDIMetaFileSharedPtr& rMtf, 530*cdf0e10cSrcweir const ::basegfx::B2DRectangle& rBounds, 531*cdf0e10cSrcweir const ::basegfx::B2DRectangle& rUpdateBounds, 532*cdf0e10cSrcweir int nUpdateFlags, 533*cdf0e10cSrcweir const ShapeAttributeLayerSharedPtr& pAttr, 534*cdf0e10cSrcweir const VectorOfDocTreeNodes& rSubsets, 535*cdf0e10cSrcweir bool bIsVisible ) const 536*cdf0e10cSrcweir { 537*cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::render()" ); 538*cdf0e10cSrcweir 539*cdf0e10cSrcweir // TODO(P1): For multiple views, it might pay off to reorg Shape and ViewShape, 540*cdf0e10cSrcweir // in that all the common setup steps here are refactored to Shape (would then 541*cdf0e10cSrcweir // have to be performed only _once_ per Shape paint). 542*cdf0e10cSrcweir 543*cdf0e10cSrcweir if( !bIsVisible ) 544*cdf0e10cSrcweir { 545*cdf0e10cSrcweir VERBOSE_TRACE( "ViewShape::render(): skipping shape %X", this ); 546*cdf0e10cSrcweir 547*cdf0e10cSrcweir // shape is invisible, no need to update anything. 548*cdf0e10cSrcweir return true; 549*cdf0e10cSrcweir } 550*cdf0e10cSrcweir 551*cdf0e10cSrcweir // since we have no sprite here, _any_ update request 552*cdf0e10cSrcweir // translates into a required redraw. 553*cdf0e10cSrcweir bool bRedrawRequired( mbForceUpdate || nUpdateFlags != 0 ); 554*cdf0e10cSrcweir 555*cdf0e10cSrcweir if( (nUpdateFlags & CONTENT) ) 556*cdf0e10cSrcweir { 557*cdf0e10cSrcweir // TODO(P1): maybe provide some appearance change methods at 558*cdf0e10cSrcweir // the Renderer interface 559*cdf0e10cSrcweir 560*cdf0e10cSrcweir // force the renderer to be regenerated below, for the 561*cdf0e10cSrcweir // different attributes to take effect 562*cdf0e10cSrcweir invalidateRenderer(); 563*cdf0e10cSrcweir } 564*cdf0e10cSrcweir 565*cdf0e10cSrcweir mbForceUpdate = false; 566*cdf0e10cSrcweir 567*cdf0e10cSrcweir if( !bRedrawRequired ) 568*cdf0e10cSrcweir return true; 569*cdf0e10cSrcweir 570*cdf0e10cSrcweir VERBOSE_TRACE( "ViewShape::render(): rendering shape %X at position (%f,%f)", 571*cdf0e10cSrcweir this, 572*cdf0e10cSrcweir rBounds.getMinX(), 573*cdf0e10cSrcweir rBounds.getMinY() ); 574*cdf0e10cSrcweir 575*cdf0e10cSrcweir 576*cdf0e10cSrcweir // shape needs repaint - setup all that's needed 577*cdf0e10cSrcweir // --------------------------------------------- 578*cdf0e10cSrcweir 579*cdf0e10cSrcweir boost::optional<basegfx::B2DPolyPolygon> aClip; 580*cdf0e10cSrcweir 581*cdf0e10cSrcweir if( pAttr ) 582*cdf0e10cSrcweir { 583*cdf0e10cSrcweir // setup clip poly 584*cdf0e10cSrcweir if( pAttr->isClipValid() ) 585*cdf0e10cSrcweir aClip.reset( pAttr->getClip() ); 586*cdf0e10cSrcweir 587*cdf0e10cSrcweir // emulate global shape alpha by first rendering into 588*cdf0e10cSrcweir // a temp bitmap, and then to screen (this would have 589*cdf0e10cSrcweir // been much easier if we'd be currently a sprite - 590*cdf0e10cSrcweir // see above) 591*cdf0e10cSrcweir if( pAttr->isAlphaValid() ) 592*cdf0e10cSrcweir { 593*cdf0e10cSrcweir const double nAlpha( pAttr->getAlpha() ); 594*cdf0e10cSrcweir 595*cdf0e10cSrcweir if( !::basegfx::fTools::equalZero( nAlpha ) && 596*cdf0e10cSrcweir !::rtl::math::approxEqual(nAlpha, 1.0) ) 597*cdf0e10cSrcweir { 598*cdf0e10cSrcweir // render with global alpha - have to prepare 599*cdf0e10cSrcweir // a bitmap, and render that with modulated 600*cdf0e10cSrcweir // alpha 601*cdf0e10cSrcweir // ------------------------------------------- 602*cdf0e10cSrcweir 603*cdf0e10cSrcweir const ::basegfx::B2DHomMatrix aTransform( 604*cdf0e10cSrcweir getShapeTransformation( rBounds, 605*cdf0e10cSrcweir pAttr ) ); 606*cdf0e10cSrcweir 607*cdf0e10cSrcweir // TODO(P1): Should the view transform some 608*cdf0e10cSrcweir // day contain rotation/shear, transforming 609*cdf0e10cSrcweir // the original bounds with the total 610*cdf0e10cSrcweir // transformation might result in smaller 611*cdf0e10cSrcweir // overall bounds. 612*cdf0e10cSrcweir 613*cdf0e10cSrcweir // determine output rect of _shape update 614*cdf0e10cSrcweir // area_ in device pixel 615*cdf0e10cSrcweir const ::basegfx::B2DHomMatrix aCanvasTransform( 616*cdf0e10cSrcweir rDestinationCanvas->getTransformation() ); 617*cdf0e10cSrcweir ::basegfx::B2DRectangle aTmpRect; 618*cdf0e10cSrcweir ::canvas::tools::calcTransformedRectBounds( aTmpRect, 619*cdf0e10cSrcweir rUpdateBounds, 620*cdf0e10cSrcweir aCanvasTransform ); 621*cdf0e10cSrcweir 622*cdf0e10cSrcweir // pixel size of cache bitmap: round up to 623*cdf0e10cSrcweir // nearest int 624*cdf0e10cSrcweir const ::basegfx::B2ISize aBmpSize( static_cast<sal_Int32>( aTmpRect.getWidth() )+1, 625*cdf0e10cSrcweir static_cast<sal_Int32>( aTmpRect.getHeight() )+1 ); 626*cdf0e10cSrcweir 627*cdf0e10cSrcweir // try to fetch temporary surface for alpha 628*cdf0e10cSrcweir // compositing (to achieve the global alpha 629*cdf0e10cSrcweir // blend effect, have to first render shape as 630*cdf0e10cSrcweir // a whole, then blit that surface with global 631*cdf0e10cSrcweir // alpha to the destination) 632*cdf0e10cSrcweir const RendererCacheVector::iterator aCompositingSurface( 633*cdf0e10cSrcweir getCacheEntry( rDestinationCanvas ) ); 634*cdf0e10cSrcweir 635*cdf0e10cSrcweir if( !aCompositingSurface->mpLastBitmapCanvas || 636*cdf0e10cSrcweir aCompositingSurface->mpLastBitmapCanvas->getSize() != aBmpSize ) 637*cdf0e10cSrcweir { 638*cdf0e10cSrcweir // create a bitmap of appropriate size 639*cdf0e10cSrcweir ::cppcanvas::BitmapSharedPtr pBitmap( 640*cdf0e10cSrcweir ::cppcanvas::BaseGfxFactory::getInstance().createAlphaBitmap( 641*cdf0e10cSrcweir rDestinationCanvas, 642*cdf0e10cSrcweir aBmpSize ) ); 643*cdf0e10cSrcweir 644*cdf0e10cSrcweir ENSURE_OR_THROW(pBitmap, 645*cdf0e10cSrcweir "ViewShape::render(): Could not create compositing surface"); 646*cdf0e10cSrcweir 647*cdf0e10cSrcweir aCompositingSurface->mpDestinationCanvas = rDestinationCanvas; 648*cdf0e10cSrcweir aCompositingSurface->mpLastBitmap = pBitmap; 649*cdf0e10cSrcweir aCompositingSurface->mpLastBitmapCanvas = pBitmap->getBitmapCanvas(); 650*cdf0e10cSrcweir } 651*cdf0e10cSrcweir 652*cdf0e10cSrcweir // buffer aCompositingSurface iterator content 653*cdf0e10cSrcweir // - said one might get invalidated during 654*cdf0e10cSrcweir // draw() below. 655*cdf0e10cSrcweir ::cppcanvas::BitmapCanvasSharedPtr pBitmapCanvas( 656*cdf0e10cSrcweir aCompositingSurface->mpLastBitmapCanvas ); 657*cdf0e10cSrcweir 658*cdf0e10cSrcweir ::cppcanvas::BitmapSharedPtr pBitmap( 659*cdf0e10cSrcweir aCompositingSurface->mpLastBitmap); 660*cdf0e10cSrcweir 661*cdf0e10cSrcweir // setup bitmap canvas transformation - 662*cdf0e10cSrcweir // which happens to be the destination 663*cdf0e10cSrcweir // canvas transformation without any 664*cdf0e10cSrcweir // translational components. 665*cdf0e10cSrcweir // 666*cdf0e10cSrcweir // But then, the render transformation as 667*cdf0e10cSrcweir // calculated by getShapeTransformation() 668*cdf0e10cSrcweir // above outputs the shape at its real 669*cdf0e10cSrcweir // destination position. Thus, we have to 670*cdf0e10cSrcweir // offset the output back to the origin, 671*cdf0e10cSrcweir // for which we simply plug in the 672*cdf0e10cSrcweir // negative position of the left, top edge 673*cdf0e10cSrcweir // of the shape's bound rect in device 674*cdf0e10cSrcweir // pixel into aLinearTransform below. 675*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aAdjustedCanvasTransform( aCanvasTransform ); 676*cdf0e10cSrcweir aAdjustedCanvasTransform.translate( -aTmpRect.getMinX(), 677*cdf0e10cSrcweir -aTmpRect.getMinY() ); 678*cdf0e10cSrcweir 679*cdf0e10cSrcweir pBitmapCanvas->setTransformation( aAdjustedCanvasTransform ); 680*cdf0e10cSrcweir 681*cdf0e10cSrcweir // TODO(P2): If no update flags, or only 682*cdf0e10cSrcweir // alpha_update is set, we can save us the 683*cdf0e10cSrcweir // rendering into the bitmap (uh, it's not 684*cdf0e10cSrcweir // _that_ easy - for a forced redraw, 685*cdf0e10cSrcweir // e.g. when ending an animation, we always 686*cdf0e10cSrcweir // get UPDATE_FORCE here). 687*cdf0e10cSrcweir 688*cdf0e10cSrcweir // render into this bitmap 689*cdf0e10cSrcweir if( !draw( pBitmapCanvas, 690*cdf0e10cSrcweir rMtf, 691*cdf0e10cSrcweir pAttr, 692*cdf0e10cSrcweir aTransform, 693*cdf0e10cSrcweir !aClip ? NULL : &(*aClip), 694*cdf0e10cSrcweir rSubsets ) ) 695*cdf0e10cSrcweir { 696*cdf0e10cSrcweir return false; 697*cdf0e10cSrcweir } 698*cdf0e10cSrcweir 699*cdf0e10cSrcweir // render bitmap to screen, with given global 700*cdf0e10cSrcweir // alpha. Since the bitmap already contains 701*cdf0e10cSrcweir // pixel-equivalent output, we have to use the 702*cdf0e10cSrcweir // inverse view transformation, adjusted with 703*cdf0e10cSrcweir // the final shape output position (note: 704*cdf0e10cSrcweir // cannot simply change the view 705*cdf0e10cSrcweir // transformation here, as that would affect a 706*cdf0e10cSrcweir // possibly set clip!) 707*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aBitmapTransform( aCanvasTransform ); 708*cdf0e10cSrcweir OSL_ENSURE( aBitmapTransform.isInvertible(), 709*cdf0e10cSrcweir "ViewShape::render(): View transformation is singular!" ); 710*cdf0e10cSrcweir 711*cdf0e10cSrcweir aBitmapTransform.invert(); 712*cdf0e10cSrcweir 713*cdf0e10cSrcweir const basegfx::B2DHomMatrix aTranslation(basegfx::tools::createTranslateB2DHomMatrix( 714*cdf0e10cSrcweir aTmpRect.getMinX(), aTmpRect.getMinY())); 715*cdf0e10cSrcweir 716*cdf0e10cSrcweir aBitmapTransform = aBitmapTransform * aTranslation; 717*cdf0e10cSrcweir pBitmap->setTransformation( aBitmapTransform ); 718*cdf0e10cSrcweir 719*cdf0e10cSrcweir // finally, render bitmap alpha-modulated 720*cdf0e10cSrcweir pBitmap->drawAlphaModulated( nAlpha ); 721*cdf0e10cSrcweir 722*cdf0e10cSrcweir return true; 723*cdf0e10cSrcweir } 724*cdf0e10cSrcweir } 725*cdf0e10cSrcweir } 726*cdf0e10cSrcweir 727*cdf0e10cSrcweir // retrieve shape transformation, _with_ shape translation 728*cdf0e10cSrcweir // to actual page position. 729*cdf0e10cSrcweir const ::basegfx::B2DHomMatrix aTransform( 730*cdf0e10cSrcweir getShapeTransformation( rBounds, 731*cdf0e10cSrcweir pAttr ) ); 732*cdf0e10cSrcweir 733*cdf0e10cSrcweir return draw( rDestinationCanvas, 734*cdf0e10cSrcweir rMtf, 735*cdf0e10cSrcweir pAttr, 736*cdf0e10cSrcweir aTransform, 737*cdf0e10cSrcweir !aClip ? NULL : &(*aClip), 738*cdf0e10cSrcweir rSubsets ); 739*cdf0e10cSrcweir } 740*cdf0e10cSrcweir 741*cdf0e10cSrcweir 742*cdf0e10cSrcweir // ------------------------------------------------------------------------------------- 743*cdf0e10cSrcweir 744*cdf0e10cSrcweir ViewShape::ViewShape( const ViewLayerSharedPtr& rViewLayer ) : 745*cdf0e10cSrcweir mpViewLayer( rViewLayer ), 746*cdf0e10cSrcweir maRenderers(), 747*cdf0e10cSrcweir mpSprite(), 748*cdf0e10cSrcweir mbAnimationMode( false ), 749*cdf0e10cSrcweir mbForceUpdate( true ) 750*cdf0e10cSrcweir { 751*cdf0e10cSrcweir ENSURE_OR_THROW( mpViewLayer, "ViewShape::ViewShape(): Invalid View" ); 752*cdf0e10cSrcweir } 753*cdf0e10cSrcweir 754*cdf0e10cSrcweir ViewLayerSharedPtr ViewShape::getViewLayer() const 755*cdf0e10cSrcweir { 756*cdf0e10cSrcweir return mpViewLayer; 757*cdf0e10cSrcweir } 758*cdf0e10cSrcweir 759*cdf0e10cSrcweir ViewShape::RendererCacheVector::iterator ViewShape::getCacheEntry( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas ) const 760*cdf0e10cSrcweir { 761*cdf0e10cSrcweir // lookup destination canvas - is there already a renderer 762*cdf0e10cSrcweir // created for that target? 763*cdf0e10cSrcweir RendererCacheVector::iterator aIter; 764*cdf0e10cSrcweir const RendererCacheVector::iterator aEnd( maRenderers.end() ); 765*cdf0e10cSrcweir 766*cdf0e10cSrcweir // already there? 767*cdf0e10cSrcweir if( (aIter=::std::find_if( maRenderers.begin(), 768*cdf0e10cSrcweir aEnd, 769*cdf0e10cSrcweir ::boost::bind( 770*cdf0e10cSrcweir ::std::equal_to< ::cppcanvas::CanvasSharedPtr >(), 771*cdf0e10cSrcweir ::boost::cref( rDestinationCanvas ), 772*cdf0e10cSrcweir ::boost::bind( 773*cdf0e10cSrcweir &RendererCacheEntry::getDestinationCanvas, 774*cdf0e10cSrcweir _1 ) ) ) ) == aEnd ) 775*cdf0e10cSrcweir { 776*cdf0e10cSrcweir if( maRenderers.size() >= MAX_RENDER_CACHE_ENTRIES ) 777*cdf0e10cSrcweir { 778*cdf0e10cSrcweir // cache size exceeded - prune entries. For now, 779*cdf0e10cSrcweir // simply remove the first one, which of course 780*cdf0e10cSrcweir // breaks for more complex access schemes. But in 781*cdf0e10cSrcweir // general, this leads to most recently used 782*cdf0e10cSrcweir // entries to reside at the end of the vector. 783*cdf0e10cSrcweir maRenderers.erase( maRenderers.begin() ); 784*cdf0e10cSrcweir 785*cdf0e10cSrcweir // ATTENTION: after this, both aIter and aEnd are 786*cdf0e10cSrcweir // invalid! 787*cdf0e10cSrcweir } 788*cdf0e10cSrcweir 789*cdf0e10cSrcweir // not yet in cache - add default-constructed cache 790*cdf0e10cSrcweir // entry, to have something to return 791*cdf0e10cSrcweir maRenderers.push_back( RendererCacheEntry() ); 792*cdf0e10cSrcweir aIter = maRenderers.end()-1; 793*cdf0e10cSrcweir } 794*cdf0e10cSrcweir 795*cdf0e10cSrcweir return aIter; 796*cdf0e10cSrcweir } 797*cdf0e10cSrcweir 798*cdf0e10cSrcweir ::cppcanvas::RendererSharedPtr ViewShape::getRenderer( const ::cppcanvas::CanvasSharedPtr& rDestinationCanvas, 799*cdf0e10cSrcweir const GDIMetaFileSharedPtr& rMtf, 800*cdf0e10cSrcweir const ShapeAttributeLayerSharedPtr& rAttr ) const 801*cdf0e10cSrcweir { 802*cdf0e10cSrcweir // lookup destination canvas - is there already a renderer 803*cdf0e10cSrcweir // created for that target? 804*cdf0e10cSrcweir const RendererCacheVector::iterator aIter( 805*cdf0e10cSrcweir getCacheEntry( rDestinationCanvas ) ); 806*cdf0e10cSrcweir 807*cdf0e10cSrcweir // now we have a valid entry, either way. call prefetch() 808*cdf0e10cSrcweir // on it, nevertheless - maybe the metafile changed, and 809*cdf0e10cSrcweir // the renderer still needs an update (prefetch() will 810*cdf0e10cSrcweir // detect that) 811*cdf0e10cSrcweir if( prefetch( *aIter, 812*cdf0e10cSrcweir rDestinationCanvas, 813*cdf0e10cSrcweir rMtf, 814*cdf0e10cSrcweir rAttr ) ) 815*cdf0e10cSrcweir { 816*cdf0e10cSrcweir return aIter->mpRenderer; 817*cdf0e10cSrcweir } 818*cdf0e10cSrcweir else 819*cdf0e10cSrcweir { 820*cdf0e10cSrcweir // prefetch failed - renderer is invalid 821*cdf0e10cSrcweir return ::cppcanvas::RendererSharedPtr(); 822*cdf0e10cSrcweir } 823*cdf0e10cSrcweir } 824*cdf0e10cSrcweir 825*cdf0e10cSrcweir void ViewShape::invalidateRenderer() const 826*cdf0e10cSrcweir { 827*cdf0e10cSrcweir // simply clear the cache. Subsequent getRenderer() calls 828*cdf0e10cSrcweir // will regenerate the Renderers. 829*cdf0e10cSrcweir maRenderers.clear(); 830*cdf0e10cSrcweir } 831*cdf0e10cSrcweir 832*cdf0e10cSrcweir ::basegfx::B2DSize ViewShape::getAntialiasingBorder() const 833*cdf0e10cSrcweir { 834*cdf0e10cSrcweir ENSURE_OR_THROW( mpViewLayer->getCanvas(), 835*cdf0e10cSrcweir "ViewShape::getAntialiasingBorder(): Invalid ViewLayer canvas" ); 836*cdf0e10cSrcweir 837*cdf0e10cSrcweir const ::basegfx::B2DHomMatrix& rViewTransform( 838*cdf0e10cSrcweir mpViewLayer->getTransformation() ); 839*cdf0e10cSrcweir 840*cdf0e10cSrcweir // TODO(F1): As a quick shortcut (did not want to invert 841*cdf0e10cSrcweir // whole matrix here), taking only scale components of 842*cdf0e10cSrcweir // view transformation matrix. This will be wrong when 843*cdf0e10cSrcweir // e.g. shearing is involved. 844*cdf0e10cSrcweir const double nXBorder( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE / rViewTransform.get(0,0) ); 845*cdf0e10cSrcweir const double nYBorder( ::cppcanvas::Canvas::ANTIALIASING_EXTRA_SIZE / rViewTransform.get(1,1) ); 846*cdf0e10cSrcweir 847*cdf0e10cSrcweir return ::basegfx::B2DSize( nXBorder, 848*cdf0e10cSrcweir nYBorder ); 849*cdf0e10cSrcweir } 850*cdf0e10cSrcweir 851*cdf0e10cSrcweir bool ViewShape::enterAnimationMode() 852*cdf0e10cSrcweir { 853*cdf0e10cSrcweir mbForceUpdate = true; 854*cdf0e10cSrcweir mbAnimationMode = true; 855*cdf0e10cSrcweir 856*cdf0e10cSrcweir return true; 857*cdf0e10cSrcweir } 858*cdf0e10cSrcweir 859*cdf0e10cSrcweir void ViewShape::leaveAnimationMode() 860*cdf0e10cSrcweir { 861*cdf0e10cSrcweir mpSprite.reset(); 862*cdf0e10cSrcweir mbAnimationMode = false; 863*cdf0e10cSrcweir mbForceUpdate = true; 864*cdf0e10cSrcweir } 865*cdf0e10cSrcweir 866*cdf0e10cSrcweir bool ViewShape::update( const GDIMetaFileSharedPtr& rMtf, 867*cdf0e10cSrcweir const RenderArgs& rArgs, 868*cdf0e10cSrcweir int nUpdateFlags, 869*cdf0e10cSrcweir bool bIsVisible ) const 870*cdf0e10cSrcweir { 871*cdf0e10cSrcweir RTL_LOGFILE_CONTEXT( aLog, "::presentation::internal::ViewShape::update()" ); 872*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( mpViewLayer->getCanvas(), "ViewShape::update(): Invalid layer canvas" ); 873*cdf0e10cSrcweir 874*cdf0e10cSrcweir // Shall we render to a sprite, or to a plain canvas? 875*cdf0e10cSrcweir if( isBackgroundDetached() ) 876*cdf0e10cSrcweir return renderSprite( mpViewLayer, 877*cdf0e10cSrcweir rMtf, 878*cdf0e10cSrcweir rArgs.maOrigBounds, 879*cdf0e10cSrcweir rArgs.maBounds, 880*cdf0e10cSrcweir rArgs.maUnitBounds, 881*cdf0e10cSrcweir nUpdateFlags, 882*cdf0e10cSrcweir rArgs.mrAttr, 883*cdf0e10cSrcweir rArgs.mrSubsets, 884*cdf0e10cSrcweir rArgs.mnShapePriority, 885*cdf0e10cSrcweir bIsVisible ); 886*cdf0e10cSrcweir else 887*cdf0e10cSrcweir return render( mpViewLayer->getCanvas(), 888*cdf0e10cSrcweir rMtf, 889*cdf0e10cSrcweir rArgs.maBounds, 890*cdf0e10cSrcweir rArgs.maUpdateBounds, 891*cdf0e10cSrcweir nUpdateFlags, 892*cdf0e10cSrcweir rArgs.mrAttr, 893*cdf0e10cSrcweir rArgs.mrSubsets, 894*cdf0e10cSrcweir bIsVisible ); 895*cdf0e10cSrcweir } 896*cdf0e10cSrcweir 897*cdf0e10cSrcweir } 898*cdf0e10cSrcweir } 899