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