incubator-ooo-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From a..@apache.org
Subject svn commit: r1398711 [3/4] - in /incubator/ooo/trunk/main: drawinglayer/ drawinglayer/inc/drawinglayer/attribute/ drawinglayer/inc/drawinglayer/primitive2d/ drawinglayer/inc/drawinglayer/primitive3d/ drawinglayer/inc/drawinglayer/processor2d/ drawingla...
Date Tue, 16 Oct 2012 09:44:04 GMT
Added: incubator/ooo/trunk/main/drawinglayer/source/processor2d/_vclmetafileprocessor2d.cxx
URL: http://svn.apache.org/viewvc/incubator/ooo/trunk/main/drawinglayer/source/processor2d/_vclmetafileprocessor2d.cxx?rev=1398711&view=auto
==============================================================================
--- incubator/ooo/trunk/main/drawinglayer/source/processor2d/_vclmetafileprocessor2d.cxx (added)
+++ incubator/ooo/trunk/main/drawinglayer/source/processor2d/_vclmetafileprocessor2d.cxx Tue Oct 16 09:44:02 2012
@@ -0,0 +1,2086 @@
+/**************************************************************
+ * 
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * 
+ *************************************************************/
+
+
+
+// MARKER(update_precomp.py): autogen include statement, do not remove
+#include "precompiled_drawinglayer.hxx"
+
+#include <drawinglayer/processor2d/vclmetafileprocessor2d.hxx>
+#include <tools/gen.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/gradient.hxx>
+#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/bitmapprimitive2d.hxx>
+#include <drawinglayer/primitive2d/metafileprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygonclipper.hxx>
+#include <basegfx/polygon/b2dpolypolygontools.hxx>
+#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/transparenceprimitive2d.hxx>
+#include <drawinglayer/primitive2d/fillgradientprimitive2d.hxx>
+#include <drawinglayer/processor2d/vclpixelprocessor2d.hxx>
+#include <tools/stream.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/markerarrayprimitive2d.hxx>
+#include <drawinglayer/primitive2d/pointarrayprimitive2d.hxx>
+#include <vcl/graphictools.hxx>
+#include <vcl/metaact.hxx>
+#include <drawinglayer/primitive2d/texthierarchyprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
+#include <comphelper/processfactory.hxx>
+#include <rtl/ustring.hxx>
+#include <com/sun/star/i18n/CharacterIteratorMode.hdl>
+#include <com/sun/star/i18n/WordType.hpp>
+#include <drawinglayer/primitive2d/controlprimitive2d.hxx>
+#include <drawinglayer/primitive2d/graphicprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <drawinglayer/primitive2d/pagepreviewprimitive2d.hxx>
+#include <drawinglayer/primitive2d/epsprimitive2d.hxx>
+#include <basegfx/polygon/b2dlinegeometry.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// for PDFExtOutDevData Graphic support
+
+#include <vcl/graph.hxx>
+#include <vcl/svapp.hxx>
+#include <toolkit/helper/formpdfexport.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+// for Control printing
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+//////////////////////////////////////////////////////////////////////////////
+// for StructureTagPrimitive support in sd's unomodel.cxx
+
+#include <drawinglayer/primitive2d/structuretagprimitive2d.hxx>
+
+//////////////////////////////////////////////////////////////////////////////
+
+using namespace com::sun::star;
+
+//////////////////////////////////////////////////////////////////////////////
+// #112245# definition for maximum allowed point count due to Metafile target.
+// To be on the safe side with the old tools polygon, use slightly less then
+// the theoretical maximum (bad experiences with tools polygon)
+
+#define MAX_POLYGON_POINT_COUNT_METAFILE    (0x0000fff0)
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace
+{
+    // #112245# helper to split line polygon in half
+    void splitLinePolygon(
+        const basegfx::B2DPolygon& rBasePolygon, 
+        basegfx::B2DPolygon& o_aLeft, 
+        basegfx::B2DPolygon& o_aRight)
+    {
+        const sal_uInt32 nCount(rBasePolygon.count());
+
+        if(nCount)
+        {
+            const sal_uInt32 nHalfCount((nCount - 1) >> 1);
+            
+            o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1);
+            o_aLeft.setClosed(false);
+
+            o_aRight = basegfx::B2DPolygon(rBasePolygon, nHalfCount, nCount - nHalfCount);
+            o_aRight.setClosed(false);
+
+            if(rBasePolygon.isClosed())
+            {
+                o_aRight.append(rBasePolygon.getB2DPoint(0));
+
+                if(rBasePolygon.areControlPointsUsed())
+                {
+                    o_aRight.setControlPoints(
+                        o_aRight.count() - 1, 
+                        rBasePolygon.getPrevControlPoint(0),
+                        rBasePolygon.getNextControlPoint(0));
+                }
+            }
+        }
+        else
+        {
+            o_aLeft.clear();
+            o_aRight.clear();
+        }
+    }
+
+    // #112245# helper to evtl. split filled polygons to maximum metafile point count
+    bool fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon)
+    {
+        bool bRetval(false);
+        const sal_uInt32 nPolyCount(rPolyPolygon.count());
+
+        if(nPolyCount)
+        {
+            basegfx::B2DPolyPolygon aSplitted;
+
+            for(sal_uInt32 a(0); a < nPolyCount; a++)
+            {
+                const basegfx::B2DPolygon aCandidate(rPolyPolygon.getB2DPolygon(a));
+                const sal_uInt32 nPointCount(aCandidate.count());
+                bool bNeedToSplit(false);
+
+                if(aCandidate.areControlPointsUsed())
+                {
+                    // compare with the maximum for bezier curved polygons
+            		bNeedToSplit = nPointCount > ((MAX_POLYGON_POINT_COUNT_METAFILE / 3L) - 1L);
+                }
+                else
+                {
+                    // compare with the maximum for simple point polygons
+                    bNeedToSplit = nPointCount > (MAX_POLYGON_POINT_COUNT_METAFILE - 1);
+                }
+
+                if(bNeedToSplit)
+                {
+                    // need to split the partial polygon
+                    const basegfx::B2DRange aRange(aCandidate.getB2DRange());
+            		const basegfx::B2DPoint aCenter(aRange.getCenter());
+
+                    if(aRange.getWidth() > aRange.getHeight())
+                    {
+                        // clip in left and right
+                        const basegfx::B2DPolyPolygon aLeft(
+                            basegfx::tools::clipPolygonOnParallelAxis(
+                                aCandidate, 
+                                false, 
+                                true, 
+                                aCenter.getX(),
+                                false));
+                        const basegfx::B2DPolyPolygon aRight(
+                            basegfx::tools::clipPolygonOnParallelAxis(
+                                aCandidate, 
+                                false, 
+                                false, 
+                                aCenter.getX(),
+                                false));
+
+                        aSplitted.append(aLeft);
+                        aSplitted.append(aRight);
+                    }
+                    else
+                    {
+                        // clip in top and bottom
+                        const basegfx::B2DPolyPolygon aTop(
+                            basegfx::tools::clipPolygonOnParallelAxis(
+                                aCandidate, 
+                                true, 
+                                true, 
+                                aCenter.getY(),
+                                false));
+                        const basegfx::B2DPolyPolygon aBottom(
+                            basegfx::tools::clipPolygonOnParallelAxis(
+                                aCandidate, 
+                                true, 
+                                false, 
+                                aCenter.getY(),
+                                false));
+                        
+                        aSplitted.append(aTop);
+                        aSplitted.append(aBottom);
+                    }
+                }
+                else
+                {
+                    aSplitted.append(aCandidate);
+                }
+            }
+
+            if(aSplitted.count() != nPolyCount)
+            {
+                rPolyPolygon = aSplitted;
+            }
+        }
+
+        return bRetval;
+    }
+} // end of anonymous namespace
+
+//////////////////////////////////////////////////////////////////////////////
+
+namespace drawinglayer
+{
+	namespace processor2d
+	{
+        Rectangle VclMetafileProcessor2D::impDumpToMetaFile(
+			const primitive2d::Primitive2DSequence& rContent, 
+			GDIMetaFile& o_rContentMetafile)
+        {
+            // Prepare VDev, MetaFile and connections
+			OutputDevice* pLastOutputDevice = mpOutputDevice;
+            GDIMetaFile* pLastMetafile = mpMetaFile;
+			basegfx::B2DRange aPrimitiveRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
+			
+			// transform primitive range with current transformation (e.g shadow offset)
+			aPrimitiveRange.transform(maCurrentTransformation);
+	
+			const Rectangle aPrimitiveRectangle(
+				basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()),
+				basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY()));
+			VirtualDevice aContentVDev;
+			MapMode aNewMapMode(pLastOutputDevice->GetMapMode());
+			
+			mpOutputDevice = &aContentVDev;
+            mpMetaFile = &o_rContentMetafile;
+			aContentVDev.EnableOutput(false);
+			aContentVDev.SetMapMode(pLastOutputDevice->GetMapMode());
+			o_rContentMetafile.Record(&aContentVDev);
+			aContentVDev.SetLineColor(pLastOutputDevice->GetLineColor());
+			aContentVDev.SetFillColor(pLastOutputDevice->GetFillColor());
+			aContentVDev.SetFont(pLastOutputDevice->GetFont());
+			aContentVDev.SetDrawMode(pLastOutputDevice->GetDrawMode());
+			aContentVDev.SetSettings(pLastOutputDevice->GetSettings());
+			aContentVDev.SetRefPoint(pLastOutputDevice->GetRefPoint());
+
+            // dump to MetaFile
+			process(rContent);
+
+            // cleanups
+			o_rContentMetafile.Stop();
+			o_rContentMetafile.WindStart();
+			aNewMapMode.SetOrigin(aPrimitiveRectangle.TopLeft());
+			o_rContentMetafile.SetPrefMapMode(aNewMapMode);
+			o_rContentMetafile.SetPrefSize(aPrimitiveRectangle.GetSize());
+			mpOutputDevice = pLastOutputDevice;
+            mpMetaFile = pLastMetafile;
+
+            return aPrimitiveRectangle;
+        }
+
+		void VclMetafileProcessor2D::impConvertFillGradientAttributeToVCLGradient(
+			Gradient& o_rVCLGradient, 
+			const attribute::FillGradientAttribute& rFiGrAtt,
+			bool bIsTransparenceGradient)
+        {
+			if(bIsTransparenceGradient)
+			{
+				// it's about transparence channel intensities (black/white), do not use color modifier
+			    o_rVCLGradient.SetStartColor(Color(rFiGrAtt.getStartColor()));
+			    o_rVCLGradient.SetEndColor(Color(rFiGrAtt.getEndColor()));
+			}
+			else
+			{
+				// use color modifier to influence start/end color of gradient
+			    o_rVCLGradient.SetStartColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getStartColor())));
+			    o_rVCLGradient.SetEndColor(Color(maBColorModifierStack.getModifiedColor(rFiGrAtt.getEndColor())));
+			}
+
+            o_rVCLGradient.SetAngle(static_cast< sal_uInt16 >(rFiGrAtt.getAngle() * (1.0 / F_PI1800)));
+            o_rVCLGradient.SetBorder(static_cast< sal_uInt16 >(rFiGrAtt.getBorder() * 100.0));
+		    o_rVCLGradient.SetOfsX(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetX() * 100.0));
+		    o_rVCLGradient.SetOfsY(static_cast< sal_uInt16 >(rFiGrAtt.getOffsetY() * 100.0));
+		    o_rVCLGradient.SetSteps(rFiGrAtt.getSteps());
+
+            // defaults for intensity; those were computed into the start/end colors already
+		    o_rVCLGradient.SetStartIntensity(100);
+		    o_rVCLGradient.SetEndIntensity(100);
+
+            switch(rFiGrAtt.getStyle())
+            {
+                default : // attribute::GRADIENTSTYLE_LINEAR :
+                {
+                    o_rVCLGradient.SetStyle(GRADIENT_LINEAR);
+                    break;
+                }
+                case attribute::GRADIENTSTYLE_AXIAL :
+                {
+                    o_rVCLGradient.SetStyle(GRADIENT_AXIAL);
+                    break;
+                }
+                case attribute::GRADIENTSTYLE_RADIAL :
+                {
+                    o_rVCLGradient.SetStyle(GRADIENT_RADIAL);
+                    break;
+                }
+                case attribute::GRADIENTSTYLE_ELLIPTICAL :
+                {
+                    o_rVCLGradient.SetStyle(GRADIENT_ELLIPTICAL);
+                    break;
+                }
+                case attribute::GRADIENTSTYLE_SQUARE :
+                {
+                    o_rVCLGradient.SetStyle(GRADIENT_SQUARE);
+                    break;
+                }
+                case attribute::GRADIENTSTYLE_RECT :
+                {
+                    o_rVCLGradient.SetStyle(GRADIENT_RECT);
+                    break;
+                }
+            }
+        }
+
+		void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
+		{
+			if(pSvtGraphicFill && !mnSvtGraphicFillCount)
+			{
+				SvMemoryStream aMemStm;
+				
+				aMemStm << *pSvtGraphicFill;
+				mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
+				mnSvtGraphicFillCount++;
+			}
+		}
+
+		void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill* pSvtGraphicFill)
+		{
+			if(pSvtGraphicFill && mnSvtGraphicFillCount)
+			{
+				mnSvtGraphicFillCount--;
+				mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END"));
+				delete pSvtGraphicFill;
+			}
+		}
+
+		SvtGraphicStroke* VclMetafileProcessor2D::impTryToCreateSvtGraphicStroke(
+			const basegfx::B2DPolygon& rB2DPolygon, 
+			const basegfx::BColor* pColor, 
+			const attribute::LineAttribute* pLineAttribute, 
+			const attribute::StrokeAttribute* pStrokeAttribute, 
+			const attribute::LineStartEndAttribute* pStart,
+			const attribute::LineStartEndAttribute* pEnd)
+		{
+			SvtGraphicStroke* pRetval = 0;
+
+			if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount)
+			{
+				basegfx::BColor aStrokeColor;
+				basegfx::B2DPolyPolygon aStartArrow;
+				basegfx::B2DPolyPolygon aEndArrow;
+				
+				if(pColor)
+				{
+					aStrokeColor = *pColor;
+				}
+				else if(pLineAttribute)
+				{
+					aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor());
+				}
+
+				// It IS needed to record the stroke color at all in the metafile,
+				// SvtGraphicStroke has NO entry for stroke color(!)
+				mpOutputDevice->SetLineColor(Color(aStrokeColor));
+
+				if(!rB2DPolygon.isClosed())
+				{
+					double fPolyLength(0.0);
+
+					if(pStart && pStart->isActive())
+					{
+						fPolyLength = basegfx::tools::getLength(rB2DPolygon);
+						
+						aStartArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
+							rB2DPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(), 
+							fPolyLength, pStart->isCentered() ? 0.5 : 0.0, 0);
+					}
+
+					if(pEnd && pEnd->isActive())
+					{
+						if(basegfx::fTools::equalZero(fPolyLength))
+						{
+							fPolyLength = basegfx::tools::getLength(rB2DPolygon);
+						}
+
+						aEndArrow = basegfx::tools::createAreaGeometryForLineStartEnd(
+							rB2DPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(), 
+							fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, 0);
+					}
+				}
+
+                SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone);
+                SvtGraphicStroke::CapType eCap(SvtGraphicStroke::capButt);
+				double fLineWidth(0.0);
+				double fMiterLength(0.0);
+				SvtGraphicStroke::DashArray aDashArray;
+
+				if(pLineAttribute)
+				{
+					// pre-fill fLineWidth #119198# Need to apply maCurrentTransformation, too (!)
+					const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(pLineAttribute->getWidth(), 0.0));
+					fLineWidth = aDiscreteUnit.getLength();
+
+					// pre-fill fMiterLength
+					fMiterLength = fLineWidth;
+
+					// get Join
+					switch(pLineAttribute->getLineJoin())
+					{
+						default : // basegfx::B2DLINEJOIN_NONE :
+						{
+							eJoin = SvtGraphicStroke::joinNone;
+							break;
+						}
+						case basegfx::B2DLINEJOIN_BEVEL :
+						{
+							eJoin = SvtGraphicStroke::joinBevel;
+							break;
+						}
+						case basegfx::B2DLINEJOIN_MIDDLE :
+						case basegfx::B2DLINEJOIN_MITER :
+						{
+							eJoin = SvtGraphicStroke::joinMiter;
+							// ATM 15 degrees is assumed
+							fMiterLength /= rtl::math::sin(M_PI * (15.0 / 360.0));
+							break;
+						}
+						case basegfx::B2DLINEJOIN_ROUND :
+						{
+							eJoin = SvtGraphicStroke::joinRound;
+							break;
+						}
+					}
+
+                    // get stroke
+                    switch(pLineAttribute->getLineCap())
+                    {
+                        default: /* com::sun::star::drawing::LineCap_BUTT */
+                        {
+                            eCap = SvtGraphicStroke::capButt;
+                            break;
+                        }
+                        case com::sun::star::drawing::LineCap_ROUND:
+                        {
+                            eCap = SvtGraphicStroke::capRound;
+                            break;
+                        }
+                        case com::sun::star::drawing::LineCap_SQUARE:
+                        {
+                            eCap = SvtGraphicStroke::capSquare;
+                            break;
+                        }
+                    }
+                }
+
+				if(pStrokeAttribute)
+				{
+					// copy dash array
+					aDashArray = pStrokeAttribute->getDotDashArray();
+				}
+
+				// #i101734# apply current object transformation to created geometry.
+				// This is a partial fix. When a object transformation is used which
+				// e.g. contains a scaleX != scaleY, an unproportional scaling would
+				// have to be applied to the evtl. existing fat line. The current
+				// concept of PDF export and SvtGraphicStroke usage does simply not 
+				// allow handling such definitions. The only clean way would be to
+				// add the transformation to SvtGraphicStroke and to handle it there
+				basegfx::B2DPolygon aB2DPolygon(rB2DPolygon);
+
+				aB2DPolygon.transform(maCurrentTransformation);
+				aStartArrow.transform(maCurrentTransformation);
+				aEndArrow.transform(maCurrentTransformation);
+
+				pRetval = new SvtGraphicStroke(
+					Polygon(aB2DPolygon),
+					PolyPolygon(aStartArrow),
+					PolyPolygon(aEndArrow),
+					mfCurrentUnifiedTransparence,
+					fLineWidth,
+					eCap,
+					eJoin,
+					fMiterLength,
+					aDashArray);
+			}
+
+			return pRetval;
+		}
+
+		void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
+		{
+			if(pSvtGraphicStroke && !mnSvtGraphicStrokeCount)
+			{
+				SvMemoryStream aMemStm;
+				
+				aMemStm << *pSvtGraphicStroke;
+				mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.Seek(STREAM_SEEK_TO_END)));
+				mnSvtGraphicStrokeCount++;
+			}
+		}
+
+		void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke* pSvtGraphicStroke)
+		{
+			if(pSvtGraphicStroke && mnSvtGraphicStrokeCount)
+			{
+				mnSvtGraphicStrokeCount--;
+				mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END"));
+				delete pSvtGraphicStroke;
+			}
+		}
+
+        // init static break iterator
+        uno::Reference< ::com::sun::star::i18n::XBreakIterator > VclMetafileProcessor2D::mxBreakIterator;
+
+		VclMetafileProcessor2D::VclMetafileProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev)
+		:	VclProcessor2D(rViewInformation, rOutDev),
+			mpMetaFile(rOutDev.GetConnectMetaFile()),
+			mnSvtGraphicFillCount(0),
+			mnSvtGraphicStrokeCount(0),
+			mfCurrentUnifiedTransparence(0.0),
+			mpPDFExtOutDevData(dynamic_cast< vcl::PDFExtOutDevData* >(rOutDev.GetExtOutDevData()))
+		{
+			OSL_ENSURE(rOutDev.GetConnectMetaFile(), "VclMetafileProcessor2D: Used on OutDev which has no MetaFile Target (!)");
+			// draw to logic coordinates, do not initialize maCurrentTransformation to viewTransformation
+            // but only to ObjectTransformation. Do not change MapMode of destination.
+			maCurrentTransformation = rViewInformation.getObjectTransformation();
+		}
+
+		VclMetafileProcessor2D::~VclMetafileProcessor2D()
+		{
+			// MapMode was not changed, no restore necessary
+		}
+
+        /***********************************************************************************************
+
+            Support of MetaCommentActions in the VclMetafileProcessor2D
+            Found MetaCommentActions and how they are supported:
+
+            XGRAD_SEQ_BEGIN, XGRAD_SEQ_END:
+
+			Used inside OutputDevice::DrawGradient to mark the start and end of a MetaGradientEx action.
+            It is used in various exporters/importers to have direct access to the gradient before it
+            is rendered by VCL (and thus fragmented to polygon color actions and others). On that base, e.g.
+            the Metafile to SdrObject import creates it's gradient objects.
+            Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
+            map it back to the corresponding tools PolyPolygon and the Gradient and just call
+            OutputDevice::DrawGradient which creates the necessary compatible actions.
+
+            XPATHFILL_SEQ_BEGIN, XPATHFILL_SEQ_END:
+
+			Two producers, one is vcl/source/gdi/gdimtf.cxx, line 1273. There, it is transformed
+            inside GDIMetaFile::Rotate, nothing to take care of here.
+            The second producer is in graphics/svx/source/svdraw/impgrfll.cxx, line 374. This is used
+            with each incarnation of Imp_GraphicFill when a metafile is recorded, fillstyle is not
+            XFILL_NONE and not completely transparent. It creates a SvtGraphicFill and streams it
+            to the comment action. A closing end token is created in the destructor.
+			Usages of Imp_GraphicFill are in Do_Paint_Object-methods of SdrCircObj, SdrPathObj and
+			SdrRectObj.
+            The token users pick various actions from SvtGraphicFill, so it may need to be added for all kind
+            of filled objects, even simple colored polygons. It is added as extra information; the
+            Metafile actions between the two tokens are interpreted as output generated from those
+            fills. Thus, users have the choice to use the SvtGraphicFill info or the created output
+            actions.
+            Even for XFillTransparenceItem it is used, thus it may need to be supported in
+            UnifiedTransparencePrimitive2D, too, when interpreted as normally filled PolyPolygon.
+			Implemented for:
+				PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D,
+				PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D,
+				PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
+				PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D,
+				and for PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D when detected unified transparence
+
+            XPATHSTROKE_SEQ_BEGIN, XPATHSTROKE_SEQ_END:
+
+			Similar to pathfill, but using SvtGraphicStroke instead. It also has two producers where one
+			is also the GDIMetaFile::Rotate. Another user is MetaCommentAction::Move which modifies the
+			contained path accordingly.
+			The other one is SdrObject::Imp_DrawLineGeometry. It's done when MetaFile is set at OutDev and 
+			only when geometry is a single polygon (!). I see no reason for that; in the PS exporter this
+			would hinder to make use of PolyPolygon strokes. I will need to add support at:
+				PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D
+				PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D
+				PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D
+			This can be done hierarchical, too.
+			Okay, base implementation done based on those three primitives.
+
+            FIELD_SEQ_BEGIN, FIELD_SEQ_END
+            
+            Used from slideshow for URLs, created from diverse SvxField implementations inside
+            createBeginComment()/createEndComment(). createBeginComment() is used from editeng\impedit3.cxx
+            inside ImpEditEngine::Paint.
+            Created TextHierarchyFieldPrimitive2D and added needed infos there; it is an group primitive and wraps
+            text primitives (but is not limited to that). It contains the field type if special actions for the 
+			support of FIELD_SEQ_BEGIN/END are needed; this is the case for Page and URL fields. If more is
+			needed, it may be supported there.
+            FIELD_SEQ_BEGIN;PageField
+            FIELD_SEQ_END
+            Okay, these are now completely supported by TextHierarchyFieldPrimitive2D. URL works, too.
+
+            XTEXT
+
+            XTEXT_EOC(i) end of character
+            XTEXT_EOW(i) end of word
+            XTEXT_EOS(i) end of sentence
+            
+            this three are with index and are created with the help of a i18n::XBreakIterator in
+            ImplDrawWithComments. Simplifying, moving out text painting, reworking to create some
+            data structure for holding those TEXT infos.
+            Supported directly by TextSimplePortionPrimitive2D with adding a Locale to the basic text
+            primitive. In the MetaFileRenderer, the creation is now done (see below). This has the advantage
+            that this creations do not need to be done for all paints all the time. This would be
+            expensive since the BreakIterator and it's usage is expensive and for each paint also the
+            whole character stops would need to be created.
+            Created only for TextDecoratedPortionPrimitive2D due to XTEXT_EOL and XTEXT_EOP (see below)
+
+            XTEXT_EOL() end of line
+            XTEXT_EOP() end of paragraph
+			
+            First try with boolean marks at TextDecoratedPortionPrimitive2D did not work too well,
+			i decided to solve it with structure. I added the TextHierarchyPrimitives for this,
+			namely:
+			- TextHierarchyLinePrimitive2D: Encapsulates single line
+			- TextHierarchyParagraphPrimitive2D: Encapsulates single paragraph
+			- TextHierarchyBlockPrimitive2D: encapsulates object texts (only one ATM)
+			Those are now supported in hierarchy. This means the MetaFile renderer will support them
+			by using them, reculrively using their content and adding MetaFile comments as needed.
+			This also means that when another text layouter will be used it will be necessary to
+			create/support the same HierarchyPrimitives to support users.
+			To transport the information using this hierarchy is best suited to all future needs;
+			the slideshow will be able to profit from it directly when using primitives; all other
+			renderers not interested in the text structure will just ignore the encapsulations.
+
+            XTEXT_PAINTSHAPE_BEGIN, XTEXT_PAINTSHAPE_END
+			Supported now by the TextHierarchyBlockPrimitive2D.
+			
+            EPSReplacementGraphic:
+			Only used in goodies\source\filter.vcl\ieps\ieps.cxx and svx\source\xml\xmlgrhlp.cxx to
+			hold the original EPS which was imported in the same MetaFile as first 2 entries. Only
+			used to export the original again (if exists).
+			Not necessary to support with MetaFuleRenderer.
+			
+            XTEXT_SCROLLRECT, XTEXT_PAINTRECT
+			Currently used to get extra MetaFile infos using GraphicExporter which again uses
+			SdrTextObj::GetTextScrollMetaFileAndRectangle(). ATM works with primitives since
+			the rectangle data is added directly by the GraphicsExporter as comment. Does not need
+			to be adapted at once.
+			When adapting later, the only user - the diashow - should directly use the provided
+			Anination infos in the appropriate primitives (e.g. AnimatedSwitchPrimitive2D)
+
+            PRNSPOOL_TRANSPARENTBITMAP_BEGIN, PRNSPOOL_TRANSPARENTBITMAP_END
+			VCL usage when printing PL -> THB. Okay, THB confirms that it is only used as
+			a fix (hack) while VCL printing. It is needed to not downscale a bitmap which
+			was explicitely created for the printer already again to some default maximum
+			bitmap sizes.
+			Nothing to do here for the primitive renderer.
+			
+			Support for vcl::PDFExtOutDevData:
+			PL knows that SJ did that stuff, it's used to hold a pointer to PDFExtOutDevData at
+			the OutDev. When set, some extra data is written there. Trying simple PDF export and
+			watching if i get those infos.
+			Well, a PDF export does not use e.g. ImpEditEngine::Paint since the PdfFilter uses
+			the SdXImpressDocument::render and thus uses the VclMetafileProcessor2D. I will check
+			if i get a PDFExtOutDevData at the target output device.
+			Indeed, i get one. Checking what all may be done when that extra-device-info is there.
+			
+		    All in all i have to talk to SJ. I will need to emulate some of those actions, but
+			i need to discuss which ones.
+			In the future, all those infos would be taken from the primitive sequence anyways,
+			thus these extensions would potentially be temporary, too.
+            Discussed with SJ, added the necessary support and tested it. Details follow.
+
+			- In ImpEditEngine::Paint, paragraph infos and URL stuff is added.
+			  Added in primitive MetaFile renderer.
+			  Checking URL: Indeed, current version exports it, but it is missing in primitive
+			  CWS version. Adding support.
+			  Okay, URLs work. Checked, Done.
+
+            - UnoControlPDFExportContact is only created when PDFExtOutDevData is used at the
+			  target and uno control data is created in UnoControlPDFExportContact::do_PaintObject.
+			  This may be added in primitive MetaFile renderer.
+			  Adding support...
+			  OOps, the necessary helper stuff is in svx/source/form/formpdxexport.cxx in namespace
+			  svxform. Have to talk to FS if this has to be like that. Especially since
+			  ::vcl::PDFWriter::AnyWidget is filled out, which is already part of vcl.
+			  Wrote an eMail to FS, he is on vacation currently. I see no reason why not to move
+			  that stuff to somewhere else, maybe tools or svtools ?!? We will see...
+              Moved to toolkit, so i have to link against it. I tried VCL first, but it did
+              not work since VCLUnoHelper::CreateFont is unresolved in VCL (!). Other then the name
+              may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself,
+              the lowest move,ment plave is toolkit.
+              Checked form control export, it works well. Done.
+
+		    - In goodies, in GraphicObject::Draw, when the used Graphic is linked, infos are
+			  generated. I will need to check what happens here with primitives.
+			  To support, use of GraphicPrimitive2D (PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D) may be needed.
+			  Added support, but feature is broken in main version, so i cannot test at all.
+			  Writing a bug to CL (or SJ) and seeing what happens (#i80380#).
+              SJ took a look and we got it working. Tested VCL MetaFile Renderer based export,
+              as intended, the original file is exported. Works, Done.
+
+
+              
+              
+            To be done:
+
+            - Maybe there are more places to take care of for vcl::PDFExtOutDevData!
+
+
+
+        ****************************************************************************************************/
+
+		void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+		{
+            switch(rCandidate.getPrimitive2DID())
+			{
+                case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
+                {
+					// directdraw of wrong spell primitive
+                    // Ignore for VclMetafileProcessor2D, this is for printing and MetaFile recording only
+                    break;
+                }
+				case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D :
+				{
+                    const primitive2d::GraphicPrimitive2D& rGraphicPrimitive = static_cast< const primitive2d::GraphicPrimitive2D& >(rCandidate);
+					bool bUsingPDFExtOutDevData(false);
+					basegfx::B2DVector aTranslate, aScale;
+					static bool bSuppressPDFExtOutDevDataSupport(false);
+                    
+					if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
+					{
+						// emulate data handling from UnoControlPDFExportContact, original see 
+						// svtools/source/graphic/grfmgr.cxx
+						const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
+
+						if(rGraphic.IsLink())
+						{
+							const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
+
+							if(!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted())
+							{
+								const basegfx::B2DHomMatrix& rTransform = rGraphicPrimitive.getTransform();
+								double fRotate, fShearX;
+								rTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+
+								if( basegfx::fTools::equalZero( fRotate ) && ( aScale.getX() > 0.0 ) && ( aScale.getY() > 0.0 ) )
+								{
+									bUsingPDFExtOutDevData = true;
+									mpPDFExtOutDevData->BeginGroup();
+								}
+							}
+						}
+					}
+
+					// process recursively and add MetaFile comment
+					process(rGraphicPrimitive.get2DDecomposition(getViewInformation2D()));
+
+					if(bUsingPDFExtOutDevData)
+					{
+						// emulate data handling from UnoControlPDFExportContact, original see 
+						// svtools/source/graphic/grfmgr.cxx
+						const basegfx::B2DRange aCurrentRange(
+							aTranslate.getX(), aTranslate.getY(), 
+							aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
+						const Rectangle aCurrentRect(
+							sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())),
+							sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY())));
+						const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
+						Rectangle aCropRect;
+
+						if(rAttr.IsCropped())
+						{
+							// calculate scalings between real image size and logic object size. This
+							// is necessary since the crop values are relative to original bitmap size
+							double fFactorX(1.0);
+							double fFactorY(1.0);
+
+							{
+								const MapMode aMapMode100thmm(MAP_100TH_MM);
+								const Size aBitmapSize(Application::GetDefaultDevice()->LogicToLogic(
+									rGraphicPrimitive.getGraphicObject().GetPrefSize(), 
+									rGraphicPrimitive.getGraphicObject().GetPrefMapMode(), aMapMode100thmm));
+								const double fDivX(aBitmapSize.Width() - rAttr.GetLeftCrop() - rAttr.GetRightCrop());
+								const double fDivY(aBitmapSize.Height() - rAttr.GetTopCrop() - rAttr.GetBottomCrop());
+
+								if(!basegfx::fTools::equalZero(fDivX))
+								{
+									fFactorX = aScale.getX() / fDivX;
+								}
+
+								if(!basegfx::fTools::equalZero(fDivY))
+								{
+									fFactorY = aScale.getY() / fDivY;
+								}
+							}
+
+							// calculate crop range and rect
+							basegfx::B2DRange aCropRange;
+							aCropRange.expand(aCurrentRange.getMinimum() - basegfx::B2DPoint(rAttr.GetLeftCrop() * fFactorX, rAttr.GetTopCrop() * fFactorY));
+							aCropRange.expand(aCurrentRange.getMaximum() + basegfx::B2DPoint(rAttr.GetRightCrop() * fFactorX, rAttr.GetBottomCrop() * fFactorY));
+
+							aCropRect = Rectangle(
+								sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())),
+								sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY())));
+						}
+
+						mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(),
+							rAttr.GetTransparency(),
+							aCurrentRect,
+							aCropRect);
+					}
+				
+					break;
+				}
+				case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
+				{
+                    const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate);
+        			const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
+					bool bIsPrintableControl(false);
+
+                    // find out if control is printable
+					if(rXControl.is())
+					{
+						try
+						{
+							uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY);
+							uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is() 
+								? xModelProperties->getPropertySetInfo() 
+								: uno::Reference< beans::XPropertySetInfo >());
+							const ::rtl::OUString sPrintablePropertyName(RTL_CONSTASCII_USTRINGPARAM("Printable"));
+
+							if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName))
+							{
+								OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl);
+							}
+						}
+						catch(const uno::Exception&)
+						{
+				            OSL_ENSURE(false, "VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!");
+						}
+					}
+
+                    // PDF export and printing only for printable controls
+                    if(bIsPrintableControl)
+                    {
+                        const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
+                        bool bDoProcessRecursively(true);
+
+                        if(bPDFExport)
+					    {
+						    // PDF export. Emulate data handling from UnoControlPDFExportContact
+                            // I have now moved describePDFControl to toolkit, thus i can implement the PDF
+                            // form control support now as follows
+                            ::std::auto_ptr< ::vcl::PDFWriter::AnyWidget > pPDFControl;
+                            ::toolkitform::describePDFControl( rXControl, pPDFControl, *mpPDFExtOutDevData );
+                            
+                            if(pPDFControl.get())
+                            {
+                                // still need to fill in the location (is a class Rectangle)
+			                    const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D()));
+	                            const Rectangle aRectLogic(
+		                            (sal_Int32)floor(aRangeLogic.getMinX()), (sal_Int32)floor(aRangeLogic.getMinY()), 
+		                            (sal_Int32)ceil(aRangeLogic.getMaxX()), (sal_Int32)ceil(aRangeLogic.getMaxY()));
+                                pPDFControl->Location = aRectLogic;
+                                
+                                Size aFontSize(pPDFControl->TextFont.GetSize());
+                                aFontSize = mpOutputDevice->LogicToLogic(aFontSize, MapMode(MAP_POINT), mpOutputDevice->GetMapMode());
+                                pPDFControl->TextFont.SetSize(aFontSize);
+                                
+                                mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form);
+                                mpPDFExtOutDevData->CreateControl(*pPDFControl.get());
+                                mpPDFExtOutDevData->EndStructureElement();
+
+                                // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject); 
+                                // do not process recursively
+                                bDoProcessRecursively = false;
+                            }
+                            else
+                            {
+                                // PDF export did not work, try simple output.
+                                // Fallback to printer output by not setting bDoProcessRecursively
+                                // to false.
+                            }
+					    }
+                        
+                        // #i93169# used flag the wrong way; true means that nothing was done yet
+                        if(bDoProcessRecursively)
+					    {
+    					    // printer output
+					        try
+					        {
+                                // remember old graphics and create new
+					            uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW);
+                                const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics());
+					            const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics());
+
+                                if(xNewGraphics.is())
+                                {
+				                    // link graphics and view
+				                    xControlView->setGraphics(xNewGraphics);
+
+                                    // get position
+                                    const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform());
+                                    const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0));
+                                    
+                                    // draw it
+                                    xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY()));
+                                    bDoProcessRecursively = false;
+                                    
+                                    // restore original graphics
+				                    xControlView->setGraphics(xOriginalGraphics);
+                                }
+					        }
+					        catch( const uno::Exception& )
+					        {
+			                    OSL_ENSURE(false, "VclMetafileProcessor2D: Printing of Control failed, caught an exception!");
+					        }
+					    }
+
+					    // process recursively if not done yet to export as decomposition (bitmap)
+                        if(bDoProcessRecursively)
+                        {
+    					    process(rControlPrimitive.get2DDecomposition(getViewInformation2D()));
+                        }
+                    }
+					
+					break;
+				}
+                case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D :
+                {
+                    // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to)
+                    // thus do the MetafileAction embedding stuff but just handle recursively.
+					const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive = static_cast< const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate);
+                    static const ByteString aCommentStringCommon("FIELD_SEQ_BEGIN");
+					static const ByteString aCommentStringPage("FIELD_SEQ_BEGIN;PageField");
+					static const ByteString aCommentStringEnd("FIELD_SEQ_END");
+
+					switch(rFieldPrimitive.getType())
+					{
+						default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON :
+						{
+		                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon));
+							break;
+						}
+						case drawinglayer::primitive2d::FIELD_TYPE_PAGE :
+						{
+		                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage));
+							break;
+						}
+						case drawinglayer::primitive2d::FIELD_TYPE_URL :
+						{
+							const rtl::OUString& rURL = rFieldPrimitive.getString();
+                            const String aOldString(rURL);
+		                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast< const sal_uInt8* >(aOldString.GetBuffer()), 2 * aOldString.Len()));
+							break;
+						}
+					}
+
+					// process recursively
+					const primitive2d::Primitive2DSequence rContent = rFieldPrimitive.get2DDecomposition(getViewInformation2D());
+					process(rContent);
+
+					// for the end comment the type is not relevant yet, they are all the same. Just add.
+                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd));
+
+					if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType())
+					{
+						// emulate data handling from ImpEditEngine::Paint
+			            const basegfx::B2DRange aViewRange(primitive2d::getB2DRangeFromPrimitive2DSequence(rContent, getViewInformation2D()));
+	                    const Rectangle aRectLogic(
+		                    (sal_Int32)floor(aViewRange.getMinX()), (sal_Int32)floor(aViewRange.getMinY()), 
+		                    (sal_Int32)ceil(aViewRange.getMaxX()), (sal_Int32)ceil(aViewRange.getMaxY()));
+						vcl::PDFExtOutDevBookmarkEntry aBookmark;
+						aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic);
+						aBookmark.aBookmark = rFieldPrimitive.getString();
+						std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks();
+						rBookmarks.push_back( aBookmark );
+					}
+
+                    break;
+                }
+                case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D :
+                {
+                    const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive = static_cast< const primitive2d::TextHierarchyLinePrimitive2D& >(rCandidate);
+                    static const ByteString aCommentString("XTEXT_EOL");
+					
+                    // process recursively and add MetaFile comment
+					process(rLinePrimitive.get2DDecomposition(getViewInformation2D()));
+                    mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+
+                    break;
+                }
+                case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D :
+                {
+                    // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The
+                    // "XTEXT_EOC" is used, use here, too.
+					const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive = static_cast< const primitive2d::TextHierarchyBulletPrimitive2D& >(rCandidate);
+                    static const ByteString aCommentString("XTEXT_EOC");
+					
+                    // process recursively and add MetaFile comment
+					process(rBulletPrimitive.get2DDecomposition(getViewInformation2D()));
+                    mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+
+                    break;
+                }
+                case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D :
+                {
+                    const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive = static_cast< const primitive2d::TextHierarchyParagraphPrimitive2D& >(rCandidate);
+                    static const ByteString aCommentString("XTEXT_EOP");
+
+					if(mpPDFExtOutDevData)
+					{
+						// emulate data handling from ImpEditEngine::Paint
+						mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
+					}
+
+                    // process recursively and add MetaFile comment
+					process(rParagraphPrimitive.get2DDecomposition(getViewInformation2D()));
+                    mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+
+					if(mpPDFExtOutDevData)
+					{
+						// emulate data handling from ImpEditEngine::Paint
+						mpPDFExtOutDevData->EndStructureElement();
+					}
+
+					break;
+                }
+                case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D :
+                {
+                    const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive = static_cast< const primitive2d::TextHierarchyBlockPrimitive2D& >(rCandidate);
+                    static const ByteString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN");
+                    static const ByteString aCommentStringB("XTEXT_PAINTSHAPE_END");
+
+                    // add MetaFile comment, process recursively and add MetaFile comment
+                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA));
+					process(rBlockPrimitive.get2DDecomposition(getViewInformation2D()));
+                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB));
+
+                    break;
+                }
+				case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
+				case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
+				{
+                    // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate
+					const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate = static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate);
+					// const primitive2d::TextDecoratedPortionPrimitive2D* pTextDecoratedCandidate = dynamic_cast< const primitive2d::TextDecoratedPortionPrimitive2D* >(&rCandidate);
+
+					// Adapt evtl. used special DrawMode
+					const sal_uInt32 nOriginalDrawMode(mpOutputDevice->GetDrawMode());
+					adaptTextToFillDrawMode();
+
+					// directdraw of text simple portion; use default processing
+					RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate);
+
+					// restore DrawMode
+					mpOutputDevice->SetDrawMode(nOriginalDrawMode);
+
+					// #i101169# if(pTextDecoratedCandidate)
+                    {
+                        // support for TEXT_ MetaFile actions only for decorated texts
+                        if(!mxBreakIterator.is())
+                        {
+                            uno::Reference< ::com::sun::star::lang::XMultiServiceFactory > xMSF(::comphelper::getProcessServiceFactory());
+                            mxBreakIterator.set(xMSF->createInstance(rtl::OUString::createFromAscii("com.sun.star.i18n.BreakIterator")), uno::UNO_QUERY);
+                        }
+
+                        if(mxBreakIterator.is())
+                        {
+                            const rtl::OUString& rTxt = rTextCandidate.getText();
+                            const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength());
+
+                            if(nTextLength)
+                            {
+                                const ::com::sun::star::lang::Locale& rLocale = rTextCandidate.getLocale();
+                                const sal_Int32 nTextPosition(rTextCandidate.getTextPosition());
+
+                                sal_Int32 nDone;
+                                sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
+                                ::com::sun::star::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True));
+                                sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
+                                static const ByteString aCommentStringA("XTEXT_EOC");
+                                static const ByteString aCommentStringB("XTEXT_EOW");
+                                static const ByteString aCommentStringC("XTEXT_EOS");
+
+                                for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++)
+                                {
+                                    // create the entries for the respective break positions
+                                    if(i == nNextCellBreak)
+                                    {
+                                        mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition));
+                                        nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, ::com::sun::star::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
+                                    }
+                                    if(i == nNextWordBoundary.endPos)
+                                    {
+                                        mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition));
+                                        nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, ::com::sun::star::i18n::WordType::ANY_WORD, sal_True);
+                                    }
+                                    if(i == nNextSentenceBreak)
+                                    {
+                                        mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition));
+                                        nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale);
+                                    }
+                                }
+                            }
+                        }
+                    }
+
+                    break;
+				}
+				case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
+				{
+					const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate);
+        			const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon();
+
+                    if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
+                    {
+                        // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+                        // per polygon. If there are more, split the polygon in half and call recursively
+                        basegfx::B2DPolygon aLeft, aRight;
+                        splitLinePolygon(rBasePolygon, aLeft, aRight);
+                        const primitive2d::PolygonHairlinePrimitive2D aPLeft(aLeft, rHairlinePrimitive.getBColor());
+                        const primitive2d::PolygonHairlinePrimitive2D aPRight(aRight, rHairlinePrimitive.getBColor());
+                   
+                        processBasePrimitive2D(aPLeft);
+                        processBasePrimitive2D(aPRight);
+                    }
+                    else
+                    {
+    					// direct draw of hairline; use default processing
+    					// support SvtGraphicStroke MetaCommentAction
+					    const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor()));
+					    SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
+                            rHairlinePrimitive.getB2DPolygon(), 
+                            &aLineColor, 
+                            0, 0, 0, 0);
+
+					    impStartSvtGraphicStroke(pSvtGraphicStroke);
+					    RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false);
+					    impEndSvtGraphicStroke(pSvtGraphicStroke);
+                    }
+					break;
+				}
+				case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D :
+				{
+					const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate);
+        			const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon();
+
+                    if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
+                    {
+                        // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+                        // per polygon. If there are more, split the polygon in half and call recursively
+                        basegfx::B2DPolygon aLeft, aRight;
+                        splitLinePolygon(rBasePolygon, aLeft, aRight);
+                        const primitive2d::PolygonStrokePrimitive2D aPLeft(
+                            aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute());
+                        const primitive2d::PolygonStrokePrimitive2D aPRight(
+                            aRight, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute());
+                   
+                        processBasePrimitive2D(aPLeft);
+                        processBasePrimitive2D(aPRight);
+                    }
+                    else
+                    {
+    					// support SvtGraphicStroke MetaCommentAction
+					    SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
+                            rBasePolygon, 0, 
+                            &rStrokePrimitive.getLineAttribute(), 
+                            &rStrokePrimitive.getStrokeAttribute(), 
+                            0, 0);
+
+					    impStartSvtGraphicStroke(pSvtGraphicStroke);
+					    const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute();
+
+					    // create MetaPolyLineActions, but without LINE_DASH
+					    if(basegfx::fTools::more(rLine.getWidth(), 0.0))
+					    {
+						    const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute();
+						    basegfx::B2DPolyPolygon aHairLinePolyPolygon;
+
+						    if(0.0 == rStroke.getFullDotDashLen())
+						    {
+							    aHairLinePolyPolygon.append(rBasePolygon);
+						    }
+						    else
+						    {
+							    basegfx::tools::applyLineDashing(
+								    rBasePolygon, rStroke.getDotDashArray(), 
+								    &aHairLinePolyPolygon, 0, rStroke.getFullDotDashLen());
+						    }
+
+						    const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor()));
+						    mpOutputDevice->SetLineColor(Color(aHairlineColor));
+						    mpOutputDevice->SetFillColor();
+						    aHairLinePolyPolygon.transform(maCurrentTransformation);
+							
+							// #i113922# LineWidth needs to be transformed, too
+							const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation * basegfx::B2DVector(rLine.getWidth(), 0.0));
+							const double fDiscreteLineWidth(aDiscreteUnit.getLength());
+
+							LineInfo aLineInfo(LINE_SOLID, basegfx::fround(fDiscreteLineWidth));
+						    aLineInfo.SetLineJoin(rLine.getLineJoin());
+                            aLineInfo.SetLineCap(rLine.getLineCap());
+
+						    for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
+						    {
+							    const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a));
+
+							    if(aCandidate.count() > 1)
+							    {
+								    const Polygon aToolsPolygon(aCandidate);
+
+                				    mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo));
+							    }
+						    }
+					    }
+					    else
+					    {
+						    process(rCandidate.get2DDecomposition(getViewInformation2D()));
+					    }
+
+					    impEndSvtGraphicStroke(pSvtGraphicStroke);
+                    }
+					
+					break;
+				}
+				case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D :
+				{
+					const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate);
+        			const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon();
+
+                    if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
+                    {
+                        // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+                        // per polygon. If there are more, split the polygon in half and call recursively
+                        basegfx::B2DPolygon aLeft, aRight;
+                        splitLinePolygon(rBasePolygon, aLeft, aRight);
+                        const attribute::LineStartEndAttribute aEmpty;
+                        const primitive2d::PolygonStrokeArrowPrimitive2D aPLeft(
+                            aLeft, 
+                            rStrokeArrowPrimitive.getLineAttribute(), 
+                            rStrokeArrowPrimitive.getStrokeAttribute(),
+                            rStrokeArrowPrimitive.getStart(),
+                            aEmpty);
+                        const primitive2d::PolygonStrokeArrowPrimitive2D aPRight(
+                            aRight, 
+                            rStrokeArrowPrimitive.getLineAttribute(), 
+                            rStrokeArrowPrimitive.getStrokeAttribute(),
+                            aEmpty,
+                            rStrokeArrowPrimitive.getEnd());
+                   
+                        processBasePrimitive2D(aPLeft);
+                        processBasePrimitive2D(aPRight);
+                    }
+                    else
+                    {
+    					// support SvtGraphicStroke MetaCommentAction
+	    				SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
+                            rBasePolygon, 0, 
+                            &rStrokeArrowPrimitive.getLineAttribute(), 
+                            &rStrokeArrowPrimitive.getStrokeAttribute(), 
+                            &rStrokeArrowPrimitive.getStart(), 
+                            &rStrokeArrowPrimitive.getEnd());
+
+			    		impStartSvtGraphicStroke(pSvtGraphicStroke);
+				    	process(rCandidate.get2DDecomposition(getViewInformation2D()));
+					    impEndSvtGraphicStroke(pSvtGraphicStroke);
+                    }
+
+                    break;
+				}
+				case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
+				{
+                    // direct draw of transformed BitmapEx primitive; use default processing
+					RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
+					break;
+				}
+				case PRIMITIVE2D_ID_POLYPOLYGONBITMAPPRIMITIVE2D :
+				{
+					// need to handle PolyPolygonBitmapPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
+					const primitive2d::PolyPolygonBitmapPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonBitmapPrimitive2D& >(rCandidate);
+					basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon());
+
+                    if(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
+                    {
+                        // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+                        // per polygon. If there are more use the splitted polygon and call recursively
+                        const primitive2d::PolyPolygonBitmapPrimitive2D aSplitted(
+                            aLocalPolyPolygon,
+                            rBitmapCandidate.getFillBitmap());
+                        
+                        processBasePrimitive2D(aSplitted);
+                    }
+                    else
+                    {
+                        SvtGraphicFill* pSvtGraphicFill = 0;
+
+					    if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+					    {
+						    aLocalPolyPolygon.transform(maCurrentTransformation);
+						    // calculate transformation. Get real object size, all values in FillBitmapAttribute
+						    // are relative to the unified object
+						    const attribute::FillBitmapAttribute& rFillBitmapAttribute = rBitmapCandidate .getFillBitmap();
+						    const basegfx::B2DRange aOutlineRange(basegfx::tools::getRange(aLocalPolyPolygon));
+						    const basegfx::B2DVector aOutlineSize(aOutlineRange.getRange());
+
+						    // get absolute values
+						    const basegfx::B2DVector aFillBitmapSize(rFillBitmapAttribute.getSize() * aOutlineSize);
+						    const basegfx::B2DPoint aFillBitmapTopLeft(rFillBitmapAttribute.getTopLeft() * aOutlineSize);
+
+						    // the scaling needs scale from pixel to logic coordinate system
+						    const BitmapEx& rBitmapEx = rFillBitmapAttribute.getBitmapEx();
+						    Size aBmpSizePixel(rBitmapEx.GetSizePixel());
+
+						    if(!aBmpSizePixel.Width())
+						    {
+							    aBmpSizePixel.Width() = 1;
+						    }
+
+						    if(!aBmpSizePixel.Height())
+						    {
+							    aBmpSizePixel.Height() = 1;
+						    }
+
+						    // setup transformation like in impgrfll
+						    SvtGraphicFill::Transform aTransform;
+
+						    // scale values are divided by bitmap pixel sizes
+						    aTransform.matrix[0] = aFillBitmapSize.getX() / aBmpSizePixel.Width();
+						    aTransform.matrix[4] = aFillBitmapSize.getY() / aBmpSizePixel.Height();
+    						
+                            // translates are absolute
+                            aTransform.matrix[2] = aFillBitmapTopLeft.getX();
+						    aTransform.matrix[5] = aFillBitmapTopLeft.getY();
+
+						    // setup fill graphic like in impgrfll
+						    Graphic aFillGraphic = Graphic(rBitmapEx);
+						    aFillGraphic.SetPrefMapMode(MapMode(MAP_PIXEL));
+						    aFillGraphic.SetPrefSize(aBmpSizePixel);
+
+						    pSvtGraphicFill = new SvtGraphicFill(
+							    PolyPolygon(aLocalPolyPolygon),
+							    Color(),
+							    0.0,
+							    SvtGraphicFill::fillEvenOdd,
+							    SvtGraphicFill::fillTexture,
+							    aTransform,
+							    rFillBitmapAttribute.getTiling(),
+							    SvtGraphicFill::hatchSingle,
+							    Color(),
+							    SvtGraphicFill::gradientLinear,
+							    Color(),
+							    Color(),
+							    0,
+							    aFillGraphic);
+					    }
+
+					    // Do use decomposition; encapsulate with SvtGraphicFill
+					    impStartSvtGraphicFill(pSvtGraphicFill);
+					    process(rCandidate.get2DDecomposition(getViewInformation2D()));
+					    impEndSvtGraphicFill(pSvtGraphicFill);
+                    }
+
+					break;
+				}
+				case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D :
+				{
+					// need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
+					const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate);
+				    const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch();
+					basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon());
+
+                    // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+                    // per polygon. Split polygon until there are less than that
+                    while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
+                        ;
+
+					if(rFillHatchAttribute.isFillBackground())
+					{
+						// with fixing #i111954# (see below) the possible background
+						// fill of a hatched object was lost.Generate a background fill 
+						// primitive and render it
+					    const primitive2d::Primitive2DReference xBackground(
+							new primitive2d::PolyPolygonColorPrimitive2D(
+								aLocalPolyPolygon, 
+								rHatchCandidate.getBackgroundColor()));
+						
+						process(primitive2d::Primitive2DSequence(&xBackground, 1));
+					}
+
+                    SvtGraphicFill* pSvtGraphicFill = 0;
+				    aLocalPolyPolygon.transform(maCurrentTransformation);
+
+				    if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+				    {
+					    // re-create a VCL hatch as base data
+					    SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle);
+
+					    switch(rFillHatchAttribute.getStyle())
+					    {
+						    default: // attribute::HATCHSTYLE_SINGLE : 
+						    {
+							    eHatch = SvtGraphicFill::hatchSingle;
+							    break;
+						    }
+						    case attribute::HATCHSTYLE_DOUBLE :
+						    {
+							    eHatch = SvtGraphicFill::hatchDouble;
+							    break;
+						    }
+						    case attribute::HATCHSTYLE_TRIPLE :
+						    {
+							    eHatch = SvtGraphicFill::hatchTriple;
+							    break;
+						    }
+					    }
+
+					    SvtGraphicFill::Transform aTransform;
+						
+					    // scale
+					    aTransform.matrix[0] *= rFillHatchAttribute.getDistance();
+					    aTransform.matrix[4] *= rFillHatchAttribute.getDistance();
+
+					    // rotate (was never correct in impgrfll anyways, use correct angle now)
+					    aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle());
+					    aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle());
+					    aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle());
+					    aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle());
+						
+					    pSvtGraphicFill = new SvtGraphicFill(
+						    PolyPolygon(aLocalPolyPolygon),
+						    Color(),
+						    0.0,
+						    SvtGraphicFill::fillEvenOdd,
+						    SvtGraphicFill::fillHatch,
+						    aTransform,
+						    false,
+						    eHatch,
+						    Color(rFillHatchAttribute.getColor()),
+						    SvtGraphicFill::gradientLinear,
+						    Color(),
+						    Color(),
+						    0,
+						    Graphic());
+				    }
+
+				    // Do use decomposition; encapsulate with SvtGraphicFill
+				    impStartSvtGraphicFill(pSvtGraphicFill);
+
+                    // #i111954# do NOT use decomposition, but use direct VCL-command
+			        // process(rCandidate.get2DDecomposition(getViewInformation2D()));
+			        const PolyPolygon aToolsPolyPolygon(aLocalPolyPolygon);
+                    const HatchStyle aHatchStyle(
+                        attribute::HATCHSTYLE_SINGLE == rFillHatchAttribute.getStyle() ? HATCH_SINGLE :
+                        attribute::HATCHSTYLE_DOUBLE == rFillHatchAttribute.getStyle() ? HATCH_DOUBLE :
+                        HATCH_TRIPLE);
+
+                    mpOutputDevice->DrawHatch(aToolsPolyPolygon, 
+                        Hatch(aHatchStyle, 
+                            Color(rFillHatchAttribute.getColor()),
+                            basegfx::fround(rFillHatchAttribute.getDistance()),
+                            basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800)));
+
+                    impEndSvtGraphicFill(pSvtGraphicFill);
+
+					break;
+				}
+				case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
+                {
+                    basegfx::B2DVector aScale, aTranslate;
+                    double fRotate, fShearX;
+
+                    maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
+
+                    if(!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX))
+                    {
+                        // #121185# When rotation or shear is used, a VCL Gradient cannot be used directly.
+                        // This is because VCL Gradient mechanism does *not* support to rotate the gradient
+                        // with objects and this case is not expressable in a Metafile (and cannot be added
+                        // since the FileFormats used, e.g. *.wmf, do not support it either).
+                        // Such cases happen when a graphic object uses a Metafile as graphic information or
+                        // a fill style definition uses a Metafile. In this cases the graphic content is 
+                        // rotated with the graphic or filled object; this is not supported by the target 
+                        // format of this conversion renderer - Metafiles.
+                        // To solve this, not a Gradient is written, but the decomposition of this object
+                        // is written to the Metafile. This is the PolyPolygons building the gradient fill.
+                        // These will need more space and time, but the result will be as if the Gradient
+                        // was rotated with the object.
+                        // This mechanism is used by all exporters still not using Primtives (e.g. Print,
+                        // Slideshow, Export rto PDF, export to Picture, ...) but relying on Metafile 
+                        // transfers. One more reason to *change* these to primitives.
+                        // BTW: One more example how useful the principles of primitives are; the decomposition
+                        // is by definition a simpler, maybe more expensive representation of the same content.
+                        process(rCandidate.get2DDecomposition(getViewInformation2D()));
+                    }
+                    else
+                    {
+					    const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate);
+			            basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon());
+
+                        // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+                        // per polygon. Split polygon until there are less than that
+                        while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
+                            ;
+
+                        // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END
+                        // it is safest to use the VCL OutputDevice::DrawGradient method which creates those.
+                        // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon
+				        Gradient aVCLGradient;
+                        impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false);
+		                aLocalPolyPolygon.transform(maCurrentTransformation);
+                    
+				        // #i82145# ATM VCL printing of gradients using curved shapes does not work,
+				        // i submitted the bug with the given ID to THB. When that task is fixed it is
+				        // necessary to again remove this subdivision since it decreases possible
+				        // printing quality (not even resolution-dependent for now). THB will tell
+				        // me when that task is fixed in the master
+				        const PolyPolygon aToolsPolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(aLocalPolyPolygon));
+
+				        // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
+				        SvtGraphicFill* pSvtGraphicFill = 0;
+
+				        if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+				        {
+					        // setup gradient stuff like in like in impgrfll
+					        SvtGraphicFill::GradientType eGrad(SvtGraphicFill::gradientLinear);
+
+					        switch(aVCLGradient.GetStyle())
+					        {
+						        default : // GRADIENT_LINEAR:
+						        case GRADIENT_AXIAL:
+							        eGrad = SvtGraphicFill::gradientLinear;
+							        break;
+						        case GRADIENT_RADIAL:
+						        case GRADIENT_ELLIPTICAL:
+							        eGrad = SvtGraphicFill::gradientRadial;
+							        break;
+						        case GRADIENT_SQUARE:
+						        case GRADIENT_RECT:
+							        eGrad = SvtGraphicFill::gradientRectangular;
+							        break;
+					        }
+						
+					        pSvtGraphicFill = new SvtGraphicFill(
+						        aToolsPolyPolygon,
+						        Color(),
+						        0.0,
+						        SvtGraphicFill::fillEvenOdd,
+						        SvtGraphicFill::fillGradient,
+						        SvtGraphicFill::Transform(),
+						        false,
+						        SvtGraphicFill::hatchSingle,
+						        Color(),
+						        eGrad,
+						        aVCLGradient.GetStartColor(),
+						        aVCLGradient.GetEndColor(),
+						        aVCLGradient.GetSteps(),
+						        Graphic());
+				        }
+
+				        // call VCL directly; encapsulate with SvtGraphicFill
+				        impStartSvtGraphicFill(pSvtGraphicFill);
+		                mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient);
+				        impEndSvtGraphicFill(pSvtGraphicFill);
+
+				        // NO usage of common own gradient randerer, not used ATM for VCL MetaFile, see text above
+				        // RenderPolyPolygonGradientPrimitive2D(static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate));
+                    }
+
+                    break;
+                }
+				case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
+				{
+					const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
+					basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
+
+                    // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+                    // per polygon. Split polygon until there are less than that
+                    while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
+                        ;
+
+				    const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
+				    aLocalPolyPolygon.transform(maCurrentTransformation);
+
+				    // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
+				    SvtGraphicFill* pSvtGraphicFill = 0;
+
+				    if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+				    {
+					    // setup simple color fill stuff like in impgrfll
+					    pSvtGraphicFill = new SvtGraphicFill(
+						    PolyPolygon(aLocalPolyPolygon),
+						    Color(aPolygonColor),
+						    0.0,
+						    SvtGraphicFill::fillEvenOdd,
+						    SvtGraphicFill::fillSolid,
+						    SvtGraphicFill::Transform(),
+						    false,
+						    SvtGraphicFill::hatchSingle,
+						    Color(),
+						    SvtGraphicFill::gradientLinear,
+						    Color(),
+						    Color(),
+						    0,
+						    Graphic());
+				    }
+
+                    // set line and fill color
+				    mpOutputDevice->SetFillColor(Color(aPolygonColor));
+				    mpOutputDevice->SetLineColor();
+
+				    // call VCL directly; encapsulate with SvtGraphicFill
+                    impStartSvtGraphicFill(pSvtGraphicFill);
+				    mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
+				    impEndSvtGraphicFill(pSvtGraphicFill);
+
+					break;
+				}
+				case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
+				{
+                    static bool bUseMetaFilePrimitiveDecomposition(true);
+                    
+                    if(bUseMetaFilePrimitiveDecomposition)
+                    {
+                        // use new Metafile decomposition
+    					process(rCandidate.get2DDecomposition(getViewInformation2D()));
+                    }
+                    else
+                    {
+                        // direct draw of MetaFile, use default pocessing
+					    RenderMetafilePrimitive2D(static_cast< const primitive2d::MetafilePrimitive2D& >(rCandidate));
+                    }
+					
+                    break;
+				}
+				case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
+				{
+                    // mask group. Special handling for MetaFiles.
+					const primitive2d::MaskPrimitive2D& rMaskCandidate = static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate);
+
+                    if(rMaskCandidate.getChildren().hasElements())
+			        {
+				        basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
+
+				        if(aMask.count())
+				        {
+							// prepare new mask polygon and rescue current one
+					        aMask.transform(maCurrentTransformation);
+                            const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
+					        
+                            if(maClipPolyPolygon.count())
+                            {
+								// there is already a clip polygon set; build clipped union of 
+								// current mask polygon and new one
+								maClipPolyPolygon = basegfx::tools::clipPolyPolygonOnPolyPolygon(
+                                    aMask, 
+                                    maClipPolyPolygon, 
+                                    true, // #i106516# we want the inside of aMask, not the outside
+                                    false);
+                            }
+                            else
+                            {
+                                // use mask directly
+                                maClipPolyPolygon = aMask;
+                            }
+
+                            if(maClipPolyPolygon.count())
+                            {
+                                // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!)
+                                // Removed subdivision and fixed in Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where
+                                // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there
+                                mpOutputDevice->Push(PUSH_CLIPREGION);
+								//mpOutputDevice->SetClipRegion(Region(PolyPolygon(basegfx::tools::adaptiveSubdivideByAngle(maClipPolyPolygon))));
+								//mpOutputDevice->SetClipRegion(Region(PolyPolygon(maClipPolyPolygon)));
+								mpOutputDevice->SetClipRegion(Region(maClipPolyPolygon));
+                            }
+
+					        // recursively paint content
+					        process(rMaskCandidate.getChildren());
+                            
+                            if(maClipPolyPolygon.count())
+                            {
+                                // restore VCL clip region
+                                mpOutputDevice->Pop();
+                            }
+
+                            // restore to rescued clip polygon
+                            maClipPolyPolygon = aLastClipPolyPolygon;
+				        }
+                        else
+                        {
+                            // no mask, no clipping. recursively paint content
+					        process(rMaskCandidate.getChildren());
+                        }
+			        }
+
+                    break;
+				}
+				case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
+				{
+					// modified color group. Force output to unified color. Use default pocessing.
+					RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
+					break;
+				}
+                case PRIMITIVE2D_ID_HIDDENGEOMETRYPRIMITIVE2D :
+				{
+                    // HiddenGeometryPrimitive2D; to rebuilt the old MetaFile creation, it is necessary to
+                    // not ignore them (as it was thought), but to add a MetaFile entry for them.
+        		    basegfx::B2DRange aInvisibleRange(rCandidate.getB2DRange(getViewInformation2D()));
+
+                    if(!aInvisibleRange.isEmpty())
+                    {
+		                aInvisibleRange.transform(maCurrentTransformation);
+                        const Rectangle aRectLogic(
+	                        (sal_Int32)floor(aInvisibleRange.getMinX()), (sal_Int32)floor(aInvisibleRange.getMinY()), 
+	                        (sal_Int32)ceil(aInvisibleRange.getMaxX()), (sal_Int32)ceil(aInvisibleRange.getMaxY()));
+
+                        mpOutputDevice->SetFillColor();
+		                mpOutputDevice->SetLineColor();
+		                mpOutputDevice->DrawRect(aRectLogic);
+                    }
+
+					break;
+				}
+				case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
+				{
+					// for metafile: Need to examine what the pure vcl version is doing here actually
+					// - uses DrawTransparent with metafile for content and a gradient
+					// - uses DrawTransparent for single PolyPoylgons directly. Can be detected by
+					//   checking the content for single PolyPolygonColorPrimitive2D
+					const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate);
+					const primitive2d::Primitive2DSequence rContent = rUniTransparenceCandidate.getChildren();
+
+					if(rContent.hasElements())
+					{
+                        if(0.0 == rUniTransparenceCandidate.getTransparence())
+                        {
+                            // not transparent at all, use content
+	                        process(rUniTransparenceCandidate.getChildren());
+                        }
+			            else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
+			            {
+						    // try to identify a single PolyPolygonColorPrimitive2D in the
+						    // content part of the transparence primitive
+						    const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = 0;
+						    static bool bForceToMetafile(false);
+
+						    if(!bForceToMetafile && 1 == rContent.getLength())
+						    {
+							    const primitive2d::Primitive2DReference xReference(rContent[0]);
+							    pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get());
+						    }
+
+						    // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and
+						    // PolyPolygonBitmapPrimitive2D are derived from PolyPolygonColorPrimitive2D.
+						    // Check also for correct ID to exclude derived implementations
+						    if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID())
+						    {
+							    // single transparent PolyPolygon identified, use directly
+							    const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
+							    basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon());
+                                
+                                // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
+                                // per polygon. Split polygon until there are less than that
+                                while(fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon))
+                                    ;
+
+                                // now transform
+                                aLocalPolyPolygon.transform(maCurrentTransformation);
+
+							    // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
+							    SvtGraphicFill* pSvtGraphicFill = 0;
+
+							    if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
+							    {
+								    // setup simple color with transparence fill stuff like in impgrfll
+								    pSvtGraphicFill = new SvtGraphicFill(
+									    PolyPolygon(aLocalPolyPolygon),
+									    Color(aPolygonColor),
+									    rUniTransparenceCandidate.getTransparence(),
+									    SvtGraphicFill::fillEvenOdd,
+									    SvtGraphicFill::fillSolid,
+									    SvtGraphicFill::Transform(),
+									    false,
+									    SvtGraphicFill::hatchSingle,
+									    Color(),
+									    SvtGraphicFill::gradientLinear,
+									    Color(),
+									    Color(),
+									    0,
+									    Graphic());
+							    }
+
+                                // set line and fill color
+							    const sal_uInt16 nTransPercentVcl((sal_uInt16)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0));
+							    mpOutputDevice->SetFillColor(Color(aPolygonColor));
+							    mpOutputDevice->SetLineColor();
+
+							    // call VCL directly; encapsulate with SvtGraphicFill
+                                impStartSvtGraphicFill(pSvtGraphicFill);
+							    mpOutputDevice->DrawTransparent(
+								    PolyPolygon(aLocalPolyPolygon), 
+								    nTransPercentVcl);
+							    impEndSvtGraphicFill(pSvtGraphicFill);
+						    }
+						    else
+						    {
+							    // svae old mfCurrentUnifiedTransparence and set new one
+							    // so that contained SvtGraphicStroke may use the current one
+							    const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence);
+                                // #i105377# paint the content metafile opaque as the transparency gets
+                                // split of into the gradient below
+							    // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence();
+							    mfCurrentUnifiedTransparence = 0;
+
+							    // various content, create content-metafile
+							    GDIMetaFile aContentMetafile;
+                                const Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
+
+							    // restore mfCurrentUnifiedTransparence; it may have been used
+							    // while processing the sub-content in impDumpToMetaFile
+							    mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence;
+
+							    // create uniform VCL gradient for uniform transparency
+							    Gradient aVCLGradient;
+							    const sal_uInt8 nTransPercentVcl((sal_uInt8)basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0));
+							    const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl);
+
+							    aVCLGradient.SetStyle(GRADIENT_LINEAR);
+							    aVCLGradient.SetStartColor(aTransColor);
+							    aVCLGradient.SetEndColor(aTransColor);
+							    aVCLGradient.SetAngle(0);
+							    aVCLGradient.SetBorder(0);
+							    aVCLGradient.SetOfsX(0);
+							    aVCLGradient.SetOfsY(0);
+							    aVCLGradient.SetStartIntensity(100);
+							    aVCLGradient.SetEndIntensity(100);
+							    aVCLGradient.SetSteps(2);
+    							
+							    // render it to VCL
+							    mpOutputDevice->DrawTransparent(
+								    aContentMetafile, aPrimitiveRectangle.TopLeft(), 
+								    aPrimitiveRectangle.GetSize(), aVCLGradient);
+						    }
+					    }
+                    }
+
+					break;
+				}
+				case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
+				{

[... 211 lines stripped ...]


Mime
View raw message