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/math.hxx> 35*cdf0e10cSrcweir 36*cdf0e10cSrcweir #include <com/sun/star/rendering/CompositeOperation.hpp> 37*cdf0e10cSrcweir #include <com/sun/star/util/Endianness.hpp> 38*cdf0e10cSrcweir #include <com/sun/star/rendering/TextDirection.hpp> 39*cdf0e10cSrcweir #include <com/sun/star/rendering/TexturingMode.hpp> 40*cdf0e10cSrcweir #include <com/sun/star/rendering/PathCapType.hpp> 41*cdf0e10cSrcweir #include <com/sun/star/rendering/PathJoinType.hpp> 42*cdf0e10cSrcweir 43*cdf0e10cSrcweir #include <tools/poly.hxx> 44*cdf0e10cSrcweir #include <vcl/window.hxx> 45*cdf0e10cSrcweir #include <vcl/bitmapex.hxx> 46*cdf0e10cSrcweir #include <vcl/bmpacc.hxx> 47*cdf0e10cSrcweir #include <vcl/canvastools.hxx> 48*cdf0e10cSrcweir 49*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 50*cdf0e10cSrcweir #include <basegfx/range/b2drectangle.hxx> 51*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx> 52*cdf0e10cSrcweir #include <basegfx/vector/b2dsize.hxx> 53*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx> 54*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx> 55*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx> 56*cdf0e10cSrcweir #include <basegfx/polygon/b2dlinegeometry.hxx> 57*cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx> 58*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 59*cdf0e10cSrcweir 60*cdf0e10cSrcweir #include <utility> 61*cdf0e10cSrcweir 62*cdf0e10cSrcweir #include <comphelper/sequence.hxx> 63*cdf0e10cSrcweir #include <canvas/canvastools.hxx> 64*cdf0e10cSrcweir 65*cdf0e10cSrcweir #include "textlayout.hxx" 66*cdf0e10cSrcweir #include "canvashelper.hxx" 67*cdf0e10cSrcweir #include "canvasbitmap.hxx" 68*cdf0e10cSrcweir #include "impltools.hxx" 69*cdf0e10cSrcweir #include "canvasfont.hxx" 70*cdf0e10cSrcweir 71*cdf0e10cSrcweir 72*cdf0e10cSrcweir using namespace ::com::sun::star; 73*cdf0e10cSrcweir 74*cdf0e10cSrcweir namespace vclcanvas 75*cdf0e10cSrcweir { 76*cdf0e10cSrcweir namespace 77*cdf0e10cSrcweir { 78*cdf0e10cSrcweir basegfx::B2DLineJoin b2DJoineFromJoin( sal_Int8 nJoinType ) 79*cdf0e10cSrcweir { 80*cdf0e10cSrcweir switch( nJoinType ) 81*cdf0e10cSrcweir { 82*cdf0e10cSrcweir case rendering::PathJoinType::NONE: 83*cdf0e10cSrcweir return basegfx::B2DLINEJOIN_NONE; 84*cdf0e10cSrcweir 85*cdf0e10cSrcweir case rendering::PathJoinType::MITER: 86*cdf0e10cSrcweir return basegfx::B2DLINEJOIN_MITER; 87*cdf0e10cSrcweir 88*cdf0e10cSrcweir case rendering::PathJoinType::ROUND: 89*cdf0e10cSrcweir return basegfx::B2DLINEJOIN_ROUND; 90*cdf0e10cSrcweir 91*cdf0e10cSrcweir case rendering::PathJoinType::BEVEL: 92*cdf0e10cSrcweir return basegfx::B2DLINEJOIN_BEVEL; 93*cdf0e10cSrcweir 94*cdf0e10cSrcweir default: 95*cdf0e10cSrcweir ENSURE_OR_THROW( false, 96*cdf0e10cSrcweir "b2DJoineFromJoin(): Unexpected join type" ); 97*cdf0e10cSrcweir } 98*cdf0e10cSrcweir 99*cdf0e10cSrcweir return basegfx::B2DLINEJOIN_NONE; 100*cdf0e10cSrcweir } 101*cdf0e10cSrcweir } 102*cdf0e10cSrcweir 103*cdf0e10cSrcweir CanvasHelper::CanvasHelper() : 104*cdf0e10cSrcweir mpDevice(), 105*cdf0e10cSrcweir mpProtectedOutDev(), 106*cdf0e10cSrcweir mpOutDev(), 107*cdf0e10cSrcweir mp2ndOutDev(), 108*cdf0e10cSrcweir mbHaveAlpha( false ) 109*cdf0e10cSrcweir { 110*cdf0e10cSrcweir } 111*cdf0e10cSrcweir 112*cdf0e10cSrcweir void CanvasHelper::disposing() 113*cdf0e10cSrcweir { 114*cdf0e10cSrcweir mpDevice = NULL; 115*cdf0e10cSrcweir mpProtectedOutDev.reset(); 116*cdf0e10cSrcweir mpOutDev.reset(); 117*cdf0e10cSrcweir mp2ndOutDev.reset(); 118*cdf0e10cSrcweir } 119*cdf0e10cSrcweir 120*cdf0e10cSrcweir void CanvasHelper::init( rendering::XGraphicDevice& rDevice, 121*cdf0e10cSrcweir const OutDevProviderSharedPtr& rOutDev, 122*cdf0e10cSrcweir bool bProtect, 123*cdf0e10cSrcweir bool bHaveAlpha ) 124*cdf0e10cSrcweir { 125*cdf0e10cSrcweir // cast away const, need to change refcount (as this is 126*cdf0e10cSrcweir // ~invisible to client code, still logically const) 127*cdf0e10cSrcweir mpDevice = &rDevice; 128*cdf0e10cSrcweir mbHaveAlpha = bHaveAlpha; 129*cdf0e10cSrcweir 130*cdf0e10cSrcweir setOutDev( rOutDev, bProtect ); 131*cdf0e10cSrcweir } 132*cdf0e10cSrcweir 133*cdf0e10cSrcweir void CanvasHelper::setOutDev( const OutDevProviderSharedPtr& rOutDev, 134*cdf0e10cSrcweir bool bProtect ) 135*cdf0e10cSrcweir { 136*cdf0e10cSrcweir if( bProtect ) 137*cdf0e10cSrcweir mpProtectedOutDev = rOutDev; 138*cdf0e10cSrcweir else 139*cdf0e10cSrcweir mpProtectedOutDev.reset(); 140*cdf0e10cSrcweir 141*cdf0e10cSrcweir mpOutDev = rOutDev; 142*cdf0e10cSrcweir } 143*cdf0e10cSrcweir 144*cdf0e10cSrcweir void CanvasHelper::setBackgroundOutDev( const OutDevProviderSharedPtr& rOutDev ) 145*cdf0e10cSrcweir { 146*cdf0e10cSrcweir mp2ndOutDev = rOutDev; 147*cdf0e10cSrcweir mp2ndOutDev->getOutDev().EnableMapMode( sal_False ); 148*cdf0e10cSrcweir } 149*cdf0e10cSrcweir 150*cdf0e10cSrcweir void CanvasHelper::clear() 151*cdf0e10cSrcweir { 152*cdf0e10cSrcweir // are we disposed? 153*cdf0e10cSrcweir if( mpOutDev ) 154*cdf0e10cSrcweir { 155*cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 156*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 157*cdf0e10cSrcweir 158*cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 159*cdf0e10cSrcweir rOutDev.SetLineColor( COL_WHITE ); 160*cdf0e10cSrcweir rOutDev.SetFillColor( COL_WHITE ); 161*cdf0e10cSrcweir rOutDev.DrawRect( Rectangle( Point(), 162*cdf0e10cSrcweir rOutDev.GetOutputSizePixel()) ); 163*cdf0e10cSrcweir 164*cdf0e10cSrcweir if( mp2ndOutDev ) 165*cdf0e10cSrcweir { 166*cdf0e10cSrcweir OutputDevice& rOutDev2( mp2ndOutDev->getOutDev() ); 167*cdf0e10cSrcweir 168*cdf0e10cSrcweir rOutDev2.SetDrawMode( DRAWMODE_DEFAULT ); 169*cdf0e10cSrcweir rOutDev2.EnableMapMode( sal_False ); 170*cdf0e10cSrcweir rOutDev2.SetLineColor( COL_WHITE ); 171*cdf0e10cSrcweir rOutDev2.SetFillColor( COL_WHITE ); 172*cdf0e10cSrcweir rOutDev2.DrawRect( Rectangle( Point(), 173*cdf0e10cSrcweir rOutDev2.GetOutputSizePixel()) ); 174*cdf0e10cSrcweir rOutDev2.SetDrawMode( DRAWMODE_BLACKLINE | DRAWMODE_BLACKFILL | DRAWMODE_BLACKTEXT | 175*cdf0e10cSrcweir DRAWMODE_BLACKGRADIENT | DRAWMODE_BLACKBITMAP ); 176*cdf0e10cSrcweir } 177*cdf0e10cSrcweir } 178*cdf0e10cSrcweir } 179*cdf0e10cSrcweir 180*cdf0e10cSrcweir void CanvasHelper::drawPoint( const rendering::XCanvas* , 181*cdf0e10cSrcweir const geometry::RealPoint2D& aPoint, 182*cdf0e10cSrcweir const rendering::ViewState& viewState, 183*cdf0e10cSrcweir const rendering::RenderState& renderState ) 184*cdf0e10cSrcweir { 185*cdf0e10cSrcweir // are we disposed? 186*cdf0e10cSrcweir if( mpOutDev ) 187*cdf0e10cSrcweir { 188*cdf0e10cSrcweir // nope, render 189*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 190*cdf0e10cSrcweir setupOutDevState( viewState, renderState, LINE_COLOR ); 191*cdf0e10cSrcweir 192*cdf0e10cSrcweir const Point aOutPoint( tools::mapRealPoint2D( aPoint, 193*cdf0e10cSrcweir viewState, renderState ) ); 194*cdf0e10cSrcweir // TODO(F1): alpha 195*cdf0e10cSrcweir mpOutDev->getOutDev().DrawPixel( aOutPoint ); 196*cdf0e10cSrcweir 197*cdf0e10cSrcweir if( mp2ndOutDev ) 198*cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPixel( aOutPoint ); 199*cdf0e10cSrcweir } 200*cdf0e10cSrcweir } 201*cdf0e10cSrcweir 202*cdf0e10cSrcweir void CanvasHelper::drawLine( const rendering::XCanvas* , 203*cdf0e10cSrcweir const geometry::RealPoint2D& aStartRealPoint2D, 204*cdf0e10cSrcweir const geometry::RealPoint2D& aEndRealPoint2D, 205*cdf0e10cSrcweir const rendering::ViewState& viewState, 206*cdf0e10cSrcweir const rendering::RenderState& renderState ) 207*cdf0e10cSrcweir { 208*cdf0e10cSrcweir // are we disposed? 209*cdf0e10cSrcweir if( mpOutDev ) 210*cdf0e10cSrcweir { 211*cdf0e10cSrcweir // nope, render 212*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 213*cdf0e10cSrcweir setupOutDevState( viewState, renderState, LINE_COLOR ); 214*cdf0e10cSrcweir 215*cdf0e10cSrcweir const Point aStartPoint( tools::mapRealPoint2D( aStartRealPoint2D, 216*cdf0e10cSrcweir viewState, renderState ) ); 217*cdf0e10cSrcweir const Point aEndPoint( tools::mapRealPoint2D( aEndRealPoint2D, 218*cdf0e10cSrcweir viewState, renderState ) ); 219*cdf0e10cSrcweir // TODO(F2): alpha 220*cdf0e10cSrcweir mpOutDev->getOutDev().DrawLine( aStartPoint, aEndPoint ); 221*cdf0e10cSrcweir 222*cdf0e10cSrcweir if( mp2ndOutDev ) 223*cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawLine( aStartPoint, aEndPoint ); 224*cdf0e10cSrcweir } 225*cdf0e10cSrcweir } 226*cdf0e10cSrcweir 227*cdf0e10cSrcweir void CanvasHelper::drawBezier( const rendering::XCanvas* , 228*cdf0e10cSrcweir const geometry::RealBezierSegment2D& aBezierSegment, 229*cdf0e10cSrcweir const geometry::RealPoint2D& _aEndPoint, 230*cdf0e10cSrcweir const rendering::ViewState& viewState, 231*cdf0e10cSrcweir const rendering::RenderState& renderState ) 232*cdf0e10cSrcweir { 233*cdf0e10cSrcweir if( mpOutDev ) 234*cdf0e10cSrcweir { 235*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 236*cdf0e10cSrcweir setupOutDevState( viewState, renderState, LINE_COLOR ); 237*cdf0e10cSrcweir 238*cdf0e10cSrcweir const Point& rStartPoint( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.Px, 239*cdf0e10cSrcweir aBezierSegment.Py), 240*cdf0e10cSrcweir viewState, renderState ) ); 241*cdf0e10cSrcweir const Point& rCtrlPoint1( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.C1x, 242*cdf0e10cSrcweir aBezierSegment.C1y), 243*cdf0e10cSrcweir viewState, renderState ) ); 244*cdf0e10cSrcweir const Point& rCtrlPoint2( tools::mapRealPoint2D( geometry::RealPoint2D(aBezierSegment.C2x, 245*cdf0e10cSrcweir aBezierSegment.C2y), 246*cdf0e10cSrcweir viewState, renderState ) ); 247*cdf0e10cSrcweir const Point& rEndPoint( tools::mapRealPoint2D( _aEndPoint, 248*cdf0e10cSrcweir viewState, renderState ) ); 249*cdf0e10cSrcweir 250*cdf0e10cSrcweir ::Polygon aPoly(4); 251*cdf0e10cSrcweir aPoly.SetPoint( rStartPoint, 0 ); 252*cdf0e10cSrcweir aPoly.SetFlags( 0, POLY_NORMAL ); 253*cdf0e10cSrcweir aPoly.SetPoint( rCtrlPoint1, 1 ); 254*cdf0e10cSrcweir aPoly.SetFlags( 1, POLY_CONTROL ); 255*cdf0e10cSrcweir aPoly.SetPoint( rCtrlPoint2, 2 ); 256*cdf0e10cSrcweir aPoly.SetFlags( 2, POLY_CONTROL ); 257*cdf0e10cSrcweir aPoly.SetPoint( rEndPoint, 3 ); 258*cdf0e10cSrcweir aPoly.SetFlags( 3, POLY_NORMAL ); 259*cdf0e10cSrcweir 260*cdf0e10cSrcweir // TODO(F2): alpha 261*cdf0e10cSrcweir mpOutDev->getOutDev().DrawPolygon( aPoly ); 262*cdf0e10cSrcweir if( mp2ndOutDev ) 263*cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPolygon( aPoly ); 264*cdf0e10cSrcweir } 265*cdf0e10cSrcweir } 266*cdf0e10cSrcweir 267*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawPolyPolygon( const rendering::XCanvas* , 268*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, 269*cdf0e10cSrcweir const rendering::ViewState& viewState, 270*cdf0e10cSrcweir const rendering::RenderState& renderState ) 271*cdf0e10cSrcweir { 272*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xPolyPolygon.is(), 273*cdf0e10cSrcweir "polygon is NULL"); 274*cdf0e10cSrcweir 275*cdf0e10cSrcweir if( mpOutDev ) 276*cdf0e10cSrcweir { 277*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 278*cdf0e10cSrcweir setupOutDevState( viewState, renderState, LINE_COLOR ); 279*cdf0e10cSrcweir 280*cdf0e10cSrcweir const ::basegfx::B2DPolyPolygon& rPolyPoly( 281*cdf0e10cSrcweir ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon) ); 282*cdf0e10cSrcweir const PolyPolygon aPolyPoly( tools::mapPolyPolygon( rPolyPoly, viewState, renderState ) ); 283*cdf0e10cSrcweir 284*cdf0e10cSrcweir if( rPolyPoly.isClosed() ) 285*cdf0e10cSrcweir { 286*cdf0e10cSrcweir mpOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); 287*cdf0e10cSrcweir 288*cdf0e10cSrcweir if( mp2ndOutDev ) 289*cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); 290*cdf0e10cSrcweir } 291*cdf0e10cSrcweir else 292*cdf0e10cSrcweir { 293*cdf0e10cSrcweir // mixed open/closed state. Cannot render open polygon 294*cdf0e10cSrcweir // via DrawPolyPolygon(), since that implicitley 295*cdf0e10cSrcweir // closed every polygon. OTOH, no need to distinguish 296*cdf0e10cSrcweir // further and render closed polygons via 297*cdf0e10cSrcweir // DrawPolygon(), and open ones via DrawPolyLine(): 298*cdf0e10cSrcweir // closed polygons will simply already contain the 299*cdf0e10cSrcweir // closing segment. 300*cdf0e10cSrcweir sal_uInt16 nSize( aPolyPoly.Count() ); 301*cdf0e10cSrcweir 302*cdf0e10cSrcweir for( sal_uInt16 i=0; i<nSize; ++i ) 303*cdf0e10cSrcweir { 304*cdf0e10cSrcweir mpOutDev->getOutDev().DrawPolyLine( aPolyPoly[i] ); 305*cdf0e10cSrcweir 306*cdf0e10cSrcweir if( mp2ndOutDev ) 307*cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPolyLine( aPolyPoly[i] ); 308*cdf0e10cSrcweir } 309*cdf0e10cSrcweir } 310*cdf0e10cSrcweir } 311*cdf0e10cSrcweir 312*cdf0e10cSrcweir // TODO(P1): Provide caching here. 313*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 314*cdf0e10cSrcweir } 315*cdf0e10cSrcweir 316*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokePolyPolygon( const rendering::XCanvas* , 317*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, 318*cdf0e10cSrcweir const rendering::ViewState& viewState, 319*cdf0e10cSrcweir const rendering::RenderState& renderState, 320*cdf0e10cSrcweir const rendering::StrokeAttributes& strokeAttributes ) 321*cdf0e10cSrcweir { 322*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xPolyPolygon.is(), 323*cdf0e10cSrcweir "polygon is NULL"); 324*cdf0e10cSrcweir 325*cdf0e10cSrcweir if( mpOutDev ) 326*cdf0e10cSrcweir { 327*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 328*cdf0e10cSrcweir 329*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 330*cdf0e10cSrcweir ::canvas::tools::mergeViewAndRenderTransform(aMatrix, viewState, renderState); 331*cdf0e10cSrcweir 332*cdf0e10cSrcweir ::basegfx::B2DSize aLinePixelSize(strokeAttributes.StrokeWidth, 333*cdf0e10cSrcweir strokeAttributes.StrokeWidth); 334*cdf0e10cSrcweir aLinePixelSize *= aMatrix; 335*cdf0e10cSrcweir 336*cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aPolyPoly( 337*cdf0e10cSrcweir ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon) ); 338*cdf0e10cSrcweir 339*cdf0e10cSrcweir if( aPolyPoly.areControlPointsUsed() ) 340*cdf0e10cSrcweir { 341*cdf0e10cSrcweir // AW: Not needed for ApplyLineDashing anymore; should be removed 342*cdf0e10cSrcweir aPolyPoly = ::basegfx::tools::adaptiveSubdivideByAngle(aPolyPoly); 343*cdf0e10cSrcweir } 344*cdf0e10cSrcweir 345*cdf0e10cSrcweir // apply dashing, if any 346*cdf0e10cSrcweir if( strokeAttributes.DashArray.getLength() ) 347*cdf0e10cSrcweir { 348*cdf0e10cSrcweir const ::std::vector<double>& aDashArray( 349*cdf0e10cSrcweir ::comphelper::sequenceToContainer< ::std::vector<double> >(strokeAttributes.DashArray) ); 350*cdf0e10cSrcweir 351*cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aDashedPolyPoly; 352*cdf0e10cSrcweir 353*cdf0e10cSrcweir for( sal_uInt32 i=0; i<aPolyPoly.count(); ++i ) 354*cdf0e10cSrcweir { 355*cdf0e10cSrcweir // AW: new interface; You may also get gaps in the same run now 356*cdf0e10cSrcweir basegfx::tools::applyLineDashing(aPolyPoly.getB2DPolygon(i), aDashArray, &aDashedPolyPoly); 357*cdf0e10cSrcweir //aDashedPolyPoly.append( 358*cdf0e10cSrcweir // ::basegfx::tools::applyLineDashing( aPolyPoly.getB2DPolygon(i), 359*cdf0e10cSrcweir // aDashArray ) ); 360*cdf0e10cSrcweir } 361*cdf0e10cSrcweir 362*cdf0e10cSrcweir aPolyPoly = aDashedPolyPoly; 363*cdf0e10cSrcweir } 364*cdf0e10cSrcweir 365*cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aStrokedPolyPoly; 366*cdf0e10cSrcweir if( aLinePixelSize.getLength() < 1.42 ) 367*cdf0e10cSrcweir { 368*cdf0e10cSrcweir // line width < 1.0 in device pixel, thus, output as a 369*cdf0e10cSrcweir // simple hairline poly-polygon 370*cdf0e10cSrcweir setupOutDevState( viewState, renderState, LINE_COLOR ); 371*cdf0e10cSrcweir 372*cdf0e10cSrcweir aStrokedPolyPoly = aPolyPoly; 373*cdf0e10cSrcweir } 374*cdf0e10cSrcweir else 375*cdf0e10cSrcweir { 376*cdf0e10cSrcweir // render as a 'thick' line 377*cdf0e10cSrcweir setupOutDevState( viewState, renderState, FILL_COLOR ); 378*cdf0e10cSrcweir 379*cdf0e10cSrcweir for( sal_uInt32 i=0; i<aPolyPoly.count(); ++i ) 380*cdf0e10cSrcweir { 381*cdf0e10cSrcweir // TODO(F2): Use MiterLimit from StrokeAttributes, 382*cdf0e10cSrcweir // need to convert it here to angle. 383*cdf0e10cSrcweir 384*cdf0e10cSrcweir // TODO(F2): Also use Cap settings from 385*cdf0e10cSrcweir // StrokeAttributes, the 386*cdf0e10cSrcweir // createAreaGeometryForLineStartEnd() method does not 387*cdf0e10cSrcweir // seem to fit very well here 388*cdf0e10cSrcweir 389*cdf0e10cSrcweir // AW: New interface, will create bezier polygons now 390*cdf0e10cSrcweir aStrokedPolyPoly.append(basegfx::tools::createAreaGeometry( 391*cdf0e10cSrcweir aPolyPoly.getB2DPolygon(i), strokeAttributes.StrokeWidth*0.5, b2DJoineFromJoin(strokeAttributes.JoinType))); 392*cdf0e10cSrcweir //aStrokedPolyPoly.append( 393*cdf0e10cSrcweir // ::basegfx::tools::createAreaGeometryForPolygon( aPolyPoly.getB2DPolygon(i), 394*cdf0e10cSrcweir // strokeAttributes.StrokeWidth*0.5, 395*cdf0e10cSrcweir // b2DJoineFromJoin(strokeAttributes.JoinType) ) ); 396*cdf0e10cSrcweir } 397*cdf0e10cSrcweir } 398*cdf0e10cSrcweir 399*cdf0e10cSrcweir // transform only _now_, all the StrokeAttributes are in 400*cdf0e10cSrcweir // user coordinates. 401*cdf0e10cSrcweir aStrokedPolyPoly.transform( aMatrix ); 402*cdf0e10cSrcweir 403*cdf0e10cSrcweir const PolyPolygon aVCLPolyPoly( aStrokedPolyPoly ); 404*cdf0e10cSrcweir 405*cdf0e10cSrcweir // TODO(F2): When using alpha here, must handle that via 406*cdf0e10cSrcweir // temporary surface or somesuch. 407*cdf0e10cSrcweir 408*cdf0e10cSrcweir // Note: the generated stroke poly-polygon is NOT free of 409*cdf0e10cSrcweir // self-intersections. Therefore, if we would render it 410*cdf0e10cSrcweir // via OutDev::DrawPolyPolygon(), on/off fill would 411*cdf0e10cSrcweir // generate off areas on those self-intersections. 412*cdf0e10cSrcweir sal_uInt16 nSize( aVCLPolyPoly.Count() ); 413*cdf0e10cSrcweir 414*cdf0e10cSrcweir for( sal_uInt16 i=0; i<nSize; ++i ) 415*cdf0e10cSrcweir { 416*cdf0e10cSrcweir if( aStrokedPolyPoly.getB2DPolygon( i ).isClosed() ) { 417*cdf0e10cSrcweir mpOutDev->getOutDev().DrawPolygon( aVCLPolyPoly[i] ); 418*cdf0e10cSrcweir if( mp2ndOutDev ) 419*cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPolygon( aVCLPolyPoly[i] ); 420*cdf0e10cSrcweir } else { 421*cdf0e10cSrcweir const sal_uInt16 nPolySize = aVCLPolyPoly[i].GetSize(); 422*cdf0e10cSrcweir if( nPolySize ) { 423*cdf0e10cSrcweir Point rPrevPoint = aVCLPolyPoly[i].GetPoint( 0 ); 424*cdf0e10cSrcweir Point rPoint; 425*cdf0e10cSrcweir 426*cdf0e10cSrcweir for( sal_uInt16 j=1; j<nPolySize; j++ ) { 427*cdf0e10cSrcweir rPoint = aVCLPolyPoly[i].GetPoint( j ); 428*cdf0e10cSrcweir mpOutDev->getOutDev().DrawLine( rPrevPoint, rPoint ); 429*cdf0e10cSrcweir if( mp2ndOutDev ) 430*cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawLine( rPrevPoint, rPoint ); 431*cdf0e10cSrcweir rPrevPoint = rPoint; 432*cdf0e10cSrcweir } 433*cdf0e10cSrcweir } 434*cdf0e10cSrcweir } 435*cdf0e10cSrcweir } 436*cdf0e10cSrcweir } 437*cdf0e10cSrcweir 438*cdf0e10cSrcweir // TODO(P1): Provide caching here. 439*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 440*cdf0e10cSrcweir } 441*cdf0e10cSrcweir 442*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTexturedPolyPolygon( const rendering::XCanvas* , 443*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& , 444*cdf0e10cSrcweir const rendering::ViewState& , 445*cdf0e10cSrcweir const rendering::RenderState& , 446*cdf0e10cSrcweir const uno::Sequence< rendering::Texture >& , 447*cdf0e10cSrcweir const rendering::StrokeAttributes& ) 448*cdf0e10cSrcweir { 449*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 450*cdf0e10cSrcweir } 451*cdf0e10cSrcweir 452*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::strokeTextureMappedPolyPolygon( const rendering::XCanvas* , 453*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& , 454*cdf0e10cSrcweir const rendering::ViewState& , 455*cdf0e10cSrcweir const rendering::RenderState& , 456*cdf0e10cSrcweir const uno::Sequence< rendering::Texture >& , 457*cdf0e10cSrcweir const uno::Reference< geometry::XMapping2D >& , 458*cdf0e10cSrcweir const rendering::StrokeAttributes& ) 459*cdf0e10cSrcweir { 460*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 461*cdf0e10cSrcweir } 462*cdf0e10cSrcweir 463*cdf0e10cSrcweir uno::Reference< rendering::XPolyPolygon2D > CanvasHelper::queryStrokeShapes( const rendering::XCanvas* , 464*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& , 465*cdf0e10cSrcweir const rendering::ViewState& , 466*cdf0e10cSrcweir const rendering::RenderState& , 467*cdf0e10cSrcweir const rendering::StrokeAttributes& ) 468*cdf0e10cSrcweir { 469*cdf0e10cSrcweir return uno::Reference< rendering::XPolyPolygon2D >(NULL); 470*cdf0e10cSrcweir } 471*cdf0e10cSrcweir 472*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillPolyPolygon( const rendering::XCanvas* , 473*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& xPolyPolygon, 474*cdf0e10cSrcweir const rendering::ViewState& viewState, 475*cdf0e10cSrcweir const rendering::RenderState& renderState ) 476*cdf0e10cSrcweir { 477*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xPolyPolygon.is(), 478*cdf0e10cSrcweir "polygon is NULL"); 479*cdf0e10cSrcweir 480*cdf0e10cSrcweir if( mpOutDev ) 481*cdf0e10cSrcweir { 482*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 483*cdf0e10cSrcweir 484*cdf0e10cSrcweir const int nTransparency( setupOutDevState( viewState, renderState, FILL_COLOR ) ); 485*cdf0e10cSrcweir const int nTransPercent( (nTransparency * 100 + 128) / 255 ); // normal rounding, no truncation here 486*cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aB2DPolyPoly( 487*cdf0e10cSrcweir ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(xPolyPolygon)); 488*cdf0e10cSrcweir aB2DPolyPoly.setClosed(true); // ensure closed poly, otherwise VCL does not fill 489*cdf0e10cSrcweir const PolyPolygon aPolyPoly( tools::mapPolyPolygon( 490*cdf0e10cSrcweir aB2DPolyPoly, 491*cdf0e10cSrcweir viewState, renderState ) ); 492*cdf0e10cSrcweir const bool bSourceAlpha( renderState.CompositeOperation == rendering::CompositeOperation::SOURCE ); 493*cdf0e10cSrcweir if( !nTransparency || bSourceAlpha ) 494*cdf0e10cSrcweir { 495*cdf0e10cSrcweir mpOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); 496*cdf0e10cSrcweir } 497*cdf0e10cSrcweir else 498*cdf0e10cSrcweir { 499*cdf0e10cSrcweir mpOutDev->getOutDev().DrawTransparent( aPolyPoly, (sal_uInt16)nTransPercent ); 500*cdf0e10cSrcweir } 501*cdf0e10cSrcweir 502*cdf0e10cSrcweir if( mp2ndOutDev ) 503*cdf0e10cSrcweir { 504*cdf0e10cSrcweir if( !nTransparency || bSourceAlpha ) 505*cdf0e10cSrcweir { 506*cdf0e10cSrcweir // HACK. Normally, CanvasHelper does not care 507*cdf0e10cSrcweir // about actually what mp2ndOutDev is... 508*cdf0e10cSrcweir if( bSourceAlpha && nTransparency == 255 ) 509*cdf0e10cSrcweir { 510*cdf0e10cSrcweir mp2ndOutDev->getOutDev().SetDrawMode( DRAWMODE_WHITELINE | DRAWMODE_WHITEFILL | DRAWMODE_WHITETEXT | 511*cdf0e10cSrcweir DRAWMODE_WHITEGRADIENT | DRAWMODE_WHITEBITMAP ); 512*cdf0e10cSrcweir mp2ndOutDev->getOutDev().SetFillColor( COL_WHITE ); 513*cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); 514*cdf0e10cSrcweir mp2ndOutDev->getOutDev().SetDrawMode( DRAWMODE_BLACKLINE | DRAWMODE_BLACKFILL | DRAWMODE_BLACKTEXT | 515*cdf0e10cSrcweir DRAWMODE_BLACKGRADIENT | DRAWMODE_BLACKBITMAP ); 516*cdf0e10cSrcweir } 517*cdf0e10cSrcweir else 518*cdf0e10cSrcweir { 519*cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawPolyPolygon( aPolyPoly ); 520*cdf0e10cSrcweir } 521*cdf0e10cSrcweir } 522*cdf0e10cSrcweir else 523*cdf0e10cSrcweir { 524*cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawTransparent( aPolyPoly, (sal_uInt16)nTransPercent ); 525*cdf0e10cSrcweir } 526*cdf0e10cSrcweir } 527*cdf0e10cSrcweir } 528*cdf0e10cSrcweir 529*cdf0e10cSrcweir // TODO(P1): Provide caching here. 530*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 531*cdf0e10cSrcweir } 532*cdf0e10cSrcweir 533*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::fillTextureMappedPolyPolygon( const rendering::XCanvas* , 534*cdf0e10cSrcweir const uno::Reference< rendering::XPolyPolygon2D >& , 535*cdf0e10cSrcweir const rendering::ViewState& , 536*cdf0e10cSrcweir const rendering::RenderState& , 537*cdf0e10cSrcweir const uno::Sequence< rendering::Texture >& , 538*cdf0e10cSrcweir const uno::Reference< geometry::XMapping2D >& ) 539*cdf0e10cSrcweir { 540*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 541*cdf0e10cSrcweir } 542*cdf0e10cSrcweir 543*cdf0e10cSrcweir uno::Reference< rendering::XCanvasFont > CanvasHelper::createFont( const rendering::XCanvas* , 544*cdf0e10cSrcweir const rendering::FontRequest& fontRequest, 545*cdf0e10cSrcweir const uno::Sequence< beans::PropertyValue >& extraFontProperties, 546*cdf0e10cSrcweir const geometry::Matrix2D& fontMatrix ) 547*cdf0e10cSrcweir { 548*cdf0e10cSrcweir if( mpOutDev && mpDevice ) 549*cdf0e10cSrcweir { 550*cdf0e10cSrcweir // TODO(F2): font properties and font matrix 551*cdf0e10cSrcweir return uno::Reference< rendering::XCanvasFont >( 552*cdf0e10cSrcweir new CanvasFont(fontRequest, extraFontProperties, fontMatrix, 553*cdf0e10cSrcweir *mpDevice, mpOutDev) ); 554*cdf0e10cSrcweir } 555*cdf0e10cSrcweir 556*cdf0e10cSrcweir return uno::Reference< rendering::XCanvasFont >(); 557*cdf0e10cSrcweir } 558*cdf0e10cSrcweir 559*cdf0e10cSrcweir uno::Sequence< rendering::FontInfo > CanvasHelper::queryAvailableFonts( const rendering::XCanvas* , 560*cdf0e10cSrcweir const rendering::FontInfo& , 561*cdf0e10cSrcweir const uno::Sequence< beans::PropertyValue >& ) 562*cdf0e10cSrcweir { 563*cdf0e10cSrcweir // TODO(F2) 564*cdf0e10cSrcweir return uno::Sequence< rendering::FontInfo >(); 565*cdf0e10cSrcweir } 566*cdf0e10cSrcweir 567*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawText( const rendering::XCanvas* , 568*cdf0e10cSrcweir const rendering::StringContext& text, 569*cdf0e10cSrcweir const uno::Reference< rendering::XCanvasFont >& xFont, 570*cdf0e10cSrcweir const rendering::ViewState& viewState, 571*cdf0e10cSrcweir const rendering::RenderState& renderState, 572*cdf0e10cSrcweir sal_Int8 textDirection ) 573*cdf0e10cSrcweir { 574*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xFont.is(), 575*cdf0e10cSrcweir "font is NULL"); 576*cdf0e10cSrcweir 577*cdf0e10cSrcweir if( mpOutDev ) 578*cdf0e10cSrcweir { 579*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 580*cdf0e10cSrcweir 581*cdf0e10cSrcweir ::Point aOutpos; 582*cdf0e10cSrcweir if( !setupTextOutput( aOutpos, viewState, renderState, xFont ) ) 583*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); // no output necessary 584*cdf0e10cSrcweir 585*cdf0e10cSrcweir // change text direction and layout mode 586*cdf0e10cSrcweir sal_uIntPtr nLayoutMode(0); 587*cdf0e10cSrcweir switch( textDirection ) 588*cdf0e10cSrcweir { 589*cdf0e10cSrcweir case rendering::TextDirection::WEAK_LEFT_TO_RIGHT: 590*cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_BIDI_LTR; 591*cdf0e10cSrcweir // FALLTHROUGH intended 592*cdf0e10cSrcweir case rendering::TextDirection::STRONG_LEFT_TO_RIGHT: 593*cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG; 594*cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_TEXTORIGIN_LEFT; 595*cdf0e10cSrcweir break; 596*cdf0e10cSrcweir 597*cdf0e10cSrcweir case rendering::TextDirection::WEAK_RIGHT_TO_LEFT: 598*cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_BIDI_RTL; 599*cdf0e10cSrcweir // FALLTHROUGH intended 600*cdf0e10cSrcweir case rendering::TextDirection::STRONG_RIGHT_TO_LEFT: 601*cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG; 602*cdf0e10cSrcweir nLayoutMode |= TEXT_LAYOUT_TEXTORIGIN_RIGHT; 603*cdf0e10cSrcweir break; 604*cdf0e10cSrcweir } 605*cdf0e10cSrcweir 606*cdf0e10cSrcweir // TODO(F2): alpha 607*cdf0e10cSrcweir mpOutDev->getOutDev().SetLayoutMode( nLayoutMode ); 608*cdf0e10cSrcweir mpOutDev->getOutDev().DrawText( aOutpos, 609*cdf0e10cSrcweir text.Text, 610*cdf0e10cSrcweir ::canvas::tools::numeric_cast<sal_uInt16>(text.StartPosition), 611*cdf0e10cSrcweir ::canvas::tools::numeric_cast<sal_uInt16>(text.Length) ); 612*cdf0e10cSrcweir 613*cdf0e10cSrcweir if( mp2ndOutDev ) 614*cdf0e10cSrcweir { 615*cdf0e10cSrcweir mp2ndOutDev->getOutDev().SetLayoutMode( nLayoutMode ); 616*cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawText( aOutpos, 617*cdf0e10cSrcweir text.Text, 618*cdf0e10cSrcweir ::canvas::tools::numeric_cast<sal_uInt16>(text.StartPosition), 619*cdf0e10cSrcweir ::canvas::tools::numeric_cast<sal_uInt16>(text.Length) ); 620*cdf0e10cSrcweir } 621*cdf0e10cSrcweir } 622*cdf0e10cSrcweir 623*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 624*cdf0e10cSrcweir } 625*cdf0e10cSrcweir 626*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawTextLayout( const rendering::XCanvas* , 627*cdf0e10cSrcweir const uno::Reference< rendering::XTextLayout >& xLayoutedText, 628*cdf0e10cSrcweir const rendering::ViewState& viewState, 629*cdf0e10cSrcweir const rendering::RenderState& renderState ) 630*cdf0e10cSrcweir { 631*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xLayoutedText.is(), 632*cdf0e10cSrcweir "layout is NULL"); 633*cdf0e10cSrcweir 634*cdf0e10cSrcweir TextLayout* pTextLayout = dynamic_cast< TextLayout* >( xLayoutedText.get() ); 635*cdf0e10cSrcweir 636*cdf0e10cSrcweir if( pTextLayout ) 637*cdf0e10cSrcweir { 638*cdf0e10cSrcweir if( mpOutDev ) 639*cdf0e10cSrcweir { 640*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 641*cdf0e10cSrcweir 642*cdf0e10cSrcweir // TODO(T3): Race condition. We're taking the font 643*cdf0e10cSrcweir // from xLayoutedText, and then calling draw() at it, 644*cdf0e10cSrcweir // without exclusive access. Move setupTextOutput(), 645*cdf0e10cSrcweir // e.g. to impltools? 646*cdf0e10cSrcweir 647*cdf0e10cSrcweir ::Point aOutpos; 648*cdf0e10cSrcweir if( !setupTextOutput( aOutpos, viewState, renderState, xLayoutedText->getFont() ) ) 649*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); // no output necessary 650*cdf0e10cSrcweir 651*cdf0e10cSrcweir // TODO(F2): What about the offset scalings? 652*cdf0e10cSrcweir // TODO(F2): alpha 653*cdf0e10cSrcweir pTextLayout->draw( mpOutDev->getOutDev(), aOutpos, viewState, renderState ); 654*cdf0e10cSrcweir 655*cdf0e10cSrcweir if( mp2ndOutDev ) 656*cdf0e10cSrcweir pTextLayout->draw( mp2ndOutDev->getOutDev(), aOutpos, viewState, renderState ); 657*cdf0e10cSrcweir } 658*cdf0e10cSrcweir } 659*cdf0e10cSrcweir else 660*cdf0e10cSrcweir { 661*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( false, 662*cdf0e10cSrcweir "TextLayout not compatible with this canvas" ); 663*cdf0e10cSrcweir } 664*cdf0e10cSrcweir 665*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 666*cdf0e10cSrcweir } 667*cdf0e10cSrcweir 668*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::implDrawBitmap( const rendering::XCanvas* pCanvas, 669*cdf0e10cSrcweir const uno::Reference< rendering::XBitmap >& xBitmap, 670*cdf0e10cSrcweir const rendering::ViewState& viewState, 671*cdf0e10cSrcweir const rendering::RenderState& renderState, 672*cdf0e10cSrcweir bool bModulateColors ) 673*cdf0e10cSrcweir { 674*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xBitmap.is(), 675*cdf0e10cSrcweir "bitmap is NULL"); 676*cdf0e10cSrcweir 677*cdf0e10cSrcweir ::canvas::tools::verifyInput( renderState, 678*cdf0e10cSrcweir BOOST_CURRENT_FUNCTION, 679*cdf0e10cSrcweir mpDevice, 680*cdf0e10cSrcweir 4, 681*cdf0e10cSrcweir bModulateColors ? 3 : 0 ); 682*cdf0e10cSrcweir 683*cdf0e10cSrcweir if( mpOutDev ) 684*cdf0e10cSrcweir { 685*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 686*cdf0e10cSrcweir setupOutDevState( viewState, renderState, IGNORE_COLOR ); 687*cdf0e10cSrcweir 688*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 689*cdf0e10cSrcweir ::canvas::tools::mergeViewAndRenderTransform(aMatrix, viewState, renderState); 690*cdf0e10cSrcweir 691*cdf0e10cSrcweir ::basegfx::B2DPoint aOutputPos( 0.0, 0.0 ); 692*cdf0e10cSrcweir aOutputPos *= aMatrix; 693*cdf0e10cSrcweir 694*cdf0e10cSrcweir BitmapEx aBmpEx( tools::bitmapExFromXBitmap(xBitmap) ); 695*cdf0e10cSrcweir 696*cdf0e10cSrcweir // TODO(F2): Implement modulation again for other color 697*cdf0e10cSrcweir // channels (currently, works only for alpha). Note: this 698*cdf0e10cSrcweir // is already implemented in transformBitmap() 699*cdf0e10cSrcweir if( bModulateColors && 700*cdf0e10cSrcweir renderState.DeviceColor.getLength() > 3 ) 701*cdf0e10cSrcweir { 702*cdf0e10cSrcweir // optimize away the case where alpha modulation value 703*cdf0e10cSrcweir // is 1.0 - we then simply switch off modulation at all 704*cdf0e10cSrcweir bModulateColors = !::rtl::math::approxEqual( 705*cdf0e10cSrcweir renderState.DeviceColor[3], 1.0); 706*cdf0e10cSrcweir } 707*cdf0e10cSrcweir 708*cdf0e10cSrcweir // check whether we can render bitmap as-is: must not 709*cdf0e10cSrcweir // modulate colors, matrix must either be the identity 710*cdf0e10cSrcweir // transform (that's clear), _or_ contain only 711*cdf0e10cSrcweir // translational components. 712*cdf0e10cSrcweir if( !bModulateColors && 713*cdf0e10cSrcweir (aMatrix.isIdentity() || 714*cdf0e10cSrcweir (::basegfx::fTools::equalZero( aMatrix.get(0,1) ) && 715*cdf0e10cSrcweir ::basegfx::fTools::equalZero( aMatrix.get(1,0) ) && 716*cdf0e10cSrcweir ::rtl::math::approxEqual(aMatrix.get(0,0), 1.0) && 717*cdf0e10cSrcweir ::rtl::math::approxEqual(aMatrix.get(1,1), 1.0)) ) ) 718*cdf0e10cSrcweir { 719*cdf0e10cSrcweir // optimized case: identity matrix, or only 720*cdf0e10cSrcweir // translational components. 721*cdf0e10cSrcweir mpOutDev->getOutDev().DrawBitmapEx( ::vcl::unotools::pointFromB2DPoint( aOutputPos ), 722*cdf0e10cSrcweir aBmpEx ); 723*cdf0e10cSrcweir 724*cdf0e10cSrcweir if( mp2ndOutDev ) 725*cdf0e10cSrcweir mp2ndOutDev->getOutDev().DrawBitmapEx( ::vcl::unotools::pointFromB2DPoint( aOutputPos ), 726*cdf0e10cSrcweir aBmpEx ); 727*cdf0e10cSrcweir 728*cdf0e10cSrcweir // Returning a cache object is not useful, the XBitmap 729*cdf0e10cSrcweir // itself serves this purpose 730*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 731*cdf0e10cSrcweir } 732*cdf0e10cSrcweir else 733*cdf0e10cSrcweir { 734*cdf0e10cSrcweir // Matrix contains non-trivial transformation (or 735*cdf0e10cSrcweir // color modulation is requested), decompose to check 736*cdf0e10cSrcweir // whether GraphicObject suffices 737*cdf0e10cSrcweir ::basegfx::B2DVector aScale; 738*cdf0e10cSrcweir double nRotate; 739*cdf0e10cSrcweir double nShearX; 740*cdf0e10cSrcweir aMatrix.decompose( aScale, aOutputPos, nRotate, nShearX ); 741*cdf0e10cSrcweir 742*cdf0e10cSrcweir GraphicAttr aGrfAttr; 743*cdf0e10cSrcweir GraphicObjectSharedPtr pGrfObj; 744*cdf0e10cSrcweir 745*cdf0e10cSrcweir ::Size aBmpSize( aBmpEx.GetSizePixel() ); 746*cdf0e10cSrcweir 747*cdf0e10cSrcweir // setup alpha modulation 748*cdf0e10cSrcweir if( bModulateColors ) 749*cdf0e10cSrcweir { 750*cdf0e10cSrcweir const double nAlphaModulation( renderState.DeviceColor[3] ); 751*cdf0e10cSrcweir 752*cdf0e10cSrcweir // TODO(F1): Note that the GraphicManager has a 753*cdf0e10cSrcweir // subtle difference in how it calculates the 754*cdf0e10cSrcweir // resulting alpha value: it's using the inverse 755*cdf0e10cSrcweir // alpha values (i.e. 'transparency'), and 756*cdf0e10cSrcweir // calculates transOrig + transModulate, instead 757*cdf0e10cSrcweir // of transOrig + transModulate - 758*cdf0e10cSrcweir // transOrig*transModulate (which would be 759*cdf0e10cSrcweir // equivalent to the origAlpha*modulateAlpha the 760*cdf0e10cSrcweir // DX canvas performs) 761*cdf0e10cSrcweir aGrfAttr.SetTransparency( 762*cdf0e10cSrcweir static_cast< sal_uInt8 >( 763*cdf0e10cSrcweir ::basegfx::fround( 255.0*( 1.0 - nAlphaModulation ) ) ) ); 764*cdf0e10cSrcweir } 765*cdf0e10cSrcweir 766*cdf0e10cSrcweir if( ::basegfx::fTools::equalZero( nShearX ) ) 767*cdf0e10cSrcweir { 768*cdf0e10cSrcweir // no shear, GraphicObject is enough (the 769*cdf0e10cSrcweir // GraphicObject only supports scaling, rotation 770*cdf0e10cSrcweir // and translation) 771*cdf0e10cSrcweir 772*cdf0e10cSrcweir // #i75339# don't apply mirror flags, having 773*cdf0e10cSrcweir // negative size values is enough to make 774*cdf0e10cSrcweir // GraphicObject flip the bitmap 775*cdf0e10cSrcweir 776*cdf0e10cSrcweir // The angle has to be mapped from radian to tenths of 777*cdf0e10cSrcweir // degress with the orientation reversed: [0,2Pi) -> 778*cdf0e10cSrcweir // (3600,0]. Note that the original angle may have 779*cdf0e10cSrcweir // values outside the [0,2Pi) interval. 780*cdf0e10cSrcweir const double nAngleInTenthOfDegrees (3600.0 - nRotate * 3600.0 / (2*M_PI)); 781*cdf0e10cSrcweir aGrfAttr.SetRotation( static_cast< sal_uInt16 >(::basegfx::fround(nAngleInTenthOfDegrees)) ); 782*cdf0e10cSrcweir 783*cdf0e10cSrcweir pGrfObj.reset( new GraphicObject( aBmpEx ) ); 784*cdf0e10cSrcweir } 785*cdf0e10cSrcweir else 786*cdf0e10cSrcweir { 787*cdf0e10cSrcweir // modify output position, to account for the fact 788*cdf0e10cSrcweir // that transformBitmap() always normalizes its output 789*cdf0e10cSrcweir // bitmap into the smallest enclosing box. 790*cdf0e10cSrcweir ::basegfx::B2DRectangle aDestRect; 791*cdf0e10cSrcweir ::canvas::tools::calcTransformedRectBounds( aDestRect, 792*cdf0e10cSrcweir ::basegfx::B2DRectangle(0, 793*cdf0e10cSrcweir 0, 794*cdf0e10cSrcweir aBmpSize.Width(), 795*cdf0e10cSrcweir aBmpSize.Height()), 796*cdf0e10cSrcweir aMatrix ); 797*cdf0e10cSrcweir 798*cdf0e10cSrcweir aOutputPos.setX( aDestRect.getMinX() ); 799*cdf0e10cSrcweir aOutputPos.setY( aDestRect.getMinY() ); 800*cdf0e10cSrcweir 801*cdf0e10cSrcweir // complex transformation, use generic affine bitmap 802*cdf0e10cSrcweir // transformation 803*cdf0e10cSrcweir aBmpEx = tools::transformBitmap( aBmpEx, 804*cdf0e10cSrcweir aMatrix, 805*cdf0e10cSrcweir renderState.DeviceColor, 806*cdf0e10cSrcweir tools::MODULATE_NONE ); 807*cdf0e10cSrcweir 808*cdf0e10cSrcweir pGrfObj.reset( new GraphicObject( aBmpEx ) ); 809*cdf0e10cSrcweir 810*cdf0e10cSrcweir // clear scale values, generated bitmap already 811*cdf0e10cSrcweir // contains scaling 812*cdf0e10cSrcweir aScale.setX( 1.0 ); aScale.setY( 1.0 ); 813*cdf0e10cSrcweir 814*cdf0e10cSrcweir // update bitmap size, bitmap has changed above. 815*cdf0e10cSrcweir aBmpSize = aBmpEx.GetSizePixel(); 816*cdf0e10cSrcweir } 817*cdf0e10cSrcweir 818*cdf0e10cSrcweir // output GraphicObject 819*cdf0e10cSrcweir const ::Point aPt( ::vcl::unotools::pointFromB2DPoint( aOutputPos ) ); 820*cdf0e10cSrcweir const ::Size aSz( ::basegfx::fround( aScale.getX() * aBmpSize.Width() ), 821*cdf0e10cSrcweir ::basegfx::fround( aScale.getY() * aBmpSize.Height() ) ); 822*cdf0e10cSrcweir 823*cdf0e10cSrcweir pGrfObj->Draw( &mpOutDev->getOutDev(), 824*cdf0e10cSrcweir aPt, 825*cdf0e10cSrcweir aSz, 826*cdf0e10cSrcweir &aGrfAttr ); 827*cdf0e10cSrcweir 828*cdf0e10cSrcweir if( mp2ndOutDev ) 829*cdf0e10cSrcweir pGrfObj->Draw( &mp2ndOutDev->getOutDev(), 830*cdf0e10cSrcweir aPt, 831*cdf0e10cSrcweir aSz, 832*cdf0e10cSrcweir &aGrfAttr ); 833*cdf0e10cSrcweir 834*cdf0e10cSrcweir // created GraphicObject, which possibly cached 835*cdf0e10cSrcweir // display bitmap - return cache object, to retain 836*cdf0e10cSrcweir // that information. 837*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >( 838*cdf0e10cSrcweir new CachedBitmap( pGrfObj, 839*cdf0e10cSrcweir aPt, 840*cdf0e10cSrcweir aSz, 841*cdf0e10cSrcweir aGrfAttr, 842*cdf0e10cSrcweir viewState, 843*cdf0e10cSrcweir renderState, 844*cdf0e10cSrcweir // cast away const, need to 845*cdf0e10cSrcweir // change refcount (as this is 846*cdf0e10cSrcweir // ~invisible to client code, 847*cdf0e10cSrcweir // still logically const) 848*cdf0e10cSrcweir const_cast< rendering::XCanvas* >(pCanvas)) ); 849*cdf0e10cSrcweir } 850*cdf0e10cSrcweir } 851*cdf0e10cSrcweir 852*cdf0e10cSrcweir // Nothing rendered 853*cdf0e10cSrcweir return uno::Reference< rendering::XCachedPrimitive >(NULL); 854*cdf0e10cSrcweir } 855*cdf0e10cSrcweir 856*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmap( const rendering::XCanvas* pCanvas, 857*cdf0e10cSrcweir const uno::Reference< rendering::XBitmap >& xBitmap, 858*cdf0e10cSrcweir const rendering::ViewState& viewState, 859*cdf0e10cSrcweir const rendering::RenderState& renderState ) 860*cdf0e10cSrcweir { 861*cdf0e10cSrcweir return implDrawBitmap( pCanvas, 862*cdf0e10cSrcweir xBitmap, 863*cdf0e10cSrcweir viewState, 864*cdf0e10cSrcweir renderState, 865*cdf0e10cSrcweir false ); 866*cdf0e10cSrcweir } 867*cdf0e10cSrcweir 868*cdf0e10cSrcweir uno::Reference< rendering::XCachedPrimitive > CanvasHelper::drawBitmapModulated( const rendering::XCanvas* pCanvas, 869*cdf0e10cSrcweir const uno::Reference< rendering::XBitmap >& xBitmap, 870*cdf0e10cSrcweir const rendering::ViewState& viewState, 871*cdf0e10cSrcweir const rendering::RenderState& renderState ) 872*cdf0e10cSrcweir { 873*cdf0e10cSrcweir return implDrawBitmap( pCanvas, 874*cdf0e10cSrcweir xBitmap, 875*cdf0e10cSrcweir viewState, 876*cdf0e10cSrcweir renderState, 877*cdf0e10cSrcweir true ); 878*cdf0e10cSrcweir } 879*cdf0e10cSrcweir 880*cdf0e10cSrcweir uno::Reference< rendering::XGraphicDevice > CanvasHelper::getDevice() 881*cdf0e10cSrcweir { 882*cdf0e10cSrcweir // cast away const, need to change refcount (as this is 883*cdf0e10cSrcweir // ~invisible to client code, still logically const) 884*cdf0e10cSrcweir return uno::Reference< rendering::XGraphicDevice >(mpDevice); 885*cdf0e10cSrcweir } 886*cdf0e10cSrcweir 887*cdf0e10cSrcweir void CanvasHelper::copyRect( const rendering::XCanvas* , 888*cdf0e10cSrcweir const uno::Reference< rendering::XBitmapCanvas >& , 889*cdf0e10cSrcweir const geometry::RealRectangle2D& , 890*cdf0e10cSrcweir const rendering::ViewState& , 891*cdf0e10cSrcweir const rendering::RenderState& , 892*cdf0e10cSrcweir const geometry::RealRectangle2D& , 893*cdf0e10cSrcweir const rendering::ViewState& , 894*cdf0e10cSrcweir const rendering::RenderState& ) 895*cdf0e10cSrcweir { 896*cdf0e10cSrcweir // TODO(F1) 897*cdf0e10cSrcweir } 898*cdf0e10cSrcweir 899*cdf0e10cSrcweir geometry::IntegerSize2D CanvasHelper::getSize() 900*cdf0e10cSrcweir { 901*cdf0e10cSrcweir if( !mpOutDev.get() ) 902*cdf0e10cSrcweir return geometry::IntegerSize2D(); // we're disposed 903*cdf0e10cSrcweir 904*cdf0e10cSrcweir return ::vcl::unotools::integerSize2DFromSize( mpOutDev->getOutDev().GetOutputSizePixel() ); 905*cdf0e10cSrcweir } 906*cdf0e10cSrcweir 907*cdf0e10cSrcweir uno::Reference< rendering::XBitmap > CanvasHelper::getScaledBitmap( const geometry::RealSize2D& newSize, 908*cdf0e10cSrcweir sal_Bool beFast ) 909*cdf0e10cSrcweir { 910*cdf0e10cSrcweir if( !mpOutDev.get() || !mpDevice ) 911*cdf0e10cSrcweir return uno::Reference< rendering::XBitmap >(); // we're disposed 912*cdf0e10cSrcweir 913*cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 914*cdf0e10cSrcweir 915*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 916*cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 917*cdf0e10cSrcweir 918*cdf0e10cSrcweir // TODO(F2): Support alpha vdev canvas here 919*cdf0e10cSrcweir const Point aEmptyPoint(0,0); 920*cdf0e10cSrcweir const Size aBmpSize( rOutDev.GetOutputSizePixel() ); 921*cdf0e10cSrcweir 922*cdf0e10cSrcweir Bitmap aBitmap( rOutDev.GetBitmap(aEmptyPoint, aBmpSize) ); 923*cdf0e10cSrcweir 924*cdf0e10cSrcweir aBitmap.Scale( ::vcl::unotools::sizeFromRealSize2D(newSize), 925*cdf0e10cSrcweir beFast ? BMP_SCALE_FAST : BMP_SCALE_INTERPOLATE ); 926*cdf0e10cSrcweir 927*cdf0e10cSrcweir return uno::Reference< rendering::XBitmap >( 928*cdf0e10cSrcweir new CanvasBitmap( aBitmap, *mpDevice, mpOutDev ) ); 929*cdf0e10cSrcweir } 930*cdf0e10cSrcweir 931*cdf0e10cSrcweir uno::Sequence< sal_Int8 > CanvasHelper::getData( rendering::IntegerBitmapLayout& rLayout, 932*cdf0e10cSrcweir const geometry::IntegerRectangle2D& rect ) 933*cdf0e10cSrcweir { 934*cdf0e10cSrcweir if( !mpOutDev.get() ) 935*cdf0e10cSrcweir return uno::Sequence< sal_Int8 >(); // we're disposed 936*cdf0e10cSrcweir 937*cdf0e10cSrcweir rLayout = getMemoryLayout(); 938*cdf0e10cSrcweir 939*cdf0e10cSrcweir // TODO(F2): Support alpha canvas here 940*cdf0e10cSrcweir const Rectangle aRect( ::vcl::unotools::rectangleFromIntegerRectangle2D(rect) ); 941*cdf0e10cSrcweir 942*cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 943*cdf0e10cSrcweir 944*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 945*cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 946*cdf0e10cSrcweir 947*cdf0e10cSrcweir Bitmap aBitmap( rOutDev.GetBitmap(aRect.TopLeft(), 948*cdf0e10cSrcweir aRect.GetSize()) ); 949*cdf0e10cSrcweir 950*cdf0e10cSrcweir ScopedBitmapReadAccess pReadAccess( aBitmap.AcquireReadAccess(), 951*cdf0e10cSrcweir aBitmap ); 952*cdf0e10cSrcweir 953*cdf0e10cSrcweir ENSURE_OR_THROW( pReadAccess.get() != NULL, 954*cdf0e10cSrcweir "Could not acquire read access to OutDev bitmap" ); 955*cdf0e10cSrcweir 956*cdf0e10cSrcweir const sal_Int32 nWidth( rect.X2 - rect.X1 ); 957*cdf0e10cSrcweir const sal_Int32 nHeight( rect.Y2 - rect.Y1 ); 958*cdf0e10cSrcweir 959*cdf0e10cSrcweir rLayout.ScanLines = nHeight; 960*cdf0e10cSrcweir rLayout.ScanLineBytes = nWidth*4; 961*cdf0e10cSrcweir rLayout.ScanLineStride = rLayout.ScanLineBytes; 962*cdf0e10cSrcweir 963*cdf0e10cSrcweir uno::Sequence< sal_Int8 > aRes( 4*nWidth*nHeight ); 964*cdf0e10cSrcweir sal_Int8* pRes = aRes.getArray(); 965*cdf0e10cSrcweir 966*cdf0e10cSrcweir int nCurrPos(0); 967*cdf0e10cSrcweir for( int y=0; y<nHeight; ++y ) 968*cdf0e10cSrcweir { 969*cdf0e10cSrcweir for( int x=0; x<nWidth; ++x ) 970*cdf0e10cSrcweir { 971*cdf0e10cSrcweir pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetRed(); 972*cdf0e10cSrcweir pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetGreen(); 973*cdf0e10cSrcweir pRes[ nCurrPos++ ] = pReadAccess->GetColor( y, x ).GetBlue(); 974*cdf0e10cSrcweir pRes[ nCurrPos++ ] = -1; 975*cdf0e10cSrcweir } 976*cdf0e10cSrcweir } 977*cdf0e10cSrcweir 978*cdf0e10cSrcweir return aRes; 979*cdf0e10cSrcweir } 980*cdf0e10cSrcweir 981*cdf0e10cSrcweir void CanvasHelper::setData( const uno::Sequence< sal_Int8 >& data, 982*cdf0e10cSrcweir const rendering::IntegerBitmapLayout& aLayout, 983*cdf0e10cSrcweir const geometry::IntegerRectangle2D& rect ) 984*cdf0e10cSrcweir { 985*cdf0e10cSrcweir if( !mpOutDev.get() ) 986*cdf0e10cSrcweir return; // we're disposed 987*cdf0e10cSrcweir 988*cdf0e10cSrcweir const rendering::IntegerBitmapLayout aRefLayout( getMemoryLayout() ); 989*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( aRefLayout.PlaneStride != aLayout.PlaneStride || 990*cdf0e10cSrcweir aRefLayout.ColorSpace != aLayout.ColorSpace || 991*cdf0e10cSrcweir aRefLayout.Palette != aLayout.Palette || 992*cdf0e10cSrcweir aRefLayout.IsMsbFirst != aLayout.IsMsbFirst, 993*cdf0e10cSrcweir "Mismatching memory layout" ); 994*cdf0e10cSrcweir 995*cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 996*cdf0e10cSrcweir 997*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 998*cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 999*cdf0e10cSrcweir 1000*cdf0e10cSrcweir const Rectangle aRect( ::vcl::unotools::rectangleFromIntegerRectangle2D(rect) ); 1001*cdf0e10cSrcweir const sal_uInt16 nBitCount( ::std::min( (sal_uInt16)24U, 1002*cdf0e10cSrcweir (sal_uInt16)rOutDev.GetBitCount() ) ); 1003*cdf0e10cSrcweir const BitmapPalette* pPalette = NULL; 1004*cdf0e10cSrcweir 1005*cdf0e10cSrcweir if( nBitCount <= 8 ) 1006*cdf0e10cSrcweir { 1007*cdf0e10cSrcweir // TODO(Q1): Extract this to a common place, e.g. GraphicDevice 1008*cdf0e10cSrcweir 1009*cdf0e10cSrcweir // try to determine palette from output device (by 1010*cdf0e10cSrcweir // extracting a 1,1 bitmap, and querying it) 1011*cdf0e10cSrcweir const Point aEmptyPoint; 1012*cdf0e10cSrcweir const Size aSize(1,1); 1013*cdf0e10cSrcweir Bitmap aTmpBitmap( rOutDev.GetBitmap( aEmptyPoint, 1014*cdf0e10cSrcweir aSize ) ); 1015*cdf0e10cSrcweir 1016*cdf0e10cSrcweir ScopedBitmapReadAccess pReadAccess( aTmpBitmap.AcquireReadAccess(), 1017*cdf0e10cSrcweir aTmpBitmap ); 1018*cdf0e10cSrcweir 1019*cdf0e10cSrcweir pPalette = &pReadAccess->GetPalette(); 1020*cdf0e10cSrcweir } 1021*cdf0e10cSrcweir 1022*cdf0e10cSrcweir // TODO(F2): Support alpha canvas here 1023*cdf0e10cSrcweir Bitmap aBitmap( aRect.GetSize(), nBitCount, pPalette ); 1024*cdf0e10cSrcweir 1025*cdf0e10cSrcweir bool bCopyBack( false ); // only copy something back, if we 1026*cdf0e10cSrcweir // actually changed some pixel 1027*cdf0e10cSrcweir { 1028*cdf0e10cSrcweir ScopedBitmapWriteAccess pWriteAccess( aBitmap.AcquireWriteAccess(), 1029*cdf0e10cSrcweir aBitmap ); 1030*cdf0e10cSrcweir 1031*cdf0e10cSrcweir ENSURE_OR_THROW( pWriteAccess.get() != NULL, 1032*cdf0e10cSrcweir "Could not acquire write access to OutDev bitmap" ); 1033*cdf0e10cSrcweir 1034*cdf0e10cSrcweir // for the time being, always read as RGB 1035*cdf0e10cSrcweir const sal_Int32 nWidth( rect.X2 - rect.X1 ); 1036*cdf0e10cSrcweir const sal_Int32 nHeight( rect.Y2 - rect.Y1 ); 1037*cdf0e10cSrcweir int x, y, nCurrPos(0); 1038*cdf0e10cSrcweir for( y=0; y<nHeight; ++y ) 1039*cdf0e10cSrcweir { 1040*cdf0e10cSrcweir switch( pWriteAccess->GetScanlineFormat() ) 1041*cdf0e10cSrcweir { 1042*cdf0e10cSrcweir case BMP_FORMAT_8BIT_PAL: 1043*cdf0e10cSrcweir { 1044*cdf0e10cSrcweir Scanline pScan = pWriteAccess->GetScanline( y ); 1045*cdf0e10cSrcweir 1046*cdf0e10cSrcweir for( x=0; x<nWidth; ++x ) 1047*cdf0e10cSrcweir { 1048*cdf0e10cSrcweir *pScan++ = (sal_uInt8)pWriteAccess->GetBestPaletteIndex( 1049*cdf0e10cSrcweir BitmapColor( data[ nCurrPos ], 1050*cdf0e10cSrcweir data[ nCurrPos+1 ], 1051*cdf0e10cSrcweir data[ nCurrPos+2 ] ) ); 1052*cdf0e10cSrcweir 1053*cdf0e10cSrcweir nCurrPos += 4; 1054*cdf0e10cSrcweir } 1055*cdf0e10cSrcweir } 1056*cdf0e10cSrcweir break; 1057*cdf0e10cSrcweir 1058*cdf0e10cSrcweir case BMP_FORMAT_24BIT_TC_BGR: 1059*cdf0e10cSrcweir { 1060*cdf0e10cSrcweir Scanline pScan = pWriteAccess->GetScanline( y ); 1061*cdf0e10cSrcweir 1062*cdf0e10cSrcweir for( x=0; x<nWidth; ++x ) 1063*cdf0e10cSrcweir { 1064*cdf0e10cSrcweir *pScan++ = data[ nCurrPos+2 ]; 1065*cdf0e10cSrcweir *pScan++ = data[ nCurrPos+1 ]; 1066*cdf0e10cSrcweir *pScan++ = data[ nCurrPos ]; 1067*cdf0e10cSrcweir 1068*cdf0e10cSrcweir nCurrPos += 4; 1069*cdf0e10cSrcweir } 1070*cdf0e10cSrcweir } 1071*cdf0e10cSrcweir break; 1072*cdf0e10cSrcweir 1073*cdf0e10cSrcweir case BMP_FORMAT_24BIT_TC_RGB: 1074*cdf0e10cSrcweir { 1075*cdf0e10cSrcweir Scanline pScan = pWriteAccess->GetScanline( y ); 1076*cdf0e10cSrcweir 1077*cdf0e10cSrcweir for( x=0; x<nWidth; ++x ) 1078*cdf0e10cSrcweir { 1079*cdf0e10cSrcweir *pScan++ = data[ nCurrPos ]; 1080*cdf0e10cSrcweir *pScan++ = data[ nCurrPos+1 ]; 1081*cdf0e10cSrcweir *pScan++ = data[ nCurrPos+2 ]; 1082*cdf0e10cSrcweir 1083*cdf0e10cSrcweir nCurrPos += 4; 1084*cdf0e10cSrcweir } 1085*cdf0e10cSrcweir } 1086*cdf0e10cSrcweir break; 1087*cdf0e10cSrcweir 1088*cdf0e10cSrcweir default: 1089*cdf0e10cSrcweir { 1090*cdf0e10cSrcweir for( x=0; x<nWidth; ++x ) 1091*cdf0e10cSrcweir { 1092*cdf0e10cSrcweir pWriteAccess->SetPixel( y, x, BitmapColor( data[ nCurrPos ], 1093*cdf0e10cSrcweir data[ nCurrPos+1 ], 1094*cdf0e10cSrcweir data[ nCurrPos+2 ] ) ); 1095*cdf0e10cSrcweir nCurrPos += 4; 1096*cdf0e10cSrcweir } 1097*cdf0e10cSrcweir } 1098*cdf0e10cSrcweir break; 1099*cdf0e10cSrcweir } 1100*cdf0e10cSrcweir } 1101*cdf0e10cSrcweir 1102*cdf0e10cSrcweir bCopyBack = true; 1103*cdf0e10cSrcweir } 1104*cdf0e10cSrcweir 1105*cdf0e10cSrcweir // copy back only here, since the BitmapAccessors must be 1106*cdf0e10cSrcweir // destroyed beforehand 1107*cdf0e10cSrcweir if( bCopyBack ) 1108*cdf0e10cSrcweir { 1109*cdf0e10cSrcweir // TODO(F2): Support alpha canvas here 1110*cdf0e10cSrcweir rOutDev.DrawBitmap(aRect.TopLeft(), aBitmap); 1111*cdf0e10cSrcweir } 1112*cdf0e10cSrcweir } 1113*cdf0e10cSrcweir 1114*cdf0e10cSrcweir void CanvasHelper::setPixel( const uno::Sequence< sal_Int8 >& color, 1115*cdf0e10cSrcweir const rendering::IntegerBitmapLayout& rLayout, 1116*cdf0e10cSrcweir const geometry::IntegerPoint2D& pos ) 1117*cdf0e10cSrcweir { 1118*cdf0e10cSrcweir if( !mpOutDev.get() ) 1119*cdf0e10cSrcweir return; // we're disposed 1120*cdf0e10cSrcweir 1121*cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 1122*cdf0e10cSrcweir 1123*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 1124*cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 1125*cdf0e10cSrcweir 1126*cdf0e10cSrcweir const Size aBmpSize( rOutDev.GetOutputSizePixel() ); 1127*cdf0e10cSrcweir 1128*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aBmpSize.Width(), 1129*cdf0e10cSrcweir "X coordinate out of bounds" ); 1130*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aBmpSize.Height(), 1131*cdf0e10cSrcweir "Y coordinate out of bounds" ); 1132*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( color.getLength() > 3, 1133*cdf0e10cSrcweir "not enough color components" ); 1134*cdf0e10cSrcweir 1135*cdf0e10cSrcweir const rendering::IntegerBitmapLayout aRefLayout( getMemoryLayout() ); 1136*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( aRefLayout.PlaneStride != rLayout.PlaneStride || 1137*cdf0e10cSrcweir aRefLayout.ColorSpace != rLayout.ColorSpace || 1138*cdf0e10cSrcweir aRefLayout.Palette != rLayout.Palette || 1139*cdf0e10cSrcweir aRefLayout.IsMsbFirst != rLayout.IsMsbFirst, 1140*cdf0e10cSrcweir "Mismatching memory layout" ); 1141*cdf0e10cSrcweir 1142*cdf0e10cSrcweir // TODO(F2): Support alpha canvas here 1143*cdf0e10cSrcweir rOutDev.DrawPixel( ::vcl::unotools::pointFromIntegerPoint2D( pos ), 1144*cdf0e10cSrcweir ::canvas::tools::stdIntSequenceToColor( color )); 1145*cdf0e10cSrcweir } 1146*cdf0e10cSrcweir 1147*cdf0e10cSrcweir uno::Sequence< sal_Int8 > CanvasHelper::getPixel( rendering::IntegerBitmapLayout& rLayout, 1148*cdf0e10cSrcweir const geometry::IntegerPoint2D& pos ) 1149*cdf0e10cSrcweir { 1150*cdf0e10cSrcweir if( !mpOutDev.get() ) 1151*cdf0e10cSrcweir return uno::Sequence< sal_Int8 >(); // we're disposed 1152*cdf0e10cSrcweir 1153*cdf0e10cSrcweir rLayout = getMemoryLayout(); 1154*cdf0e10cSrcweir rLayout.ScanLines = 1; 1155*cdf0e10cSrcweir rLayout.ScanLineBytes = 4; 1156*cdf0e10cSrcweir rLayout.ScanLineStride = rLayout.ScanLineBytes; 1157*cdf0e10cSrcweir 1158*cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 1159*cdf0e10cSrcweir 1160*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 1161*cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 1162*cdf0e10cSrcweir 1163*cdf0e10cSrcweir const Size aBmpSize( rOutDev.GetOutputSizePixel() ); 1164*cdf0e10cSrcweir 1165*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( pos.X >= 0 && pos.X < aBmpSize.Width(), 1166*cdf0e10cSrcweir "X coordinate out of bounds" ); 1167*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( pos.Y >= 0 && pos.Y < aBmpSize.Height(), 1168*cdf0e10cSrcweir "Y coordinate out of bounds" ); 1169*cdf0e10cSrcweir 1170*cdf0e10cSrcweir // TODO(F2): Support alpha canvas here 1171*cdf0e10cSrcweir return ::canvas::tools::colorToStdIntSequence( 1172*cdf0e10cSrcweir rOutDev.GetPixel( 1173*cdf0e10cSrcweir ::vcl::unotools::pointFromIntegerPoint2D( pos ))); 1174*cdf0e10cSrcweir } 1175*cdf0e10cSrcweir 1176*cdf0e10cSrcweir rendering::IntegerBitmapLayout CanvasHelper::getMemoryLayout() 1177*cdf0e10cSrcweir { 1178*cdf0e10cSrcweir if( !mpOutDev.get() ) 1179*cdf0e10cSrcweir return rendering::IntegerBitmapLayout(); // we're disposed 1180*cdf0e10cSrcweir 1181*cdf0e10cSrcweir return ::canvas::tools::getStdMemoryLayout(getSize()); 1182*cdf0e10cSrcweir } 1183*cdf0e10cSrcweir 1184*cdf0e10cSrcweir int CanvasHelper::setupOutDevState( const rendering::ViewState& viewState, 1185*cdf0e10cSrcweir const rendering::RenderState& renderState, 1186*cdf0e10cSrcweir ColorType eColorType ) const 1187*cdf0e10cSrcweir { 1188*cdf0e10cSrcweir ENSURE_OR_THROW( mpOutDev.get(), 1189*cdf0e10cSrcweir "outdev null. Are we disposed?" ); 1190*cdf0e10cSrcweir 1191*cdf0e10cSrcweir ::canvas::tools::verifyInput( renderState, 1192*cdf0e10cSrcweir BOOST_CURRENT_FUNCTION, 1193*cdf0e10cSrcweir mpDevice, 1194*cdf0e10cSrcweir 2, 1195*cdf0e10cSrcweir eColorType == IGNORE_COLOR ? 0 : 3 ); 1196*cdf0e10cSrcweir 1197*cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 1198*cdf0e10cSrcweir OutputDevice* p2ndOutDev = NULL; 1199*cdf0e10cSrcweir 1200*cdf0e10cSrcweir rOutDev.EnableMapMode( sal_False ); 1201*cdf0e10cSrcweir 1202*cdf0e10cSrcweir if( mp2ndOutDev ) 1203*cdf0e10cSrcweir p2ndOutDev = &mp2ndOutDev->getOutDev(); 1204*cdf0e10cSrcweir 1205*cdf0e10cSrcweir int nTransparency(0); 1206*cdf0e10cSrcweir 1207*cdf0e10cSrcweir // TODO(P2): Don't change clipping all the time, maintain current clip 1208*cdf0e10cSrcweir // state and change only when update is necessary 1209*cdf0e10cSrcweir 1210*cdf0e10cSrcweir // accumulate non-empty clips into one region 1211*cdf0e10cSrcweir // ========================================== 1212*cdf0e10cSrcweir 1213*cdf0e10cSrcweir Region aClipRegion( REGION_NULL ); 1214*cdf0e10cSrcweir 1215*cdf0e10cSrcweir if( viewState.Clip.is() ) 1216*cdf0e10cSrcweir { 1217*cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aClipPoly( 1218*cdf0e10cSrcweir ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(viewState.Clip) ); 1219*cdf0e10cSrcweir 1220*cdf0e10cSrcweir if( aClipPoly.count() ) 1221*cdf0e10cSrcweir { 1222*cdf0e10cSrcweir // setup non-empty clipping 1223*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 1224*cdf0e10cSrcweir aClipPoly.transform( 1225*cdf0e10cSrcweir ::basegfx::unotools::homMatrixFromAffineMatrix( aMatrix, 1226*cdf0e10cSrcweir viewState.AffineTransform ) ); 1227*cdf0e10cSrcweir 1228*cdf0e10cSrcweir aClipRegion = Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly ) ); 1229*cdf0e10cSrcweir } 1230*cdf0e10cSrcweir else 1231*cdf0e10cSrcweir { 1232*cdf0e10cSrcweir // clip polygon is empty 1233*cdf0e10cSrcweir aClipRegion.SetEmpty(); 1234*cdf0e10cSrcweir } 1235*cdf0e10cSrcweir } 1236*cdf0e10cSrcweir 1237*cdf0e10cSrcweir if( renderState.Clip.is() ) 1238*cdf0e10cSrcweir { 1239*cdf0e10cSrcweir ::basegfx::B2DPolyPolygon aClipPoly( 1240*cdf0e10cSrcweir ::basegfx::unotools::b2DPolyPolygonFromXPolyPolygon2D(renderState.Clip) ); 1241*cdf0e10cSrcweir 1242*cdf0e10cSrcweir ::basegfx::B2DHomMatrix aMatrix; 1243*cdf0e10cSrcweir aClipPoly.transform( 1244*cdf0e10cSrcweir ::canvas::tools::mergeViewAndRenderTransform( aMatrix, 1245*cdf0e10cSrcweir viewState, 1246*cdf0e10cSrcweir renderState ) ); 1247*cdf0e10cSrcweir 1248*cdf0e10cSrcweir if( aClipPoly.count() ) 1249*cdf0e10cSrcweir { 1250*cdf0e10cSrcweir // setup non-empty clipping 1251*cdf0e10cSrcweir Region aRegion = Region::GetRegionFromPolyPolygon( ::PolyPolygon( aClipPoly ) ); 1252*cdf0e10cSrcweir aClipRegion.Intersect( aRegion ); 1253*cdf0e10cSrcweir } 1254*cdf0e10cSrcweir else 1255*cdf0e10cSrcweir { 1256*cdf0e10cSrcweir // clip polygon is empty 1257*cdf0e10cSrcweir aClipRegion.SetEmpty(); 1258*cdf0e10cSrcweir } 1259*cdf0e10cSrcweir } 1260*cdf0e10cSrcweir 1261*cdf0e10cSrcweir // setup accumulated clip region. Note that setting an 1262*cdf0e10cSrcweir // empty clip region denotes "clip everything" on the 1263*cdf0e10cSrcweir // OutputDevice (which is why we translate that into 1264*cdf0e10cSrcweir // SetClipRegion() here). When both view and render clip 1265*cdf0e10cSrcweir // are empty, aClipRegion remains default-constructed, 1266*cdf0e10cSrcweir // i.e. empty, too. 1267*cdf0e10cSrcweir if( aClipRegion.IsNull() ) 1268*cdf0e10cSrcweir { 1269*cdf0e10cSrcweir rOutDev.SetClipRegion(); 1270*cdf0e10cSrcweir 1271*cdf0e10cSrcweir if( p2ndOutDev ) 1272*cdf0e10cSrcweir p2ndOutDev->SetClipRegion(); 1273*cdf0e10cSrcweir } 1274*cdf0e10cSrcweir else 1275*cdf0e10cSrcweir { 1276*cdf0e10cSrcweir rOutDev.SetClipRegion( aClipRegion ); 1277*cdf0e10cSrcweir 1278*cdf0e10cSrcweir if( p2ndOutDev ) 1279*cdf0e10cSrcweir p2ndOutDev->SetClipRegion( aClipRegion ); 1280*cdf0e10cSrcweir } 1281*cdf0e10cSrcweir 1282*cdf0e10cSrcweir if( eColorType != IGNORE_COLOR ) 1283*cdf0e10cSrcweir { 1284*cdf0e10cSrcweir Color aColor( COL_WHITE ); 1285*cdf0e10cSrcweir 1286*cdf0e10cSrcweir if( renderState.DeviceColor.getLength() > 2 ) 1287*cdf0e10cSrcweir { 1288*cdf0e10cSrcweir aColor = ::vcl::unotools::stdColorSpaceSequenceToColor( 1289*cdf0e10cSrcweir renderState.DeviceColor ); 1290*cdf0e10cSrcweir } 1291*cdf0e10cSrcweir 1292*cdf0e10cSrcweir // extract alpha, and make color opaque 1293*cdf0e10cSrcweir // afterwards. Otherwise, OutputDevice won't draw anything 1294*cdf0e10cSrcweir nTransparency = aColor.GetTransparency(); 1295*cdf0e10cSrcweir aColor.SetTransparency(0); 1296*cdf0e10cSrcweir 1297*cdf0e10cSrcweir switch( eColorType ) 1298*cdf0e10cSrcweir { 1299*cdf0e10cSrcweir case LINE_COLOR: 1300*cdf0e10cSrcweir rOutDev.SetLineColor( aColor ); 1301*cdf0e10cSrcweir rOutDev.SetFillColor(); 1302*cdf0e10cSrcweir 1303*cdf0e10cSrcweir if( p2ndOutDev ) 1304*cdf0e10cSrcweir { 1305*cdf0e10cSrcweir p2ndOutDev->SetLineColor( aColor ); 1306*cdf0e10cSrcweir p2ndOutDev->SetFillColor(); 1307*cdf0e10cSrcweir } 1308*cdf0e10cSrcweir break; 1309*cdf0e10cSrcweir 1310*cdf0e10cSrcweir case FILL_COLOR: 1311*cdf0e10cSrcweir rOutDev.SetFillColor( aColor ); 1312*cdf0e10cSrcweir rOutDev.SetLineColor(); 1313*cdf0e10cSrcweir 1314*cdf0e10cSrcweir if( p2ndOutDev ) 1315*cdf0e10cSrcweir { 1316*cdf0e10cSrcweir p2ndOutDev->SetFillColor( aColor ); 1317*cdf0e10cSrcweir p2ndOutDev->SetLineColor(); 1318*cdf0e10cSrcweir } 1319*cdf0e10cSrcweir break; 1320*cdf0e10cSrcweir 1321*cdf0e10cSrcweir case TEXT_COLOR: 1322*cdf0e10cSrcweir rOutDev.SetTextColor( aColor ); 1323*cdf0e10cSrcweir 1324*cdf0e10cSrcweir if( p2ndOutDev ) 1325*cdf0e10cSrcweir p2ndOutDev->SetTextColor( aColor ); 1326*cdf0e10cSrcweir break; 1327*cdf0e10cSrcweir 1328*cdf0e10cSrcweir default: 1329*cdf0e10cSrcweir ENSURE_OR_THROW( false, 1330*cdf0e10cSrcweir "Unexpected color type"); 1331*cdf0e10cSrcweir break; 1332*cdf0e10cSrcweir } 1333*cdf0e10cSrcweir } 1334*cdf0e10cSrcweir 1335*cdf0e10cSrcweir return nTransparency; 1336*cdf0e10cSrcweir } 1337*cdf0e10cSrcweir 1338*cdf0e10cSrcweir bool CanvasHelper::setupTextOutput( ::Point& o_rOutPos, 1339*cdf0e10cSrcweir const rendering::ViewState& viewState, 1340*cdf0e10cSrcweir const rendering::RenderState& renderState, 1341*cdf0e10cSrcweir const uno::Reference< rendering::XCanvasFont >& xFont ) const 1342*cdf0e10cSrcweir { 1343*cdf0e10cSrcweir ENSURE_OR_THROW( mpOutDev.get(), 1344*cdf0e10cSrcweir "outdev null. Are we disposed?" ); 1345*cdf0e10cSrcweir 1346*cdf0e10cSrcweir setupOutDevState( viewState, renderState, TEXT_COLOR ); 1347*cdf0e10cSrcweir 1348*cdf0e10cSrcweir OutputDevice& rOutDev( mpOutDev->getOutDev() ); 1349*cdf0e10cSrcweir 1350*cdf0e10cSrcweir ::Font aVCLFont; 1351*cdf0e10cSrcweir 1352*cdf0e10cSrcweir CanvasFont* pFont = dynamic_cast< CanvasFont* >( xFont.get() ); 1353*cdf0e10cSrcweir 1354*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( pFont, 1355*cdf0e10cSrcweir "Font not compatible with this canvas" ); 1356*cdf0e10cSrcweir 1357*cdf0e10cSrcweir aVCLFont = pFont->getVCLFont(); 1358*cdf0e10cSrcweir 1359*cdf0e10cSrcweir Color aColor( COL_BLACK ); 1360*cdf0e10cSrcweir 1361*cdf0e10cSrcweir if( renderState.DeviceColor.getLength() > 2 ) 1362*cdf0e10cSrcweir { 1363*cdf0e10cSrcweir aColor = ::vcl::unotools::stdColorSpaceSequenceToColor( 1364*cdf0e10cSrcweir renderState.DeviceColor ); 1365*cdf0e10cSrcweir } 1366*cdf0e10cSrcweir 1367*cdf0e10cSrcweir // setup font color 1368*cdf0e10cSrcweir aVCLFont.SetColor( aColor ); 1369*cdf0e10cSrcweir aVCLFont.SetFillColor( aColor ); 1370*cdf0e10cSrcweir 1371*cdf0e10cSrcweir // no need to replicate this for mp2ndOutDev, we're modifying only aVCLFont here. 1372*cdf0e10cSrcweir if( !tools::setupFontTransform( o_rOutPos, aVCLFont, viewState, renderState, rOutDev ) ) 1373*cdf0e10cSrcweir return false; 1374*cdf0e10cSrcweir 1375*cdf0e10cSrcweir rOutDev.SetFont( aVCLFont ); 1376*cdf0e10cSrcweir 1377*cdf0e10cSrcweir if( mp2ndOutDev ) 1378*cdf0e10cSrcweir mp2ndOutDev->getOutDev().SetFont( aVCLFont ); 1379*cdf0e10cSrcweir 1380*cdf0e10cSrcweir return true; 1381*cdf0e10cSrcweir } 1382*cdf0e10cSrcweir 1383*cdf0e10cSrcweir bool CanvasHelper::repaint( const GraphicObjectSharedPtr& rGrf, 1384*cdf0e10cSrcweir const rendering::ViewState& viewState, 1385*cdf0e10cSrcweir const rendering::RenderState& renderState, 1386*cdf0e10cSrcweir const ::Point& rPt, 1387*cdf0e10cSrcweir const ::Size& rSz, 1388*cdf0e10cSrcweir const GraphicAttr& rAttr ) const 1389*cdf0e10cSrcweir { 1390*cdf0e10cSrcweir ENSURE_OR_RETURN_FALSE( rGrf, 1391*cdf0e10cSrcweir "Invalid Graphic" ); 1392*cdf0e10cSrcweir 1393*cdf0e10cSrcweir if( !mpOutDev ) 1394*cdf0e10cSrcweir return false; // disposed 1395*cdf0e10cSrcweir else 1396*cdf0e10cSrcweir { 1397*cdf0e10cSrcweir tools::OutDevStateKeeper aStateKeeper( mpProtectedOutDev ); 1398*cdf0e10cSrcweir setupOutDevState( viewState, renderState, IGNORE_COLOR ); 1399*cdf0e10cSrcweir 1400*cdf0e10cSrcweir if( !rGrf->Draw( &mpOutDev->getOutDev(), rPt, rSz, &rAttr ) ) 1401*cdf0e10cSrcweir return false; 1402*cdf0e10cSrcweir 1403*cdf0e10cSrcweir // #i80779# Redraw also into mask outdev 1404*cdf0e10cSrcweir if( mp2ndOutDev ) 1405*cdf0e10cSrcweir return rGrf->Draw( &mp2ndOutDev->getOutDev(), rPt, rSz, &rAttr ); 1406*cdf0e10cSrcweir 1407*cdf0e10cSrcweir return true; 1408*cdf0e10cSrcweir } 1409*cdf0e10cSrcweir } 1410*cdf0e10cSrcweir 1411*cdf0e10cSrcweir void CanvasHelper::flush() const 1412*cdf0e10cSrcweir { 1413*cdf0e10cSrcweir if( mpOutDev && mpOutDev->getOutDev().GetOutDevType() == OUTDEV_WINDOW ) 1414*cdf0e10cSrcweir { 1415*cdf0e10cSrcweir // TODO(Q3): Evil downcast. And what's more, Window::Flush is 1416*cdf0e10cSrcweir // not even const. Wah. 1417*cdf0e10cSrcweir static_cast<Window&>(mpOutDev->getOutDev()).Flush(); 1418*cdf0e10cSrcweir } 1419*cdf0e10cSrcweir 1420*cdf0e10cSrcweir if( mp2ndOutDev && mp2ndOutDev->getOutDev().GetOutDevType() == OUTDEV_WINDOW ) 1421*cdf0e10cSrcweir { 1422*cdf0e10cSrcweir // TODO(Q3): Evil downcast. And what's more, Window::Flush is 1423*cdf0e10cSrcweir // not even const. Wah. 1424*cdf0e10cSrcweir static_cast<Window&>(mp2ndOutDev->getOutDev()).Flush(); 1425*cdf0e10cSrcweir } 1426*cdf0e10cSrcweir } 1427*cdf0e10cSrcweir 1428*cdf0e10cSrcweir } 1429