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