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