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