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