xref: /trunk/main/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx (revision 64b1462124697ddee7e7eda36bfbb70d1b558cff)
1464702f4SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3464702f4SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4464702f4SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5464702f4SAndrew Rist  * distributed with this work for additional information
6464702f4SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7464702f4SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8464702f4SAndrew Rist  * "License"); you may not use this file except in compliance
9464702f4SAndrew Rist  * with the License.  You may obtain a copy of the License at
10cdf0e10cSrcweir  *
11464702f4SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12cdf0e10cSrcweir  *
13464702f4SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14464702f4SAndrew Rist  * software distributed under the License is distributed on an
15464702f4SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16464702f4SAndrew Rist  * KIND, either express or implied.  See the License for the
17464702f4SAndrew Rist  * specific language governing permissions and limitations
18464702f4SAndrew Rist  * under the License.
19cdf0e10cSrcweir  *
20464702f4SAndrew Rist  *************************************************************/
21464702f4SAndrew Rist 
22cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
23cdf0e10cSrcweir #include "precompiled_drawinglayer.hxx"
24cdf0e10cSrcweir 
25cdf0e10cSrcweir #include <drawinglayer/processor2d/vclmetafileprocessor2d.hxx>
26cdf0e10cSrcweir #include <tools/gen.hxx>
27cdf0e10cSrcweir #include <vcl/virdev.hxx>
28cdf0e10cSrcweir #include <vcl/gdimtf.hxx>
29cdf0e10cSrcweir #include <vcl/gradient.hxx>
30cdf0e10cSrcweir #include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
31cdf0e10cSrcweir #include <drawinglayer/primitive2d/textprimitive2d.hxx>
32cdf0e10cSrcweir #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
33cdf0e10cSrcweir #include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
34cdf0e10cSrcweir #include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
35cdf0e10cSrcweir #include <drawinglayer/primitive2d/maskprimitive2d.hxx>
36cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygonclipper.hxx>
37cdf0e10cSrcweir #include <basegfx/polygon/b2dpolypolygontools.hxx>
38cdf0e10cSrcweir #include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
39cdf0e10cSrcweir #include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
40cdf0e10cSrcweir #include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
41cdf0e10cSrcweir #include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
42cdf0e10cSrcweir #include <drawinglayer/processor2d/vclpixelprocessor2d.hxx>
43cdf0e10cSrcweir #include <tools/stream.hxx>
44cdf0e10cSrcweir #include <drawinglayer/primitive2d/transformprimitive2d.hxx>
45cdf0e10cSrcweir #include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
46cdf0e10cSrcweir #include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
47cdf0e10cSrcweir #include <vcl/graphictools.hxx>
48cdf0e10cSrcweir #include <vcl/metaact.hxx>
49cdf0e10cSrcweir #include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
50cdf0e10cSrcweir #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
51cdf0e10cSrcweir #include <comphelper/processfactory.hxx>
52cdf0e10cSrcweir #include <rtl/ustring.hxx>
53cdf0e10cSrcweir #include <com/sun/star/i18n/CharacterIteratorMode.hdl>
54cdf0e10cSrcweir #include <com/sun/star/i18n/WordType.hpp>
55cdf0e10cSrcweir #include <drawinglayer/primitive2d/controlprimitive2d.hxx>
56cdf0e10cSrcweir #include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
57cdf0e10cSrcweir #include <basegfx/polygon/b2dpolygontools.hxx>
58cdf0e10cSrcweir #include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
59cdf0e10cSrcweir #include <drawinglayer/primitive2d/epsprimitive2d.hxx>
60cdf0e10cSrcweir #include <basegfx/polygon/b2dlinegeometry.hxx>
6145fd3b9aSArmin Le Grand #include <vcl/dibtools.hxx>
62cdf0e10cSrcweir 
63cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
64cdf0e10cSrcweir // for PDFExtOutDevData Graphic support
65cdf0e10cSrcweir 
66cdf0e10cSrcweir #include <vcl/graph.hxx>
67cdf0e10cSrcweir #include <vcl/svapp.hxx>
68cdf0e10cSrcweir #include <toolkit/helper/formpdfexport.hxx>
69cdf0e10cSrcweir 
70cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
71cdf0e10cSrcweir // for Control printing
72cdf0e10cSrcweir 
73cdf0e10cSrcweir #include <com/sun/star/beans/XPropertySet.hpp>
74cdf0e10cSrcweir 
75cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
76cdf0e10cSrcweir // for StructureTagPrimitive support in sd's unomodel.cxx
77cdf0e10cSrcweir 
78cdf0e10cSrcweir #include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
79cdf0e10cSrcweir 
80cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
81cdf0e10cSrcweir 
82cdf0e10cSrcweir using namespace com::sun::star;
83cdf0e10cSrcweir 
84cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
85cdf0e10cSrcweir // #112245# definition for maximum allowed point count due to Metafile target.
86cdf0e10cSrcweir // To be on the safe side with the old tools polygon, use slightly less then
87cdf0e10cSrcweir // the theoretical maximum (bad experiences with tools polygon)
88cdf0e10cSrcweir 
89cdf0e10cSrcweir #define MAX_POLYGON_POINT_COUNT_METAFILE    (0x0000fff0)
90cdf0e10cSrcweir 
91cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
92cdf0e10cSrcweir 
93cdf0e10cSrcweir namespace
94cdf0e10cSrcweir {
95cdf0e10cSrcweir     // #112245# helper to split line polygon in half
96cdf0e10cSrcweir     void splitLinePolygon(
97cdf0e10cSrcweir         const basegfx::B2DPolygon& rBasePolygon,
98cdf0e10cSrcweir         basegfx::B2DPolygon& o_aLeft,
99cdf0e10cSrcweir         basegfx::B2DPolygon& o_aRight)
100cdf0e10cSrcweir     {
101cdf0e10cSrcweir         const sal_uInt32 nCount(rBasePolygon.count());
102cdf0e10cSrcweir 
103cdf0e10cSrcweir         if(nCount)
104cdf0e10cSrcweir         {
105cdf0e10cSrcweir             const sal_uInt32 nHalfCount((nCount - 1) >> 1);
106cdf0e10cSrcweir 
107cdf0e10cSrcweir             o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1);
108cdf0e10cSrcweir             o_aLeft.setClosed(false);
109cdf0e10cSrcweir 
110cdf0e10cSrcweir             o_aRight = basegfx::B2DPolygon(rBasePolygon, nHalfCount, nCount - nHalfCount);
111cdf0e10cSrcweir             o_aRight.setClosed(false);
112cdf0e10cSrcweir 
113cdf0e10cSrcweir             if(rBasePolygon.isClosed())
114cdf0e10cSrcweir             {
115cdf0e10cSrcweir                 o_aRight.append(rBasePolygon.getB2DPoint(0));
116cdf0e10cSrcweir 
117cdf0e10cSrcweir                 if(rBasePolygon.areControlPointsUsed())
118cdf0e10cSrcweir                 {
119cdf0e10cSrcweir                     o_aRight.setControlPoints(
120cdf0e10cSrcweir                         o_aRight.count() - 1,
121cdf0e10cSrcweir                         rBasePolygon.getPrevControlPoint(0),
122cdf0e10cSrcweir                         rBasePolygon.getNextControlPoint(0));
123cdf0e10cSrcweir                 }
124cdf0e10cSrcweir             }
125cdf0e10cSrcweir         }
126cdf0e10cSrcweir         else
127cdf0e10cSrcweir         {
128cdf0e10cSrcweir             o_aLeft.clear();
129cdf0e10cSrcweir             o_aRight.clear();
130cdf0e10cSrcweir         }
131cdf0e10cSrcweir     }
132cdf0e10cSrcweir 
133cdf0e10cSrcweir     // #112245# helper to evtl. split filled polygons to maximum metafile point count
134cdf0e10cSrcweir     bool fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon)
135cdf0e10cSrcweir     {
136cdf0e10cSrcweir         bool bRetval(false);
137cdf0e10cSrcweir         const sal_uInt32 nPolyCount(rPolyPolygon.count());
138cdf0e10cSrcweir 
139cdf0e10cSrcweir         if(nPolyCount)
140cdf0e10cSrcweir         {
141cdf0e10cSrcweir             basegfx::B2DPolyPolygon aSplitted;
142cdf0e10cSrcweir 
143cdf0e10cSrcweir             for(sal_uInt32 a(0); a < nPolyCount; a++)
144cdf0e10cSrcweir             {
145cdf0e10cSrcweir                 const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a));
146cdf0e10cSrcweir                 const sal_uInt32 nPointCount(aCandidate.count());
147cdf0e10cSrcweir                 bool bNeedToSplit(false);
148cdf0e10cSrcweir 
149cdf0e10cSrcweir                 if(aCandidate.areControlPointsUsed())
150cdf0e10cSrcweir                 {
151cdf0e10cSrcweir                     // compare with the maximum for bezier curved polygons
152cdf0e10cSrcweir                     bNeedToSplit = nPointCount > ((MAX_POLYGON_POINT_COUNT_METAFILE / 3L) - 1L);
153cdf0e10cSrcweir                 }
154cdf0e10cSrcweir                 else
155cdf0e10cSrcweir                 {
156cdf0e10cSrcweir                     // compare with the maximum for simple point polygons
157cdf0e10cSrcweir                     bNeedToSplit = nPointCount > (MAX_POLYGON_POINT_COUNT_METAFILE - 1);
158cdf0e10cSrcweir                 }
159cdf0e10cSrcweir 
160cdf0e10cSrcweir                 if(bNeedToSplit)
161cdf0e10cSrcweir                 {
162cdf0e10cSrcweir                     // need to split the partial polygon
163cdf0e10cSrcweir                     const basegfx::B2DRange aRange(aCandidate.getB2DRange());
164cdf0e10cSrcweir                     const basegfx::B2DPoint aCenter(aRange.getCenter());
165cdf0e10cSrcweir 
166cdf0e10cSrcweir                     if(aRange.getWidth() > aRange.getHeight())
167cdf0e10cSrcweir                     {
168cdf0e10cSrcweir                         // clip in left and right
169cdf0e10cSrcweir                         const basegfx::B2DPolyPolygon aLeft(
170cdf0e10cSrcweir                             basegfx::tools::clipPolygonOnParallelAxis(
171cdf0e10cSrcweir                                 aCandidate,
172cdf0e10cSrcweir                                 false,
173cdf0e10cSrcweir                                 true,
174cdf0e10cSrcweir                                 aCenter.getX(),
175cdf0e10cSrcweir                                 false));
176cdf0e10cSrcweir                         const basegfx::B2DPolyPolygon aRight(
177cdf0e10cSrcweir                             basegfx::tools::clipPolygonOnParallelAxis(
178cdf0e10cSrcweir                                 aCandidate,
179cdf0e10cSrcweir                                 false,
180cdf0e10cSrcweir                                 false,
181cdf0e10cSrcweir                                 aCenter.getX(),
182cdf0e10cSrcweir                                 false));
183cdf0e10cSrcweir 
184cdf0e10cSrcweir                         aSplitted.append(aLeft);
185cdf0e10cSrcweir                         aSplitted.append(aRight);
186cdf0e10cSrcweir                     }
187cdf0e10cSrcweir                     else
188cdf0e10cSrcweir                     {
189cdf0e10cSrcweir                         // clip in top and bottom
190cdf0e10cSrcweir                         const basegfx::B2DPolyPolygon aTop(
191cdf0e10cSrcweir                             basegfx::tools::clipPolygonOnParallelAxis(
192cdf0e10cSrcweir                                 aCandidate,
193cdf0e10cSrcweir                                 true,
194cdf0e10cSrcweir                                 true,
195cdf0e10cSrcweir                                 aCenter.getY(),
196cdf0e10cSrcweir                                 false));
197cdf0e10cSrcweir                         const basegfx::B2DPolyPolygon aBottom(
198cdf0e10cSrcweir                             basegfx::tools::clipPolygonOnParallelAxis(
199cdf0e10cSrcweir                                 aCandidate,
200cdf0e10cSrcweir                                 true,
201cdf0e10cSrcweir                                 false,
202cdf0e10cSrcweir                                 aCenter.getY(),
203cdf0e10cSrcweir                                 false));
204cdf0e10cSrcweir 
205cdf0e10cSrcweir                         aSplitted.append(aTop);
206cdf0e10cSrcweir                         aSplitted.append(aBottom);
207cdf0e10cSrcweir                     }
208cdf0e10cSrcweir                 }
209cdf0e10cSrcweir                 else
210cdf0e10cSrcweir                 {
211cdf0e10cSrcweir                     aSplitted.append(aCandidate);
212cdf0e10cSrcweir                 }
213cdf0e10cSrcweir             }
214cdf0e10cSrcweir 
215cdf0e10cSrcweir             if(aSplitted.count() != nPolyCount)
216cdf0e10cSrcweir             {
217cdf0e10cSrcweir                 rPolyPolygon = aSplitted;
218cdf0e10cSrcweir             }
219cdf0e10cSrcweir         }
220cdf0e10cSrcweir 
221cdf0e10cSrcweir         return bRetval;
222cdf0e10cSrcweir     }
223cdf0e10cSrcweir } // end of anonymous namespace
224cdf0e10cSrcweir 
225cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
226cdf0e10cSrcweir 
227cdf0e10cSrcweir namespace drawinglayer
228cdf0e10cSrcweir {
229cdf0e10cSrcweir     namespace processor2d
230cdf0e10cSrcweir     {
231cdf0e10cSrcweir         Rectangle VclMetafileProcessor2D::impDumpToMetaFile(
232cdf0e10cSrcweir             const primitive2d::Primitive2DSequence& rContent,
233cdf0e10cSrcweir             GDIMetaFile& o_rContentMetafile)
234cdf0e10cSrcweir         {
235cdf0e10cSrcweir             // Prepare VDev, MetaFile and connections
236cdf0e10cSrcweir             OutputDevice* pLastOutputDevice = mpOutputDevice;
237cdf0e10cSrcweir             GDIMetaFile* pLastMetafile = mpMetaFile;
238cdf0e10cSrcweir             basegfx::B2DRange aPrimitiveRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
239cdf0e10cSrcweir 
240cdf0e10cSrcweir             // transform primitive range with current transformation (e.g shadow offset)
241cdf0e10cSrcweir             aPrimitiveRange.transform(maCurrentTransformation);
242cdf0e10cSrcweir 
243cdf0e10cSrcweir             const Rectangle aPrimitiveRectangle(
244cdf0e10cSrcweir                 basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()),
245cdf0e10cSrcweir                 basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY()));
246cdf0e10cSrcweir             VirtualDevice aContentVDev;
247cdf0e10cSrcweir             MapMode aNewMapMode(pLastOutputDevice->GetMapMode());
248cdf0e10cSrcweir 
249cdf0e10cSrcweir             mpOutputDevice = &aContentVDev;
250cdf0e10cSrcweir             mpMetaFile = &o_rContentMetafile;
251cdf0e10cSrcweir             aContentVDev.EnableOutput(false);
252cdf0e10cSrcweir             aContentVDev.SetMapMode(pLastOutputDevice->GetMapMode());
253cdf0e10cSrcweir             o_rContentMetafile.Record(&aContentVDev);
254cdf0e10cSrcweir             aContentVDev.SetLineColor(pLastOutputDevice->GetLineColor());
255cdf0e10cSrcweir             aContentVDev.SetFillColor(pLastOutputDevice->GetFillColor());
256cdf0e10cSrcweir             aContentVDev.SetFont(pLastOutputDevice->GetFont());
257cdf0e10cSrcweir             aContentVDev.SetDrawMode(pLastOutputDevice->GetDrawMode());
258cdf0e10cSrcweir             aContentVDev.SetSettings(pLastOutputDevice->GetSettings());
259cdf0e10cSrcweir             aContentVDev.SetRefPoint(pLastOutputDevice->GetRefPoint());
260cdf0e10cSrcweir 
261cdf0e10cSrcweir             // dump to MetaFile
262cdf0e10cSrcweir             process(rContent);
263cdf0e10cSrcweir 
264cdf0e10cSrcweir             // cleanups
265cdf0e10cSrcweir             o_rContentMetafile.Stop();
266cdf0e10cSrcweir             o_rContentMetafile.WindStart();
267cdf0e10cSrcweir             aNewMapMode.SetOrigin(aPrimitiveRectangle.TopLeft());
268cdf0e10cSrcweir             o_rContentMetafile.SetPrefMapMode(aNewMapMode);
269cdf0e10cSrcweir             o_rContentMetafile.SetPrefSize(aPrimitiveRectangle.GetSize());
270cdf0e10cSrcweir             mpOutputDevice = pLastOutputDevice;
271cdf0e10cSrcweir             mpMetaFile = pLastMetafile;
272cdf0e10cSrcweir 
273cdf0e10cSrcweir             return aPrimitiveRectangle;
274cdf0e10cSrcweir         }
275cdf0e10cSrcweir 
276cdf0e10cSrcweir         void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient(
277cdf0e10cSrcweir             Gradient& o_rVCLGradient,
278cdf0e10cSrcweir             const attribute::FillGradientAttribute& rFiGrAtt,
279cdf0e10cSrcweir             bool bIsTransparenceGradient)
280cdf0e10cSrcweir         {
281cdf0e10cSrcweir             if(bIsTransparenceGradient)
282cdf0e10cSrcweir             {
283cdf0e10cSrcweir                 // it's about transparence channel intensities (black/white), do not use color modifier
284cdf0e10cSrcweir                 o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor()));
285cdf0e10cSrcweir                 o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor()));
286cdf0e10cSrcweir             }
287cdf0e10cSrcweir             else
288cdf0e10cSrcweir             {
289cdf0e10cSrcweir                 // use color modifier to influence start/end color of gradient
290cdf0e10cSrcweir                 o_rVCLGradient.SetStartColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor())));
291cdf0e10cSrcweir                 o_rVCLGradient.SetEndColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor())));
292cdf0e10cSrcweir             }
293cdf0e10cSrcweir 
294cdf0e10cSrcweir             o_rVCLGradient.SetAngle(static_cast< sal_uInt16 >(rFiGrAtt.getAngle() * (1.0 / F_PI1800)));
295cdf0e10cSrcweir             o_rVCLGradient.SetBorder(static_cast< sal_uInt16 >(rFiGrAtt.getBorder() * 100.0));
296cdf0e10cSrcweir             o_rVCLGradient.SetOfsX(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetX() * 100.0));
297cdf0e10cSrcweir             o_rVCLGradient.SetOfsY(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetY() * 100.0));
298cdf0e10cSrcweir             o_rVCLGradient.SetSteps(rFiGrAtt.getSteps());
299cdf0e10cSrcweir 
300cdf0e10cSrcweir             // defaults for intensity; those were computed into the start/end colors already
301cdf0e10cSrcweir             o_rVCLGradient.SetStartIntensity(100);
302cdf0e10cSrcweir             o_rVCLGradient.SetEndIntensity(100);
303cdf0e10cSrcweir 
304cdf0e10cSrcweir             switch(rFiGrAtt.getStyle())
305cdf0e10cSrcweir             {
306cdf0e10cSrcweir                 default : // attribute::GRADIENTSTYLE_LINEAR :
307cdf0e10cSrcweir                 {
308cdf0e10cSrcweir                     o_rVCLGradient.SetStyle(GRADIENT_LINEAR);
309cdf0e10cSrcweir                     break;
310cdf0e10cSrcweir                 }
311cdf0e10cSrcweir                 case attribute::GRADIENTSTYLE_AXIAL :
312cdf0e10cSrcweir                 {
313cdf0e10cSrcweir                     o_rVCLGradient.SetStyle(GRADIENT_AXIAL);
314cdf0e10cSrcweir                     break;
315cdf0e10cSrcweir                 }
316cdf0e10cSrcweir                 case attribute::GRADIENTSTYLE_RADIAL :
317cdf0e10cSrcweir                 {
318cdf0e10cSrcweir                     o_rVCLGradient.SetStyle(GRADIENT_RADIAL);
319cdf0e10cSrcweir                     break;
320cdf0e10cSrcweir                 }
321cdf0e10cSrcweir                 case attribute::GRADIENTSTYLE_ELLIPTICAL :
322cdf0e10cSrcweir                 {
323cdf0e10cSrcweir                     o_rVCLGradient.SetStyle(GRADIENT_ELLIPTICAL);
324cdf0e10cSrcweir                     break;
325cdf0e10cSrcweir                 }
326cdf0e10cSrcweir                 case attribute::GRADIENTSTYLE_SQUARE :
327cdf0e10cSrcweir                 {
328cdf0e10cSrcweir                     o_rVCLGradient.SetStyle(GRADIENT_SQUARE);
329cdf0e10cSrcweir                     break;
330cdf0e10cSrcweir                 }
331cdf0e10cSrcweir                 case attribute::GRADIENTSTYLE_RECT :
332cdf0e10cSrcweir                 {
333cdf0e10cSrcweir                     o_rVCLGradient.SetStyle(GRADIENT_RECT);
334cdf0e10cSrcweir                     break;
335cdf0e10cSrcweir                 }
336cdf0e10cSrcweir             }
337cdf0e10cSrcweir         }
338cdf0e10cSrcweir 
339cdf0e10cSrcweir         void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
340cdf0e10cSrcweir         {
341cdf0e10cSrcweir             if(pSvtGraphicFill && !mnSvtGraphicFillCount)
342cdf0e10cSrcweir             {
343cdf0e10cSrcweir                 SvMemoryStream aMemStm;
344cdf0e10cSrcweir 
345cdf0e10cSrcweir                 aMemStm << *pSvtGraphicFill;
346cdf0e10cSrcweir                 mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
347cdf0e10cSrcweir                 mnSvtGraphicFillCount++;
348cdf0e10cSrcweir             }
349cdf0e10cSrcweir         }
350cdf0e10cSrcweir 
351cdf0e10cSrcweir         void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
352cdf0e10cSrcweir         {
353cdf0e10cSrcweir             if(pSvtGraphicFill && mnSvtGraphicFillCount)
354cdf0e10cSrcweir             {
355cdf0e10cSrcweir                 mnSvtGraphicFillCount--;
356cdf0e10cSrcweir                 mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END"));
357cdf0e10cSrcweir                 delete pSvtGraphicFill;
358cdf0e10cSrcweir             }
359cdf0e10cSrcweir         }
360cdf0e10cSrcweir 
361cdf0e10cSrcweir         SvtGraphicStroke* VclMetafileProcessor2D::impTryToCreateSvtGraphicStroke(
362cdf0e10cSrcweir             const basegfx::B2DPolygon& rB2DPolygon,
363cdf0e10cSrcweir             const basegfx::BColor* pColor,
364cdf0e10cSrcweir             const attribute::LineAttribute* pLineAttribute,
365cdf0e10cSrcweir             const attribute::StrokeAttribute* pStrokeAttribute,
366cdf0e10cSrcweir             const attribute::LineStartEndAttribute* pStart,
367cdf0e10cSrcweir             const attribute::LineStartEndAttribute* pEnd)
368cdf0e10cSrcweir         {
369cdf0e10cSrcweir             SvtGraphicStroke* pRetval = 0;
370cdf0e10cSrcweir 
371cdf0e10cSrcweir             if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount)
372cdf0e10cSrcweir             {
3739d531167SArmin Le Grand                 basegfx::B2DPolygon aLocalPolygon(rB2DPolygon);
374cdf0e10cSrcweir                 basegfx::BColor aStrokeColor;
375cdf0e10cSrcweir                 basegfx::B2DPolyPolygon aStartArrow;
376cdf0e10cSrcweir                 basegfx::B2DPolyPolygon aEndArrow;
377cdf0e10cSrcweir 
378cdf0e10cSrcweir                 if(pColor)
379cdf0e10cSrcweir                 {
380cdf0e10cSrcweir                     aStrokeColor = *pColor;
381cdf0e10cSrcweir                 }
382cdf0e10cSrcweir                 else if(pLineAttribute)
383cdf0e10cSrcweir                 {
384cdf0e10cSrcweir                     aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor());
385cdf0e10cSrcweir                 }
386cdf0e10cSrcweir 
387cdf0e10cSrcweir                 // It IS needed to record the stroke color at all in the metafile,
388cdf0e10cSrcweir                 // SvtGraphicStroke has NO entry for stroke color(!)
389cdf0e10cSrcweir                 mpOutputDevice->SetLineColor(Color(aStrokeColor));
390cdf0e10cSrcweir 
3919d531167SArmin Le Grand                 if(!aLocalPolygon.isClosed())
392cdf0e10cSrcweir                 {
393cdf0e10cSrcweir                     double fPolyLength(0.0);
3949d531167SArmin Le Grand                     double fStart(0.0);
3959d531167SArmin Le Grand                     double fEnd(0.0);
396cdf0e10cSrcweir 
397cdf0e10cSrcweir                     if(pStart && pStart->isActive())
398cdf0e10cSrcweir                     {
3999d531167SArmin Le Grand                         fPolyLength = basegfx::tools::getLength(aLocalPolygon);
400cdf0e10cSrcweir 
401cdf0e10cSrcweir                         aStartArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
4029d531167SArmin Le Grand                             aLocalPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(),
4039d531167SArmin Le Grand                             fPolyLength, pStart->isCentered() ? 0.5 : 0.0, &fStart);
404cdf0e10cSrcweir                     }
405cdf0e10cSrcweir 
406cdf0e10cSrcweir                     if(pEnd && pEnd->isActive())
407cdf0e10cSrcweir                     {
408cdf0e10cSrcweir                         if(basegfx::fTools::equalZero(fPolyLength))
409cdf0e10cSrcweir                         {
4109d531167SArmin Le Grand                             fPolyLength = basegfx::tools::getLength(aLocalPolygon);
411cdf0e10cSrcweir                         }
412cdf0e10cSrcweir 
413cdf0e10cSrcweir                         aEndArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
4149d531167SArmin Le Grand                             aLocalPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(),
4159d531167SArmin Le Grand                             fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, &fEnd);
4169d531167SArmin Le Grand                     }
4179d531167SArmin Le Grand 
4189d531167SArmin Le Grand                     if(0.0 != fStart || 0.0 != fEnd)
4199d531167SArmin Le Grand                     {
4209d531167SArmin Le Grand                         // build new poly, consume something from old poly
4219d531167SArmin Le Grand                         aLocalPolygon = basegfx::tools::getSnippetAbsolute(aLocalPolygon, fStart, fPolyLength - fEnd, fPolyLength);
422cdf0e10cSrcweir                     }
423cdf0e10cSrcweir                 }
424cdf0e10cSrcweir 
425cdf0e10cSrcweir                 SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone);
4265aaf853bSArmin Le Grand                 SvtGraphicStroke::CapType eCap(SvtGraphicStroke::capButt);
427cdf0e10cSrcweir                 double fLineWidth(0.0);
428cdf0e10cSrcweir                 double fMiterLength(0.0);
429cdf0e10cSrcweir                 SvtGraphicStroke::DashArray aDashArray;
430cdf0e10cSrcweir 
431cdf0e10cSrcweir                 if(pLineAttribute)
432cdf0e10cSrcweir                 {
433b22f5784SArmin Le Grand                     // pre-fill fLineWidth #119198# Need to apply maCurrentTransformation, too (!)
434b22f5784SArmin Le Grand                     const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(pLineAttribute->getWidth(), 0.0));
435b22f5784SArmin Le Grand                     fLineWidth = aDiscreteUnit.getLength();
436cdf0e10cSrcweir 
437cdf0e10cSrcweir                     // pre-fill fMiterLength
438cdf0e10cSrcweir                     fMiterLength = fLineWidth;
439cdf0e10cSrcweir 
440cdf0e10cSrcweir                     // get Join
441cdf0e10cSrcweir                     switch(pLineAttribute->getLineJoin())
442cdf0e10cSrcweir                     {
443cdf0e10cSrcweir                         default : // basegfx::B2DLINEJOIN_NONE :
444cdf0e10cSrcweir                         {
445cdf0e10cSrcweir                             eJoin = SvtGraphicStroke::joinNone;
446cdf0e10cSrcweir                             break;
447cdf0e10cSrcweir                         }
448cdf0e10cSrcweir                         case basegfx::B2DLINEJOIN_BEVEL :
449cdf0e10cSrcweir                         {
450cdf0e10cSrcweir                             eJoin = SvtGraphicStroke::joinBevel;
451cdf0e10cSrcweir                             break;
452cdf0e10cSrcweir                         }
453cdf0e10cSrcweir                         case basegfx::B2DLINEJOIN_MIDDLE :
454cdf0e10cSrcweir                         case basegfx::B2DLINEJOIN_MITER :
455cdf0e10cSrcweir                         {
456cdf0e10cSrcweir                             eJoin = SvtGraphicStroke::joinMiter;
457cdf0e10cSrcweir                             // ATM 15 degrees is assumed
458cdf0e10cSrcweir                             fMiterLength /= rtl::math::sin(M_PI * (15.0 / 360.0));
459cdf0e10cSrcweir                             break;
460cdf0e10cSrcweir                         }
461cdf0e10cSrcweir                         case basegfx::B2DLINEJOIN_ROUND :
462cdf0e10cSrcweir                         {
463cdf0e10cSrcweir                             eJoin = SvtGraphicStroke::joinRound;
464cdf0e10cSrcweir                             break;
465cdf0e10cSrcweir                         }
466cdf0e10cSrcweir                     }
4675aaf853bSArmin Le Grand 
4685aaf853bSArmin Le Grand                     // get stroke
4695aaf853bSArmin Le Grand                     switch(pLineAttribute->getLineCap())
4705aaf853bSArmin Le Grand                     {
4715aaf853bSArmin Le Grand                         default: /* com::sun::star::drawing::LineCap_BUTT */
4725aaf853bSArmin Le Grand                         {
4735aaf853bSArmin Le Grand                             eCap = SvtGraphicStroke::capButt;
4745aaf853bSArmin Le Grand                             break;
4755aaf853bSArmin Le Grand                         }
4765aaf853bSArmin Le Grand                         case com::sun::star::drawing::LineCap_ROUND:
4775aaf853bSArmin Le Grand                         {
4785aaf853bSArmin Le Grand                             eCap = SvtGraphicStroke::capRound;
4795aaf853bSArmin Le Grand                             break;
4805aaf853bSArmin Le Grand                         }
4815aaf853bSArmin Le Grand                         case com::sun::star::drawing::LineCap_SQUARE:
4825aaf853bSArmin Le Grand                         {
4835aaf853bSArmin Le Grand                             eCap = SvtGraphicStroke::capSquare;
4845aaf853bSArmin Le Grand                             break;
4855aaf853bSArmin Le Grand                         }
4865aaf853bSArmin Le Grand                     }
487cdf0e10cSrcweir                 }
488cdf0e10cSrcweir 
489cdf0e10cSrcweir                 if(pStrokeAttribute)
490cdf0e10cSrcweir                 {
491cdf0e10cSrcweir                     // copy dash array
492cdf0e10cSrcweir                     aDashArray = pStrokeAttribute->getDotDashArray();
493cdf0e10cSrcweir                 }
494cdf0e10cSrcweir 
495cdf0e10cSrcweir                 // #i101734# apply current object transformation to created geometry.
496cdf0e10cSrcweir                 // This is a partial fix. When a object transformation is used which
497cdf0e10cSrcweir                 // e.g. contains a scaleX != scaleY, an unproportional scaling would
498cdf0e10cSrcweir                 // have to be applied to the evtl. existing fat line. The current
499cdf0e10cSrcweir                 // concept of PDF export and SvtGraphicStroke usage does simply not
500cdf0e10cSrcweir                 // allow handling such definitions. The only clean way would be to
501cdf0e10cSrcweir                 // add the transformation to SvtGraphicStroke and to handle it there
5029d531167SArmin Le Grand                 aLocalPolygon.transform(maCurrentTransformation);
503cdf0e10cSrcweir                 aStartArrow.transform(maCurrentTransformation);
504cdf0e10cSrcweir                 aEndArrow.transform(maCurrentTransformation);
505cdf0e10cSrcweir 
506cdf0e10cSrcweir                 pRetval = new SvtGraphicStroke(
5079d531167SArmin Le Grand                     Polygon(aLocalPolygon),
508cdf0e10cSrcweir                     PolyPolygon(aStartArrow),
509cdf0e10cSrcweir                     PolyPolygon(aEndArrow),
510cdf0e10cSrcweir                     mfCurrentUnifiedTransparence,
511cdf0e10cSrcweir                     fLineWidth,
5125aaf853bSArmin Le Grand                     eCap,
513cdf0e10cSrcweir                     eJoin,
514cdf0e10cSrcweir                     fMiterLength,
515cdf0e10cSrcweir                     aDashArray);
516cdf0e10cSrcweir             }
517cdf0e10cSrcweir 
518cdf0e10cSrcweir             return pRetval;
519cdf0e10cSrcweir         }
520cdf0e10cSrcweir 
521cdf0e10cSrcweir         void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
522cdf0e10cSrcweir         {
523cdf0e10cSrcweir             if(pSvtGraphicStroke && !mnSvtGraphicStrokeCount)
524cdf0e10cSrcweir             {
525cdf0e10cSrcweir                 SvMemoryStream aMemStm;
526cdf0e10cSrcweir 
527cdf0e10cSrcweir                 aMemStm << *pSvtGraphicStroke;
528cdf0e10cSrcweir                 mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
529cdf0e10cSrcweir                 mnSvtGraphicStrokeCount++;
530cdf0e10cSrcweir             }
531cdf0e10cSrcweir         }
532cdf0e10cSrcweir 
533cdf0e10cSrcweir         void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
534cdf0e10cSrcweir         {
535cdf0e10cSrcweir             if(pSvtGraphicStroke && mnSvtGraphicStrokeCount)
536cdf0e10cSrcweir             {
537cdf0e10cSrcweir                 mnSvtGraphicStrokeCount--;
538cdf0e10cSrcweir                 mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END"));
539cdf0e10cSrcweir                 delete pSvtGraphicStroke;
540cdf0e10cSrcweir             }
541cdf0e10cSrcweir         }
542cdf0e10cSrcweir 
543cdf0e10cSrcweir         // init static break iterator
544cdf0e10cSrcweir         uno::Reference< ::com::sun::star::i18n::XBreakIterator > VclMetafileProcessor2D::mxBreakIterator;
545cdf0e10cSrcweir 
546cdf0e10cSrcweir         VclMetafileProcessor2D::VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev)
547cdf0e10cSrcweir         :   VclProcessor2D(rViewInformation, rOutDev),
548cdf0e10cSrcweir             mpMetaFile(rOutDev.GetConnectMetaFile()),
549cdf0e10cSrcweir             mnSvtGraphicFillCount(0),
550cdf0e10cSrcweir             mnSvtGraphicStrokeCount(0),
551cdf0e10cSrcweir             mfCurrentUnifiedTransparence(0.0),
552cdf0e10cSrcweir             mpPDFExtOutDevData(dynamic_cast< vcl::PDFExtOutDevData* >(rOutDev.GetExtOutDevData()))
553cdf0e10cSrcweir         {
554cdf0e10cSrcweir             OSL_ENSURE(rOutDev.GetConnectMetaFile(), "VclMetafileProcessor2D: Used on OutDev which has no MetaFile Target (!)");
555cdf0e10cSrcweir             // draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation
556cdf0e10cSrcweir             // but only to ObjectTransformation. Do not change MapMode of destination.
557cdf0e10cSrcweir             maCurrentTransformation = rViewInformation.getObjectTransformation();
558cdf0e10cSrcweir         }
559cdf0e10cSrcweir 
560cdf0e10cSrcweir         VclMetafileProcessor2D::~VclMetafileProcessor2D()
561cdf0e10cSrcweir         {
562cdf0e10cSrcweir             // MapMode was not changed, no restore necessary
563cdf0e10cSrcweir         }
564cdf0e10cSrcweir 
565cdf0e10cSrcweir         /***********************************************************************************************
566cdf0e10cSrcweir 
567cdf0e10cSrcweir             Support of MetaCommentActions in the VclMetafileProcessor2D
568cdf0e10cSrcweir             Found MetaCommentActions and how they are supported:
569cdf0e10cSrcweir 
570cdf0e10cSrcweir             XGRAD_SEQ_BEGIN, XGRAD_SEQ_END:
571cdf0e10cSrcweir 
572cdf0e10cSrcweir             Used inside OutputDevice::DrawGradient to mark the start and end of a MetaGradientEx action.
573cdf0e10cSrcweir             It is used in various exporters/importers to have direct access to the gradient before it
574cdf0e10cSrcweir             is rendered by VCL (and thus fragmented to polygon color actions and others). On that base, e.g.
575cdf0e10cSrcweir             the Metafile to SdrObject import creates it's gradient objects.
576cdf0e10cSrcweir             Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
577cdf0e10cSrcweir             map it back to the corresponding tools PolyPolygon and the Gradient and just call
578cdf0e10cSrcweir             OutputDevice::DrawGradient which creates the necessary compatible actions.
579cdf0e10cSrcweir 
580cdf0e10cSrcweir             XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END:
581cdf0e10cSrcweir 
582cdf0e10cSrcweir             Two producers, one is vcl/source/gdi/gdimtf.cxx, line 1273. There, it is transformed
583cdf0e10cSrcweir             inside GDIMetaFile::Rotate, nothing to take care of here.
584cdf0e10cSrcweir             The second producer is in graphics/svx/source/svdraw/impgrfll.cxx, line 374. This is used
585cdf0e10cSrcweir             with each incarnation of Imp_GraphicFill when a metafile is recorded, fillstyle is not
586cdf0e10cSrcweir             XFILL_NONE and not completely transparent. It creates a SvtGraphicFill and streams it
587cdf0e10cSrcweir             to the comment action. A closing end token is created in the destructor.
588cdf0e10cSrcweir             Usages of Imp_GraphicFill are in Do_Paint_Object-methods of SdrCircObj, SdrPathObj and
589cdf0e10cSrcweir             SdrRectObj.
590cdf0e10cSrcweir             The token users pick various actions from SvtGraphicFill, so it may need to be added for all kind
591cdf0e10cSrcweir             of filled objects, even simple colored polygons. It is added as extra information; the
592cdf0e10cSrcweir             Metafile actions between the two tokens are interpreted as output generated from those
593cdf0e10cSrcweir             fills. Thus, users have the choice to use the SvtGraphicFill info or the created output
594cdf0e10cSrcweir             actions.
595cdf0e10cSrcweir             Even for XFillTransparenceItem it is used, thus it may need to be supported in
596cdf0e10cSrcweir             UnifiedTransparencePrimitive2D, too, when interpreted as normally filled PolyPolygon.
597cdf0e10cSrcweir             Implemented for:
598035a2f44SArmin Le Grand                 PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D,
599cdf0e10cSrcweir                 PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D,
600cdf0e10cSrcweir                 PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
601cdf0e10cSrcweir                 PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D,
602cdf0e10cSrcweir                 and for PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D when detected unified transparence
603cdf0e10cSrcweir 
604cdf0e10cSrcweir             XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END:
605cdf0e10cSrcweir 
606cdf0e10cSrcweir             Similar to pathfill, but using SvtGraphicStroke instead. It also has two producers where one
607cdf0e10cSrcweir             is also the GDIMetaFile::Rotate. Another user is MetaCommentAction::Move which modifies the
608cdf0e10cSrcweir             contained path accordingly.
609cdf0e10cSrcweir             The other one is SdrObject::Imp_DrawLineGeometry. It's done when MetaFile is set at OutDev and
610cdf0e10cSrcweir             only when geometry is a single polygon (!). I see no reason for that; in the PS exporter this
611cdf0e10cSrcweir             would hinder to make use of PolyPolygon strokes. I will need to add support at:
612cdf0e10cSrcweir                 PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
613cdf0e10cSrcweir                 PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
614cdf0e10cSrcweir                 PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D
615cdf0e10cSrcweir             This can be done hierarchical, too.
616cdf0e10cSrcweir             Okay, base implementation done based on those three primitives.
617cdf0e10cSrcweir 
618cdf0e10cSrcweir             FIELD_SEQ_BEGIN, FIELD_SEQ_END
619cdf0e10cSrcweir 
620cdf0e10cSrcweir             Used from slideshow for URLs, created from diverse SvxField implementations inside
621cdf0e10cSrcweir             createBeginComment()/createEndComment(). createBeginComment() is used from editeng\impedit3.cxx
622cdf0e10cSrcweir             inside ImpEditEngine::Paint.
623cdf0e10cSrcweir             Created TextHierarchyFieldPrimitive2D and added needed infos there; it is an group primitive and wraps
624cdf0e10cSrcweir             text primitives (but is not limited to that). It contains the field type if special actions for the
625cdf0e10cSrcweir             support of FIELD_SEQ_BEGIN/END are needed; this is the case for Page and URL fields. If more is
626cdf0e10cSrcweir             needed, it may be supported there.
627cdf0e10cSrcweir             FIELD_SEQ_BEGIN;PageField
628cdf0e10cSrcweir             FIELD_SEQ_END
629cdf0e10cSrcweir             Okay, these are now completely supported by TextHierarchyFieldPrimitive2D. URL works, too.
630cdf0e10cSrcweir 
631cdf0e10cSrcweir             XTEXT
632cdf0e10cSrcweir 
633cdf0e10cSrcweir             XTEXT_EOC(i) end of character
634cdf0e10cSrcweir             XTEXT_EOW(i) end of word
635cdf0e10cSrcweir             XTEXT_EOS(i) end of sentence
636cdf0e10cSrcweir 
637cdf0e10cSrcweir             this three are with index and are created with the help of a i18n::XBreakIterator in
638cdf0e10cSrcweir             ImplDrawWithComments. Simplifying, moving out text painting, reworking to create some
639cdf0e10cSrcweir             data structure for holding those TEXT infos.
640cdf0e10cSrcweir             Supported directly by TextSimplePortionPrimitive2D with adding a Locale to the basic text
641cdf0e10cSrcweir             primitive. In the MetaFileRenderer, the creation is now done (see below). This has the advantage
642cdf0e10cSrcweir             that this creations do not need to be done for all paints all the time. This would be
643cdf0e10cSrcweir             expensive since the BreakIterator and it's usage is expensive and for each paint also the
644cdf0e10cSrcweir             whole character stops would need to be created.
645cdf0e10cSrcweir             Created only for TextDecoratedPortionPrimitive2D due to XTEXT_EOL and XTEXT_EOP (see below)
646cdf0e10cSrcweir 
647cdf0e10cSrcweir             XTEXT_EOL() end of line
648cdf0e10cSrcweir             XTEXT_EOP() end of paragraph
649cdf0e10cSrcweir 
650cdf0e10cSrcweir             First try with boolean marks at TextDecoratedPortionPrimitive2D did not work too well,
651cdf0e10cSrcweir             i decided to solve it with structure. I added the TextHierarchyPrimitives for this,
652cdf0e10cSrcweir             namely:
653cdf0e10cSrcweir             - TextHierarchyLinePrimitive2D: Encapsulates single line
654cdf0e10cSrcweir             - TextHierarchyParagraphPrimitive2D: Encapsulates single paragraph
655cdf0e10cSrcweir             - TextHierarchyBlockPrimitive2D: encapsulates object texts (only one ATM)
656cdf0e10cSrcweir             Those are now supported in hierarchy. This means the MetaFile renderer will support them
657cdf0e10cSrcweir             by using them, reculrively using their content and adding MetaFile comments as needed.
658cdf0e10cSrcweir             This also means that when another text layouter will be used it will be necessary to
659cdf0e10cSrcweir             create/support the same HierarchyPrimitives to support users.
660cdf0e10cSrcweir             To transport the information using this hierarchy is best suited to all future needs;
661cdf0e10cSrcweir             the slideshow will be able to profit from it directly when using primitives; all other
662cdf0e10cSrcweir             renderers not interested in the text structure will just ignore the encapsulations.
663cdf0e10cSrcweir 
664cdf0e10cSrcweir             XTEXT_PAINTSHAPE_BEGIN, XTEXT_PAINTSHAPE_END
665cdf0e10cSrcweir             Supported now by the TextHierarchyBlockPrimitive2D.
666cdf0e10cSrcweir 
667cdf0e10cSrcweir             EPSReplacementGraphic:
668cdf0e10cSrcweir             Only used in goodies\source\filter.vcl\ieps\ieps.cxx and svx\source\xml\xmlgrhlp.cxx to
669cdf0e10cSrcweir             hold the original EPS which was imported in the same MetaFile as first 2 entries. Only
670cdf0e10cSrcweir             used to export the original again (if exists).
671cdf0e10cSrcweir             Not necessary to support with MetaFuleRenderer.
672cdf0e10cSrcweir 
673cdf0e10cSrcweir             XTEXT_SCROLLRECT, XTEXT_PAINTRECT
674cdf0e10cSrcweir             Currently used to get extra MetaFile infos using GraphicExporter which again uses
675cdf0e10cSrcweir             SdrTextObj::GetTextScrollMetaFileAndRectangle(). ATM works with primitives since
676cdf0e10cSrcweir             the rectangle data is added directly by the GraphicsExporter as comment. Does not need
677cdf0e10cSrcweir             to be adapted at once.
678cdf0e10cSrcweir             When adapting later, the only user - the diashow - should directly use the provided
679cdf0e10cSrcweir             Anination infos in the appropriate primitives (e.g. AnimatedSwitchPrimitive2D)
680cdf0e10cSrcweir 
681cdf0e10cSrcweir             PRNSPOOL_TRANSPARENTBITMAP_BEGIN, PRNSPOOL_TRANSPARENTBITMAP_END
682cdf0e10cSrcweir             VCL usage when printing PL -> THB. Okay, THB confirms that it is only used as
683cdf0e10cSrcweir             a fix (hack) while VCL printing. It is needed to not downscale a bitmap which
684cdf0e10cSrcweir             was explicitely created for the printer already again to some default maximum
685cdf0e10cSrcweir             bitmap sizes.
686cdf0e10cSrcweir             Nothing to do here for the primitive renderer.
687cdf0e10cSrcweir 
688cdf0e10cSrcweir             Support for vcl::PDFExtOutDevData:
689cdf0e10cSrcweir             PL knows that SJ did that stuff, it's used to hold a pointer to PDFExtOutDevData at
690cdf0e10cSrcweir             the OutDev. When set, some extra data is written there. Trying simple PDF export and
691cdf0e10cSrcweir             watching if i get those infos.
692cdf0e10cSrcweir             Well, a PDF export does not use e.g. ImpEditEngine::Paint since the PdfFilter uses
693cdf0e10cSrcweir             the SdXImpressDocument::render and thus uses the VclMetafileProcessor2D. I will check
694cdf0e10cSrcweir             if i get a PDFExtOutDevData at the target output device.
695cdf0e10cSrcweir             Indeed, i get one. Checking what all may be done when that extra-device-info is there.
696cdf0e10cSrcweir 
697cdf0e10cSrcweir             All in all i have to talk to SJ. I will need to emulate some of those actions, but
698cdf0e10cSrcweir             i need to discuss which ones.
699cdf0e10cSrcweir             In the future, all those infos would be taken from the primitive sequence anyways,
700cdf0e10cSrcweir             thus these extensions would potentially be temporary, too.
701cdf0e10cSrcweir             Discussed with SJ, added the necessary support and tested it. Details follow.
702cdf0e10cSrcweir 
703cdf0e10cSrcweir             - In ImpEditEngine::Paint, paragraph infos and URL stuff is added.
704cdf0e10cSrcweir               Added in primitive MetaFile renderer.
705cdf0e10cSrcweir               Checking URL: Indeed, current version exports it, but it is missing in primitive
706cdf0e10cSrcweir               CWS version. Adding support.
707cdf0e10cSrcweir               Okay, URLs work. Checked, Done.
708cdf0e10cSrcweir 
709cdf0e10cSrcweir             - UnoControlPDFExportContact is only created when PDFExtOutDevData is used at the
710cdf0e10cSrcweir               target and uno control data is created in UnoControlPDFExportContact::do_PaintObject.
711cdf0e10cSrcweir               This may be added in primitive MetaFile renderer.
712cdf0e10cSrcweir               Adding support...
713cdf0e10cSrcweir               OOps, the necessary helper stuff is in svx/source/form/formpdxexport.cxx in namespace
714cdf0e10cSrcweir               svxform. Have to talk to FS if this has to be like that. Especially since
715cdf0e10cSrcweir               ::vcl::PDFWriter::AnyWidget is filled out, which is already part of vcl.
716cdf0e10cSrcweir               Wrote an eMail to FS, he is on vacation currently. I see no reason why not to move
717cdf0e10cSrcweir               that stuff to somewhere else, maybe tools or svtools ?!? We will see...
718cdf0e10cSrcweir               Moved to toolkit, so i have to link against it. I tried VCL first, but it did
719cdf0e10cSrcweir               not work since VCLUnoHelper::CreateFont is unresolved in VCL (!). Other then the name
720cdf0e10cSrcweir               may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself,
721cdf0e10cSrcweir               the lowest move,ment plave is toolkit.
722cdf0e10cSrcweir               Checked form control export, it works well. Done.
723cdf0e10cSrcweir 
724cdf0e10cSrcweir             - In goodies, in GraphicObject::Draw, when the used Graphic is linked, infos are
725cdf0e10cSrcweir               generated. I will need to check what happens here with primitives.
726cdf0e10cSrcweir               To support, use of GraphicPrimitive2D (PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) may be needed.
727cdf0e10cSrcweir               Added support, but feature is broken in main version, so i cannot test at all.
728cdf0e10cSrcweir               Writing a bug to CL (or SJ) and seeing what happens (#i80380#).
729cdf0e10cSrcweir               SJ took a look and we got it working. Tested VCL MetaFile Renderer based export,
730cdf0e10cSrcweir               as intended, the original file is exported. Works, Done.
731cdf0e10cSrcweir 
732cdf0e10cSrcweir 
733cdf0e10cSrcweir 
734cdf0e10cSrcweir 
735cdf0e10cSrcweir             To be done:
736cdf0e10cSrcweir 
737cdf0e10cSrcweir             - Maybe there are more places to take care of for vcl::PDFExtOutDevData!
738cdf0e10cSrcweir 
739cdf0e10cSrcweir 
740cdf0e10cSrcweir 
741cdf0e10cSrcweir         ****************************************************************************************************/
742cdf0e10cSrcweir 
743cdf0e10cSrcweir         void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
744cdf0e10cSrcweir         {
745cdf0e10cSrcweir             switch(rCandidate.getPrimitive2DID())
746cdf0e10cSrcweir             {
747cdf0e10cSrcweir                 case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
748cdf0e10cSrcweir                 {
749cdf0e10cSrcweir                     // directdraw of wrong spell primitive
750cdf0e10cSrcweir                     // Ignore for VclMetafileProcessor2D, this is for printing and MetaFile recording only
751cdf0e10cSrcweir                     break;
752cdf0e10cSrcweir                 }
753cdf0e10cSrcweir                 case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D :
754cdf0e10cSrcweir                 {
755cdf0e10cSrcweir                     const primitive2d::GraphicPrimitive2D& rGraphicPrimitive = static_cast< const primitive2d::GraphicPrimitive2D& >(rCandidate);
756cdf0e10cSrcweir                     bool bUsingPDFExtOutDevData(false);
757cdf0e10cSrcweir                     basegfx::B2DVector aTranslate, aScale;
758cdf0e10cSrcweir                     static bool bSuppressPDFExtOutDevDataSupport(false);
759cdf0e10cSrcweir 
760cdf0e10cSrcweir                     if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
761cdf0e10cSrcweir                     {
762cdf0e10cSrcweir                         // emulate data handling from UnoControlPDFExportContact, original see
763cdf0e10cSrcweir                         // svtools/source/graphic/grfmgr.cxx
764cdf0e10cSrcweir                         const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
765cdf0e10cSrcweir 
766cdf0e10cSrcweir                         if(rGraphic.IsLink())
767cdf0e10cSrcweir                         {
768cdf0e10cSrcweir                             const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
769cdf0e10cSrcweir 
770cdf0e10cSrcweir                             if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted())
771cdf0e10cSrcweir                             {
772cdf0e10cSrcweir                                 const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform();
773cdf0e10cSrcweir                                 double fRotate, fShearX;
774cdf0e10cSrcweir                                 rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
775cdf0e10cSrcweir 
776cdf0e10cSrcweir                                 if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) )
777cdf0e10cSrcweir                                 {
778cdf0e10cSrcweir                                     bUsingPDFExtOutDevData = true;
779cdf0e10cSrcweir                                     mpPDFExtOutDevData->BeginGroup();
780cdf0e10cSrcweir                                 }
781cdf0e10cSrcweir                             }
782cdf0e10cSrcweir                         }
783cdf0e10cSrcweir                     }
784cdf0e10cSrcweir 
785cdf0e10cSrcweir                     // process recursively and add MetaFile comment
786cdf0e10cSrcweir                     process(rGraphicPrimitive.get2DDecomposition(getViewInformation2D()));
787cdf0e10cSrcweir 
788cdf0e10cSrcweir                     if(bUsingPDFExtOutDevData)
789cdf0e10cSrcweir                     {
790cdf0e10cSrcweir                         // emulate data handling from UnoControlPDFExportContact, original see
791cdf0e10cSrcweir                         // svtools/source/graphic/grfmgr.cxx
792cdf0e10cSrcweir                         const basegfx::B2DRange aCurrentRange(
793cdf0e10cSrcweir                             aTranslate.getX(), aTranslate.getY(),
794cdf0e10cSrcweir                             aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
795cdf0e10cSrcweir                         const Rectangle aCurrentRect(
796cdf0e10cSrcweir                             sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())),
797cdf0e10cSrcweir                             sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY())));
798cdf0e10cSrcweir                         const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
799cdf0e10cSrcweir                         Rectangle aCropRect;
800cdf0e10cSrcweir 
801cdf0e10cSrcweir                         if(rAttr.IsCropped())
802cdf0e10cSrcweir                         {
803cdf0e10cSrcweir                             // calculate scalings between real image size and logic object size. This
804cdf0e10cSrcweir                             // is necessary since the crop values are relative to original bitmap size
805cdf0e10cSrcweir                             double fFactorX(1.0);
806cdf0e10cSrcweir                             double fFactorY(1.0);
807cdf0e10cSrcweir 
808cdf0e10cSrcweir                             {
809cdf0e10cSrcweir                                 const MapMode aMapMode100thmm(MAP_100TH_MM);
810cdf0e10cSrcweir                                 const Size aBitmapSize(Application::GetDefaultDevice()->LogicToLogic(
811cdf0e10cSrcweir                                     rGraphicPrimitive.getGraphicObject().GetPrefSize(),
812cdf0e10cSrcweir                                     rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm));
813cdf0e10cSrcweir                                 const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop());
814cdf0e10cSrcweir                                 const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop());
815cdf0e10cSrcweir 
816cdf0e10cSrcweir                                 if(!basegfx::fTools::equalZero(fDivX))
817cdf0e10cSrcweir                                 {
818cdf0e10cSrcweir                                     fFactorX = aScale.getX() / fDivX;
819cdf0e10cSrcweir                                 }
820cdf0e10cSrcweir 
821cdf0e10cSrcweir                                 if(!basegfx::fTools::equalZero(fDivY))
822cdf0e10cSrcweir                                 {
823cdf0e10cSrcweir                                     fFactorY = aScale.getY() / fDivY;
824cdf0e10cSrcweir                                 }
825cdf0e10cSrcweir                             }
826cdf0e10cSrcweir 
827cdf0e10cSrcweir                             // calculate crop range and rect
828cdf0e10cSrcweir                             basegfx::B2DRange aCropRange;
829cdf0e10cSrcweir                             aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY));
830cdf0e10cSrcweir                             aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY));
831cdf0e10cSrcweir 
832cdf0e10cSrcweir                             aCropRect = Rectangle(
833cdf0e10cSrcweir                                 sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())),
834cdf0e10cSrcweir                                 sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY())));
835cdf0e10cSrcweir                         }
836cdf0e10cSrcweir 
837a133aed6SArmin Le Grand                         // #123295# 3rd param is uncropped rect, 4th is cropped. The primitive has the cropped
838a133aed6SArmin Le Grand                         // object transformation, thus aCurrentRect *is* the clip region while aCropRect is the expanded,
839a133aed6SArmin Le Grand                         // uncropped region. Thus, correct order is aCropRect, aCurrentRect
840cdf0e10cSrcweir                         mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(),
841cdf0e10cSrcweir                             rAttr.GetTransparency(),
842a133aed6SArmin Le Grand                             aCropRect,
843a133aed6SArmin Le Grand                             aCurrentRect);
844cdf0e10cSrcweir                     }
845cdf0e10cSrcweir 
846cdf0e10cSrcweir                     break;
847cdf0e10cSrcweir                 }
848cdf0e10cSrcweir                 case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
849cdf0e10cSrcweir                 {
850cdf0e10cSrcweir                     const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate);
851cdf0e10cSrcweir                     const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
852cdf0e10cSrcweir                     bool bIsPrintableControl(false);
853cdf0e10cSrcweir 
854cdf0e10cSrcweir                     // find out if control is printable
855cdf0e10cSrcweir                     if(rXControl.is())
856cdf0e10cSrcweir                     {
857cdf0e10cSrcweir                         try
858cdf0e10cSrcweir                         {
859cdf0e10cSrcweir                             uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY);
860cdf0e10cSrcweir                             uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is()
861cdf0e10cSrcweir                                 ? xModelProperties->getPropertySetInfo()
862cdf0e10cSrcweir                                 : uno::Reference< beans::XPropertySetInfo >());
863cdf0e10cSrcweir                             const ::rtl::OUString sPrintablePropertyName(RTL_CONSTASCII_USTRINGPARAM("Printable"));
864cdf0e10cSrcweir 
865cdf0e10cSrcweir                             if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName))
866cdf0e10cSrcweir                             {
867cdf0e10cSrcweir                                 OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl);
868cdf0e10cSrcweir                             }
869cdf0e10cSrcweir                         }
870cdf0e10cSrcweir                         catch(const uno::Exception&)
871cdf0e10cSrcweir                         {
872cdf0e10cSrcweir                             OSL_ENSURE(false, "VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!");
873cdf0e10cSrcweir                         }
874cdf0e10cSrcweir                     }
875cdf0e10cSrcweir 
876cdf0e10cSrcweir                     // PDF export and printing only for printable controls
877cdf0e10cSrcweir                     if(bIsPrintableControl)
878cdf0e10cSrcweir                     {
879cdf0e10cSrcweir                         const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
880cdf0e10cSrcweir                         bool bDoProcessRecursively(true);
881cdf0e10cSrcweir 
882cdf0e10cSrcweir                         if(bPDFExport)
883cdf0e10cSrcweir                         {
884cdf0e10cSrcweir                             // PDF export. Emulate data handling from UnoControlPDFExportContact
885cdf0e10cSrcweir                             // I have now moved describePDFControl to toolkit, thus i can implement the PDF
886cdf0e10cSrcweir                             // form control support now as follows
887cdf0e10cSrcweir                             ::std::auto_ptr< ::vcl::PDFWriter::AnyWidget > pPDFControl;
888cdf0e10cSrcweir                             ::toolkitform::describePDFControl( rXControl, pPDFControl, *mpPDFExtOutDevData );
889cdf0e10cSrcweir 
890cdf0e10cSrcweir                             if(pPDFControl.get())
891cdf0e10cSrcweir                             {
892cdf0e10cSrcweir                                 // still need to fill in the location (is a class Rectangle)
893cdf0e10cSrcweir                                 const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D()));
894cdf0e10cSrcweir                                 const Rectangle aRectLogic(
895cdf0e10cSrcweir                                     (sal_Int32)floor(aRangeLogic.getMinX()), (sal_Int32)floor(aRangeLogic.getMinY()),
896cdf0e10cSrcweir                                     (sal_Int32)ceil(aRangeLogic.getMaxX()), (sal_Int32)ceil(aRangeLogic.getMaxY()));
897cdf0e10cSrcweir                                 pPDFControl->Location = aRectLogic;
898cdf0e10cSrcweir 
899cdf0e10cSrcweir                                 Size aFontSize(pPDFControl->TextFont.GetSize());
900cdf0e10cSrcweir                                 aFontSize = mpOutputDevice->LogicToLogic(aFontSize, MapMode(MAP_POINT), mpOutputDevice->GetMapMode());
901cdf0e10cSrcweir                                 pPDFControl->TextFont.SetSize(aFontSize);
902cdf0e10cSrcweir 
903cdf0e10cSrcweir                                 mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form);
904cdf0e10cSrcweir                                 mpPDFExtOutDevData->CreateControl(*pPDFControl.get());
905cdf0e10cSrcweir                                 mpPDFExtOutDevData->EndStructureElement();
906cdf0e10cSrcweir 
907cdf0e10cSrcweir                                 // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject);
908cdf0e10cSrcweir                                 // do not process recursively
909cdf0e10cSrcweir                                 bDoProcessRecursively = false;
910cdf0e10cSrcweir                             }
911cdf0e10cSrcweir                             else
912cdf0e10cSrcweir                             {
913cdf0e10cSrcweir                                 // PDF export did not work, try simple output.
914cdf0e10cSrcweir                                 // Fallback to printer output by not setting bDoProcessRecursively
915cdf0e10cSrcweir                                 // to false.
916cdf0e10cSrcweir                             }
917cdf0e10cSrcweir                         }
918cdf0e10cSrcweir 
919cdf0e10cSrcweir                         // #i93169# used flag the wrong way; true means that nothing was done yet
920cdf0e10cSrcweir                         if(bDoProcessRecursively)
921cdf0e10cSrcweir                         {
922cdf0e10cSrcweir                             // printer output
923cdf0e10cSrcweir                             try
924cdf0e10cSrcweir                             {
925cdf0e10cSrcweir                                 // remember old graphics and create new
926cdf0e10cSrcweir                                 uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW);
927cdf0e10cSrcweir                                 const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics());
928cdf0e10cSrcweir                                 const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics());
929cdf0e10cSrcweir 
930cdf0e10cSrcweir                                 if(xNewGraphics.is())
931cdf0e10cSrcweir                                 {
932cdf0e10cSrcweir                                     // link graphics and view
933cdf0e10cSrcweir                                     xControlView->setGraphics(xNewGraphics);
934cdf0e10cSrcweir 
935cdf0e10cSrcweir                                     // get position
936cdf0e10cSrcweir                                     const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform());
937cdf0e10cSrcweir                                     const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0));
938cdf0e10cSrcweir 
939cdf0e10cSrcweir                                     // draw it
940cdf0e10cSrcweir                                     xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY()));
941cdf0e10cSrcweir                                     bDoProcessRecursively = false;
942cdf0e10cSrcweir 
943cdf0e10cSrcweir                                     // restore original graphics
944cdf0e10cSrcweir                                     xControlView->setGraphics(xOriginalGraphics);
945cdf0e10cSrcweir                                 }
946cdf0e10cSrcweir                             }
947cdf0e10cSrcweir                             catch( const uno::Exception& )
948cdf0e10cSrcweir                             {
949cdf0e10cSrcweir                                 OSL_ENSURE(false, "VclMetafileProcessor2D: Printing of Control failed, caught an exception!");
950cdf0e10cSrcweir                             }
951cdf0e10cSrcweir                         }
952cdf0e10cSrcweir 
953cdf0e10cSrcweir                         // process recursively if not done yet to export as decomposition (bitmap)
954cdf0e10cSrcweir                         if(bDoProcessRecursively)
955cdf0e10cSrcweir                         {
956cdf0e10cSrcweir                             process(rControlPrimitive.get2DDecomposition(getViewInformation2D()));
957cdf0e10cSrcweir                         }
958cdf0e10cSrcweir                     }
959cdf0e10cSrcweir 
960cdf0e10cSrcweir                     break;
961cdf0e10cSrcweir                 }
962cdf0e10cSrcweir                 case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D :
963cdf0e10cSrcweir                 {
964cdf0e10cSrcweir                     // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to)
965cdf0e10cSrcweir                     // thus do the MetafileAction embedding stuff but just handle recursively.
966cdf0e10cSrcweir                     const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive = static_cast< const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate);
967cdf0e10cSrcweir                     static const ByteString aCommentStringCommon("FIELD_SEQ_BEGIN");
968cdf0e10cSrcweir                     static const ByteString aCommentStringPage("FIELD_SEQ_BEGIN;PageField");
969cdf0e10cSrcweir                     static const ByteString aCommentStringEnd("FIELD_SEQ_END");
970cdf0e10cSrcweir 
971cdf0e10cSrcweir                     switch(rFieldPrimitive.getType())
972cdf0e10cSrcweir                     {
973cdf0e10cSrcweir                         default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON :
974cdf0e10cSrcweir                         {
975cdf0e10cSrcweir                             mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon));
976cdf0e10cSrcweir                             break;
977cdf0e10cSrcweir                         }
978cdf0e10cSrcweir                         case drawinglayer::primitive2d::FIELD_TYPE_PAGE :
979cdf0e10cSrcweir                         {
980cdf0e10cSrcweir                             mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage));
981cdf0e10cSrcweir                             break;
982cdf0e10cSrcweir                         }
983cdf0e10cSrcweir                         case drawinglayer::primitive2d::FIELD_TYPE_URL :
984cdf0e10cSrcweir                         {
985cdf0e10cSrcweir                             const rtl::OUString& rURL = rFieldPrimitive.getString();
986cdf0e10cSrcweir                             const String aOldString(rURL);
987cdf0e10cSrcweir                             mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast< const sal_uInt8* >(aOldString.GetBuffer()), 2 * aOldString.Len()));
988cdf0e10cSrcweir                             break;
989cdf0e10cSrcweir                         }
990cdf0e10cSrcweir                     }
991cdf0e10cSrcweir 
992cdf0e10cSrcweir                     // process recursively
993cdf0e10cSrcweir                     const primitive2d::Primitive2DSequence rContent = rFieldPrimitive.get2DDecomposition(getViewInformation2D());
994cdf0e10cSrcweir                     process(rContent);
995cdf0e10cSrcweir 
996cdf0e10cSrcweir                     // for the end comment the type is not relevant yet, they are all the same. Just add.
997cdf0e10cSrcweir                     mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd));
998cdf0e10cSrcweir 
999cdf0e10cSrcweir                     if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType())
1000cdf0e10cSrcweir                     {
1001cdf0e10cSrcweir                         // emulate data handling from ImpEditEngine::Paint
1002cdf0e10cSrcweir                         const basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
1003cdf0e10cSrcweir                         const Rectangle aRectLogic(
1004cdf0e10cSrcweir                             (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()),
1005cdf0e10cSrcweir                             (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
1006cdf0e10cSrcweir                         vcl::PDFExtOutDevBookmarkEntry aBookmark;
1007cdf0e10cSrcweir                         aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic);
1008cdf0e10cSrcweir                         aBookmark.aBookmark = rFieldPrimitive.getString();
1009cdf0e10cSrcweir                         std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks();
1010cdf0e10cSrcweir                         rBookmarks.push_back( aBookmark );
1011cdf0e10cSrcweir                     }
1012cdf0e10cSrcweir 
1013cdf0e10cSrcweir                     break;
1014cdf0e10cSrcweir                 }
1015cdf0e10cSrcweir                 case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D :
1016cdf0e10cSrcweir                 {
1017cdf0e10cSrcweir                     const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive = static_cast< const primitive2d::TextHierarchyLinePrimitive2D& >(rCandidate);
1018cdf0e10cSrcweir                     static const ByteString aCommentString("XTEXT_EOL");
1019cdf0e10cSrcweir 
1020cdf0e10cSrcweir                     // process recursively and add MetaFile comment
1021cdf0e10cSrcweir                     process(rLinePrimitive.get2DDecomposition(getViewInformation2D()));
1022cdf0e10cSrcweir                     mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
1023cdf0e10cSrcweir 
1024cdf0e10cSrcweir                     break;
1025cdf0e10cSrcweir                 }
1026cdf0e10cSrcweir                 case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D :
1027cdf0e10cSrcweir                 {
1028cdf0e10cSrcweir                     // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The
1029cdf0e10cSrcweir                     // "XTEXT_EOC" is used, use here, too.
1030cdf0e10cSrcweir                     const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive = static_cast< const primitive2d::TextHierarchyBulletPrimitive2D& >(rCandidate);
1031cdf0e10cSrcweir                     static const ByteString aCommentString("XTEXT_EOC");
1032cdf0e10cSrcweir 
1033cdf0e10cSrcweir                     // process recursively and add MetaFile comment
1034cdf0e10cSrcweir                     process(rBulletPrimitive.get2DDecomposition(getViewInformation2D()));
1035cdf0e10cSrcweir                     mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
1036cdf0e10cSrcweir 
1037cdf0e10cSrcweir                     break;
1038cdf0e10cSrcweir                 }
1039cdf0e10cSrcweir                 case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D :
1040cdf0e10cSrcweir                 {
1041cdf0e10cSrcweir                     const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive = static_cast< const primitive2d::TextHierarchyParagraphPrimitive2D& >(rCandidate);
1042cdf0e10cSrcweir                     static const ByteString aCommentString("XTEXT_EOP");
1043cdf0e10cSrcweir 
1044cdf0e10cSrcweir                     if(mpPDFExtOutDevData)
1045cdf0e10cSrcweir                     {
1046cdf0e10cSrcweir                         // emulate data handling from ImpEditEngine::Paint
1047cdf0e10cSrcweir                         mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
1048cdf0e10cSrcweir                     }
1049cdf0e10cSrcweir 
1050cdf0e10cSrcweir                     // process recursively and add MetaFile comment
1051cdf0e10cSrcweir                     process(rParagraphPrimitive.get2DDecomposition(getViewInformation2D()));
1052cdf0e10cSrcweir                     mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
1053cdf0e10cSrcweir 
1054cdf0e10cSrcweir                     if(mpPDFExtOutDevData)
1055cdf0e10cSrcweir                     {
1056cdf0e10cSrcweir                         // emulate data handling from ImpEditEngine::Paint
1057cdf0e10cSrcweir                         mpPDFExtOutDevData->EndStructureElement();
1058cdf0e10cSrcweir                     }
1059cdf0e10cSrcweir 
1060cdf0e10cSrcweir                     break;
1061cdf0e10cSrcweir                 }
1062cdf0e10cSrcweir                 case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D :
1063cdf0e10cSrcweir                 {
1064cdf0e10cSrcweir                     const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive = static_cast< const primitive2d::TextHierarchyBlockPrimitive2D& >(rCandidate);
1065cdf0e10cSrcweir                     static const ByteString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN");
1066cdf0e10cSrcweir                     static const ByteString aCommentStringB("XTEXT_PAINTSHAPE_END");
1067cdf0e10cSrcweir 
1068cdf0e10cSrcweir                     // add MetaFile comment, process recursively and add MetaFile comment
1069cdf0e10cSrcweir                     mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA));
1070cdf0e10cSrcweir                     process(rBlockPrimitive.get2DDecomposition(getViewInformation2D()));
1071cdf0e10cSrcweir                     mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB));
1072cdf0e10cSrcweir 
1073cdf0e10cSrcweir                     break;
1074cdf0e10cSrcweir                 }
1075cdf0e10cSrcweir                 case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
1076cdf0e10cSrcweir                 case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
1077cdf0e10cSrcweir                 {
1078cdf0e10cSrcweir                     // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate
1079cdf0e10cSrcweir                     const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate = static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate);
1080cdf0e10cSrcweir                     // const primitive2d::TextDecoratedPortionPrimitive2D* pTextDecoratedCandidate = dynamic_cast< const primitive2d::TextDecoratedPortionPrimitive2D* >(&rCandidate);
1081cdf0e10cSrcweir 
1082cdf0e10cSrcweir                     // Adapt evtl. used special DrawMode
1083cdf0e10cSrcweir                     const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
1084cdf0e10cSrcweir                     adaptTextToFillDrawMode();
1085cdf0e10cSrcweir 
1086cdf0e10cSrcweir                     // directdraw of text simple portion; use default processing
1087cdf0e10cSrcweir                     RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate);
1088cdf0e10cSrcweir 
1089cdf0e10cSrcweir                     // restore DrawMode
1090cdf0e10cSrcweir                     mpOutputDevice->SetDrawMode(nOriginalDrawMode);
1091cdf0e10cSrcweir 
1092cdf0e10cSrcweir                     // #i101169# if(pTextDecoratedCandidate)
1093cdf0e10cSrcweir                     {
1094cdf0e10cSrcweir                         // support for TEXT_ MetaFile actions only for decorated texts
1095cdf0e10cSrcweir                         if(!mxBreakIterator.is())
1096cdf0e10cSrcweir                         {
1097cdf0e10cSrcweir                             uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory());
1098cdf0e10cSrcweir                             mxBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), uno::UNO_QUERY);
1099cdf0e10cSrcweir                         }
1100cdf0e10cSrcweir 
1101cdf0e10cSrcweir                         if(mxBreakIterator.is())
1102cdf0e10cSrcweir                         {
1103cdf0e10cSrcweir                             const rtl::OUString& rTxt = rTextCandidate.getText();
1104cdf0e10cSrcweir                             const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength());
1105cdf0e10cSrcweir 
1106cdf0e10cSrcweir                             if(nTextLength)
1107cdf0e10cSrcweir                             {
1108cdf0e10cSrcweir                                 const ::com::sun::star::lang::Locale& rLocale = rTextCandidate.getLocale();
1109cdf0e10cSrcweir                                 const sal_Int32 nTextPosition(rTextCandidate.getTextPosition());
1110cdf0e10cSrcweir 
1111cdf0e10cSrcweir                                 sal_Int32 nDone;
1112cdf0e10cSrcweir                                 sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
1113cdf0e10cSrcweir                                 ::com::sun::star::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True));
1114cdf0e10cSrcweir                                 sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
1115cdf0e10cSrcweir                                 static const ByteString aCommentStringA("XTEXT_EOC");
1116cdf0e10cSrcweir                                 static const ByteString aCommentStringB("XTEXT_EOW");
1117cdf0e10cSrcweir                                 static const ByteString aCommentStringC("XTEXT_EOS");
1118cdf0e10cSrcweir 
1119cdf0e10cSrcweir                                 for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++)
1120cdf0e10cSrcweir                                 {
1121cdf0e10cSrcweir                                     // create the entries for the respective break positions
1122cdf0e10cSrcweir                                     if(i == nNextCellBreak)
1123cdf0e10cSrcweir                                     {
1124cdf0e10cSrcweir                                         mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition));
1125cdf0e10cSrcweir                                         nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
1126cdf0e10cSrcweir                                     }
1127cdf0e10cSrcweir                                     if(i == nNextWordBoundary.endPos)
1128cdf0e10cSrcweir                                     {
1129cdf0e10cSrcweir                                         mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition));
1130cdf0e10cSrcweir                                         nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True);
1131cdf0e10cSrcweir                                     }
1132cdf0e10cSrcweir                                     if(i == nNextSentenceBreak)
1133cdf0e10cSrcweir                                     {
1134cdf0e10cSrcweir                                         mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition));
1135cdf0e10cSrcweir                                         nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale);
1136cdf0e10cSrcweir                                     }
1137cdf0e10cSrcweir                                 }
1138cdf0e10cSrcweir                             }
1139cdf0e10cSrcweir                         }
1140cdf0e10cSrcweir                     }
1141cdf0e10cSrcweir 
1142cdf0e10cSrcweir                     break;
1143cdf0e10cSrcweir                 }
1144cdf0e10cSrcweir                 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
1145cdf0e10cSrcweir                 {
1146cdf0e10cSrcweir                     const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate);
1147cdf0e10cSrcweir                     const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon();
1148cdf0e10cSrcweir 
1149cdf0e10cSrcweir                     if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
1150cdf0e10cSrcweir                     {
1151cdf0e10cSrcweir                         // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1152cdf0e10cSrcweir                         // per polygon. If there are more, split the polygon in half and call recursively
1153cdf0e10cSrcweir                         basegfx::B2DPolygon aLeft, aRight;
1154cdf0e10cSrcweir                         splitLinePolygon(rBasePolygon, aLeft, aRight);
1155cdf0e10cSrcweir                         const primitive2d::PolygonHairlinePrimitive2D aPLeft(aLeft, rHairlinePrimitive.getBColor());
1156cdf0e10cSrcweir                         const primitive2d::PolygonHairlinePrimitive2D aPRight(aRight, rHairlinePrimitive.getBColor());
1157cdf0e10cSrcweir 
1158cdf0e10cSrcweir                         processBasePrimitive2D(aPLeft);
1159cdf0e10cSrcweir                         processBasePrimitive2D(aPRight);
1160cdf0e10cSrcweir                     }
1161cdf0e10cSrcweir                     else
1162cdf0e10cSrcweir                     {
1163cdf0e10cSrcweir                         // direct draw of hairline; use default processing
1164cdf0e10cSrcweir                         // support SvtGraphicStroke MetaCommentAction
1165cdf0e10cSrcweir                         const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor()));
11664665f8d3SArmin Le Grand                         SvtGraphicStroke* pSvtGraphicStroke = 0;
11674665f8d3SArmin Le Grand 
11684665f8d3SArmin Le Grand                         // #121267# Not needed, does not give better quality compared with
11694665f8d3SArmin Le Grand                         // the META_POLYPOLYGON_ACTION written by RenderPolygonHairlinePrimitive2D
11704665f8d3SArmin Le Grand                         // below
11714665f8d3SArmin Le Grand                         bool bSupportSvtGraphicStroke(false);
11724665f8d3SArmin Le Grand 
11734665f8d3SArmin Le Grand                         if(bSupportSvtGraphicStroke)
11744665f8d3SArmin Le Grand                         {
11754665f8d3SArmin Le Grand                             pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
1176cdf0e10cSrcweir                                 rHairlinePrimitive.getB2DPolygon(),
1177cdf0e10cSrcweir                                 &aLineColor,
1178cdf0e10cSrcweir                                 0, 0, 0, 0);
1179cdf0e10cSrcweir 
1180cdf0e10cSrcweir                             impStartSvtGraphicStroke(pSvtGraphicStroke);
11814665f8d3SArmin Le Grand                         }
11824665f8d3SArmin Le Grand 
1183cdf0e10cSrcweir                         RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false);
11844665f8d3SArmin Le Grand 
11854665f8d3SArmin Le Grand                         if(bSupportSvtGraphicStroke)
11864665f8d3SArmin Le Grand                         {
1187cdf0e10cSrcweir                             impEndSvtGraphicStroke(pSvtGraphicStroke);
1188cdf0e10cSrcweir                         }
11894665f8d3SArmin Le Grand                     }
1190cdf0e10cSrcweir                     break;
1191cdf0e10cSrcweir                 }
1192cdf0e10cSrcweir                 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D :
1193cdf0e10cSrcweir                 {
1194cdf0e10cSrcweir                     const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate);
1195cdf0e10cSrcweir                     const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon();
1196cdf0e10cSrcweir 
1197cdf0e10cSrcweir                     if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
1198cdf0e10cSrcweir                     {
1199cdf0e10cSrcweir                         // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1200cdf0e10cSrcweir                         // per polygon. If there are more, split the polygon in half and call recursively
1201cdf0e10cSrcweir                         basegfx::B2DPolygon aLeft, aRight;
1202cdf0e10cSrcweir                         splitLinePolygon(rBasePolygon, aLeft, aRight);
1203cdf0e10cSrcweir                         const primitive2d::PolygonStrokePrimitive2D aPLeft(
1204cdf0e10cSrcweir                             aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute());
1205cdf0e10cSrcweir                         const primitive2d::PolygonStrokePrimitive2D aPRight(
1206cdf0e10cSrcweir                             aRight, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute());
1207cdf0e10cSrcweir 
1208cdf0e10cSrcweir                         processBasePrimitive2D(aPLeft);
1209cdf0e10cSrcweir                         processBasePrimitive2D(aPRight);
1210cdf0e10cSrcweir                     }
1211cdf0e10cSrcweir                     else
1212cdf0e10cSrcweir                     {
1213cdf0e10cSrcweir                         // support SvtGraphicStroke MetaCommentAction
1214cdf0e10cSrcweir                         SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
1215cdf0e10cSrcweir                             rBasePolygon, 0,
1216cdf0e10cSrcweir                             &rStrokePrimitive.getLineAttribute(),
1217cdf0e10cSrcweir                             &rStrokePrimitive.getStrokeAttribute(),
1218cdf0e10cSrcweir                             0, 0);
1219cdf0e10cSrcweir 
1220cdf0e10cSrcweir                         impStartSvtGraphicStroke(pSvtGraphicStroke);
1221cdf0e10cSrcweir                         const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute();
1222cdf0e10cSrcweir 
1223cdf0e10cSrcweir                         // create MetaPolyLineActions, but without LINE_DASH
1224cdf0e10cSrcweir                         if(basegfx::fTools::more(rLine.getWidth(), 0.0))
1225cdf0e10cSrcweir                         {
1226cdf0e10cSrcweir                             const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute();
1227cdf0e10cSrcweir                             basegfx::B2DPolyPolygon aHairLinePolyPolygon;
1228cdf0e10cSrcweir 
1229cdf0e10cSrcweir                             if(0.0 == rStroke.getFullDotDashLen())
1230cdf0e10cSrcweir                             {
1231cdf0e10cSrcweir                                 aHairLinePolyPolygon.append(rBasePolygon);
1232cdf0e10cSrcweir                             }
1233cdf0e10cSrcweir                             else
1234cdf0e10cSrcweir                             {
1235cdf0e10cSrcweir                                 basegfx::tools::applyLineDashing(
1236cdf0e10cSrcweir                                     rBasePolygon, rStroke.getDotDashArray(),
1237cdf0e10cSrcweir                                     &aHairLinePolyPolygon, 0, rStroke.getFullDotDashLen());
1238cdf0e10cSrcweir                             }
1239cdf0e10cSrcweir 
1240cdf0e10cSrcweir                             const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor()));
1241cdf0e10cSrcweir                             mpOutputDevice->SetLineColor(Color(aHairlineColor));
1242cdf0e10cSrcweir                             mpOutputDevice->SetFillColor();
1243cdf0e10cSrcweir                             aHairLinePolyPolygon.transform(maCurrentTransformation);
1244cdf0e10cSrcweir 
1245cdf0e10cSrcweir                             // #i113922# LineWidth needs to be transformed, too
1246cdf0e10cSrcweir                             const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(rLine.getWidth(), 0.0));
1247cdf0e10cSrcweir                             const double fDiscreteLineWidth(aDiscreteUnit.getLength());
1248cdf0e10cSrcweir 
1249cdf0e10cSrcweir                             LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fDiscreteLineWidth));
1250cdf0e10cSrcweir                             aLineInfo.SetLineJoin(rLine.getLineJoin());
12515aaf853bSArmin Le Grand                             aLineInfo.SetLineCap(rLine.getLineCap());
1252cdf0e10cSrcweir 
1253cdf0e10cSrcweir                             for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
1254cdf0e10cSrcweir                             {
1255cdf0e10cSrcweir                                 const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a));
1256cdf0e10cSrcweir 
1257cdf0e10cSrcweir                                 if(aCandidate.count() > 1)
1258cdf0e10cSrcweir                                 {
1259cdf0e10cSrcweir                                     const Polygon aToolsPolygon(aCandidate);
1260cdf0e10cSrcweir 
1261cdf0e10cSrcweir                                     mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo));
1262cdf0e10cSrcweir                                 }
1263cdf0e10cSrcweir                             }
1264cdf0e10cSrcweir                         }
1265cdf0e10cSrcweir                         else
1266cdf0e10cSrcweir                         {
1267cdf0e10cSrcweir                             process(rCandidate.get2DDecomposition(getViewInformation2D()));
1268cdf0e10cSrcweir                         }
1269cdf0e10cSrcweir 
1270cdf0e10cSrcweir                         impEndSvtGraphicStroke(pSvtGraphicStroke);
1271cdf0e10cSrcweir                     }
1272cdf0e10cSrcweir 
1273cdf0e10cSrcweir                     break;
1274cdf0e10cSrcweir                 }
1275cdf0e10cSrcweir                 case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D :
1276cdf0e10cSrcweir                 {
1277cdf0e10cSrcweir                     const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate);
1278cdf0e10cSrcweir                     const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon();
1279cdf0e10cSrcweir 
1280cdf0e10cSrcweir                     if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
1281cdf0e10cSrcweir                     {
1282cdf0e10cSrcweir                         // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1283cdf0e10cSrcweir                         // per polygon. If there are more, split the polygon in half and call recursively
1284cdf0e10cSrcweir                         basegfx::B2DPolygon aLeft, aRight;
1285cdf0e10cSrcweir                         splitLinePolygon(rBasePolygon, aLeft, aRight);
1286cdf0e10cSrcweir                         const attribute::LineStartEndAttribute aEmpty;
1287cdf0e10cSrcweir                         const primitive2d::PolygonStrokeArrowPrimitive2D aPLeft(
1288cdf0e10cSrcweir                             aLeft,
1289cdf0e10cSrcweir                             rStrokeArrowPrimitive.getLineAttribute(),
1290cdf0e10cSrcweir                             rStrokeArrowPrimitive.getStrokeAttribute(),
1291cdf0e10cSrcweir                             rStrokeArrowPrimitive.getStart(),
1292cdf0e10cSrcweir                             aEmpty);
1293cdf0e10cSrcweir                         const primitive2d::PolygonStrokeArrowPrimitive2D aPRight(
1294cdf0e10cSrcweir                             aRight,
1295cdf0e10cSrcweir                             rStrokeArrowPrimitive.getLineAttribute(),
1296cdf0e10cSrcweir                             rStrokeArrowPrimitive.getStrokeAttribute(),
1297cdf0e10cSrcweir                             aEmpty,
1298cdf0e10cSrcweir                             rStrokeArrowPrimitive.getEnd());
1299cdf0e10cSrcweir 
1300cdf0e10cSrcweir                         processBasePrimitive2D(aPLeft);
1301cdf0e10cSrcweir                         processBasePrimitive2D(aPRight);
1302cdf0e10cSrcweir                     }
1303cdf0e10cSrcweir                     else
1304cdf0e10cSrcweir                     {
1305cdf0e10cSrcweir                         // support SvtGraphicStroke MetaCommentAction
1306cdf0e10cSrcweir                         SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
1307cdf0e10cSrcweir                             rBasePolygon, 0,
1308cdf0e10cSrcweir                             &rStrokeArrowPrimitive.getLineAttribute(),
1309cdf0e10cSrcweir                             &rStrokeArrowPrimitive.getStrokeAttribute(),
1310cdf0e10cSrcweir                             &rStrokeArrowPrimitive.getStart(),
1311cdf0e10cSrcweir                             &rStrokeArrowPrimitive.getEnd());
1312cdf0e10cSrcweir 
131378137d97SArmin Le Grand                         // write LineGeometry start marker
1314cdf0e10cSrcweir                         impStartSvtGraphicStroke(pSvtGraphicStroke);
131578137d97SArmin Le Grand 
131678137d97SArmin Le Grand                         // #116162# When B&W is set as DrawMode, DRAWMODE_WHITEFILL is used
131778137d97SArmin Le Grand                         // to let all fills be just white; for lines DRAWMODE_BLACKLINE is used
131878137d97SArmin Le Grand                         // so all line geometry is supposed to get black. Since in the in-between
131978137d97SArmin Le Grand                         // stages of line geometry drawing filled polygons are used (e.g. line
132078137d97SArmin Le Grand                         // start/ends) it is necessary to change these drawmodes to preserve
132178137d97SArmin Le Grand                         // that lines shall be black; thus change DRAWMODE_WHITEFILL to
132278137d97SArmin Le Grand                         // DRAWMODE_BLACKFILL during line geometry processing to have line geometry
132378137d97SArmin Le Grand                         // parts filled black.
132478137d97SArmin Le Grand                         const sal_uLong nOldDrawMode(mpOutputDevice->GetDrawMode());
132578137d97SArmin Le Grand                         const bool bDrawmodeChange(nOldDrawMode & DRAWMODE_WHITEFILL && mnSvtGraphicStrokeCount);
132678137d97SArmin Le Grand 
132778137d97SArmin Le Grand                         if(bDrawmodeChange)
132878137d97SArmin Le Grand                         {
132978137d97SArmin Le Grand                             mpOutputDevice->SetDrawMode((nOldDrawMode & ~DRAWMODE_WHITEFILL) | DRAWMODE_BLACKFILL);
133078137d97SArmin Le Grand                         }
133178137d97SArmin Le Grand 
133278137d97SArmin Le Grand                         // process sub-line geometry (evtl. filled PolyPolygons)
1333cdf0e10cSrcweir                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
133478137d97SArmin Le Grand 
133578137d97SArmin Le Grand                         if(bDrawmodeChange)
133678137d97SArmin Le Grand                         {
133778137d97SArmin Le Grand                             mpOutputDevice->SetDrawMode(nOldDrawMode);
133878137d97SArmin Le Grand                         }
133978137d97SArmin Le Grand 
134078137d97SArmin Le Grand                         // write LineGeometry end marker
1341cdf0e10cSrcweir                         impEndSvtGraphicStroke(pSvtGraphicStroke);
1342cdf0e10cSrcweir                     }
1343cdf0e10cSrcweir 
1344cdf0e10cSrcweir                     break;
1345cdf0e10cSrcweir                 }
1346cdf0e10cSrcweir                 case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
1347cdf0e10cSrcweir                 {
1348cf95e506SArmin Le Grand                     // direct draw of transformed BitmapEx primitive; use default processing, but without
1349cf95e506SArmin Le Grand                     // former testing if graphic content is inside discrete local viewport; this is not
1350cf95e506SArmin Le Grand                     // setup for metafile targets (metafile renderer tries to render in logic coordinates,
1351cf95e506SArmin Le Grand                     // the mapping is kept to the OutputDevice for better Metafile recording)
1352cdf0e10cSrcweir                     RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
1353cdf0e10cSrcweir                     break;
1354cdf0e10cSrcweir                 }
1355035a2f44SArmin Le Grand                 case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D :
1356cdf0e10cSrcweir                 {
1357035a2f44SArmin Le Grand                     // need to handle PolyPolygonGraphicPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
1358035a2f44SArmin Le Grand                     const primitive2d::PolyPolygonGraphicPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate);
1359cdf0e10cSrcweir                     basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon());
1360cdf0e10cSrcweir 
1361cdf0e10cSrcweir                     if(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1362cdf0e10cSrcweir                     {
1363cdf0e10cSrcweir                         // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1364cdf0e10cSrcweir                         // per polygon. If there are more use the splitted polygon and call recursively
1365035a2f44SArmin Le Grand                         const primitive2d::PolyPolygonGraphicPrimitive2D aSplitted(
1366cdf0e10cSrcweir                             aLocalPolyPolygon,
1367035a2f44SArmin Le Grand                             rBitmapCandidate.getFillGraphic());
1368cdf0e10cSrcweir 
1369cdf0e10cSrcweir                         processBasePrimitive2D(aSplitted);
1370cdf0e10cSrcweir                     }
1371cdf0e10cSrcweir                     else
1372cdf0e10cSrcweir                     {
1373cdf0e10cSrcweir                         SvtGraphicFill* pSvtGraphicFill = 0;
1374cdf0e10cSrcweir 
1375cdf0e10cSrcweir                         if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1376cdf0e10cSrcweir                         {
1377035a2f44SArmin Le Grand                             // #121194# Changed implementation and checked usages fo convert to metafile,
1378035a2f44SArmin Le Grand                             // presentation start (uses SvtGraphicFill) and printing.
1379cdf0e10cSrcweir 
1380035a2f44SArmin Le Grand                             // calculate transformation. Get real object size, all values in FillGraphicAttribute
1381035a2f44SArmin Le Grand                             // are relative to the unified object
1382035a2f44SArmin Le Grand                             aLocalPolyPolygon.transform(maCurrentTransformation);
1383035a2f44SArmin Le Grand                             const basegfx::B2DVector aOutlineSize(aLocalPolyPolygon.getB2DRange().getRange());
1384cdf0e10cSrcweir 
1385cdf0e10cSrcweir                             // the scaling needs scale from pixel to logic coordinate system
1386035a2f44SArmin Le Grand                             const attribute::FillGraphicAttribute& rFillGraphicAttribute = rBitmapCandidate.getFillGraphic();
1387035a2f44SArmin Le Grand                             const Size aBmpSizePixel(rFillGraphicAttribute.getGraphic().GetSizePixel());
1388cdf0e10cSrcweir 
1389035a2f44SArmin Le Grand                             // setup transformation like in impgrfll. Multiply with aOutlineSize
1390035a2f44SArmin Le Grand                             // to get from unit coordinates in rFillGraphicAttribute.getGraphicRange()
1391035a2f44SArmin Le Grand                             // to object coordinates with object's top left being at (0,0). Divide
1392035a2f44SArmin Le Grand                             // by pixel size so that scale from pixel to logic will work in SvtGraphicFill.
1393035a2f44SArmin Le Grand                             const basegfx::B2DVector aTransformScale(
1394035a2f44SArmin Le Grand                                 rFillGraphicAttribute.getGraphicRange().getRange() /
1395035a2f44SArmin Le Grand                                 basegfx::B2DVector(
1396035a2f44SArmin Le Grand                                     std::max(1.0, double(aBmpSizePixel.Width())),
1397035a2f44SArmin Le Grand                                     std::max(1.0, double(aBmpSizePixel.Height()))) *
1398035a2f44SArmin Le Grand                                 aOutlineSize);
1399035a2f44SArmin Le Grand                             const basegfx::B2DPoint aTransformPosition(
1400035a2f44SArmin Le Grand                                 rFillGraphicAttribute.getGraphicRange().getMinimum() * aOutlineSize);
1401cdf0e10cSrcweir 
1402cdf0e10cSrcweir                             // setup transformation like in impgrfll
1403cdf0e10cSrcweir                             SvtGraphicFill::Transform aTransform;
1404cdf0e10cSrcweir 
1405cdf0e10cSrcweir                             // scale values are divided by bitmap pixel sizes
1406035a2f44SArmin Le Grand                             aTransform.matrix[0] = aTransformScale.getX();
1407035a2f44SArmin Le Grand                             aTransform.matrix[4] = aTransformScale.getY();
1408cdf0e10cSrcweir 
1409cdf0e10cSrcweir                             // translates are absolute
1410035a2f44SArmin Le Grand                             aTransform.matrix[2] = aTransformPosition.getX();
1411035a2f44SArmin Le Grand                             aTransform.matrix[5] = aTransformPosition.getY();
1412cdf0e10cSrcweir 
1413cdf0e10cSrcweir                             pSvtGraphicFill = new SvtGraphicFill(
1414cdf0e10cSrcweir                                 PolyPolygon(aLocalPolyPolygon),
1415cdf0e10cSrcweir                                 Color(),
1416cdf0e10cSrcweir                                 0.0,
1417cdf0e10cSrcweir                                 SvtGraphicFill::fillEvenOdd,
1418cdf0e10cSrcweir                                 SvtGraphicFill::fillTexture,
1419cdf0e10cSrcweir                                 aTransform,
1420035a2f44SArmin Le Grand                                 rFillGraphicAttribute.getTiling(),
1421cdf0e10cSrcweir                                 SvtGraphicFill::hatchSingle,
1422cdf0e10cSrcweir                                 Color(),
1423cdf0e10cSrcweir                                 SvtGraphicFill::gradientLinear,
1424cdf0e10cSrcweir                                 Color(),
1425cdf0e10cSrcweir                                 Color(),
1426cdf0e10cSrcweir                                 0,
1427035a2f44SArmin Le Grand                                 rFillGraphicAttribute.getGraphic());
1428cdf0e10cSrcweir                         }
1429cdf0e10cSrcweir 
1430cdf0e10cSrcweir                         // Do use decomposition; encapsulate with SvtGraphicFill
1431cdf0e10cSrcweir                         impStartSvtGraphicFill(pSvtGraphicFill);
1432cdf0e10cSrcweir                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
1433cdf0e10cSrcweir                         impEndSvtGraphicFill(pSvtGraphicFill);
1434cdf0e10cSrcweir                     }
1435cdf0e10cSrcweir 
1436cdf0e10cSrcweir                     break;
1437cdf0e10cSrcweir                 }
1438cdf0e10cSrcweir                 case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D :
1439cdf0e10cSrcweir                 {
1440cdf0e10cSrcweir                     // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
1441cdf0e10cSrcweir                     const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate);
1442cdf0e10cSrcweir                     const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch();
1443cdf0e10cSrcweir                     basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon());
1444cdf0e10cSrcweir 
1445*64b14621SArmin Le Grand                     if(aLocalPolyPolygon.getB2DRange() != rHatchCandidate.getDefinitionRange())
1446*64b14621SArmin Le Grand                     {
1447*64b14621SArmin Le Grand                         // the range which defines the hatch is different from the range of the
1448*64b14621SArmin Le Grand                         // geometry (used for writer frames). This cannot be done calling vcl, thus use
1449*64b14621SArmin Le Grand                         // decomposition here
1450*64b14621SArmin Le Grand                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
1451*64b14621SArmin Le Grand                         break;
1452*64b14621SArmin Le Grand                     }
1453*64b14621SArmin Le Grand 
1454cdf0e10cSrcweir                     // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1455cdf0e10cSrcweir                     // per polygon. Split polygon until there are less than that
1456cdf0e10cSrcweir                     while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1457cdf0e10cSrcweir                         ;
1458cdf0e10cSrcweir 
1459cdf0e10cSrcweir                     if(rFillHatchAttribute.isFillBackground())
1460cdf0e10cSrcweir                     {
1461cdf0e10cSrcweir                         // with fixing #i111954# (see below) the possible background
1462cdf0e10cSrcweir                         // fill of a hatched object was lost.Generate a background fill
1463cdf0e10cSrcweir                         // primitive and render it
1464cdf0e10cSrcweir                         const primitive2d::Primitive2DReference xBackground(
1465cdf0e10cSrcweir                             new primitive2d::PolyPolygonColorPrimitive2D(
1466cdf0e10cSrcweir                                 aLocalPolyPolygon,
1467cdf0e10cSrcweir                                 rHatchCandidate.getBackgroundColor()));
1468cdf0e10cSrcweir 
1469cdf0e10cSrcweir                         process(primitive2d::Primitive2DSequence(&xBackground, 1));
1470cdf0e10cSrcweir                     }
1471cdf0e10cSrcweir 
1472cdf0e10cSrcweir                     SvtGraphicFill* pSvtGraphicFill = 0;
1473cdf0e10cSrcweir                     aLocalPolyPolygon.transform(maCurrentTransformation);
1474cdf0e10cSrcweir 
1475cdf0e10cSrcweir                     if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1476cdf0e10cSrcweir                     {
1477cdf0e10cSrcweir                         // re-create a VCL hatch as base data
1478cdf0e10cSrcweir                         SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle);
1479cdf0e10cSrcweir 
1480cdf0e10cSrcweir                         switch(rFillHatchAttribute.getStyle())
1481cdf0e10cSrcweir                         {
1482cdf0e10cSrcweir                             default: // attribute::HATCHSTYLE_SINGLE :
1483cdf0e10cSrcweir                             {
1484cdf0e10cSrcweir                                 eHatch = SvtGraphicFill::hatchSingle;
1485cdf0e10cSrcweir                                 break;
1486cdf0e10cSrcweir                             }
1487cdf0e10cSrcweir                             case attribute::HATCHSTYLE_DOUBLE :
1488cdf0e10cSrcweir                             {
1489cdf0e10cSrcweir                                 eHatch = SvtGraphicFill::hatchDouble;
1490cdf0e10cSrcweir                                 break;
1491cdf0e10cSrcweir                             }
1492cdf0e10cSrcweir                             case attribute::HATCHSTYLE_TRIPLE :
1493cdf0e10cSrcweir                             {
1494cdf0e10cSrcweir                                 eHatch = SvtGraphicFill::hatchTriple;
1495cdf0e10cSrcweir                                 break;
1496cdf0e10cSrcweir                             }
1497cdf0e10cSrcweir                         }
1498cdf0e10cSrcweir 
1499cdf0e10cSrcweir                         SvtGraphicFill::Transform aTransform;
1500cdf0e10cSrcweir 
1501cdf0e10cSrcweir                         // scale
1502cdf0e10cSrcweir                         aTransform.matrix[0] *= rFillHatchAttribute.getDistance();
1503cdf0e10cSrcweir                         aTransform.matrix[4] *= rFillHatchAttribute.getDistance();
1504cdf0e10cSrcweir 
1505cdf0e10cSrcweir                         // rotate (was never correct in impgrfll anyways, use correct angle now)
1506cdf0e10cSrcweir                         aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle());
1507cdf0e10cSrcweir                         aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle());
1508cdf0e10cSrcweir                         aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle());
1509cdf0e10cSrcweir                         aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle());
1510cdf0e10cSrcweir 
1511cdf0e10cSrcweir                         pSvtGraphicFill = new SvtGraphicFill(
1512cdf0e10cSrcweir                             PolyPolygon(aLocalPolyPolygon),
1513cdf0e10cSrcweir                             Color(),
1514cdf0e10cSrcweir                             0.0,
1515cdf0e10cSrcweir                             SvtGraphicFill::fillEvenOdd,
1516cdf0e10cSrcweir                             SvtGraphicFill::fillHatch,
1517cdf0e10cSrcweir                             aTransform,
1518cdf0e10cSrcweir                             false,
1519cdf0e10cSrcweir                             eHatch,
1520cdf0e10cSrcweir                             Color(rFillHatchAttribute.getColor()),
1521cdf0e10cSrcweir                             SvtGraphicFill::gradientLinear,
1522cdf0e10cSrcweir                             Color(),
1523cdf0e10cSrcweir                             Color(),
1524cdf0e10cSrcweir                             0,
1525cdf0e10cSrcweir                             Graphic());
1526cdf0e10cSrcweir                     }
1527cdf0e10cSrcweir 
1528cdf0e10cSrcweir                     // Do use decomposition; encapsulate with SvtGraphicFill
1529cdf0e10cSrcweir                     impStartSvtGraphicFill(pSvtGraphicFill);
1530cdf0e10cSrcweir 
1531cdf0e10cSrcweir                     // #i111954# do NOT use decomposition, but use direct VCL-command
1532cdf0e10cSrcweir                     // process(rCandidate.get2DDecomposition(getViewInformation2D()));
1533cdf0e10cSrcweir                     const PolyPolygon aToolsPolyPolygon(aLocalPolyPolygon);
1534cdf0e10cSrcweir                     const HatchStyle aHatchStyle(
1535cdf0e10cSrcweir                         attribute::HATCHSTYLE_SINGLE == rFillHatchAttribute.getStyle() ? HATCH_SINGLE :
1536cdf0e10cSrcweir                         attribute::HATCHSTYLE_DOUBLE == rFillHatchAttribute.getStyle() ? HATCH_DOUBLE :
1537cdf0e10cSrcweir                         HATCH_TRIPLE);
1538cdf0e10cSrcweir 
1539cdf0e10cSrcweir                     mpOutputDevice->DrawHatch(aToolsPolyPolygon,
1540cdf0e10cSrcweir                         Hatch(aHatchStyle,
1541cdf0e10cSrcweir                             Color(rFillHatchAttribute.getColor()),
1542cdf0e10cSrcweir                             basegfx::fround(rFillHatchAttribute.getDistance()),
1543cdf0e10cSrcweir                             basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800)));
1544cdf0e10cSrcweir 
1545cdf0e10cSrcweir                     impEndSvtGraphicFill(pSvtGraphicFill);
1546cdf0e10cSrcweir 
1547cdf0e10cSrcweir                     break;
1548cdf0e10cSrcweir                 }
1549cdf0e10cSrcweir                 case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
1550cdf0e10cSrcweir                 {
15516d3fd5d0SArmin Le Grand                     basegfx::B2DVector aScale, aTranslate;
15526d3fd5d0SArmin Le Grand                     double fRotate, fShearX;
15536d3fd5d0SArmin Le Grand 
15546d3fd5d0SArmin Le Grand                     maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
15556d3fd5d0SArmin Le Grand 
15566d3fd5d0SArmin Le Grand                     if(!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX))
15576d3fd5d0SArmin Le Grand                     {
15586d3fd5d0SArmin Le Grand                         // #121185# When rotation or shear is used, a VCL Gradient cannot be used directly.
15596d3fd5d0SArmin Le Grand                         // This is because VCL Gradient mechanism does *not* support to rotate the gradient
15606d3fd5d0SArmin Le Grand                         // with objects and this case is not expressable in a Metafile (and cannot be added
15616d3fd5d0SArmin Le Grand                         // since the FileFormats used, e.g. *.wmf, do not support it either).
15626d3fd5d0SArmin Le Grand                         // Such cases happen when a graphic object uses a Metafile as graphic information or
15636d3fd5d0SArmin Le Grand                         // a fill style definition uses a Metafile. In this cases the graphic content is
15646d3fd5d0SArmin Le Grand                         // rotated with the graphic or filled object; this is not supported by the target
15656d3fd5d0SArmin Le Grand                         // format of this conversion renderer - Metafiles.
15666d3fd5d0SArmin Le Grand                         // To solve this, not a Gradient is written, but the decomposition of this object
15676d3fd5d0SArmin Le Grand                         // is written to the Metafile. This is the PolyPolygons building the gradient fill.
15686d3fd5d0SArmin Le Grand                         // These will need more space and time, but the result will be as if the Gradient
15696d3fd5d0SArmin Le Grand                         // was rotated with the object.
15706d3fd5d0SArmin Le Grand                         // This mechanism is used by all exporters still not using Primtives (e.g. Print,
15716d3fd5d0SArmin Le Grand                         // Slideshow, Export rto PDF, export to Picture, ...) but relying on Metafile
15726d3fd5d0SArmin Le Grand                         // transfers. One more reason to *change* these to primitives.
15736d3fd5d0SArmin Le Grand                         // BTW: One more example how useful the principles of primitives are; the decomposition
15746d3fd5d0SArmin Le Grand                         // is by definition a simpler, maybe more expensive representation of the same content.
15756d3fd5d0SArmin Le Grand                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
1576*64b14621SArmin Le Grand                         break;
15776d3fd5d0SArmin Le Grand                     }
1578*64b14621SArmin Le Grand 
1579cdf0e10cSrcweir                     const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate);
1580cdf0e10cSrcweir                     basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon());
1581cdf0e10cSrcweir 
1582*64b14621SArmin Le Grand                     if(aLocalPolyPolygon.getB2DRange() != rGradientCandidate.getDefinitionRange())
1583*64b14621SArmin Le Grand                     {
1584*64b14621SArmin Le Grand                         // the range which defines the gradient is different from the range of the
1585*64b14621SArmin Le Grand                         // geometry (used for writer frames). This cannot be done calling vcl, thus use
1586*64b14621SArmin Le Grand                         // decomposition here
1587*64b14621SArmin Le Grand                         process(rCandidate.get2DDecomposition(getViewInformation2D()));
1588*64b14621SArmin Le Grand                         break;
1589*64b14621SArmin Le Grand                     }
1590*64b14621SArmin Le Grand 
1591cdf0e10cSrcweir                     // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1592cdf0e10cSrcweir                     // per polygon. Split polygon until there are less than that
1593cdf0e10cSrcweir                     while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1594cdf0e10cSrcweir                         ;
1595cdf0e10cSrcweir 
1596cdf0e10cSrcweir                     // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END
1597cdf0e10cSrcweir                     // it is safest to use the VCL OutputDevice::DrawGradient method which creates those.
1598cdf0e10cSrcweir                     // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon
1599cdf0e10cSrcweir                     Gradient aVCLGradient;
1600cdf0e10cSrcweir                     impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false);
1601cdf0e10cSrcweir                     aLocalPolyPolygon.transform(maCurrentTransformation);
1602cdf0e10cSrcweir 
1603cdf0e10cSrcweir                     // #i82145# ATM VCL printing of gradients using curved shapes does not work,
1604cdf0e10cSrcweir                     // i submitted the bug with the given ID to THB. When that task is fixed it is
1605cdf0e10cSrcweir                     // necessary to again remove this subdivision since it decreases possible
1606cdf0e10cSrcweir                     // printing quality (not even resolution-dependent for now). THB will tell
1607cdf0e10cSrcweir                     // me when that task is fixed in the master
1608cdf0e10cSrcweir                     const PolyPolygon aToolsPolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(aLocalPolyPolygon));
1609cdf0e10cSrcweir 
1610cdf0e10cSrcweir                     // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
1611cdf0e10cSrcweir                     SvtGraphicFill* pSvtGraphicFill = 0;
1612cdf0e10cSrcweir 
1613cdf0e10cSrcweir                     if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1614cdf0e10cSrcweir                     {
1615cdf0e10cSrcweir                         // setup gradient stuff like in like in impgrfll
1616cdf0e10cSrcweir                         SvtGraphicFill::GradientType eGrad(SvtGraphicFill::gradientLinear);
1617cdf0e10cSrcweir 
1618cdf0e10cSrcweir                         switch(aVCLGradient.GetStyle())
1619cdf0e10cSrcweir                         {
1620cdf0e10cSrcweir                             default : // GRADIENT_LINEAR:
1621cdf0e10cSrcweir                             case GRADIENT_AXIAL:
1622cdf0e10cSrcweir                                 eGrad = SvtGraphicFill::gradientLinear;
1623cdf0e10cSrcweir                                 break;
1624cdf0e10cSrcweir                             case GRADIENT_RADIAL:
1625cdf0e10cSrcweir                             case GRADIENT_ELLIPTICAL:
1626cdf0e10cSrcweir                                 eGrad = SvtGraphicFill::gradientRadial;
1627cdf0e10cSrcweir                                 break;
1628cdf0e10cSrcweir                             case GRADIENT_SQUARE:
1629cdf0e10cSrcweir                             case GRADIENT_RECT:
1630cdf0e10cSrcweir                                 eGrad = SvtGraphicFill::gradientRectangular;
1631cdf0e10cSrcweir                                 break;
1632cdf0e10cSrcweir                         }
1633cdf0e10cSrcweir 
1634cdf0e10cSrcweir                         pSvtGraphicFill = new SvtGraphicFill(
1635cdf0e10cSrcweir                             aToolsPolyPolygon,
1636cdf0e10cSrcweir                             Color(),
1637cdf0e10cSrcweir                             0.0,
1638cdf0e10cSrcweir                             SvtGraphicFill::fillEvenOdd,
1639cdf0e10cSrcweir                             SvtGraphicFill::fillGradient,
1640cdf0e10cSrcweir                             SvtGraphicFill::Transform(),
1641cdf0e10cSrcweir                             false,
1642cdf0e10cSrcweir                             SvtGraphicFill::hatchSingle,
1643cdf0e10cSrcweir                             Color(),
1644cdf0e10cSrcweir                             eGrad,
1645cdf0e10cSrcweir                             aVCLGradient.GetStartColor(),
1646cdf0e10cSrcweir                             aVCLGradient.GetEndColor(),
1647cdf0e10cSrcweir                             aVCLGradient.GetSteps(),
1648cdf0e10cSrcweir                             Graphic());
1649cdf0e10cSrcweir                     }
1650cdf0e10cSrcweir 
1651cdf0e10cSrcweir                     // call VCL directly; encapsulate with SvtGraphicFill
1652cdf0e10cSrcweir                     impStartSvtGraphicFill(pSvtGraphicFill);
1653cdf0e10cSrcweir                     mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient);
1654cdf0e10cSrcweir                     impEndSvtGraphicFill(pSvtGraphicFill);
1655cdf0e10cSrcweir 
1656cdf0e10cSrcweir                     break;
1657cdf0e10cSrcweir                 }
1658cdf0e10cSrcweir                 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
1659cdf0e10cSrcweir                 {
1660cdf0e10cSrcweir                     const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
1661cdf0e10cSrcweir                     basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
1662cdf0e10cSrcweir 
1663cdf0e10cSrcweir                     // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1664cdf0e10cSrcweir                     // per polygon. Split polygon until there are less than that
1665cdf0e10cSrcweir                     while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1666cdf0e10cSrcweir                         ;
1667cdf0e10cSrcweir 
1668cdf0e10cSrcweir                     const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
1669cdf0e10cSrcweir                     aLocalPolyPolygon.transform(maCurrentTransformation);
1670cdf0e10cSrcweir 
1671cdf0e10cSrcweir                     // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
1672cdf0e10cSrcweir                     SvtGraphicFill* pSvtGraphicFill = 0;
1673cdf0e10cSrcweir 
16744665f8d3SArmin Le Grand                     // #121267# Not needed, does not give better quality compared with
16754665f8d3SArmin Le Grand                     // the META_POLYPOLYGON_ACTION written by the DrawPolyPolygon command
16764665f8d3SArmin Le Grand                     // below
16774665f8d3SArmin Le Grand                     bool bSupportSvtGraphicFill(false);
16784665f8d3SArmin Le Grand 
16794665f8d3SArmin Le Grand                     if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1680cdf0e10cSrcweir                     {
1681cdf0e10cSrcweir                         // setup simple color fill stuff like in impgrfll
1682cdf0e10cSrcweir                         pSvtGraphicFill = new SvtGraphicFill(
1683cdf0e10cSrcweir                             PolyPolygon(aLocalPolyPolygon),
1684cdf0e10cSrcweir                             Color(aPolygonColor),
1685cdf0e10cSrcweir                             0.0,
1686cdf0e10cSrcweir                             SvtGraphicFill::fillEvenOdd,
1687cdf0e10cSrcweir                             SvtGraphicFill::fillSolid,
1688cdf0e10cSrcweir                             SvtGraphicFill::Transform(),
1689cdf0e10cSrcweir                             false,
1690cdf0e10cSrcweir                             SvtGraphicFill::hatchSingle,
1691cdf0e10cSrcweir                             Color(),
1692cdf0e10cSrcweir                             SvtGraphicFill::gradientLinear,
1693cdf0e10cSrcweir                             Color(),
1694cdf0e10cSrcweir                             Color(),
1695cdf0e10cSrcweir                             0,
1696cdf0e10cSrcweir                             Graphic());
1697cdf0e10cSrcweir                     }
1698cdf0e10cSrcweir 
1699cdf0e10cSrcweir                     // set line and fill color
1700cdf0e10cSrcweir                     mpOutputDevice->SetFillColor(Color(aPolygonColor));
1701cdf0e10cSrcweir                     mpOutputDevice->SetLineColor();
1702cdf0e10cSrcweir 
1703cdf0e10cSrcweir                     // call VCL directly; encapsulate with SvtGraphicFill
17044665f8d3SArmin Le Grand                     if(bSupportSvtGraphicFill)
17054665f8d3SArmin Le Grand                     {
1706cdf0e10cSrcweir                             impStartSvtGraphicFill(pSvtGraphicFill);
17074665f8d3SArmin Le Grand                     }
17084665f8d3SArmin Le Grand 
1709cdf0e10cSrcweir                     mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
17104665f8d3SArmin Le Grand 
17114665f8d3SArmin Le Grand                     if(bSupportSvtGraphicFill)
17124665f8d3SArmin Le Grand                     {
1713cdf0e10cSrcweir                         impEndSvtGraphicFill(pSvtGraphicFill);
17144665f8d3SArmin Le Grand                     }
1715cdf0e10cSrcweir 
1716cdf0e10cSrcweir                     break;
1717cdf0e10cSrcweir                 }
1718cdf0e10cSrcweir                 case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
1719cdf0e10cSrcweir                 {
1720cdf0e10cSrcweir                     // mask group. Special handling for MetaFiles.
1721cdf0e10cSrcweir                     const primitive2d::MaskPrimitive2D& rMaskCandidate = static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate);
1722cdf0e10cSrcweir 
1723cdf0e10cSrcweir                     if(rMaskCandidate.getChildren().hasElements())
1724cdf0e10cSrcweir                     {
1725cdf0e10cSrcweir                         basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
1726cdf0e10cSrcweir 
1727cdf0e10cSrcweir                         if(aMask.count())
1728cdf0e10cSrcweir                         {
1729cdf0e10cSrcweir                             // prepare new mask polygon and rescue current one
1730cdf0e10cSrcweir                             aMask.transform(maCurrentTransformation);
1731cdf0e10cSrcweir                             const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
1732cdf0e10cSrcweir 
1733cdf0e10cSrcweir                             if(maClipPolyPolygon.count())
1734cdf0e10cSrcweir                             {
1735cdf0e10cSrcweir                                 // there is already a clip polygon set; build clipped union of
1736cdf0e10cSrcweir                                 // current mask polygon and new one
1737cdf0e10cSrcweir                                 maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
1738cdf0e10cSrcweir                                     aMask,
1739cdf0e10cSrcweir                                     maClipPolyPolygon,
1740cdf0e10cSrcweir                                     true, // #i106516# we want the inside of aMask, not the outside
1741cdf0e10cSrcweir                                     false);
1742cdf0e10cSrcweir                             }
1743cdf0e10cSrcweir                             else
1744cdf0e10cSrcweir                             {
1745cdf0e10cSrcweir                                 // use mask directly
1746cdf0e10cSrcweir                                 maClipPolyPolygon = aMask;
1747cdf0e10cSrcweir                             }
1748cdf0e10cSrcweir 
1749cdf0e10cSrcweir                             if(maClipPolyPolygon.count())
1750cdf0e10cSrcweir                             {
1751cdf0e10cSrcweir                                 // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!)
1752cdf0e10cSrcweir                                 // Removed subdivision and fixed in Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where
1753cdf0e10cSrcweir                                 // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there
1754cdf0e10cSrcweir                                 mpOutputDevice->Push(PUSH_CLIPREGION);
1755ddde725dSArmin Le Grand                                 mpOutputDevice->SetClipRegion(Region(maClipPolyPolygon));
1756cdf0e10cSrcweir 
1757cdf0e10cSrcweir                                 // recursively paint content
17584665f8d3SArmin Le Grand                                 // #121267# Only need to process sub-content when clip polygon is *not* empty.
17594665f8d3SArmin Le Grand                                 // If it is empty, the clip is empty and there can be nothing inside.
1760cdf0e10cSrcweir                                 process(rMaskCandidate.getChildren());
1761cdf0e10cSrcweir 
1762cdf0e10cSrcweir                                 // restore VCL clip region
1763cdf0e10cSrcweir                                 mpOutputDevice->Pop();
1764cdf0e10cSrcweir                             }
1765cdf0e10cSrcweir 
1766cdf0e10cSrcweir                             // restore to rescued clip polygon
1767cdf0e10cSrcweir                             maClipPolyPolygon = aLastClipPolyPolygon;
1768cdf0e10cSrcweir                         }
1769cdf0e10cSrcweir                         else
1770cdf0e10cSrcweir                         {
1771cdf0e10cSrcweir                             // no mask, no clipping. recursively paint content
1772cdf0e10cSrcweir                             process(rMaskCandidate.getChildren());
1773cdf0e10cSrcweir                         }
1774cdf0e10cSrcweir                     }
1775cdf0e10cSrcweir 
1776cdf0e10cSrcweir                     break;
1777cdf0e10cSrcweir                 }
1778cdf0e10cSrcweir                 case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
1779cdf0e10cSrcweir                 {
1780cdf0e10cSrcweir                     // modified color group. Force output to unified color. Use default pocessing.
1781cdf0e10cSrcweir                     RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
1782cdf0e10cSrcweir                     break;
1783cdf0e10cSrcweir                 }
1784cdf0e10cSrcweir                 case PRIMITIVE2D_ID_HIDDENGEOMETRYPRIMITIVE2D :
1785cdf0e10cSrcweir                 {
1786cdf0e10cSrcweir                     // HiddenGeometryPrimitive2D; to rebuilt the old MetaFile creation, it is necessary to
1787cdf0e10cSrcweir                     // not ignore them (as it was thought), but to add a MetaFile entry for them.
1788cdf0e10cSrcweir                     basegfx::B2DRange aInvisibleRange(rCandidate.getB2DRange(getViewInformation2D()));
1789cdf0e10cSrcweir 
1790cdf0e10cSrcweir                     if(!aInvisibleRange.isEmpty())
1791cdf0e10cSrcweir                     {
1792cdf0e10cSrcweir                         aInvisibleRange.transform(maCurrentTransformation);
1793cdf0e10cSrcweir                         const Rectangle aRectLogic(
1794cdf0e10cSrcweir                             (sal_Int32)floor(aInvisibleRange.getMinX()), (sal_Int32)floor(aInvisibleRange.getMinY()),
1795cdf0e10cSrcweir                             (sal_Int32)ceil(aInvisibleRange.getMaxX()), (sal_Int32)ceil(aInvisibleRange.getMaxY()));
1796cdf0e10cSrcweir 
1797cdf0e10cSrcweir                         mpOutputDevice->SetFillColor();
1798cdf0e10cSrcweir                         mpOutputDevice->SetLineColor();
1799cdf0e10cSrcweir                         mpOutputDevice->DrawRect(aRectLogic);
1800cdf0e10cSrcweir                     }
1801cdf0e10cSrcweir 
1802cdf0e10cSrcweir                     break;
1803cdf0e10cSrcweir                 }
1804cdf0e10cSrcweir                 case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
1805cdf0e10cSrcweir                 {
1806cdf0e10cSrcweir                     // for metafile: Need to examine what the pure vcl version is doing here actually
1807cdf0e10cSrcweir                     // - uses DrawTransparent with metafile for content and a gradient
1808cdf0e10cSrcweir                     // - uses DrawTransparent for single PolyPoylgons directly. Can be detected by
1809cdf0e10cSrcweir                     //   checking the content for single PolyPolygonColorPrimitive2D
1810cdf0e10cSrcweir                     const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate);
1811cdf0e10cSrcweir                     const primitive2d::Primitive2DSequence rContent = rUniTransparenceCandidate.getChildren();
1812cdf0e10cSrcweir 
1813cdf0e10cSrcweir                     if(rContent.hasElements())
1814cdf0e10cSrcweir                     {
1815cdf0e10cSrcweir                         if(0.0 == rUniTransparenceCandidate.getTransparence())
1816cdf0e10cSrcweir                         {
1817cdf0e10cSrcweir                             // not transparent at all, use content
1818cdf0e10cSrcweir                             process(rUniTransparenceCandidate.getChildren());
1819cdf0e10cSrcweir                         }
1820cdf0e10cSrcweir                         else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
1821cdf0e10cSrcweir                         {
1822cdf0e10cSrcweir                             // try to identify a single PolyPolygonColorPrimitive2D in the
1823cdf0e10cSrcweir                             // content part of the transparence primitive
1824cdf0e10cSrcweir                             const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = 0;
1825cdf0e10cSrcweir                             static bool bForceToMetafile(false);
1826cdf0e10cSrcweir 
1827cdf0e10cSrcweir                             if(!bForceToMetafile && 1 == rContent.getLength())
1828cdf0e10cSrcweir                             {
1829cdf0e10cSrcweir                                 const primitive2d::Primitive2DReference xReference(rContent[0]);
1830cdf0e10cSrcweir                                 pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get());
1831cdf0e10cSrcweir                             }
1832cdf0e10cSrcweir 
1833cdf0e10cSrcweir                             // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and
1834035a2f44SArmin Le Grand                             // PolyPolygonGraphicPrimitive2D are derived from PolyPolygonColorPrimitive2D.
1835cdf0e10cSrcweir                             // Check also for correct ID to exclude derived implementations
1836cdf0e10cSrcweir                             if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID())
1837cdf0e10cSrcweir                             {
1838cdf0e10cSrcweir                                 // single transparent PolyPolygon identified, use directly
1839cdf0e10cSrcweir                                 const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
1840cdf0e10cSrcweir                                 basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon());
1841cdf0e10cSrcweir 
1842cdf0e10cSrcweir                                 // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
1843cdf0e10cSrcweir                                 // per polygon. Split polygon until there are less than that
1844cdf0e10cSrcweir                                 while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
1845cdf0e10cSrcweir                                     ;
1846cdf0e10cSrcweir 
1847cdf0e10cSrcweir                                 // now transform
1848cdf0e10cSrcweir                                 aLocalPolyPolygon.transform(maCurrentTransformation);
1849cdf0e10cSrcweir 
1850cdf0e10cSrcweir                                 // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
1851cdf0e10cSrcweir                                 SvtGraphicFill* pSvtGraphicFill = 0;
1852cdf0e10cSrcweir 
18534665f8d3SArmin Le Grand                                 // #121267# Not needed, does not give better quality compared with
18544665f8d3SArmin Le Grand                                 // the META_POLYPOLYGON_ACTION written by the DrawPolyPolygon command
18554665f8d3SArmin Le Grand                                 // below
18564665f8d3SArmin Le Grand                                 bool bSupportSvtGraphicFill(false);
18574665f8d3SArmin Le Grand 
18584665f8d3SArmin Le Grand                                 if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count())
1859cdf0e10cSrcweir                                 {
1860cdf0e10cSrcweir                                     // setup simple color with transparence fill stuff like in impgrfll
1861cdf0e10cSrcweir                                     pSvtGraphicFill = new SvtGraphicFill(
1862cdf0e10cSrcweir                                         PolyPolygon(aLocalPolyPolygon),
1863cdf0e10cSrcweir                                         Color(aPolygonColor),
1864cdf0e10cSrcweir                                         rUniTransparenceCandidate.getTransparence(),
1865cdf0e10cSrcweir                                         SvtGraphicFill::fillEvenOdd,
1866cdf0e10cSrcweir                                         SvtGraphicFill::fillSolid,
1867cdf0e10cSrcweir                                         SvtGraphicFill::Transform(),
1868cdf0e10cSrcweir                                         false,
1869cdf0e10cSrcweir                                         SvtGraphicFill::hatchSingle,
1870cdf0e10cSrcweir                                         Color(),
1871cdf0e10cSrcweir                                         SvtGraphicFill::gradientLinear,
1872cdf0e10cSrcweir                                         Color(),
1873cdf0e10cSrcweir                                         Color(),
1874cdf0e10cSrcweir                                         0,
1875cdf0e10cSrcweir                                         Graphic());
1876cdf0e10cSrcweir                                 }
1877cdf0e10cSrcweir 
1878cdf0e10cSrcweir                                 // set line and fill color
1879cdf0e10cSrcweir                                 const sal_uInt16 nTransPercentVcl((sal_uInt16)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0));
1880cdf0e10cSrcweir                                 mpOutputDevice->SetFillColor(Color(aPolygonColor));
1881cdf0e10cSrcweir                                 mpOutputDevice->SetLineColor();
1882cdf0e10cSrcweir 
1883cdf0e10cSrcweir                                 // call VCL directly; encapsulate with SvtGraphicFill
18844665f8d3SArmin Le Grand                                 if(bSupportSvtGraphicFill)
18854665f8d3SArmin Le Grand                                 {
1886cdf0e10cSrcweir                                     impStartSvtGraphicFill(pSvtGraphicFill);
18874665f8d3SArmin Le Grand                                 }
18884665f8d3SArmin Le Grand 
1889cdf0e10cSrcweir                                 mpOutputDevice->DrawTransparent(
1890cdf0e10cSrcweir                                     PolyPolygon(aLocalPolyPolygon),
1891cdf0e10cSrcweir                                     nTransPercentVcl);
18924665f8d3SArmin Le Grand 
18934665f8d3SArmin Le Grand                                 if(bSupportSvtGraphicFill)
18944665f8d3SArmin Le Grand                                 {
1895cdf0e10cSrcweir                                     impEndSvtGraphicFill(pSvtGraphicFill);
1896cdf0e10cSrcweir                                 }
18974665f8d3SArmin Le Grand                             }
1898cdf0e10cSrcweir                             else
1899cdf0e10cSrcweir                             {
1900cdf0e10cSrcweir                                 // svae old mfCurrentUnifiedTransparence and set new one
1901cdf0e10cSrcweir                                 // so that contained SvtGraphicStroke may use the current one
1902cdf0e10cSrcweir                                 const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence);
1903cdf0e10cSrcweir                                 // #i105377# paint the content metafile opaque as the transparency gets
1904cdf0e10cSrcweir                                 // split of into the gradient below
1905cdf0e10cSrcweir                                 // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence();
1906cdf0e10cSrcweir                                 mfCurrentUnifiedTransparence = 0;
1907cdf0e10cSrcweir 
1908cdf0e10cSrcweir                                 // various content, create content-metafile
1909cdf0e10cSrcweir                                 GDIMetaFile aContentMetafile;
1910cdf0e10cSrcweir                                 const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
1911cdf0e10cSrcweir 
1912cdf0e10cSrcweir                                 // restore mfCurrentUnifiedTransparence; it may have been used
1913cdf0e10cSrcweir                                 // while processing the sub-content in impDumpToMetaFile
1914cdf0e10cSrcweir                                 mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence;
1915cdf0e10cSrcweir 
1916cdf0e10cSrcweir                                 // create uniform VCL gradient for uniform transparency
1917cdf0e10cSrcweir                                 Gradient aVCLGradient;
1918cdf0e10cSrcweir                                 const sal_uInt8 nTransPercentVcl((sal_uInt8)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0));
1919cdf0e10cSrcweir                                 const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl);
1920cdf0e10cSrcweir 
1921cdf0e10cSrcweir                                 aVCLGradient.SetStyle(GRADIENT_LINEAR);
1922cdf0e10cSrcweir                                 aVCLGradient.SetStartColor(aTransColor);
1923cdf0e10cSrcweir                                 aVCLGradient.SetEndColor(aTransColor);
1924cdf0e10cSrcweir                                 aVCLGradient.SetAngle(0);
1925cdf0e10cSrcweir                                 aVCLGradient.SetBorder(0);
1926cdf0e10cSrcweir                                 aVCLGradient.SetOfsX(0);
1927cdf0e10cSrcweir                                 aVCLGradient.SetOfsY(0);
1928cdf0e10cSrcweir                                 aVCLGradient.SetStartIntensity(100);
1929cdf0e10cSrcweir                                 aVCLGradient.SetEndIntensity(100);
1930cdf0e10cSrcweir                                 aVCLGradient.SetSteps(2);
1931cdf0e10cSrcweir 
1932cdf0e10cSrcweir                                 // render it to VCL
1933cdf0e10cSrcweir                                 mpOutputDevice->DrawTransparent(
1934cdf0e10cSrcweir                                     aContentMetafile, aPrimitiveRectangle.TopLeft(),
1935cdf0e10cSrcweir                                     aPrimitiveRectangle.GetSize(), aVCLGradient);
1936cdf0e10cSrcweir                             }
1937cdf0e10cSrcweir                         }
1938cdf0e10cSrcweir                     }
1939cdf0e10cSrcweir 
1940cdf0e10cSrcweir                     break;
1941cdf0e10cSrcweir                 }
1942cdf0e10cSrcweir                 case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
1943cdf0e10cSrcweir                 {
1944cdf0e10cSrcweir                     // for metafile: Need to examine what the pure vcl version is doing here actually
1945cdf0e10cSrcweir                     // - uses DrawTransparent with metafile for content and a gradient
1946cdf0e10cSrcweir                     // i can detect this here with checking the gradient part for a single
1947cdf0e10cSrcweir                     // FillGradientPrimitive2D and reconstruct the gradient.
1948cdf0e10cSrcweir                     // If that detection goes wrong, i have to create an transparence-blended bitmap. Eventually
1949cdf0e10cSrcweir                     // do that in stripes, else RenderTransparencePrimitive2D may just be used
1950cdf0e10cSrcweir                     const primitive2d::TransparencePrimitive2D& rTransparenceCandidate = static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate);
1951cdf0e10cSrcweir                     const primitive2d::Primitive2DSequence rContent = rTransparenceCandidate.getChildren();
1952cdf0e10cSrcweir                     const primitive2d::Primitive2DSequence rTransparence = rTransparenceCandidate.getTransparence();
1953cdf0e10cSrcweir 
1954cdf0e10cSrcweir                     if(rContent.hasElements() && rTransparence.hasElements())
1955cdf0e10cSrcweir                     {
1956cdf0e10cSrcweir                         // try to identify a single FillGradientPrimitive2D in the
1957cdf0e10cSrcweir                         // transparence part of the primitive
1958cdf0e10cSrcweir                         const primitive2d::FillGradientPrimitive2D* pFiGradient = 0;
1959cdf0e10cSrcweir                         static bool bForceToBigTransparentVDev(false);
1960cdf0e10cSrcweir 
1961cdf0e10cSrcweir                         if(!bForceToBigTransparentVDev && 1 == rTransparence.getLength())
1962cdf0e10cSrcweir                         {
1963cdf0e10cSrcweir                             const primitive2d::Primitive2DReference xReference(rTransparence[0]);
1964cdf0e10cSrcweir                             pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get());
1965cdf0e10cSrcweir                         }
1966cdf0e10cSrcweir 
1967cdf0e10cSrcweir                         // Check also for correct ID to exclude derived implementations
1968cdf0e10cSrcweir                         if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID())
1969cdf0e10cSrcweir                         {
1970cdf0e10cSrcweir                             // various content, create content-metafile
1971cdf0e10cSrcweir                             GDIMetaFile aContentMetafile;
1972cdf0e10cSrcweir                             const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
1973cdf0e10cSrcweir 
1974cdf0e10cSrcweir                             // re-create a VCL-gradient from FillGradientPrimitive2D
1975cdf0e10cSrcweir                             Gradient aVCLGradient;
1976cdf0e10cSrcweir                             impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true);
1977cdf0e10cSrcweir 
1978cdf0e10cSrcweir                             // render it to VCL
1979cdf0e10cSrcweir                             mpOutputDevice->DrawTransparent(
1980cdf0e10cSrcweir                                 aContentMetafile, aPrimitiveRectangle.TopLeft(),
1981cdf0e10cSrcweir                                 aPrimitiveRectangle.GetSize(), aVCLGradient);
1982cdf0e10cSrcweir                         }
1983cdf0e10cSrcweir                         else
1984cdf0e10cSrcweir                         {
1985cdf0e10cSrcweir                             // sub-transparence group. Draw to VDev first.
1986cdf0e10cSrcweir                             // this may get refined to tiling when resolution is too big here
1987cdf0e10cSrcweir 
1988cdf0e10cSrcweir                             // need to avoid switching off MapMode stuff here; maybe need another
1989cdf0e10cSrcweir                             // tooling class, cannot just do the same as with the pixel renderer.
1990cdf0e10cSrcweir                             // Need to experiment...
1991cdf0e10cSrcweir 
1992cdf0e10cSrcweir                             // Okay, basic implementation finished and tested. The DPI stuff was hard
1993cdf0e10cSrcweir                             // and not easy to find out that it's needed.
1994cdf0e10cSrcweir                             // Since this will not yet happen normally (as long as noone constructs
1995cdf0e10cSrcweir                             // transparence primitives with non-trivial transparence content) i will for now not
1996cdf0e10cSrcweir                             // refine to tiling here.
1997cdf0e10cSrcweir 
1998cdf0e10cSrcweir                             basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
1999cdf0e10cSrcweir                             aViewRange.transform(maCurrentTransformation);
2000cdf0e10cSrcweir                             const Rectangle aRectLogic(
2001cdf0e10cSrcweir                                 (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()),
2002cdf0e10cSrcweir                                 (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
2003cdf0e10cSrcweir                             const Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic));
200489cebadeSArmin Le Grand                             Size aSizePixel(aRectPixel.GetSize());
2005cdf0e10cSrcweir                             const Point aEmptyPoint;
2006cdf0e10cSrcweir                             VirtualDevice aBufferDevice;
200789cebadeSArmin Le Grand                             const sal_uInt32 nMaxQuadratPixels(500000);
200889cebadeSArmin Le Grand                             const sal_uInt32 nViewVisibleArea(aSizePixel.getWidth() * aSizePixel.getHeight());
200989cebadeSArmin Le Grand                             double fReduceFactor(1.0);
201089cebadeSArmin Le Grand 
201189cebadeSArmin Le Grand                             if(nViewVisibleArea > nMaxQuadratPixels)
201289cebadeSArmin Le Grand                             {
201389cebadeSArmin Le Grand                                 // reduce render size
201489cebadeSArmin Le Grand                                 fReduceFactor = sqrt((double)nMaxQuadratPixels / (double)nViewVisibleArea);
201589cebadeSArmin Le Grand                                 aSizePixel = Size(basegfx::fround((double)aSizePixel.getWidth() * fReduceFactor),
201689cebadeSArmin Le Grand                                     basegfx::fround((double)aSizePixel.getHeight() * fReduceFactor));
201789cebadeSArmin Le Grand                             }
2018cdf0e10cSrcweir 
2019cdf0e10cSrcweir                             if(aBufferDevice.SetOutputSizePixel(aSizePixel))
2020cdf0e10cSrcweir                             {
2021cdf0e10cSrcweir                                 // create and set MapModes for target devices
2022cdf0e10cSrcweir                                 MapMode aNewMapMode(mpOutputDevice->GetMapMode());
2023cdf0e10cSrcweir                                 aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top()));
2024cdf0e10cSrcweir                                 aBufferDevice.SetMapMode(aNewMapMode);
2025cdf0e10cSrcweir 
2026cdf0e10cSrcweir                                 // prepare view transformation for target renderers
2027cdf0e10cSrcweir                                 // ATTENTION! Need to apply another scaling because of the potential DPI differences
2028cdf0e10cSrcweir                                 // between Printer and VDev (mpOutputDevice and aBufferDevice here).
2029cdf0e10cSrcweir                                 // To get the DPI, LogicToPixel from (1,1) from MAP_INCH needs to be used.
2030cdf0e10cSrcweir                                 basegfx::B2DHomMatrix aViewTransform(aBufferDevice.GetViewTransformation());
2031cdf0e10cSrcweir                                 const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MAP_INCH));
2032cdf0e10cSrcweir                                 const Size aDPINew(aBufferDevice.LogicToPixel(Size(1, 1), MAP_INCH));
2033cdf0e10cSrcweir                                 const double fDPIXChange((double)aDPIOld.getWidth() / (double)aDPINew.getWidth());
2034cdf0e10cSrcweir                                 const double fDPIYChange((double)aDPIOld.getHeight() / (double)aDPINew.getHeight());
2035cdf0e10cSrcweir 
2036cdf0e10cSrcweir                                 if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0))
2037cdf0e10cSrcweir                                 {
2038cdf0e10cSrcweir                                     aViewTransform.scale(fDPIXChange, fDPIYChange);
2039cdf0e10cSrcweir                                 }
2040cdf0e10cSrcweir 
204189cebadeSArmin Le Grand                                 // also take scaling from Size reduction into acount
204289cebadeSArmin Le Grand                                 if(!basegfx::fTools::equal(fReduceFactor, 1.0))
204389cebadeSArmin Le Grand                                 {
204489cebadeSArmin Le Grand                                     aViewTransform.scale(fReduceFactor, fReduceFactor);
204589cebadeSArmin Le Grand                                 }
204689cebadeSArmin Le Grand 
2047cdf0e10cSrcweir                                 // create view information and pixel renderer. Reuse known ViewInformation
2048cdf0e10cSrcweir                                 // except new transformation and range
2049cdf0e10cSrcweir                                 const geometry::ViewInformation2D aViewInfo(
2050cdf0e10cSrcweir                                     getViewInformation2D().getObjectTransformation(),
2051cdf0e10cSrcweir                                     aViewTransform,
2052cdf0e10cSrcweir                                     aViewRange,
2053cdf0e10cSrcweir                                     getViewInformation2D().getVisualizedPage(),
2054cdf0e10cSrcweir                                     getViewInformation2D().getViewTime(),
2055cdf0e10cSrcweir                                     getViewInformation2D().getExtendedInformationSequence());
2056cdf0e10cSrcweir 
2057cdf0e10cSrcweir                                 VclPixelProcessor2D aBufferProcessor(aViewInfo, aBufferDevice);
2058cdf0e10cSrcweir 
2059cdf0e10cSrcweir                                 // draw content using pixel renderer
2060cdf0e10cSrcweir                                 aBufferProcessor.process(rContent);
2061cdf0e10cSrcweir                                 const Bitmap aBmContent(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel));
2062cdf0e10cSrcweir 
2063cdf0e10cSrcweir                                 // draw transparence using pixel renderer
2064cdf0e10cSrcweir                                 aBufferDevice.Erase();
2065cdf0e10cSrcweir                                 aBufferProcessor.process(rTransparence);
2066cdf0e10cSrcweir                                 const AlphaMask aBmAlpha(aBufferDevice.GetBitmap(aEmptyPoint, aSizePixel));
2067cdf0e10cSrcweir 
2068cdf0e10cSrcweir #ifdef DBG_UTIL
2069cdf0e10cSrcweir                                 static bool bDoSaveForVisualControl(false);
2070cdf0e10cSrcweir                                 if(bDoSaveForVisualControl)
2071cdf0e10cSrcweir                                 {
2072cdf0e10cSrcweir                                     SvFileStream aNew(String(ByteString( "c:\\test.bmp" ), RTL_TEXTENCODING_UTF8), STREAM_WRITE|STREAM_TRUNC);
207345fd3b9aSArmin Le Grand 
207445fd3b9aSArmin Le Grand                                     WriteDIB(aBmContent, aNew, false, true);
2075cdf0e10cSrcweir                                 }
2076cdf0e10cSrcweir #endif
2077cdf0e10cSrcweir 
2078cdf0e10cSrcweir                                 // paint
2079cdf0e10cSrcweir                                 mpOutputDevice->DrawBitmapEx(
2080cdf0e10cSrcweir                                     aRectLogic.TopLeft(),
2081cdf0e10cSrcweir                                     aRectLogic.GetSize(),
2082cdf0e10cSrcweir                                     BitmapEx(aBmContent, aBmAlpha));
2083cdf0e10cSrcweir                             }
2084cdf0e10cSrcweir                         }
2085cdf0e10cSrcweir                     }
2086cdf0e10cSrcweir 
2087cdf0e10cSrcweir                     break;
2088cdf0e10cSrcweir                 }
2089cdf0e10cSrcweir                 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
2090cdf0e10cSrcweir                 {
2091cdf0e10cSrcweir                     // use default transform group pocessing
2092cdf0e10cSrcweir                     RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
2093cdf0e10cSrcweir                     break;
2094cdf0e10cSrcweir                 }
2095cdf0e10cSrcweir                 case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
2096cdf0e10cSrcweir                 {
2097cdf0e10cSrcweir                     // new XDrawPage for ViewInformation2D
2098cdf0e10cSrcweir                     RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate));
2099cdf0e10cSrcweir                     break;
2100cdf0e10cSrcweir                 }
2101cdf0e10cSrcweir                 case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
2102cdf0e10cSrcweir                 {
2103cdf0e10cSrcweir                     // use default marker array pocessing
2104cdf0e10cSrcweir                     RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate));
2105cdf0e10cSrcweir                     break;
2106cdf0e10cSrcweir                 }
2107cdf0e10cSrcweir                 case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
2108cdf0e10cSrcweir                 {
2109cdf0e10cSrcweir                     // use default point array pocessing
2110cdf0e10cSrcweir                     RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
2111cdf0e10cSrcweir                     break;
2112cdf0e10cSrcweir                 }
2113cdf0e10cSrcweir                 case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D :
2114cdf0e10cSrcweir                 {
2115cdf0e10cSrcweir                     // structured tag primitive
2116cdf0e10cSrcweir                     const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate = static_cast< const primitive2d::StructureTagPrimitive2D& >(rCandidate);
2117cdf0e10cSrcweir                     const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement());
2118cdf0e10cSrcweir                     const bool bTagUsed(vcl::PDFWriter::NonStructElement != rTagElement);
2119cdf0e10cSrcweir 
2120cdf0e10cSrcweir                     if(mpPDFExtOutDevData &&  bTagUsed)
2121cdf0e10cSrcweir                     {
2122cdf0e10cSrcweir                         // write start tag
2123cdf0e10cSrcweir                         mpPDFExtOutDevData->BeginStructureElement(rTagElement);
2124cdf0e10cSrcweir                     }
2125cdf0e10cSrcweir 
2126cdf0e10cSrcweir                     // proccess childs normally
2127cdf0e10cSrcweir                     process(rStructureTagCandidate.getChildren());
2128cdf0e10cSrcweir 
2129cdf0e10cSrcweir                     if(mpPDFExtOutDevData &&  bTagUsed)
2130cdf0e10cSrcweir                     {
2131cdf0e10cSrcweir                         // write end tag
2132cdf0e10cSrcweir                         mpPDFExtOutDevData->EndStructureElement();
2133cdf0e10cSrcweir                     }
2134cdf0e10cSrcweir 
2135cdf0e10cSrcweir                     break;
2136cdf0e10cSrcweir                 }
2137cdf0e10cSrcweir                 case PRIMITIVE2D_ID_EPSPRIMITIVE2D :
2138cdf0e10cSrcweir                 {
2139cdf0e10cSrcweir                     RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate));
2140cdf0e10cSrcweir                     break;
2141cdf0e10cSrcweir                 }
2142cdf0e10cSrcweir                 default :
2143cdf0e10cSrcweir                 {
2144cdf0e10cSrcweir                     // process recursively
2145cdf0e10cSrcweir                     process(rCandidate.get2DDecomposition(getViewInformation2D()));
2146cdf0e10cSrcweir                     break;
2147cdf0e10cSrcweir                 }
2148cdf0e10cSrcweir             }
2149cdf0e10cSrcweir         }
2150cdf0e10cSrcweir     } // end of namespace processor2d
2151cdf0e10cSrcweir } // end of namespace drawinglayer
2152cdf0e10cSrcweir 
2153cdf0e10cSrcweir //////////////////////////////////////////////////////////////////////////////
2154cdf0e10cSrcweir // eof
2155