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_cppcanvas.hxx"
30*cdf0e10cSrcweir 
31*cdf0e10cSrcweir #include <canvas/debug.hxx>
32*cdf0e10cSrcweir #include <tools/diagnose_ex.h>
33*cdf0e10cSrcweir #include <canvas/verbosetrace.hxx>
34*cdf0e10cSrcweir #include <osl/mutex.hxx>
35*cdf0e10cSrcweir #include <vos/mutex.hxx>
36*cdf0e10cSrcweir #include <vcl/svapp.hxx>
37*cdf0e10cSrcweir #include <rtl/logfile.hxx>
38*cdf0e10cSrcweir #include <comphelper/sequence.hxx>
39*cdf0e10cSrcweir #include <comphelper/anytostring.hxx>
40*cdf0e10cSrcweir #include <cppuhelper/exc_hlp.hxx>
41*cdf0e10cSrcweir #include <cppcanvas/canvas.hxx>
42*cdf0e10cSrcweir #include <com/sun/star/rendering/XGraphicDevice.hpp>
43*cdf0e10cSrcweir #include <com/sun/star/rendering/TexturingMode.hpp>
44*cdf0e10cSrcweir #include <com/sun/star/uno/Sequence.hxx>
45*cdf0e10cSrcweir #include <com/sun/star/geometry/RealPoint2D.hpp>
46*cdf0e10cSrcweir #include <com/sun/star/rendering/PanoseProportion.hpp>
47*cdf0e10cSrcweir #include <com/sun/star/rendering/ViewState.hpp>
48*cdf0e10cSrcweir #include <com/sun/star/rendering/RenderState.hpp>
49*cdf0e10cSrcweir #include <com/sun/star/rendering/XCanvasFont.hpp>
50*cdf0e10cSrcweir #include <com/sun/star/rendering/XPolyPolygon2D.hpp>
51*cdf0e10cSrcweir #include <com/sun/star/rendering/XCanvas.hpp>
52*cdf0e10cSrcweir #include <com/sun/star/rendering/PathCapType.hpp>
53*cdf0e10cSrcweir #include <com/sun/star/rendering/PathJoinType.hpp>
54*cdf0e10cSrcweir #include <basegfx/tools/canvastools.hxx>
55*cdf0e10cSrcweir #include <basegfx/tools/gradienttools.hxx>
56*cdf0e10cSrcweir #include <basegfx/numeric/ftools.hxx>
57*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx>
58*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
59*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygon.hxx>
60*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygon.hxx>
61*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrix.hxx>
62*cdf0e10cSrcweir #include <basegfx/vector/b2dsize.hxx>
63*cdf0e10cSrcweir #include <basegfx/range/b2drectangle.hxx>
64*cdf0e10cSrcweir #include <basegfx/point/b2dpoint.hxx>
65*cdf0e10cSrcweir #include <basegfx/tuple/b2dtuple.hxx>
66*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygonclipper.hxx>
67*cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygoncutter.hxx>
68*cdf0e10cSrcweir #include <canvas/canvastools.hxx>
69*cdf0e10cSrcweir #include <vcl/canvastools.hxx>
70*cdf0e10cSrcweir #include <vcl/salbtype.hxx>
71*cdf0e10cSrcweir #include <vcl/gdimtf.hxx>
72*cdf0e10cSrcweir #include <vcl/metaact.hxx>
73*cdf0e10cSrcweir #include <vcl/virdev.hxx>
74*cdf0e10cSrcweir #include <vcl/metric.hxx>
75*cdf0e10cSrcweir #include <vcl/graphictools.hxx>
76*cdf0e10cSrcweir #include <tools/poly.hxx>
77*cdf0e10cSrcweir #include <i18npool/mslangid.hxx>
78*cdf0e10cSrcweir #include <implrenderer.hxx>
79*cdf0e10cSrcweir #include <tools.hxx>
80*cdf0e10cSrcweir #include <outdevstate.hxx>
81*cdf0e10cSrcweir #include <action.hxx>
82*cdf0e10cSrcweir #include <bitmapaction.hxx>
83*cdf0e10cSrcweir #include <lineaction.hxx>
84*cdf0e10cSrcweir #include <pointaction.hxx>
85*cdf0e10cSrcweir #include <polypolyaction.hxx>
86*cdf0e10cSrcweir #include <rendergraphicaction.hxx>
87*cdf0e10cSrcweir #include <textaction.hxx>
88*cdf0e10cSrcweir #include <transparencygroupaction.hxx>
89*cdf0e10cSrcweir #include <vector>
90*cdf0e10cSrcweir #include <algorithm>
91*cdf0e10cSrcweir #include <iterator>
92*cdf0e10cSrcweir #include <boost/scoped_array.hpp>
93*cdf0e10cSrcweir #include "mtftools.hxx"
94*cdf0e10cSrcweir #include "outdevstate.hxx"
95*cdf0e10cSrcweir #include <basegfx/matrix/b2dhommatrixtools.hxx>
96*cdf0e10cSrcweir 
97*cdf0e10cSrcweir 
98*cdf0e10cSrcweir using namespace ::com::sun::star;
99*cdf0e10cSrcweir 
100*cdf0e10cSrcweir 
101*cdf0e10cSrcweir // free support functions
102*cdf0e10cSrcweir // ======================
103*cdf0e10cSrcweir namespace
104*cdf0e10cSrcweir {
105*cdf0e10cSrcweir     template < class MetaActionType > void setStateColor( MetaActionType* 					pAct,
106*cdf0e10cSrcweir                                                           bool&								rIsColorSet,
107*cdf0e10cSrcweir                                                           uno::Sequence< double >& 			rColorSequence,
108*cdf0e10cSrcweir                                                           const cppcanvas::CanvasSharedPtr&	rCanvas )
109*cdf0e10cSrcweir     {
110*cdf0e10cSrcweir         // set rIsColorSet and check for true at the same time
111*cdf0e10cSrcweir         if( (rIsColorSet=pAct->IsSetting()) != false )
112*cdf0e10cSrcweir         {
113*cdf0e10cSrcweir             ::Color aColor( pAct->GetColor() );
114*cdf0e10cSrcweir 
115*cdf0e10cSrcweir             // force alpha part of color to
116*cdf0e10cSrcweir             // opaque. transparent painting is done
117*cdf0e10cSrcweir             // explicitely via META_TRANSPARENT_ACTION
118*cdf0e10cSrcweir             aColor.SetTransparency(0);
119*cdf0e10cSrcweir             //aColor.SetTransparency(128);
120*cdf0e10cSrcweir 
121*cdf0e10cSrcweir             rColorSequence = ::vcl::unotools::colorToDoubleSequence(
122*cdf0e10cSrcweir                 aColor,
123*cdf0e10cSrcweir                 rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
124*cdf0e10cSrcweir         }
125*cdf0e10cSrcweir     }
126*cdf0e10cSrcweir 
127*cdf0e10cSrcweir 
128*cdf0e10cSrcweir     // state stack manipulators
129*cdf0e10cSrcweir     // ------------------------
130*cdf0e10cSrcweir     void clearStateStack( ::cppcanvas::internal::VectorOfOutDevStates& rStates )
131*cdf0e10cSrcweir     {
132*cdf0e10cSrcweir         rStates.clear();
133*cdf0e10cSrcweir         const ::cppcanvas::internal::OutDevState aDefaultState;
134*cdf0e10cSrcweir         rStates.push_back( aDefaultState );
135*cdf0e10cSrcweir     }
136*cdf0e10cSrcweir 
137*cdf0e10cSrcweir     ::cppcanvas::internal::OutDevState& getState( ::cppcanvas::internal::VectorOfOutDevStates& rStates )
138*cdf0e10cSrcweir     {
139*cdf0e10cSrcweir         return rStates.back();
140*cdf0e10cSrcweir     }
141*cdf0e10cSrcweir 
142*cdf0e10cSrcweir     const ::cppcanvas::internal::OutDevState& getState( const ::cppcanvas::internal::VectorOfOutDevStates& rStates )
143*cdf0e10cSrcweir     {
144*cdf0e10cSrcweir         return rStates.back();
145*cdf0e10cSrcweir     }
146*cdf0e10cSrcweir 
147*cdf0e10cSrcweir     void pushState( ::cppcanvas::internal::VectorOfOutDevStates& rStates,
148*cdf0e10cSrcweir                     sal_uInt16 nFlags											)
149*cdf0e10cSrcweir     {
150*cdf0e10cSrcweir         rStates.push_back( getState( rStates ) );
151*cdf0e10cSrcweir         getState( rStates ).pushFlags = nFlags;
152*cdf0e10cSrcweir     }
153*cdf0e10cSrcweir 
154*cdf0e10cSrcweir     void popState( ::cppcanvas::internal::VectorOfOutDevStates& rStates )
155*cdf0e10cSrcweir     {
156*cdf0e10cSrcweir         if( getState( rStates ).pushFlags != PUSH_ALL )
157*cdf0e10cSrcweir         {
158*cdf0e10cSrcweir             // a state is pushed which is incomplete, i.e. does not
159*cdf0e10cSrcweir             // restore everything to the previous stack level when
160*cdf0e10cSrcweir             // popped.
161*cdf0e10cSrcweir             // That means, we take the old state, and restore every
162*cdf0e10cSrcweir             // OutDevState member whose flag is set, from the new to the
163*cdf0e10cSrcweir             // old state. Then the new state gets overwritten by the
164*cdf0e10cSrcweir             // calculated state
165*cdf0e10cSrcweir 
166*cdf0e10cSrcweir             // preset to-be-calculated new state with old state
167*cdf0e10cSrcweir             ::cppcanvas::internal::OutDevState aCalculatedNewState( getState( rStates ) );
168*cdf0e10cSrcweir 
169*cdf0e10cSrcweir             // selectively copy to-be-restored content over saved old
170*cdf0e10cSrcweir             // state
171*cdf0e10cSrcweir             rStates.pop_back();
172*cdf0e10cSrcweir 
173*cdf0e10cSrcweir             const ::cppcanvas::internal::OutDevState& rNewState( getState( rStates ) );
174*cdf0e10cSrcweir 
175*cdf0e10cSrcweir             if( (aCalculatedNewState.pushFlags & PUSH_LINECOLOR) )
176*cdf0e10cSrcweir             {
177*cdf0e10cSrcweir                 aCalculatedNewState.lineColor 	   = rNewState.lineColor;
178*cdf0e10cSrcweir                 aCalculatedNewState.isLineColorSet = rNewState.isLineColorSet;
179*cdf0e10cSrcweir             }
180*cdf0e10cSrcweir 
181*cdf0e10cSrcweir             if( (aCalculatedNewState.pushFlags & PUSH_FILLCOLOR) )
182*cdf0e10cSrcweir             {
183*cdf0e10cSrcweir                 aCalculatedNewState.fillColor 	   = rNewState.fillColor;
184*cdf0e10cSrcweir                 aCalculatedNewState.isFillColorSet = rNewState.isFillColorSet;
185*cdf0e10cSrcweir             }
186*cdf0e10cSrcweir 
187*cdf0e10cSrcweir             if( (aCalculatedNewState.pushFlags & PUSH_FONT) )
188*cdf0e10cSrcweir             {
189*cdf0e10cSrcweir                 aCalculatedNewState.xFont 					= rNewState.xFont;
190*cdf0e10cSrcweir                 aCalculatedNewState.fontRotation 			= rNewState.fontRotation;
191*cdf0e10cSrcweir                 aCalculatedNewState.textReliefStyle 		= rNewState.textReliefStyle;
192*cdf0e10cSrcweir                 aCalculatedNewState.textOverlineStyle 		= rNewState.textOverlineStyle;
193*cdf0e10cSrcweir                 aCalculatedNewState.textUnderlineStyle 		= rNewState.textUnderlineStyle;
194*cdf0e10cSrcweir                 aCalculatedNewState.textStrikeoutStyle 		= rNewState.textStrikeoutStyle;
195*cdf0e10cSrcweir                 aCalculatedNewState.textEmphasisMarkStyle 	= rNewState.textEmphasisMarkStyle;
196*cdf0e10cSrcweir                 aCalculatedNewState.isTextEffectShadowSet 	= rNewState.isTextEffectShadowSet;
197*cdf0e10cSrcweir                 aCalculatedNewState.isTextWordUnderlineSet 	= rNewState.isTextWordUnderlineSet;
198*cdf0e10cSrcweir                 aCalculatedNewState.isTextOutlineModeSet 	= rNewState.isTextOutlineModeSet;
199*cdf0e10cSrcweir             }
200*cdf0e10cSrcweir 
201*cdf0e10cSrcweir             if( (aCalculatedNewState.pushFlags & PUSH_TEXTCOLOR) )
202*cdf0e10cSrcweir             {
203*cdf0e10cSrcweir                 aCalculatedNewState.textColor = rNewState.textColor;
204*cdf0e10cSrcweir             }
205*cdf0e10cSrcweir 
206*cdf0e10cSrcweir             if( (aCalculatedNewState.pushFlags & PUSH_MAPMODE) )
207*cdf0e10cSrcweir             {
208*cdf0e10cSrcweir                 aCalculatedNewState.mapModeTransform = rNewState.mapModeTransform;
209*cdf0e10cSrcweir             }
210*cdf0e10cSrcweir 
211*cdf0e10cSrcweir             if( (aCalculatedNewState.pushFlags & PUSH_CLIPREGION) )
212*cdf0e10cSrcweir             {
213*cdf0e10cSrcweir                 aCalculatedNewState.clip 		= rNewState.clip;
214*cdf0e10cSrcweir                 aCalculatedNewState.clipRect	= rNewState.clipRect;
215*cdf0e10cSrcweir                 aCalculatedNewState.xClipPoly	= rNewState.xClipPoly;
216*cdf0e10cSrcweir             }
217*cdf0e10cSrcweir 
218*cdf0e10cSrcweir             // TODO(F2): Raster ops NYI
219*cdf0e10cSrcweir             // if( (aCalculatedNewState.pushFlags & PUSH_RASTEROP) )
220*cdf0e10cSrcweir             // {
221*cdf0e10cSrcweir             // }
222*cdf0e10cSrcweir 
223*cdf0e10cSrcweir             if( (aCalculatedNewState.pushFlags & PUSH_TEXTFILLCOLOR) )
224*cdf0e10cSrcweir             {
225*cdf0e10cSrcweir                 aCalculatedNewState.textFillColor 	   = rNewState.textFillColor;
226*cdf0e10cSrcweir                 aCalculatedNewState.isTextFillColorSet = rNewState.isTextFillColorSet;
227*cdf0e10cSrcweir             }
228*cdf0e10cSrcweir 
229*cdf0e10cSrcweir             if( (aCalculatedNewState.pushFlags & PUSH_TEXTALIGN) )
230*cdf0e10cSrcweir             {
231*cdf0e10cSrcweir                 aCalculatedNewState.textReferencePoint = rNewState.textReferencePoint;
232*cdf0e10cSrcweir             }
233*cdf0e10cSrcweir 
234*cdf0e10cSrcweir             // TODO(F1): Refpoint handling NYI
235*cdf0e10cSrcweir             // if( (aCalculatedNewState.pushFlags & PUSH_REFPOINT) )
236*cdf0e10cSrcweir             // {
237*cdf0e10cSrcweir             // }
238*cdf0e10cSrcweir 
239*cdf0e10cSrcweir             if( (aCalculatedNewState.pushFlags & PUSH_TEXTLINECOLOR) )
240*cdf0e10cSrcweir             {
241*cdf0e10cSrcweir                 aCalculatedNewState.textLineColor 	   = rNewState.textLineColor;
242*cdf0e10cSrcweir                 aCalculatedNewState.isTextLineColorSet = rNewState.isTextLineColorSet;
243*cdf0e10cSrcweir             }
244*cdf0e10cSrcweir 
245*cdf0e10cSrcweir             if( (aCalculatedNewState.pushFlags & PUSH_TEXTLAYOUTMODE) )
246*cdf0e10cSrcweir             {
247*cdf0e10cSrcweir                 aCalculatedNewState.textAlignment = rNewState.textAlignment;
248*cdf0e10cSrcweir                 aCalculatedNewState.textDirection = rNewState.textDirection;
249*cdf0e10cSrcweir             }
250*cdf0e10cSrcweir 
251*cdf0e10cSrcweir             // TODO(F2): Text language handling NYI
252*cdf0e10cSrcweir             // if( (aCalculatedNewState.pushFlags & PUSH_TEXTLANGUAGE) )
253*cdf0e10cSrcweir             // {
254*cdf0e10cSrcweir             // }
255*cdf0e10cSrcweir 
256*cdf0e10cSrcweir             // always copy push mode
257*cdf0e10cSrcweir             aCalculatedNewState.pushFlags = rNewState.pushFlags;
258*cdf0e10cSrcweir 
259*cdf0e10cSrcweir             // flush to stack
260*cdf0e10cSrcweir             getState( rStates ) = aCalculatedNewState;
261*cdf0e10cSrcweir         }
262*cdf0e10cSrcweir         else
263*cdf0e10cSrcweir         {
264*cdf0e10cSrcweir             rStates.pop_back();
265*cdf0e10cSrcweir         }
266*cdf0e10cSrcweir     }
267*cdf0e10cSrcweir 
268*cdf0e10cSrcweir     void setupStrokeAttributes( rendering::StrokeAttributes&                          o_rStrokeAttributes,
269*cdf0e10cSrcweir                                 const ::cppcanvas::internal::ActionFactoryParameters& rParms,
270*cdf0e10cSrcweir                                 const LineInfo&                                       rLineInfo 				)
271*cdf0e10cSrcweir     {
272*cdf0e10cSrcweir         const ::basegfx::B2DSize aWidth( rLineInfo.GetWidth(), 0 );
273*cdf0e10cSrcweir         o_rStrokeAttributes.StrokeWidth =
274*cdf0e10cSrcweir             (getState( rParms.mrStates ).mapModeTransform * aWidth).getX();
275*cdf0e10cSrcweir 
276*cdf0e10cSrcweir         // setup reasonable defaults
277*cdf0e10cSrcweir         o_rStrokeAttributes.MiterLimit 	 = 15.0; // 1.0 was no good default; GDI+'s limit is 10.0, our's is 15.0
278*cdf0e10cSrcweir         o_rStrokeAttributes.StartCapType = rendering::PathCapType::BUTT;
279*cdf0e10cSrcweir         o_rStrokeAttributes.EndCapType   = rendering::PathCapType::BUTT;
280*cdf0e10cSrcweir 
281*cdf0e10cSrcweir         switch(rLineInfo.GetLineJoin())
282*cdf0e10cSrcweir         {
283*cdf0e10cSrcweir             default: // B2DLINEJOIN_NONE, B2DLINEJOIN_MIDDLE
284*cdf0e10cSrcweir                 o_rStrokeAttributes.JoinType = rendering::PathJoinType::NONE;
285*cdf0e10cSrcweir                 break;
286*cdf0e10cSrcweir             case basegfx::B2DLINEJOIN_BEVEL:
287*cdf0e10cSrcweir                 o_rStrokeAttributes.JoinType = rendering::PathJoinType::BEVEL;
288*cdf0e10cSrcweir                 break;
289*cdf0e10cSrcweir             case basegfx::B2DLINEJOIN_MITER:
290*cdf0e10cSrcweir                 o_rStrokeAttributes.JoinType = rendering::PathJoinType::MITER;
291*cdf0e10cSrcweir                 break;
292*cdf0e10cSrcweir             case basegfx::B2DLINEJOIN_ROUND:
293*cdf0e10cSrcweir                 o_rStrokeAttributes.JoinType = rendering::PathJoinType::ROUND;
294*cdf0e10cSrcweir                 break;
295*cdf0e10cSrcweir         }
296*cdf0e10cSrcweir 
297*cdf0e10cSrcweir         if( LINE_DASH == rLineInfo.GetStyle() )
298*cdf0e10cSrcweir         {
299*cdf0e10cSrcweir             const ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) );
300*cdf0e10cSrcweir 
301*cdf0e10cSrcweir             // TODO(F1): Interpret OutDev::GetRefPoint() for the start of the dashing.
302*cdf0e10cSrcweir 
303*cdf0e10cSrcweir             // interpret dash info only if explicitely enabled as
304*cdf0e10cSrcweir             // style
305*cdf0e10cSrcweir             const ::basegfx::B2DSize aDistance( rLineInfo.GetDistance(), 0 );
306*cdf0e10cSrcweir             const double nDistance( (rState.mapModeTransform * aDistance).getX() );
307*cdf0e10cSrcweir 
308*cdf0e10cSrcweir             const ::basegfx::B2DSize aDashLen( rLineInfo.GetDashLen(), 0 );
309*cdf0e10cSrcweir             const double nDashLen( (rState.mapModeTransform * aDashLen).getX() );
310*cdf0e10cSrcweir 
311*cdf0e10cSrcweir             const ::basegfx::B2DSize aDotLen( rLineInfo.GetDotLen(), 0 );
312*cdf0e10cSrcweir             const double nDotLen( (rState.mapModeTransform * aDotLen).getX() );
313*cdf0e10cSrcweir 
314*cdf0e10cSrcweir             const sal_Int32 nNumArryEntries( 2*rLineInfo.GetDashCount() +
315*cdf0e10cSrcweir                                              2*rLineInfo.GetDotCount() );
316*cdf0e10cSrcweir 
317*cdf0e10cSrcweir             o_rStrokeAttributes.DashArray.realloc( nNumArryEntries );
318*cdf0e10cSrcweir             double* pDashArray = o_rStrokeAttributes.DashArray.getArray();
319*cdf0e10cSrcweir 
320*cdf0e10cSrcweir 
321*cdf0e10cSrcweir             // iteratively fill dash array, first with dashs, then
322*cdf0e10cSrcweir             // with dots.
323*cdf0e10cSrcweir             // ===================================================
324*cdf0e10cSrcweir 
325*cdf0e10cSrcweir             sal_Int32 nCurrEntry=0;
326*cdf0e10cSrcweir 
327*cdf0e10cSrcweir             for( sal_Int32 i=0; i<rLineInfo.GetDashCount(); ++i )
328*cdf0e10cSrcweir             {
329*cdf0e10cSrcweir                 pDashArray[nCurrEntry++] = nDashLen;
330*cdf0e10cSrcweir                 pDashArray[nCurrEntry++] = nDistance;
331*cdf0e10cSrcweir             }
332*cdf0e10cSrcweir             for( sal_Int32 i=0; i<rLineInfo.GetDotCount(); ++i )
333*cdf0e10cSrcweir             {
334*cdf0e10cSrcweir                 pDashArray[nCurrEntry++] = nDotLen;
335*cdf0e10cSrcweir                 pDashArray[nCurrEntry++] = nDistance;
336*cdf0e10cSrcweir             }
337*cdf0e10cSrcweir         }
338*cdf0e10cSrcweir     }
339*cdf0e10cSrcweir 
340*cdf0e10cSrcweir 
341*cdf0e10cSrcweir     /** Create masked BitmapEx, where the white areas of rBitmap are
342*cdf0e10cSrcweir         transparent, and the other appear in rMaskColor.
343*cdf0e10cSrcweir      */
344*cdf0e10cSrcweir     BitmapEx createMaskBmpEx( const Bitmap&  rBitmap,
345*cdf0e10cSrcweir                               const ::Color& rMaskColor )
346*cdf0e10cSrcweir     {
347*cdf0e10cSrcweir         const ::Color aWhite( COL_WHITE );
348*cdf0e10cSrcweir         BitmapPalette aBiLevelPalette(2);
349*cdf0e10cSrcweir         aBiLevelPalette[0] = aWhite;
350*cdf0e10cSrcweir         aBiLevelPalette[1] = rMaskColor;
351*cdf0e10cSrcweir 
352*cdf0e10cSrcweir         Bitmap aMask( rBitmap.CreateMask( aWhite ));
353*cdf0e10cSrcweir         Bitmap aSolid( rBitmap.GetSizePixel(),
354*cdf0e10cSrcweir                        1,
355*cdf0e10cSrcweir                        &aBiLevelPalette );
356*cdf0e10cSrcweir         aSolid.Erase( rMaskColor );
357*cdf0e10cSrcweir 
358*cdf0e10cSrcweir         return BitmapEx( aSolid, aMask );
359*cdf0e10cSrcweir     }
360*cdf0e10cSrcweir 
361*cdf0e10cSrcweir     /** Shameless rip from vcl/source/gdi/outdev3.cxx
362*cdf0e10cSrcweir 
363*cdf0e10cSrcweir         Should consolidate, into something like basetxt...
364*cdf0e10cSrcweir      */
365*cdf0e10cSrcweir     sal_Unicode getLocalizedChar( sal_Unicode nChar, LanguageType eLang )
366*cdf0e10cSrcweir     {
367*cdf0e10cSrcweir         // currently only conversion from ASCII digits is interesting
368*cdf0e10cSrcweir         if( (nChar < '0') || ('9' < nChar) )
369*cdf0e10cSrcweir             return nChar;
370*cdf0e10cSrcweir 
371*cdf0e10cSrcweir         sal_Unicode nOffset(0);
372*cdf0e10cSrcweir         // eLang & LANGUAGE_MASK_PRIMARY catches language independent of region.
373*cdf0e10cSrcweir         // CAVEAT! To some like Mongolian MS assigned the same primary language
374*cdf0e10cSrcweir         // although the script type is different!
375*cdf0e10cSrcweir         switch( eLang & LANGUAGE_MASK_PRIMARY )
376*cdf0e10cSrcweir         {
377*cdf0e10cSrcweir             default:
378*cdf0e10cSrcweir                 break;
379*cdf0e10cSrcweir 
380*cdf0e10cSrcweir             case LANGUAGE_ARABIC_SAUDI_ARABIA  & LANGUAGE_MASK_PRIMARY:
381*cdf0e10cSrcweir             case LANGUAGE_URDU          & LANGUAGE_MASK_PRIMARY:
382*cdf0e10cSrcweir             case LANGUAGE_PUNJABI       & LANGUAGE_MASK_PRIMARY: //???
383*cdf0e10cSrcweir                 nOffset = 0x0660 - '0';  // arabic/persian/urdu
384*cdf0e10cSrcweir                 break;
385*cdf0e10cSrcweir             case LANGUAGE_BENGALI       & LANGUAGE_MASK_PRIMARY:
386*cdf0e10cSrcweir                 nOffset = 0x09E6 - '0';  // bengali
387*cdf0e10cSrcweir                 break;
388*cdf0e10cSrcweir             case LANGUAGE_BURMESE       & LANGUAGE_MASK_PRIMARY:
389*cdf0e10cSrcweir                 nOffset = 0x1040 - '0';  // burmese
390*cdf0e10cSrcweir                 break;
391*cdf0e10cSrcweir             case LANGUAGE_HINDI         & LANGUAGE_MASK_PRIMARY:
392*cdf0e10cSrcweir                 nOffset = 0x0966 - '0';  // devanagari
393*cdf0e10cSrcweir                 break;
394*cdf0e10cSrcweir             case LANGUAGE_GUJARATI      & LANGUAGE_MASK_PRIMARY:
395*cdf0e10cSrcweir                 nOffset = 0x0AE6 - '0';  // gujarati
396*cdf0e10cSrcweir                 break;
397*cdf0e10cSrcweir             case LANGUAGE_KANNADA       & LANGUAGE_MASK_PRIMARY:
398*cdf0e10cSrcweir                 nOffset = 0x0CE6 - '0';  // kannada
399*cdf0e10cSrcweir                 break;
400*cdf0e10cSrcweir             case LANGUAGE_KHMER         & LANGUAGE_MASK_PRIMARY:
401*cdf0e10cSrcweir                 nOffset = 0x17E0 - '0';  // khmer
402*cdf0e10cSrcweir                 break;
403*cdf0e10cSrcweir             case LANGUAGE_LAO           & LANGUAGE_MASK_PRIMARY:
404*cdf0e10cSrcweir                 nOffset = 0x0ED0 - '0';  // lao
405*cdf0e10cSrcweir                 break;
406*cdf0e10cSrcweir             case LANGUAGE_MALAYALAM     & LANGUAGE_MASK_PRIMARY:
407*cdf0e10cSrcweir                 nOffset = 0x0D66 - '0';   // malayalam
408*cdf0e10cSrcweir                 break;
409*cdf0e10cSrcweir             case LANGUAGE_MONGOLIAN     & LANGUAGE_MASK_PRIMARY:
410*cdf0e10cSrcweir                 if (eLang == LANGUAGE_MONGOLIAN_MONGOLIAN)
411*cdf0e10cSrcweir                     nOffset = 0x1810 - '0';   // mongolian
412*cdf0e10cSrcweir                 else
413*cdf0e10cSrcweir                     nOffset = 0;              // mongolian cyrillic
414*cdf0e10cSrcweir                 break;
415*cdf0e10cSrcweir             case LANGUAGE_ORIYA         & LANGUAGE_MASK_PRIMARY:
416*cdf0e10cSrcweir                 nOffset = 0x0B66 - '0';   // oriya
417*cdf0e10cSrcweir                 break;
418*cdf0e10cSrcweir             case LANGUAGE_TAMIL         & LANGUAGE_MASK_PRIMARY:
419*cdf0e10cSrcweir                 nOffset = 0x0BE7 - '0';   // tamil
420*cdf0e10cSrcweir                 break;
421*cdf0e10cSrcweir             case LANGUAGE_TELUGU        & LANGUAGE_MASK_PRIMARY:
422*cdf0e10cSrcweir                 nOffset = 0x0C66 - '0';   // telugu
423*cdf0e10cSrcweir                 break;
424*cdf0e10cSrcweir             case LANGUAGE_THAI          & LANGUAGE_MASK_PRIMARY:
425*cdf0e10cSrcweir                 nOffset = 0x0E50 - '0';   // thai
426*cdf0e10cSrcweir                 break;
427*cdf0e10cSrcweir             case LANGUAGE_TIBETAN       & LANGUAGE_MASK_PRIMARY:
428*cdf0e10cSrcweir                 nOffset = 0x0F20 - '0';   // tibetan
429*cdf0e10cSrcweir                 break;
430*cdf0e10cSrcweir         }
431*cdf0e10cSrcweir 
432*cdf0e10cSrcweir         nChar = sal::static_int_cast<sal_Unicode>(nChar + nOffset);
433*cdf0e10cSrcweir         return nChar;
434*cdf0e10cSrcweir     }
435*cdf0e10cSrcweir 
436*cdf0e10cSrcweir     void convertToLocalizedNumerals( XubString&   rStr,
437*cdf0e10cSrcweir                                      LanguageType eTextLanguage )
438*cdf0e10cSrcweir     {
439*cdf0e10cSrcweir         const sal_Unicode* pBase = rStr.GetBuffer();
440*cdf0e10cSrcweir         const sal_Unicode* pBegin = pBase + 0;
441*cdf0e10cSrcweir         const xub_StrLen nEndIndex = rStr.Len();
442*cdf0e10cSrcweir         const sal_Unicode* pEnd = pBase + nEndIndex;
443*cdf0e10cSrcweir 
444*cdf0e10cSrcweir         for( ; pBegin < pEnd; ++pBegin )
445*cdf0e10cSrcweir         {
446*cdf0e10cSrcweir             // TODO: are there non-digit localizations?
447*cdf0e10cSrcweir             if( (*pBegin >= '0') && (*pBegin <= '9') )
448*cdf0e10cSrcweir             {
449*cdf0e10cSrcweir                 // translate characters to local preference
450*cdf0e10cSrcweir                 sal_Unicode cChar = getLocalizedChar( *pBegin, eTextLanguage );
451*cdf0e10cSrcweir                 if( cChar != *pBegin )
452*cdf0e10cSrcweir                     rStr.SetChar( sal::static_int_cast<sal_uInt16>(pBegin - pBase), cChar );
453*cdf0e10cSrcweir             }
454*cdf0e10cSrcweir         }
455*cdf0e10cSrcweir     }
456*cdf0e10cSrcweir }
457*cdf0e10cSrcweir 
458*cdf0e10cSrcweir 
459*cdf0e10cSrcweir namespace cppcanvas
460*cdf0e10cSrcweir {
461*cdf0e10cSrcweir     namespace internal
462*cdf0e10cSrcweir     {
463*cdf0e10cSrcweir         bool ImplRenderer::createFillAndStroke( const ::basegfx::B2DPolyPolygon& rPolyPoly,
464*cdf0e10cSrcweir                                                 const ActionFactoryParameters&   rParms )
465*cdf0e10cSrcweir         {
466*cdf0e10cSrcweir             const OutDevState& rState( getState( rParms.mrStates ) );
467*cdf0e10cSrcweir             if( (!rState.isLineColorSet &&
468*cdf0e10cSrcweir                  !rState.isFillColorSet) ||
469*cdf0e10cSrcweir                 (rState.lineColor.getLength() == 0 &&
470*cdf0e10cSrcweir                  rState.fillColor.getLength() == 0) )
471*cdf0e10cSrcweir             {
472*cdf0e10cSrcweir                 return false;
473*cdf0e10cSrcweir             }
474*cdf0e10cSrcweir 
475*cdf0e10cSrcweir             ActionSharedPtr pPolyAction(
476*cdf0e10cSrcweir                 internal::PolyPolyActionFactory::createPolyPolyAction(
477*cdf0e10cSrcweir                     rPolyPoly, rParms.mrCanvas, rState ) );
478*cdf0e10cSrcweir 
479*cdf0e10cSrcweir             if( pPolyAction )
480*cdf0e10cSrcweir             {
481*cdf0e10cSrcweir                 maActions.push_back(
482*cdf0e10cSrcweir                     MtfAction(
483*cdf0e10cSrcweir                         pPolyAction,
484*cdf0e10cSrcweir                         rParms.mrCurrActionIndex ) );
485*cdf0e10cSrcweir 
486*cdf0e10cSrcweir                 rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
487*cdf0e10cSrcweir             }
488*cdf0e10cSrcweir 
489*cdf0e10cSrcweir             return true;
490*cdf0e10cSrcweir         }
491*cdf0e10cSrcweir 
492*cdf0e10cSrcweir         bool ImplRenderer::createFillAndStroke( const ::basegfx::B2DPolygon&   rPoly,
493*cdf0e10cSrcweir                                                 const ActionFactoryParameters& rParms )
494*cdf0e10cSrcweir         {
495*cdf0e10cSrcweir             return createFillAndStroke( ::basegfx::B2DPolyPolygon( rPoly ),
496*cdf0e10cSrcweir                                         rParms );
497*cdf0e10cSrcweir         }
498*cdf0e10cSrcweir 
499*cdf0e10cSrcweir         void ImplRenderer::skipContent( GDIMetaFile& rMtf,
500*cdf0e10cSrcweir                                         const char*  pCommentString,
501*cdf0e10cSrcweir                                         sal_Int32& 	 io_rCurrActionIndex ) const
502*cdf0e10cSrcweir         {
503*cdf0e10cSrcweir             ENSURE_OR_THROW( pCommentString,
504*cdf0e10cSrcweir                               "ImplRenderer::skipContent(): NULL string given" );
505*cdf0e10cSrcweir 
506*cdf0e10cSrcweir             MetaAction* pCurrAct;
507*cdf0e10cSrcweir             while( (pCurrAct=rMtf.NextAction()) != NULL )
508*cdf0e10cSrcweir             {
509*cdf0e10cSrcweir                 // increment action index, we've skipped an action.
510*cdf0e10cSrcweir                 ++io_rCurrActionIndex;
511*cdf0e10cSrcweir 
512*cdf0e10cSrcweir                 if( pCurrAct->GetType() == META_COMMENT_ACTION &&
513*cdf0e10cSrcweir                     static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii(
514*cdf0e10cSrcweir                         pCommentString ) == COMPARE_EQUAL )
515*cdf0e10cSrcweir                 {
516*cdf0e10cSrcweir                     // requested comment found, done
517*cdf0e10cSrcweir                     return;
518*cdf0e10cSrcweir                 }
519*cdf0e10cSrcweir             }
520*cdf0e10cSrcweir 
521*cdf0e10cSrcweir             // EOF
522*cdf0e10cSrcweir             return;
523*cdf0e10cSrcweir         }
524*cdf0e10cSrcweir 
525*cdf0e10cSrcweir         bool ImplRenderer::isActionContained( GDIMetaFile& rMtf,
526*cdf0e10cSrcweir                                               const char*  pCommentString,
527*cdf0e10cSrcweir                                               sal_uInt16	   nType ) const
528*cdf0e10cSrcweir         {
529*cdf0e10cSrcweir             ENSURE_OR_THROW( pCommentString,
530*cdf0e10cSrcweir                               "ImplRenderer::isActionContained(): NULL string given" );
531*cdf0e10cSrcweir 
532*cdf0e10cSrcweir             bool bRet( false );
533*cdf0e10cSrcweir 
534*cdf0e10cSrcweir             // at least _one_ call to GDIMetaFile::NextAction() is
535*cdf0e10cSrcweir             // executed
536*cdf0e10cSrcweir             sal_uIntPtr nPos( 1 );
537*cdf0e10cSrcweir 
538*cdf0e10cSrcweir             MetaAction* pCurrAct;
539*cdf0e10cSrcweir             while( (pCurrAct=rMtf.NextAction()) != NULL )
540*cdf0e10cSrcweir             {
541*cdf0e10cSrcweir                 if( pCurrAct->GetType() == nType )
542*cdf0e10cSrcweir                 {
543*cdf0e10cSrcweir                     bRet = true; // action type found
544*cdf0e10cSrcweir                     break;
545*cdf0e10cSrcweir                 }
546*cdf0e10cSrcweir 
547*cdf0e10cSrcweir                 if( pCurrAct->GetType() == META_COMMENT_ACTION &&
548*cdf0e10cSrcweir                     static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii(
549*cdf0e10cSrcweir                         pCommentString ) == COMPARE_EQUAL )
550*cdf0e10cSrcweir                 {
551*cdf0e10cSrcweir                     // delimiting end comment found, done
552*cdf0e10cSrcweir                     bRet = false; // not yet found
553*cdf0e10cSrcweir                     break;
554*cdf0e10cSrcweir                 }
555*cdf0e10cSrcweir 
556*cdf0e10cSrcweir                 ++nPos;
557*cdf0e10cSrcweir             }
558*cdf0e10cSrcweir 
559*cdf0e10cSrcweir             // rewind metafile to previous position (this method must
560*cdf0e10cSrcweir             // not change the current metaaction)
561*cdf0e10cSrcweir             while( nPos-- )
562*cdf0e10cSrcweir                 rMtf.WindPrev();
563*cdf0e10cSrcweir 
564*cdf0e10cSrcweir             if( !pCurrAct )
565*cdf0e10cSrcweir             {
566*cdf0e10cSrcweir                 // EOF, and not yet found
567*cdf0e10cSrcweir                 bRet = false;
568*cdf0e10cSrcweir             }
569*cdf0e10cSrcweir 
570*cdf0e10cSrcweir             return bRet;
571*cdf0e10cSrcweir         }
572*cdf0e10cSrcweir 
573*cdf0e10cSrcweir         void ImplRenderer::createGradientAction( const ::PolyPolygon& 			rPoly,
574*cdf0e10cSrcweir                                                  const ::Gradient&				rGradient,
575*cdf0e10cSrcweir                                                  const ActionFactoryParameters& rParms,
576*cdf0e10cSrcweir                                                  bool							bIsPolygonRectangle,
577*cdf0e10cSrcweir                                                  bool 							bSubsettableActions )
578*cdf0e10cSrcweir         {
579*cdf0e10cSrcweir             DBG_TESTSOLARMUTEX();
580*cdf0e10cSrcweir 
581*cdf0e10cSrcweir             ::basegfx::B2DPolyPolygon aDevicePoly( rPoly.getB2DPolyPolygon() );
582*cdf0e10cSrcweir             aDevicePoly.transform( getState( rParms.mrStates ).mapModeTransform );
583*cdf0e10cSrcweir 
584*cdf0e10cSrcweir             // decide, whether this gradient can be rendered natively
585*cdf0e10cSrcweir             // by the canvas, or must be emulated via VCL gradient
586*cdf0e10cSrcweir             // action extraction.
587*cdf0e10cSrcweir             const sal_uInt16 nSteps( rGradient.GetSteps() );
588*cdf0e10cSrcweir 
589*cdf0e10cSrcweir             if( // step count is infinite, can use native canvas
590*cdf0e10cSrcweir                 // gradients here
591*cdf0e10cSrcweir                 nSteps == 0 ||
592*cdf0e10cSrcweir                 // step count is sufficiently high, such that no
593*cdf0e10cSrcweir                 // discernible difference should be visible.
594*cdf0e10cSrcweir                 nSteps > 64 )
595*cdf0e10cSrcweir             {
596*cdf0e10cSrcweir                 uno::Reference< lang::XMultiServiceFactory> xFactory(
597*cdf0e10cSrcweir                     rParms.mrCanvas->getUNOCanvas()->getDevice()->getParametricPolyPolygonFactory() );
598*cdf0e10cSrcweir 
599*cdf0e10cSrcweir                 if( xFactory.is() )
600*cdf0e10cSrcweir                 {
601*cdf0e10cSrcweir                     rendering::Texture aTexture;
602*cdf0e10cSrcweir 
603*cdf0e10cSrcweir                     aTexture.RepeatModeX = rendering::TexturingMode::CLAMP;
604*cdf0e10cSrcweir                     aTexture.RepeatModeY = rendering::TexturingMode::CLAMP;
605*cdf0e10cSrcweir                     aTexture.Alpha = 1.0;
606*cdf0e10cSrcweir 
607*cdf0e10cSrcweir 
608*cdf0e10cSrcweir                     // setup start/end color values
609*cdf0e10cSrcweir                     // ----------------------------
610*cdf0e10cSrcweir 
611*cdf0e10cSrcweir                     // scale color coefficients with gradient intensities
612*cdf0e10cSrcweir                     const sal_uInt16 nStartIntensity( rGradient.GetStartIntensity() );
613*cdf0e10cSrcweir                     ::Color aVCLStartColor( rGradient.GetStartColor() );
614*cdf0e10cSrcweir                     aVCLStartColor.SetRed( (sal_uInt8)(aVCLStartColor.GetRed() * nStartIntensity / 100) );
615*cdf0e10cSrcweir                     aVCLStartColor.SetGreen( (sal_uInt8)(aVCLStartColor.GetGreen() * nStartIntensity / 100) );
616*cdf0e10cSrcweir                     aVCLStartColor.SetBlue( (sal_uInt8)(aVCLStartColor.GetBlue() * nStartIntensity / 100) );
617*cdf0e10cSrcweir 
618*cdf0e10cSrcweir                     const sal_uInt16 nEndIntensity( rGradient.GetEndIntensity() );
619*cdf0e10cSrcweir                     ::Color aVCLEndColor( rGradient.GetEndColor() );
620*cdf0e10cSrcweir                     aVCLEndColor.SetRed( (sal_uInt8)(aVCLEndColor.GetRed() * nEndIntensity / 100) );
621*cdf0e10cSrcweir                     aVCLEndColor.SetGreen( (sal_uInt8)(aVCLEndColor.GetGreen() * nEndIntensity / 100) );
622*cdf0e10cSrcweir                     aVCLEndColor.SetBlue( (sal_uInt8)(aVCLEndColor.GetBlue() * nEndIntensity / 100) );
623*cdf0e10cSrcweir 
624*cdf0e10cSrcweir                     uno::Reference<rendering::XColorSpace> xColorSpace(
625*cdf0e10cSrcweir                         rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace());
626*cdf0e10cSrcweir                     const uno::Sequence< double > aStartColor(
627*cdf0e10cSrcweir                         ::vcl::unotools::colorToDoubleSequence( aVCLStartColor,
628*cdf0e10cSrcweir                                                                 xColorSpace ));
629*cdf0e10cSrcweir                     const uno::Sequence< double > aEndColor(
630*cdf0e10cSrcweir                         ::vcl::unotools::colorToDoubleSequence( aVCLEndColor,
631*cdf0e10cSrcweir                                                                 xColorSpace ));
632*cdf0e10cSrcweir 
633*cdf0e10cSrcweir                     uno::Sequence< uno::Sequence < double > > aColors(2);
634*cdf0e10cSrcweir                     uno::Sequence< double > aStops(2);
635*cdf0e10cSrcweir 
636*cdf0e10cSrcweir                     if( rGradient.GetStyle() == GRADIENT_AXIAL )
637*cdf0e10cSrcweir                     {
638*cdf0e10cSrcweir                         aStops.realloc(3);
639*cdf0e10cSrcweir                         aColors.realloc(3);
640*cdf0e10cSrcweir 
641*cdf0e10cSrcweir                         aStops[0] = 0.0;
642*cdf0e10cSrcweir                         aStops[1] = 0.5;
643*cdf0e10cSrcweir                         aStops[2] = 1.0;
644*cdf0e10cSrcweir 
645*cdf0e10cSrcweir                         aColors[0] = aEndColor;
646*cdf0e10cSrcweir                         aColors[1] = aStartColor;
647*cdf0e10cSrcweir                         aColors[2] = aEndColor;
648*cdf0e10cSrcweir                     }
649*cdf0e10cSrcweir                     else
650*cdf0e10cSrcweir                     {
651*cdf0e10cSrcweir                         aStops[0] = 0.0;
652*cdf0e10cSrcweir                         aStops[1] = 1.0;
653*cdf0e10cSrcweir 
654*cdf0e10cSrcweir                         aColors[0] = aStartColor;
655*cdf0e10cSrcweir                         aColors[1] = aEndColor;
656*cdf0e10cSrcweir                     }
657*cdf0e10cSrcweir 
658*cdf0e10cSrcweir                     const ::basegfx::B2DRectangle aBounds(
659*cdf0e10cSrcweir                         ::basegfx::tools::getRange(aDevicePoly) );
660*cdf0e10cSrcweir                     const ::basegfx::B2DVector aOffset(
661*cdf0e10cSrcweir                         rGradient.GetOfsX() / 100.0,
662*cdf0e10cSrcweir                         rGradient.GetOfsY() / 100.0);
663*cdf0e10cSrcweir                     double fRotation( rGradient.GetAngle() * M_PI / 1800.0 );
664*cdf0e10cSrcweir                     const double fBorder( rGradient.GetBorder() / 100.0 );
665*cdf0e10cSrcweir 
666*cdf0e10cSrcweir                     basegfx::B2DHomMatrix aRot90;
667*cdf0e10cSrcweir                     aRot90.rotate(M_PI_2);
668*cdf0e10cSrcweir 
669*cdf0e10cSrcweir                     basegfx::ODFGradientInfo aGradInfo;
670*cdf0e10cSrcweir                     rtl::OUString aGradientService;
671*cdf0e10cSrcweir                     switch( rGradient.GetStyle() )
672*cdf0e10cSrcweir                     {
673*cdf0e10cSrcweir                         case GRADIENT_LINEAR:
674*cdf0e10cSrcweir                             basegfx::tools::createLinearODFGradientInfo(aGradInfo,
675*cdf0e10cSrcweir                                                                         aBounds,
676*cdf0e10cSrcweir                                                                         nSteps,
677*cdf0e10cSrcweir                                                                         fBorder,
678*cdf0e10cSrcweir                                                                         fRotation);
679*cdf0e10cSrcweir                             // map odf to svg gradient orientation - x
680*cdf0e10cSrcweir                             // instead of y direction
681*cdf0e10cSrcweir                             aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aRot90;
682*cdf0e10cSrcweir                             aGradientService = rtl::OUString::createFromAscii("LinearGradient");
683*cdf0e10cSrcweir                             break;
684*cdf0e10cSrcweir 
685*cdf0e10cSrcweir                         case GRADIENT_AXIAL:
686*cdf0e10cSrcweir                         {
687*cdf0e10cSrcweir                             // Adapt the border so that it is suitable
688*cdf0e10cSrcweir                             // for the axial gradient.  An axial
689*cdf0e10cSrcweir                             // gradient consists of two linear
690*cdf0e10cSrcweir                             // gradients.  Each of those covers half
691*cdf0e10cSrcweir                             // of the total size.  In order to
692*cdf0e10cSrcweir                             // compensate for the condensed display of
693*cdf0e10cSrcweir                             // the linear gradients, we have to
694*cdf0e10cSrcweir                             // enlarge the area taken up by the actual
695*cdf0e10cSrcweir                             // gradient (1-fBorder).  After that we
696*cdf0e10cSrcweir                             // have to turn the result back into a
697*cdf0e10cSrcweir                             // border value, hence the second (left
698*cdf0e10cSrcweir                             // most 1-...
699*cdf0e10cSrcweir                             const double fAxialBorder (1-2*(1-fBorder));
700*cdf0e10cSrcweir                             basegfx::tools::createAxialODFGradientInfo(aGradInfo,
701*cdf0e10cSrcweir                                                                         aBounds,
702*cdf0e10cSrcweir                                                                         nSteps,
703*cdf0e10cSrcweir                                                                         fAxialBorder,
704*cdf0e10cSrcweir                                                                         fRotation);
705*cdf0e10cSrcweir                             // map odf to svg gradient orientation - x
706*cdf0e10cSrcweir                             // instead of y direction
707*cdf0e10cSrcweir                             aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aRot90;
708*cdf0e10cSrcweir 
709*cdf0e10cSrcweir                             // map odf axial gradient to 3-stop linear
710*cdf0e10cSrcweir                             // gradient - shift left by 0.5
711*cdf0e10cSrcweir                             basegfx::B2DHomMatrix aShift;
712*cdf0e10cSrcweir                             aShift.translate(-0.5,0);
713*cdf0e10cSrcweir                             aGradInfo.maTextureTransform = aGradInfo.maTextureTransform * aShift;
714*cdf0e10cSrcweir 
715*cdf0e10cSrcweir                             aGradientService = rtl::OUString::createFromAscii("LinearGradient");
716*cdf0e10cSrcweir                             break;
717*cdf0e10cSrcweir                         }
718*cdf0e10cSrcweir 
719*cdf0e10cSrcweir                         case GRADIENT_RADIAL:
720*cdf0e10cSrcweir                             basegfx::tools::createRadialODFGradientInfo(aGradInfo,
721*cdf0e10cSrcweir                                                                         aBounds,
722*cdf0e10cSrcweir                                                                         aOffset,
723*cdf0e10cSrcweir                                                                         nSteps,
724*cdf0e10cSrcweir                                                                         fBorder);
725*cdf0e10cSrcweir                             aGradientService = rtl::OUString::createFromAscii("EllipticalGradient");
726*cdf0e10cSrcweir                             break;
727*cdf0e10cSrcweir 
728*cdf0e10cSrcweir                         case GRADIENT_ELLIPTICAL:
729*cdf0e10cSrcweir                             basegfx::tools::createEllipticalODFGradientInfo(aGradInfo,
730*cdf0e10cSrcweir                                                                             aBounds,
731*cdf0e10cSrcweir                                                                             aOffset,
732*cdf0e10cSrcweir                                                                             nSteps,
733*cdf0e10cSrcweir                                                                             fBorder,
734*cdf0e10cSrcweir                                                                             fRotation);
735*cdf0e10cSrcweir                             aGradientService = rtl::OUString::createFromAscii("EllipticalGradient");
736*cdf0e10cSrcweir                             break;
737*cdf0e10cSrcweir 
738*cdf0e10cSrcweir                         case GRADIENT_SQUARE:
739*cdf0e10cSrcweir                             basegfx::tools::createSquareODFGradientInfo(aGradInfo,
740*cdf0e10cSrcweir                                                                         aBounds,
741*cdf0e10cSrcweir                                                                         aOffset,
742*cdf0e10cSrcweir                                                                         nSteps,
743*cdf0e10cSrcweir                                                                         fBorder,
744*cdf0e10cSrcweir                                                                         fRotation);
745*cdf0e10cSrcweir                             aGradientService = rtl::OUString::createFromAscii("RectangularGradient");
746*cdf0e10cSrcweir                             break;
747*cdf0e10cSrcweir 
748*cdf0e10cSrcweir                         case GRADIENT_RECT:
749*cdf0e10cSrcweir                             basegfx::tools::createRectangularODFGradientInfo(aGradInfo,
750*cdf0e10cSrcweir                                                                              aBounds,
751*cdf0e10cSrcweir                                                                              aOffset,
752*cdf0e10cSrcweir                                                                              nSteps,
753*cdf0e10cSrcweir                                                                              fBorder,
754*cdf0e10cSrcweir                                                                              fRotation);
755*cdf0e10cSrcweir                             aGradientService = rtl::OUString::createFromAscii("RectangularGradient");
756*cdf0e10cSrcweir                             break;
757*cdf0e10cSrcweir 
758*cdf0e10cSrcweir                         default:
759*cdf0e10cSrcweir                             ENSURE_OR_THROW( false,
760*cdf0e10cSrcweir                                              "ImplRenderer::createGradientAction(): Unexpected gradient type" );
761*cdf0e10cSrcweir                             break;
762*cdf0e10cSrcweir                     }
763*cdf0e10cSrcweir 
764*cdf0e10cSrcweir                     // As the texture coordinate space is relative to
765*cdf0e10cSrcweir                     // the polygon coordinate space (NOT to the
766*cdf0e10cSrcweir                     // polygon itself), move gradient to the start of
767*cdf0e10cSrcweir                     // the actual polygon. If we skip this, the
768*cdf0e10cSrcweir                     // gradient will always display at the origin, and
769*cdf0e10cSrcweir                     // not within the polygon bound (which might be
770*cdf0e10cSrcweir                     // miles away from the origin).
771*cdf0e10cSrcweir                     aGradInfo.maTextureTransform.translate( aBounds.getMinX(),
772*cdf0e10cSrcweir                                                             aBounds.getMinY() );
773*cdf0e10cSrcweir                     ::basegfx::unotools::affineMatrixFromHomMatrix( aTexture.AffineTransform,
774*cdf0e10cSrcweir                                                                     aGradInfo.maTextureTransform );
775*cdf0e10cSrcweir 
776*cdf0e10cSrcweir                     uno::Sequence<uno::Any> args(3);
777*cdf0e10cSrcweir                     beans::PropertyValue aProp;
778*cdf0e10cSrcweir                     aProp.Name = rtl::OUString::createFromAscii("Colors");
779*cdf0e10cSrcweir                     aProp.Value <<= aColors;
780*cdf0e10cSrcweir                     args[0] <<= aProp;
781*cdf0e10cSrcweir                     aProp.Name = rtl::OUString::createFromAscii("Stops");
782*cdf0e10cSrcweir                     aProp.Value <<= aStops;
783*cdf0e10cSrcweir                     args[1] <<= aProp;
784*cdf0e10cSrcweir                     aProp.Name = rtl::OUString::createFromAscii("AspectRatio");
785*cdf0e10cSrcweir                     aProp.Value <<= aGradInfo.mfAspectRatio;
786*cdf0e10cSrcweir                     args[2] <<= aProp;
787*cdf0e10cSrcweir 
788*cdf0e10cSrcweir                     aTexture.Gradient.set(
789*cdf0e10cSrcweir                         xFactory->createInstanceWithArguments(aGradientService,
790*cdf0e10cSrcweir                                                               args),
791*cdf0e10cSrcweir                         uno::UNO_QUERY);
792*cdf0e10cSrcweir                     if( aTexture.Gradient.is() )
793*cdf0e10cSrcweir                     {
794*cdf0e10cSrcweir                         ActionSharedPtr pPolyAction(
795*cdf0e10cSrcweir                             internal::PolyPolyActionFactory::createPolyPolyAction(
796*cdf0e10cSrcweir                                 aDevicePoly,
797*cdf0e10cSrcweir                                 rParms.mrCanvas,
798*cdf0e10cSrcweir                                 getState( rParms.mrStates ),
799*cdf0e10cSrcweir                                 aTexture ) );
800*cdf0e10cSrcweir 
801*cdf0e10cSrcweir                         if( pPolyAction )
802*cdf0e10cSrcweir                         {
803*cdf0e10cSrcweir                             maActions.push_back(
804*cdf0e10cSrcweir                                 MtfAction(
805*cdf0e10cSrcweir                                     pPolyAction,
806*cdf0e10cSrcweir                                     rParms.mrCurrActionIndex ) );
807*cdf0e10cSrcweir 
808*cdf0e10cSrcweir                             rParms.mrCurrActionIndex += pPolyAction->getActionCount()-1;
809*cdf0e10cSrcweir                         }
810*cdf0e10cSrcweir 
811*cdf0e10cSrcweir                         // done, using native gradients
812*cdf0e10cSrcweir                         return;
813*cdf0e10cSrcweir                     }
814*cdf0e10cSrcweir                 }
815*cdf0e10cSrcweir             }
816*cdf0e10cSrcweir 
817*cdf0e10cSrcweir             // cannot currently use native canvas gradients, as a
818*cdf0e10cSrcweir             // finite step size is given (this funny feature is not
819*cdf0e10cSrcweir             // supported by the XCanvas API)
820*cdf0e10cSrcweir             pushState( rParms.mrStates, PUSH_ALL );
821*cdf0e10cSrcweir 
822*cdf0e10cSrcweir             if( !bIsPolygonRectangle )
823*cdf0e10cSrcweir             {
824*cdf0e10cSrcweir                 // only clip, if given polygon is not a rectangle in
825*cdf0e10cSrcweir                 // the first place (the gradient is always limited to
826*cdf0e10cSrcweir                 // the given bound rect)
827*cdf0e10cSrcweir                 updateClipping(
828*cdf0e10cSrcweir                     aDevicePoly,
829*cdf0e10cSrcweir                     rParms,
830*cdf0e10cSrcweir                     true );
831*cdf0e10cSrcweir             }
832*cdf0e10cSrcweir 
833*cdf0e10cSrcweir             GDIMetaFile aTmpMtf;
834*cdf0e10cSrcweir             rParms.mrVDev.AddGradientActions( rPoly.GetBoundRect(),
835*cdf0e10cSrcweir                                               rGradient,
836*cdf0e10cSrcweir                                                aTmpMtf );
837*cdf0e10cSrcweir 
838*cdf0e10cSrcweir             createActions( aTmpMtf, rParms, bSubsettableActions );
839*cdf0e10cSrcweir 
840*cdf0e10cSrcweir             popState( rParms.mrStates );
841*cdf0e10cSrcweir         }
842*cdf0e10cSrcweir 
843*cdf0e10cSrcweir         uno::Reference< rendering::XCanvasFont > ImplRenderer::createFont( double&                        o_rFontRotation,
844*cdf0e10cSrcweir                                                                            const ::Font&                  rFont,
845*cdf0e10cSrcweir                                                                            const ActionFactoryParameters& rParms ) const
846*cdf0e10cSrcweir         {
847*cdf0e10cSrcweir             rendering::FontRequest aFontRequest;
848*cdf0e10cSrcweir 
849*cdf0e10cSrcweir             if( rParms.mrParms.maFontName.is_initialized() )
850*cdf0e10cSrcweir                 aFontRequest.FontDescription.FamilyName = *rParms.mrParms.maFontName;
851*cdf0e10cSrcweir             else
852*cdf0e10cSrcweir                 aFontRequest.FontDescription.FamilyName = rFont.GetName();
853*cdf0e10cSrcweir 
854*cdf0e10cSrcweir             aFontRequest.FontDescription.StyleName = rFont.GetStyleName();
855*cdf0e10cSrcweir 
856*cdf0e10cSrcweir             aFontRequest.FontDescription.IsSymbolFont = (rFont.GetCharSet() == RTL_TEXTENCODING_SYMBOL) ? util::TriState_YES : util::TriState_NO;
857*cdf0e10cSrcweir             aFontRequest.FontDescription.IsVertical = rFont.IsVertical() ? util::TriState_YES : util::TriState_NO;
858*cdf0e10cSrcweir 
859*cdf0e10cSrcweir             // TODO(F2): improve vclenum->panose conversion
860*cdf0e10cSrcweir             aFontRequest.FontDescription.FontDescription.Weight =
861*cdf0e10cSrcweir                 rParms.mrParms.maFontWeight.is_initialized() ?
862*cdf0e10cSrcweir                 *rParms.mrParms.maFontWeight :
863*cdf0e10cSrcweir                 ::canvas::tools::numeric_cast<sal_Int8>( ::basegfx::fround( rFont.GetWeight() ) );
864*cdf0e10cSrcweir             aFontRequest.FontDescription.FontDescription.Letterform =
865*cdf0e10cSrcweir                 rParms.mrParms.maFontLetterForm.is_initialized() ?
866*cdf0e10cSrcweir                 *rParms.mrParms.maFontLetterForm :
867*cdf0e10cSrcweir                 (rFont.GetItalic() == ITALIC_NONE) ? 0 : 9;
868*cdf0e10cSrcweir             aFontRequest.FontDescription.FontDescription.Proportion =
869*cdf0e10cSrcweir                 rParms.mrParms.maFontProportion.is_initialized() ?
870*cdf0e10cSrcweir                 *rParms.mrParms.maFontProportion :
871*cdf0e10cSrcweir                 (rFont.GetPitch() == PITCH_FIXED)
872*cdf0e10cSrcweir                     ? rendering::PanoseProportion::MONO_SPACED
873*cdf0e10cSrcweir                     : rendering::PanoseProportion::ANYTHING;
874*cdf0e10cSrcweir 
875*cdf0e10cSrcweir             LanguageType aLang = rFont.GetLanguage();
876*cdf0e10cSrcweir             aFontRequest.Locale = MsLangId::convertLanguageToLocale(aLang, false);
877*cdf0e10cSrcweir 
878*cdf0e10cSrcweir             // setup state-local text transformation,
879*cdf0e10cSrcweir             // if the font be rotated
880*cdf0e10cSrcweir             const short nFontAngle( rFont.GetOrientation() );
881*cdf0e10cSrcweir             if( nFontAngle != 0 )
882*cdf0e10cSrcweir             {
883*cdf0e10cSrcweir                 // set to unity transform rotated by font angle
884*cdf0e10cSrcweir                 const double nAngle( nFontAngle * (F_PI / 1800.0) );
885*cdf0e10cSrcweir                 o_rFontRotation = -nAngle;
886*cdf0e10cSrcweir             }
887*cdf0e10cSrcweir             else
888*cdf0e10cSrcweir             {
889*cdf0e10cSrcweir                 o_rFontRotation = 0.0;
890*cdf0e10cSrcweir             }
891*cdf0e10cSrcweir 
892*cdf0e10cSrcweir             geometry::Matrix2D aFontMatrix;
893*cdf0e10cSrcweir             ::canvas::tools::setIdentityMatrix2D( aFontMatrix );
894*cdf0e10cSrcweir 
895*cdf0e10cSrcweir             // TODO(F2): use correct scale direction, font
896*cdf0e10cSrcweir             // height might be width or anything else
897*cdf0e10cSrcweir 
898*cdf0e10cSrcweir             // TODO(Q3): This code smells of programming by
899*cdf0e10cSrcweir             // coincidence (the next two if statements)
900*cdf0e10cSrcweir             const ::Size rFontSizeLog( rFont.GetSize() );
901*cdf0e10cSrcweir             const sal_Int32 nFontWidthLog = rFontSizeLog.Width();
902*cdf0e10cSrcweir             if( nFontWidthLog != 0 )
903*cdf0e10cSrcweir             {
904*cdf0e10cSrcweir                 ::Font aTestFont = rFont;
905*cdf0e10cSrcweir                 aTestFont.SetWidth( 0 );
906*cdf0e10cSrcweir                 sal_Int32 nNormalWidth = rParms.mrVDev.GetFontMetric( aTestFont ).GetWidth();
907*cdf0e10cSrcweir                 if( nNormalWidth != nFontWidthLog )
908*cdf0e10cSrcweir                     if( nNormalWidth )
909*cdf0e10cSrcweir                         aFontMatrix.m00 = (double)nFontWidthLog / nNormalWidth;
910*cdf0e10cSrcweir             }
911*cdf0e10cSrcweir 
912*cdf0e10cSrcweir             // #i52608# apply map mode scale also to font matrix - an
913*cdf0e10cSrcweir             // anisotrophic mapmode must be reflected in an
914*cdf0e10cSrcweir             // anisotrophic font matrix scale.
915*cdf0e10cSrcweir             const OutDevState& rState( getState( rParms.mrStates ) );
916*cdf0e10cSrcweir             if( !::basegfx::fTools::equal(
917*cdf0e10cSrcweir                     rState.mapModeTransform.get(0,0),
918*cdf0e10cSrcweir                     rState.mapModeTransform.get(1,1)) )
919*cdf0e10cSrcweir             {
920*cdf0e10cSrcweir                 const double nScaleX( rState.mapModeTransform.get(0,0) );
921*cdf0e10cSrcweir                 const double nScaleY( rState.mapModeTransform.get(1,1) );
922*cdf0e10cSrcweir 
923*cdf0e10cSrcweir                 // note: no reason to check for division by zero, we
924*cdf0e10cSrcweir                 // always have the value closer (or equal) to zero as
925*cdf0e10cSrcweir                 // the nominator.
926*cdf0e10cSrcweir                 if( fabs(nScaleX) < fabs(nScaleY) )
927*cdf0e10cSrcweir                     aFontMatrix.m00 *= nScaleX / nScaleY;
928*cdf0e10cSrcweir                 else
929*cdf0e10cSrcweir                     aFontMatrix.m11 *= nScaleY / nScaleX;
930*cdf0e10cSrcweir             }
931*cdf0e10cSrcweir             aFontRequest.CellSize = (rState.mapModeTransform * ::vcl::unotools::b2DSizeFromSize(rFontSizeLog)).getY();
932*cdf0e10cSrcweir 
933*cdf0e10cSrcweir             return rParms.mrCanvas->getUNOCanvas()->createFont( aFontRequest,
934*cdf0e10cSrcweir                                                                 uno::Sequence< beans::PropertyValue >(),
935*cdf0e10cSrcweir                                                                 aFontMatrix );
936*cdf0e10cSrcweir         }
937*cdf0e10cSrcweir 
938*cdf0e10cSrcweir         // create text effects such as shadow/relief/embossed
939*cdf0e10cSrcweir         void ImplRenderer::createTextAction( const ::Point& 		        rStartPoint,
940*cdf0e10cSrcweir                                              const String                   rString,
941*cdf0e10cSrcweir                                              int                            nIndex,
942*cdf0e10cSrcweir                                              int                            nLength,
943*cdf0e10cSrcweir                                              const sal_Int32*               pCharWidths,
944*cdf0e10cSrcweir                                              const ActionFactoryParameters& rParms,
945*cdf0e10cSrcweir                                              bool                           bSubsettableActions )
946*cdf0e10cSrcweir         {
947*cdf0e10cSrcweir             ENSURE_OR_THROW( nIndex >= 0 && nLength <= rString.Len() + nIndex,
948*cdf0e10cSrcweir                               "ImplRenderer::createTextWithEffectsAction(): Invalid text index" );
949*cdf0e10cSrcweir 
950*cdf0e10cSrcweir             if( !nLength )
951*cdf0e10cSrcweir                 return; // zero-length text, no visible output
952*cdf0e10cSrcweir 
953*cdf0e10cSrcweir             const OutDevState& rState( getState( rParms.mrStates ) );
954*cdf0e10cSrcweir 
955*cdf0e10cSrcweir             // TODO(F2): implement all text effects
956*cdf0e10cSrcweir             // if( rState.textAlignment );             // TODO(F2): NYI
957*cdf0e10cSrcweir 
958*cdf0e10cSrcweir             ::Color aShadowColor( COL_AUTO );
959*cdf0e10cSrcweir             ::Color aReliefColor( COL_AUTO );
960*cdf0e10cSrcweir             ::Size  aShadowOffset;
961*cdf0e10cSrcweir             ::Size  aReliefOffset;
962*cdf0e10cSrcweir 
963*cdf0e10cSrcweir             uno::Reference<rendering::XColorSpace> xColorSpace(
964*cdf0e10cSrcweir                 rParms.mrCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
965*cdf0e10cSrcweir 
966*cdf0e10cSrcweir             if( rState.isTextEffectShadowSet )
967*cdf0e10cSrcweir             {
968*cdf0e10cSrcweir                 // calculate shadow offset (similar to outdev3.cxx)
969*cdf0e10cSrcweir                 // TODO(F3): better match with outdev3.cxx
970*cdf0e10cSrcweir                 sal_Int32 nShadowOffset = static_cast<sal_Int32>(1.5 + ((rParms.mrVDev.GetFont().GetHeight()-24.0)/24.0));
971*cdf0e10cSrcweir                 if( nShadowOffset < 1 )
972*cdf0e10cSrcweir                     nShadowOffset = 1;
973*cdf0e10cSrcweir 
974*cdf0e10cSrcweir                 aShadowOffset.setWidth( nShadowOffset );
975*cdf0e10cSrcweir                 aShadowOffset.setHeight( nShadowOffset );
976*cdf0e10cSrcweir 
977*cdf0e10cSrcweir                 // determine shadow color (from outdev3.cxx)
978*cdf0e10cSrcweir                 ::Color aTextColor = ::vcl::unotools::doubleSequenceToColor(
979*cdf0e10cSrcweir                     rState.textColor, xColorSpace );
980*cdf0e10cSrcweir                 bool bIsDark = (aTextColor.GetColor() == COL_BLACK)
981*cdf0e10cSrcweir                     || (aTextColor.GetLuminance() < 8);
982*cdf0e10cSrcweir 
983*cdf0e10cSrcweir                 aShadowColor = bIsDark ? COL_LIGHTGRAY : COL_BLACK;
984*cdf0e10cSrcweir                 aShadowColor.SetTransparency( aTextColor.GetTransparency() );
985*cdf0e10cSrcweir             }
986*cdf0e10cSrcweir 
987*cdf0e10cSrcweir             if( rState.textReliefStyle )
988*cdf0e10cSrcweir             {
989*cdf0e10cSrcweir                 // calculate relief offset (similar to outdev3.cxx)
990*cdf0e10cSrcweir                 sal_Int32 nReliefOffset = rParms.mrVDev.PixelToLogic( Size( 1, 1 ) ).Height();
991*cdf0e10cSrcweir                 nReliefOffset += nReliefOffset/2;
992*cdf0e10cSrcweir                 if( nReliefOffset < 1 )
993*cdf0e10cSrcweir                     nReliefOffset = 1;
994*cdf0e10cSrcweir 
995*cdf0e10cSrcweir                 if( rState.textReliefStyle == RELIEF_ENGRAVED )
996*cdf0e10cSrcweir                     nReliefOffset = -nReliefOffset;
997*cdf0e10cSrcweir 
998*cdf0e10cSrcweir                 aReliefOffset.setWidth( nReliefOffset );
999*cdf0e10cSrcweir                 aReliefOffset.setHeight( nReliefOffset );
1000*cdf0e10cSrcweir 
1001*cdf0e10cSrcweir                 // determine relief color (from outdev3.cxx)
1002*cdf0e10cSrcweir                 ::Color aTextColor = ::vcl::unotools::doubleSequenceToColor(
1003*cdf0e10cSrcweir                     rState.textColor, xColorSpace );
1004*cdf0e10cSrcweir 
1005*cdf0e10cSrcweir                 aReliefColor = ::Color( COL_LIGHTGRAY );
1006*cdf0e10cSrcweir 
1007*cdf0e10cSrcweir                 // we don't have a automatic color, so black is always
1008*cdf0e10cSrcweir                 // drawn on white (literally copied from
1009*cdf0e10cSrcweir                 // vcl/source/gdi/outdev3.cxx)
1010*cdf0e10cSrcweir                 if( aTextColor.GetColor() == COL_BLACK )
1011*cdf0e10cSrcweir                 {
1012*cdf0e10cSrcweir                     aTextColor = ::Color( COL_WHITE );
1013*cdf0e10cSrcweir                     getState( rParms.mrStates ).textColor =
1014*cdf0e10cSrcweir                         ::vcl::unotools::colorToDoubleSequence(
1015*cdf0e10cSrcweir                             aTextColor, xColorSpace );
1016*cdf0e10cSrcweir                 }
1017*cdf0e10cSrcweir 
1018*cdf0e10cSrcweir                 if( aTextColor.GetColor() == COL_WHITE )
1019*cdf0e10cSrcweir                     aReliefColor = ::Color( COL_BLACK );
1020*cdf0e10cSrcweir                 aReliefColor.SetTransparency( aTextColor.GetTransparency() );
1021*cdf0e10cSrcweir             }
1022*cdf0e10cSrcweir 
1023*cdf0e10cSrcweir             // create the actual text action
1024*cdf0e10cSrcweir             ActionSharedPtr pTextAction(
1025*cdf0e10cSrcweir                 TextActionFactory::createTextAction(
1026*cdf0e10cSrcweir                     rStartPoint,
1027*cdf0e10cSrcweir                     aReliefOffset,
1028*cdf0e10cSrcweir                     aReliefColor,
1029*cdf0e10cSrcweir                     aShadowOffset,
1030*cdf0e10cSrcweir                     aShadowColor,
1031*cdf0e10cSrcweir                     rString,
1032*cdf0e10cSrcweir                     nIndex,
1033*cdf0e10cSrcweir                     nLength,
1034*cdf0e10cSrcweir                     pCharWidths,
1035*cdf0e10cSrcweir                     rParms.mrVDev,
1036*cdf0e10cSrcweir                     rParms.mrCanvas,
1037*cdf0e10cSrcweir                     rState,
1038*cdf0e10cSrcweir                     rParms.mrParms,
1039*cdf0e10cSrcweir                     bSubsettableActions ) );
1040*cdf0e10cSrcweir 
1041*cdf0e10cSrcweir             ActionSharedPtr pStrikeoutTextAction;
1042*cdf0e10cSrcweir 
1043*cdf0e10cSrcweir             if ( rState.textStrikeoutStyle == STRIKEOUT_X || rState.textStrikeoutStyle == STRIKEOUT_SLASH )
1044*cdf0e10cSrcweir             {
1045*cdf0e10cSrcweir                 long nWidth = rParms.mrVDev.GetTextWidth( rString,nIndex,nLength );
1046*cdf0e10cSrcweir 
1047*cdf0e10cSrcweir                 xub_Unicode pChars[5];
1048*cdf0e10cSrcweir                 if ( rState.textStrikeoutStyle == STRIKEOUT_X )
1049*cdf0e10cSrcweir                     pChars[0] = 'X';
1050*cdf0e10cSrcweir                 else
1051*cdf0e10cSrcweir                     pChars[0] = '/';
1052*cdf0e10cSrcweir                 pChars[3]=pChars[2]=pChars[1]=pChars[0];
1053*cdf0e10cSrcweir 
1054*cdf0e10cSrcweir                 long nStrikeoutWidth = nWidth;
1055*cdf0e10cSrcweir                 String aStrikeoutTest( pChars, 4 );
1056*cdf0e10cSrcweir 
1057*cdf0e10cSrcweir                 if( aStrikeoutTest.Len() )
1058*cdf0e10cSrcweir                 {
1059*cdf0e10cSrcweir                     nStrikeoutWidth = ( rParms.mrVDev.GetTextWidth( aStrikeoutTest ) + 2 ) / 4;
1060*cdf0e10cSrcweir                     aStrikeoutTest.Erase();
1061*cdf0e10cSrcweir 
1062*cdf0e10cSrcweir                     if( nStrikeoutWidth <= 0 )
1063*cdf0e10cSrcweir                         nStrikeoutWidth = 1;
1064*cdf0e10cSrcweir                 }
1065*cdf0e10cSrcweir 
1066*cdf0e10cSrcweir                 long nMaxWidth = nStrikeoutWidth/2;
1067*cdf0e10cSrcweir                 if ( nMaxWidth < 2 )
1068*cdf0e10cSrcweir                     nMaxWidth = 2;
1069*cdf0e10cSrcweir                 nMaxWidth += nWidth + 1;
1070*cdf0e10cSrcweir 
1071*cdf0e10cSrcweir                 long nFullStrikeoutWidth = 0;
1072*cdf0e10cSrcweir                 String aStrikeoutText( pChars, 0 );
1073*cdf0e10cSrcweir                 while( (nFullStrikeoutWidth+=nStrikeoutWidth ) < nMaxWidth+1 )
1074*cdf0e10cSrcweir                     aStrikeoutText += pChars[0];
1075*cdf0e10cSrcweir 
1076*cdf0e10cSrcweir 
1077*cdf0e10cSrcweir                 sal_Int32 nStartPos = 0;
1078*cdf0e10cSrcweir                 xub_StrLen nLen = aStrikeoutText.Len();
1079*cdf0e10cSrcweir 
1080*cdf0e10cSrcweir                 if( nLen )
1081*cdf0e10cSrcweir                 {
1082*cdf0e10cSrcweir                     long nInterval = ( nWidth - nStrikeoutWidth * nLen ) / nLen;
1083*cdf0e10cSrcweir                     nStrikeoutWidth += nInterval;
1084*cdf0e10cSrcweir                     sal_Int32* pStrikeoutCharWidths = new sal_Int32[nLen];
1085*cdf0e10cSrcweir 
1086*cdf0e10cSrcweir                     for ( int i = 0;i<nLen; i++)
1087*cdf0e10cSrcweir                     {
1088*cdf0e10cSrcweir                         pStrikeoutCharWidths[i] = nStrikeoutWidth;
1089*cdf0e10cSrcweir                     }
1090*cdf0e10cSrcweir 
1091*cdf0e10cSrcweir                     for ( int i = 1;i< nLen; i++ )
1092*cdf0e10cSrcweir                     {
1093*cdf0e10cSrcweir                         pStrikeoutCharWidths[ i ] += pStrikeoutCharWidths[ i-1 ];
1094*cdf0e10cSrcweir                     }
1095*cdf0e10cSrcweir 
1096*cdf0e10cSrcweir                     pStrikeoutTextAction =
1097*cdf0e10cSrcweir                         TextActionFactory::createTextAction(
1098*cdf0e10cSrcweir                             rStartPoint,
1099*cdf0e10cSrcweir                             aReliefOffset,
1100*cdf0e10cSrcweir                             aReliefColor,
1101*cdf0e10cSrcweir                             aShadowOffset,
1102*cdf0e10cSrcweir                             aShadowColor,
1103*cdf0e10cSrcweir                             aStrikeoutText,
1104*cdf0e10cSrcweir                             nStartPos,
1105*cdf0e10cSrcweir                             aStrikeoutText.Len(),
1106*cdf0e10cSrcweir                             pStrikeoutCharWidths,
1107*cdf0e10cSrcweir                             rParms.mrVDev,
1108*cdf0e10cSrcweir                             rParms.mrCanvas,
1109*cdf0e10cSrcweir                             rState,
1110*cdf0e10cSrcweir                             rParms.mrParms,
1111*cdf0e10cSrcweir                             bSubsettableActions ) ;
1112*cdf0e10cSrcweir                 }
1113*cdf0e10cSrcweir             }
1114*cdf0e10cSrcweir 
1115*cdf0e10cSrcweir             if( pTextAction )
1116*cdf0e10cSrcweir             {
1117*cdf0e10cSrcweir                 maActions.push_back(
1118*cdf0e10cSrcweir                     MtfAction(
1119*cdf0e10cSrcweir                         pTextAction,
1120*cdf0e10cSrcweir                         rParms.mrCurrActionIndex ) );
1121*cdf0e10cSrcweir 
1122*cdf0e10cSrcweir                 if ( pStrikeoutTextAction )
1123*cdf0e10cSrcweir                 {
1124*cdf0e10cSrcweir                     maActions.push_back(
1125*cdf0e10cSrcweir                         MtfAction(
1126*cdf0e10cSrcweir                         pStrikeoutTextAction,
1127*cdf0e10cSrcweir                         rParms.mrCurrActionIndex ) );
1128*cdf0e10cSrcweir                 }
1129*cdf0e10cSrcweir 
1130*cdf0e10cSrcweir                 rParms.mrCurrActionIndex += pTextAction->getActionCount()-1;
1131*cdf0e10cSrcweir             }
1132*cdf0e10cSrcweir 		}
1133*cdf0e10cSrcweir 
1134*cdf0e10cSrcweir         void ImplRenderer::updateClipping( const ::basegfx::B2DPolyPolygon&	rClipPoly,
1135*cdf0e10cSrcweir                                            const ActionFactoryParameters&   rParms,
1136*cdf0e10cSrcweir                                            bool								bIntersect )
1137*cdf0e10cSrcweir         {
1138*cdf0e10cSrcweir             ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) );
1139*cdf0e10cSrcweir             ::basegfx::B2DPolyPolygon aClipPoly( rClipPoly );
1140*cdf0e10cSrcweir 
1141*cdf0e10cSrcweir             const bool bEmptyClipRect( rState.clipRect.IsEmpty() );
1142*cdf0e10cSrcweir             const bool bEmptyClipPoly( rState.clip.count() == 0 );
1143*cdf0e10cSrcweir 
1144*cdf0e10cSrcweir             ENSURE_OR_THROW( bEmptyClipPoly || bEmptyClipRect,
1145*cdf0e10cSrcweir                               "ImplRenderer::updateClipping(): Clip rect and polygon are both set!" );
1146*cdf0e10cSrcweir 
1147*cdf0e10cSrcweir             if( !bIntersect ||
1148*cdf0e10cSrcweir                 (bEmptyClipRect && bEmptyClipPoly) )
1149*cdf0e10cSrcweir             {
1150*cdf0e10cSrcweir                 rState.clip = rClipPoly;
1151*cdf0e10cSrcweir             }
1152*cdf0e10cSrcweir             else
1153*cdf0e10cSrcweir             {
1154*cdf0e10cSrcweir                 if( !bEmptyClipRect )
1155*cdf0e10cSrcweir                 {
1156*cdf0e10cSrcweir                     // TODO(P3): Use Liang-Barsky polygon clip here,
1157*cdf0e10cSrcweir                     // after all, one object is just a rectangle!
1158*cdf0e10cSrcweir 
1159*cdf0e10cSrcweir                     // convert rect to polygon beforehand, must revert
1160*cdf0e10cSrcweir                     // to general polygon clipping here.
1161*cdf0e10cSrcweir                     rState.clip = ::basegfx::B2DPolyPolygon(
1162*cdf0e10cSrcweir                         ::basegfx::tools::createPolygonFromRect(
1163*cdf0e10cSrcweir                             // #121100# VCL rectangular clips always
1164*cdf0e10cSrcweir                             // include one more pixel to the right
1165*cdf0e10cSrcweir                             // and the bottom
1166*cdf0e10cSrcweir                             ::basegfx::B2DRectangle( rState.clipRect.Left(),
1167*cdf0e10cSrcweir                                                      rState.clipRect.Top(),
1168*cdf0e10cSrcweir                                                      rState.clipRect.Right()+1,
1169*cdf0e10cSrcweir                                                      rState.clipRect.Bottom()+1 ) ) );
1170*cdf0e10cSrcweir                 }
1171*cdf0e10cSrcweir 
1172*cdf0e10cSrcweir                 // AW: Simplified
1173*cdf0e10cSrcweir 				rState.clip = basegfx::tools::clipPolyPolygonOnPolyPolygon(
1174*cdf0e10cSrcweir 					aClipPoly, rState.clip, true, false);
1175*cdf0e10cSrcweir             }
1176*cdf0e10cSrcweir 
1177*cdf0e10cSrcweir             // by now, our clip resides in the OutDevState::clip
1178*cdf0e10cSrcweir             // poly-polygon.
1179*cdf0e10cSrcweir             rState.clipRect.SetEmpty();
1180*cdf0e10cSrcweir 
1181*cdf0e10cSrcweir             if( rState.clip.count() == 0 )
1182*cdf0e10cSrcweir             {
1183*cdf0e10cSrcweir                 if( rState.clipRect.IsEmpty() )
1184*cdf0e10cSrcweir                 {
1185*cdf0e10cSrcweir                     rState.xClipPoly.clear();
1186*cdf0e10cSrcweir                 }
1187*cdf0e10cSrcweir                 else
1188*cdf0e10cSrcweir                 {
1189*cdf0e10cSrcweir                     rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1190*cdf0e10cSrcweir                         rParms.mrCanvas->getUNOCanvas()->getDevice(),
1191*cdf0e10cSrcweir                         ::basegfx::B2DPolyPolygon(
1192*cdf0e10cSrcweir                             ::basegfx::tools::createPolygonFromRect(
1193*cdf0e10cSrcweir                                 // #121100# VCL rectangular clips
1194*cdf0e10cSrcweir                                 // always include one more pixel to
1195*cdf0e10cSrcweir                                 // the right and the bottom
1196*cdf0e10cSrcweir                                 ::basegfx::B2DRectangle( rState.clipRect.Left(),
1197*cdf0e10cSrcweir                                                          rState.clipRect.Top(),
1198*cdf0e10cSrcweir                                                          rState.clipRect.Right()+1,
1199*cdf0e10cSrcweir                                                          rState.clipRect.Bottom()+1 ) ) ) );
1200*cdf0e10cSrcweir                 }
1201*cdf0e10cSrcweir             }
1202*cdf0e10cSrcweir             else
1203*cdf0e10cSrcweir             {
1204*cdf0e10cSrcweir                 rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1205*cdf0e10cSrcweir                     rParms.mrCanvas->getUNOCanvas()->getDevice(),
1206*cdf0e10cSrcweir                     rState.clip );
1207*cdf0e10cSrcweir             }
1208*cdf0e10cSrcweir         }
1209*cdf0e10cSrcweir 
1210*cdf0e10cSrcweir         void ImplRenderer::updateClipping( const ::Rectangle&		      rClipRect,
1211*cdf0e10cSrcweir                                            const ActionFactoryParameters& rParms,
1212*cdf0e10cSrcweir                                            bool                           bIntersect )
1213*cdf0e10cSrcweir         {
1214*cdf0e10cSrcweir             ::cppcanvas::internal::OutDevState& rState( getState( rParms.mrStates ) );
1215*cdf0e10cSrcweir 
1216*cdf0e10cSrcweir             const bool bEmptyClipRect( rState.clipRect.IsEmpty() );
1217*cdf0e10cSrcweir             const bool bEmptyClipPoly( rState.clip.count() == 0 );
1218*cdf0e10cSrcweir 
1219*cdf0e10cSrcweir             ENSURE_OR_THROW( bEmptyClipPoly || bEmptyClipRect,
1220*cdf0e10cSrcweir                               "ImplRenderer::updateClipping(): Clip rect and polygon are both set!" );
1221*cdf0e10cSrcweir 
1222*cdf0e10cSrcweir             if( !bIntersect ||
1223*cdf0e10cSrcweir                 (bEmptyClipRect && bEmptyClipPoly) )
1224*cdf0e10cSrcweir             {
1225*cdf0e10cSrcweir                 rState.clipRect = rClipRect;
1226*cdf0e10cSrcweir                 rState.clip.clear();
1227*cdf0e10cSrcweir             }
1228*cdf0e10cSrcweir             else if( bEmptyClipPoly )
1229*cdf0e10cSrcweir             {
1230*cdf0e10cSrcweir                 rState.clipRect.Intersection( rClipRect );
1231*cdf0e10cSrcweir                 rState.clip.clear();
1232*cdf0e10cSrcweir             }
1233*cdf0e10cSrcweir             else
1234*cdf0e10cSrcweir             {
1235*cdf0e10cSrcweir                 // TODO(P3): Handle a fourth case here, when all clip
1236*cdf0e10cSrcweir                 // polygons are rectangular, once B2DMultiRange's
1237*cdf0e10cSrcweir                 // sweep line implementation is done.
1238*cdf0e10cSrcweir 
1239*cdf0e10cSrcweir                 // general case: convert to polygon and clip
1240*cdf0e10cSrcweir                 // -----------------------------------------
1241*cdf0e10cSrcweir 
1242*cdf0e10cSrcweir                 // convert rect to polygon beforehand, must revert
1243*cdf0e10cSrcweir                 // to general polygon clipping here.
1244*cdf0e10cSrcweir                 ::basegfx::B2DPolyPolygon aClipPoly(
1245*cdf0e10cSrcweir                     ::basegfx::tools::createPolygonFromRect(
1246*cdf0e10cSrcweir                         ::basegfx::B2DRectangle( rClipRect.Left(),
1247*cdf0e10cSrcweir                                                  rClipRect.Top(),
1248*cdf0e10cSrcweir                                                  rClipRect.Right(),
1249*cdf0e10cSrcweir                                                  rClipRect.Bottom() ) ) );
1250*cdf0e10cSrcweir 
1251*cdf0e10cSrcweir                 rState.clipRect.SetEmpty();
1252*cdf0e10cSrcweir 
1253*cdf0e10cSrcweir                 // AW: Simplified
1254*cdf0e10cSrcweir 				rState.clip = basegfx::tools::clipPolyPolygonOnPolyPolygon(
1255*cdf0e10cSrcweir 					aClipPoly, rState.clip, true, false);
1256*cdf0e10cSrcweir             }
1257*cdf0e10cSrcweir 
1258*cdf0e10cSrcweir             if( rState.clip.count() == 0 )
1259*cdf0e10cSrcweir             {
1260*cdf0e10cSrcweir                 if( rState.clipRect.IsEmpty() )
1261*cdf0e10cSrcweir                 {
1262*cdf0e10cSrcweir                     rState.xClipPoly.clear();
1263*cdf0e10cSrcweir                 }
1264*cdf0e10cSrcweir                 else
1265*cdf0e10cSrcweir                 {
1266*cdf0e10cSrcweir                     rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1267*cdf0e10cSrcweir                         rParms.mrCanvas->getUNOCanvas()->getDevice(),
1268*cdf0e10cSrcweir                         ::basegfx::B2DPolyPolygon(
1269*cdf0e10cSrcweir                             ::basegfx::tools::createPolygonFromRect(
1270*cdf0e10cSrcweir                                 // #121100# VCL rectangular clips
1271*cdf0e10cSrcweir                                 // always include one more pixel to
1272*cdf0e10cSrcweir                                 // the right and the bottom
1273*cdf0e10cSrcweir                                 ::basegfx::B2DRectangle( rState.clipRect.Left(),
1274*cdf0e10cSrcweir                                                          rState.clipRect.Top(),
1275*cdf0e10cSrcweir                                                          rState.clipRect.Right()+1,
1276*cdf0e10cSrcweir                                                          rState.clipRect.Bottom()+1 ) ) ) );
1277*cdf0e10cSrcweir                 }
1278*cdf0e10cSrcweir             }
1279*cdf0e10cSrcweir             else
1280*cdf0e10cSrcweir             {
1281*cdf0e10cSrcweir                 rState.xClipPoly = ::basegfx::unotools::xPolyPolygonFromB2DPolyPolygon(
1282*cdf0e10cSrcweir                     rParms.mrCanvas->getUNOCanvas()->getDevice(),
1283*cdf0e10cSrcweir                     rState.clip );
1284*cdf0e10cSrcweir             }
1285*cdf0e10cSrcweir         }
1286*cdf0e10cSrcweir 
1287*cdf0e10cSrcweir         bool ImplRenderer::createActions( GDIMetaFile&				     rMtf,
1288*cdf0e10cSrcweir                                           const ActionFactoryParameters& rFactoryParms,
1289*cdf0e10cSrcweir                                           bool                           bSubsettableActions )
1290*cdf0e10cSrcweir         {
1291*cdf0e10cSrcweir             /* TODO(P2): interpret mtf-comments
1292*cdf0e10cSrcweir                ================================
1293*cdf0e10cSrcweir 
1294*cdf0e10cSrcweir                - gradient fillings (do that via comments)
1295*cdf0e10cSrcweir 
1296*cdf0e10cSrcweir                - think about mapping. _If_ we do everything in logical
1297*cdf0e10cSrcweir                	 coordinates (which would solve the probs for stroke
1298*cdf0e10cSrcweir                  widths and text offsets), then we would have to
1299*cdf0e10cSrcweir                  recalc scaling for every drawing operation. This is
1300*cdf0e10cSrcweir                  because the outdev map mode might change at any time.
1301*cdf0e10cSrcweir                  Also keep in mind, that, although we've double precision
1302*cdf0e10cSrcweir                  float arithmetic now, different offsets might still
1303*cdf0e10cSrcweir                  generate different roundings (aka
1304*cdf0e10cSrcweir                  'OutputDevice::SetPixelOffset())
1305*cdf0e10cSrcweir 
1306*cdf0e10cSrcweir              */
1307*cdf0e10cSrcweir 
1308*cdf0e10cSrcweir             // alias common parameters
1309*cdf0e10cSrcweir             VectorOfOutDevStates&  rStates(rFactoryParms.mrStates);
1310*cdf0e10cSrcweir             const CanvasSharedPtr& rCanvas(rFactoryParms.mrCanvas);
1311*cdf0e10cSrcweir             ::VirtualDevice&       rVDev(rFactoryParms.mrVDev);
1312*cdf0e10cSrcweir             const Parameters&      rParms(rFactoryParms.mrParms);
1313*cdf0e10cSrcweir             sal_Int32&             io_rCurrActionIndex(rFactoryParms.mrCurrActionIndex);
1314*cdf0e10cSrcweir 
1315*cdf0e10cSrcweir 
1316*cdf0e10cSrcweir             // Loop over every metaaction
1317*cdf0e10cSrcweir             // ==========================
1318*cdf0e10cSrcweir             MetaAction* pCurrAct;
1319*cdf0e10cSrcweir 
1320*cdf0e10cSrcweir             // TODO(P1): think about caching
1321*cdf0e10cSrcweir             for( pCurrAct=rMtf.FirstAction();
1322*cdf0e10cSrcweir                  pCurrAct;
1323*cdf0e10cSrcweir                  pCurrAct = rMtf.NextAction() )
1324*cdf0e10cSrcweir             {
1325*cdf0e10cSrcweir                 // execute every action, to keep VDev state up-to-date
1326*cdf0e10cSrcweir                 // currently used only for
1327*cdf0e10cSrcweir                 // - the map mode
1328*cdf0e10cSrcweir                 // - the line/fill color when processing a META_TRANSPARENT_ACTION
1329*cdf0e10cSrcweir                 // - SetFont to process font metric specific actions
1330*cdf0e10cSrcweir                 pCurrAct->Execute( &rVDev );
1331*cdf0e10cSrcweir 
1332*cdf0e10cSrcweir                 switch( pCurrAct->GetType() )
1333*cdf0e10cSrcweir                 {
1334*cdf0e10cSrcweir                     // ------------------------------------------------------------
1335*cdf0e10cSrcweir 
1336*cdf0e10cSrcweir                     // In the first part of this monster-switch, we
1337*cdf0e10cSrcweir                     // handle all state-changing meta actions. These
1338*cdf0e10cSrcweir                     // are all handled locally.
1339*cdf0e10cSrcweir 
1340*cdf0e10cSrcweir                     // ------------------------------------------------------------
1341*cdf0e10cSrcweir 
1342*cdf0e10cSrcweir                     case META_PUSH_ACTION:
1343*cdf0e10cSrcweir                     {
1344*cdf0e10cSrcweir                         MetaPushAction* pPushAction = static_cast<MetaPushAction*>(pCurrAct);
1345*cdf0e10cSrcweir                         pushState( rStates,
1346*cdf0e10cSrcweir                                    pPushAction->GetFlags() );
1347*cdf0e10cSrcweir                     }
1348*cdf0e10cSrcweir                     break;
1349*cdf0e10cSrcweir 
1350*cdf0e10cSrcweir                     case META_POP_ACTION:
1351*cdf0e10cSrcweir                         popState( rStates );
1352*cdf0e10cSrcweir                         break;
1353*cdf0e10cSrcweir 
1354*cdf0e10cSrcweir                     case META_TEXTLANGUAGE_ACTION:
1355*cdf0e10cSrcweir                         // FALLTHROUGH intended
1356*cdf0e10cSrcweir                     case META_REFPOINT_ACTION:
1357*cdf0e10cSrcweir                         // handled via pCurrAct->Execute( &rVDev )
1358*cdf0e10cSrcweir                         break;
1359*cdf0e10cSrcweir 
1360*cdf0e10cSrcweir                     case META_MAPMODE_ACTION:
1361*cdf0e10cSrcweir                         // modify current mapModeTransformation
1362*cdf0e10cSrcweir                         // transformation, such that subsequent
1363*cdf0e10cSrcweir                         // coordinates map correctly
1364*cdf0e10cSrcweir                         tools::calcLogic2PixelAffineTransform( getState( rStates ).mapModeTransform,
1365*cdf0e10cSrcweir                                                                rVDev );
1366*cdf0e10cSrcweir                         break;
1367*cdf0e10cSrcweir 
1368*cdf0e10cSrcweir                     // monitor clip regions, to assemble clip polygon on our own
1369*cdf0e10cSrcweir                     case META_CLIPREGION_ACTION:
1370*cdf0e10cSrcweir                     {
1371*cdf0e10cSrcweir                         MetaClipRegionAction* pClipAction = static_cast<MetaClipRegionAction*>(pCurrAct);
1372*cdf0e10cSrcweir 
1373*cdf0e10cSrcweir                         if( !pClipAction->IsClipping() )
1374*cdf0e10cSrcweir                         {
1375*cdf0e10cSrcweir                             // clear clipping
1376*cdf0e10cSrcweir                             getState( rStates ).clip.clear();
1377*cdf0e10cSrcweir                         }
1378*cdf0e10cSrcweir                         else
1379*cdf0e10cSrcweir                         {
1380*cdf0e10cSrcweir                             if( !pClipAction->GetRegion().HasPolyPolygon() )
1381*cdf0e10cSrcweir                             {
1382*cdf0e10cSrcweir                                 VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip "
1383*cdf0e10cSrcweir                                                "region encountered, falling back to bounding box!" );
1384*cdf0e10cSrcweir 
1385*cdf0e10cSrcweir                                 // #121806# explicitely kept integer
1386*cdf0e10cSrcweir                                 Rectangle aClipRect(
1387*cdf0e10cSrcweir                                     rVDev.LogicToPixel(
1388*cdf0e10cSrcweir                                         pClipAction->GetRegion().GetBoundRect() ) );
1389*cdf0e10cSrcweir 
1390*cdf0e10cSrcweir                                 // intersect current clip with given rect
1391*cdf0e10cSrcweir                                 updateClipping(
1392*cdf0e10cSrcweir                                     aClipRect,
1393*cdf0e10cSrcweir                                     rFactoryParms,
1394*cdf0e10cSrcweir                                     false );
1395*cdf0e10cSrcweir                             }
1396*cdf0e10cSrcweir                             else
1397*cdf0e10cSrcweir                             {
1398*cdf0e10cSrcweir                                 // set new clip polygon (don't intersect
1399*cdf0e10cSrcweir                                 // with old one, just set it)
1400*cdf0e10cSrcweir 
1401*cdf0e10cSrcweir                                 // #121806# explicitely kept integer
1402*cdf0e10cSrcweir                                 updateClipping(
1403*cdf0e10cSrcweir                                     rVDev.LogicToPixel(
1404*cdf0e10cSrcweir                                         pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(),
1405*cdf0e10cSrcweir                                     rFactoryParms,
1406*cdf0e10cSrcweir                                     false );
1407*cdf0e10cSrcweir                             }
1408*cdf0e10cSrcweir                         }
1409*cdf0e10cSrcweir 
1410*cdf0e10cSrcweir                         break;
1411*cdf0e10cSrcweir                     }
1412*cdf0e10cSrcweir 
1413*cdf0e10cSrcweir                     case META_ISECTRECTCLIPREGION_ACTION:
1414*cdf0e10cSrcweir                     {
1415*cdf0e10cSrcweir                         MetaISectRectClipRegionAction* pClipAction = static_cast<MetaISectRectClipRegionAction*>(pCurrAct);
1416*cdf0e10cSrcweir 
1417*cdf0e10cSrcweir                         // #121806# explicitely kept integer
1418*cdf0e10cSrcweir                         Rectangle aClipRect(
1419*cdf0e10cSrcweir                             rVDev.LogicToPixel( pClipAction->GetRect() ) );
1420*cdf0e10cSrcweir 
1421*cdf0e10cSrcweir                         // intersect current clip with given rect
1422*cdf0e10cSrcweir                         updateClipping(
1423*cdf0e10cSrcweir                             aClipRect,
1424*cdf0e10cSrcweir                             rFactoryParms,
1425*cdf0e10cSrcweir                             true );
1426*cdf0e10cSrcweir 
1427*cdf0e10cSrcweir                         break;
1428*cdf0e10cSrcweir                     }
1429*cdf0e10cSrcweir 
1430*cdf0e10cSrcweir                     case META_ISECTREGIONCLIPREGION_ACTION:
1431*cdf0e10cSrcweir                     {
1432*cdf0e10cSrcweir                         MetaISectRegionClipRegionAction* pClipAction = static_cast<MetaISectRegionClipRegionAction*>(pCurrAct);
1433*cdf0e10cSrcweir 
1434*cdf0e10cSrcweir                         if( !pClipAction->GetRegion().HasPolyPolygon() )
1435*cdf0e10cSrcweir                         {
1436*cdf0e10cSrcweir                             VERBOSE_TRACE( "ImplRenderer::createActions(): non-polygonal clip "
1437*cdf0e10cSrcweir                                            "region encountered, falling back to bounding box!" );
1438*cdf0e10cSrcweir 
1439*cdf0e10cSrcweir                             // #121806# explicitely kept integer
1440*cdf0e10cSrcweir                             Rectangle aClipRect(
1441*cdf0e10cSrcweir                                 rVDev.LogicToPixel( pClipAction->GetRegion().GetBoundRect() ) );
1442*cdf0e10cSrcweir 
1443*cdf0e10cSrcweir                             // intersect current clip with given rect
1444*cdf0e10cSrcweir                             updateClipping(
1445*cdf0e10cSrcweir                                 aClipRect,
1446*cdf0e10cSrcweir                                 rFactoryParms,
1447*cdf0e10cSrcweir                                 true );
1448*cdf0e10cSrcweir                         }
1449*cdf0e10cSrcweir                         else
1450*cdf0e10cSrcweir                         {
1451*cdf0e10cSrcweir                             // intersect current clip with given clip polygon
1452*cdf0e10cSrcweir 
1453*cdf0e10cSrcweir                             // #121806# explicitely kept integer
1454*cdf0e10cSrcweir                             updateClipping(
1455*cdf0e10cSrcweir                                 rVDev.LogicToPixel(
1456*cdf0e10cSrcweir                                     pClipAction->GetRegion().GetPolyPolygon() ).getB2DPolyPolygon(),
1457*cdf0e10cSrcweir                                 rFactoryParms,
1458*cdf0e10cSrcweir                                 true );
1459*cdf0e10cSrcweir                         }
1460*cdf0e10cSrcweir 
1461*cdf0e10cSrcweir                         break;
1462*cdf0e10cSrcweir                     }
1463*cdf0e10cSrcweir 
1464*cdf0e10cSrcweir                     case META_MOVECLIPREGION_ACTION:
1465*cdf0e10cSrcweir                         // TODO(F2): NYI
1466*cdf0e10cSrcweir                         break;
1467*cdf0e10cSrcweir 
1468*cdf0e10cSrcweir                     case META_LINECOLOR_ACTION:
1469*cdf0e10cSrcweir                         if( !rParms.maLineColor.is_initialized() )
1470*cdf0e10cSrcweir                         {
1471*cdf0e10cSrcweir                             setStateColor( static_cast<MetaLineColorAction*>(pCurrAct),
1472*cdf0e10cSrcweir                                            getState( rStates ).isLineColorSet,
1473*cdf0e10cSrcweir                                            getState( rStates ).lineColor,
1474*cdf0e10cSrcweir                                            rCanvas );
1475*cdf0e10cSrcweir                         }
1476*cdf0e10cSrcweir                         break;
1477*cdf0e10cSrcweir 
1478*cdf0e10cSrcweir                     case META_FILLCOLOR_ACTION:
1479*cdf0e10cSrcweir                         if( !rParms.maFillColor.is_initialized() )
1480*cdf0e10cSrcweir                         {
1481*cdf0e10cSrcweir                             setStateColor( static_cast<MetaFillColorAction*>(pCurrAct),
1482*cdf0e10cSrcweir                                            getState( rStates ).isFillColorSet,
1483*cdf0e10cSrcweir                                            getState( rStates ).fillColor,
1484*cdf0e10cSrcweir                                            rCanvas );
1485*cdf0e10cSrcweir                         }
1486*cdf0e10cSrcweir                         break;
1487*cdf0e10cSrcweir 
1488*cdf0e10cSrcweir                     case META_TEXTCOLOR_ACTION:
1489*cdf0e10cSrcweir                     {
1490*cdf0e10cSrcweir                         if( !rParms.maTextColor.is_initialized() )
1491*cdf0e10cSrcweir                         {
1492*cdf0e10cSrcweir                             // Text color is set unconditionally, thus, no
1493*cdf0e10cSrcweir                             // use of setStateColor here
1494*cdf0e10cSrcweir                             ::Color aColor( static_cast<MetaTextColorAction*>(pCurrAct)->GetColor() );
1495*cdf0e10cSrcweir 
1496*cdf0e10cSrcweir                             // force alpha part of color to
1497*cdf0e10cSrcweir                             // opaque. transparent painting is done
1498*cdf0e10cSrcweir                             // explicitely via META_TRANSPARENT_ACTION
1499*cdf0e10cSrcweir                             aColor.SetTransparency(0);
1500*cdf0e10cSrcweir 
1501*cdf0e10cSrcweir                             getState( rStates ).textColor =
1502*cdf0e10cSrcweir                                 ::vcl::unotools::colorToDoubleSequence(
1503*cdf0e10cSrcweir                                     aColor,
1504*cdf0e10cSrcweir                                     rCanvas->getUNOCanvas()->getDevice()->getDeviceColorSpace() );
1505*cdf0e10cSrcweir                         }
1506*cdf0e10cSrcweir                     }
1507*cdf0e10cSrcweir                     break;
1508*cdf0e10cSrcweir 
1509*cdf0e10cSrcweir                     case META_TEXTFILLCOLOR_ACTION:
1510*cdf0e10cSrcweir                         if( !rParms.maTextColor.is_initialized() )
1511*cdf0e10cSrcweir                         {
1512*cdf0e10cSrcweir                             setStateColor( static_cast<MetaTextFillColorAction*>(pCurrAct),
1513*cdf0e10cSrcweir                                            getState( rStates ).isTextFillColorSet,
1514*cdf0e10cSrcweir                                            getState( rStates ).textFillColor,
1515*cdf0e10cSrcweir                                            rCanvas );
1516*cdf0e10cSrcweir                         }
1517*cdf0e10cSrcweir                         break;
1518*cdf0e10cSrcweir 
1519*cdf0e10cSrcweir                     case META_TEXTLINECOLOR_ACTION:
1520*cdf0e10cSrcweir                         if( !rParms.maTextColor.is_initialized() )
1521*cdf0e10cSrcweir                         {
1522*cdf0e10cSrcweir                             setStateColor( static_cast<MetaTextLineColorAction*>(pCurrAct),
1523*cdf0e10cSrcweir                                            getState( rStates ).isTextLineColorSet,
1524*cdf0e10cSrcweir                                            getState( rStates ).textLineColor,
1525*cdf0e10cSrcweir                                            rCanvas );
1526*cdf0e10cSrcweir                         }
1527*cdf0e10cSrcweir                         break;
1528*cdf0e10cSrcweir 
1529*cdf0e10cSrcweir                     case META_TEXTALIGN_ACTION:
1530*cdf0e10cSrcweir                     {
1531*cdf0e10cSrcweir                         ::cppcanvas::internal::OutDevState& rState = getState( rStates );
1532*cdf0e10cSrcweir                         const TextAlign eTextAlign( static_cast<MetaTextAlignAction*>(pCurrAct)->GetTextAlign() );
1533*cdf0e10cSrcweir 
1534*cdf0e10cSrcweir                         rState.textReferencePoint = eTextAlign;
1535*cdf0e10cSrcweir                     }
1536*cdf0e10cSrcweir                     break;
1537*cdf0e10cSrcweir 
1538*cdf0e10cSrcweir                     case META_FONT_ACTION:
1539*cdf0e10cSrcweir                     {
1540*cdf0e10cSrcweir                         ::cppcanvas::internal::OutDevState& rState = getState( rStates );
1541*cdf0e10cSrcweir                         const ::Font& rFont( static_cast<MetaFontAction*>(pCurrAct)->GetFont() );
1542*cdf0e10cSrcweir 
1543*cdf0e10cSrcweir                         rState.xFont = createFont( rState.fontRotation,
1544*cdf0e10cSrcweir                                                    rFont,
1545*cdf0e10cSrcweir                                                    rFactoryParms );
1546*cdf0e10cSrcweir 
1547*cdf0e10cSrcweir                         // TODO(Q2): define and use appropriate enumeration types
1548*cdf0e10cSrcweir                         rState.textReliefStyle          = (sal_Int8)rFont.GetRelief();
1549*cdf0e10cSrcweir                         rState.textOverlineStyle        = (sal_Int8)rFont.GetOverline();
1550*cdf0e10cSrcweir                         rState.textUnderlineStyle       = rParms.maFontUnderline.is_initialized() ?
1551*cdf0e10cSrcweir                             (*rParms.maFontUnderline ? (sal_Int8)UNDERLINE_SINGLE : (sal_Int8)UNDERLINE_NONE) :
1552*cdf0e10cSrcweir                             (sal_Int8)rFont.GetUnderline();
1553*cdf0e10cSrcweir                         rState.textStrikeoutStyle       = (sal_Int8)rFont.GetStrikeout();
1554*cdf0e10cSrcweir                         rState.textEmphasisMarkStyle    = (sal_Int8)rFont.GetEmphasisMark();
1555*cdf0e10cSrcweir                         rState.isTextEffectShadowSet    = (rFont.IsShadow() != sal_False);
1556*cdf0e10cSrcweir                         rState.isTextWordUnderlineSet   = (rFont.IsWordLineMode() != sal_False);
1557*cdf0e10cSrcweir                         rState.isTextOutlineModeSet     = (rFont.IsOutline() != sal_False);
1558*cdf0e10cSrcweir                     }
1559*cdf0e10cSrcweir                     break;
1560*cdf0e10cSrcweir 
1561*cdf0e10cSrcweir                     case META_RASTEROP_ACTION:
1562*cdf0e10cSrcweir                         // TODO(F2): NYI
1563*cdf0e10cSrcweir                         break;
1564*cdf0e10cSrcweir 
1565*cdf0e10cSrcweir                     case META_LAYOUTMODE_ACTION:
1566*cdf0e10cSrcweir                     {
1567*cdf0e10cSrcweir                         // TODO(F2): A lot is missing here
1568*cdf0e10cSrcweir                         int nLayoutMode = static_cast<MetaLayoutModeAction*>(pCurrAct)->GetLayoutMode();
1569*cdf0e10cSrcweir                         ::cppcanvas::internal::OutDevState& rState = getState( rStates );
1570*cdf0e10cSrcweir                         switch( nLayoutMode & (TEXT_LAYOUT_BIDI_RTL|TEXT_LAYOUT_BIDI_STRONG) )
1571*cdf0e10cSrcweir                         {
1572*cdf0e10cSrcweir                             case TEXT_LAYOUT_BIDI_LTR:
1573*cdf0e10cSrcweir                                 rState.textDirection = rendering::TextDirection::WEAK_LEFT_TO_RIGHT;
1574*cdf0e10cSrcweir                                 break;
1575*cdf0e10cSrcweir 
1576*cdf0e10cSrcweir                             case (TEXT_LAYOUT_BIDI_LTR | TEXT_LAYOUT_BIDI_STRONG):
1577*cdf0e10cSrcweir                                 rState.textDirection = rendering::TextDirection::STRONG_LEFT_TO_RIGHT;
1578*cdf0e10cSrcweir                                 break;
1579*cdf0e10cSrcweir 
1580*cdf0e10cSrcweir                             case TEXT_LAYOUT_BIDI_RTL:
1581*cdf0e10cSrcweir                                 rState.textDirection = rendering::TextDirection::WEAK_RIGHT_TO_LEFT;
1582*cdf0e10cSrcweir                                 break;
1583*cdf0e10cSrcweir 
1584*cdf0e10cSrcweir                             case (TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_BIDI_STRONG):
1585*cdf0e10cSrcweir                                 rState.textDirection = rendering::TextDirection::STRONG_RIGHT_TO_LEFT;
1586*cdf0e10cSrcweir                                 break;
1587*cdf0e10cSrcweir                         }
1588*cdf0e10cSrcweir 
1589*cdf0e10cSrcweir                         rState.textAlignment = 0; // TODO(F2): rendering::TextAlignment::LEFT_ALIGNED;
1590*cdf0e10cSrcweir                         if( (nLayoutMode & (TEXT_LAYOUT_BIDI_RTL | TEXT_LAYOUT_TEXTORIGIN_RIGHT) )
1591*cdf0e10cSrcweir                             && !(nLayoutMode & TEXT_LAYOUT_TEXTORIGIN_LEFT ) )
1592*cdf0e10cSrcweir                         {
1593*cdf0e10cSrcweir                             rState.textAlignment = 1; // TODO(F2): rendering::TextAlignment::RIGHT_ALIGNED;
1594*cdf0e10cSrcweir                         }
1595*cdf0e10cSrcweir                     }
1596*cdf0e10cSrcweir                     break;
1597*cdf0e10cSrcweir 
1598*cdf0e10cSrcweir                     // ------------------------------------------------------------
1599*cdf0e10cSrcweir 
1600*cdf0e10cSrcweir                     // In the second part of this monster-switch, we
1601*cdf0e10cSrcweir                     // handle all recursing meta actions. These are the
1602*cdf0e10cSrcweir                     // ones generating a metafile by themselves, which is
1603*cdf0e10cSrcweir                     // then processed by recursively calling this method.
1604*cdf0e10cSrcweir 
1605*cdf0e10cSrcweir                     // ------------------------------------------------------------
1606*cdf0e10cSrcweir 
1607*cdf0e10cSrcweir                     case META_GRADIENT_ACTION:
1608*cdf0e10cSrcweir                     {
1609*cdf0e10cSrcweir                         MetaGradientAction* pGradAct = static_cast<MetaGradientAction*>(pCurrAct);
1610*cdf0e10cSrcweir                         createGradientAction( ::Polygon( pGradAct->GetRect() ),
1611*cdf0e10cSrcweir                                               pGradAct->GetGradient(),
1612*cdf0e10cSrcweir                                               rFactoryParms,
1613*cdf0e10cSrcweir                                               true,
1614*cdf0e10cSrcweir                                               bSubsettableActions );
1615*cdf0e10cSrcweir                     }
1616*cdf0e10cSrcweir                     break;
1617*cdf0e10cSrcweir 
1618*cdf0e10cSrcweir                     case META_HATCH_ACTION:
1619*cdf0e10cSrcweir                     {
1620*cdf0e10cSrcweir                         // TODO(F2): use native Canvas hatches here
1621*cdf0e10cSrcweir                         GDIMetaFile aTmpMtf;
1622*cdf0e10cSrcweir 
1623*cdf0e10cSrcweir                         rVDev.AddHatchActions( static_cast<MetaHatchAction*>(pCurrAct)->GetPolyPolygon(),
1624*cdf0e10cSrcweir                                                static_cast<MetaHatchAction*>(pCurrAct)->GetHatch(),
1625*cdf0e10cSrcweir                                                aTmpMtf );
1626*cdf0e10cSrcweir                         createActions( aTmpMtf, rFactoryParms,
1627*cdf0e10cSrcweir                                        bSubsettableActions );
1628*cdf0e10cSrcweir                     }
1629*cdf0e10cSrcweir                     break;
1630*cdf0e10cSrcweir 
1631*cdf0e10cSrcweir                     case META_EPS_ACTION:
1632*cdf0e10cSrcweir                     {
1633*cdf0e10cSrcweir                         MetaEPSAction* 		pAct = static_cast<MetaEPSAction*>(pCurrAct);
1634*cdf0e10cSrcweir                         const GDIMetaFile&  rSubstitute = pAct->GetSubstitute();
1635*cdf0e10cSrcweir 
1636*cdf0e10cSrcweir                         // #121806# explicitely kept integer
1637*cdf0e10cSrcweir                         const Size aMtfSize( rSubstitute.GetPrefSize() );
1638*cdf0e10cSrcweir                         const Size aMtfSizePixPre( rVDev.LogicToPixel( aMtfSize,
1639*cdf0e10cSrcweir                                                                        rSubstitute.GetPrefMapMode() ) );
1640*cdf0e10cSrcweir 
1641*cdf0e10cSrcweir                         // #i44110# correct null-sized output - there
1642*cdf0e10cSrcweir                         // are metafiles which have zero size in at
1643*cdf0e10cSrcweir                         // least one dimension
1644*cdf0e10cSrcweir                         const Size aMtfSizePix( ::std::max( aMtfSizePixPre.Width(), 1L ),
1645*cdf0e10cSrcweir                                                 ::std::max( aMtfSizePixPre.Height(), 1L ) );
1646*cdf0e10cSrcweir 
1647*cdf0e10cSrcweir                         // Setup local transform, such that the
1648*cdf0e10cSrcweir                         // metafile renders itself into the given
1649*cdf0e10cSrcweir                         // output rectangle
1650*cdf0e10cSrcweir                         pushState( rStates, PUSH_ALL );
1651*cdf0e10cSrcweir 
1652*cdf0e10cSrcweir                         rVDev.Push();
1653*cdf0e10cSrcweir                         rVDev.SetMapMode( rSubstitute.GetPrefMapMode() );
1654*cdf0e10cSrcweir 
1655*cdf0e10cSrcweir                         const ::Point& rPos( rVDev.LogicToPixel( pAct->GetPoint() ) );
1656*cdf0e10cSrcweir                         const ::Size&  rSize( rVDev.LogicToPixel( pAct->GetSize() ) );
1657*cdf0e10cSrcweir 
1658*cdf0e10cSrcweir                         getState( rStates ).transform.translate( rPos.X(),
1659*cdf0e10cSrcweir                                                                  rPos.Y() );
1660*cdf0e10cSrcweir                         getState( rStates ).transform.scale( (double)rSize.Width() / aMtfSizePix.Width(),
1661*cdf0e10cSrcweir                                                              (double)rSize.Height() / aMtfSizePix.Height() );
1662*cdf0e10cSrcweir 
1663*cdf0e10cSrcweir                         createActions( const_cast<GDIMetaFile&>(pAct->GetSubstitute()),
1664*cdf0e10cSrcweir                                        rFactoryParms,
1665*cdf0e10cSrcweir                                        bSubsettableActions );
1666*cdf0e10cSrcweir 
1667*cdf0e10cSrcweir                         rVDev.Pop();
1668*cdf0e10cSrcweir                         popState( rStates );
1669*cdf0e10cSrcweir                     }
1670*cdf0e10cSrcweir                     break;
1671*cdf0e10cSrcweir 
1672*cdf0e10cSrcweir                     // handle metafile comments, to retrieve
1673*cdf0e10cSrcweir                     // meta-information for gradients, fills and
1674*cdf0e10cSrcweir                     // strokes. May skip actions, and may recurse.
1675*cdf0e10cSrcweir                     case META_COMMENT_ACTION:
1676*cdf0e10cSrcweir                     {
1677*cdf0e10cSrcweir                         MetaCommentAction* pAct = static_cast<MetaCommentAction*>(pCurrAct);
1678*cdf0e10cSrcweir 
1679*cdf0e10cSrcweir                         // Handle gradients
1680*cdf0e10cSrcweir                         if ( pAct->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_BEGIN" ) == COMPARE_EQUAL )
1681*cdf0e10cSrcweir                         {
1682*cdf0e10cSrcweir                             MetaGradientExAction* pGradAction = NULL;
1683*cdf0e10cSrcweir                             bool bDone( false );
1684*cdf0e10cSrcweir                             while( !bDone &&
1685*cdf0e10cSrcweir                                    (pCurrAct=rMtf.NextAction()) != NULL )
1686*cdf0e10cSrcweir                             {
1687*cdf0e10cSrcweir                                 switch( pCurrAct->GetType() )
1688*cdf0e10cSrcweir                                 {
1689*cdf0e10cSrcweir                                     // extract gradient info
1690*cdf0e10cSrcweir                                     case META_GRADIENTEX_ACTION:
1691*cdf0e10cSrcweir                                         pGradAction = static_cast<MetaGradientExAction*>(pCurrAct);
1692*cdf0e10cSrcweir                                         break;
1693*cdf0e10cSrcweir 
1694*cdf0e10cSrcweir                                     // skip broken-down rendering, output gradient when sequence is ended
1695*cdf0e10cSrcweir                                     case META_COMMENT_ACTION:
1696*cdf0e10cSrcweir                                         if( static_cast<MetaCommentAction*>(pCurrAct)->GetComment().CompareIgnoreCaseToAscii( "XGRAD_SEQ_END" ) == COMPARE_EQUAL )
1697*cdf0e10cSrcweir                                         {
1698*cdf0e10cSrcweir                                             bDone = true;
1699*cdf0e10cSrcweir 
1700*cdf0e10cSrcweir                                             if( pGradAction )
1701*cdf0e10cSrcweir                                             {
1702*cdf0e10cSrcweir                                                 createGradientAction( pGradAction->GetPolyPolygon(),
1703*cdf0e10cSrcweir                                                                       pGradAction->GetGradient(),
1704*cdf0e10cSrcweir                                                                       rFactoryParms,
1705*cdf0e10cSrcweir                                                                       false,
1706*cdf0e10cSrcweir                                                                       bSubsettableActions );
1707*cdf0e10cSrcweir                                             }
1708*cdf0e10cSrcweir                                         }
1709*cdf0e10cSrcweir                                         break;
1710*cdf0e10cSrcweir                                 }
1711*cdf0e10cSrcweir                             }
1712*cdf0e10cSrcweir                         }
1713*cdf0e10cSrcweir                         // TODO(P2): Handle drawing layer strokes, via
1714*cdf0e10cSrcweir                         // XPATHSTROKE_SEQ_BEGIN comment
1715*cdf0e10cSrcweir 
1716*cdf0e10cSrcweir                         // Handle drawing layer fills
1717*cdf0e10cSrcweir                         else if( pAct->GetComment().Equals( "XPATHFILL_SEQ_BEGIN" ) )
1718*cdf0e10cSrcweir                         {
1719*cdf0e10cSrcweir                             const sal_uInt8* pData = pAct->GetData();
1720*cdf0e10cSrcweir                             if ( pData )
1721*cdf0e10cSrcweir                             {
1722*cdf0e10cSrcweir                                 SvMemoryStream	aMemStm( (void*)pData, pAct->GetDataSize(), STREAM_READ );
1723*cdf0e10cSrcweir 
1724*cdf0e10cSrcweir                                 SvtGraphicFill aFill;
1725*cdf0e10cSrcweir                                 aMemStm >> aFill;
1726*cdf0e10cSrcweir 
1727*cdf0e10cSrcweir                                 // TODO(P2): Also handle gradients and
1728*cdf0e10cSrcweir                                 // hatches like this
1729*cdf0e10cSrcweir 
1730*cdf0e10cSrcweir                                 // only evaluate comment for pure
1731*cdf0e10cSrcweir                                 // bitmap fills. If a transparency
1732*cdf0e10cSrcweir                                 // gradient is involved (denoted by
1733*cdf0e10cSrcweir                                 // the FloatTransparent action), take
1734*cdf0e10cSrcweir                                 // the normal meta actions.
1735*cdf0e10cSrcweir                                 if( aFill.getFillType() == SvtGraphicFill::fillTexture &&
1736*cdf0e10cSrcweir                                     !isActionContained( rMtf,
1737*cdf0e10cSrcweir                                                        "XPATHFILL_SEQ_END",
1738*cdf0e10cSrcweir                                                         META_FLOATTRANSPARENT_ACTION ) )
1739*cdf0e10cSrcweir                                 {
1740*cdf0e10cSrcweir                                     rendering::Texture aTexture;
1741*cdf0e10cSrcweir 
1742*cdf0e10cSrcweir                                     // TODO(F1): the SvtGraphicFill
1743*cdf0e10cSrcweir                                     // can also transport metafiles
1744*cdf0e10cSrcweir                                     // here, handle that case, too
1745*cdf0e10cSrcweir                                     Graphic	aGraphic;
1746*cdf0e10cSrcweir                                     aFill.getGraphic( aGraphic );
1747*cdf0e10cSrcweir 
1748*cdf0e10cSrcweir                                     BitmapEx 	 aBmpEx( aGraphic.GetBitmapEx() );
1749*cdf0e10cSrcweir                                     const ::Size aBmpSize( aBmpEx.GetSizePixel() );
1750*cdf0e10cSrcweir 
1751*cdf0e10cSrcweir                                     ::SvtGraphicFill::Transform aTransform;
1752*cdf0e10cSrcweir                                     aFill.getTransform( aTransform );
1753*cdf0e10cSrcweir 
1754*cdf0e10cSrcweir                                     ::basegfx::B2DHomMatrix aMatrix;
1755*cdf0e10cSrcweir 
1756*cdf0e10cSrcweir                                     // convert to basegfx matrix
1757*cdf0e10cSrcweir                                     aMatrix.set(0,0, aTransform.matrix[ 0 ] );
1758*cdf0e10cSrcweir                                     aMatrix.set(0,1, aTransform.matrix[ 1 ] );
1759*cdf0e10cSrcweir                                     aMatrix.set(0,2, aTransform.matrix[ 2 ] );
1760*cdf0e10cSrcweir                                     aMatrix.set(1,0, aTransform.matrix[ 3 ] );
1761*cdf0e10cSrcweir                                     aMatrix.set(1,1, aTransform.matrix[ 4 ] );
1762*cdf0e10cSrcweir                                     aMatrix.set(1,2, aTransform.matrix[ 5 ] );
1763*cdf0e10cSrcweir 
1764*cdf0e10cSrcweir                                     ::basegfx::B2DHomMatrix aScale;
1765*cdf0e10cSrcweir                                     aScale.scale( aBmpSize.Width(),
1766*cdf0e10cSrcweir                                                   aBmpSize.Height() );
1767*cdf0e10cSrcweir 
1768*cdf0e10cSrcweir                                     // post-multiply with the bitmap
1769*cdf0e10cSrcweir                                     // size (XCanvas' texture assumes
1770*cdf0e10cSrcweir                                     // the given bitmap to be
1771*cdf0e10cSrcweir                                     // normalized to [0,1]x[0,1]
1772*cdf0e10cSrcweir                                     // rectangle)
1773*cdf0e10cSrcweir                                     aMatrix = aMatrix * aScale;
1774*cdf0e10cSrcweir 
1775*cdf0e10cSrcweir                                     // pre-multiply with the
1776*cdf0e10cSrcweir                                     // logic-to-pixel scale factor
1777*cdf0e10cSrcweir                                     // (the metafile comment works in
1778*cdf0e10cSrcweir                                     // logical coordinates).
1779*cdf0e10cSrcweir                                     ::basegfx::B2DHomMatrix aLogic2PixelTransform;
1780*cdf0e10cSrcweir                                     aMatrix *= tools::calcLogic2PixelLinearTransform( aLogic2PixelTransform,
1781*cdf0e10cSrcweir                                                                                       rVDev );
1782*cdf0e10cSrcweir 
1783*cdf0e10cSrcweir                                     ::basegfx::unotools::affineMatrixFromHomMatrix(
1784*cdf0e10cSrcweir                                         aTexture.AffineTransform,
1785*cdf0e10cSrcweir                                         aMatrix );
1786*cdf0e10cSrcweir 
1787*cdf0e10cSrcweir                                     aTexture.Alpha = 1.0 - aFill.getTransparency();
1788*cdf0e10cSrcweir                                     aTexture.Bitmap =
1789*cdf0e10cSrcweir                                         ::vcl::unotools::xBitmapFromBitmapEx(
1790*cdf0e10cSrcweir                                             rCanvas->getUNOCanvas()->getDevice(),
1791*cdf0e10cSrcweir                                             aBmpEx );
1792*cdf0e10cSrcweir                                     if( aFill.isTiling() )
1793*cdf0e10cSrcweir                                     {
1794*cdf0e10cSrcweir                                         aTexture.RepeatModeX = rendering::TexturingMode::REPEAT;
1795*cdf0e10cSrcweir                                         aTexture.RepeatModeY = rendering::TexturingMode::REPEAT;
1796*cdf0e10cSrcweir                                     }
1797*cdf0e10cSrcweir                                     else
1798*cdf0e10cSrcweir                                     {
1799*cdf0e10cSrcweir                                         aTexture.RepeatModeX = rendering::TexturingMode::NONE;
1800*cdf0e10cSrcweir                                         aTexture.RepeatModeY = rendering::TexturingMode::NONE;
1801*cdf0e10cSrcweir                                     }
1802*cdf0e10cSrcweir 
1803*cdf0e10cSrcweir                                     ::PolyPolygon aPath;
1804*cdf0e10cSrcweir                                     aFill.getPath( aPath );
1805*cdf0e10cSrcweir 
1806*cdf0e10cSrcweir                                     ::basegfx::B2DPolyPolygon aPoly( aPath.getB2DPolyPolygon() );
1807*cdf0e10cSrcweir                                     aPoly.transform( getState( rStates ).mapModeTransform );
1808*cdf0e10cSrcweir                                     ActionSharedPtr pPolyAction(
1809*cdf0e10cSrcweir                                         internal::PolyPolyActionFactory::createPolyPolyAction(
1810*cdf0e10cSrcweir                                             aPoly,
1811*cdf0e10cSrcweir                                             rCanvas,
1812*cdf0e10cSrcweir                                             getState( rStates ),
1813*cdf0e10cSrcweir                                             aTexture ) );
1814*cdf0e10cSrcweir 
1815*cdf0e10cSrcweir                                     if( pPolyAction )
1816*cdf0e10cSrcweir                                     {
1817*cdf0e10cSrcweir                                         maActions.push_back(
1818*cdf0e10cSrcweir                                             MtfAction(
1819*cdf0e10cSrcweir                                                 pPolyAction,
1820*cdf0e10cSrcweir                                                 io_rCurrActionIndex ) );
1821*cdf0e10cSrcweir 
1822*cdf0e10cSrcweir                                         io_rCurrActionIndex += pPolyAction->getActionCount()-1;
1823*cdf0e10cSrcweir                                     }
1824*cdf0e10cSrcweir 
1825*cdf0e10cSrcweir                                     // skip broken-down render output
1826*cdf0e10cSrcweir                                     skipContent( rMtf,
1827*cdf0e10cSrcweir                                                  "XPATHFILL_SEQ_END",
1828*cdf0e10cSrcweir                                                  io_rCurrActionIndex );
1829*cdf0e10cSrcweir                                 }
1830*cdf0e10cSrcweir                             }
1831*cdf0e10cSrcweir                         }
1832*cdf0e10cSrcweir                     }
1833*cdf0e10cSrcweir                     break;
1834*cdf0e10cSrcweir 
1835*cdf0e10cSrcweir                     // ------------------------------------------------------------
1836*cdf0e10cSrcweir 
1837*cdf0e10cSrcweir                     // In the third part of this monster-switch, we
1838*cdf0e10cSrcweir                     // handle all 'acting' meta actions. These are all
1839*cdf0e10cSrcweir                     // processed by constructing function objects for
1840*cdf0e10cSrcweir                     // them, which will later ease caching.
1841*cdf0e10cSrcweir 
1842*cdf0e10cSrcweir                     // ------------------------------------------------------------
1843*cdf0e10cSrcweir 
1844*cdf0e10cSrcweir                     case META_POINT_ACTION:
1845*cdf0e10cSrcweir                     {
1846*cdf0e10cSrcweir                         const OutDevState& rState( getState( rStates ) );
1847*cdf0e10cSrcweir                         if( rState.lineColor.getLength() )
1848*cdf0e10cSrcweir                         {
1849*cdf0e10cSrcweir                             ActionSharedPtr pPointAction(
1850*cdf0e10cSrcweir                                 internal::PointActionFactory::createPointAction(
1851*cdf0e10cSrcweir                                     rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint(
1852*cdf0e10cSrcweir                                         static_cast<MetaPointAction*>(pCurrAct)->GetPoint() ),
1853*cdf0e10cSrcweir                                     rCanvas,
1854*cdf0e10cSrcweir                                     rState ) );
1855*cdf0e10cSrcweir 
1856*cdf0e10cSrcweir                             if( pPointAction )
1857*cdf0e10cSrcweir                             {
1858*cdf0e10cSrcweir                                 maActions.push_back(
1859*cdf0e10cSrcweir                                     MtfAction(
1860*cdf0e10cSrcweir                                         pPointAction,
1861*cdf0e10cSrcweir                                         io_rCurrActionIndex ) );
1862*cdf0e10cSrcweir 
1863*cdf0e10cSrcweir                                 io_rCurrActionIndex += pPointAction->getActionCount()-1;
1864*cdf0e10cSrcweir                             }
1865*cdf0e10cSrcweir                         }
1866*cdf0e10cSrcweir                     }
1867*cdf0e10cSrcweir                     break;
1868*cdf0e10cSrcweir 
1869*cdf0e10cSrcweir                     case META_PIXEL_ACTION:
1870*cdf0e10cSrcweir                     {
1871*cdf0e10cSrcweir                         const OutDevState& rState( getState( rStates ) );
1872*cdf0e10cSrcweir                         if( rState.lineColor.getLength() )
1873*cdf0e10cSrcweir                         {
1874*cdf0e10cSrcweir                             ActionSharedPtr pPointAction(
1875*cdf0e10cSrcweir                                 internal::PointActionFactory::createPointAction(
1876*cdf0e10cSrcweir                                     rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint(
1877*cdf0e10cSrcweir                                         static_cast<MetaPixelAction*>(pCurrAct)->GetPoint() ),
1878*cdf0e10cSrcweir                                     rCanvas,
1879*cdf0e10cSrcweir                                     rState,
1880*cdf0e10cSrcweir                                     static_cast<MetaPixelAction*>(pCurrAct)->GetColor() ) );
1881*cdf0e10cSrcweir 
1882*cdf0e10cSrcweir                             if( pPointAction )
1883*cdf0e10cSrcweir                             {
1884*cdf0e10cSrcweir                                 maActions.push_back(
1885*cdf0e10cSrcweir                                     MtfAction(
1886*cdf0e10cSrcweir                                         pPointAction,
1887*cdf0e10cSrcweir                                         io_rCurrActionIndex ) );
1888*cdf0e10cSrcweir 
1889*cdf0e10cSrcweir                                 io_rCurrActionIndex += pPointAction->getActionCount()-1;
1890*cdf0e10cSrcweir                             }
1891*cdf0e10cSrcweir                         }
1892*cdf0e10cSrcweir                     }
1893*cdf0e10cSrcweir                     break;
1894*cdf0e10cSrcweir 
1895*cdf0e10cSrcweir                     case META_LINE_ACTION:
1896*cdf0e10cSrcweir                     {
1897*cdf0e10cSrcweir                         const OutDevState& rState( getState( rStates ) );
1898*cdf0e10cSrcweir                         if( rState.lineColor.getLength() )
1899*cdf0e10cSrcweir                         {
1900*cdf0e10cSrcweir                             MetaLineAction* pLineAct = static_cast<MetaLineAction*>(pCurrAct);
1901*cdf0e10cSrcweir 
1902*cdf0e10cSrcweir                             const LineInfo& rLineInfo( pLineAct->GetLineInfo() );
1903*cdf0e10cSrcweir 
1904*cdf0e10cSrcweir                             const ::basegfx::B2DPoint aStartPoint(
1905*cdf0e10cSrcweir                                 rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( pLineAct->GetStartPoint() ));
1906*cdf0e10cSrcweir                             const ::basegfx::B2DPoint aEndPoint(
1907*cdf0e10cSrcweir                                 rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( pLineAct->GetEndPoint() ));
1908*cdf0e10cSrcweir 
1909*cdf0e10cSrcweir                             ActionSharedPtr pLineAction;
1910*cdf0e10cSrcweir 
1911*cdf0e10cSrcweir                             if( rLineInfo.IsDefault() )
1912*cdf0e10cSrcweir                             {
1913*cdf0e10cSrcweir                                 // plain hair line
1914*cdf0e10cSrcweir                                 pLineAction =
1915*cdf0e10cSrcweir                                     internal::LineActionFactory::createLineAction(
1916*cdf0e10cSrcweir                                         aStartPoint,
1917*cdf0e10cSrcweir                                         aEndPoint,
1918*cdf0e10cSrcweir                                         rCanvas,
1919*cdf0e10cSrcweir                                         rState );
1920*cdf0e10cSrcweir 
1921*cdf0e10cSrcweir                                 if( pLineAction )
1922*cdf0e10cSrcweir                                 {
1923*cdf0e10cSrcweir                                     maActions.push_back(
1924*cdf0e10cSrcweir                                         MtfAction(
1925*cdf0e10cSrcweir                                             pLineAction,
1926*cdf0e10cSrcweir                                             io_rCurrActionIndex ) );
1927*cdf0e10cSrcweir 
1928*cdf0e10cSrcweir                                     io_rCurrActionIndex += pLineAction->getActionCount()-1;
1929*cdf0e10cSrcweir                                 }
1930*cdf0e10cSrcweir                             }
1931*cdf0e10cSrcweir                             else if( LINE_NONE != rLineInfo.GetStyle() )
1932*cdf0e10cSrcweir                             {
1933*cdf0e10cSrcweir                                 // 'thick' line
1934*cdf0e10cSrcweir                                 rendering::StrokeAttributes aStrokeAttributes;
1935*cdf0e10cSrcweir 
1936*cdf0e10cSrcweir                                 setupStrokeAttributes( aStrokeAttributes,
1937*cdf0e10cSrcweir                                                        rFactoryParms,
1938*cdf0e10cSrcweir                                                        rLineInfo );
1939*cdf0e10cSrcweir 
1940*cdf0e10cSrcweir                                 // XCanvas can only stroke polygons,
1941*cdf0e10cSrcweir                                 // not simple lines - thus, handle
1942*cdf0e10cSrcweir                                 // this case via the polypolygon
1943*cdf0e10cSrcweir                                 // action
1944*cdf0e10cSrcweir                                 ::basegfx::B2DPolygon aPoly;
1945*cdf0e10cSrcweir                                 aPoly.append( aStartPoint );
1946*cdf0e10cSrcweir                                 aPoly.append( aEndPoint );
1947*cdf0e10cSrcweir                                 pLineAction =
1948*cdf0e10cSrcweir                                     internal::PolyPolyActionFactory::createPolyPolyAction(
1949*cdf0e10cSrcweir                                         ::basegfx::B2DPolyPolygon( aPoly ),
1950*cdf0e10cSrcweir                                         rCanvas, rState, aStrokeAttributes );
1951*cdf0e10cSrcweir 
1952*cdf0e10cSrcweir                                 if( pLineAction )
1953*cdf0e10cSrcweir                                 {
1954*cdf0e10cSrcweir                                     maActions.push_back(
1955*cdf0e10cSrcweir                                         MtfAction(
1956*cdf0e10cSrcweir                                             pLineAction,
1957*cdf0e10cSrcweir                                             io_rCurrActionIndex ) );
1958*cdf0e10cSrcweir 
1959*cdf0e10cSrcweir                                     io_rCurrActionIndex += pLineAction->getActionCount()-1;
1960*cdf0e10cSrcweir                                 }
1961*cdf0e10cSrcweir                             }
1962*cdf0e10cSrcweir                             // else: line style is default
1963*cdf0e10cSrcweir                             // (i.e. invisible), don't generate action
1964*cdf0e10cSrcweir                         }
1965*cdf0e10cSrcweir                     }
1966*cdf0e10cSrcweir                     break;
1967*cdf0e10cSrcweir 
1968*cdf0e10cSrcweir                     case META_RECT_ACTION:
1969*cdf0e10cSrcweir                     {
1970*cdf0e10cSrcweir                         const Rectangle& rRect(
1971*cdf0e10cSrcweir                             static_cast<MetaRectAction*>(pCurrAct)->GetRect() );
1972*cdf0e10cSrcweir 
1973*cdf0e10cSrcweir                         if( rRect.IsEmpty() )
1974*cdf0e10cSrcweir                             break;
1975*cdf0e10cSrcweir 
1976*cdf0e10cSrcweir                         const OutDevState& rState( getState( rStates ) );
1977*cdf0e10cSrcweir                         const ::basegfx::B2DPoint aTopLeftPixel(
1978*cdf0e10cSrcweir                             rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ) );
1979*cdf0e10cSrcweir                         const ::basegfx::B2DPoint aBottomRightPixel(
1980*cdf0e10cSrcweir                             rState.mapModeTransform * ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) +
1981*cdf0e10cSrcweir                             // #121100# OutputDevice::DrawRect() fills
1982*cdf0e10cSrcweir                             // rectangles Apple-like, i.e. with one
1983*cdf0e10cSrcweir                             // additional pixel to the right and bottom.
1984*cdf0e10cSrcweir                             ::basegfx::B2DPoint(1,1) );
1985*cdf0e10cSrcweir 
1986*cdf0e10cSrcweir                         createFillAndStroke( ::basegfx::tools::createPolygonFromRect(
1987*cdf0e10cSrcweir                                                  ::basegfx::B2DRange( aTopLeftPixel,
1988*cdf0e10cSrcweir                                                                       aBottomRightPixel )),
1989*cdf0e10cSrcweir                                              rFactoryParms );
1990*cdf0e10cSrcweir                         break;
1991*cdf0e10cSrcweir                     }
1992*cdf0e10cSrcweir 
1993*cdf0e10cSrcweir                     case META_ROUNDRECT_ACTION:
1994*cdf0e10cSrcweir                     {
1995*cdf0e10cSrcweir                         const Rectangle& rRect(
1996*cdf0e10cSrcweir                             static_cast<MetaRoundRectAction*>(pCurrAct)->GetRect());
1997*cdf0e10cSrcweir 
1998*cdf0e10cSrcweir                         if( rRect.IsEmpty() )
1999*cdf0e10cSrcweir                             break;
2000*cdf0e10cSrcweir 
2001*cdf0e10cSrcweir                         ::basegfx::B2DPolygon aPoly(
2002*cdf0e10cSrcweir                             ::basegfx::tools::createPolygonFromRect(
2003*cdf0e10cSrcweir                                 ::basegfx::B2DRange(
2004*cdf0e10cSrcweir                                     ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ),
2005*cdf0e10cSrcweir                                     ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) +
2006*cdf0e10cSrcweir                                     ::basegfx::B2DPoint(1,1) ),
2007*cdf0e10cSrcweir                                 static_cast<MetaRoundRectAction*>(pCurrAct)->GetHorzRound(),
2008*cdf0e10cSrcweir                                 static_cast<MetaRoundRectAction*>(pCurrAct)->GetVertRound() ));
2009*cdf0e10cSrcweir                         aPoly.transform( getState( rStates ).mapModeTransform );
2010*cdf0e10cSrcweir 
2011*cdf0e10cSrcweir                         createFillAndStroke( aPoly,
2012*cdf0e10cSrcweir                                              rFactoryParms );
2013*cdf0e10cSrcweir                     }
2014*cdf0e10cSrcweir                     break;
2015*cdf0e10cSrcweir 
2016*cdf0e10cSrcweir                     case META_ELLIPSE_ACTION:
2017*cdf0e10cSrcweir                     {
2018*cdf0e10cSrcweir                         const Rectangle& rRect(
2019*cdf0e10cSrcweir                             static_cast<MetaEllipseAction*>(pCurrAct)->GetRect() );
2020*cdf0e10cSrcweir 
2021*cdf0e10cSrcweir                         if( rRect.IsEmpty() )
2022*cdf0e10cSrcweir                             break;
2023*cdf0e10cSrcweir 
2024*cdf0e10cSrcweir                         const ::basegfx::B2DRange aRange(
2025*cdf0e10cSrcweir                             ::vcl::unotools::b2DPointFromPoint( rRect.TopLeft() ),
2026*cdf0e10cSrcweir                             ::vcl::unotools::b2DPointFromPoint( rRect.BottomRight() ) +
2027*cdf0e10cSrcweir                             ::basegfx::B2DPoint(1,1) );
2028*cdf0e10cSrcweir 
2029*cdf0e10cSrcweir                         ::basegfx::B2DPolygon aPoly(
2030*cdf0e10cSrcweir                             ::basegfx::tools::createPolygonFromEllipse(
2031*cdf0e10cSrcweir                                 aRange.getCenter(),
2032*cdf0e10cSrcweir                                 aRange.getWidth(),
2033*cdf0e10cSrcweir                                 aRange.getHeight() ));
2034*cdf0e10cSrcweir                         aPoly.transform( getState( rStates ).mapModeTransform );
2035*cdf0e10cSrcweir 
2036*cdf0e10cSrcweir                         createFillAndStroke( aPoly,
2037*cdf0e10cSrcweir                                              rFactoryParms );
2038*cdf0e10cSrcweir                     }
2039*cdf0e10cSrcweir                     break;
2040*cdf0e10cSrcweir 
2041*cdf0e10cSrcweir                     case META_ARC_ACTION:
2042*cdf0e10cSrcweir                     {
2043*cdf0e10cSrcweir                         // TODO(F1): Missing basegfx functionality. Mind empty rects!
2044*cdf0e10cSrcweir                         const Polygon aToolsPoly( static_cast<MetaArcAction*>(pCurrAct)->GetRect(),
2045*cdf0e10cSrcweir                                                   static_cast<MetaArcAction*>(pCurrAct)->GetStartPoint(),
2046*cdf0e10cSrcweir                                                   static_cast<MetaArcAction*>(pCurrAct)->GetEndPoint(), POLY_ARC );
2047*cdf0e10cSrcweir                         ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() );
2048*cdf0e10cSrcweir                         aPoly.transform( getState( rStates ).mapModeTransform );
2049*cdf0e10cSrcweir 
2050*cdf0e10cSrcweir                         createFillAndStroke( aPoly,
2051*cdf0e10cSrcweir                                              rFactoryParms );
2052*cdf0e10cSrcweir                     }
2053*cdf0e10cSrcweir                     break;
2054*cdf0e10cSrcweir 
2055*cdf0e10cSrcweir                     case META_PIE_ACTION:
2056*cdf0e10cSrcweir                     {
2057*cdf0e10cSrcweir                         // TODO(F1): Missing basegfx functionality. Mind empty rects!
2058*cdf0e10cSrcweir                         const Polygon aToolsPoly( static_cast<MetaPieAction*>(pCurrAct)->GetRect(),
2059*cdf0e10cSrcweir                                                   static_cast<MetaPieAction*>(pCurrAct)->GetStartPoint(),
2060*cdf0e10cSrcweir                                                   static_cast<MetaPieAction*>(pCurrAct)->GetEndPoint(), POLY_PIE );
2061*cdf0e10cSrcweir                         ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() );
2062*cdf0e10cSrcweir                         aPoly.transform( getState( rStates ).mapModeTransform );
2063*cdf0e10cSrcweir 
2064*cdf0e10cSrcweir                         createFillAndStroke( aPoly,
2065*cdf0e10cSrcweir                                              rFactoryParms );
2066*cdf0e10cSrcweir                     }
2067*cdf0e10cSrcweir                     break;
2068*cdf0e10cSrcweir 
2069*cdf0e10cSrcweir                     case META_CHORD_ACTION:
2070*cdf0e10cSrcweir                     {
2071*cdf0e10cSrcweir                         // TODO(F1): Missing basegfx functionality. Mind empty rects!
2072*cdf0e10cSrcweir                         const Polygon aToolsPoly( static_cast<MetaChordAction*>(pCurrAct)->GetRect(),
2073*cdf0e10cSrcweir                                                   static_cast<MetaChordAction*>(pCurrAct)->GetStartPoint(),
2074*cdf0e10cSrcweir                                                   static_cast<MetaChordAction*>(pCurrAct)->GetEndPoint(), POLY_CHORD );
2075*cdf0e10cSrcweir                         ::basegfx::B2DPolygon aPoly( aToolsPoly.getB2DPolygon() );
2076*cdf0e10cSrcweir                         aPoly.transform( getState( rStates ).mapModeTransform );
2077*cdf0e10cSrcweir 
2078*cdf0e10cSrcweir                         createFillAndStroke( aPoly,
2079*cdf0e10cSrcweir                                              rFactoryParms );
2080*cdf0e10cSrcweir                     }
2081*cdf0e10cSrcweir                     break;
2082*cdf0e10cSrcweir 
2083*cdf0e10cSrcweir                     case META_POLYLINE_ACTION:
2084*cdf0e10cSrcweir                     {
2085*cdf0e10cSrcweir                         const OutDevState& rState( getState( rStates ) );
2086*cdf0e10cSrcweir                         if( rState.lineColor.getLength() ||
2087*cdf0e10cSrcweir                             rState.fillColor.getLength() )
2088*cdf0e10cSrcweir                         {
2089*cdf0e10cSrcweir                             MetaPolyLineAction* pPolyLineAct = static_cast<MetaPolyLineAction*>(pCurrAct);
2090*cdf0e10cSrcweir 
2091*cdf0e10cSrcweir                             const LineInfo& rLineInfo( pPolyLineAct->GetLineInfo() );
2092*cdf0e10cSrcweir                             ::basegfx::B2DPolygon aPoly( pPolyLineAct->GetPolygon().getB2DPolygon() );
2093*cdf0e10cSrcweir                             aPoly.transform( rState.mapModeTransform );
2094*cdf0e10cSrcweir 
2095*cdf0e10cSrcweir                             ActionSharedPtr pLineAction;
2096*cdf0e10cSrcweir 
2097*cdf0e10cSrcweir                             if( rLineInfo.IsDefault() )
2098*cdf0e10cSrcweir                             {
2099*cdf0e10cSrcweir                                 // plain hair line polygon
2100*cdf0e10cSrcweir                                 pLineAction =
2101*cdf0e10cSrcweir                                     internal::PolyPolyActionFactory::createLinePolyPolyAction(
2102*cdf0e10cSrcweir                                         ::basegfx::B2DPolyPolygon(aPoly),
2103*cdf0e10cSrcweir                                         rCanvas,
2104*cdf0e10cSrcweir                                         rState );
2105*cdf0e10cSrcweir 
2106*cdf0e10cSrcweir                                 if( pLineAction )
2107*cdf0e10cSrcweir                                 {
2108*cdf0e10cSrcweir                                     maActions.push_back(
2109*cdf0e10cSrcweir                                         MtfAction(
2110*cdf0e10cSrcweir                                             pLineAction,
2111*cdf0e10cSrcweir                                             io_rCurrActionIndex ) );
2112*cdf0e10cSrcweir 
2113*cdf0e10cSrcweir                                     io_rCurrActionIndex += pLineAction->getActionCount()-1;
2114*cdf0e10cSrcweir                                 }
2115*cdf0e10cSrcweir                             }
2116*cdf0e10cSrcweir                             else if( LINE_NONE != rLineInfo.GetStyle() )
2117*cdf0e10cSrcweir                             {
2118*cdf0e10cSrcweir                                 // 'thick' line polygon
2119*cdf0e10cSrcweir                                 rendering::StrokeAttributes aStrokeAttributes;
2120*cdf0e10cSrcweir 
2121*cdf0e10cSrcweir                                 setupStrokeAttributes( aStrokeAttributes,
2122*cdf0e10cSrcweir                                                        rFactoryParms,
2123*cdf0e10cSrcweir                                                        rLineInfo );
2124*cdf0e10cSrcweir 
2125*cdf0e10cSrcweir                                 pLineAction =
2126*cdf0e10cSrcweir                                     internal::PolyPolyActionFactory::createPolyPolyAction(
2127*cdf0e10cSrcweir                                         ::basegfx::B2DPolyPolygon(aPoly),
2128*cdf0e10cSrcweir                                         rCanvas,
2129*cdf0e10cSrcweir                                         rState,
2130*cdf0e10cSrcweir                                         aStrokeAttributes ) ;
2131*cdf0e10cSrcweir 
2132*cdf0e10cSrcweir                                 if( pLineAction )
2133*cdf0e10cSrcweir                                 {
2134*cdf0e10cSrcweir                                     maActions.push_back(
2135*cdf0e10cSrcweir                                         MtfAction(
2136*cdf0e10cSrcweir                                             pLineAction,
2137*cdf0e10cSrcweir                                             io_rCurrActionIndex ) );
2138*cdf0e10cSrcweir 
2139*cdf0e10cSrcweir                                     io_rCurrActionIndex += pLineAction->getActionCount()-1;
2140*cdf0e10cSrcweir                                 }
2141*cdf0e10cSrcweir                             }
2142*cdf0e10cSrcweir                             // else: line style is default
2143*cdf0e10cSrcweir                             // (i.e. invisible), don't generate action
2144*cdf0e10cSrcweir                         }
2145*cdf0e10cSrcweir                     }
2146*cdf0e10cSrcweir                     break;
2147*cdf0e10cSrcweir 
2148*cdf0e10cSrcweir                     case META_POLYGON_ACTION:
2149*cdf0e10cSrcweir                     {
2150*cdf0e10cSrcweir                         ::basegfx::B2DPolygon aPoly( static_cast<MetaPolygonAction*>(pCurrAct)->GetPolygon().getB2DPolygon() );
2151*cdf0e10cSrcweir                         aPoly.transform( getState( rStates ).mapModeTransform );
2152*cdf0e10cSrcweir                         createFillAndStroke( aPoly,
2153*cdf0e10cSrcweir                                              rFactoryParms );
2154*cdf0e10cSrcweir                     }
2155*cdf0e10cSrcweir                     break;
2156*cdf0e10cSrcweir 
2157*cdf0e10cSrcweir                     case META_POLYPOLYGON_ACTION:
2158*cdf0e10cSrcweir                     {
2159*cdf0e10cSrcweir                         ::basegfx::B2DPolyPolygon aPoly( static_cast<MetaPolyPolygonAction*>(pCurrAct)->GetPolyPolygon().getB2DPolyPolygon() );
2160*cdf0e10cSrcweir                         aPoly.transform( getState( rStates ).mapModeTransform );
2161*cdf0e10cSrcweir                         createFillAndStroke( aPoly,
2162*cdf0e10cSrcweir                                              rFactoryParms );
2163*cdf0e10cSrcweir                     }
2164*cdf0e10cSrcweir                     break;
2165*cdf0e10cSrcweir 
2166*cdf0e10cSrcweir                     case META_BMP_ACTION:
2167*cdf0e10cSrcweir                     {
2168*cdf0e10cSrcweir                         MetaBmpAction* pAct = static_cast<MetaBmpAction*>(pCurrAct);
2169*cdf0e10cSrcweir 
2170*cdf0e10cSrcweir                         ActionSharedPtr pBmpAction(
2171*cdf0e10cSrcweir                                 internal::BitmapActionFactory::createBitmapAction(
2172*cdf0e10cSrcweir                                     pAct->GetBitmap(),
2173*cdf0e10cSrcweir                                     getState( rStates ).mapModeTransform *
2174*cdf0e10cSrcweir                                     ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2175*cdf0e10cSrcweir                                     rCanvas,
2176*cdf0e10cSrcweir                                     getState( rStates ) ) );
2177*cdf0e10cSrcweir 
2178*cdf0e10cSrcweir                         if( pBmpAction )
2179*cdf0e10cSrcweir                         {
2180*cdf0e10cSrcweir                             maActions.push_back(
2181*cdf0e10cSrcweir                                 MtfAction(
2182*cdf0e10cSrcweir                                     pBmpAction,
2183*cdf0e10cSrcweir                                     io_rCurrActionIndex ) );
2184*cdf0e10cSrcweir 
2185*cdf0e10cSrcweir                             io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2186*cdf0e10cSrcweir                         }
2187*cdf0e10cSrcweir                     }
2188*cdf0e10cSrcweir                     break;
2189*cdf0e10cSrcweir 
2190*cdf0e10cSrcweir                     case META_BMPSCALE_ACTION:
2191*cdf0e10cSrcweir                     {
2192*cdf0e10cSrcweir                         MetaBmpScaleAction* pAct = static_cast<MetaBmpScaleAction*>(pCurrAct);
2193*cdf0e10cSrcweir 
2194*cdf0e10cSrcweir                         ActionSharedPtr pBmpAction(
2195*cdf0e10cSrcweir                                 internal::BitmapActionFactory::createBitmapAction(
2196*cdf0e10cSrcweir                                     pAct->GetBitmap(),
2197*cdf0e10cSrcweir                                     getState( rStates ).mapModeTransform *
2198*cdf0e10cSrcweir                                     ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2199*cdf0e10cSrcweir                                     getState( rStates ).mapModeTransform *
2200*cdf0e10cSrcweir                                     ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ),
2201*cdf0e10cSrcweir                                     rCanvas,
2202*cdf0e10cSrcweir                                     getState( rStates ) ) );
2203*cdf0e10cSrcweir 
2204*cdf0e10cSrcweir                         if( pBmpAction )
2205*cdf0e10cSrcweir                         {
2206*cdf0e10cSrcweir                             maActions.push_back(
2207*cdf0e10cSrcweir                                 MtfAction(
2208*cdf0e10cSrcweir                                     pBmpAction,
2209*cdf0e10cSrcweir                                     io_rCurrActionIndex ) );
2210*cdf0e10cSrcweir 
2211*cdf0e10cSrcweir                             io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2212*cdf0e10cSrcweir                         }
2213*cdf0e10cSrcweir                     }
2214*cdf0e10cSrcweir                     break;
2215*cdf0e10cSrcweir 
2216*cdf0e10cSrcweir                     case META_BMPSCALEPART_ACTION:
2217*cdf0e10cSrcweir                     {
2218*cdf0e10cSrcweir                         MetaBmpScalePartAction* pAct = static_cast<MetaBmpScalePartAction*>(pCurrAct);
2219*cdf0e10cSrcweir 
2220*cdf0e10cSrcweir                         // crop bitmap to given source rectangle (no
2221*cdf0e10cSrcweir                         // need to copy and convert the whole bitmap)
2222*cdf0e10cSrcweir                         Bitmap aBmp( pAct->GetBitmap() );
2223*cdf0e10cSrcweir                         const Rectangle aCropRect( pAct->GetSrcPoint(),
2224*cdf0e10cSrcweir                                                     pAct->GetSrcSize() );
2225*cdf0e10cSrcweir                         aBmp.Crop( aCropRect );
2226*cdf0e10cSrcweir 
2227*cdf0e10cSrcweir                         ActionSharedPtr pBmpAction(
2228*cdf0e10cSrcweir                                 internal::BitmapActionFactory::createBitmapAction(
2229*cdf0e10cSrcweir                                     aBmp,
2230*cdf0e10cSrcweir                                     getState( rStates ).mapModeTransform *
2231*cdf0e10cSrcweir                                     ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ),
2232*cdf0e10cSrcweir                                     getState( rStates ).mapModeTransform *
2233*cdf0e10cSrcweir                                     ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ),
2234*cdf0e10cSrcweir                                     rCanvas,
2235*cdf0e10cSrcweir                                     getState( rStates ) ) );
2236*cdf0e10cSrcweir 
2237*cdf0e10cSrcweir                         if( pBmpAction )
2238*cdf0e10cSrcweir                         {
2239*cdf0e10cSrcweir                             maActions.push_back(
2240*cdf0e10cSrcweir                                 MtfAction(
2241*cdf0e10cSrcweir                                     pBmpAction,
2242*cdf0e10cSrcweir                                     io_rCurrActionIndex ) );
2243*cdf0e10cSrcweir 
2244*cdf0e10cSrcweir                             io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2245*cdf0e10cSrcweir                         }
2246*cdf0e10cSrcweir                     }
2247*cdf0e10cSrcweir                     break;
2248*cdf0e10cSrcweir 
2249*cdf0e10cSrcweir                     case META_BMPEX_ACTION:
2250*cdf0e10cSrcweir                     {
2251*cdf0e10cSrcweir                         MetaBmpExAction* pAct = static_cast<MetaBmpExAction*>(pCurrAct);
2252*cdf0e10cSrcweir 
2253*cdf0e10cSrcweir                         ActionSharedPtr pBmpAction(
2254*cdf0e10cSrcweir                                 internal::BitmapActionFactory::createBitmapAction(
2255*cdf0e10cSrcweir                                     pAct->GetBitmapEx(),
2256*cdf0e10cSrcweir                                     getState( rStates ).mapModeTransform *
2257*cdf0e10cSrcweir                                     ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2258*cdf0e10cSrcweir                                     rCanvas,
2259*cdf0e10cSrcweir                                     getState( rStates ) ) );
2260*cdf0e10cSrcweir 
2261*cdf0e10cSrcweir                         if( pBmpAction )
2262*cdf0e10cSrcweir                         {
2263*cdf0e10cSrcweir                             maActions.push_back(
2264*cdf0e10cSrcweir                                 MtfAction(
2265*cdf0e10cSrcweir                                     pBmpAction,
2266*cdf0e10cSrcweir                                     io_rCurrActionIndex ) );
2267*cdf0e10cSrcweir 
2268*cdf0e10cSrcweir                             io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2269*cdf0e10cSrcweir                         }
2270*cdf0e10cSrcweir                     }
2271*cdf0e10cSrcweir                     break;
2272*cdf0e10cSrcweir 
2273*cdf0e10cSrcweir                     case META_BMPEXSCALE_ACTION:
2274*cdf0e10cSrcweir                     {
2275*cdf0e10cSrcweir                         MetaBmpExScaleAction* pAct = static_cast<MetaBmpExScaleAction*>(pCurrAct);
2276*cdf0e10cSrcweir 
2277*cdf0e10cSrcweir                         ActionSharedPtr pBmpAction(
2278*cdf0e10cSrcweir                                 internal::BitmapActionFactory::createBitmapAction(
2279*cdf0e10cSrcweir                                     pAct->GetBitmapEx(),
2280*cdf0e10cSrcweir                                     getState( rStates ).mapModeTransform *
2281*cdf0e10cSrcweir                                     ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2282*cdf0e10cSrcweir                                     getState( rStates ).mapModeTransform *
2283*cdf0e10cSrcweir                                     ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ),
2284*cdf0e10cSrcweir                                     rCanvas,
2285*cdf0e10cSrcweir                                     getState( rStates ) ) );
2286*cdf0e10cSrcweir 
2287*cdf0e10cSrcweir                         if( pBmpAction )
2288*cdf0e10cSrcweir                         {
2289*cdf0e10cSrcweir                             maActions.push_back(
2290*cdf0e10cSrcweir                                 MtfAction(
2291*cdf0e10cSrcweir                                     pBmpAction,
2292*cdf0e10cSrcweir                                     io_rCurrActionIndex ) );
2293*cdf0e10cSrcweir 
2294*cdf0e10cSrcweir                             io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2295*cdf0e10cSrcweir                         }
2296*cdf0e10cSrcweir                     }
2297*cdf0e10cSrcweir                     break;
2298*cdf0e10cSrcweir 
2299*cdf0e10cSrcweir                     case META_BMPEXSCALEPART_ACTION:
2300*cdf0e10cSrcweir                     {
2301*cdf0e10cSrcweir                         MetaBmpExScalePartAction* pAct = static_cast<MetaBmpExScalePartAction*>(pCurrAct);
2302*cdf0e10cSrcweir 
2303*cdf0e10cSrcweir                         // crop bitmap to given source rectangle (no
2304*cdf0e10cSrcweir                         // need to copy and convert the whole bitmap)
2305*cdf0e10cSrcweir                         BitmapEx aBmp( pAct->GetBitmapEx() );
2306*cdf0e10cSrcweir                         const Rectangle aCropRect( pAct->GetSrcPoint(),
2307*cdf0e10cSrcweir                                                    pAct->GetSrcSize() );
2308*cdf0e10cSrcweir                         aBmp.Crop( aCropRect );
2309*cdf0e10cSrcweir 
2310*cdf0e10cSrcweir                         ActionSharedPtr pBmpAction(
2311*cdf0e10cSrcweir                             internal::BitmapActionFactory::createBitmapAction(
2312*cdf0e10cSrcweir                                 aBmp,
2313*cdf0e10cSrcweir                                 getState( rStates ).mapModeTransform *
2314*cdf0e10cSrcweir                                 ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ),
2315*cdf0e10cSrcweir                                 getState( rStates ).mapModeTransform *
2316*cdf0e10cSrcweir                                 ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ),
2317*cdf0e10cSrcweir                                 rCanvas,
2318*cdf0e10cSrcweir                                 getState( rStates ) ) );
2319*cdf0e10cSrcweir 
2320*cdf0e10cSrcweir                         if( pBmpAction )
2321*cdf0e10cSrcweir                         {
2322*cdf0e10cSrcweir                             maActions.push_back(
2323*cdf0e10cSrcweir                                 MtfAction(
2324*cdf0e10cSrcweir                                     pBmpAction,
2325*cdf0e10cSrcweir                                     io_rCurrActionIndex ) );
2326*cdf0e10cSrcweir 
2327*cdf0e10cSrcweir                             io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2328*cdf0e10cSrcweir                         }
2329*cdf0e10cSrcweir                     }
2330*cdf0e10cSrcweir                     break;
2331*cdf0e10cSrcweir 
2332*cdf0e10cSrcweir                     case META_MASK_ACTION:
2333*cdf0e10cSrcweir                     {
2334*cdf0e10cSrcweir                         MetaMaskAction* pAct = static_cast<MetaMaskAction*>(pCurrAct);
2335*cdf0e10cSrcweir 
2336*cdf0e10cSrcweir                         // create masked BitmapEx right here, as the
2337*cdf0e10cSrcweir                         // canvas does not provide equivalent
2338*cdf0e10cSrcweir                         // functionality
2339*cdf0e10cSrcweir                         BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(),
2340*cdf0e10cSrcweir                                                         pAct->GetColor() ));
2341*cdf0e10cSrcweir 
2342*cdf0e10cSrcweir                         ActionSharedPtr pBmpAction(
2343*cdf0e10cSrcweir                             internal::BitmapActionFactory::createBitmapAction(
2344*cdf0e10cSrcweir                                 aBmp,
2345*cdf0e10cSrcweir                                 getState( rStates ).mapModeTransform *
2346*cdf0e10cSrcweir                                 ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2347*cdf0e10cSrcweir                                 rCanvas,
2348*cdf0e10cSrcweir                                 getState( rStates ) ) );
2349*cdf0e10cSrcweir 
2350*cdf0e10cSrcweir                         if( pBmpAction )
2351*cdf0e10cSrcweir                         {
2352*cdf0e10cSrcweir                             maActions.push_back(
2353*cdf0e10cSrcweir                                 MtfAction(
2354*cdf0e10cSrcweir                                     pBmpAction,
2355*cdf0e10cSrcweir                                     io_rCurrActionIndex ) );
2356*cdf0e10cSrcweir 
2357*cdf0e10cSrcweir                             io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2358*cdf0e10cSrcweir                         }
2359*cdf0e10cSrcweir                     }
2360*cdf0e10cSrcweir                     break;
2361*cdf0e10cSrcweir 
2362*cdf0e10cSrcweir                     case META_MASKSCALE_ACTION:
2363*cdf0e10cSrcweir                     {
2364*cdf0e10cSrcweir                         MetaMaskScaleAction* pAct = static_cast<MetaMaskScaleAction*>(pCurrAct);
2365*cdf0e10cSrcweir 
2366*cdf0e10cSrcweir                         // create masked BitmapEx right here, as the
2367*cdf0e10cSrcweir                         // canvas does not provide equivalent
2368*cdf0e10cSrcweir                         // functionality
2369*cdf0e10cSrcweir                         BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(),
2370*cdf0e10cSrcweir                                                         pAct->GetColor() ));
2371*cdf0e10cSrcweir 
2372*cdf0e10cSrcweir                         ActionSharedPtr pBmpAction(
2373*cdf0e10cSrcweir                             internal::BitmapActionFactory::createBitmapAction(
2374*cdf0e10cSrcweir                                 aBmp,
2375*cdf0e10cSrcweir                                 getState( rStates ).mapModeTransform *
2376*cdf0e10cSrcweir                                 ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2377*cdf0e10cSrcweir                                 getState( rStates ).mapModeTransform *
2378*cdf0e10cSrcweir                                 ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ),
2379*cdf0e10cSrcweir                                 rCanvas,
2380*cdf0e10cSrcweir                                 getState( rStates ) ) );
2381*cdf0e10cSrcweir 
2382*cdf0e10cSrcweir                         if( pBmpAction )
2383*cdf0e10cSrcweir                         {
2384*cdf0e10cSrcweir                             maActions.push_back(
2385*cdf0e10cSrcweir                                 MtfAction(
2386*cdf0e10cSrcweir                                     pBmpAction,
2387*cdf0e10cSrcweir                                     io_rCurrActionIndex ) );
2388*cdf0e10cSrcweir 
2389*cdf0e10cSrcweir                             io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2390*cdf0e10cSrcweir                         }
2391*cdf0e10cSrcweir                     }
2392*cdf0e10cSrcweir                     break;
2393*cdf0e10cSrcweir 
2394*cdf0e10cSrcweir                     case META_MASKSCALEPART_ACTION:
2395*cdf0e10cSrcweir                     {
2396*cdf0e10cSrcweir                         MetaMaskScalePartAction* pAct = static_cast<MetaMaskScalePartAction*>(pCurrAct);
2397*cdf0e10cSrcweir 
2398*cdf0e10cSrcweir                         // create masked BitmapEx right here, as the
2399*cdf0e10cSrcweir                         // canvas does not provide equivalent
2400*cdf0e10cSrcweir                         // functionality
2401*cdf0e10cSrcweir                         BitmapEx aBmp( createMaskBmpEx( pAct->GetBitmap(),
2402*cdf0e10cSrcweir                                                         pAct->GetColor() ));
2403*cdf0e10cSrcweir 
2404*cdf0e10cSrcweir                         // crop bitmap to given source rectangle (no
2405*cdf0e10cSrcweir                         // need to copy and convert the whole bitmap)
2406*cdf0e10cSrcweir                         const Rectangle aCropRect( pAct->GetSrcPoint(),
2407*cdf0e10cSrcweir                                                    pAct->GetSrcSize() );
2408*cdf0e10cSrcweir                         aBmp.Crop( aCropRect );
2409*cdf0e10cSrcweir 
2410*cdf0e10cSrcweir                         ActionSharedPtr pBmpAction(
2411*cdf0e10cSrcweir                             internal::BitmapActionFactory::createBitmapAction(
2412*cdf0e10cSrcweir                                 aBmp,
2413*cdf0e10cSrcweir                                 getState( rStates ).mapModeTransform *
2414*cdf0e10cSrcweir                                 ::vcl::unotools::b2DPointFromPoint( pAct->GetDestPoint() ),
2415*cdf0e10cSrcweir                                 getState( rStates ).mapModeTransform *
2416*cdf0e10cSrcweir                                 ::vcl::unotools::b2DSizeFromSize( pAct->GetDestSize() ),
2417*cdf0e10cSrcweir                                 rCanvas,
2418*cdf0e10cSrcweir                                 getState( rStates ) ) );
2419*cdf0e10cSrcweir 
2420*cdf0e10cSrcweir                         if( pBmpAction )
2421*cdf0e10cSrcweir                         {
2422*cdf0e10cSrcweir                             maActions.push_back(
2423*cdf0e10cSrcweir                                 MtfAction(
2424*cdf0e10cSrcweir                                     pBmpAction,
2425*cdf0e10cSrcweir                                     io_rCurrActionIndex ) );
2426*cdf0e10cSrcweir 
2427*cdf0e10cSrcweir                             io_rCurrActionIndex += pBmpAction->getActionCount()-1;
2428*cdf0e10cSrcweir                         }
2429*cdf0e10cSrcweir                     }
2430*cdf0e10cSrcweir                     break;
2431*cdf0e10cSrcweir 
2432*cdf0e10cSrcweir                     case META_GRADIENTEX_ACTION:
2433*cdf0e10cSrcweir                         // TODO(F1): use native Canvas gradients here
2434*cdf0e10cSrcweir                         // action is ignored here, because redundant to META_GRADIENT_ACTION
2435*cdf0e10cSrcweir                         break;
2436*cdf0e10cSrcweir 
2437*cdf0e10cSrcweir                     case META_WALLPAPER_ACTION:
2438*cdf0e10cSrcweir                         // TODO(F2): NYI
2439*cdf0e10cSrcweir                         break;
2440*cdf0e10cSrcweir 
2441*cdf0e10cSrcweir                     case META_TRANSPARENT_ACTION:
2442*cdf0e10cSrcweir                     {
2443*cdf0e10cSrcweir                         const OutDevState& rState( getState( rStates ) );
2444*cdf0e10cSrcweir                         if( rState.lineColor.getLength() ||
2445*cdf0e10cSrcweir                             rState.fillColor.getLength() )
2446*cdf0e10cSrcweir                         {
2447*cdf0e10cSrcweir                             MetaTransparentAction* pAct = static_cast<MetaTransparentAction*>(pCurrAct);
2448*cdf0e10cSrcweir                             ::basegfx::B2DPolyPolygon aPoly( pAct->GetPolyPolygon().getB2DPolyPolygon() );
2449*cdf0e10cSrcweir                             aPoly.transform( rState.mapModeTransform );
2450*cdf0e10cSrcweir 
2451*cdf0e10cSrcweir                             ActionSharedPtr pPolyAction(
2452*cdf0e10cSrcweir                                 internal::PolyPolyActionFactory::createPolyPolyAction(
2453*cdf0e10cSrcweir                                     aPoly,
2454*cdf0e10cSrcweir                                     rCanvas,
2455*cdf0e10cSrcweir                                     rState,
2456*cdf0e10cSrcweir                                     pAct->GetTransparence() ) );
2457*cdf0e10cSrcweir 
2458*cdf0e10cSrcweir                             if( pPolyAction )
2459*cdf0e10cSrcweir                             {
2460*cdf0e10cSrcweir                                 maActions.push_back(
2461*cdf0e10cSrcweir                                     MtfAction(
2462*cdf0e10cSrcweir                                         pPolyAction,
2463*cdf0e10cSrcweir                                         io_rCurrActionIndex ) );
2464*cdf0e10cSrcweir 
2465*cdf0e10cSrcweir                                 io_rCurrActionIndex += pPolyAction->getActionCount()-1;
2466*cdf0e10cSrcweir                             }
2467*cdf0e10cSrcweir                         }
2468*cdf0e10cSrcweir                     }
2469*cdf0e10cSrcweir                     break;
2470*cdf0e10cSrcweir 
2471*cdf0e10cSrcweir                     case META_FLOATTRANSPARENT_ACTION:
2472*cdf0e10cSrcweir                     {
2473*cdf0e10cSrcweir                         MetaFloatTransparentAction* pAct = static_cast<MetaFloatTransparentAction*>(pCurrAct);
2474*cdf0e10cSrcweir 
2475*cdf0e10cSrcweir                         internal::MtfAutoPtr pMtf(
2476*cdf0e10cSrcweir                             new ::GDIMetaFile( pAct->GetGDIMetaFile() ) );
2477*cdf0e10cSrcweir 
2478*cdf0e10cSrcweir                         // TODO(P2): Use native canvas gradients here (saves a lot of UNO calls)
2479*cdf0e10cSrcweir                         internal::GradientAutoPtr pGradient(
2480*cdf0e10cSrcweir                             new Gradient( pAct->GetGradient() ) );
2481*cdf0e10cSrcweir 
2482*cdf0e10cSrcweir                         DBG_TESTSOLARMUTEX();
2483*cdf0e10cSrcweir 
2484*cdf0e10cSrcweir                         ActionSharedPtr pFloatTransAction(
2485*cdf0e10cSrcweir                             internal::TransparencyGroupActionFactory::createTransparencyGroupAction(
2486*cdf0e10cSrcweir                                 pMtf,
2487*cdf0e10cSrcweir                                 pGradient,
2488*cdf0e10cSrcweir                                 rParms,
2489*cdf0e10cSrcweir                                 getState( rStates ).mapModeTransform *
2490*cdf0e10cSrcweir                                 ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2491*cdf0e10cSrcweir                                 getState( rStates ).mapModeTransform *
2492*cdf0e10cSrcweir                                 ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ),
2493*cdf0e10cSrcweir                                 rCanvas,
2494*cdf0e10cSrcweir                                 getState( rStates ) ) );
2495*cdf0e10cSrcweir 
2496*cdf0e10cSrcweir                         if( pFloatTransAction )
2497*cdf0e10cSrcweir                         {
2498*cdf0e10cSrcweir                             maActions.push_back(
2499*cdf0e10cSrcweir                                 MtfAction(
2500*cdf0e10cSrcweir                                     pFloatTransAction,
2501*cdf0e10cSrcweir                                     io_rCurrActionIndex ) );
2502*cdf0e10cSrcweir 
2503*cdf0e10cSrcweir                             io_rCurrActionIndex += pFloatTransAction->getActionCount()-1;
2504*cdf0e10cSrcweir                         }
2505*cdf0e10cSrcweir                     }
2506*cdf0e10cSrcweir                     break;
2507*cdf0e10cSrcweir 
2508*cdf0e10cSrcweir                     case META_TEXT_ACTION:
2509*cdf0e10cSrcweir                     {
2510*cdf0e10cSrcweir                         MetaTextAction* pAct = static_cast<MetaTextAction*>(pCurrAct);
2511*cdf0e10cSrcweir                         XubString sText = XubString( pAct->GetText() );
2512*cdf0e10cSrcweir 
2513*cdf0e10cSrcweir                         if( rVDev.GetDigitLanguage())
2514*cdf0e10cSrcweir                             convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() );
2515*cdf0e10cSrcweir 
2516*cdf0e10cSrcweir                         createTextAction(
2517*cdf0e10cSrcweir                             pAct->GetPoint(),
2518*cdf0e10cSrcweir                             sText,
2519*cdf0e10cSrcweir                             pAct->GetIndex(),
2520*cdf0e10cSrcweir                             pAct->GetLen() == (sal_uInt16)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(),
2521*cdf0e10cSrcweir                             NULL,
2522*cdf0e10cSrcweir                             rFactoryParms,
2523*cdf0e10cSrcweir                             bSubsettableActions );
2524*cdf0e10cSrcweir                     }
2525*cdf0e10cSrcweir                     break;
2526*cdf0e10cSrcweir 
2527*cdf0e10cSrcweir                     case META_TEXTARRAY_ACTION:
2528*cdf0e10cSrcweir                     {
2529*cdf0e10cSrcweir                         MetaTextArrayAction* pAct = static_cast<MetaTextArrayAction*>(pCurrAct);
2530*cdf0e10cSrcweir                         XubString sText = XubString( pAct->GetText() );
2531*cdf0e10cSrcweir 
2532*cdf0e10cSrcweir                         if( rVDev.GetDigitLanguage())
2533*cdf0e10cSrcweir                             convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() );
2534*cdf0e10cSrcweir 
2535*cdf0e10cSrcweir                         createTextAction(
2536*cdf0e10cSrcweir                             pAct->GetPoint(),
2537*cdf0e10cSrcweir                             sText,
2538*cdf0e10cSrcweir                             pAct->GetIndex(),
2539*cdf0e10cSrcweir                             pAct->GetLen() == (sal_uInt16)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(),
2540*cdf0e10cSrcweir                             pAct->GetDXArray(),
2541*cdf0e10cSrcweir                             rFactoryParms,
2542*cdf0e10cSrcweir                             bSubsettableActions );
2543*cdf0e10cSrcweir                     }
2544*cdf0e10cSrcweir                     break;
2545*cdf0e10cSrcweir 
2546*cdf0e10cSrcweir                     case META_TEXTLINE_ACTION:
2547*cdf0e10cSrcweir                     {
2548*cdf0e10cSrcweir                         MetaTextLineAction*      pAct = static_cast<MetaTextLineAction*>(pCurrAct);
2549*cdf0e10cSrcweir 
2550*cdf0e10cSrcweir                         const OutDevState&       rState( getState( rStates ) );
2551*cdf0e10cSrcweir                         const ::Size             aBaselineOffset( tools::getBaselineOffset( rState,
2552*cdf0e10cSrcweir                                                                                             rVDev ) );
2553*cdf0e10cSrcweir                         const ::Point 		     aStartPoint( pAct->GetStartPoint() );
2554*cdf0e10cSrcweir                         const ::basegfx::B2DSize aSize( rState.mapModeTransform *
2555*cdf0e10cSrcweir                                                         ::basegfx::B2DSize(pAct->GetWidth(),
2556*cdf0e10cSrcweir                                                                            0 ));
2557*cdf0e10cSrcweir 
2558*cdf0e10cSrcweir                         ActionSharedPtr pPolyAction(
2559*cdf0e10cSrcweir                             PolyPolyActionFactory::createPolyPolyAction(
2560*cdf0e10cSrcweir                                 tools::createTextLinesPolyPolygon(
2561*cdf0e10cSrcweir                                     rState.mapModeTransform *
2562*cdf0e10cSrcweir                                     ::basegfx::B2DPoint(
2563*cdf0e10cSrcweir                                         ::vcl::unotools::b2DPointFromPoint(pAct->GetStartPoint()) +
2564*cdf0e10cSrcweir                                         ::vcl::unotools::b2DSizeFromSize(aBaselineOffset)),
2565*cdf0e10cSrcweir                                     aSize.getX(),
2566*cdf0e10cSrcweir                                     tools::createTextLineInfo( rVDev,
2567*cdf0e10cSrcweir                                                                rState )),
2568*cdf0e10cSrcweir                                 rCanvas,
2569*cdf0e10cSrcweir                                 rState ) );
2570*cdf0e10cSrcweir 
2571*cdf0e10cSrcweir                         if( pPolyAction.get() )
2572*cdf0e10cSrcweir                         {
2573*cdf0e10cSrcweir                             maActions.push_back(
2574*cdf0e10cSrcweir                                 MtfAction(
2575*cdf0e10cSrcweir                                     pPolyAction,
2576*cdf0e10cSrcweir                                     io_rCurrActionIndex ) );
2577*cdf0e10cSrcweir 
2578*cdf0e10cSrcweir                             io_rCurrActionIndex += pPolyAction->getActionCount()-1;
2579*cdf0e10cSrcweir                         }
2580*cdf0e10cSrcweir                     }
2581*cdf0e10cSrcweir                     break;
2582*cdf0e10cSrcweir 
2583*cdf0e10cSrcweir                     case META_TEXTRECT_ACTION:
2584*cdf0e10cSrcweir                     {
2585*cdf0e10cSrcweir                         MetaTextRectAction* pAct = static_cast<MetaTextRectAction*>(pCurrAct);
2586*cdf0e10cSrcweir 
2587*cdf0e10cSrcweir                         pushState( rStates, PUSH_ALL );
2588*cdf0e10cSrcweir 
2589*cdf0e10cSrcweir                         // use the VDev to break up the text rect
2590*cdf0e10cSrcweir                         // action into readily formatted lines
2591*cdf0e10cSrcweir                         GDIMetaFile aTmpMtf;
2592*cdf0e10cSrcweir                         rVDev.AddTextRectActions( pAct->GetRect(),
2593*cdf0e10cSrcweir                                                   pAct->GetText(),
2594*cdf0e10cSrcweir                                                   pAct->GetStyle(),
2595*cdf0e10cSrcweir                                                   aTmpMtf );
2596*cdf0e10cSrcweir 
2597*cdf0e10cSrcweir                         createActions( aTmpMtf,
2598*cdf0e10cSrcweir                                        rFactoryParms,
2599*cdf0e10cSrcweir                                        bSubsettableActions );
2600*cdf0e10cSrcweir 
2601*cdf0e10cSrcweir                         popState( rStates );
2602*cdf0e10cSrcweir 
2603*cdf0e10cSrcweir                         break;
2604*cdf0e10cSrcweir                     }
2605*cdf0e10cSrcweir 
2606*cdf0e10cSrcweir                     case META_STRETCHTEXT_ACTION:
2607*cdf0e10cSrcweir                     {
2608*cdf0e10cSrcweir                         MetaStretchTextAction* pAct = static_cast<MetaStretchTextAction*>(pCurrAct);
2609*cdf0e10cSrcweir                         XubString sText = XubString( pAct->GetText() );
2610*cdf0e10cSrcweir 
2611*cdf0e10cSrcweir                         if( rVDev.GetDigitLanguage())
2612*cdf0e10cSrcweir                             convertToLocalizedNumerals ( sText,rVDev.GetDigitLanguage() );
2613*cdf0e10cSrcweir 
2614*cdf0e10cSrcweir                         const sal_uInt16 nLen( pAct->GetLen() == (sal_uInt16)STRING_LEN ?
2615*cdf0e10cSrcweir                                            pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen() );
2616*cdf0e10cSrcweir 
2617*cdf0e10cSrcweir                         // #i70897# Nothing to do, actually...
2618*cdf0e10cSrcweir                         if( nLen == 0 )
2619*cdf0e10cSrcweir                             break;
2620*cdf0e10cSrcweir 
2621*cdf0e10cSrcweir                         // have to fit the text into the given
2622*cdf0e10cSrcweir                         // width. This is achieved by internally
2623*cdf0e10cSrcweir                         // generating a DX array, and uniformly
2624*cdf0e10cSrcweir                         // distributing the excess/insufficient width
2625*cdf0e10cSrcweir                         // to every logical character.
2626*cdf0e10cSrcweir                         ::boost::scoped_array< sal_Int32 > pDXArray( new sal_Int32[nLen] );
2627*cdf0e10cSrcweir 
2628*cdf0e10cSrcweir                         rVDev.GetTextArray( pAct->GetText(), pDXArray.get(),
2629*cdf0e10cSrcweir                                             pAct->GetIndex(), pAct->GetLen() );
2630*cdf0e10cSrcweir 
2631*cdf0e10cSrcweir                         const sal_Int32 nWidthDifference( pAct->GetWidth() - pDXArray[ nLen-1 ] );
2632*cdf0e10cSrcweir 
2633*cdf0e10cSrcweir                         // Last entry of pDXArray contains total width of the text
2634*cdf0e10cSrcweir                         sal_Int32* p=pDXArray.get();
2635*cdf0e10cSrcweir                         for( sal_uInt16 i=1; i<=nLen; ++i )
2636*cdf0e10cSrcweir                         {
2637*cdf0e10cSrcweir                             // calc ratio for every array entry, to
2638*cdf0e10cSrcweir                             // distribute rounding errors 'evenly'
2639*cdf0e10cSrcweir                             // across the characters. Note that each
2640*cdf0e10cSrcweir                             // entry represents the 'end' position of
2641*cdf0e10cSrcweir                             // the corresponding character, thus, we
2642*cdf0e10cSrcweir                             // let i run from 1 to nLen.
2643*cdf0e10cSrcweir                             *p++ += (sal_Int32)i*nWidthDifference/nLen;
2644*cdf0e10cSrcweir                         }
2645*cdf0e10cSrcweir 
2646*cdf0e10cSrcweir                         createTextAction(
2647*cdf0e10cSrcweir                             pAct->GetPoint(),
2648*cdf0e10cSrcweir                             sText,
2649*cdf0e10cSrcweir                             pAct->GetIndex(),
2650*cdf0e10cSrcweir                             pAct->GetLen() == (sal_uInt16)STRING_LEN ? pAct->GetText().Len() - pAct->GetIndex() : pAct->GetLen(),
2651*cdf0e10cSrcweir                             pDXArray.get(),
2652*cdf0e10cSrcweir                             rFactoryParms,
2653*cdf0e10cSrcweir                             bSubsettableActions );
2654*cdf0e10cSrcweir                     }
2655*cdf0e10cSrcweir                     break;
2656*cdf0e10cSrcweir 
2657*cdf0e10cSrcweir                     case META_RENDERGRAPHIC_ACTION:
2658*cdf0e10cSrcweir                     {
2659*cdf0e10cSrcweir                         MetaRenderGraphicAction* pAct = static_cast<MetaRenderGraphicAction*>(pCurrAct);
2660*cdf0e10cSrcweir 
2661*cdf0e10cSrcweir                         ActionSharedPtr pRenderGraphicAction(
2662*cdf0e10cSrcweir                                 internal::RenderGraphicActionFactory::createRenderGraphicAction(
2663*cdf0e10cSrcweir                                     pAct->GetRenderGraphic(),
2664*cdf0e10cSrcweir                                     getState( rStates ).mapModeTransform *
2665*cdf0e10cSrcweir                                     ::vcl::unotools::b2DPointFromPoint( pAct->GetPoint() ),
2666*cdf0e10cSrcweir                                     getState( rStates ).mapModeTransform *
2667*cdf0e10cSrcweir                                     ::vcl::unotools::b2DSizeFromSize( pAct->GetSize() ),
2668*cdf0e10cSrcweir                                     rCanvas,
2669*cdf0e10cSrcweir                                     getState( rStates ) ) );
2670*cdf0e10cSrcweir 
2671*cdf0e10cSrcweir                         if( pRenderGraphicAction )
2672*cdf0e10cSrcweir                         {
2673*cdf0e10cSrcweir                             maActions.push_back(
2674*cdf0e10cSrcweir                                 MtfAction(
2675*cdf0e10cSrcweir                                     pRenderGraphicAction,
2676*cdf0e10cSrcweir                                     io_rCurrActionIndex ) );
2677*cdf0e10cSrcweir 
2678*cdf0e10cSrcweir                             io_rCurrActionIndex += pRenderGraphicAction->getActionCount()-1;
2679*cdf0e10cSrcweir                         }
2680*cdf0e10cSrcweir                     }
2681*cdf0e10cSrcweir                     break;
2682*cdf0e10cSrcweir 
2683*cdf0e10cSrcweir                     default:
2684*cdf0e10cSrcweir                         OSL_ENSURE( false,
2685*cdf0e10cSrcweir                                     "Unknown meta action type encountered" );
2686*cdf0e10cSrcweir                         break;
2687*cdf0e10cSrcweir                 }
2688*cdf0e10cSrcweir 
2689*cdf0e10cSrcweir                 // increment action index (each mtf action counts _at
2690*cdf0e10cSrcweir                 // least_ one. Some count for more, therefore,
2691*cdf0e10cSrcweir                 // io_rCurrActionIndex is sometimes incremented by
2692*cdf0e10cSrcweir                 // pAct->getActionCount()-1 above, the -1 being the
2693*cdf0e10cSrcweir                 // correction for the unconditional increment here).
2694*cdf0e10cSrcweir                 ++io_rCurrActionIndex;
2695*cdf0e10cSrcweir             }
2696*cdf0e10cSrcweir 
2697*cdf0e10cSrcweir             return true;
2698*cdf0e10cSrcweir         }
2699*cdf0e10cSrcweir 
2700*cdf0e10cSrcweir 
2701*cdf0e10cSrcweir         namespace
2702*cdf0e10cSrcweir         {
2703*cdf0e10cSrcweir             class ActionRenderer
2704*cdf0e10cSrcweir             {
2705*cdf0e10cSrcweir             public:
2706*cdf0e10cSrcweir                 ActionRenderer( const ::basegfx::B2DHomMatrix& rTransformation ) :
2707*cdf0e10cSrcweir                     maTransformation( rTransformation ),
2708*cdf0e10cSrcweir                     mbRet( true )
2709*cdf0e10cSrcweir                 {
2710*cdf0e10cSrcweir                 }
2711*cdf0e10cSrcweir 
2712*cdf0e10cSrcweir                 bool result()
2713*cdf0e10cSrcweir                 {
2714*cdf0e10cSrcweir                     return mbRet;
2715*cdf0e10cSrcweir                 }
2716*cdf0e10cSrcweir 
2717*cdf0e10cSrcweir                 void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction )
2718*cdf0e10cSrcweir                 {
2719*cdf0e10cSrcweir                     // ANDing the result. We want to fail if at least
2720*cdf0e10cSrcweir                     // one action failed.
2721*cdf0e10cSrcweir                     mbRet &= rAction.mpAction->render( maTransformation );
2722*cdf0e10cSrcweir                 }
2723*cdf0e10cSrcweir 
2724*cdf0e10cSrcweir                 void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction&	rAction,
2725*cdf0e10cSrcweir                                  const Action::Subset&									rSubset )
2726*cdf0e10cSrcweir                 {
2727*cdf0e10cSrcweir                     // ANDing the result. We want to fail if at least
2728*cdf0e10cSrcweir                     // one action failed.
2729*cdf0e10cSrcweir                     mbRet &= rAction.mpAction->render( maTransformation,
2730*cdf0e10cSrcweir                                                        rSubset );
2731*cdf0e10cSrcweir                 }
2732*cdf0e10cSrcweir 
2733*cdf0e10cSrcweir             private:
2734*cdf0e10cSrcweir                 ::basegfx::B2DHomMatrix	maTransformation;
2735*cdf0e10cSrcweir                 bool					mbRet;
2736*cdf0e10cSrcweir             };
2737*cdf0e10cSrcweir 
2738*cdf0e10cSrcweir             class AreaQuery
2739*cdf0e10cSrcweir             {
2740*cdf0e10cSrcweir             public:
2741*cdf0e10cSrcweir                 AreaQuery( const ::basegfx::B2DHomMatrix& rTransformation ) :
2742*cdf0e10cSrcweir                     maTransformation( rTransformation ),
2743*cdf0e10cSrcweir                     maBounds()
2744*cdf0e10cSrcweir                 {
2745*cdf0e10cSrcweir                 }
2746*cdf0e10cSrcweir 
2747*cdf0e10cSrcweir                 bool result()
2748*cdf0e10cSrcweir                 {
2749*cdf0e10cSrcweir                     return true; // nothing can fail here
2750*cdf0e10cSrcweir                 }
2751*cdf0e10cSrcweir 
2752*cdf0e10cSrcweir                 void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rAction )
2753*cdf0e10cSrcweir                 {
2754*cdf0e10cSrcweir                     maBounds.expand( rAction.mpAction->getBounds( maTransformation ) );
2755*cdf0e10cSrcweir                 }
2756*cdf0e10cSrcweir 
2757*cdf0e10cSrcweir                 void operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction&	rAction,
2758*cdf0e10cSrcweir                                  const Action::Subset&									rSubset )
2759*cdf0e10cSrcweir                 {
2760*cdf0e10cSrcweir                     maBounds.expand( rAction.mpAction->getBounds( maTransformation,
2761*cdf0e10cSrcweir                                                                   rSubset ) );
2762*cdf0e10cSrcweir                 }
2763*cdf0e10cSrcweir 
2764*cdf0e10cSrcweir                 ::basegfx::B2DRange getBounds() const
2765*cdf0e10cSrcweir                 {
2766*cdf0e10cSrcweir                     return maBounds;
2767*cdf0e10cSrcweir                 }
2768*cdf0e10cSrcweir 
2769*cdf0e10cSrcweir             private:
2770*cdf0e10cSrcweir                 ::basegfx::B2DHomMatrix	maTransformation;
2771*cdf0e10cSrcweir                 ::basegfx::B2DRange		maBounds;
2772*cdf0e10cSrcweir             };
2773*cdf0e10cSrcweir 
2774*cdf0e10cSrcweir             // Doing that via inline class. Compilers tend to not inline free
2775*cdf0e10cSrcweir             // functions.
2776*cdf0e10cSrcweir             struct UpperBoundActionIndexComparator
2777*cdf0e10cSrcweir             {
2778*cdf0e10cSrcweir                 bool operator()( const ::cppcanvas::internal::ImplRenderer::MtfAction& rLHS,
2779*cdf0e10cSrcweir                                  const ::cppcanvas::internal::ImplRenderer::MtfAction& rRHS )
2780*cdf0e10cSrcweir                 {
2781*cdf0e10cSrcweir                     const sal_Int32 nLHSCount( rLHS.mpAction ?
2782*cdf0e10cSrcweir                                                rLHS.mpAction->getActionCount() : 0 );
2783*cdf0e10cSrcweir                     const sal_Int32 nRHSCount( rRHS.mpAction ?
2784*cdf0e10cSrcweir                                                rRHS.mpAction->getActionCount() : 0 );
2785*cdf0e10cSrcweir 
2786*cdf0e10cSrcweir                     // compare end of action range, to have an action selected
2787*cdf0e10cSrcweir                     // by lower_bound even if the requested index points in
2788*cdf0e10cSrcweir                     // the middle of the action's range
2789*cdf0e10cSrcweir                     return rLHS.mnOrigIndex + nLHSCount < rRHS.mnOrigIndex + nRHSCount;
2790*cdf0e10cSrcweir                 }
2791*cdf0e10cSrcweir             };
2792*cdf0e10cSrcweir 
2793*cdf0e10cSrcweir             /** Algorithm to apply given functor to a subset range
2794*cdf0e10cSrcweir 
2795*cdf0e10cSrcweir             	@tpl Functor
2796*cdf0e10cSrcweir 
2797*cdf0e10cSrcweir                 Functor to call for each element of the subset
2798*cdf0e10cSrcweir                 range. Must provide the following method signatures:
2799*cdf0e10cSrcweir                 bool result() (returning false if operation failed)
2800*cdf0e10cSrcweir 
2801*cdf0e10cSrcweir              */
2802*cdf0e10cSrcweir             template< typename Functor > bool
2803*cdf0e10cSrcweir             	forSubsetRange( Functor& 											rFunctor,
2804*cdf0e10cSrcweir                                 ImplRenderer::ActionVector::const_iterator			aRangeBegin,
2805*cdf0e10cSrcweir                                 ImplRenderer::ActionVector::const_iterator			aRangeEnd,
2806*cdf0e10cSrcweir                                 sal_Int32											nStartIndex,
2807*cdf0e10cSrcweir                                 sal_Int32											nEndIndex,
2808*cdf0e10cSrcweir                                 const ImplRenderer::ActionVector::const_iterator&	rEnd )
2809*cdf0e10cSrcweir             {
2810*cdf0e10cSrcweir                 if( aRangeBegin == aRangeEnd )
2811*cdf0e10cSrcweir                 {
2812*cdf0e10cSrcweir                     // only a single action. Setup subset, and call functor
2813*cdf0e10cSrcweir                     Action::Subset aSubset;
2814*cdf0e10cSrcweir                     aSubset.mnSubsetBegin = ::std::max( sal_Int32( 0 ),
2815*cdf0e10cSrcweir                                                         nStartIndex - aRangeBegin->mnOrigIndex );
2816*cdf0e10cSrcweir                     aSubset.mnSubsetEnd   = ::std::min( aRangeBegin->mpAction->getActionCount(),
2817*cdf0e10cSrcweir                                                         nEndIndex - aRangeBegin->mnOrigIndex );
2818*cdf0e10cSrcweir 
2819*cdf0e10cSrcweir                     ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0,
2820*cdf0e10cSrcweir                                       "ImplRenderer::forSubsetRange(): Invalid indices" );
2821*cdf0e10cSrcweir 
2822*cdf0e10cSrcweir                     rFunctor( *aRangeBegin, aSubset );
2823*cdf0e10cSrcweir                 }
2824*cdf0e10cSrcweir                 else
2825*cdf0e10cSrcweir                 {
2826*cdf0e10cSrcweir                     // more than one action.
2827*cdf0e10cSrcweir 
2828*cdf0e10cSrcweir                     // render partial first, full intermediate, and
2829*cdf0e10cSrcweir                     // partial last action
2830*cdf0e10cSrcweir                     Action::Subset aSubset;
2831*cdf0e10cSrcweir                     aSubset.mnSubsetBegin = ::std::max( sal_Int32( 0 ),
2832*cdf0e10cSrcweir                                                         nStartIndex - aRangeBegin->mnOrigIndex );
2833*cdf0e10cSrcweir                     aSubset.mnSubsetEnd   = aRangeBegin->mpAction->getActionCount();
2834*cdf0e10cSrcweir 
2835*cdf0e10cSrcweir                     ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0,
2836*cdf0e10cSrcweir                                       "ImplRenderer::forSubsetRange(): Invalid indices" );
2837*cdf0e10cSrcweir 
2838*cdf0e10cSrcweir                     rFunctor( *aRangeBegin, aSubset );
2839*cdf0e10cSrcweir 
2840*cdf0e10cSrcweir                     // first action rendered, skip to next
2841*cdf0e10cSrcweir                     ++aRangeBegin;
2842*cdf0e10cSrcweir 
2843*cdf0e10cSrcweir                     // render full middle actions
2844*cdf0e10cSrcweir                     while( aRangeBegin != aRangeEnd )
2845*cdf0e10cSrcweir                         rFunctor( *aRangeBegin++ );
2846*cdf0e10cSrcweir 
2847*cdf0e10cSrcweir                     if( aRangeEnd == rEnd ||
2848*cdf0e10cSrcweir                         aRangeEnd->mnOrigIndex > nEndIndex )
2849*cdf0e10cSrcweir                     {
2850*cdf0e10cSrcweir                         // aRangeEnd denotes end of action vector,
2851*cdf0e10cSrcweir                         //
2852*cdf0e10cSrcweir                         // or
2853*cdf0e10cSrcweir                         //
2854*cdf0e10cSrcweir                         // nEndIndex references something _after_
2855*cdf0e10cSrcweir                         // aRangeBegin, but _before_ aRangeEnd
2856*cdf0e10cSrcweir                         //
2857*cdf0e10cSrcweir                         // either way: no partial action left
2858*cdf0e10cSrcweir                         return rFunctor.result();
2859*cdf0e10cSrcweir                     }
2860*cdf0e10cSrcweir 
2861*cdf0e10cSrcweir                     aSubset.mnSubsetBegin = 0;
2862*cdf0e10cSrcweir                     aSubset.mnSubsetEnd   = nEndIndex - aRangeEnd->mnOrigIndex;
2863*cdf0e10cSrcweir 
2864*cdf0e10cSrcweir                     ENSURE_OR_RETURN_FALSE( aSubset.mnSubsetBegin >= 0 && aSubset.mnSubsetEnd >= 0,
2865*cdf0e10cSrcweir                                       "ImplRenderer::forSubsetRange(): Invalid indices" );
2866*cdf0e10cSrcweir 
2867*cdf0e10cSrcweir                     rFunctor( *aRangeEnd, aSubset );
2868*cdf0e10cSrcweir                 }
2869*cdf0e10cSrcweir 
2870*cdf0e10cSrcweir                 return rFunctor.result();
2871*cdf0e10cSrcweir             }
2872*cdf0e10cSrcweir         }
2873*cdf0e10cSrcweir 
2874*cdf0e10cSrcweir         bool ImplRenderer::getSubsetIndices( sal_Int32&						io_rStartIndex,
2875*cdf0e10cSrcweir                                              sal_Int32&						io_rEndIndex,
2876*cdf0e10cSrcweir                                              ActionVector::const_iterator& 	o_rRangeBegin,
2877*cdf0e10cSrcweir                                              ActionVector::const_iterator& 	o_rRangeEnd ) const
2878*cdf0e10cSrcweir         {
2879*cdf0e10cSrcweir             ENSURE_OR_RETURN_FALSE( io_rStartIndex<=io_rEndIndex,
2880*cdf0e10cSrcweir                               "ImplRenderer::getSubsetIndices(): invalid action range" );
2881*cdf0e10cSrcweir 
2882*cdf0e10cSrcweir             ENSURE_OR_RETURN_FALSE( !maActions.empty(),
2883*cdf0e10cSrcweir                               "ImplRenderer::getSubsetIndices(): no actions to render" );
2884*cdf0e10cSrcweir 
2885*cdf0e10cSrcweir             const sal_Int32 nMinActionIndex( maActions.front().mnOrigIndex );
2886*cdf0e10cSrcweir             const sal_Int32 nMaxActionIndex( maActions.back().mnOrigIndex +
2887*cdf0e10cSrcweir                                              maActions.back().mpAction->getActionCount() );
2888*cdf0e10cSrcweir 
2889*cdf0e10cSrcweir             // clip given range to permissible values (there might be
2890*cdf0e10cSrcweir             // ranges before and behind the valid indices)
2891*cdf0e10cSrcweir             io_rStartIndex = ::std::max( nMinActionIndex,
2892*cdf0e10cSrcweir                                          io_rStartIndex );
2893*cdf0e10cSrcweir             io_rEndIndex = ::std::min( nMaxActionIndex,
2894*cdf0e10cSrcweir                                        io_rEndIndex );
2895*cdf0e10cSrcweir 
2896*cdf0e10cSrcweir             if( io_rStartIndex == io_rEndIndex ||
2897*cdf0e10cSrcweir                 io_rStartIndex > io_rEndIndex )
2898*cdf0e10cSrcweir             {
2899*cdf0e10cSrcweir 				// empty range, don't render anything. The second
2900*cdf0e10cSrcweir 				// condition e.g. happens if the requested range lies
2901*cdf0e10cSrcweir 				// fully before or behind the valid action indices.
2902*cdf0e10cSrcweir                 return false;
2903*cdf0e10cSrcweir             }
2904*cdf0e10cSrcweir 
2905*cdf0e10cSrcweir 
2906*cdf0e10cSrcweir             const ActionVector::const_iterator aBegin( maActions.begin() );
2907*cdf0e10cSrcweir             const ActionVector::const_iterator aEnd( maActions.end() );
2908*cdf0e10cSrcweir 
2909*cdf0e10cSrcweir 
2910*cdf0e10cSrcweir             // find start and end action
2911*cdf0e10cSrcweir             // =========================
2912*cdf0e10cSrcweir             o_rRangeBegin = ::std::lower_bound( aBegin, aEnd,
2913*cdf0e10cSrcweir                                                 MtfAction( ActionSharedPtr(), io_rStartIndex ),
2914*cdf0e10cSrcweir                                                 UpperBoundActionIndexComparator() );
2915*cdf0e10cSrcweir             o_rRangeEnd   = ::std::lower_bound( aBegin, aEnd,
2916*cdf0e10cSrcweir                                                 MtfAction( ActionSharedPtr(), io_rEndIndex ),
2917*cdf0e10cSrcweir                                                 UpperBoundActionIndexComparator() );
2918*cdf0e10cSrcweir             return true;
2919*cdf0e10cSrcweir         }
2920*cdf0e10cSrcweir 
2921*cdf0e10cSrcweir 
2922*cdf0e10cSrcweir         // Public methods
2923*cdf0e10cSrcweir         // ====================================================================
2924*cdf0e10cSrcweir 
2925*cdf0e10cSrcweir         ImplRenderer::ImplRenderer( const CanvasSharedPtr&	rCanvas,
2926*cdf0e10cSrcweir                                     const GDIMetaFile&		rMtf,
2927*cdf0e10cSrcweir                                     const Parameters&		rParams ) :
2928*cdf0e10cSrcweir             CanvasGraphicHelper( rCanvas ),
2929*cdf0e10cSrcweir             maActions()
2930*cdf0e10cSrcweir         {
2931*cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::ImplRenderer(mtf)" );
2932*cdf0e10cSrcweir 
2933*cdf0e10cSrcweir             OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(),
2934*cdf0e10cSrcweir                         "ImplRenderer::ImplRenderer(): Invalid canvas" );
2935*cdf0e10cSrcweir             OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(),
2936*cdf0e10cSrcweir                         "ImplRenderer::ImplRenderer(): Invalid graphic device" );
2937*cdf0e10cSrcweir 
2938*cdf0e10cSrcweir             // make sure canvas and graphic device are valid; action
2939*cdf0e10cSrcweir             // creation don't check that every time
2940*cdf0e10cSrcweir             if( rCanvas.get() == NULL ||
2941*cdf0e10cSrcweir                 !rCanvas->getUNOCanvas().is() ||
2942*cdf0e10cSrcweir                 !rCanvas->getUNOCanvas()->getDevice().is() )
2943*cdf0e10cSrcweir             {
2944*cdf0e10cSrcweir                 // leave actions empty
2945*cdf0e10cSrcweir                 return;
2946*cdf0e10cSrcweir             }
2947*cdf0e10cSrcweir 
2948*cdf0e10cSrcweir             VectorOfOutDevStates	aStateStack;
2949*cdf0e10cSrcweir 
2950*cdf0e10cSrcweir             VirtualDevice aVDev;
2951*cdf0e10cSrcweir             aVDev.EnableOutput( sal_False );
2952*cdf0e10cSrcweir 
2953*cdf0e10cSrcweir             // Setup VDev for state tracking and mapping
2954*cdf0e10cSrcweir             // =========================================
2955*cdf0e10cSrcweir 
2956*cdf0e10cSrcweir             aVDev.SetMapMode( rMtf.GetPrefMapMode() );
2957*cdf0e10cSrcweir 
2958*cdf0e10cSrcweir             const Size aMtfSize( rMtf.GetPrefSize() );
2959*cdf0e10cSrcweir             const Size aMtfSizePixPre( aVDev.LogicToPixel( aMtfSize,
2960*cdf0e10cSrcweir                                                            rMtf.GetPrefMapMode() ) );
2961*cdf0e10cSrcweir             const Point aEmptyPt;
2962*cdf0e10cSrcweir             const Point aMtfOriginPix( aVDev.LogicToPixel( aEmptyPt ) );
2963*cdf0e10cSrcweir 
2964*cdf0e10cSrcweir             // #i44110# correct null-sized output - there are shapes
2965*cdf0e10cSrcweir             // which have zero size in at least one dimension
2966*cdf0e10cSrcweir             const Size aMtfSizePix( ::std::max( aMtfSizePixPre.Width(), 1L ),
2967*cdf0e10cSrcweir                                     ::std::max( aMtfSizePixPre.Height(), 1L ) );
2968*cdf0e10cSrcweir 
2969*cdf0e10cSrcweir             sal_Int32 nCurrActions(0);
2970*cdf0e10cSrcweir             ActionFactoryParameters aParms(aStateStack,
2971*cdf0e10cSrcweir                                            rCanvas,
2972*cdf0e10cSrcweir                                            aVDev,
2973*cdf0e10cSrcweir                                            rParams,
2974*cdf0e10cSrcweir                                            nCurrActions );
2975*cdf0e10cSrcweir 
2976*cdf0e10cSrcweir             // init state stack
2977*cdf0e10cSrcweir             clearStateStack( aStateStack );
2978*cdf0e10cSrcweir 
2979*cdf0e10cSrcweir             // Setup local state, such that the metafile renders
2980*cdf0e10cSrcweir             // itself into a one-by-one square at the origin for
2981*cdf0e10cSrcweir             // identity view and render transformations
2982*cdf0e10cSrcweir             getState( aStateStack ).transform.scale( 1.0 / aMtfSizePix.Width(),
2983*cdf0e10cSrcweir                                                      1.0 / aMtfSizePix.Height() );
2984*cdf0e10cSrcweir 
2985*cdf0e10cSrcweir             tools::calcLogic2PixelAffineTransform( getState( aStateStack ).mapModeTransform,
2986*cdf0e10cSrcweir                                                    aVDev );
2987*cdf0e10cSrcweir 
2988*cdf0e10cSrcweir             ColorSharedPtr pColor( getCanvas()->createColor() );
2989*cdf0e10cSrcweir 
2990*cdf0e10cSrcweir             // setup default text color to black
2991*cdf0e10cSrcweir             getState( aStateStack ).textColor =
2992*cdf0e10cSrcweir                 getState( aStateStack ).textFillColor =
2993*cdf0e10cSrcweir                 getState( aStateStack ).textLineColor = pColor->getDeviceColor( 0x000000FF );
2994*cdf0e10cSrcweir 
2995*cdf0e10cSrcweir             // apply overrides from the Parameters struct
2996*cdf0e10cSrcweir             if( rParams.maFillColor.is_initialized() )
2997*cdf0e10cSrcweir             {
2998*cdf0e10cSrcweir                 getState( aStateStack ).isFillColorSet = true;
2999*cdf0e10cSrcweir                 getState( aStateStack ).fillColor = pColor->getDeviceColor( *rParams.maFillColor );
3000*cdf0e10cSrcweir             }
3001*cdf0e10cSrcweir             if( rParams.maLineColor.is_initialized() )
3002*cdf0e10cSrcweir             {
3003*cdf0e10cSrcweir                 getState( aStateStack ).isLineColorSet = true;
3004*cdf0e10cSrcweir                 getState( aStateStack ).lineColor = pColor->getDeviceColor( *rParams.maLineColor );
3005*cdf0e10cSrcweir             }
3006*cdf0e10cSrcweir             if( rParams.maTextColor.is_initialized() )
3007*cdf0e10cSrcweir             {
3008*cdf0e10cSrcweir                 getState( aStateStack ).isTextFillColorSet = true;
3009*cdf0e10cSrcweir                 getState( aStateStack ).isTextLineColorSet = true;
3010*cdf0e10cSrcweir                 getState( aStateStack ).textColor =
3011*cdf0e10cSrcweir                     getState( aStateStack ).textFillColor =
3012*cdf0e10cSrcweir                     getState( aStateStack ).textLineColor = pColor->getDeviceColor( *rParams.maTextColor );
3013*cdf0e10cSrcweir             }
3014*cdf0e10cSrcweir             if( rParams.maFontName.is_initialized() ||
3015*cdf0e10cSrcweir                 rParams.maFontWeight.is_initialized() ||
3016*cdf0e10cSrcweir                 rParams.maFontLetterForm.is_initialized() ||
3017*cdf0e10cSrcweir                 rParams.maFontUnderline.is_initialized()  ||
3018*cdf0e10cSrcweir                 rParams.maFontProportion.is_initialized() )
3019*cdf0e10cSrcweir             {
3020*cdf0e10cSrcweir                 ::cppcanvas::internal::OutDevState& rState = getState( aStateStack );
3021*cdf0e10cSrcweir 
3022*cdf0e10cSrcweir                 rState.xFont = createFont( rState.fontRotation,
3023*cdf0e10cSrcweir                                            ::Font(), // default font
3024*cdf0e10cSrcweir                                            aParms );
3025*cdf0e10cSrcweir             }
3026*cdf0e10cSrcweir 
3027*cdf0e10cSrcweir             createActions( const_cast<GDIMetaFile&>(rMtf), // HACK(Q2):
3028*cdf0e10cSrcweir 								                           // we're
3029*cdf0e10cSrcweir                         		                           // changing
3030*cdf0e10cSrcweir                            		                           // the
3031*cdf0e10cSrcweir                            		                           // current
3032*cdf0e10cSrcweir                            		                           // action
3033*cdf0e10cSrcweir                            		                           // in
3034*cdf0e10cSrcweir                            		                           // createActions!
3035*cdf0e10cSrcweir                            aParms,
3036*cdf0e10cSrcweir                            true // TODO(P1): make subsettability configurable
3037*cdf0e10cSrcweir                             );
3038*cdf0e10cSrcweir         }
3039*cdf0e10cSrcweir 
3040*cdf0e10cSrcweir         ImplRenderer::ImplRenderer( const CanvasSharedPtr&	rCanvas,
3041*cdf0e10cSrcweir                                     const BitmapEx&			rBmpEx,
3042*cdf0e10cSrcweir                                     const Parameters&		rParams ) :
3043*cdf0e10cSrcweir             CanvasGraphicHelper( rCanvas ),
3044*cdf0e10cSrcweir             maActions()
3045*cdf0e10cSrcweir         {
3046*cdf0e10cSrcweir             // TODO(F3): property modification parameters are
3047*cdf0e10cSrcweir             // currently ignored for Bitmaps
3048*cdf0e10cSrcweir             (void)rParams;
3049*cdf0e10cSrcweir 
3050*cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::ImplRenderer(bitmap)" );
3051*cdf0e10cSrcweir 
3052*cdf0e10cSrcweir             OSL_ENSURE( rCanvas.get() != NULL && rCanvas->getUNOCanvas().is(),
3053*cdf0e10cSrcweir                         "ImplRenderer::ImplRenderer(): Invalid canvas" );
3054*cdf0e10cSrcweir             OSL_ENSURE( rCanvas->getUNOCanvas()->getDevice().is(),
3055*cdf0e10cSrcweir                         "ImplRenderer::ImplRenderer(): Invalid graphic device" );
3056*cdf0e10cSrcweir 
3057*cdf0e10cSrcweir             // make sure canvas and graphic device are valid; action
3058*cdf0e10cSrcweir             // creation don't check that every time
3059*cdf0e10cSrcweir             if( rCanvas.get() == NULL ||
3060*cdf0e10cSrcweir                 !rCanvas->getUNOCanvas().is() ||
3061*cdf0e10cSrcweir                 !rCanvas->getUNOCanvas()->getDevice().is() )
3062*cdf0e10cSrcweir             {
3063*cdf0e10cSrcweir                 // leave actions empty
3064*cdf0e10cSrcweir                 return;
3065*cdf0e10cSrcweir             }
3066*cdf0e10cSrcweir 
3067*cdf0e10cSrcweir             OutDevState aState;
3068*cdf0e10cSrcweir 
3069*cdf0e10cSrcweir             const Size aBmpSize( rBmpEx.GetSizePixel() );
3070*cdf0e10cSrcweir 
3071*cdf0e10cSrcweir             // Setup local state, such that the bitmap renders itself
3072*cdf0e10cSrcweir             // into a one-by-one square for identity view and render
3073*cdf0e10cSrcweir             // transformations
3074*cdf0e10cSrcweir             aState.transform.scale( 1.0 / aBmpSize.Width(),
3075*cdf0e10cSrcweir                                     1.0 / aBmpSize.Height() );
3076*cdf0e10cSrcweir 
3077*cdf0e10cSrcweir             // create a single action for the provided BitmapEx
3078*cdf0e10cSrcweir             maActions.push_back(
3079*cdf0e10cSrcweir                 MtfAction(
3080*cdf0e10cSrcweir                     BitmapActionFactory::createBitmapAction(
3081*cdf0e10cSrcweir                         rBmpEx,
3082*cdf0e10cSrcweir                         ::basegfx::B2DPoint(),
3083*cdf0e10cSrcweir                         rCanvas,
3084*cdf0e10cSrcweir                         aState),
3085*cdf0e10cSrcweir                     0 ) );
3086*cdf0e10cSrcweir         }
3087*cdf0e10cSrcweir 
3088*cdf0e10cSrcweir         ImplRenderer::~ImplRenderer()
3089*cdf0e10cSrcweir         {
3090*cdf0e10cSrcweir         }
3091*cdf0e10cSrcweir 
3092*cdf0e10cSrcweir         bool ImplRenderer::drawSubset( sal_Int32	nStartIndex,
3093*cdf0e10cSrcweir                                        sal_Int32	nEndIndex ) const
3094*cdf0e10cSrcweir         {
3095*cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::drawSubset()" );
3096*cdf0e10cSrcweir 
3097*cdf0e10cSrcweir             ActionVector::const_iterator aRangeBegin;
3098*cdf0e10cSrcweir             ActionVector::const_iterator aRangeEnd;
3099*cdf0e10cSrcweir 
3100*cdf0e10cSrcweir             try
3101*cdf0e10cSrcweir             {
3102*cdf0e10cSrcweir                 if( !getSubsetIndices( nStartIndex, nEndIndex,
3103*cdf0e10cSrcweir                                        aRangeBegin, aRangeEnd ) )
3104*cdf0e10cSrcweir                     return true; // nothing to render (but _that_ was successful)
3105*cdf0e10cSrcweir 
3106*cdf0e10cSrcweir                 // now, aRangeBegin references the action in which the
3107*cdf0e10cSrcweir                 // subset rendering must start, and aRangeEnd references
3108*cdf0e10cSrcweir                 // the action in which the subset rendering must end (it
3109*cdf0e10cSrcweir                 // might also end right at the start of the referenced
3110*cdf0e10cSrcweir                 // action, such that zero of that action needs to be
3111*cdf0e10cSrcweir                 // rendered).
3112*cdf0e10cSrcweir 
3113*cdf0e10cSrcweir 
3114*cdf0e10cSrcweir                 // render subset of actions
3115*cdf0e10cSrcweir                 // ========================
3116*cdf0e10cSrcweir 
3117*cdf0e10cSrcweir                 ::basegfx::B2DHomMatrix aMatrix;
3118*cdf0e10cSrcweir                 ::canvas::tools::getRenderStateTransform( aMatrix,
3119*cdf0e10cSrcweir                                                           getRenderState() );
3120*cdf0e10cSrcweir 
3121*cdf0e10cSrcweir                 ActionRenderer aRenderer( aMatrix );
3122*cdf0e10cSrcweir 
3123*cdf0e10cSrcweir                 return forSubsetRange( aRenderer,
3124*cdf0e10cSrcweir                                        aRangeBegin,
3125*cdf0e10cSrcweir                                        aRangeEnd,
3126*cdf0e10cSrcweir                                        nStartIndex,
3127*cdf0e10cSrcweir                                        nEndIndex,
3128*cdf0e10cSrcweir                                        maActions.end() );
3129*cdf0e10cSrcweir             }
3130*cdf0e10cSrcweir             catch( uno::Exception& )
3131*cdf0e10cSrcweir             {
3132*cdf0e10cSrcweir                 OSL_ENSURE( false,
3133*cdf0e10cSrcweir                             rtl::OUStringToOString(
3134*cdf0e10cSrcweir                                 comphelper::anyToString( cppu::getCaughtException() ),
3135*cdf0e10cSrcweir                                 RTL_TEXTENCODING_UTF8 ).getStr() );
3136*cdf0e10cSrcweir 
3137*cdf0e10cSrcweir                 // convert error to return value
3138*cdf0e10cSrcweir                 return false;
3139*cdf0e10cSrcweir             }
3140*cdf0e10cSrcweir         }
3141*cdf0e10cSrcweir 
3142*cdf0e10cSrcweir         ::basegfx::B2DRange ImplRenderer::getSubsetArea( sal_Int32	nStartIndex,
3143*cdf0e10cSrcweir                                                          sal_Int32	nEndIndex ) const
3144*cdf0e10cSrcweir         {
3145*cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::getSubsetArea()" );
3146*cdf0e10cSrcweir 
3147*cdf0e10cSrcweir             ActionVector::const_iterator aRangeBegin;
3148*cdf0e10cSrcweir             ActionVector::const_iterator aRangeEnd;
3149*cdf0e10cSrcweir 
3150*cdf0e10cSrcweir             if( !getSubsetIndices( nStartIndex, nEndIndex,
3151*cdf0e10cSrcweir                                    aRangeBegin, aRangeEnd ) )
3152*cdf0e10cSrcweir                 return ::basegfx::B2DRange(); // nothing to render -> empty range
3153*cdf0e10cSrcweir 
3154*cdf0e10cSrcweir             // now, aRangeBegin references the action in which the
3155*cdf0e10cSrcweir             // subset querying must start, and aRangeEnd references
3156*cdf0e10cSrcweir             // the action in which the subset querying must end (it
3157*cdf0e10cSrcweir             // might also end right at the start of the referenced
3158*cdf0e10cSrcweir             // action, such that zero of that action needs to be
3159*cdf0e10cSrcweir             // queried).
3160*cdf0e10cSrcweir 
3161*cdf0e10cSrcweir 
3162*cdf0e10cSrcweir             // query bounds for subset of actions
3163*cdf0e10cSrcweir             // ==================================
3164*cdf0e10cSrcweir 
3165*cdf0e10cSrcweir             ::basegfx::B2DHomMatrix aMatrix;
3166*cdf0e10cSrcweir             ::canvas::tools::getRenderStateTransform( aMatrix,
3167*cdf0e10cSrcweir                                                       getRenderState() );
3168*cdf0e10cSrcweir 
3169*cdf0e10cSrcweir             AreaQuery aQuery( aMatrix );
3170*cdf0e10cSrcweir             forSubsetRange( aQuery,
3171*cdf0e10cSrcweir                             aRangeBegin,
3172*cdf0e10cSrcweir                             aRangeEnd,
3173*cdf0e10cSrcweir                             nStartIndex,
3174*cdf0e10cSrcweir                             nEndIndex,
3175*cdf0e10cSrcweir                             maActions.end() );
3176*cdf0e10cSrcweir 
3177*cdf0e10cSrcweir             return aQuery.getBounds();
3178*cdf0e10cSrcweir         }
3179*cdf0e10cSrcweir 
3180*cdf0e10cSrcweir         bool ImplRenderer::draw() const
3181*cdf0e10cSrcweir         {
3182*cdf0e10cSrcweir             RTL_LOGFILE_CONTEXT( aLog, "::cppcanvas::internal::ImplRenderer::draw()" );
3183*cdf0e10cSrcweir 
3184*cdf0e10cSrcweir             ::basegfx::B2DHomMatrix aMatrix;
3185*cdf0e10cSrcweir             ::canvas::tools::getRenderStateTransform( aMatrix,
3186*cdf0e10cSrcweir                                                       getRenderState() );
3187*cdf0e10cSrcweir 
3188*cdf0e10cSrcweir             try
3189*cdf0e10cSrcweir             {
3190*cdf0e10cSrcweir                 return ::std::for_each( maActions.begin(), maActions.end(), ActionRenderer( aMatrix ) ).result();
3191*cdf0e10cSrcweir             }
3192*cdf0e10cSrcweir             catch( uno::Exception& )
3193*cdf0e10cSrcweir             {
3194*cdf0e10cSrcweir                 OSL_ENSURE( false,
3195*cdf0e10cSrcweir                             rtl::OUStringToOString(
3196*cdf0e10cSrcweir                                 comphelper::anyToString( cppu::getCaughtException() ),
3197*cdf0e10cSrcweir                                 RTL_TEXTENCODING_UTF8 ).getStr() );
3198*cdf0e10cSrcweir 
3199*cdf0e10cSrcweir                 return false;
3200*cdf0e10cSrcweir             }
3201*cdf0e10cSrcweir         }
3202*cdf0e10cSrcweir     }
3203*cdf0e10cSrcweir }
3204