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