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