xref: /AOO41X/main/canvas/source/directx/dx_impltools.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3)
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