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