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