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