1*cdf0e10cSrcweir /************************************************************************* 2*cdf0e10cSrcweir * 3*cdf0e10cSrcweir * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4*cdf0e10cSrcweir * 5*cdf0e10cSrcweir * Copyright 2000, 2010 Oracle and/or its affiliates. 6*cdf0e10cSrcweir * 7*cdf0e10cSrcweir * OpenOffice.org - a multi-platform office productivity suite 8*cdf0e10cSrcweir * 9*cdf0e10cSrcweir * This file is part of OpenOffice.org. 10*cdf0e10cSrcweir * 11*cdf0e10cSrcweir * OpenOffice.org is free software: you can redistribute it and/or modify 12*cdf0e10cSrcweir * it under the terms of the GNU Lesser General Public License version 3 13*cdf0e10cSrcweir * only, as published by the Free Software Foundation. 14*cdf0e10cSrcweir * 15*cdf0e10cSrcweir * OpenOffice.org is distributed in the hope that it will be useful, 16*cdf0e10cSrcweir * but WITHOUT ANY WARRANTY; without even the implied warranty of 17*cdf0e10cSrcweir * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18*cdf0e10cSrcweir * GNU Lesser General Public License version 3 for more details 19*cdf0e10cSrcweir * (a copy is included in the LICENSE file that accompanied this code). 20*cdf0e10cSrcweir * 21*cdf0e10cSrcweir * You should have received a copy of the GNU Lesser General Public License 22*cdf0e10cSrcweir * version 3 along with OpenOffice.org. If not, see 23*cdf0e10cSrcweir * <http://www.openoffice.org/license.html> 24*cdf0e10cSrcweir * for a copy of the LGPLv3 License. 25*cdf0e10cSrcweir * 26*cdf0e10cSrcweir ************************************************************************/ 27*cdf0e10cSrcweir 28*cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove 29*cdf0e10cSrcweir #include "precompiled_canvas.hxx" 30*cdf0e10cSrcweir 31*cdf0e10cSrcweir #include <canvas/debug.hxx> 32*cdf0e10cSrcweir #include <tools/diagnose_ex.h> 33*cdf0e10cSrcweir 34*cdf0e10cSrcweir #include <rtl/logfile.hxx> 35*cdf0e10cSrcweir #include <rtl/math.hxx> 36*cdf0e10cSrcweir 37*cdf0e10cSrcweir #include <com/sun/star/rendering/TexturingMode.hpp> 38*cdf0e10cSrcweir #include <com/sun/star/rendering/CompositeOperation.hpp> 39*cdf0e10cSrcweir #include <com/sun/star/rendering/RepaintResult.hpp> 40*cdf0e10cSrcweir #include <com/sun/star/rendering/PathCapType.hpp> 41*cdf0e10cSrcweir #include <com/sun/star/rendering/PathJoinType.hpp> 42*cdf0e10cSrcweir 43*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 44*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx> 45*cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx> 46*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrixtools.hxx> 47*cdf0e10cSrcweir 48*cdf0e10cSrcweir #include <comphelper/sequence.hxx> 49*cdf0e10cSrcweir #include <canvas/canvastools.hxx> 50*cdf0e10cSrcweir 51*cdf0e10cSrcweir #include "dx_spritecanvas.hxx" 52*cdf0e10cSrcweir #include "dx_impltools.hxx" 53*cdf0e10cSrcweir #include "dx_vcltools.hxx" 54*cdf0e10cSrcweir #include "dx_canvasfont.hxx" 55*cdf0e10cSrcweir #include "dx_textlayout.hxx" 56*cdf0e10cSrcweir #include "dx_canvashelper.hxx" 57*cdf0e10cSrcweir 58*cdf0e10cSrcweir #include <algorithm> 59*cdf0e10cSrcweir 60*cdf0e10cSrcweir 61*cdf0e10cSrcweir using namespace ::com::sun::star; 62*cdf0e10cSrcweir 63*cdf0e10cSrcweir namespace dxcanvas 64*cdf0e10cSrcweir { 65*cdf0e10cSrcweir namespace 66*cdf0e10cSrcweir { 67*cdf0e10cSrcweir Gdiplus::LineCap gdiCapFromCap( sal_Int8 nCapType ) 68*cdf0e10cSrcweir { 69*cdf0e10cSrcweir switch( nCapType ) 70*cdf0e10cSrcweir { 71*cdf0e10cSrcweir case rendering::PathCapType::BUTT: 72*cdf0e10cSrcweir return Gdiplus::LineCapFlat; 73*cdf0e10cSrcweir 74*cdf0e10cSrcweir case rendering::PathCapType::ROUND: 75*cdf0e10cSrcweir return Gdiplus::LineCapRound; 76*cdf0e10cSrcweir 77*cdf0e10cSrcweir case rendering::PathCapType::SQUARE: 78*cdf0e10cSrcweir return Gdiplus::LineCapSquare; 79*cdf0e10cSrcweir 80*cdf0e10cSrcweir default: 81*cdf0e10cSrcweir ENSURE_OR_THROW( false, 82*cdf0e10cSrcweir "gdiCapFromCap(): Unexpected cap type" ); 83*cdf0e10cSrcweir } 84*cdf0e10cSrcweir 85*cdf0e10cSrcweir return Gdiplus::LineCapFlat; 86*cdf0e10cSrcweir } 87*cdf0e10cSrcweir 88*cdf0e10cSrcweir Gdiplus::LineJoin gdiJoinFromJoin( sal_Int8 nJoinType ) 89*cdf0e10cSrcweir { 90*cdf0e10cSrcweir switch( nJoinType ) 91*cdf0e10cSrcweir { 92*cdf0e10cSrcweir case rendering::PathJoinType::NONE: 93*cdf0e10cSrcweir OSL_ENSURE( false, 94*cdf0e10cSrcweir "gdiJoinFromJoin(): Join NONE not possible, mapping to MITER" ); 95*cdf0e10cSrcweir // FALLTHROUGH intended 96*cdf0e10cSrcweir case rendering::PathJoinType::MITER: 97*cdf0e10cSrcweir return Gdiplus::LineJoinMiter; 98*cdf0e10cSrcweir 99*cdf0e10cSrcweir case rendering::PathJoinType::ROUND: 100*cdf0e10cSrcweir return Gdiplus::LineJoinRound; 101*cdf0e10cSrcweir 102*cdf0e10cSrcweir case rendering::PathJoinType::BEVEL: 103*cdf0e10cSrcweir return Gdiplus::LineJoinBevel; 104*cdf0e10cSrcweir 105*cdf0e10cSrcweir default: 106*cdf0e10cSrcweir ENSURE_OR_THROW( false, 107*cdf0e10cSrcweir "gdiJoinFromJoin(): Unexpected join type" ); 108*cdf0e10cSrcweir } 109*cdf0e10cSrcweir 110*cdf0e10cSrcweir return Gdiplus::LineJoinMiter; 111*cdf0e10cSrcweir } 112*cdf0e10cSrcweir } 113*cdf0e10cSrcweir 114*cdf0e10cSrcweir CanvasHelper::CanvasHelper() : 115*cdf0e10cSrcweir mpGdiPlusUser( GDIPlusUser::createInstance() ), 116*cdf0e10cSrcweir mpDevice( NULL ), 117*cdf0e10cSrcweir mpGraphicsProvider(), 118*cdf0e10cSrcweir maOutputOffset() 119*cdf0e10cSrcweir { 120*cdf0e10cSrcweir } 121*cdf0e10cSrcweir 122*cdf0e10cSrcweir void CanvasHelper::disposing() 123*cdf0e10cSrcweir { 124*cdf0e10cSrcweir mpGraphicsProvider.reset(); 125*cdf0e10cSrcweir mpDevice = NULL; 126*cdf0e10cSrcweir mpGdiPlusUser.reset(); 127*cdf0e10cSrcweir } 128*cdf0e10cSrcweir 129*cdf0e10cSrcweir void CanvasHelper::setDevice( rendering::XGraphicDevice& rDevice ) 130*cdf0e10cSrcweir { 131*cdf0e10cSrcweir mpDevice = &rDevice; 132*cdf0e10cSrcweir } 133*cdf0e10cSrcweir 134*cdf0e10cSrcweir void CanvasHelper::setTarget( const GraphicsProviderSharedPtr& rTarget ) 135*cdf0e10cSrcweir { 136*cdf0e10cSrcweir ENSURE_OR_THROW( rTarget, 137*cdf0e10cSrcweir "CanvasHelper::setTarget(): Invalid target" ); 138*cdf0e10cSrcweir ENSURE_OR_THROW( !mpGraphicsProvider.get(), 139*cdf0e10cSrcweir "CanvasHelper::setTarget(): target set, old target would be overwritten" ); 140*cdf0e10cSrcweir 141*cdf0e10cSrcweir mpGraphicsProvider = rTarget; 142*cdf0e10cSrcweir } 143*cdf0e10cSrcweir 144*cdf0e10cSrcweir void CanvasHelper::setTarget( const GraphicsProviderSharedPtr& rTarget, 145*cdf0e10cSrcweir const ::basegfx::B2ISize& rOutputOffset ) 146*cdf0e10cSrcweir { 147*cdf0e10cSrcweir ENSURE_OR_THROW( rTarget, 148*cdf0e10cSrcweir "CanvasHelper::setTarget(): invalid target" ); 149*cdf0e10cSrcweir ENSURE_OR_THROW( !mpGraphicsProvider.get(), 150*cdf0e10cSrcweir "CanvasHelper::setTarget(): target set, old target would be overwritten" ); 151*cdf0e10cSrcweir 152*cdf0e10cSrcweir mpGraphicsProvider = rTarget; 153*cdf0e10cSrcweir maOutputOffset = rOutputOffset; 154*cdf0e10cSrcweir } 155*cdf0e10cSrcweir 156*cdf0e10cSrcweir void CanvasHelper::clear() 157*cdf0e10cSrcweir { 158*cdf0e10cSrcweir if( needOutput() ) 159*cdf0e10cSrcweir { 160*cdf0e10cSrcweir GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); 161*cdf0e10cSrcweir Gdiplus::Color aClearColor = Gdiplus::Color((Gdiplus::ARGB)Gdiplus::Color::White); 162*cdf0e10cSrcweir 163*cdf0e10cSrcweir ENSURE_OR_THROW( 164*cdf0e10cSrcweir Gdiplus::Ok == pGraphics->SetCompositingMode( 165*cdf0e10cSrcweir Gdiplus::CompositingModeSourceCopy ), // force set, don't blend 166*cdf0e10cSrcweir "CanvasHelper::clear(): GDI+ SetCompositingMode call failed" ); 167*cdf0e10cSrcweir ENSURE_OR_THROW( 168*cdf0e10cSrcweir Gdiplus::Ok == pGraphics->Clear( aClearColor ), 169*cdf0e10cSrcweir "CanvasHelper::clear(): GDI+ Clear call failed" ); 170*cdf0e10cSrcweir } 171*cdf0e10cSrcweir } 172*cdf0e10cSrcweir 173*cdf0e10cSrcweir void CanvasHelper::drawPoint( const rendering::XCanvas* /*pCanvas*/, 174*cdf0e10cSrcweir const geometry::RealPoint2D& aPoint, 175*cdf0e10cSrcweir const rendering::ViewState& viewState, 176*cdf0e10cSrcweir const rendering::RenderState& renderState ) 177*cdf0e10cSrcweir { 178*cdf0e10cSrcweir if( needOutput() ) 179*cdf0e10cSrcweir { 180*cdf0e10cSrcweir GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); 181*cdf0e10cSrcweir 182*cdf0e10cSrcweir setupGraphicsState( pGraphics, viewState, renderState ); 183*cdf0e10cSrcweir 184*cdf0e10cSrcweir Gdiplus::SolidBrush aBrush( 185*cdf0e10cSrcweir Gdiplus::Color( 186*cdf0e10cSrcweir tools::sequenceToArgb(renderState.DeviceColor)) ); 187*cdf0e10cSrcweir 188*cdf0e10cSrcweir // determine size of one-by-one device pixel ellipse 189*cdf0e10cSrcweir Gdiplus::Matrix aMatrix; 190*cdf0e10cSrcweir pGraphics->GetTransform(&aMatrix); 191*cdf0e10cSrcweir aMatrix.Invert(); 192*cdf0e10cSrcweir Gdiplus::PointF vector(1, 1); 193*cdf0e10cSrcweir aMatrix.TransformVectors(&vector); 194*cdf0e10cSrcweir 195*cdf0e10cSrcweir // paint a one-by-one circle, with the given point 196*cdf0e10cSrcweir // in the middle (rounded to float) 197*cdf0e10cSrcweir ENSURE_OR_THROW( 198*cdf0e10cSrcweir Gdiplus::Ok == pGraphics->FillEllipse( &aBrush, 199*cdf0e10cSrcweir // disambiguate call 200*cdf0e10cSrcweir Gdiplus::REAL(aPoint.X), 201*cdf0e10cSrcweir Gdiplus::REAL(aPoint.Y), 202*cdf0e10cSrcweir Gdiplus::REAL(vector.X), 203*cdf0e10cSrcweir Gdiplus::REAL(vector.Y) ), 204*cdf0e10cSrcweir "CanvasHelper::drawPoint(): GDI+ call failed" ); 205*cdf0e10cSrcweir } 206*cdf0e10cSrcweir } 207*cdf0e10cSrcweir 208*cdf0e10cSrcweir void CanvasHelper::drawLine( const rendering::XCanvas* /*pCanvas*/, 209*cdf0e10cSrcweir const geometry::RealPoint2D& aStartPoint, 210*cdf0e10cSrcweir const geometry::RealPoint2D& aEndPoint, 211*cdf0e10cSrcweir const rendering::ViewState& viewState, 212*cdf0e10cSrcweir const rendering::RenderState& renderState ) 213*cdf0e10cSrcweir { 214*cdf0e10cSrcweir if( needOutput() ) 215*cdf0e10cSrcweir { 216*cdf0e10cSrcweir GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); 217*cdf0e10cSrcweir 218*cdf0e10cSrcweir setupGraphicsState( pGraphics, viewState, renderState ); 219*cdf0e10cSrcweir 220*cdf0e10cSrcweir Gdiplus::Pen aPen( 221*cdf0e10cSrcweir Gdiplus::Color( 222*cdf0e10cSrcweir tools::sequenceToArgb(renderState.DeviceColor)), 223*cdf0e10cSrcweir Gdiplus::REAL(0.0) ); 224*cdf0e10cSrcweir 225*cdf0e10cSrcweir // #122683# Switched precedence of pixel offset 226*cdf0e10cSrcweir // mode. Seemingly, polygon stroking needs 227*cdf0e10cSrcweir // PixelOffsetModeNone to achieve visually pleasing 228*cdf0e10cSrcweir // results, whereas all other operations (e.g. polygon 229*cdf0e10cSrcweir // fills, bitmaps) look better with PixelOffsetModeHalf. 230*cdf0e10cSrcweir const Gdiplus::PixelOffsetMode aOldMode( 231*cdf0e10cSrcweir pGraphics->GetPixelOffsetMode() ); 232*cdf0e10cSrcweir pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); 233*cdf0e10cSrcweir 234*cdf0e10cSrcweir Gdiplus::Status hr = pGraphics->DrawLine( &aPen, 235*cdf0e10cSrcweir Gdiplus::REAL(aStartPoint.X), // disambiguate call 236*cdf0e10cSrcweir Gdiplus::REAL(aStartPoint.Y), 237*cdf0e10cSrcweir Gdiplus::REAL(aEndPoint.X), 238*cdf0e10cSrcweir Gdiplus::REAL(aEndPoint.Y) ); 239*cdf0e10cSrcweir pGraphics->SetPixelOffsetMode( aOldMode ); 240*cdf0e10cSrcweir 241*cdf0e10cSrcweir ENSURE_OR_THROW( 242*cdf0e10cSrcweir Gdiplus::Ok == hr, 243*cdf0e10cSrcweir "CanvasHelper::drawLine(): GDI+ call failed" ); 244*cdf0e10cSrcweir } 245*cdf0e10cSrcweir } 246*cdf0e10cSrcweir 247*cdf0e10cSrcweir void CanvasHelper::drawBezier( const rendering::XCanvas* /*pCanvas*/, 248*cdf0e10cSrcweir const geometry::RealBezierSegment2D& aBezierSegment, 249*cdf0e10cSrcweir const geometry::RealPoint2D& aEndPoint, 250*cdf0e10cSrcweir const rendering::ViewState& viewState, 251*cdf0e10cSrcweir const rendering::RenderState& renderState ) 252*cdf0e10cSrcweir { 253*cdf0e10cSrcweir if( needOutput() ) 254*cdf0e10cSrcweir { 255*cdf0e10cSrcweir GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); 256*cdf0e10cSrcweir 257*cdf0e10cSrcweir setupGraphicsState( pGraphics, viewState, renderState ); 258*cdf0e10cSrcweir 259*cdf0e10cSrcweir Gdiplus::Pen aPen( 260*cdf0e10cSrcweir Gdiplus::Color( 261*cdf0e10cSrcweir tools::sequenceToArgb(renderState.DeviceColor)), 262*cdf0e10cSrcweir Gdiplus::REAL(0.0) ); 263*cdf0e10cSrcweir 264*cdf0e10cSrcweir // #122683# Switched precedence of pixel offset 265*cdf0e10cSrcweir // mode. Seemingly, polygon stroking needs 266*cdf0e10cSrcweir // PixelOffsetModeNone to achieve visually pleasing 267*cdf0e10cSrcweir // results, whereas all other operations (e.g. polygon 268*cdf0e10cSrcweir // fills, bitmaps) look better with PixelOffsetModeHalf. 269*cdf0e10cSrcweir const Gdiplus::PixelOffsetMode aOldMode( 270*cdf0e10cSrcweir pGraphics->GetPixelOffsetMode() ); 271*cdf0e10cSrcweir pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); 272*cdf0e10cSrcweir 273*cdf0e10cSrcweir Gdiplus::Status hr = pGraphics->DrawBezier( &aPen, 274*cdf0e10cSrcweir Gdiplus::REAL(aBezierSegment.Px), // disambiguate call 275*cdf0e10cSrcweir Gdiplus::REAL(aBezierSegment.Py), 276*cdf0e10cSrcweir Gdiplus::REAL(aBezierSegment.C1x), 277*cdf0e10cSrcweir Gdiplus::REAL(aBezierSegment.C1y), 278*cdf0e10cSrcweir Gdiplus::REAL(aEndPoint.X), 279*cdf0e10cSrcweir Gdiplus::REAL(aEndPoint.Y), 280*cdf0e10cSrcweir Gdiplus::REAL(aBezierSegment.C2x), 281*cdf0e10cSrcweir Gdiplus::REAL(aBezierSegment.C2y) ); 282*cdf0e10cSrcweir 283*cdf0e10cSrcweir pGraphics->SetPixelOffsetMode( aOldMode ); 284*cdf0e10cSrcweir 285*cdf0e10cSrcweir ENSURE_OR_THROW( 286*cdf0e10cSrcweir Gdiplus::Ok == hr, 287*cdf0e10cSrcweir "CanvasHelper::drawBezier(): GDI+ call failed" ); 288*cdf0e10cSrcweir } 289*cdf0e10cSrcweir } 290*cdf0e10cSrcweir 291*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* /*pCanvas*/, 292*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, 293*cdf0e10cSrcweir const rendering::ViewState& viewState, 294*cdf0e10cSrcweir const rendering::RenderState& renderState ) 295*cdf0e10cSrcweir { 296*cdf0e10cSrcweir ENSURE_OR_THROW( xPolyPolygon.is(), 297*cdf0e10cSrcweir "CanvasHelper::drawPolyPolygon: polygon is NULL"); 298*cdf0e10cSrcweir 299*cdf0e10cSrcweir if( needOutput() ) 300*cdf0e10cSrcweir { 301*cdf0e10cSrcweir GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); 302*cdf0e10cSrcweir 303*cdf0e10cSrcweir setupGraphicsState( pGraphics, viewState, renderState ); 304*cdf0e10cSrcweir 305*cdf0e10cSrcweir Gdiplus::Pen aPen( 306*cdf0e10cSrcweir Gdiplus::Color( 307*cdf0e10cSrcweir tools::sequenceToArgb(renderState.DeviceColor)), 308*cdf0e10cSrcweir Gdiplus::REAL(0.0) ); 309*cdf0e10cSrcweir 310*cdf0e10cSrcweir // #122683# Switched precedence of pixel offset 311*cdf0e10cSrcweir // mode. Seemingly, polygon stroking needs 312*cdf0e10cSrcweir // PixelOffsetModeNone to achieve visually pleasing 313*cdf0e10cSrcweir // results, whereas all other operations (e.g. polygon 314*cdf0e10cSrcweir // fills, bitmaps) look better with PixelOffsetModeHalf. 315*cdf0e10cSrcweir const Gdiplus::PixelOffsetMode aOldMode( 316*cdf0e10cSrcweir pGraphics->GetPixelOffsetMode() ); 317*cdf0e10cSrcweir pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); 318*cdf0e10cSrcweir 319*cdf0e10cSrcweir GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ) ); 320*cdf0e10cSrcweir 321*cdf0e10cSrcweir // TODO(E1): Return value 322*cdf0e10cSrcweir Gdiplus::Status hr = pGraphics->DrawPath( &aPen, pPath.get() ); 323*cdf0e10cSrcweir 324*cdf0e10cSrcweir pGraphics->SetPixelOffsetMode( aOldMode ); 325*cdf0e10cSrcweir 326*cdf0e10cSrcweir ENSURE_OR_THROW( 327*cdf0e10cSrcweir Gdiplus::Ok == hr, 328*cdf0e10cSrcweir "CanvasHelper::drawPolyPolygon(): GDI+ call failed" ); 329*cdf0e10cSrcweir } 330*cdf0e10cSrcweir 331*cdf0e10cSrcweir // TODO(P1): Provide caching here. 332*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 333*cdf0e10cSrcweir } 334*cdf0e10cSrcweir 335*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokePolyPolygon( const rendering::XCanvas* /*pCanvas*/, 336*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, 337*cdf0e10cSrcweir const rendering::ViewState& viewState, 338*cdf0e10cSrcweir const rendering::RenderState& renderState, 339*cdf0e10cSrcweir const rendering::StrokeAttributes& strokeAttributes ) 340*cdf0e10cSrcweir { 341*cdf0e10cSrcweir ENSURE_OR_THROW( xPolyPolygon.is(), 342*cdf0e10cSrcweir "CanvasHelper::drawPolyPolygon: polygon is NULL"); 343*cdf0e10cSrcweir 344*cdf0e10cSrcweir if( needOutput() ) 345*cdf0e10cSrcweir { 346*cdf0e10cSrcweir GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); 347*cdf0e10cSrcweir 348*cdf0e10cSrcweir setupGraphicsState( pGraphics, viewState, renderState ); 349*cdf0e10cSrcweir 350*cdf0e10cSrcweir 351*cdf0e10cSrcweir // Setup stroke pen 352*cdf0e10cSrcweir // ---------------- 353*cdf0e10cSrcweir 354*cdf0e10cSrcweir Gdiplus::Pen aPen( 355*cdf0e10cSrcweir Gdiplus::Color( 356*cdf0e10cSrcweir tools::sequenceToArgb(renderState.DeviceColor)), 357*cdf0e10cSrcweir static_cast< Gdiplus::REAL >(strokeAttributes.StrokeWidth) ); 358*cdf0e10cSrcweir 359*cdf0e10cSrcweir // #122683# Switched precedence of pixel offset 360*cdf0e10cSrcweir // mode. Seemingly, polygon stroking needs 361*cdf0e10cSrcweir // PixelOffsetModeNone to achieve visually pleasing 362*cdf0e10cSrcweir // results, whereas all other operations (e.g. polygon 363*cdf0e10cSrcweir // fills, bitmaps) look better with PixelOffsetModeHalf. 364*cdf0e10cSrcweir const Gdiplus::PixelOffsetMode aOldMode( 365*cdf0e10cSrcweir pGraphics->GetPixelOffsetMode() ); 366*cdf0e10cSrcweir pGraphics->SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); 367*cdf0e10cSrcweir 368*cdf0e10cSrcweir const bool bIsMiter(rendering::PathJoinType::MITER == strokeAttributes.JoinType); 369*cdf0e10cSrcweir const bool bIsNone(rendering::PathJoinType::NONE == strokeAttributes.JoinType); 370*cdf0e10cSrcweir 371*cdf0e10cSrcweir if(bIsMiter) 372*cdf0e10cSrcweir aPen.SetMiterLimit( static_cast< Gdiplus::REAL >(strokeAttributes.MiterLimit) ); 373*cdf0e10cSrcweir 374*cdf0e10cSrcweir const ::std::vector< Gdiplus::REAL >& rDashArray( 375*cdf0e10cSrcweir ::comphelper::sequenceToContainer< ::std::vector< Gdiplus::REAL > >( 376*cdf0e10cSrcweir strokeAttributes.DashArray ) ); 377*cdf0e10cSrcweir if( !rDashArray.empty() ) 378*cdf0e10cSrcweir { 379*cdf0e10cSrcweir aPen.SetDashPattern( &rDashArray[0], 380*cdf0e10cSrcweir rDashArray.size() ); 381*cdf0e10cSrcweir } 382*cdf0e10cSrcweir aPen.SetLineCap( gdiCapFromCap(strokeAttributes.StartCapType), 383*cdf0e10cSrcweir gdiCapFromCap(strokeAttributes.EndCapType), 384*cdf0e10cSrcweir Gdiplus::DashCapFlat ); 385*cdf0e10cSrcweir if(!bIsNone) 386*cdf0e10cSrcweir aPen.SetLineJoin( gdiJoinFromJoin(strokeAttributes.JoinType) ); 387*cdf0e10cSrcweir 388*cdf0e10cSrcweir GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon, bIsNone ) ); 389*cdf0e10cSrcweir 390*cdf0e10cSrcweir // TODO(E1): Return value 391*cdf0e10cSrcweir Gdiplus::Status hr = pGraphics->DrawPath( &aPen, pPath.get() ); 392*cdf0e10cSrcweir 393*cdf0e10cSrcweir pGraphics->SetPixelOffsetMode( aOldMode ); 394*cdf0e10cSrcweir 395*cdf0e10cSrcweir ENSURE_OR_THROW( 396*cdf0e10cSrcweir Gdiplus::Ok == hr, 397*cdf0e10cSrcweir "CanvasHelper::strokePolyPolygon(): GDI+ call failed" ); 398*cdf0e10cSrcweir } 399*cdf0e10cSrcweir 400*cdf0e10cSrcweir // TODO(P1): Provide caching here. 401*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 402*cdf0e10cSrcweir } 403*cdf0e10cSrcweir 404*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, 405*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, 406*cdf0e10cSrcweir const rendering::ViewState& /*viewState*/, 407*cdf0e10cSrcweir const rendering::RenderState& /*renderState*/, 408*cdf0e10cSrcweir const uno::Sequence< rendering::Texture >& /*textures*/, 409*cdf0e10cSrcweir const rendering::StrokeAttributes& /*strokeAttributes*/ ) 410*cdf0e10cSrcweir { 411*cdf0e10cSrcweir // TODO 412*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 413*cdf0e10cSrcweir } 414*cdf0e10cSrcweir 415*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, 416*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, 417*cdf0e10cSrcweir const rendering::ViewState& /*viewState*/, 418*cdf0e10cSrcweir const rendering::RenderState& /*renderState*/, 419*cdf0e10cSrcweir const uno::Sequence< rendering::Texture >& /*textures*/, 420*cdf0e10cSrcweir const uno::Reference< geometry::XMapping2D >& /*xMapping*/, 421*cdf0e10cSrcweir const rendering::StrokeAttributes& /*strokeAttributes*/ ) 422*cdf0e10cSrcweir { 423*cdf0e10cSrcweir // TODO 424*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 425*cdf0e10cSrcweir } 426*cdf0e10cSrcweir 427*cdf0e10cSrcweir uno::Reference< rendering::XPolyPolygon2D > CanvasHelper::queryStrokeShapes( const rendering::XCanvas* /*pCanvas*/, 428*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, 429*cdf0e10cSrcweir const rendering::ViewState& /*viewState*/, 430*cdf0e10cSrcweir const rendering::RenderState& /*renderState*/, 431*cdf0e10cSrcweir const rendering::StrokeAttributes& /*strokeAttributes*/ ) 432*cdf0e10cSrcweir { 433*cdf0e10cSrcweir // TODO 434*cdf0e10cSrcweir return uno::Reference< rendering::XPolyPolygon2D >(NULL); 435*cdf0e10cSrcweir } 436*cdf0e10cSrcweir 437*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillPolyPolygon( const rendering::XCanvas* /*pCanvas*/, 438*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, 439*cdf0e10cSrcweir const rendering::ViewState& viewState, 440*cdf0e10cSrcweir const rendering::RenderState& renderState ) 441*cdf0e10cSrcweir { 442*cdf0e10cSrcweir ENSURE_OR_THROW( xPolyPolygon.is(), 443*cdf0e10cSrcweir "CanvasHelper::fillPolyPolygon: polygon is NULL"); 444*cdf0e10cSrcweir 445*cdf0e10cSrcweir if( needOutput() ) 446*cdf0e10cSrcweir { 447*cdf0e10cSrcweir GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); 448*cdf0e10cSrcweir 449*cdf0e10cSrcweir setupGraphicsState( pGraphics, viewState, renderState ); 450*cdf0e10cSrcweir 451*cdf0e10cSrcweir Gdiplus::SolidBrush aBrush( 452*cdf0e10cSrcweir tools::sequenceToArgb(renderState.DeviceColor)); 453*cdf0e10cSrcweir 454*cdf0e10cSrcweir GraphicsPathSharedPtr pPath( tools::graphicsPathFromXPolyPolygon2D( xPolyPolygon ) ); 455*cdf0e10cSrcweir 456*cdf0e10cSrcweir // TODO(F1): FillRule 457*cdf0e10cSrcweir ENSURE_OR_THROW( Gdiplus::Ok == pGraphics->FillPath( &aBrush, pPath.get() ), 458*cdf0e10cSrcweir "CanvasHelper::fillPolyPolygon(): GDI+ call failed " ); 459*cdf0e10cSrcweir } 460*cdf0e10cSrcweir 461*cdf0e10cSrcweir // TODO(P1): Provide caching here. 462*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 463*cdf0e10cSrcweir } 464*cdf0e10cSrcweir 465*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas* /*pCanvas*/, 466*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& /*xPolyPolygon*/, 467*cdf0e10cSrcweir const rendering::ViewState& /*viewState*/, 468*cdf0e10cSrcweir const rendering::RenderState& /*renderState*/, 469*cdf0e10cSrcweir const uno::Sequence< rendering::Texture >& /*textures*/, 470*cdf0e10cSrcweir const uno::Reference< geometry::XMapping2D >& /*xMapping*/ ) 471*cdf0e10cSrcweir { 472*cdf0e10cSrcweir // TODO 473*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 474*cdf0e10cSrcweir } 475*cdf0e10cSrcweir 476*cdf0e10cSrcweir uno::Reference< rendering::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* /*pCanvas*/, 477*cdf0e10cSrcweir const rendering::FontRequest& fontRequest, 478*cdf0e10cSrcweir const uno::Sequence< beans::PropertyValue >& extraFontProperties, 479*cdf0e10cSrcweir const geometry::Matrix2D& fontMatrix ) 480*cdf0e10cSrcweir { 481*cdf0e10cSrcweir if( needOutput() ) 482*cdf0e10cSrcweir { 483*cdf0e10cSrcweir return uno::Reference< rendering::XCanvasFont >( 484*cdf0e10cSrcweir new CanvasFont(fontRequest, extraFontProperties, fontMatrix ) ); 485*cdf0e10cSrcweir } 486*cdf0e10cSrcweir 487*cdf0e10cSrcweir return uno::Reference< rendering::XCanvasFont >(); 488*cdf0e10cSrcweir } 489*cdf0e10cSrcweir 490*cdf0e10cSrcweir uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* /*pCanvas*/, 491*cdf0e10cSrcweir const rendering::FontInfo& /*aFilter*/, 492*cdf0e10cSrcweir const uno::Sequence< beans::PropertyValue >& /*aFontProperties*/ ) 493*cdf0e10cSrcweir { 494*cdf0e10cSrcweir // TODO 495*cdf0e10cSrcweir return uno::Sequence< rendering::FontInfo >(); 496*cdf0e10cSrcweir } 497*cdf0e10cSrcweir 498*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* /*pCanvas*/, 499*cdf0e10cSrcweir const rendering::StringContext& text, 500*cdf0e10cSrcweir const uno::Reference< rendering::XCanvasFont >& xFont, 501*cdf0e10cSrcweir const rendering::ViewState& viewState, 502*cdf0e10cSrcweir const rendering::RenderState& renderState, 503*cdf0e10cSrcweir sal_Int8 /*textDirection*/ ) 504*cdf0e10cSrcweir { 505*cdf0e10cSrcweir ENSURE_OR_THROW( xFont.is(), 506*cdf0e10cSrcweir "CanvasHelper::drawText: font is NULL"); 507*cdf0e10cSrcweir 508*cdf0e10cSrcweir if( needOutput() ) 509*cdf0e10cSrcweir { 510*cdf0e10cSrcweir GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); 511*cdf0e10cSrcweir 512*cdf0e10cSrcweir setupGraphicsState( pGraphics, viewState, renderState ); 513*cdf0e10cSrcweir 514*cdf0e10cSrcweir Gdiplus::SolidBrush aBrush( 515*cdf0e10cSrcweir Gdiplus::Color( 516*cdf0e10cSrcweir tools::sequenceToArgb(renderState.DeviceColor))); 517*cdf0e10cSrcweir 518*cdf0e10cSrcweir CanvasFont::ImplRef pFont( 519*cdf0e10cSrcweir tools::canvasFontFromXFont(xFont) ); 520*cdf0e10cSrcweir 521*cdf0e10cSrcweir // Move glyphs up, such that output happens at the font 522*cdf0e10cSrcweir // baseline. 523*cdf0e10cSrcweir Gdiplus::PointF aPoint( 0.0, 524*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(-(pFont->getFont()->GetSize()* 525*cdf0e10cSrcweir pFont->getCellAscent() / 526*cdf0e10cSrcweir pFont->getEmHeight())) ); 527*cdf0e10cSrcweir 528*cdf0e10cSrcweir // TODO(F1): According to 529*cdf0e10cSrcweir // http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q307208, 530*cdf0e10cSrcweir // we might have to revert to GDI and ExTextOut here, 531*cdf0e10cSrcweir // since GDI+ takes the scalability a little bit too 532*cdf0e10cSrcweir // far... 533*cdf0e10cSrcweir 534*cdf0e10cSrcweir // TODO(F2): Proper layout (BiDi, CTL)! IMHO must use 535*cdf0e10cSrcweir // DrawDriverString here, and perform layouting myself... 536*cdf0e10cSrcweir ENSURE_OR_THROW( 537*cdf0e10cSrcweir Gdiplus::Ok == pGraphics->DrawString( reinterpret_cast<LPCWSTR>( 538*cdf0e10cSrcweir text.Text.copy( text.StartPosition, 539*cdf0e10cSrcweir text.Length ).getStr()), 540*cdf0e10cSrcweir text.Length, 541*cdf0e10cSrcweir pFont->getFont().get(), 542*cdf0e10cSrcweir aPoint, 543*cdf0e10cSrcweir &aBrush ), 544*cdf0e10cSrcweir "CanvasHelper::drawText(): GDI+ call failed" ); 545*cdf0e10cSrcweir } 546*cdf0e10cSrcweir 547*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 548*cdf0e10cSrcweir } 549*cdf0e10cSrcweir 550*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* /*pCanvas*/, 551*cdf0e10cSrcweir const uno::Reference< rendering::XTextLayout >& xLayoutetText, 552*cdf0e10cSrcweir const rendering::ViewState& viewState, 553*cdf0e10cSrcweir const rendering::RenderState& renderState ) 554*cdf0e10cSrcweir { 555*cdf0e10cSrcweir ENSURE_OR_THROW( xLayoutetText.is(), 556*cdf0e10cSrcweir "CanvasHelper::drawTextLayout: layout is NULL"); 557*cdf0e10cSrcweir 558*cdf0e10cSrcweir if( needOutput() ) 559*cdf0e10cSrcweir { 560*cdf0e10cSrcweir TextLayout* pTextLayout = 561*cdf0e10cSrcweir dynamic_cast< TextLayout* >( xLayoutetText.get() ); 562*cdf0e10cSrcweir 563*cdf0e10cSrcweir ENSURE_OR_THROW( pTextLayout, 564*cdf0e10cSrcweir "CanvasHelper::drawTextLayout(): TextLayout not compatible with this canvas" ); 565*cdf0e10cSrcweir 566*cdf0e10cSrcweir pTextLayout->draw( mpGraphicsProvider->getGraphics(), 567*cdf0e10cSrcweir viewState, 568*cdf0e10cSrcweir renderState, 569*cdf0e10cSrcweir maOutputOffset, 570*cdf0e10cSrcweir mpDevice, 571*cdf0e10cSrcweir false ); 572*cdf0e10cSrcweir } 573*cdf0e10cSrcweir 574*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 575*cdf0e10cSrcweir } 576*cdf0e10cSrcweir 577*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmap( const rendering::XCanvas* /*pCanvas*/, 578*cdf0e10cSrcweir const uno::Reference< rendering::XBitmap >& xBitmap, 579*cdf0e10cSrcweir const rendering::ViewState& viewState, 580*cdf0e10cSrcweir const rendering::RenderState& renderState ) 581*cdf0e10cSrcweir { 582*cdf0e10cSrcweir ENSURE_OR_THROW( xBitmap.is(), 583*cdf0e10cSrcweir "CanvasHelper::drawBitmap: bitmap is NULL"); 584*cdf0e10cSrcweir 585*cdf0e10cSrcweir if( needOutput() ) 586*cdf0e10cSrcweir { 587*cdf0e10cSrcweir // check whether one of our own objects - need to retrieve 588*cdf0e10cSrcweir // bitmap _before_ calling 589*cdf0e10cSrcweir // GraphicsProvider::getGraphics(), to avoid locking our 590*cdf0e10cSrcweir // own surface. 591*cdf0e10cSrcweir BitmapSharedPtr pGdiBitmap; 592*cdf0e10cSrcweir BitmapProvider* pBitmap = dynamic_cast< BitmapProvider* >(xBitmap.get()); 593*cdf0e10cSrcweir if( pBitmap ) 594*cdf0e10cSrcweir { 595*cdf0e10cSrcweir IBitmapSharedPtr pDXBitmap( pBitmap->getBitmap() ); 596*cdf0e10cSrcweir if( pDXBitmap ) 597*cdf0e10cSrcweir pGdiBitmap = pDXBitmap->getBitmap(); 598*cdf0e10cSrcweir } 599*cdf0e10cSrcweir 600*cdf0e10cSrcweir GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); 601*cdf0e10cSrcweir setupGraphicsState( pGraphics, viewState, renderState ); 602*cdf0e10cSrcweir 603*cdf0e10cSrcweir if( pGdiBitmap ) 604*cdf0e10cSrcweir tools::drawGdiPlusBitmap(pGraphics,pGdiBitmap); 605*cdf0e10cSrcweir else 606*cdf0e10cSrcweir tools::drawVCLBitmapFromXBitmap(pGraphics, 607*cdf0e10cSrcweir xBitmap); 608*cdf0e10cSrcweir } 609*cdf0e10cSrcweir 610*cdf0e10cSrcweir // TODO(P1): Provide caching here. 611*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 612*cdf0e10cSrcweir } 613*cdf0e10cSrcweir 614*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* pCanvas, 615*cdf0e10cSrcweir const uno::Reference< rendering::XBitmap >& xBitmap, 616*cdf0e10cSrcweir const rendering::ViewState& viewState, 617*cdf0e10cSrcweir const rendering::RenderState& renderState ) 618*cdf0e10cSrcweir { 619*cdf0e10cSrcweir ENSURE_OR_THROW( xBitmap.is(), 620*cdf0e10cSrcweir "CanvasHelper::drawBitmap: bitmap is NULL"); 621*cdf0e10cSrcweir 622*cdf0e10cSrcweir // no color set -> this is equivalent to a plain drawBitmap(), then 623*cdf0e10cSrcweir if( renderState.DeviceColor.getLength() < 3 ) 624*cdf0e10cSrcweir return drawBitmap( pCanvas, xBitmap, viewState, renderState ); 625*cdf0e10cSrcweir 626*cdf0e10cSrcweir if( needOutput() ) 627*cdf0e10cSrcweir { 628*cdf0e10cSrcweir GraphicsSharedPtr pGraphics( mpGraphicsProvider->getGraphics() ); 629*cdf0e10cSrcweir 630*cdf0e10cSrcweir setupGraphicsState( pGraphics, viewState, renderState ); 631*cdf0e10cSrcweir 632*cdf0e10cSrcweir BitmapSharedPtr pBitmap( tools::bitmapFromXBitmap( xBitmap ) ); 633*cdf0e10cSrcweir Gdiplus::Rect aRect( 0, 0, 634*cdf0e10cSrcweir pBitmap->GetWidth(), 635*cdf0e10cSrcweir pBitmap->GetHeight() ); 636*cdf0e10cSrcweir 637*cdf0e10cSrcweir // Setup an ImageAttributes with an alpha-modulating 638*cdf0e10cSrcweir // color matrix. 639*cdf0e10cSrcweir const rendering::ARGBColor& rARGBColor( 640*cdf0e10cSrcweir mpDevice->getDeviceColorSpace()->convertToARGB(renderState.DeviceColor)[0]); 641*cdf0e10cSrcweir 642*cdf0e10cSrcweir Gdiplus::ImageAttributes aImgAttr; 643*cdf0e10cSrcweir tools::setModulateImageAttributes( aImgAttr, 644*cdf0e10cSrcweir rARGBColor.Red, 645*cdf0e10cSrcweir rARGBColor.Green, 646*cdf0e10cSrcweir rARGBColor.Blue, 647*cdf0e10cSrcweir rARGBColor.Alpha ); 648*cdf0e10cSrcweir 649*cdf0e10cSrcweir ENSURE_OR_THROW( 650*cdf0e10cSrcweir Gdiplus::Ok == pGraphics->DrawImage( pBitmap.get(), 651*cdf0e10cSrcweir aRect, 652*cdf0e10cSrcweir 0, 0, 653*cdf0e10cSrcweir pBitmap->GetWidth(), 654*cdf0e10cSrcweir pBitmap->GetHeight(), 655*cdf0e10cSrcweir Gdiplus::UnitPixel, 656*cdf0e10cSrcweir &aImgAttr, 657*cdf0e10cSrcweir NULL, 658*cdf0e10cSrcweir NULL ), 659*cdf0e10cSrcweir "CanvasHelper::drawBitmapModulated(): GDI+ call failed" ); 660*cdf0e10cSrcweir } 661*cdf0e10cSrcweir 662*cdf0e10cSrcweir // TODO(P1): Provide caching here. 663*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 664*cdf0e10cSrcweir } 665*cdf0e10cSrcweir 666*cdf0e10cSrcweir uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice() 667*cdf0e10cSrcweir { 668*cdf0e10cSrcweir return uno::Reference< rendering::XGraphicDevice >(mpDevice); 669*cdf0e10cSrcweir } 670*cdf0e10cSrcweir 671*cdf0e10cSrcweir // private helper 672*cdf0e10cSrcweir // -------------------------------------------------- 673*cdf0e10cSrcweir 674*cdf0e10cSrcweir Gdiplus::CompositingMode CanvasHelper::calcCompositingMode( sal_Int8 nMode ) 675*cdf0e10cSrcweir { 676*cdf0e10cSrcweir Gdiplus::CompositingMode aRet( Gdiplus::CompositingModeSourceOver ); 677*cdf0e10cSrcweir 678*cdf0e10cSrcweir switch( nMode ) 679*cdf0e10cSrcweir { 680*cdf0e10cSrcweir case rendering::CompositeOperation::OVER: 681*cdf0e10cSrcweir // FALLTHROUGH intended 682*cdf0e10cSrcweir case rendering::CompositeOperation::CLEAR: 683*cdf0e10cSrcweir aRet = Gdiplus::CompositingModeSourceOver; 684*cdf0e10cSrcweir break; 685*cdf0e10cSrcweir 686*cdf0e10cSrcweir case rendering::CompositeOperation::SOURCE: 687*cdf0e10cSrcweir aRet = Gdiplus::CompositingModeSourceCopy; 688*cdf0e10cSrcweir break; 689*cdf0e10cSrcweir 690*cdf0e10cSrcweir case rendering::CompositeOperation::DESTINATION: 691*cdf0e10cSrcweir // FALLTHROUGH intended 692*cdf0e10cSrcweir case rendering::CompositeOperation::UNDER: 693*cdf0e10cSrcweir // FALLTHROUGH intended 694*cdf0e10cSrcweir case rendering::CompositeOperation::INSIDE: 695*cdf0e10cSrcweir // FALLTHROUGH intended 696*cdf0e10cSrcweir case rendering::CompositeOperation::INSIDE_REVERSE: 697*cdf0e10cSrcweir // FALLTHROUGH intended 698*cdf0e10cSrcweir case rendering::CompositeOperation::OUTSIDE: 699*cdf0e10cSrcweir // FALLTHROUGH intended 700*cdf0e10cSrcweir case rendering::CompositeOperation::OUTSIDE_REVERSE: 701*cdf0e10cSrcweir // FALLTHROUGH intended 702*cdf0e10cSrcweir case rendering::CompositeOperation::ATOP: 703*cdf0e10cSrcweir // FALLTHROUGH intended 704*cdf0e10cSrcweir case rendering::CompositeOperation::ATOP_REVERSE: 705*cdf0e10cSrcweir // FALLTHROUGH intended 706*cdf0e10cSrcweir case rendering::CompositeOperation::XOR: 707*cdf0e10cSrcweir // FALLTHROUGH intended 708*cdf0e10cSrcweir case rendering::CompositeOperation::ADD: 709*cdf0e10cSrcweir // FALLTHROUGH intended 710*cdf0e10cSrcweir case rendering::CompositeOperation::SATURATE: 711*cdf0e10cSrcweir // TODO(F2): Problem, because GDI+ only knows about two compositing modes 712*cdf0e10cSrcweir aRet = Gdiplus::CompositingModeSourceOver; 713*cdf0e10cSrcweir break; 714*cdf0e10cSrcweir 715*cdf0e10cSrcweir default: 716*cdf0e10cSrcweir ENSURE_OR_THROW( false, "CanvasHelper::calcCompositingMode: unexpected mode" ); 717*cdf0e10cSrcweir break; 718*cdf0e10cSrcweir } 719*cdf0e10cSrcweir 720*cdf0e10cSrcweir return aRet; 721*cdf0e10cSrcweir } 722*cdf0e10cSrcweir 723*cdf0e10cSrcweir void CanvasHelper::setupGraphicsState( GraphicsSharedPtr& rGraphics, 724*cdf0e10cSrcweir const rendering::ViewState& viewState, 725*cdf0e10cSrcweir const rendering::RenderState& renderState ) 726*cdf0e10cSrcweir { 727*cdf0e10cSrcweir ENSURE_OR_THROW( needOutput(), 728*cdf0e10cSrcweir "CanvasHelper::setupGraphicsState: primary graphics invalid" ); 729*cdf0e10cSrcweir ENSURE_OR_THROW( mpDevice, 730*cdf0e10cSrcweir "CanvasHelper::setupGraphicsState: reference device invalid" ); 731*cdf0e10cSrcweir 732*cdf0e10cSrcweir // setup view transform first. Clipping e.g. depends on it 733*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aTransform; 734*cdf0e10cSrcweir ::canvas::tools::getViewStateTransform(aTransform, viewState); 735*cdf0e10cSrcweir 736*cdf0e10cSrcweir // add output offset 737*cdf0e10cSrcweir if( !maOutputOffset.equalZero() ) 738*cdf0e10cSrcweir { 739*cdf0e10cSrcweir const basegfx::B2DHomMatrix aOutputOffset(basegfx::tools::createTranslateB2DHomMatrix( 740*cdf0e10cSrcweir maOutputOffset.getX(), maOutputOffset.getY())); 741*cdf0e10cSrcweir aTransform = aOutputOffset * aTransform; 742*cdf0e10cSrcweir } 743*cdf0e10cSrcweir 744*cdf0e10cSrcweir Gdiplus::Matrix aMatrix; 745*cdf0e10cSrcweir tools::gdiPlusMatrixFromB2DHomMatrix( aMatrix, aTransform ); 746*cdf0e10cSrcweir 747*cdf0e10cSrcweir ENSURE_OR_THROW( 748*cdf0e10cSrcweir Gdiplus::Ok == rGraphics->SetTransform( &aMatrix ), 749*cdf0e10cSrcweir "CanvasHelper::setupGraphicsState(): Failed to set GDI+ transformation" ); 750*cdf0e10cSrcweir 751*cdf0e10cSrcweir // setup view and render state clipping 752*cdf0e10cSrcweir ENSURE_OR_THROW( 753*cdf0e10cSrcweir Gdiplus::Ok == rGraphics->ResetClip(), 754*cdf0e10cSrcweir "CanvasHelper::setupGraphicsState(): Failed to reset GDI+ clip" ); 755*cdf0e10cSrcweir 756*cdf0e10cSrcweir if( viewState.Clip.is() ) 757*cdf0e10cSrcweir { 758*cdf0e10cSrcweir GraphicsPathSharedPtr aClipPath( tools::graphicsPathFromXPolyPolygon2D( viewState.Clip ) ); 759*cdf0e10cSrcweir 760*cdf0e10cSrcweir // TODO(P3): Cache clip. SetClip( GraphicsPath ) performs abyssmally on GDI+. 761*cdf0e10cSrcweir // Try SetClip( Rect ) or similar for simple clip paths (need some support in 762*cdf0e10cSrcweir // LinePolyPolygon, then) 763*cdf0e10cSrcweir ENSURE_OR_THROW( 764*cdf0e10cSrcweir Gdiplus::Ok == rGraphics->SetClip( aClipPath.get(), 765*cdf0e10cSrcweir Gdiplus::CombineModeIntersect ), 766*cdf0e10cSrcweir "CanvasHelper::setupGraphicsState(): Cannot set GDI+ clip" ); 767*cdf0e10cSrcweir } 768*cdf0e10cSrcweir 769*cdf0e10cSrcweir // setup overall transform only now. View clip above was relative to 770*cdf0e10cSrcweir // view transform 771*cdf0e10cSrcweir ::canvas::tools::mergeViewAndRenderTransform(aTransform, 772*cdf0e10cSrcweir viewState, 773*cdf0e10cSrcweir renderState); 774*cdf0e10cSrcweir 775*cdf0e10cSrcweir // add output offset 776*cdf0e10cSrcweir if( !maOutputOffset.equalZero() ) 777*cdf0e10cSrcweir { 778*cdf0e10cSrcweir const basegfx::B2DHomMatrix aOutputOffset(basegfx::tools::createTranslateB2DHomMatrix( 779*cdf0e10cSrcweir maOutputOffset.getX(), maOutputOffset.getY())); 780*cdf0e10cSrcweir aTransform = aOutputOffset * aTransform; 781*cdf0e10cSrcweir } 782*cdf0e10cSrcweir 783*cdf0e10cSrcweir tools::gdiPlusMatrixFromB2DHomMatrix( aMatrix, aTransform ); 784*cdf0e10cSrcweir 785*cdf0e10cSrcweir ENSURE_OR_THROW( 786*cdf0e10cSrcweir Gdiplus::Ok == rGraphics->SetTransform( &aMatrix ), 787*cdf0e10cSrcweir "CanvasHelper::setupGraphicsState(): Cannot set GDI+ transformation" ); 788*cdf0e10cSrcweir 789*cdf0e10cSrcweir if( renderState.Clip.is() ) 790*cdf0e10cSrcweir { 791*cdf0e10cSrcweir GraphicsPathSharedPtr aClipPath( tools::graphicsPathFromXPolyPolygon2D( renderState.Clip ) ); 792*cdf0e10cSrcweir 793*cdf0e10cSrcweir // TODO(P3): Cache clip. SetClip( GraphicsPath ) performs abyssmally on GDI+. 794*cdf0e10cSrcweir // Try SetClip( Rect ) or similar for simple clip paths (need some support in 795*cdf0e10cSrcweir // LinePolyPolygon, then) 796*cdf0e10cSrcweir ENSURE_OR_THROW( 797*cdf0e10cSrcweir Gdiplus::Ok == rGraphics->SetClip( aClipPath.get(), 798*cdf0e10cSrcweir Gdiplus::CombineModeIntersect ), 799*cdf0e10cSrcweir "CanvasHelper::setupGraphicsState(): Cannot set GDI+ clip" ); 800*cdf0e10cSrcweir } 801*cdf0e10cSrcweir 802*cdf0e10cSrcweir // setup compositing 803*cdf0e10cSrcweir const Gdiplus::CompositingMode eCompositing( calcCompositingMode( renderState.CompositeOperation ) ); 804*cdf0e10cSrcweir ENSURE_OR_THROW( 805*cdf0e10cSrcweir Gdiplus::Ok == rGraphics->SetCompositingMode( eCompositing ), 806*cdf0e10cSrcweir "CanvasHelper::setupGraphicsState(): Cannot set GDI* compositing mode)" ); 807*cdf0e10cSrcweir } 808*cdf0e10cSrcweir 809*cdf0e10cSrcweir void CanvasHelper::flush() const 810*cdf0e10cSrcweir { 811*cdf0e10cSrcweir if( needOutput() ) 812*cdf0e10cSrcweir mpGraphicsProvider->getGraphics()->Flush( Gdiplus::FlushIntentionSync ); 813*cdf0e10cSrcweir } 814*cdf0e10cSrcweir } 815