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 <ctype.h> // don't ask. msdev breaks otherwise... 32*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx> 33*cdf0e10cSrcweir 34*cdf0e10cSrcweir #include <canvas/debug.hxx> 35*cdf0e10cSrcweir #include <canvas/verbosetrace.hxx> 36*cdf0e10cSrcweir #include <tools/diagnose_ex.h> 37*cdf0e10cSrcweir 38*cdf0e10cSrcweir #include <com/sun/star/lang/XServiceInfo.hpp> 39*cdf0e10cSrcweir #include <com/sun/star/lang/XUnoTunnel.hpp> 40*cdf0e10cSrcweir #include <com/sun/star/geometry/RealPoint2D.hpp> 41*cdf0e10cSrcweir #include <com/sun/star/geometry/IntegerRectangle2D.hpp> 42*cdf0e10cSrcweir 43*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx> 44*cdf0e10cSrcweir #include <basegfx/range/b2irectangle.hxx> 45*cdf0e10cSrcweir #include <basegfx/range/b2drectangle.hxx> 46*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx> 47*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygon.hxx> 48*cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx> 49*cdf0e10cSrcweir 50*cdf0e10cSrcweir #include <canvas/canvastools.hxx> 51*cdf0e10cSrcweir #include <canvas/verifyinput.hxx> 52*cdf0e10cSrcweir 53*cdf0e10cSrcweir #include "dx_impltools.hxx" 54*cdf0e10cSrcweir #include "dx_vcltools.hxx" 55*cdf0e10cSrcweir #include "dx_linepolypolygon.hxx" 56*cdf0e10cSrcweir #include "dx_canvasbitmap.hxx" 57*cdf0e10cSrcweir #include "dx_canvasfont.hxx" 58*cdf0e10cSrcweir #include "dx_canvas.hxx" 59*cdf0e10cSrcweir #include "dx_spritecanvas.hxx" 60*cdf0e10cSrcweir 61*cdf0e10cSrcweir #include <boost/scoped_array.hpp> 62*cdf0e10cSrcweir 63*cdf0e10cSrcweir #include <vector> 64*cdf0e10cSrcweir #include <algorithm> 65*cdf0e10cSrcweir 66*cdf0e10cSrcweir 67*cdf0e10cSrcweir using namespace ::com::sun::star; 68*cdf0e10cSrcweir 69*cdf0e10cSrcweir 70*cdf0e10cSrcweir namespace dxcanvas 71*cdf0e10cSrcweir { 72*cdf0e10cSrcweir namespace tools 73*cdf0e10cSrcweir { 74*cdf0e10cSrcweir ::basegfx::B2DPolyPolygon polyPolygonFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly ) 75*cdf0e10cSrcweir { 76*cdf0e10cSrcweir LinePolyPolygon* pPolyImpl = dynamic_cast< LinePolyPolygon* >( xPoly.get() ); 77*cdf0e10cSrcweir 78*cdf0e10cSrcweir if( pPolyImpl ) 79*cdf0e10cSrcweir { 80*cdf0e10cSrcweir return pPolyImpl->getPolyPolygon(); 81*cdf0e10cSrcweir } 82*cdf0e10cSrcweir else 83*cdf0e10cSrcweir { 84*cdf0e10cSrcweir const sal_Int32 nPolys( xPoly->getNumberOfPolygons() ); 85*cdf0e10cSrcweir 86*cdf0e10cSrcweir // not a known implementation object - try data source 87*cdf0e10cSrcweir // interfaces 88*cdf0e10cSrcweir uno::Reference< rendering::XBezierPolyPolygon2D > xBezierPoly( 89*cdf0e10cSrcweir xPoly, 90*cdf0e10cSrcweir uno::UNO_QUERY ); 91*cdf0e10cSrcweir 92*cdf0e10cSrcweir if( xBezierPoly.is() ) 93*cdf0e10cSrcweir { 94*cdf0e10cSrcweir return ::basegfx::unotools::polyPolygonFromBezier2DSequenceSequence( 95*cdf0e10cSrcweir xBezierPoly->getBezierSegments( 0, 96*cdf0e10cSrcweir nPolys, 97*cdf0e10cSrcweir 0, 98*cdf0e10cSrcweir -1 ) ); 99*cdf0e10cSrcweir } 100*cdf0e10cSrcweir else 101*cdf0e10cSrcweir { 102*cdf0e10cSrcweir uno::Reference< rendering::XLinePolyPolygon2D > xLinePoly( 103*cdf0e10cSrcweir xPoly, 104*cdf0e10cSrcweir uno::UNO_QUERY ); 105*cdf0e10cSrcweir 106*cdf0e10cSrcweir // no implementation class and no data provider 107*cdf0e10cSrcweir // found - contract violation. 108*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( xLinePoly.is(), 109*cdf0e10cSrcweir "VCLCanvas::polyPolygonFromXPolyPolygon2D(): Invalid input " 110*cdf0e10cSrcweir "poly-polygon, cannot retrieve vertex data" ); 111*cdf0e10cSrcweir 112*cdf0e10cSrcweir return ::basegfx::unotools::polyPolygonFromPoint2DSequenceSequence( 113*cdf0e10cSrcweir xLinePoly->getPoints( 0, 114*cdf0e10cSrcweir nPolys, 115*cdf0e10cSrcweir 0, 116*cdf0e10cSrcweir -1 ) ); 117*cdf0e10cSrcweir } 118*cdf0e10cSrcweir } 119*cdf0e10cSrcweir } 120*cdf0e10cSrcweir 121*cdf0e10cSrcweir void setupGraphics( Gdiplus::Graphics& rGraphics ) 122*cdf0e10cSrcweir { 123*cdf0e10cSrcweir // setup graphics with (somewhat arbitrary) defaults 124*cdf0e10cSrcweir //rGraphics.SetCompositingQuality( Gdiplus::CompositingQualityHighQuality ); 125*cdf0e10cSrcweir rGraphics.SetCompositingQuality( Gdiplus::CompositingQualityHighSpeed ); 126*cdf0e10cSrcweir //rGraphics.SetInterpolationMode( Gdiplus::InterpolationModeHighQualityBilinear ); // with prefiltering for shrinks 127*cdf0e10cSrcweir rGraphics.SetInterpolationMode( Gdiplus::InterpolationModeBilinear ); 128*cdf0e10cSrcweir 129*cdf0e10cSrcweir // #122683# Switched precedence of pixel offset 130*cdf0e10cSrcweir // mode. Seemingly, polygon stroking needs 131*cdf0e10cSrcweir // PixelOffsetModeNone to achieve visually pleasing 132*cdf0e10cSrcweir // results, whereas all other operations (e.g. polygon 133*cdf0e10cSrcweir // fills, bitmaps) look better with PixelOffsetModeHalf. 134*cdf0e10cSrcweir rGraphics.SetPixelOffsetMode( Gdiplus::PixelOffsetModeHalf ); // Pixel center at (0.5, 0.5) etc. 135*cdf0e10cSrcweir //rGraphics.SetPixelOffsetMode( Gdiplus::PixelOffsetModeNone ); 136*cdf0e10cSrcweir 137*cdf0e10cSrcweir //rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeHighSpeed ); // no line/curve antialiasing 138*cdf0e10cSrcweir //rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeHighQuality ); 139*cdf0e10cSrcweir rGraphics.SetSmoothingMode( Gdiplus::SmoothingModeAntiAlias ); 140*cdf0e10cSrcweir //rGraphics.SetTextRenderingHint( Gdiplus::TextRenderingHintAntiAlias ); 141*cdf0e10cSrcweir rGraphics.SetTextRenderingHint( Gdiplus::TextRenderingHintSystemDefault ); 142*cdf0e10cSrcweir rGraphics.SetPageUnit(Gdiplus::UnitPixel); 143*cdf0e10cSrcweir } 144*cdf0e10cSrcweir 145*cdf0e10cSrcweir Gdiplus::Graphics* createGraphicsFromHDC(HDC aHDC) 146*cdf0e10cSrcweir { 147*cdf0e10cSrcweir Gdiplus::Graphics* pRet = new Gdiplus::Graphics(aHDC); 148*cdf0e10cSrcweir if( pRet ) 149*cdf0e10cSrcweir setupGraphics( *pRet ); 150*cdf0e10cSrcweir return pRet; 151*cdf0e10cSrcweir } 152*cdf0e10cSrcweir 153*cdf0e10cSrcweir Gdiplus::Graphics* createGraphicsFromBitmap(const BitmapSharedPtr& rBitmap) 154*cdf0e10cSrcweir { 155*cdf0e10cSrcweir Gdiplus::Graphics* pRet = Gdiplus::Graphics::FromImage(rBitmap.get()); 156*cdf0e10cSrcweir if( pRet ) 157*cdf0e10cSrcweir setupGraphics( *pRet ); 158*cdf0e10cSrcweir return pRet; 159*cdf0e10cSrcweir } 160*cdf0e10cSrcweir 161*cdf0e10cSrcweir void gdiPlusMatrixFromB2DHomMatrix( Gdiplus::Matrix& rGdiplusMatrix, const ::basegfx::B2DHomMatrix& rMatrix ) 162*cdf0e10cSrcweir { 163*cdf0e10cSrcweir rGdiplusMatrix.SetElements( static_cast<Gdiplus::REAL>(rMatrix.get(0,0)), 164*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rMatrix.get(1,0)), 165*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rMatrix.get(0,1)), 166*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rMatrix.get(1,1)), 167*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rMatrix.get(0,2)), 168*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rMatrix.get(1,2)) ); 169*cdf0e10cSrcweir } 170*cdf0e10cSrcweir 171*cdf0e10cSrcweir void gdiPlusMatrixFromAffineMatrix2D( Gdiplus::Matrix& rGdiplusMatrix, 172*cdf0e10cSrcweir const geometry::AffineMatrix2D& rMatrix ) 173*cdf0e10cSrcweir { 174*cdf0e10cSrcweir rGdiplusMatrix.SetElements( static_cast<Gdiplus::REAL>(rMatrix.m00), 175*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rMatrix.m10), 176*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rMatrix.m01), 177*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rMatrix.m11), 178*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rMatrix.m02), 179*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rMatrix.m12) ); 180*cdf0e10cSrcweir } 181*cdf0e10cSrcweir 182*cdf0e10cSrcweir namespace 183*cdf0e10cSrcweir { 184*cdf0e10cSrcweir // TODO(P2): Check whether this gets inlined. If not, make functor 185*cdf0e10cSrcweir // out of it 186*cdf0e10cSrcweir inline Gdiplus::PointF implGdiPlusPointFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& rPoint ) 187*cdf0e10cSrcweir { 188*cdf0e10cSrcweir return Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.X), 189*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rPoint.Y) ); 190*cdf0e10cSrcweir } 191*cdf0e10cSrcweir 192*cdf0e10cSrcweir void graphicsPathFromB2DPolygon( GraphicsPathSharedPtr& rOutput, 193*cdf0e10cSrcweir ::std::vector< Gdiplus::PointF >& rPoints, 194*cdf0e10cSrcweir const ::basegfx::B2DPolygon& rPoly, 195*cdf0e10cSrcweir bool bNoLineJoin) 196*cdf0e10cSrcweir { 197*cdf0e10cSrcweir const sal_uInt32 nPoints( rPoly.count() ); 198*cdf0e10cSrcweir 199*cdf0e10cSrcweir if( nPoints < 2 ) 200*cdf0e10cSrcweir return; 201*cdf0e10cSrcweir 202*cdf0e10cSrcweir rOutput->StartFigure(); 203*cdf0e10cSrcweir 204*cdf0e10cSrcweir const bool bClosedPolygon( rPoly.isClosed() ); 205*cdf0e10cSrcweir 206*cdf0e10cSrcweir if( rPoly.areControlPointsUsed() ) 207*cdf0e10cSrcweir { 208*cdf0e10cSrcweir // control points used -> for now, add all 209*cdf0e10cSrcweir // segments as curves to GraphicsPath 210*cdf0e10cSrcweir 211*cdf0e10cSrcweir // If the polygon is closed, we need to add the 212*cdf0e10cSrcweir // first point, thus, one more (can't simply 213*cdf0e10cSrcweir // GraphicsPath::CloseFigure() it, since the last 214*cdf0e10cSrcweir // point cannot have any control points for GDI+) 215*cdf0e10cSrcweir rPoints.resize( 3*nPoints + bClosedPolygon ); 216*cdf0e10cSrcweir 217*cdf0e10cSrcweir sal_uInt32 nCurrOutput=0; 218*cdf0e10cSrcweir for( sal_uInt32 nCurrPoint=0; nCurrPoint<nPoints; ++nCurrPoint ) 219*cdf0e10cSrcweir { 220*cdf0e10cSrcweir const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint( nCurrPoint ) ); 221*cdf0e10cSrcweir rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), 222*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rPoint.getY()) ); 223*cdf0e10cSrcweir 224*cdf0e10cSrcweir const ::basegfx::B2DPoint& rControlPointA( rPoly.getNextControlPoint( nCurrPoint ) ); 225*cdf0e10cSrcweir rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rControlPointA.getX()), 226*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rControlPointA.getY()) ); 227*cdf0e10cSrcweir 228*cdf0e10cSrcweir const ::basegfx::B2DPoint& rControlPointB( rPoly.getPrevControlPoint( (nCurrPoint + 1) % nPoints) ); 229*cdf0e10cSrcweir rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rControlPointB.getX()), 230*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rControlPointB.getY()) ); 231*cdf0e10cSrcweir } 232*cdf0e10cSrcweir 233*cdf0e10cSrcweir if( bClosedPolygon ) 234*cdf0e10cSrcweir { 235*cdf0e10cSrcweir // add first point again (to be able to pass 236*cdf0e10cSrcweir // control points for the last point, see 237*cdf0e10cSrcweir // above) 238*cdf0e10cSrcweir const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint(0) ); 239*cdf0e10cSrcweir rPoints[nCurrOutput++] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), 240*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rPoint.getY()) ); 241*cdf0e10cSrcweir 242*cdf0e10cSrcweir if(bNoLineJoin && nCurrOutput > 7) 243*cdf0e10cSrcweir { 244*cdf0e10cSrcweir for(sal_uInt32 a(3); a < nCurrOutput; a+=3) 245*cdf0e10cSrcweir { 246*cdf0e10cSrcweir rOutput->StartFigure(); 247*cdf0e10cSrcweir rOutput->AddBezier(rPoints[a - 3], rPoints[a - 2], rPoints[a - 1], rPoints[a]); 248*cdf0e10cSrcweir } 249*cdf0e10cSrcweir } 250*cdf0e10cSrcweir else 251*cdf0e10cSrcweir { 252*cdf0e10cSrcweir rOutput->AddBeziers( &rPoints[0], nCurrOutput ); 253*cdf0e10cSrcweir } 254*cdf0e10cSrcweir } 255*cdf0e10cSrcweir else 256*cdf0e10cSrcweir { 257*cdf0e10cSrcweir // GraphicsPath expects 3(n-1)+1 points (i.e. the 258*cdf0e10cSrcweir // last point must not have any trailing control 259*cdf0e10cSrcweir // points after it). 260*cdf0e10cSrcweir // Therefore, simply don't pass the last two 261*cdf0e10cSrcweir // points here. 262*cdf0e10cSrcweir if( nCurrOutput > 3 ) 263*cdf0e10cSrcweir { 264*cdf0e10cSrcweir if(bNoLineJoin && nCurrOutput > 7) 265*cdf0e10cSrcweir { 266*cdf0e10cSrcweir for(sal_uInt32 a(3); a < nCurrOutput; a+=3) 267*cdf0e10cSrcweir { 268*cdf0e10cSrcweir rOutput->StartFigure(); 269*cdf0e10cSrcweir rOutput->AddBezier(rPoints[a - 3], rPoints[a - 2], rPoints[a - 1], rPoints[a]); 270*cdf0e10cSrcweir } 271*cdf0e10cSrcweir } 272*cdf0e10cSrcweir else 273*cdf0e10cSrcweir { 274*cdf0e10cSrcweir rOutput->AddBeziers( &rPoints[0], nCurrOutput-2 ); 275*cdf0e10cSrcweir } 276*cdf0e10cSrcweir } 277*cdf0e10cSrcweir } 278*cdf0e10cSrcweir } 279*cdf0e10cSrcweir else 280*cdf0e10cSrcweir { 281*cdf0e10cSrcweir // no control points -> no curves, simply add 282*cdf0e10cSrcweir // straigt lines to GraphicsPath 283*cdf0e10cSrcweir rPoints.resize( nPoints ); 284*cdf0e10cSrcweir 285*cdf0e10cSrcweir for( sal_uInt32 nCurrPoint=0; nCurrPoint<nPoints; ++nCurrPoint ) 286*cdf0e10cSrcweir { 287*cdf0e10cSrcweir const ::basegfx::B2DPoint& rPoint( rPoly.getB2DPoint( nCurrPoint ) ); 288*cdf0e10cSrcweir rPoints[nCurrPoint] = Gdiplus::PointF( static_cast<Gdiplus::REAL>(rPoint.getX()), 289*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rPoint.getY()) ); 290*cdf0e10cSrcweir } 291*cdf0e10cSrcweir 292*cdf0e10cSrcweir if(bNoLineJoin && nPoints > 2) 293*cdf0e10cSrcweir { 294*cdf0e10cSrcweir for(sal_uInt32 a(1); a < nPoints; a++) 295*cdf0e10cSrcweir { 296*cdf0e10cSrcweir rOutput->StartFigure(); 297*cdf0e10cSrcweir rOutput->AddLine(rPoints[a - 1], rPoints[a]); 298*cdf0e10cSrcweir } 299*cdf0e10cSrcweir 300*cdf0e10cSrcweir if(bClosedPolygon) 301*cdf0e10cSrcweir { 302*cdf0e10cSrcweir rOutput->StartFigure(); 303*cdf0e10cSrcweir rOutput->AddLine(rPoints[nPoints - 1], rPoints[0]); 304*cdf0e10cSrcweir } 305*cdf0e10cSrcweir } 306*cdf0e10cSrcweir else 307*cdf0e10cSrcweir { 308*cdf0e10cSrcweir rOutput->AddLines( &rPoints[0], nPoints ); 309*cdf0e10cSrcweir } 310*cdf0e10cSrcweir } 311*cdf0e10cSrcweir 312*cdf0e10cSrcweir if( bClosedPolygon && !bNoLineJoin ) 313*cdf0e10cSrcweir rOutput->CloseFigure(); 314*cdf0e10cSrcweir } 315*cdf0e10cSrcweir } 316*cdf0e10cSrcweir 317*cdf0e10cSrcweir Gdiplus::PointF gdiPlusPointFromRealPoint2D( const ::com::sun::star::geometry::RealPoint2D& rPoint ) 318*cdf0e10cSrcweir { 319*cdf0e10cSrcweir return implGdiPlusPointFromRealPoint2D( rPoint ); 320*cdf0e10cSrcweir } 321*cdf0e10cSrcweir 322*cdf0e10cSrcweir Gdiplus::Rect gdiPlusRectFromIntegerRectangle2D( const geometry::IntegerRectangle2D& rRect ) 323*cdf0e10cSrcweir { 324*cdf0e10cSrcweir return Gdiplus::Rect( rRect.X1, 325*cdf0e10cSrcweir rRect.Y1, 326*cdf0e10cSrcweir rRect.X2 - rRect.X1, 327*cdf0e10cSrcweir rRect.Y2 - rRect.Y1 ); 328*cdf0e10cSrcweir } 329*cdf0e10cSrcweir 330*cdf0e10cSrcweir Gdiplus::RectF gdiPlusRectFFromRectangle2D( const geometry::RealRectangle2D& rRect ) 331*cdf0e10cSrcweir { 332*cdf0e10cSrcweir return Gdiplus::RectF( static_cast<Gdiplus::REAL>(rRect.X1), 333*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rRect.Y1), 334*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rRect.X2 - rRect.X1), 335*cdf0e10cSrcweir static_cast<Gdiplus::REAL>(rRect.Y2 - rRect.Y1) ); 336*cdf0e10cSrcweir } 337*cdf0e10cSrcweir 338*cdf0e10cSrcweir RECT gdiRectFromB2IRect( const ::basegfx::B2IRange& rRect ) 339*cdf0e10cSrcweir { 340*cdf0e10cSrcweir RECT aRect = {rRect.getMinX(), 341*cdf0e10cSrcweir rRect.getMinY(), 342*cdf0e10cSrcweir rRect.getMaxX(), 343*cdf0e10cSrcweir rRect.getMaxY()}; 344*cdf0e10cSrcweir 345*cdf0e10cSrcweir return aRect; 346*cdf0e10cSrcweir } 347*cdf0e10cSrcweir 348*cdf0e10cSrcweir geometry::RealPoint2D realPoint2DFromGdiPlusPointF( const Gdiplus::PointF& rPoint ) 349*cdf0e10cSrcweir { 350*cdf0e10cSrcweir return geometry::RealPoint2D( rPoint.X, rPoint.Y ); 351*cdf0e10cSrcweir } 352*cdf0e10cSrcweir 353*cdf0e10cSrcweir geometry::RealRectangle2D realRectangle2DFromGdiPlusRectF( const Gdiplus::RectF& rRect ) 354*cdf0e10cSrcweir { 355*cdf0e10cSrcweir return geometry::RealRectangle2D( rRect.X, rRect.Y, 356*cdf0e10cSrcweir rRect.X + rRect.Width, 357*cdf0e10cSrcweir rRect.Y + rRect.Height ); 358*cdf0e10cSrcweir } 359*cdf0e10cSrcweir 360*cdf0e10cSrcweir ::basegfx::B2DPoint b2dPointFromGdiPlusPointF( const Gdiplus::PointF& rPoint ) 361*cdf0e10cSrcweir { 362*cdf0e10cSrcweir return ::basegfx::B2DPoint( rPoint.X, rPoint.Y ); 363*cdf0e10cSrcweir } 364*cdf0e10cSrcweir 365*cdf0e10cSrcweir ::basegfx::B2DRange b2dRangeFromGdiPlusRectF( const Gdiplus::RectF& rRect ) 366*cdf0e10cSrcweir { 367*cdf0e10cSrcweir return ::basegfx::B2DRange( rRect.X, rRect.Y, 368*cdf0e10cSrcweir rRect.X + rRect.Width, 369*cdf0e10cSrcweir rRect.Y + rRect.Height ); 370*cdf0e10cSrcweir } 371*cdf0e10cSrcweir 372*cdf0e10cSrcweir uno::Sequence< double > argbToDoubleSequence( const Gdiplus::ARGB& rColor ) 373*cdf0e10cSrcweir { 374*cdf0e10cSrcweir // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice 375*cdf0e10cSrcweir uno::Sequence< double > aRet(4); 376*cdf0e10cSrcweir 377*cdf0e10cSrcweir aRet[0] = ((rColor >> 16) & 0xFF) / 255.0; // red 378*cdf0e10cSrcweir aRet[1] = ((rColor >> 8) & 0xFF) / 255.0; // green 379*cdf0e10cSrcweir aRet[2] = (rColor & 0xFF) / 255.0; // blue 380*cdf0e10cSrcweir aRet[3] = ((rColor >> 24) & 0xFF) / 255.0; // alpha 381*cdf0e10cSrcweir 382*cdf0e10cSrcweir return aRet; 383*cdf0e10cSrcweir } 384*cdf0e10cSrcweir 385*cdf0e10cSrcweir uno::Sequence< sal_Int8 > argbToIntSequence( const Gdiplus::ARGB& rColor ) 386*cdf0e10cSrcweir { 387*cdf0e10cSrcweir // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice 388*cdf0e10cSrcweir uno::Sequence< sal_Int8 > aRet(4); 389*cdf0e10cSrcweir 390*cdf0e10cSrcweir aRet[0] = static_cast<sal_Int8>((rColor >> 16) & 0xFF); // red 391*cdf0e10cSrcweir aRet[1] = static_cast<sal_Int8>((rColor >> 8) & 0xFF); // green 392*cdf0e10cSrcweir aRet[2] = static_cast<sal_Int8>(rColor & 0xFF); // blue 393*cdf0e10cSrcweir aRet[3] = static_cast<sal_Int8>((rColor >> 24) & 0xFF); // alpha 394*cdf0e10cSrcweir 395*cdf0e10cSrcweir return aRet; 396*cdf0e10cSrcweir } 397*cdf0e10cSrcweir 398*cdf0e10cSrcweir Gdiplus::ARGB sequenceToArgb( const uno::Sequence< sal_Int8 >& rColor ) 399*cdf0e10cSrcweir { 400*cdf0e10cSrcweir ENSURE_OR_THROW( rColor.getLength() > 2, 401*cdf0e10cSrcweir "sequenceToArgb: need at least three channels" ); 402*cdf0e10cSrcweir 403*cdf0e10cSrcweir // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice 404*cdf0e10cSrcweir Gdiplus::ARGB aColor; 405*cdf0e10cSrcweir 406*cdf0e10cSrcweir aColor = (static_cast<sal_uInt8>(rColor[0]) << 16) | (static_cast<sal_uInt8>(rColor[1]) << 8) | static_cast<sal_uInt8>(rColor[2]); 407*cdf0e10cSrcweir 408*cdf0e10cSrcweir if( rColor.getLength() > 3 ) 409*cdf0e10cSrcweir aColor |= static_cast<sal_uInt8>(rColor[3]) << 24; 410*cdf0e10cSrcweir 411*cdf0e10cSrcweir return aColor; 412*cdf0e10cSrcweir } 413*cdf0e10cSrcweir 414*cdf0e10cSrcweir Gdiplus::ARGB sequenceToArgb( const uno::Sequence< double >& rColor ) 415*cdf0e10cSrcweir { 416*cdf0e10cSrcweir ENSURE_OR_THROW( rColor.getLength() > 2, 417*cdf0e10cSrcweir "sequenceToColor: need at least three channels" ); 418*cdf0e10cSrcweir 419*cdf0e10cSrcweir // TODO(F1): handle color space conversions, when defined on canvas/graphicDevice 420*cdf0e10cSrcweir Gdiplus::ARGB aColor; 421*cdf0e10cSrcweir 422*cdf0e10cSrcweir ::canvas::tools::verifyRange(rColor[0],0.0,1.0); 423*cdf0e10cSrcweir ::canvas::tools::verifyRange(rColor[1],0.0,1.0); 424*cdf0e10cSrcweir ::canvas::tools::verifyRange(rColor[2],0.0,1.0); 425*cdf0e10cSrcweir 426*cdf0e10cSrcweir aColor = 427*cdf0e10cSrcweir (static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[0] ) ) << 16) | 428*cdf0e10cSrcweir (static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[1] ) ) << 8) | 429*cdf0e10cSrcweir static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[2] ) ); 430*cdf0e10cSrcweir 431*cdf0e10cSrcweir if( rColor.getLength() > 3 ) 432*cdf0e10cSrcweir { 433*cdf0e10cSrcweir ::canvas::tools::verifyRange(rColor[3],0.0,1.0); 434*cdf0e10cSrcweir aColor |= static_cast<sal_uInt8>( ::basegfx::fround( 255*rColor[3] ) ) << 24; 435*cdf0e10cSrcweir } 436*cdf0e10cSrcweir 437*cdf0e10cSrcweir return aColor; 438*cdf0e10cSrcweir } 439*cdf0e10cSrcweir 440*cdf0e10cSrcweir GraphicsPathSharedPtr graphicsPathFromRealPoint2DSequence( const uno::Sequence< uno::Sequence< geometry::RealPoint2D > >& points ) 441*cdf0e10cSrcweir { 442*cdf0e10cSrcweir GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); 443*cdf0e10cSrcweir ::std::vector< Gdiplus::PointF > aPoints; 444*cdf0e10cSrcweir 445*cdf0e10cSrcweir sal_Int32 nCurrPoly; 446*cdf0e10cSrcweir for( nCurrPoly=0; nCurrPoly<points.getLength(); ++nCurrPoly ) 447*cdf0e10cSrcweir { 448*cdf0e10cSrcweir const sal_Int32 nCurrSize( points[nCurrPoly].getLength() ); 449*cdf0e10cSrcweir if( nCurrSize ) 450*cdf0e10cSrcweir { 451*cdf0e10cSrcweir aPoints.resize( nCurrSize ); 452*cdf0e10cSrcweir 453*cdf0e10cSrcweir // TODO(F1): Closed/open polygons 454*cdf0e10cSrcweir 455*cdf0e10cSrcweir // convert from RealPoint2D array to Gdiplus::PointF array 456*cdf0e10cSrcweir ::std::transform( const_cast< uno::Sequence< geometry::RealPoint2D >& >(points[nCurrPoly]).getArray(), 457*cdf0e10cSrcweir const_cast< uno::Sequence< geometry::RealPoint2D >& >(points[nCurrPoly]).getArray()+nCurrSize, 458*cdf0e10cSrcweir aPoints.begin(), 459*cdf0e10cSrcweir implGdiPlusPointFromRealPoint2D ); 460*cdf0e10cSrcweir 461*cdf0e10cSrcweir pRes->AddLines( &aPoints[0], nCurrSize ); 462*cdf0e10cSrcweir } 463*cdf0e10cSrcweir } 464*cdf0e10cSrcweir 465*cdf0e10cSrcweir return pRes; 466*cdf0e10cSrcweir } 467*cdf0e10cSrcweir 468*cdf0e10cSrcweir GraphicsPathSharedPtr graphicsPathFromB2DPolygon( const ::basegfx::B2DPolygon& rPoly, bool bNoLineJoin ) 469*cdf0e10cSrcweir { 470*cdf0e10cSrcweir GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); 471*cdf0e10cSrcweir ::std::vector< Gdiplus::PointF > aPoints; 472*cdf0e10cSrcweir 473*cdf0e10cSrcweir graphicsPathFromB2DPolygon( pRes, aPoints, rPoly, bNoLineJoin ); 474*cdf0e10cSrcweir 475*cdf0e10cSrcweir return pRes; 476*cdf0e10cSrcweir } 477*cdf0e10cSrcweir 478*cdf0e10cSrcweir GraphicsPathSharedPtr graphicsPathFromB2DPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly, bool bNoLineJoin ) 479*cdf0e10cSrcweir { 480*cdf0e10cSrcweir GraphicsPathSharedPtr pRes( new Gdiplus::GraphicsPath() ); 481*cdf0e10cSrcweir ::std::vector< Gdiplus::PointF > aPoints; 482*cdf0e10cSrcweir 483*cdf0e10cSrcweir const sal_uInt32 nPolies( rPoly.count() ); 484*cdf0e10cSrcweir for( sal_uInt32 nCurrPoly=0; nCurrPoly<nPolies; ++nCurrPoly ) 485*cdf0e10cSrcweir { 486*cdf0e10cSrcweir graphicsPathFromB2DPolygon( pRes, 487*cdf0e10cSrcweir aPoints, 488*cdf0e10cSrcweir rPoly.getB2DPolygon( nCurrPoly ), 489*cdf0e10cSrcweir bNoLineJoin); 490*cdf0e10cSrcweir } 491*cdf0e10cSrcweir 492*cdf0e10cSrcweir return pRes; 493*cdf0e10cSrcweir } 494*cdf0e10cSrcweir 495*cdf0e10cSrcweir GraphicsPathSharedPtr graphicsPathFromXPolyPolygon2D( const uno::Reference< rendering::XPolyPolygon2D >& xPoly, bool bNoLineJoin ) 496*cdf0e10cSrcweir { 497*cdf0e10cSrcweir LinePolyPolygon* pPolyImpl = dynamic_cast< LinePolyPolygon* >( xPoly.get() ); 498*cdf0e10cSrcweir 499*cdf0e10cSrcweir if( pPolyImpl ) 500*cdf0e10cSrcweir { 501*cdf0e10cSrcweir return pPolyImpl->getGraphicsPath( bNoLineJoin ); 502*cdf0e10cSrcweir } 503*cdf0e10cSrcweir else 504*cdf0e10cSrcweir { 505*cdf0e10cSrcweir return tools::graphicsPathFromB2DPolyPolygon( 506*cdf0e10cSrcweir polyPolygonFromXPolyPolygon2D( xPoly ), bNoLineJoin ); 507*cdf0e10cSrcweir } 508*cdf0e10cSrcweir } 509*cdf0e10cSrcweir 510*cdf0e10cSrcweir bool drawGdiPlusBitmap( const GraphicsSharedPtr& rGraphics, 511*cdf0e10cSrcweir const BitmapSharedPtr& rBitmap ) 512*cdf0e10cSrcweir { 513*cdf0e10cSrcweir Gdiplus::PointF aPoint; 514*cdf0e10cSrcweir return (Gdiplus::Ok == rGraphics->DrawImage( rBitmap.get(), 515*cdf0e10cSrcweir aPoint ) ); 516*cdf0e10cSrcweir } 517*cdf0e10cSrcweir 518*cdf0e10cSrcweir bool drawDIBits( const GraphicsSharedPtr& rGraphics, 519*cdf0e10cSrcweir const BITMAPINFO& rBI, 520*cdf0e10cSrcweir const void* pBits ) 521*cdf0e10cSrcweir { 522*cdf0e10cSrcweir BitmapSharedPtr pBitmap( 523*cdf0e10cSrcweir Gdiplus::Bitmap::FromBITMAPINFO( &rBI, 524*cdf0e10cSrcweir (void*)pBits ) ); 525*cdf0e10cSrcweir 526*cdf0e10cSrcweir return drawGdiPlusBitmap( rGraphics, 527*cdf0e10cSrcweir pBitmap ); 528*cdf0e10cSrcweir } 529*cdf0e10cSrcweir 530*cdf0e10cSrcweir bool drawRGBABits( const GraphicsSharedPtr& rGraphics, 531*cdf0e10cSrcweir const RawRGBABitmap& rRawRGBAData ) 532*cdf0e10cSrcweir { 533*cdf0e10cSrcweir BitmapSharedPtr pBitmap( new Gdiplus::Bitmap( rRawRGBAData.mnWidth, 534*cdf0e10cSrcweir rRawRGBAData.mnHeight, 535*cdf0e10cSrcweir PixelFormat32bppARGB ) ); 536*cdf0e10cSrcweir 537*cdf0e10cSrcweir Gdiplus::BitmapData aBmpData; 538*cdf0e10cSrcweir aBmpData.Width = rRawRGBAData.mnWidth; 539*cdf0e10cSrcweir aBmpData.Height = rRawRGBAData.mnHeight; 540*cdf0e10cSrcweir aBmpData.Stride = 4*aBmpData.Width; // bottom-up format 541*cdf0e10cSrcweir aBmpData.PixelFormat = PixelFormat32bppARGB; 542*cdf0e10cSrcweir aBmpData.Scan0 = rRawRGBAData.mpBitmapData.get(); 543*cdf0e10cSrcweir 544*cdf0e10cSrcweir const Gdiplus::Rect aRect( 0,0,aBmpData.Width,aBmpData.Height ); 545*cdf0e10cSrcweir if( Gdiplus::Ok != pBitmap->LockBits( &aRect, 546*cdf0e10cSrcweir Gdiplus::ImageLockModeWrite | Gdiplus::ImageLockModeUserInputBuf, 547*cdf0e10cSrcweir PixelFormat32bppARGB, 548*cdf0e10cSrcweir &aBmpData ) ) 549*cdf0e10cSrcweir { 550*cdf0e10cSrcweir return false; 551*cdf0e10cSrcweir } 552*cdf0e10cSrcweir 553*cdf0e10cSrcweir // commit data to bitmap 554*cdf0e10cSrcweir pBitmap->UnlockBits( &aBmpData ); 555*cdf0e10cSrcweir 556*cdf0e10cSrcweir return drawGdiPlusBitmap( rGraphics, 557*cdf0e10cSrcweir pBitmap ); 558*cdf0e10cSrcweir } 559*cdf0e10cSrcweir 560*cdf0e10cSrcweir BitmapSharedPtr bitmapFromXBitmap( const uno::Reference< rendering::XBitmap >& xBitmap ) 561*cdf0e10cSrcweir { 562*cdf0e10cSrcweir BitmapProvider* pBitmapProvider = dynamic_cast< BitmapProvider* >(xBitmap.get()); 563*cdf0e10cSrcweir 564*cdf0e10cSrcweir if( pBitmapProvider ) 565*cdf0e10cSrcweir { 566*cdf0e10cSrcweir IBitmapSharedPtr pBitmap( pBitmapProvider->getBitmap() ); 567*cdf0e10cSrcweir return pBitmap->getBitmap(); 568*cdf0e10cSrcweir } 569*cdf0e10cSrcweir else 570*cdf0e10cSrcweir { 571*cdf0e10cSrcweir // not a native CanvasBitmap, extract VCL bitmap and 572*cdf0e10cSrcweir // render into GDI+ bitmap of similar size 573*cdf0e10cSrcweir // ================================================= 574*cdf0e10cSrcweir 575*cdf0e10cSrcweir const geometry::IntegerSize2D aBmpSize( xBitmap->getSize() ); 576*cdf0e10cSrcweir BitmapSharedPtr pBitmap; 577*cdf0e10cSrcweir 578*cdf0e10cSrcweir if( xBitmap->hasAlpha() ) 579*cdf0e10cSrcweir { 580*cdf0e10cSrcweir // TODO(P2): At least for the alpha bitmap case, it 581*cdf0e10cSrcweir // would be possible to generate the corresponding 582*cdf0e10cSrcweir // bitmap directly 583*cdf0e10cSrcweir pBitmap.reset( new Gdiplus::Bitmap( aBmpSize.Width, 584*cdf0e10cSrcweir aBmpSize.Height, 585*cdf0e10cSrcweir PixelFormat32bppARGB ) ); 586*cdf0e10cSrcweir } 587*cdf0e10cSrcweir else 588*cdf0e10cSrcweir { 589*cdf0e10cSrcweir // TODO(F2): Might be wise to create bitmap compatible 590*cdf0e10cSrcweir // to the VCL bitmap. Also, check whether the VCL 591*cdf0e10cSrcweir // bitmap's system handles can be used to create the 592*cdf0e10cSrcweir // GDI+ bitmap (currently, it does not seem so). 593*cdf0e10cSrcweir pBitmap.reset( new Gdiplus::Bitmap( aBmpSize.Width, 594*cdf0e10cSrcweir aBmpSize.Height, 595*cdf0e10cSrcweir PixelFormat24bppRGB ) ); 596*cdf0e10cSrcweir } 597*cdf0e10cSrcweir 598*cdf0e10cSrcweir GraphicsSharedPtr pGraphics(createGraphicsFromBitmap(pBitmap)); 599*cdf0e10cSrcweir tools::setupGraphics(*pGraphics); 600*cdf0e10cSrcweir if( !drawVCLBitmapFromXBitmap( 601*cdf0e10cSrcweir pGraphics, 602*cdf0e10cSrcweir xBitmap) ) 603*cdf0e10cSrcweir { 604*cdf0e10cSrcweir pBitmap.reset(); 605*cdf0e10cSrcweir } 606*cdf0e10cSrcweir 607*cdf0e10cSrcweir return pBitmap; 608*cdf0e10cSrcweir } 609*cdf0e10cSrcweir } 610*cdf0e10cSrcweir 611*cdf0e10cSrcweir CanvasFont::ImplRef canvasFontFromXFont( const uno::Reference< rendering::XCanvasFont >& xFont ) 612*cdf0e10cSrcweir { 613*cdf0e10cSrcweir CanvasFont* pCanvasFont = dynamic_cast< CanvasFont* >(xFont.get()); 614*cdf0e10cSrcweir 615*cdf0e10cSrcweir ENSURE_ARG_OR_THROW( pCanvasFont, 616*cdf0e10cSrcweir "canvasFontFromXFont(): Invalid XFont (or incompatible font for this XCanvas)" ); 617*cdf0e10cSrcweir 618*cdf0e10cSrcweir return CanvasFont::ImplRef( pCanvasFont ); 619*cdf0e10cSrcweir } 620*cdf0e10cSrcweir 621*cdf0e10cSrcweir void setModulateImageAttributes( Gdiplus::ImageAttributes& o_rAttr, 622*cdf0e10cSrcweir double nRedModulation, 623*cdf0e10cSrcweir double nGreenModulation, 624*cdf0e10cSrcweir double nBlueModulation, 625*cdf0e10cSrcweir double nAlphaModulation ) 626*cdf0e10cSrcweir { 627*cdf0e10cSrcweir // This gets rather verbose, but we have to setup a color 628*cdf0e10cSrcweir // transformation matrix, in order to incorporate the global 629*cdf0e10cSrcweir // alpha value mfAlpha into the bitmap rendering. 630*cdf0e10cSrcweir Gdiplus::ColorMatrix aColorMatrix; 631*cdf0e10cSrcweir 632*cdf0e10cSrcweir aColorMatrix.m[0][0] = static_cast<Gdiplus::REAL>(nRedModulation); 633*cdf0e10cSrcweir aColorMatrix.m[0][1] = 0.0; 634*cdf0e10cSrcweir aColorMatrix.m[0][2] = 0.0; 635*cdf0e10cSrcweir aColorMatrix.m[0][3] = 0.0; 636*cdf0e10cSrcweir aColorMatrix.m[0][4] = 0.0; 637*cdf0e10cSrcweir 638*cdf0e10cSrcweir aColorMatrix.m[1][0] = 0.0; 639*cdf0e10cSrcweir aColorMatrix.m[1][1] = static_cast<Gdiplus::REAL>(nGreenModulation); 640*cdf0e10cSrcweir aColorMatrix.m[1][2] = 0.0; 641*cdf0e10cSrcweir aColorMatrix.m[1][3] = 0.0; 642*cdf0e10cSrcweir aColorMatrix.m[1][4] = 0.0; 643*cdf0e10cSrcweir 644*cdf0e10cSrcweir aColorMatrix.m[2][0] = 0.0; 645*cdf0e10cSrcweir aColorMatrix.m[2][1] = 0.0; 646*cdf0e10cSrcweir aColorMatrix.m[2][2] = static_cast<Gdiplus::REAL>(nBlueModulation); 647*cdf0e10cSrcweir aColorMatrix.m[2][3] = 0.0; 648*cdf0e10cSrcweir aColorMatrix.m[2][4] = 0.0; 649*cdf0e10cSrcweir 650*cdf0e10cSrcweir aColorMatrix.m[3][0] = 0.0; 651*cdf0e10cSrcweir aColorMatrix.m[3][1] = 0.0; 652*cdf0e10cSrcweir aColorMatrix.m[3][2] = 0.0; 653*cdf0e10cSrcweir aColorMatrix.m[3][3] = static_cast<Gdiplus::REAL>(nAlphaModulation); 654*cdf0e10cSrcweir aColorMatrix.m[3][4] = 0.0; 655*cdf0e10cSrcweir 656*cdf0e10cSrcweir aColorMatrix.m[4][0] = 0.0; 657*cdf0e10cSrcweir aColorMatrix.m[4][1] = 0.0; 658*cdf0e10cSrcweir aColorMatrix.m[4][2] = 0.0; 659*cdf0e10cSrcweir aColorMatrix.m[4][3] = 0.0; 660*cdf0e10cSrcweir aColorMatrix.m[4][4] = 1.0; 661*cdf0e10cSrcweir 662*cdf0e10cSrcweir o_rAttr.SetColorMatrix( &aColorMatrix, 663*cdf0e10cSrcweir Gdiplus::ColorMatrixFlagsDefault, 664*cdf0e10cSrcweir Gdiplus::ColorAdjustTypeDefault ); 665*cdf0e10cSrcweir } 666*cdf0e10cSrcweir 667*cdf0e10cSrcweir } // namespace tools 668*cdf0e10cSrcweir } // namespace dxcanvas 669