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