[Libreoffice-commits] core.git: drawinglayer/source solenv/clang-format

Tomaž Vajngerl (via logerrit) logerrit at kemper.freedesktop.org
Sat May 9 19:09:18 UTC 2020


 drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx | 3872 ++++++-------
 drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx |  309 -
 solenv/clang-format/blacklist                              |    2 
 3 files changed, 2113 insertions(+), 2070 deletions(-)

New commits:
commit 9e2a9f4151babc6cb22553798ee70f7f623924db
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Tue May 5 23:20:38 2020 +0200
Commit:     Tomaž Vajngerl <quikee at gmail.com>
CommitDate: Sat May 9 21:08:28 2020 +0200

    remove vclmetafileprocessor2d.{cxx,hxx} from clang-format blacklist
    
    Change-Id: I53f7660a22ed66ab7d50370d871f9d10d1bedc10
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/93825
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <quikee at gmail.com>

diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
index d853820abbdc..231bf8bc9259 100644
--- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
@@ -76,2215 +76,2241 @@ using namespace com::sun::star;
 // To be on the safe side with the old tools polygon, use slightly less than
 // the theoretical maximum (bad experiences with tools polygon)
 
-#define MAX_POLYGON_POINT_COUNT_METAFILE    (0x0000fff0)
+#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)
+// #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 nCount(rBasePolygon.count());
+        const sal_uInt32 nHalfCount((nCount - 1) >> 1);
 
-        if(nCount)
-        {
-            const sal_uInt32 nHalfCount((nCount - 1) >> 1);
+        o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1);
+        o_aLeft.setClosed(false);
 
-            o_aLeft = basegfx::B2DPolygon(rBasePolygon, 0, nHalfCount + 1);
-            o_aLeft.setClosed(false);
+        o_aRight = basegfx::B2DPolygon(rBasePolygon, nHalfCount, nCount - nHalfCount);
+        o_aRight.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.isClosed())
+            if (rBasePolygon.areControlPointsUsed())
             {
-                o_aRight.append(rBasePolygon.getB2DPoint(0));
-
-                if(rBasePolygon.areControlPointsUsed())
-                {
-                    o_aRight.setControlPoints(
-                        o_aRight.count() - 1,
-                        rBasePolygon.getPrevControlPoint(0),
-                        rBasePolygon.getNextControlPoint(0));
-                }
+                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
-    void fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon)
+    else
     {
-        const sal_uInt32 nPolyCount(rPolyPolygon.count());
+        o_aLeft.clear();
+        o_aRight.clear();
+    }
+}
 
-        if(!nPolyCount)
-            return;
+// #112245# helper to evtl. split filled polygons to maximum metafile point count
+void fillPolyPolygonNeededToBeSplit(basegfx::B2DPolyPolygon& rPolyPolygon)
+{
+    const sal_uInt32 nPolyCount(rPolyPolygon.count());
 
-        basegfx::B2DPolyPolygon aSplitted;
+    if (!nPolyCount)
+        return;
 
-        for(sal_uInt32 a(0); a < nPolyCount; a++)
+    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) - 1);
+        }
+        else
         {
-            const basegfx::B2DPolygon& aCandidate(rPolyPolygon.getB2DPolygon(a));
-            const sal_uInt32 nPointCount(aCandidate.count());
-            bool bNeedToSplit(false);
+            // compare with the maximum for simple point polygons
+            bNeedToSplit = nPointCount > (MAX_POLYGON_POINT_COUNT_METAFILE - 1);
+        }
 
-            if(aCandidate.areControlPointsUsed())
-            {
-                // compare with the maximum for bezier curved polygons
-                bNeedToSplit = nPointCount > ((MAX_POLYGON_POINT_COUNT_METAFILE / 3L) - 1);
-            }
-            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(bNeedToSplit)
+            if (aRange.getWidth() > aRange.getHeight())
             {
-                // 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::utils::clipPolygonOnParallelAxis(
-                            aCandidate,
-                            false,
-                            true,
-                            aCenter.getX(),
-                            false));
-                    const basegfx::B2DPolyPolygon aRight(
-                        basegfx::utils::clipPolygonOnParallelAxis(
-                            aCandidate,
-                            false,
-                            false,
-                            aCenter.getX(),
-                            false));
-
-                    aSplitted.append(aLeft);
-                    aSplitted.append(aRight);
-                }
-                else
-                {
-                    // clip in top and bottom
-                    const basegfx::B2DPolyPolygon aTop(
-                        basegfx::utils::clipPolygonOnParallelAxis(
-                            aCandidate,
-                            true,
-                            true,
-                            aCenter.getY(),
-                            false));
-                    const basegfx::B2DPolyPolygon aBottom(
-                        basegfx::utils::clipPolygonOnParallelAxis(
-                            aCandidate,
-                            true,
-                            false,
-                            aCenter.getY(),
-                            false));
-
-                    aSplitted.append(aTop);
-                    aSplitted.append(aBottom);
-                }
+                // clip in left and right
+                const basegfx::B2DPolyPolygon aLeft(basegfx::utils::clipPolygonOnParallelAxis(
+                    aCandidate, false, true, aCenter.getX(), false));
+                const basegfx::B2DPolyPolygon aRight(basegfx::utils::clipPolygonOnParallelAxis(
+                    aCandidate, false, false, aCenter.getX(), false));
+
+                aSplitted.append(aLeft);
+                aSplitted.append(aRight);
             }
             else
             {
-                aSplitted.append(aCandidate);
+                // clip in top and bottom
+                const basegfx::B2DPolyPolygon aTop(basegfx::utils::clipPolygonOnParallelAxis(
+                    aCandidate, true, true, aCenter.getY(), false));
+                const basegfx::B2DPolyPolygon aBottom(basegfx::utils::clipPolygonOnParallelAxis(
+                    aCandidate, true, false, aCenter.getY(), false));
+
+                aSplitted.append(aTop);
+                aSplitted.append(aBottom);
             }
         }
-
-        if(aSplitted.count() != nPolyCount)
+        else
         {
-            rPolyPolygon = aSplitted;
+            aSplitted.append(aCandidate);
         }
     }
 
-    /** Filter input polypolygon for effectively empty sub-fills
+    if (aSplitted.count() != nPolyCount)
+    {
+        rPolyPolygon = aSplitted;
+    }
+}
+
+/** Filter input polypolygon for effectively empty sub-fills
 
-        Needed to fix fdo#37559
+    Needed to fix fdo#37559
 
-        @param rPoly
-        tools::PolyPolygon to filter
+    @param rPoly
+    tools::PolyPolygon to filter
 
-        @return converted tools PolyPolygon, w/o one-point fills
-     */
-    ::tools::PolyPolygon getFillPolyPolygon( const ::basegfx::B2DPolyPolygon& rPoly )
+    @return converted tools PolyPolygon, w/o one-point fills
+ */
+tools::PolyPolygon getFillPolyPolygon(const ::basegfx::B2DPolyPolygon& rPoly)
+{
+    // filter input rPoly
+    basegfx::B2DPolyPolygon aPoly;
+    sal_uInt32 nCount(rPoly.count());
+    for (sal_uInt32 i = 0; i < nCount; ++i)
     {
-        // filter input rPoly
-        basegfx::B2DPolyPolygon aPoly;
-        sal_uInt32 nCount(rPoly.count());
-        for( sal_uInt32 i=0; i<nCount; ++i )
-        {
-            const basegfx::B2DPolygon& aCandidate(rPoly.getB2DPolygon(i));
-            if( !aCandidate.isClosed() || aCandidate.count() > 1 )
-                aPoly.append(aCandidate);
-        }
-        return ::tools::PolyPolygon(aPoly);
+        const basegfx::B2DPolygon& aCandidate(rPoly.getB2DPolygon(i));
+        if (!aCandidate.isClosed() || aCandidate.count() > 1)
+            aPoly.append(aCandidate);
     }
+    return tools::PolyPolygon(aPoly);
+}
 
 } // end of anonymous namespace
 
 namespace drawinglayer::processor2d
 {
-        ::tools::Rectangle VclMetafileProcessor2D::impDumpToMetaFile(
-            const primitive2d::Primitive2DContainer& rContent,
-            GDIMetaFile& o_rContentMetafile)
-        {
-            // Prepare VDev, MetaFile and connections
-            OutputDevice* pLastOutputDevice = mpOutputDevice;
-            GDIMetaFile* pLastMetafile = mpMetaFile;
-            basegfx::B2DRange aPrimitiveRange(rContent.getB2DRange(getViewInformation2D()));
-
-            // transform primitive range with current transformation (e.g shadow offset)
-            aPrimitiveRange.transform(maCurrentTransformation);
-
-            const ::tools::Rectangle aPrimitiveRectangle(
-                basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()),
-                basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY()));
-            ScopedVclPtrInstance< VirtualDevice > aContentVDev;
-            MapMode aNewMapMode(pLastOutputDevice->GetMapMode());
-
-            mpOutputDevice = aContentVDev.get();
-            mpMetaFile = &o_rContentMetafile;
-            aContentVDev->EnableOutput(false);
-            aContentVDev->SetMapMode(pLastOutputDevice->GetMapMode());
-            o_rContentMetafile.Record(aContentVDev.get());
-            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) const
-        {
-            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())));
-            }
+tools::Rectangle
+VclMetafileProcessor2D::impDumpToMetaFile(const primitive2d::Primitive2DContainer& rContent,
+                                          GDIMetaFile& o_rContentMetafile)
+{
+    // Prepare VDev, MetaFile and connections
+    OutputDevice* pLastOutputDevice = mpOutputDevice;
+    GDIMetaFile* pLastMetafile = mpMetaFile;
+    basegfx::B2DRange aPrimitiveRange(rContent.getB2DRange(getViewInformation2D()));
+
+    // transform primitive range with current transformation (e.g shadow offset)
+    aPrimitiveRange.transform(maCurrentTransformation);
+
+    const tools::Rectangle aPrimitiveRectangle(
+        basegfx::fround(aPrimitiveRange.getMinX()), basegfx::fround(aPrimitiveRange.getMinY()),
+        basegfx::fround(aPrimitiveRange.getMaxX()), basegfx::fround(aPrimitiveRange.getMaxY()));
+    ScopedVclPtrInstance<VirtualDevice> aContentVDev;
+    MapMode aNewMapMode(pLastOutputDevice->GetMapMode());
+
+    mpOutputDevice = aContentVDev.get();
+    mpMetaFile = &o_rContentMetafile;
+    aContentVDev->EnableOutput(false);
+    aContentVDev->SetMapMode(pLastOutputDevice->GetMapMode());
+    o_rContentMetafile.Record(aContentVDev.get());
+    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) const
+{
+    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());
+    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);
+    // 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(GradientStyle::Linear);
-                    break;
-                }
-                case attribute::GradientStyle::Axial :
-                {
-                    o_rVCLGradient.SetStyle(GradientStyle::Axial);
-                    break;
-                }
-                case attribute::GradientStyle::Radial :
-                {
-                    o_rVCLGradient.SetStyle(GradientStyle::Radial);
-                    break;
-                }
-                case attribute::GradientStyle::Elliptical :
-                {
-                    o_rVCLGradient.SetStyle(GradientStyle::Elliptical);
-                    break;
-                }
-                case attribute::GradientStyle::Square :
-                {
-                    o_rVCLGradient.SetStyle(GradientStyle::Square);
-                    break;
-                }
-                case attribute::GradientStyle::Rect :
-                {
-                    o_rVCLGradient.SetStyle(GradientStyle::Rect);
-                    break;
-                }
-            }
+    switch (rFiGrAtt.getStyle())
+    {
+        default: // attribute::GradientStyle::Linear :
+        {
+            o_rVCLGradient.SetStyle(GradientStyle::Linear);
+            break;
         }
-
-        void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill const * pSvtGraphicFill)
+        case attribute::GradientStyle::Axial:
         {
-            if(pSvtGraphicFill && !mnSvtGraphicFillCount)
-            {
-                SvMemoryStream aMemStm;
-
-                WriteSvtGraphicFill( aMemStm, *pSvtGraphicFill );
-                mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.TellEnd()));
-                mnSvtGraphicFillCount++;
-            }
+            o_rVCLGradient.SetStyle(GradientStyle::Axial);
+            break;
         }
-
-        void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill const * pSvtGraphicFill)
+        case attribute::GradientStyle::Radial:
         {
-            if(pSvtGraphicFill && mnSvtGraphicFillCount)
-            {
-                mnSvtGraphicFillCount--;
-                mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END"));
-            }
+            o_rVCLGradient.SetStyle(GradientStyle::Radial);
+            break;
         }
-
-        double VclMetafileProcessor2D::getTransformedLineWidth( double fWidth ) const
+        case attribute::GradientStyle::Elliptical:
         {
-            // #i113922# the LineWidth is duplicated in the MetaPolylineAction,
-            // and also inside the SvtGraphicStroke and needs transforming into
-            // the same space as its coordinates here cf. fdo#61789
-            // This is a partial fix. When an object transformation is used which
-            // e.g. contains a scaleX != scaleY, an unproportional scaling will happen.
-            const basegfx::B2DVector aDiscreteUnit( maCurrentTransformation * basegfx::B2DVector( fWidth, 0.0 ) );
-
-            return aDiscreteUnit.getLength();
+            o_rVCLGradient.SetStyle(GradientStyle::Elliptical);
+            break;
         }
-
-        std::unique_ptr<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)
+        case attribute::GradientStyle::Square:
+        {
+            o_rVCLGradient.SetStyle(GradientStyle::Square);
+            break;
+        }
+        case attribute::GradientStyle::Rect:
         {
-            std::unique_ptr<SvtGraphicStroke> pRetval;
+            o_rVCLGradient.SetStyle(GradientStyle::Rect);
+            break;
+        }
+    }
+}
 
-            if(rB2DPolygon.count() && !mnSvtGraphicStrokeCount)
-            {
-                basegfx::B2DPolygon aLocalPolygon(rB2DPolygon);
-                basegfx::BColor aStrokeColor;
-                basegfx::B2DPolyPolygon aStartArrow;
-                basegfx::B2DPolyPolygon aEndArrow;
+void VclMetafileProcessor2D::impStartSvtGraphicFill(SvtGraphicFill const* pSvtGraphicFill)
+{
+    if (pSvtGraphicFill && !mnSvtGraphicFillCount)
+    {
+        SvMemoryStream aMemStm;
 
-                if(pColor)
-                {
-                    aStrokeColor = *pColor;
-                }
-                else if(pLineAttribute)
-                {
-                    aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor());
-                }
+        WriteSvtGraphicFill(aMemStm, *pSvtGraphicFill);
+        mpMetaFile->AddAction(new MetaCommentAction(
+            "XPATHFILL_SEQ_BEGIN", 0, static_cast<const sal_uInt8*>(aMemStm.GetData()),
+            aMemStm.TellEnd()));
+        mnSvtGraphicFillCount++;
+    }
+}
 
-                // It IS needed to record the stroke color at all in the metafile,
-                // SvtGraphicStroke has NO entry for stroke color(!)
-                mpOutputDevice->SetLineColor(Color(aStrokeColor));
+void VclMetafileProcessor2D::impEndSvtGraphicFill(SvtGraphicFill const* pSvtGraphicFill)
+{
+    if (pSvtGraphicFill && mnSvtGraphicFillCount)
+    {
+        mnSvtGraphicFillCount--;
+        mpMetaFile->AddAction(new MetaCommentAction("XPATHFILL_SEQ_END"));
+    }
+}
 
-                if(!aLocalPolygon.isClosed())
-                {
-                    double fPolyLength(0.0);
-                    double fStart(0.0);
-                    double fEnd(0.0);
-
-                    if(pStart && pStart->isActive())
-                    {
-                        fPolyLength = basegfx::utils::getLength(aLocalPolygon);
-
-                        aStartArrow = basegfx::utils::createAreaGeometryForLineStartEnd(
-                            aLocalPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(),
-                            fPolyLength, pStart->isCentered() ? 0.5 : 0.0, &fStart);
-                    }
-
-                    if(pEnd && pEnd->isActive())
-                    {
-                        if(basegfx::fTools::equalZero(fPolyLength))
-                        {
-                            fPolyLength = basegfx::utils::getLength(aLocalPolygon);
-                        }
-
-                        aEndArrow = basegfx::utils::createAreaGeometryForLineStartEnd(
-                            aLocalPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(),
-                            fPolyLength, pEnd->isCentered() ? 0.5 : 0.0, &fEnd);
-                    }
-
-                    if(0.0 != fStart || 0.0 != fEnd)
-                    {
-                        // build new poly, consume something from old poly
-                        aLocalPolygon = basegfx::utils::getSnippetAbsolute(aLocalPolygon, fStart, fPolyLength - fEnd, fPolyLength);
-                    }
-                }
+double VclMetafileProcessor2D::getTransformedLineWidth(double fWidth) const
+{
+    // #i113922# the LineWidth is duplicated in the MetaPolylineAction,
+    // and also inside the SvtGraphicStroke and needs transforming into
+    // the same space as its coordinates here cf. fdo#61789
+    // This is a partial fix. When an object transformation is used which
+    // e.g. contains a scaleX != scaleY, an unproportional scaling will happen.
+    const basegfx::B2DVector aDiscreteUnit(maCurrentTransformation
+                                           * basegfx::B2DVector(fWidth, 0.0));
+
+    return aDiscreteUnit.getLength();
+}
+
+std::unique_ptr<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)
+{
+    std::unique_ptr<SvtGraphicStroke> pRetval;
 
-                SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone);
-                SvtGraphicStroke::CapType eCap(SvtGraphicStroke::capButt);
-                double fLineWidth(0.0);
-                double fMiterLength(0.0);
-                SvtGraphicStroke::DashArray aDashArray;
+    if (rB2DPolygon.count() && !mnSvtGraphicStrokeCount)
+    {
+        basegfx::B2DPolygon aLocalPolygon(rB2DPolygon);
+        basegfx::BColor aStrokeColor;
+        basegfx::B2DPolyPolygon aStartArrow;
+        basegfx::B2DPolyPolygon aEndArrow;
 
-                if(pLineAttribute)
-                {
-                    fLineWidth = fMiterLength = getTransformedLineWidth( pLineAttribute->getWidth() );
-
-                    // get Join
-                    switch(pLineAttribute->getLineJoin())
-                    {
-                        case basegfx::B2DLineJoin::NONE :
-                        {
-                            eJoin = SvtGraphicStroke::joinNone;
-                            break;
-                        }
-                        case basegfx::B2DLineJoin::Bevel :
-                        {
-                            eJoin = SvtGraphicStroke::joinBevel;
-                            break;
-                        }
-                        case basegfx::B2DLineJoin::Miter :
-                        {
-                            eJoin = SvtGraphicStroke::joinMiter;
-                            // ATM 15 degrees is assumed
-                            fMiterLength /= rtl::math::sin(basegfx::deg2rad(15.0));
-                            break;
-                        }
-                        case basegfx::B2DLineJoin::Round :
-                        {
-                            eJoin = SvtGraphicStroke::joinRound;
-                            break;
-                        }
-                    }
-
-                    // get stroke
-                    switch(pLineAttribute->getLineCap())
-                    {
-                        default: /* css::drawing::LineCap_BUTT */
-                        {
-                            eCap = SvtGraphicStroke::capButt;
-                            break;
-                        }
-                        case css::drawing::LineCap_ROUND:
-                        {
-                            eCap = SvtGraphicStroke::capRound;
-                            break;
-                        }
-                        case css::drawing::LineCap_SQUARE:
-                        {
-                            eCap = SvtGraphicStroke::capSquare;
-                            break;
-                        }
-                    }
-                }
+        if (pColor)
+        {
+            aStrokeColor = *pColor;
+        }
+        else if (pLineAttribute)
+        {
+            aStrokeColor = maBColorModifierStack.getModifiedColor(pLineAttribute->getColor());
+        }
 
-                if(pStrokeAttribute)
-                {
-                    // copy dash array
-                    aDashArray = pStrokeAttribute->getDotDashArray();
-                }
+        // It IS needed to record the stroke color at all in the metafile,
+        // SvtGraphicStroke has NO entry for stroke color(!)
+        mpOutputDevice->SetLineColor(Color(aStrokeColor));
 
-                // #i101734# apply current object transformation to created geometry.
-                // This is a partial fix. When an 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
-                aLocalPolygon.transform(maCurrentTransformation);
-                aStartArrow.transform(maCurrentTransformation);
-                aEndArrow.transform(maCurrentTransformation);
-
-                pRetval.reset(new SvtGraphicStroke(
-                        ::tools::Polygon(aLocalPolygon),
-                        ::tools::PolyPolygon(aStartArrow),
-                        ::tools::PolyPolygon(aEndArrow),
-                        mfCurrentUnifiedTransparence,
-                        fLineWidth,
-                        eCap,
-                        eJoin,
-                        fMiterLength,
-                        aDashArray));
-            }
+        if (!aLocalPolygon.isClosed())
+        {
+            double fPolyLength(0.0);
+            double fStart(0.0);
+            double fEnd(0.0);
 
-            return pRetval;
-        }
+            if (pStart && pStart->isActive())
+            {
+                fPolyLength = basegfx::utils::getLength(aLocalPolygon);
 
-        void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke const * pSvtGraphicStroke)
-        {
-            if(pSvtGraphicStroke && !mnSvtGraphicStrokeCount)
+                aStartArrow = basegfx::utils::createAreaGeometryForLineStartEnd(
+                    aLocalPolygon, pStart->getB2DPolyPolygon(), true, pStart->getWidth(),
+                    fPolyLength, pStart->isCentered() ? 0.5 : 0.0, &fStart);
+            }
+
+            if (pEnd && pEnd->isActive())
             {
-                SvMemoryStream aMemStm;
+                if (basegfx::fTools::equalZero(fPolyLength))
+                {
+                    fPolyLength = basegfx::utils::getLength(aLocalPolygon);
+                }
 
-                WriteSvtGraphicStroke( aMemStm, *pSvtGraphicStroke );
-                mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_BEGIN", 0, static_cast< const sal_uInt8* >(aMemStm.GetData()), aMemStm.TellEnd()));
-                mnSvtGraphicStrokeCount++;
+                aEndArrow = basegfx::utils::createAreaGeometryForLineStartEnd(
+                    aLocalPolygon, pEnd->getB2DPolyPolygon(), false, pEnd->getWidth(), fPolyLength,
+                    pEnd->isCentered() ? 0.5 : 0.0, &fEnd);
             }
-        }
 
-        void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke const * pSvtGraphicStroke)
-        {
-            if(pSvtGraphicStroke && mnSvtGraphicStrokeCount)
+            if (0.0 != fStart || 0.0 != fEnd)
             {
-                mnSvtGraphicStrokeCount--;
-                mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END"));
+                // build new poly, consume something from old poly
+                aLocalPolygon = basegfx::utils::getSnippetAbsolute(aLocalPolygon, fStart,
+                                                                   fPolyLength - fEnd, fPolyLength);
             }
         }
 
-        void VclMetafileProcessor2D::popStructureElement(vcl::PDFWriter::StructElement eElem)
-        {
-           if (!maListElements.empty() && maListElements.top() == eElem)
-           {
-               maListElements.pop();
-               mpPDFExtOutDevData->EndStructureElement();
-           }
-        }
+        SvtGraphicStroke::JoinType eJoin(SvtGraphicStroke::joinNone);
+        SvtGraphicStroke::CapType eCap(SvtGraphicStroke::capButt);
+        double fLineWidth(0.0);
+        double fMiterLength(0.0);
+        SvtGraphicStroke::DashArray aDashArray;
 
-        void VclMetafileProcessor2D::popListItem()
+        if (pLineAttribute)
         {
-            popStructureElement(vcl::PDFWriter::LIBody);
-            popStructureElement(vcl::PDFWriter::ListItem);
-        }
+            fLineWidth = fMiterLength = getTransformedLineWidth(pLineAttribute->getWidth());
 
-        void VclMetafileProcessor2D::popList()
-        {
-            popListItem();
-            popStructureElement(vcl::PDFWriter::List);
-        }
-
-        // init static break iterator
-        uno::Reference< css::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())),
-            mnCurrentOutlineLevel(-1),
-            mbInListItem(false),
-            mbBulletPresent(false)
-        {
-            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 its gradient objects.
-            Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
-            map it back to the corresponding tools 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_POLYPOLYGONGRAPHICPRIMITIVE2D,
-                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 tools::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 a 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 an 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, recursively 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
-            Animation 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 explicitly 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 than the name
-              may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself,
-              the lowest movement plane 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())
+            // get Join
+            switch (pLineAttribute->getLineJoin())
             {
-                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 :
-                {
-                    processGraphicPrimitive2D(static_cast<const primitive2d::GraphicPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
-                {
-                    processControlPrimitive2D(static_cast<const primitive2d::ControlPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D :
-                {
-                    processTextHierarchyFieldPrimitive2D(static_cast<const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D :
-                {
-                    processTextHierarchyLinePrimitive2D(static_cast<const primitive2d::TextHierarchyLinePrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D :
-                {
-                    processTextHierarchyBulletPrimitive2D(static_cast<const primitive2d::TextHierarchyBulletPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D :
-                {
-                    processTextHierarchyParagraphPrimitive2D(static_cast<const primitive2d::TextHierarchyParagraphPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D :
-                {
-                    processTextHierarchyBlockPrimitive2D(static_cast<const primitive2d::TextHierarchyBlockPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
-                case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
-                {
-                    // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate
-                    processTextSimplePortionPrimitive2D(static_cast<const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
-                {
-                    processPolygonHairlinePrimitive2D(static_cast<const primitive2d::PolygonHairlinePrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D :
-                {
-                    processPolygonStrokePrimitive2D(static_cast<const primitive2d::PolygonStrokePrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D :
-                {
-                    processPolygonStrokeArrowPrimitive2D(static_cast<const primitive2d::PolygonStrokeArrowPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
-                {
-                    // direct draw of transformed BitmapEx primitive; use default processing, but without
-                    // former testing if graphic content is inside discrete local viewport; this is not
-                    // setup for metafile targets (metafile renderer tries to render in logic coordinates,
-                    // the mapping is kept to the OutputDevice for better Metafile recording)
-                    RenderBitmapPrimitive2D(static_cast< const primitive2d::BitmapPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D :
-                {
-                    processPolyPolygonGraphicPrimitive2D(static_cast<const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D :
-                {
-                    processPolyPolygonHatchPrimitive2D(static_cast<const primitive2d::PolyPolygonHatchPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
-                {
-                    processPolyPolygonGradientPrimitive2D(static_cast<const primitive2d::PolyPolygonGradientPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
-                {
-                    processPolyPolygonColorPrimitive2D(static_cast<const primitive2d::PolyPolygonColorPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
-                {
-                    processMaskPrimitive2D(static_cast<const primitive2d::MaskPrimitive2D&>(rCandidate));
-                    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_UNIFIEDTRANSPARENCEPRIMITIVE2D :
-                {
-                    processUnifiedTransparencePrimitive2D(static_cast<const primitive2d::UnifiedTransparencePrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
-                {
-                    processTransparencePrimitive2D(static_cast<const primitive2d::TransparencePrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
-                {
-                    // use default transform group pocessing
-                    RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
+                case basegfx::B2DLineJoin::NONE:
                 {
-                    // new XDrawPage for ViewInformation2D
-                    RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate));
+                    eJoin = SvtGraphicStroke::joinNone;
                     break;
                 }
-                case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
+                case basegfx::B2DLineJoin::Bevel:
                 {
-                    // use default marker array pocessing
-                    RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate));
+                    eJoin = SvtGraphicStroke::joinBevel;
                     break;
                 }
-                case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
+                case basegfx::B2DLineJoin::Miter:
                 {
-                    // use default point array pocessing
-                    RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
+                    eJoin = SvtGraphicStroke::joinMiter;
+                    // ATM 15 degrees is assumed
+                    fMiterLength /= rtl::math::sin(basegfx::deg2rad(15.0));
                     break;
                 }
-                case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D :
+                case basegfx::B2DLineJoin::Round:
                 {
-                    processStructureTagPrimitive2D(static_cast<const primitive2d::StructureTagPrimitive2D&>(rCandidate));
+                    eJoin = SvtGraphicStroke::joinRound;
                     break;
                 }
-                case PRIMITIVE2D_ID_EPSPRIMITIVE2D :
+            }
+
+            // get stroke
+            switch (pLineAttribute->getLineCap())
+            {
+                default: /* css::drawing::LineCap_BUTT */
                 {
-                    RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate));
+                    eCap = SvtGraphicStroke::capButt;
                     break;
                 }
-                case PRIMITIVE2D_ID_OBJECTINFOPRIMITIVE2D :
+                case css::drawing::LineCap_ROUND:
                 {
-                    RenderObjectInfoPrimitive2D(static_cast< const primitive2d::ObjectInfoPrimitive2D& >(rCandidate));
+                    eCap = SvtGraphicStroke::capRound;
                     break;
                 }
-                default :
+                case css::drawing::LineCap_SQUARE:
                 {
-                    // process recursively
-                    process(rCandidate);
+                    eCap = SvtGraphicStroke::capSquare;
                     break;
                 }
             }
         }
 
-        void VclMetafileProcessor2D::processGraphicPrimitive2D(const primitive2d::GraphicPrimitive2D& rGraphicPrimitive)
+        if (pStrokeAttribute)
         {
-            bool bUsingPDFExtOutDevData(false);
-            basegfx::B2DVector aTranslate, aScale;
-            static bool bSuppressPDFExtOutDevDataSupport(false); // loplugin:constvars:ignore
+            // copy dash array
+            aDashArray = pStrokeAttribute->getDotDashArray();
+        }
 
-            if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
-            {
-                // emulate data handling from UnoControlPDFExportContact, original see
-                // svtools/source/graphic/grfmgr.cxx
-                const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
+        // #i101734# apply current object transformation to created geometry.
+        // This is a partial fix. When an 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
+        aLocalPolygon.transform(maCurrentTransformation);
+        aStartArrow.transform(maCurrentTransformation);
+        aEndArrow.transform(maCurrentTransformation);
+
+        pRetval.reset(
+            new SvtGraphicStroke(tools::Polygon(aLocalPolygon), tools::PolyPolygon(aStartArrow),
+                                 tools::PolyPolygon(aEndArrow), mfCurrentUnifiedTransparence,
+                                 fLineWidth, eCap, eJoin, fMiterLength, aDashArray));
+    }
 
-                if(rGraphic.IsGfxLink())
-                {
-                    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();
-                        }
-                    }
-                }
-            }
+    return pRetval;
+}
 
-            // process recursively and add MetaFile comment
-            process(rGraphicPrimitive);
+void VclMetafileProcessor2D::impStartSvtGraphicStroke(SvtGraphicStroke const* pSvtGraphicStroke)
+{
+    if (pSvtGraphicStroke && !mnSvtGraphicStrokeCount)
+    {
+        SvMemoryStream aMemStm;
 
-            if(!bUsingPDFExtOutDevData)
-                return;
+        WriteSvtGraphicStroke(aMemStm, *pSvtGraphicStroke);
+        mpMetaFile->AddAction(new MetaCommentAction(
+            "XPATHSTROKE_SEQ_BEGIN", 0, static_cast<const sal_uInt8*>(aMemStm.GetData()),
+            aMemStm.TellEnd()));
+        mnSvtGraphicStrokeCount++;
+    }
+}
 
-            // 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 ::tools::Rectangle aCurrentRect(
-                sal_Int32(floor(aCurrentRange.getMinX())), sal_Int32(floor(aCurrentRange.getMinY())),
-                sal_Int32(ceil(aCurrentRange.getMaxX())), sal_Int32(ceil(aCurrentRange.getMaxY())));
+void VclMetafileProcessor2D::impEndSvtGraphicStroke(SvtGraphicStroke const* pSvtGraphicStroke)
+{
+    if (pSvtGraphicStroke && mnSvtGraphicStrokeCount)
+    {
+        mnSvtGraphicStrokeCount--;
+        mpMetaFile->AddAction(new MetaCommentAction("XPATHSTROKE_SEQ_END"));
+    }
+}
+
+void VclMetafileProcessor2D::popStructureElement(vcl::PDFWriter::StructElement eElem)
+{
+    if (!maListElements.empty() && maListElements.top() == eElem)
+    {
+        maListElements.pop();
+        mpPDFExtOutDevData->EndStructureElement();
+    }
+}
+
+void VclMetafileProcessor2D::popListItem()
+{
+    popStructureElement(vcl::PDFWriter::LIBody);
+    popStructureElement(vcl::PDFWriter::ListItem);
+}
+
+void VclMetafileProcessor2D::popList()
+{
+    popListItem();
+    popStructureElement(vcl::PDFWriter::List);
+}
+
+// init static break iterator
+uno::Reference<css::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()))
+    , mnCurrentOutlineLevel(-1)
+    , mbInListItem(false)
+    , mbBulletPresent(false)
+{
+    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 its gradient objects.
+    Best (and safest) way to support it here is to use PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D,
+    map it back to the corresponding tools 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_POLYPOLYGONGRAPHICPRIMITIVE2D,
+        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 tools::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 a 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 an 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, recursively 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
+    Animation 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 explicitly 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 than the name
+      may imply, it is defined in toolkit (!). Since toolkit is linked against VCL itself,
+      the lowest movement plane 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:
+        {
+            processGraphicPrimitive2D(
+                static_cast<const primitive2d::GraphicPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D:
+        {
+            processControlPrimitive2D(
+                static_cast<const primitive2d::ControlPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D:
+        {
+            processTextHierarchyFieldPrimitive2D(
+                static_cast<const primitive2d::TextHierarchyFieldPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D:
+        {
+            processTextHierarchyLinePrimitive2D(
+                static_cast<const primitive2d::TextHierarchyLinePrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D:
+        {
+            processTextHierarchyBulletPrimitive2D(
+                static_cast<const primitive2d::TextHierarchyBulletPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D:
+        {
+            processTextHierarchyParagraphPrimitive2D(
+                static_cast<const primitive2d::TextHierarchyParagraphPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D:
+        {
+            processTextHierarchyBlockPrimitive2D(
+                static_cast<const primitive2d::TextHierarchyBlockPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D:
+        case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D:
+        {
+            // for supporting TEXT_ MetaFile actions there is more to do here; get the candidate
+            processTextSimplePortionPrimitive2D(
+                static_cast<const primitive2d::TextSimplePortionPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D:
+        {
+            processPolygonHairlinePrimitive2D(
+                static_cast<const primitive2d::PolygonHairlinePrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
+        {
+            processPolygonStrokePrimitive2D(
+                static_cast<const primitive2d::PolygonStrokePrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D:
+        {
+            processPolygonStrokeArrowPrimitive2D(
+                static_cast<const primitive2d::PolygonStrokeArrowPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D:
+        {
+            // direct draw of transformed BitmapEx primitive; use default processing, but without
+            // former testing if graphic content is inside discrete local viewport; this is not
+            // setup for metafile targets (metafile renderer tries to render in logic coordinates,
+            // the mapping is kept to the OutputDevice for better Metafile recording)
+            RenderBitmapPrimitive2D(static_cast<const primitive2d::BitmapPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D:
+        {
+            processPolyPolygonGraphicPrimitive2D(
+                static_cast<const primitive2d::PolyPolygonGraphicPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D:
+        {
+            processPolyPolygonHatchPrimitive2D(
+                static_cast<const primitive2d::PolyPolygonHatchPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D:
+        {
+            processPolyPolygonGradientPrimitive2D(
+                static_cast<const primitive2d::PolyPolygonGradientPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D:
+        {
+            processPolyPolygonColorPrimitive2D(
+                static_cast<const primitive2d::PolyPolygonColorPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_MASKPRIMITIVE2D:
+        {
+            processMaskPrimitive2D(static_cast<const primitive2d::MaskPrimitive2D&>(rCandidate));
+            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_UNIFIEDTRANSPARENCEPRIMITIVE2D:
+        {
+            processUnifiedTransparencePrimitive2D(
+                static_cast<const primitive2d::UnifiedTransparencePrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D:
+        {
+            processTransparencePrimitive2D(
+                static_cast<const primitive2d::TransparencePrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D:
+        {
+            // use default transform group pocessing
+            RenderTransformPrimitive2D(
+                static_cast<const primitive2d::TransformPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D:
+        {
+            // new XDrawPage for ViewInformation2D
+            RenderPagePreviewPrimitive2D(
+                static_cast<const primitive2d::PagePreviewPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D:
+        {
+            // use default marker array pocessing
+            RenderMarkerArrayPrimitive2D(
+                static_cast<const primitive2d::MarkerArrayPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D:
+        {
+            // use default point array pocessing
+            RenderPointArrayPrimitive2D(
+                static_cast<const primitive2d::PointArrayPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D:
+        {
+            processStructureTagPrimitive2D(
+                static_cast<const primitive2d::StructureTagPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_EPSPRIMITIVE2D:
+        {
+            RenderEpsPrimitive2D(static_cast<const primitive2d::EpsPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_OBJECTINFOPRIMITIVE2D:
+        {
+            RenderObjectInfoPrimitive2D(
+                static_cast<const primitive2d::ObjectInfoPrimitive2D&>(rCandidate));
+            break;
+        }
+        default:
+        {
+            // process recursively
+            process(rCandidate);
+            break;
+        }
+    }
+}
+
+void VclMetafileProcessor2D::processGraphicPrimitive2D(
+    const primitive2d::GraphicPrimitive2D& rGraphicPrimitive)
+{
+    bool bUsingPDFExtOutDevData(false);
+    basegfx::B2DVector aTranslate, aScale;
+    static bool bSuppressPDFExtOutDevDataSupport(false); // loplugin:constvars:ignore
+
+    if (mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
+    {
+        // emulate data handling from UnoControlPDFExportContact, original see
+        // svtools/source/graphic/grfmgr.cxx
+        const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
+
+        if (rGraphic.IsGfxLink())
+        {
             const GraphicAttr& rAttr = rGraphicPrimitive.getGraphicAttr();
-            // fdo#72530 don't pass empty Rectangle to EndGroup
-            ::tools::Rectangle aCropRect(aCurrentRect);
 
-            if(rAttr.IsCropped())
+            if (!rAttr.IsSpecialDrawMode() && !rAttr.IsAdjusted())
             {
-                // 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 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))
                 {
-                    const MapMode aMapMode100thmm(MapUnit::Map100thMM);
-                    const Size aBitmapSize(OutputDevice::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;
-                    }
+                    bUsingPDFExtOutDevData = true;
+                    mpPDFExtOutDevData->BeginGroup();
                 }
+            }
+        }
+    }
 
-                // 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));
+    // process recursively and add MetaFile comment
+    process(rGraphicPrimitive);
+
+    if (!bUsingPDFExtOutDevData)
+        return;
+
+    // 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 tools::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();
+    // fdo#72530 don't pass empty Rectangle to EndGroup
+    tools::Rectangle aCropRect(aCurrentRect);
+
+    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);
 
-                aCropRect = ::tools::Rectangle(
-                    sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())),
-                    sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY())));
+        {
+            const MapMode aMapMode100thmm(MapUnit::Map100thMM);
+            const Size aBitmapSize(OutputDevice::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;
             }
 
-            // Create image alternative description from ObjectInfoPrimitive2D info
-            // for PDF export
-            if(mpPDFExtOutDevData->GetIsExportTaggedPDF() && nullptr != getObjectInfoPrimitive2D())
+            if (!basegfx::fTools::equalZero(fDivY))
             {
-                OUString aAlternateDescription;
+                fFactorY = aScale.getY() / fDivY;
+            }
+        }
 
-                if(!getObjectInfoPrimitive2D()->getTitle().isEmpty())
-                {
-                    aAlternateDescription += getObjectInfoPrimitive2D()->getTitle();
-                }
+        // 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 = tools::Rectangle(
+            sal_Int32(floor(aCropRange.getMinX())), sal_Int32(floor(aCropRange.getMinY())),
+            sal_Int32(ceil(aCropRange.getMaxX())), sal_Int32(ceil(aCropRange.getMaxY())));
+    }
 
-                if(!getObjectInfoPrimitive2D()->getDesc().isEmpty())
-                {
-                    if(!aAlternateDescription.isEmpty())
-                    {
-                        aAlternateDescription += " - ";
-                    }
+    // Create image alternative description from ObjectInfoPrimitive2D info
+    // for PDF export
+    if (mpPDFExtOutDevData->GetIsExportTaggedPDF() && nullptr != getObjectInfoPrimitive2D())
+    {
+        OUString aAlternateDescription;
 
-                    aAlternateDescription += getObjectInfoPrimitive2D()->getDesc();
-                }
+        if (!getObjectInfoPrimitive2D()->getTitle().isEmpty())
+        {
+            aAlternateDescription += getObjectInfoPrimitive2D()->getTitle();
+        }
 
-                // Use SetAlternateText to set it. This will work as long as some
-                // structure is used (see PDFWriterImpl::setAlternateText and
-                // m_nCurrentStructElement - tagged PDF export works with this in
-                // Draw/Impress/Writer, but not in Calc due to too less structure...)
-                //Z maybe add structure to Calc PDF export, may need some BeginGroup/EndGroup stuff ..?
-                if(!aAlternateDescription.isEmpty())
-                {
-                    mpPDFExtOutDevData->SetAlternateText(aAlternateDescription);
-                }
+        if (!getObjectInfoPrimitive2D()->getDesc().isEmpty())
+        {
+            if (!aAlternateDescription.isEmpty())
+            {
+                aAlternateDescription += " - ";
             }
 
-            // #i123295# 3rd param is uncropped rect, 4th is cropped. The primitive has the cropped
-            // object transformation, thus aCurrentRect *is* the clip region while aCropRect is the expanded,
-            // uncropped region. Thus, correct order is aCropRect, aCurrentRect
-            mpPDFExtOutDevData->EndGroup(
-                rGraphicPrimitive.getGraphicObject().GetGraphic(),
-                rAttr.GetTransparency(),
-                aCropRect,
-                aCurrentRect);
+            aAlternateDescription += getObjectInfoPrimitive2D()->getDesc();
         }
 
-        void VclMetafileProcessor2D::processControlPrimitive2D(const primitive2d::ControlPrimitive2D& rControlPrimitive)
+        // Use SetAlternateText to set it. This will work as long as some
+        // structure is used (see PDFWriterImpl::setAlternateText and
+        // m_nCurrentStructElement - tagged PDF export works with this in
+        // Draw/Impress/Writer, but not in Calc due to too less structure...)
+        //Z maybe add structure to Calc PDF export, may need some BeginGroup/EndGroup stuff ..?
+        if (!aAlternateDescription.isEmpty())
         {
-            const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
-            bool bIsPrintableControl(false);
+            mpPDFExtOutDevData->SetAlternateText(aAlternateDescription);
+        }
+    }
 
-            // find out if control is printable
-            if(rXControl.is())
+    // #i123295# 3rd param is uncropped rect, 4th is cropped. The primitive has the cropped
+    // object transformation, thus aCurrentRect *is* the clip region while aCropRect is the expanded,
+    // uncropped region. Thus, correct order is aCropRect, aCurrentRect
+    mpPDFExtOutDevData->EndGroup(rGraphicPrimitive.getGraphicObject().GetGraphic(),
+                                 rAttr.GetTransparency(), aCropRect, aCurrentRect);
+}
+
+void VclMetafileProcessor2D::processControlPrimitive2D(
+    const primitive2d::ControlPrimitive2D& rControlPrimitive)
+{
+    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 OUString sPrintablePropertyName("Printable");
+
+            if (xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName))
             {
-                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 OUString sPrintablePropertyName("Printable");
-
-                    if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName))
-                    {
-                        OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl);
-                    }
-                }
-                catch(const uno::Exception&)
-                {
-                    TOOLS_WARN_EXCEPTION("drawinglayer", "VclMetafileProcessor2D: No access to printable flag of Control");
-                }
+                OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName)
+                           >>= bIsPrintableControl);
             }
+        }
+        catch (const uno::Exception&)
+        {
+            TOOLS_WARN_EXCEPTION("drawinglayer",
+                                 "VclMetafileProcessor2D: No access to printable flag of Control");
+        }
+    }
 
-            // PDF export and printing only for printable controls
-            if(!bIsPrintableControl)
-                return;
+    // PDF export and printing only for printable controls
+    if (!bIsPrintableControl)
+        return;
 
-            const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
-            bool bDoProcessRecursively(true);
+    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::unique_ptr< vcl::PDFWriter::AnyWidget > pPDFControl(
-                    ::toolkitform::describePDFControl( rXControl, *mpPDFExtOutDevData ) );
+    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::unique_ptr<vcl::PDFWriter::AnyWidget> pPDFControl(
+            ::toolkitform::describePDFControl(rXControl, *mpPDFExtOutDevData));
 
-                if (pPDFControl)
-                {
-                    // still need to fill in the location (is a class Rectangle)
-                    const basegfx::B2DRange aRangeLogic(rControlPrimitive.getB2DRange(getViewInformation2D()));
-                    const ::tools::Rectangle aRectLogic(
-                        static_cast<sal_Int32>(floor(aRangeLogic.getMinX())), static_cast<sal_Int32>(floor(aRangeLogic.getMinY())),
-                        static_cast<sal_Int32>(ceil(aRangeLogic.getMaxX())), static_cast<sal_Int32>(ceil(aRangeLogic.getMaxY())));
-                    pPDFControl->Location = aRectLogic;
-
-                    Size aFontSize(pPDFControl->TextFont.GetFontSize());
-                    aFontSize = OutputDevice::LogicToLogic(aFontSize, MapMode(MapUnit::MapPoint), mpOutputDevice->GetMapMode());
-                    pPDFControl->TextFont.SetFontSize(aFontSize);
-
-                    mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form);
-                    mpPDFExtOutDevData->CreateControl(*pPDFControl);
-                    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.
-                }
-            }
+        if (pPDFControl)
+        {
+            // still need to fill in the location (is a class Rectangle)
+            const basegfx::B2DRange aRangeLogic(
+                rControlPrimitive.getB2DRange(getViewInformation2D()));
+            const tools::Rectangle aRectLogic(static_cast<sal_Int32>(floor(aRangeLogic.getMinX())),
+                                              static_cast<sal_Int32>(floor(aRangeLogic.getMinY())),
+                                              static_cast<sal_Int32>(ceil(aRangeLogic.getMaxX())),
+                                              static_cast<sal_Int32>(ceil(aRangeLogic.getMaxY())));
+            pPDFControl->Location = aRectLogic;
+
+            Size aFontSize(pPDFControl->TextFont.GetFontSize());
+            aFontSize = OutputDevice::LogicToLogic(aFontSize, MapMode(MapUnit::MapPoint),
+                                                   mpOutputDevice->GetMapMode());
+            pPDFControl->TextFont.SetFontSize(aFontSize);
+
+            mpPDFExtOutDevData->BeginStructureElement(vcl::PDFWriter::Form);
+            mpPDFExtOutDevData->CreateControl(*pPDFControl);
+            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& )
-                {
-                    TOOLS_WARN_EXCEPTION("drawinglayer", "VclMetafileProcessor2D: Printing of Control failed");
-                }
-            }
+    // #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());
 
-            // process recursively if not done yet to export as decomposition (bitmap)
-            if(bDoProcessRecursively)
+            if (xNewGraphics.is())
             {
-                process(rControlPrimitive);
+                // 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

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list