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