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

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Tue Jul 31 16:19:00 UTC 2018


 drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx | 2526 ++++++-------
 drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx |   42 
 2 files changed, 1334 insertions(+), 1234 deletions(-)

New commits:
commit 2a4b054b3685aaeca5bdcb2969bcfc25365421d9
Author:     Caolán McNamara <caolanm at redhat.com>
AuthorDate: Tue Jul 31 14:20:52 2018 +0100
Commit:     Caolán McNamara <caolanm at redhat.com>
CommitDate: Tue Jul 31 18:18:36 2018 +0200

    crashtesting: stack exhaustion exporting moz943243-4.svg to odg
    
    happens on the crashtesting box, but not locally, comparing the stack frames its clear
    that the stack used on the crashtester for VclMetafileProcessor2D::processBasePrimitive2D is
    over double that used locally...
    
    comparison on
    > objdump -S workdir/CxxObject/drawinglayer/source/processor2d/vclmetafileprocessor2d.o |less
    gives...
    void VclMetafileProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
    gcc-4.8.2-3.2.mga4 has...       sub    $0x11e8,%rsp
    vs...
    gcc-8.1.1-5.fc28.x86_64 has...  sub    $0x4c0,%rsp
    
    lets split up this method
    
    Change-Id: I73ef1eb0280224988176986918a2d025344197d0
    Reviewed-on: https://gerrit.libreoffice.org/58362
    Reviewed-by: Caolán McNamara <caolanm at redhat.com>
    Tested-by: Caolán McNamara <caolanm at redhat.com>

diff --git a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
index bcd18d2d1f26..a7228338c689 100644
--- a/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
@@ -761,600 +761,59 @@ namespace drawinglayer
                 }
                 case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D :
                 {
-                    const primitive2d::GraphicPrimitive2D& rGraphicPrimitive = static_cast< const primitive2d::GraphicPrimitive2D& >(rCandidate);
-                    bool bUsingPDFExtOutDevData(false);
-                    basegfx::B2DVector aTranslate, aScale;
-                    static bool bSuppressPDFExtOutDevDataSupport(false);
-
-                    if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
-                    {
-                        // emulate data handling from UnoControlPDFExportContact, original see
-                        // svtools/source/graphic/grfmgr.cxx
-                        const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
-
-                        if(rGraphic.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();
-                                }
-                            }
-                        }
-                    }
-
-                    // process recursively and add MetaFile comment
-                    process(rGraphicPrimitive);
-
-                    if(bUsingPDFExtOutDevData)
-                    {
-                        // emulate data handling from UnoControlPDFExportContact, original see
-                        // svtools/source/graphic/grfmgr.cxx
-                        const basegfx::B2DRange aCurrentRange(
-                            aTranslate.getX(), aTranslate.getY(),
-                            aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
-                        const ::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);
-
-                            {
-                                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;
-                                }
-                            }
-
-                            // 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())));
-                        }
-
-                        // #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);
-                    }
-
+                    processGraphicPrimitive2D(static_cast<const primitive2d::GraphicPrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
                 {
-                    const primitive2d::ControlPrimitive2D& rControlPrimitive = static_cast< const primitive2d::ControlPrimitive2D& >(rCandidate);
-                    const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
-                    bool bIsPrintableControl(false);
-
-                    // find out if control is printable
-                    if(rXControl.is())
-                    {
-                        try
-                        {
-                            uno::Reference< beans::XPropertySet > xModelProperties(rXControl->getModel(), uno::UNO_QUERY);
-                            uno::Reference< beans::XPropertySetInfo > xPropertyInfo(xModelProperties.is()
-                                ? xModelProperties->getPropertySetInfo()
-                                : uno::Reference< beans::XPropertySetInfo >());
-                            const OUString sPrintablePropertyName("Printable");
-
-                            if(xPropertyInfo.is() && xPropertyInfo->hasPropertyByName(sPrintablePropertyName))
-                            {
-                                OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl);
-                            }
-                        }
-                        catch(const uno::Exception&)
-                        {
-                            OSL_FAIL("VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!");
-                        }
-                    }
-
-                    // PDF export and printing only for printable controls
-                    if(bIsPrintableControl)
-                    {
-                        const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
-                        bool bDoProcessRecursively(true);
-
-                        if(bPDFExport)
-                        {
-                            // PDF export. Emulate data handling from UnoControlPDFExportContact
-                            // I have now moved describePDFControl to toolkit, thus i can implement the PDF
-                            // form control support now as follows
-                            std::unique_ptr< vcl::PDFWriter::AnyWidget > pPDFControl(
-                                ::toolkitform::describePDFControl( rXControl, *mpPDFExtOutDevData ) );
-
-                            if(pPDFControl.get())
-                            {
-                                // 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.get());
-                                mpPDFExtOutDevData->EndStructureElement();
-
-                                // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject);
-                                // do not process recursively
-                                bDoProcessRecursively = false;
-                            }
-                            else
-                            {
-                                // PDF export did not work, try simple output.
-                                // Fallback to printer output by not setting bDoProcessRecursively
-                                // to false.
-                            }
-                        }
-
-                        // #i93169# used flag the wrong way; true means that nothing was done yet
-                        if(bDoProcessRecursively)
-                        {
-                            // printer output
-                            try
-                            {
-                                // remember old graphics and create new
-                                uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW);
-                                const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics());
-                                const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics());
-
-                                if(xNewGraphics.is())
-                                {
-                                    // link graphics and view
-                                    xControlView->setGraphics(xNewGraphics);
-
-                                    // get position
-                                    const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform());
-                                    const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0));
-
-                                    // draw it
-                                    xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY()));
-                                    bDoProcessRecursively = false;
-
-                                    // restore original graphics
-                                    xControlView->setGraphics(xOriginalGraphics);
-                                }
-                            }
-                            catch( const uno::Exception& )
-                            {
-                                OSL_FAIL("VclMetafileProcessor2D: Printing of Control failed, caught an exception!");
-                            }
-                        }
-
-                        // process recursively if not done yet to export as decomposition (bitmap)
-                        if(bDoProcessRecursively)
-                        {
-                            process(rControlPrimitive);
-                        }
-                    }
-
+                    processControlPrimitive2D(static_cast<const primitive2d::ControlPrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_TEXTHIERARCHYFIELDPRIMITIVE2D :
                 {
-                    // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to)
-                    // thus do the MetafileAction embedding stuff but just handle recursively.
-                    const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive = static_cast< const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate);
-                    const OString aCommentStringCommon("FIELD_SEQ_BEGIN");
-                    const OString aCommentStringPage("FIELD_SEQ_BEGIN;PageField");
-                    const OString aCommentStringEnd("FIELD_SEQ_END");
-                    OUString aURL;
-
-                    switch(rFieldPrimitive.getType())
-                    {
-                        default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON :
-                        {
-                            mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon));
-                            break;
-                        }
-                        case drawinglayer::primitive2d::FIELD_TYPE_PAGE :
-                        {
-                            mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage));
-                            break;
-                        }
-                        case drawinglayer::primitive2d::FIELD_TYPE_URL :
-                        {
-                            aURL = rFieldPrimitive.getValue("URL");
-
-                            if (!aURL.isEmpty())
-                            {
-                                mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast<const sal_uInt8*>(aURL.getStr()), 2 * aURL.getLength()));
-                            }
-
-                            break;
-                        }
-                    }
-
-                    // process recursively
-                    primitive2d::Primitive2DContainer rContent;
-                    rFieldPrimitive.get2DDecomposition(rContent, getViewInformation2D());
-                    process(rContent);
-
-                    // for the end comment the type is not relevant yet, they are all the same. Just add.
-                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd));
-
-                    if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType())
-                    {
-                        // emulate data handling from ImpEditEngine::Paint
-                        const basegfx::B2DRange aViewRange(rContent.getB2DRange(getViewInformation2D()));
-                        const ::tools::Rectangle aRectLogic(
-                            static_cast<sal_Int32>(floor(aViewRange.getMinX())), static_cast<sal_Int32>(floor(aViewRange.getMinY())),
-                            static_cast<sal_Int32>(ceil(aViewRange.getMaxX())), static_cast<sal_Int32>(ceil(aViewRange.getMaxY())));
-                        vcl::PDFExtOutDevBookmarkEntry aBookmark;
-                        aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic);
-                        aBookmark.aBookmark = aURL;
-                        std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks();
-                        rBookmarks.push_back( aBookmark );
-                    }
-
+                    processTextHierarchyFieldPrimitive2D(static_cast<const primitive2d::TextHierarchyFieldPrimitive2D& >(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_TEXTHIERARCHYLINEPRIMITIVE2D :
                 {
-                    const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive = static_cast< const primitive2d::TextHierarchyLinePrimitive2D& >(rCandidate);
-                    const OString aCommentString("XTEXT_EOL");
-
-                    // process recursively and add MetaFile comment
-                    process(rLinePrimitive);
-                    mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
-
+                    processTextHierarchyLinePrimitive2D(static_cast<const primitive2d::TextHierarchyLinePrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_TEXTHIERARCHYBULLETPRIMITIVE2D :
                 {
-                    // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The
-                    // "XTEXT_EOC" is used, use here, too.
-                    const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive = static_cast< const primitive2d::TextHierarchyBulletPrimitive2D& >(rCandidate);
-                    const OString aCommentString("XTEXT_EOC");
-
-                    // process recursively and add MetaFile comment
-                    process(rBulletPrimitive);
-                    mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
-
+                    processTextHierarchyBulletPrimitive2D(static_cast<const primitive2d::TextHierarchyBulletPrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_TEXTHIERARCHYPARAGRAPHPRIMITIVE2D :
                 {
-                    const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive = static_cast< const primitive2d::TextHierarchyParagraphPrimitive2D& >(rCandidate);
-                    const OString aCommentString("XTEXT_EOP");
-
-                    if(mpPDFExtOutDevData)
-                    {
-                        // emulate data handling from ImpEditEngine::Paint
-                        mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
-                    }
-
-                    // process recursively and add MetaFile comment
-                    process(rParagraphPrimitive);
-                    mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
-
-                    if(mpPDFExtOutDevData)
-                    {
-                        // emulate data handling from ImpEditEngine::Paint
-                        mpPDFExtOutDevData->EndStructureElement();
-                    }
-
+                    processTextHierarchyParagraphPrimitive2D(static_cast<const primitive2d::TextHierarchyParagraphPrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_TEXTHIERARCHYBLOCKPRIMITIVE2D :
                 {
-                    const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive = static_cast< const primitive2d::TextHierarchyBlockPrimitive2D& >(rCandidate);
-                    const OString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN");
-                    const OString aCommentStringB("XTEXT_PAINTSHAPE_END");
-
-                    // add MetaFile comment, process recursively and add MetaFile comment
-                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA));
-                    process(rBlockPrimitive);
-                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB));
-
+                    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
-                    const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate = static_cast< const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate);
-                    // const primitive2d::TextDecoratedPortionPrimitive2D* pTextDecoratedCandidate = dynamic_cast< const primitive2d::TextDecoratedPortionPrimitive2D* >(&rCandidate);
-
-                    // Adapt evtl. used special DrawMode
-                    const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
-                    adaptTextToFillDrawMode();
-
-                    // directdraw of text simple portion; use default processing
-                    RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate);
-
-                    // restore DrawMode
-                    mpOutputDevice->SetDrawMode(nOriginalDrawMode);
-
-                    // #i101169# if(pTextDecoratedCandidate)
-                    {
-                        // support for TEXT_ MetaFile actions only for decorated texts
-                        if(!mxBreakIterator.is())
-                        {
-                            uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
-                            mxBreakIterator = i18n::BreakIterator::create(xContext);
-                        }
-
-                        const OUString& rTxt = rTextCandidate.getText();
-                        const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength());
-
-                        if(nTextLength)
-                        {
-                            const css::lang::Locale& rLocale = rTextCandidate.getLocale();
-                            const sal_Int32 nTextPosition(rTextCandidate.getTextPosition());
-
-                            sal_Int32 nDone;
-                            sal_Int32 nNextCellBreak(mxBreakIterator->nextCharacters(rTxt, nTextPosition, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 0, nDone));
-                            css::i18n::Boundary nNextWordBoundary(mxBreakIterator->getWordBoundary(rTxt, nTextPosition, rLocale, css::i18n::WordType::ANY_WORD, true));
-                            sal_Int32 nNextSentenceBreak(mxBreakIterator->endOfSentence(rTxt, nTextPosition, rLocale));
-                            const OString aCommentStringA("XTEXT_EOC");
-                            const OString aCommentStringB("XTEXT_EOW");
-                            const OString aCommentStringC("XTEXT_EOS");
-
-                            for(sal_Int32 i(nTextPosition); i < nTextPosition + nTextLength; i++)
-                            {
-                                // create the entries for the respective break positions
-                                if(i == nNextCellBreak)
-                                {
-                                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA, i - nTextPosition));
-                                    nNextCellBreak = mxBreakIterator->nextCharacters(rTxt, i, rLocale, css::i18n::CharacterIteratorMode::SKIPCELL, 1, nDone);
-                                }
-                                if(i == nNextWordBoundary.endPos)
-                                {
-                                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB, i - nTextPosition));
-                                    nNextWordBoundary = mxBreakIterator->getWordBoundary(rTxt, i + 1, rLocale, css::i18n::WordType::ANY_WORD, true);
-                                }
-                                if(i == nNextSentenceBreak)
-                                {
-                                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringC, i - nTextPosition));
-                                    nNextSentenceBreak = mxBreakIterator->endOfSentence(rTxt, i + 1, rLocale);
-                                }
-                            }
-                        }
-                    }
-
+                    processTextSimplePortionPrimitive2D(static_cast<const primitive2d::TextSimplePortionPrimitive2D& >(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
                 {
-                    const primitive2d::PolygonHairlinePrimitive2D& rHairlinePrimitive = static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate);
-                    const basegfx::B2DPolygon& rBasePolygon = rHairlinePrimitive.getB2DPolygon();
-
-                    if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
-                    {
-                        // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
-                        // per polygon. If there are more, split the polygon in half and call recursively
-                        basegfx::B2DPolygon aLeft, aRight;
-                        splitLinePolygon(rBasePolygon, aLeft, aRight);
-                        rtl::Reference< primitive2d::PolygonHairlinePrimitive2D > xPLeft(new primitive2d::PolygonHairlinePrimitive2D(aLeft, rHairlinePrimitive.getBColor()));
-                        rtl::Reference< primitive2d::PolygonHairlinePrimitive2D > xPRight(new primitive2d::PolygonHairlinePrimitive2D(aRight, rHairlinePrimitive.getBColor()));
-
-                        processBasePrimitive2D(*xPLeft.get());
-                        processBasePrimitive2D(*xPRight.get());
-                    }
-                    else
-                    {
-                        // direct draw of hairline; use default processing
-                        // support SvtGraphicStroke MetaCommentAction
-                        const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rHairlinePrimitive.getBColor()));
-                        SvtGraphicStroke* pSvtGraphicStroke = nullptr;
-
-                        // #i121267# Not needed, does not give better quality compared with
-                        // the MetaActionType::POLYPOLYGON written by RenderPolygonHairlinePrimitive2D
-                        // below
-                        bool bSupportSvtGraphicStroke(false);
-
-                        if(bSupportSvtGraphicStroke)
-                        {
-                            pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
-                                rHairlinePrimitive.getB2DPolygon(),
-                                &aLineColor,
-                                nullptr, nullptr, nullptr, nullptr);
-
-                            impStartSvtGraphicStroke(pSvtGraphicStroke);
-                        }
-
-                        RenderPolygonHairlinePrimitive2D(static_cast< const primitive2d::PolygonHairlinePrimitive2D& >(rCandidate), false);
-
-                        if(bSupportSvtGraphicStroke)
-                        {
-                            impEndSvtGraphicStroke(pSvtGraphicStroke);
-                        }
-                    }
+                    processPolygonHairlinePrimitive2D(static_cast<const primitive2d::PolygonHairlinePrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D :
                 {
-                    const primitive2d::PolygonStrokePrimitive2D& rStrokePrimitive = static_cast< const primitive2d::PolygonStrokePrimitive2D& >(rCandidate);
-                    const basegfx::B2DPolygon& rBasePolygon = rStrokePrimitive.getB2DPolygon();
-
-                    if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
-                    {
-                        // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
-                        // per polygon. If there are more, split the polygon in half and call recursively
-                        basegfx::B2DPolygon aLeft, aRight;
-                        splitLinePolygon(rBasePolygon, aLeft, aRight);
-                        rtl::Reference< primitive2d::PolygonStrokePrimitive2D > xPLeft(new primitive2d::PolygonStrokePrimitive2D(
-                            aLeft, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute()));
-                        rtl::Reference< primitive2d::PolygonStrokePrimitive2D > xPRight(new primitive2d::PolygonStrokePrimitive2D(
-                            aRight, rStrokePrimitive.getLineAttribute(), rStrokePrimitive.getStrokeAttribute()));
-
-                        processBasePrimitive2D(*xPLeft.get());
-                        processBasePrimitive2D(*xPRight.get());
-                    }
-                    else
-                    {
-                        mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
-
-                        // support SvtGraphicStroke MetaCommentAction
-                        SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
-                            rBasePolygon, nullptr,
-                            &rStrokePrimitive.getLineAttribute(),
-                            &rStrokePrimitive.getStrokeAttribute(),
-                            nullptr, nullptr);
-
-                        impStartSvtGraphicStroke(pSvtGraphicStroke);
-                        const attribute::LineAttribute& rLine = rStrokePrimitive.getLineAttribute();
-
-                        // create MetaPolyLineActions, but without LineStyle::Dash
-                        if(basegfx::fTools::more(rLine.getWidth(), 0.0))
-                        {
-                            const attribute::StrokeAttribute& rStroke = rStrokePrimitive.getStrokeAttribute();
-                            basegfx::B2DPolyPolygon aHairLinePolyPolygon;
-
-                            if(0.0 == rStroke.getFullDotDashLen())
-                            {
-                                aHairLinePolyPolygon.append(rBasePolygon);
-                            }
-                            else
-                            {
-                                basegfx::utils::applyLineDashing(
-                                    rBasePolygon, rStroke.getDotDashArray(),
-                                    &aHairLinePolyPolygon, nullptr, rStroke.getFullDotDashLen());
-                            }
-
-                            const basegfx::BColor aHairlineColor(maBColorModifierStack.getModifiedColor(rLine.getColor()));
-                            mpOutputDevice->SetLineColor(Color(aHairlineColor));
-                            mpOutputDevice->SetFillColor();
-                            aHairLinePolyPolygon.transform(maCurrentTransformation);
-
-                            // use the transformed line width
-                            LineInfo aLineInfo(LineStyle::Solid, basegfx::fround(getTransformedLineWidth(rLine.getWidth())));
-                            aLineInfo.SetLineJoin(rLine.getLineJoin());
-                            aLineInfo.SetLineCap(rLine.getLineCap());
-
-                            for(sal_uInt32 a(0); a < aHairLinePolyPolygon.count(); a++)
-                            {
-                                const basegfx::B2DPolygon aCandidate(aHairLinePolyPolygon.getB2DPolygon(a));
-
-                                if(aCandidate.count() > 1)
-                                {
-                                    const ::tools::Polygon aToolsPolygon(aCandidate);
-
-                                    mpMetaFile->AddAction(new MetaPolyLineAction(aToolsPolygon, aLineInfo));
-                                }
-                            }
-                        }
-                        else
-                        {
-                            process(rCandidate);
-                        }
-
-                        impEndSvtGraphicStroke(pSvtGraphicStroke);
-
-                        mpOutputDevice->Pop();
-                    }
-
+                    processPolygonStrokePrimitive2D(static_cast<const primitive2d::PolygonStrokePrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_POLYGONSTROKEARROWPRIMITIVE2D :
                 {
-                    const primitive2d::PolygonStrokeArrowPrimitive2D& rStrokeArrowPrimitive = static_cast< const primitive2d::PolygonStrokeArrowPrimitive2D& >(rCandidate);
-                    const basegfx::B2DPolygon& rBasePolygon = rStrokeArrowPrimitive.getB2DPolygon();
-
-                    if(rBasePolygon.count() > (MAX_POLYGON_POINT_COUNT_METAFILE - 1))
-                    {
-                        // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
-                        // per polygon. If there are more, split the polygon in half and call recursively
-                        basegfx::B2DPolygon aLeft, aRight;
-                        splitLinePolygon(rBasePolygon, aLeft, aRight);
-                        const attribute::LineStartEndAttribute aEmpty;
-                        rtl::Reference< primitive2d::PolygonStrokeArrowPrimitive2D > xPLeft(new primitive2d::PolygonStrokeArrowPrimitive2D(
-                            aLeft,
-                            rStrokeArrowPrimitive.getLineAttribute(),
-                            rStrokeArrowPrimitive.getStrokeAttribute(),
-                            rStrokeArrowPrimitive.getStart(),
-                            aEmpty));
-                        rtl::Reference< primitive2d::PolygonStrokeArrowPrimitive2D > xPRight(new primitive2d::PolygonStrokeArrowPrimitive2D(
-                            aRight,
-                            rStrokeArrowPrimitive.getLineAttribute(),
-                            rStrokeArrowPrimitive.getStrokeAttribute(),
-                            aEmpty,
-                            rStrokeArrowPrimitive.getEnd()));
-
-                        processBasePrimitive2D(*xPLeft.get());
-                        processBasePrimitive2D(*xPRight.get());
-                    }
-                    else
-                    {
-                        // support SvtGraphicStroke MetaCommentAction
-                        SvtGraphicStroke* pSvtGraphicStroke = impTryToCreateSvtGraphicStroke(
-                            rBasePolygon, nullptr,
-                            &rStrokeArrowPrimitive.getLineAttribute(),
-                            &rStrokeArrowPrimitive.getStrokeAttribute(),
-                            &rStrokeArrowPrimitive.getStart(),
-                            &rStrokeArrowPrimitive.getEnd());
-
-                        // write LineGeometry start marker
-                        impStartSvtGraphicStroke(pSvtGraphicStroke);
-
-                        // #i116162# When B&W is set as DrawMode, DrawModeFlags::WhiteFill is used
-                        // to let all fills be just white; for lines DrawModeFlags::BlackLine is used
-                        // so all line geometry is supposed to get black. Since in the in-between
-                        // stages of line geometry drawing filled polygons are used (e.g. line
-                        // start/ends) it is necessary to change these drawmodes to preserve
-                        // that lines shall be black; thus change DrawModeFlags::WhiteFill to
-                        // DrawModeFlags::BlackFill during line geometry processing to have line geometry
-                        // parts filled black.
-                        const DrawModeFlags nOldDrawMode(mpOutputDevice->GetDrawMode());
-                        const bool bDrawmodeChange(nOldDrawMode & DrawModeFlags::WhiteFill && mnSvtGraphicStrokeCount);
-
-                        if(bDrawmodeChange)
-                        {
-                            mpOutputDevice->SetDrawMode((nOldDrawMode & ~DrawModeFlags::WhiteFill) | DrawModeFlags::BlackFill);
-                        }
-
-                        // process sub-line geometry (evtl. filled PolyPolygons)
-                        process(rCandidate);
-
-                        if(bDrawmodeChange)
-                        {
-                            mpOutputDevice->SetDrawMode(nOldDrawMode);
-                        }
-
-                        // write LineGeometry end marker
-                        impEndSvtGraphicStroke(pSvtGraphicStroke);
-                    }
-
+                    processPolygonStrokeArrowPrimitive2D(static_cast<const primitive2d::PolygonStrokeArrowPrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
@@ -1368,416 +827,27 @@ namespace drawinglayer
                 }
                 case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D :
                 {
-                    // need to handle PolyPolygonGraphicPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
-                    const primitive2d::PolyPolygonGraphicPrimitive2D& rBitmapCandidate = static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate);
-                    basegfx::B2DPolyPolygon aLocalPolyPolygon(rBitmapCandidate.getB2DPolyPolygon());
-
-                    fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
-
-                    SvtGraphicFill* pSvtGraphicFill = nullptr;
-
-                    if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
-                    {
-                        // #121194# Changed implementation and checked usages fo convert to metafile,
-                        // presentation start (uses SvtGraphicFill) and printing.
-
-                        // calculate transformation. Get real object size, all values in FillGraphicAttribute
-                        // are relative to the unified object
-                        aLocalPolyPolygon.transform(maCurrentTransformation);
-                        const basegfx::B2DVector aOutlineSize(aLocalPolyPolygon.getB2DRange().getRange());
-
-                        // the scaling needs scale from pixel to logic coordinate system
-                        const attribute::FillGraphicAttribute& rFillGraphicAttribute = rBitmapCandidate.getFillGraphic();
-                        const Size aBmpSizePixel(rFillGraphicAttribute.getGraphic().GetSizePixel());
-
-                        // setup transformation like in impgrfll. Multiply with aOutlineSize
-                        // to get from unit coordinates in rFillGraphicAttribute.getGraphicRange()
-                        // to object coordinates with object's top left being at (0,0). Divide
-                        // by pixel size so that scale from pixel to logic will work in SvtGraphicFill.
-                        const basegfx::B2DVector aTransformScale(
-                            rFillGraphicAttribute.getGraphicRange().getRange() /
-                            basegfx::B2DVector(
-                                std::max(1.0, double(aBmpSizePixel.Width())),
-                                std::max(1.0, double(aBmpSizePixel.Height()))) *
-                            aOutlineSize);
-                        const basegfx::B2DPoint aTransformPosition(
-                            rFillGraphicAttribute.getGraphicRange().getMinimum() * aOutlineSize);
-
-                        // setup transformation like in impgrfll
-                        SvtGraphicFill::Transform aTransform;
-
-                        // scale values are divided by bitmap pixel sizes
-                        aTransform.matrix[0] = aTransformScale.getX();
-                        aTransform.matrix[4] = aTransformScale.getY();
-
-                        // translates are absolute
-                        aTransform.matrix[2] = aTransformPosition.getX();
-                        aTransform.matrix[5] = aTransformPosition.getY();
-
-                        pSvtGraphicFill = new SvtGraphicFill(
-                            getFillPolyPolygon(aLocalPolyPolygon),
-                            Color(),
-                            0.0,
-                            SvtGraphicFill::fillEvenOdd,
-                            SvtGraphicFill::fillTexture,
-                            aTransform,
-                            rFillGraphicAttribute.getTiling(),
-                            SvtGraphicFill::hatchSingle,
-                            Color(),
-                            SvtGraphicFill::GradientType::Linear,
-                            Color(),
-                            Color(),
-                            0,
-                            rFillGraphicAttribute.getGraphic());
-                    }
-
-                    // Do use decomposition; encapsulate with SvtGraphicFill
-                    impStartSvtGraphicFill(pSvtGraphicFill);
-                    process(rCandidate);
-                    impEndSvtGraphicFill(pSvtGraphicFill);
-
+                    processPolyPolygonGraphicPrimitive2D(static_cast<const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_POLYPOLYGONHATCHPRIMITIVE2D :
                 {
-                    // need to handle PolyPolygonHatchPrimitive2D here to support XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END
-                    const primitive2d::PolyPolygonHatchPrimitive2D& rHatchCandidate = static_cast< const primitive2d::PolyPolygonHatchPrimitive2D& >(rCandidate);
-                    const attribute::FillHatchAttribute& rFillHatchAttribute = rHatchCandidate.getFillHatch();
-                    basegfx::B2DPolyPolygon aLocalPolyPolygon(rHatchCandidate.getB2DPolyPolygon());
-
-                    if(aLocalPolyPolygon.getB2DRange() != rHatchCandidate.getDefinitionRange())
-                    {
-                        // the range which defines the hatch is different from the range of the
-                        // geometry (used for writer frames). This cannot be done calling vcl, thus use
-                        // decomposition here
-                        process(rCandidate);
-                        break;
-                    }
-
-                    // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
-                    // per polygon. Split polygon until there are less than that
-                    fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
-
-                    if(rFillHatchAttribute.isFillBackground())
-                    {
-                        // with fixing #i111954# (see below) the possible background
-                        // fill of a hatched object was lost.Generate a background fill
-                        // primitive and render it
-                        const primitive2d::Primitive2DReference xBackground(
-                            new primitive2d::PolyPolygonColorPrimitive2D(
-                                aLocalPolyPolygon,
-                                rHatchCandidate.getBackgroundColor()));
-
-                        process(primitive2d::Primitive2DContainer { xBackground });
-                    }
-
-                    SvtGraphicFill* pSvtGraphicFill = nullptr;
-                    aLocalPolyPolygon.transform(maCurrentTransformation);
-
-                    if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
-                    {
-                        // re-create a VCL hatch as base data
-                        SvtGraphicFill::HatchType eHatch(SvtGraphicFill::hatchSingle);
-
-                        switch(rFillHatchAttribute.getStyle())
-                        {
-                            default: // attribute::HatchStyle::Single :
-                            {
-                                eHatch = SvtGraphicFill::hatchSingle;
-                                break;
-                            }
-                            case attribute::HatchStyle::Double :
-                            {
-                                eHatch = SvtGraphicFill::hatchDouble;
-                                break;
-                            }
-                            case attribute::HatchStyle::Triple :
-                            {
-                                eHatch = SvtGraphicFill::hatchTriple;
-                                break;
-                            }
-                        }
-
-                        SvtGraphicFill::Transform aTransform;
-
-                        // scale
-                        aTransform.matrix[0] *= rFillHatchAttribute.getDistance();
-                        aTransform.matrix[4] *= rFillHatchAttribute.getDistance();
-
-                        // rotate (was never correct in impgrfll anyways, use correct angle now)
-                        aTransform.matrix[0] *= cos(rFillHatchAttribute.getAngle());
-                        aTransform.matrix[1] *= -sin(rFillHatchAttribute.getAngle());
-                        aTransform.matrix[3] *= sin(rFillHatchAttribute.getAngle());
-                        aTransform.matrix[4] *= cos(rFillHatchAttribute.getAngle());
-
-                        pSvtGraphicFill = new SvtGraphicFill(
-                            getFillPolyPolygon(aLocalPolyPolygon),
-                            Color(),
-                            0.0,
-                            SvtGraphicFill::fillEvenOdd,
-                            SvtGraphicFill::fillHatch,
-                            aTransform,
-                            false,
-                            eHatch,
-                            Color(rFillHatchAttribute.getColor()),
-                            SvtGraphicFill::GradientType::Linear,
-                            Color(),
-                            Color(),
-                            0,
-                            Graphic());
-                    }
-
-                    // Do use decomposition; encapsulate with SvtGraphicFill
-                    impStartSvtGraphicFill(pSvtGraphicFill);
-
-                    // #i111954# do NOT use decomposition, but use direct VCL-command
-                    // process(rCandidate.get2DDecomposition(getViewInformation2D()));
-                    const ::tools::PolyPolygon aToolsPolyPolygon(basegfx::utils::adaptiveSubdivideByAngle(aLocalPolyPolygon));
-                    const HatchStyle aHatchStyle(
-                        attribute::HatchStyle::Single == rFillHatchAttribute.getStyle() ? HatchStyle::Single :
-                        attribute::HatchStyle::Double == rFillHatchAttribute.getStyle() ? HatchStyle::Double :
-                        HatchStyle::Triple);
-
-                    mpOutputDevice->DrawHatch(aToolsPolyPolygon,
-                        Hatch(aHatchStyle,
-                            Color(rFillHatchAttribute.getColor()),
-                            basegfx::fround(rFillHatchAttribute.getDistance()),
-                            basegfx::fround(rFillHatchAttribute.getAngle() / F_PI1800)));
-
-                    impEndSvtGraphicFill(pSvtGraphicFill);
-
+                    processPolyPolygonHatchPrimitive2D(static_cast<const primitive2d::PolyPolygonHatchPrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
                 {
-                    basegfx::B2DVector aScale, aTranslate;
-                    double fRotate, fShearX;
-
-                    maCurrentTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
-
-                    if(!basegfx::fTools::equalZero(fRotate) || !basegfx::fTools::equalZero(fShearX))
-                    {
-                        // #i121185# When rotation or shear is used, a VCL Gradient cannot be used directly.
-                        // This is because VCL Gradient mechanism does *not* support to rotate the gradient
-                        // with objects and this case is not expressable in a Metafile (and cannot be added
-                        // since the FileFormats used, e.g. *.wmf, do not support it either).
-                        // Such cases happen when a graphic object uses a Metafile as graphic information or
-                        // a fill style definition uses a Metafile. In this cases the graphic content is
-                        // rotated with the graphic or filled object; this is not supported by the target
-                        // format of this conversion renderer - Metafiles.
-                        // To solve this, not a Gradient is written, but the decomposition of this object
-                        // is written to the Metafile. This is the PolyPolygons building the gradient fill.
-                        // These will need more space and time, but the result will be as if the Gradient
-                        // was rotated with the object.
-                        // This mechanism is used by all exporters still not using Primtives (e.g. Print,
-                        // Slideshow, Export rto PDF, export to Picture, ...) but relying on Metafile
-                        // transfers. One more reason to *change* these to primitives.
-                        // BTW: One more example how useful the principles of primitives are; the decomposition
-                        // is by definition a simpler, maybe more expensive representation of the same content.
-                        process(rCandidate);
-                        break;
-                    }
-
-                    const primitive2d::PolyPolygonGradientPrimitive2D& rGradientCandidate = static_cast< const primitive2d::PolyPolygonGradientPrimitive2D& >(rCandidate);
-                    basegfx::B2DPolyPolygon aLocalPolyPolygon(rGradientCandidate.getB2DPolyPolygon());
-
-                    if(aLocalPolyPolygon.getB2DRange() != rGradientCandidate.getDefinitionRange())
-                    {
-                        // the range which defines the gradient is different from the range of the
-                        // geometry (used for writer frames). This cannot be done calling vcl, thus use
-                        // decomposition here
-                        process(rCandidate);
-                        break;
-                    }
-
-                        // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
-                        // per polygon. Split polygon until there are less than that
-                        fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
-
-                        // for support of MetaCommentActions of the form XGRAD_SEQ_BEGIN, XGRAD_SEQ_END
-                        // it is safest to use the VCL OutputDevice::DrawGradient method which creates those.
-                        // re-create a VCL-gradient from FillGradientPrimitive2D and the needed tools PolyPolygon
-                        Gradient aVCLGradient;
-                        impConvertFillGradientAttributeToVCLGradient(aVCLGradient, rGradientCandidate.getFillGradient(), false);
-                        aLocalPolyPolygon.transform(maCurrentTransformation);
-
-                        // #i82145# ATM VCL printing of gradients using curved shapes does not work,
-                        // i submitted the bug with the given ID to THB. When that task is fixed it is
-                        // necessary to again remove this subdivision since it decreases possible
-                        // printing quality (not even resolution-dependent for now). THB will tell
-                        // me when that task is fixed in the master
-                        const ::tools::PolyPolygon aToolsPolyPolygon(
-                            getFillPolyPolygon(
-                                basegfx::utils::adaptiveSubdivideByAngle(aLocalPolyPolygon)));
-
-
-                        // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
-                        SvtGraphicFill* pSvtGraphicFill = nullptr;
-
-                        if(!mnSvtGraphicFillCount && aLocalPolyPolygon.count())
-                        {
-                            // setup gradient stuff like in impgrfll
-                            SvtGraphicFill::GradientType eGrad(SvtGraphicFill::GradientType::Linear);
-
-                            switch(aVCLGradient.GetStyle())
-                            {
-                                default : // GradientStyle::Linear:
-                                case GradientStyle::Axial:
-                                    eGrad = SvtGraphicFill::GradientType::Linear;
-                                    break;
-                                case GradientStyle::Radial:
-                                case GradientStyle::Elliptical:
-                                    eGrad = SvtGraphicFill::GradientType::Radial;
-                                    break;
-                                case GradientStyle::Square:
-                                case GradientStyle::Rect:
-                                    eGrad = SvtGraphicFill::GradientType::Rectangular;
-                                    break;
-                            }
-
-                        pSvtGraphicFill = new SvtGraphicFill(
-                            aToolsPolyPolygon,
-                            Color(),
-                            0.0,
-                            SvtGraphicFill::fillEvenOdd,
-                            SvtGraphicFill::fillGradient,
-                            SvtGraphicFill::Transform(),
-                            false,
-                            SvtGraphicFill::hatchSingle,
-                            Color(),
-                            eGrad,
-                            aVCLGradient.GetStartColor(),
-                            aVCLGradient.GetEndColor(),
-                            aVCLGradient.GetSteps(),
-                            Graphic());
-                    }
-
-                    // call VCL directly; encapsulate with SvtGraphicFill
-                    impStartSvtGraphicFill(pSvtGraphicFill);
-                    mpOutputDevice->DrawGradient(aToolsPolyPolygon, aVCLGradient);
-                    impEndSvtGraphicFill(pSvtGraphicFill);
-
+                    processPolyPolygonGradientPrimitive2D(static_cast<const primitive2d::PolyPolygonGradientPrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
                 {
-                    mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
-                    const primitive2d::PolyPolygonColorPrimitive2D& rPolygonCandidate(static_cast< const primitive2d::PolyPolygonColorPrimitive2D& >(rCandidate));
-                    basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
-
-                    // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
-                    // per polygon. Split polygon until there are less than that
-                    fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
-
-                    const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolygonCandidate.getBColor()));
-                    aLocalPolyPolygon.transform(maCurrentTransformation);
-
-                    // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
-                    SvtGraphicFill* pSvtGraphicFill = nullptr;
-
-                    // #i121267# Not needed, does not give better quality compared with
-                    // the MetaActionType::POLYPOLYGON written by the DrawPolyPolygon command
-                    // below
-                    bool bSupportSvtGraphicFill(false);
-
-                    if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count())
-                    {
-                        // setup simple color fill stuff like in impgrfll
-                        pSvtGraphicFill = new SvtGraphicFill(
-                            getFillPolyPolygon(aLocalPolyPolygon),
-                            Color(aPolygonColor),
-                            0.0,
-                            SvtGraphicFill::fillEvenOdd,
-                            SvtGraphicFill::fillSolid,
-                            SvtGraphicFill::Transform(),
-                            false,
-                            SvtGraphicFill::hatchSingle,
-                            Color(),
-                            SvtGraphicFill::GradientType::Linear,
-                            Color(),
-                            Color(),
-                            0,
-                            Graphic());
-                    }
-
-                    // set line and fill color
-                    mpOutputDevice->SetFillColor(Color(aPolygonColor));
-                    mpOutputDevice->SetLineColor();
-
-                    // call VCL directly; encapsulate with SvtGraphicFill
-                    if(bSupportSvtGraphicFill)
-                    {
-                            impStartSvtGraphicFill(pSvtGraphicFill);
-                    }
-
-                    mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
-
-                    if(bSupportSvtGraphicFill)
-                    {
-                        impEndSvtGraphicFill(pSvtGraphicFill);
-                    }
-
-                    mpOutputDevice->Pop();
+                    processPolyPolygonColorPrimitive2D(static_cast<const primitive2d::PolyPolygonColorPrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
                 {
-                    // mask group. Special handling for MetaFiles.
-                    const primitive2d::MaskPrimitive2D& rMaskCandidate = static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate);
-
-                    if(!rMaskCandidate.getChildren().empty())
-                    {
-                        basegfx::B2DPolyPolygon aMask(rMaskCandidate.getMask());
-
-                        if(aMask.count())
-                        {
-                            // prepare new mask polygon and rescue current one
-                            aMask.transform(maCurrentTransformation);
-                            const basegfx::B2DPolyPolygon aLastClipPolyPolygon(maClipPolyPolygon);
-
-                            if(maClipPolyPolygon.count())
-                            {
-                                // there is already a clip polygon set; build clipped union of
-                                // current mask polygon and new one
-                                maClipPolyPolygon = basegfx::utils::clipPolyPolygonOnPolyPolygon(
-                                    aMask,
-                                    maClipPolyPolygon,
-                                    true, // #i106516# we want the inside of aMask, not the outside
-                                    false);
-                            }
-                            else
-                            {
-                                // use mask directly
-                                maClipPolyPolygon = aMask;
-                            }
-
-                            if(maClipPolyPolygon.count())
-                            {
-                                // set VCL clip region; subdivide before conversion to tools polygon. Subdivision necessary (!)
-                                // Removed subdivision and fixed in vcl::Region::ImplPolyPolyRegionToBandRegionFunc() in VCL where
-                                // the ClipRegion is built from the Polygon. A AdaptiveSubdivide on the source polygon was missing there
-                                mpOutputDevice->Push(PushFlags::CLIPREGION);
-                                mpOutputDevice->SetClipRegion(vcl::Region(maClipPolyPolygon));
-
-                                // recursively paint content
-                                // #i121267# Only need to process sub-content when clip polygon is *not* empty.
-                                // If it is empty, the clip is empty and there can be nothing inside.
-                                process(rMaskCandidate.getChildren());
-
-                                // restore VCL clip region
-                                mpOutputDevice->Pop();
-                            }
-
-                            // restore to rescued clip polygon
-                            maClipPolyPolygon = aLastClipPolyPolygon;
-                        }
-                        else
-                        {
-                            // no mask, no clipping. recursively paint content
-                            process(rMaskCandidate.getChildren());
-                        }
-                    }
-
+                    processMaskPrimitive2D(static_cast<const primitive2d::MaskPrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
@@ -1788,278 +858,12 @@ namespace drawinglayer
                 }
                 case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
                 {
-                    mpOutputDevice->Push(PushFlags::LINECOLOR | PushFlags::FILLCOLOR);
-                    // for metafile: Need to examine what the pure vcl version is doing here actually
-                    // - uses DrawTransparent with metafile for content and a gradient
-                    // - uses DrawTransparent for single PolyPolygons directly. Can be detected by
-                    //   checking the content for single PolyPolygonColorPrimitive2D
-                    const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate = static_cast< const primitive2d::UnifiedTransparencePrimitive2D& >(rCandidate);
-                    const primitive2d::Primitive2DContainer& rContent = rUniTransparenceCandidate.getChildren();
-
-                    if(!rContent.empty())
-                    {
-                        if(0.0 == rUniTransparenceCandidate.getTransparence())
-                        {
-                            // not transparent at all, use content
-                            process(rUniTransparenceCandidate.getChildren());
-                        }
-                        else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
-                        {
-                            // try to identify a single PolyPolygonColorPrimitive2D in the
-                            // content part of the transparence primitive
-                            const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = nullptr;
-                            static bool bForceToMetafile(false);
-
-                            if(!bForceToMetafile && 1 == rContent.size())
-                            {
-                                const primitive2d::Primitive2DReference xReference(rContent[0]);
-                                pPoPoColor = dynamic_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(xReference.get());
-                            }
-
-                            // PolyPolygonGradientPrimitive2D, PolyPolygonHatchPrimitive2D and
-                            // PolyPolygonGraphicPrimitive2D are derived from PolyPolygonColorPrimitive2D.
-                            // Check also for correct ID to exclude derived implementations
-                            if(pPoPoColor && PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D == pPoPoColor->getPrimitive2DID())
-                            {
-                                // single transparent tools::PolyPolygon identified, use directly
-                                const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(pPoPoColor->getBColor()));
-                                basegfx::B2DPolyPolygon aLocalPolyPolygon(pPoPoColor->getB2DPolyPolygon());
-
-                                // #i112245# Metafiles use tools Polygon and are not able to have more than 65535 points
-                                // per polygon. Split polygon until there are less than that
-                                fillPolyPolygonNeededToBeSplit(aLocalPolyPolygon);
-
-                                // now transform
-                                aLocalPolyPolygon.transform(maCurrentTransformation);
-
-                                // XPATHFILL_SEQ_BEGIN/XPATHFILL_SEQ_END support
-                                SvtGraphicFill* pSvtGraphicFill = nullptr;
-
-                                // #i121267# Not needed, does not give better quality compared with
-                                // the MetaActionType::POLYPOLYGON written by the DrawPolyPolygon command
-                                // below
-                                bool bSupportSvtGraphicFill(false);
-
-                                if(bSupportSvtGraphicFill && !mnSvtGraphicFillCount && aLocalPolyPolygon.count())
-                                {
-                                    // setup simple color with transparence fill stuff like in impgrfll
-                                    pSvtGraphicFill = new SvtGraphicFill(
-                                        getFillPolyPolygon(aLocalPolyPolygon),
-                                        Color(aPolygonColor),
-                                        rUniTransparenceCandidate.getTransparence(),
-                                        SvtGraphicFill::fillEvenOdd,
-                                        SvtGraphicFill::fillSolid,
-                                        SvtGraphicFill::Transform(),
-                                        false,
-                                        SvtGraphicFill::hatchSingle,
-                                        Color(),
-                                        SvtGraphicFill::GradientType::Linear,
-                                        Color(),
-                                        Color(),
-                                        0,
-                                        Graphic());
-                                }
-
-                                // set line and fill color
-                                const sal_uInt16 nTransPercentVcl(static_cast<sal_uInt16>(basegfx::fround(rUniTransparenceCandidate.getTransparence() * 100.0)));
-                                mpOutputDevice->SetFillColor(Color(aPolygonColor));
-                                mpOutputDevice->SetLineColor();
-
-                                // call VCL directly; encapsulate with SvtGraphicFill
-                                if(bSupportSvtGraphicFill)
-                                {
-                                    impStartSvtGraphicFill(pSvtGraphicFill);
-                                }
-
-                                mpOutputDevice->DrawTransparent(
-                                    ::tools::PolyPolygon(aLocalPolyPolygon),
-                                    nTransPercentVcl);
-
-                                if(bSupportSvtGraphicFill)
-                                {
-                                    impEndSvtGraphicFill(pSvtGraphicFill);
-                                }
-                            }
-                            else
-                            {
-                                // save old mfCurrentUnifiedTransparence and set new one
-                                // so that contained SvtGraphicStroke may use the current one
-                                const double fLastCurrentUnifiedTransparence(mfCurrentUnifiedTransparence);
-                                // #i105377# paint the content metafile opaque as the transparency gets
-                                // split of into the gradient below
-                                // mfCurrentUnifiedTransparence = rUniTransparenceCandidate.getTransparence();
-                                mfCurrentUnifiedTransparence = 0;
-
-                                // various content, create content-metafile
-                                GDIMetaFile aContentMetafile;
-                                const ::tools::Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
-
-                                // restore mfCurrentUnifiedTransparence; it may have been used
-                                // while processing the sub-content in impDumpToMetaFile
-                                mfCurrentUnifiedTransparence = fLastCurrentUnifiedTransparence;
-
-                                // create uniform VCL gradient for uniform transparency
-                                Gradient aVCLGradient;
-                                const sal_uInt8 nTransPercentVcl(static_cast<sal_uInt8>(basegfx::fround(rUniTransparenceCandidate.getTransparence() * 255.0)));
-                                const Color aTransColor(nTransPercentVcl, nTransPercentVcl, nTransPercentVcl);
-
-                                aVCLGradient.SetStyle(GradientStyle::Linear);
-                                aVCLGradient.SetStartColor(aTransColor);
-                                aVCLGradient.SetEndColor(aTransColor);
-                                aVCLGradient.SetAngle(0);
-                                aVCLGradient.SetBorder(0);
-                                aVCLGradient.SetOfsX(0);
-                                aVCLGradient.SetOfsY(0);
-                                aVCLGradient.SetStartIntensity(100);
-                                aVCLGradient.SetEndIntensity(100);
-                                aVCLGradient.SetSteps(2);
-
-                                // render it to VCL
-                                mpOutputDevice->DrawTransparent(
-                                    aContentMetafile, aPrimitiveRectangle.TopLeft(),
-                                    aPrimitiveRectangle.GetSize(), aVCLGradient);
-                            }
-                        }
-                    }
-
-                    mpOutputDevice->Pop();
+                    processUnifiedTransparencePrimitive2D(static_cast<const primitive2d::UnifiedTransparencePrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
                 {
-                    // for metafile: Need to examine what the pure vcl version is doing here actually
-                    // - uses DrawTransparent with metafile for content and a gradient
-                    // i can detect this here with checking the gradient part for a single
-                    // FillGradientPrimitive2D and reconstruct the gradient.
-                    // If that detection goes wrong, I have to create an transparence-blended bitmap. Eventually
-                    // do that in stripes, else RenderTransparencePrimitive2D may just be used
-                    const primitive2d::TransparencePrimitive2D& rTransparenceCandidate = static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate);
-                    const primitive2d::Primitive2DContainer& rContent = rTransparenceCandidate.getChildren();
-                    const primitive2d::Primitive2DContainer& rTransparence = rTransparenceCandidate.getTransparence();
-
-                    if(!rContent.empty() && !rTransparence.empty())
-                    {
-                        // try to identify a single FillGradientPrimitive2D in the
-                        // transparence part of the primitive
-                        const primitive2d::FillGradientPrimitive2D* pFiGradient = nullptr;
-                        static bool bForceToBigTransparentVDev(false);
-
-                        if(!bForceToBigTransparentVDev && 1 == rTransparence.size())
-                        {
-                            const primitive2d::Primitive2DReference xReference(rTransparence[0]);
-                            pFiGradient = dynamic_cast< const primitive2d::FillGradientPrimitive2D* >(xReference.get());
-                        }
-
-                        // Check also for correct ID to exclude derived implementations
-                        if(pFiGradient && PRIMITIVE2D_ID_FILLGRADIENTPRIMITIVE2D == pFiGradient->getPrimitive2DID())
-                        {
-                            // various content, create content-metafile
-                            GDIMetaFile aContentMetafile;
-                            const ::tools::Rectangle aPrimitiveRectangle(impDumpToMetaFile(rContent, aContentMetafile));
-
-                            // re-create a VCL-gradient from FillGradientPrimitive2D
-                            Gradient aVCLGradient;
-                            impConvertFillGradientAttributeToVCLGradient(aVCLGradient, pFiGradient->getFillGradient(), true);
-
-                            // render it to VCL
-                            mpOutputDevice->DrawTransparent(
-                                aContentMetafile, aPrimitiveRectangle.TopLeft(),
-                                aPrimitiveRectangle.GetSize(), aVCLGradient);
-                        }
-                        else
-                        {
-                            // sub-transparence group. Draw to VDev first.
-                            // this may get refined to tiling when resolution is too big here
-
-                            // need to avoid switching off MapMode stuff here; maybe need another
-                            // tooling class, cannot just do the same as with the pixel renderer.
-                            // Need to experiment...
-
-                            // Okay, basic implementation finished and tested. The DPI stuff was hard
-                            // and not easy to find out that it's needed.
-                            // Since this will not yet happen normally (as long as no one constructs
-                            // transparence primitives with non-trivial transparence content) i will for now not
-                            // refine to tiling here.
-
-                            basegfx::B2DRange aViewRange(rContent.getB2DRange(getViewInformation2D()));
-                            aViewRange.transform(maCurrentTransformation);
-                            const ::tools::Rectangle aRectLogic(
-                                static_cast<sal_Int32>(floor(aViewRange.getMinX())), static_cast<sal_Int32>(floor(aViewRange.getMinY())),
-                                static_cast<sal_Int32>(ceil(aViewRange.getMaxX())), static_cast<sal_Int32>(ceil(aViewRange.getMaxY())));
-                            const ::tools::Rectangle aRectPixel(mpOutputDevice->LogicToPixel(aRectLogic));
-                            Size aSizePixel(aRectPixel.GetSize());
-                            const Point aEmptyPoint;
-                            ScopedVclPtrInstance< VirtualDevice > aBufferDevice;
-                            const sal_uInt32 nMaxQuadratPixels(500000);
-                            const sal_uInt32 nViewVisibleArea(aSizePixel.getWidth() * aSizePixel.getHeight());
-                            double fReduceFactor(1.0);
-
-                            if(nViewVisibleArea > nMaxQuadratPixels)
-                            {
-                                // reduce render size
-                                fReduceFactor = sqrt(double(nMaxQuadratPixels) / static_cast<double>(nViewVisibleArea));
-                                aSizePixel = Size(basegfx::fround(static_cast<double>(aSizePixel.getWidth()) * fReduceFactor),
-                                    basegfx::fround(static_cast<double>(aSizePixel.getHeight()) * fReduceFactor));
-                            }
-
-                            if(aBufferDevice->SetOutputSizePixel(aSizePixel))
-                            {
-                                // create and set MapModes for target devices
-                                MapMode aNewMapMode(mpOutputDevice->GetMapMode());
-                                aNewMapMode.SetOrigin(Point(-aRectLogic.Left(), -aRectLogic.Top()));
-                                aBufferDevice->SetMapMode(aNewMapMode);
-
-                                // prepare view transformation for target renderers
-                                // ATTENTION! Need to apply another scaling because of the potential DPI differences
-                                // between Printer and VDev (mpOutputDevice and aBufferDevice here).
-                                // To get the DPI, LogicToPixel from (1,1) from MapUnit::MapInch needs to be used.
-                                basegfx::B2DHomMatrix aViewTransform(aBufferDevice->GetViewTransformation());
-                                const Size aDPIOld(mpOutputDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)));
-                                const Size aDPINew(aBufferDevice->LogicToPixel(Size(1, 1), MapMode(MapUnit::MapInch)));
-                                const double fDPIXChange(static_cast<double>(aDPIOld.getWidth()) / static_cast<double>(aDPINew.getWidth()));
-                                const double fDPIYChange(static_cast<double>(aDPIOld.getHeight()) / static_cast<double>(aDPINew.getHeight()));
-
-                                if(!basegfx::fTools::equal(fDPIXChange, 1.0) || !basegfx::fTools::equal(fDPIYChange, 1.0))
-                                {
-                                    aViewTransform.scale(fDPIXChange, fDPIYChange);
-                                }
-
-                                // also take scaling from Size reduction into account
-                                if(!basegfx::fTools::equal(fReduceFactor, 1.0))
-                                {
-                                    aViewTransform.scale(fReduceFactor, fReduceFactor);
-                                }
-
-                                // create view information and pixel renderer. Reuse known ViewInformation
-                                // except new transformation and range
-                                const geometry::ViewInformation2D aViewInfo(
-                                    getViewInformation2D().getObjectTransformation(),
-                                    aViewTransform,
-                                    aViewRange,
-                                    getViewInformation2D().getVisualizedPage(),
-                                    getViewInformation2D().getViewTime(),
-                                    getViewInformation2D().getExtendedInformationSequence());
-
-                                VclPixelProcessor2D aBufferProcessor(aViewInfo, *aBufferDevice.get());
-
-                                // draw content using pixel renderer
-                                aBufferProcessor.process(rContent);
-                                const Bitmap aBmContent(aBufferDevice->GetBitmap(aEmptyPoint, aSizePixel));
-
-                                // draw transparence using pixel renderer
-                                aBufferDevice->Erase();
-                                aBufferProcessor.process(rTransparence);
-                                const AlphaMask aBmAlpha(aBufferDevice->GetBitmap(aEmptyPoint, aSizePixel));
-
-                                // paint
-                                mpOutputDevice->DrawBitmapEx(
-                                    aRectLogic.TopLeft(),
-                                    aRectLogic.GetSize(),
-                                    BitmapEx(aBmContent, aBmAlpha));
-                            }
-                        }
-                    }
-
+                    processTransparencePrimitive2D(static_cast<const primitive2d::TransparencePrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
@@ -2088,26 +892,7 @@ namespace drawinglayer
                 }
                 case PRIMITIVE2D_ID_STRUCTURETAGPRIMITIVE2D :
                 {
-                    // structured tag primitive
-                    const primitive2d::StructureTagPrimitive2D& rStructureTagCandidate = static_cast< const primitive2d::StructureTagPrimitive2D& >(rCandidate);
-                    const vcl::PDFWriter::StructElement& rTagElement(rStructureTagCandidate.getStructureElement());
-                    const bool bTagUsed(vcl::PDFWriter::NonStructElement != rTagElement);
-
-                    if(mpPDFExtOutDevData &&  bTagUsed)
-                    {
-                        // write start tag
-                        mpPDFExtOutDevData->BeginStructureElement(rTagElement);
-                    }
-
-                    // process children normally
-                    process(rStructureTagCandidate.getChildren());
-
-                    if(mpPDFExtOutDevData &&  bTagUsed)
-                    {
-                        // write end tag
-                        mpPDFExtOutDevData->EndStructureElement();
-                    }
-
+                    processStructureTagPrimitive2D(static_cast<const primitive2d::StructureTagPrimitive2D&>(rCandidate));
                     break;
                 }
                 case PRIMITIVE2D_ID_EPSPRIMITIVE2D :
@@ -2123,6 +908,1279 @@ namespace drawinglayer
                 }
             }
         }
+
+        void VclMetafileProcessor2D::processGraphicPrimitive2D(const primitive2d::GraphicPrimitive2D& rGraphicPrimitive)
+        {
+            bool bUsingPDFExtOutDevData(false);
+            basegfx::B2DVector aTranslate, aScale;
+            static bool bSuppressPDFExtOutDevDataSupport(false);
+
+            if(mpPDFExtOutDevData && !bSuppressPDFExtOutDevDataSupport)
+            {
+                // emulate data handling from UnoControlPDFExportContact, original see
+                // svtools/source/graphic/grfmgr.cxx
+                const Graphic& rGraphic = rGraphicPrimitive.getGraphicObject().GetGraphic();
+
+                if(rGraphic.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();
+                        }
+                    }
+                }
+            }
+
+            // process recursively and add MetaFile comment
+            process(rGraphicPrimitive);
+
+            if(bUsingPDFExtOutDevData)
+            {
+                // emulate data handling from UnoControlPDFExportContact, original see
+                // svtools/source/graphic/grfmgr.cxx
+                const basegfx::B2DRange aCurrentRange(
+                    aTranslate.getX(), aTranslate.getY(),
+                    aTranslate.getX() + aScale.getX(), aTranslate.getY() + aScale.getY());
+                const ::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);
+
+                    {
+                        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;
+                        }
+                    }
+
+                    // 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())));
+                }
+
+                // #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))
+                    {
+                        OSL_VERIFY(xModelProperties->getPropertyValue(sPrintablePropertyName) >>= bIsPrintableControl);
+                    }
+                }
+                catch(const uno::Exception&)
+                {
+                    OSL_FAIL("VclMetafileProcessor2D: No access to printable flag of Control, caught an exception!");
+                }
+            }
+
+            // PDF export and printing only for printable controls
+            if(bIsPrintableControl)
+            {
+                const bool bPDFExport(mpPDFExtOutDevData && mpPDFExtOutDevData->GetIsExportFormFields());
+                bool bDoProcessRecursively(true);
+
+                if(bPDFExport)
+                {
+                    // PDF export. Emulate data handling from UnoControlPDFExportContact
+                    // I have now moved describePDFControl to toolkit, thus i can implement the PDF
+                    // form control support now as follows
+                    std::unique_ptr< vcl::PDFWriter::AnyWidget > pPDFControl(
+                        ::toolkitform::describePDFControl( rXControl, *mpPDFExtOutDevData ) );
+
+                    if(pPDFControl.get())
+                    {
+                        // 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.get());
+                        mpPDFExtOutDevData->EndStructureElement();
+
+                        // no normal paint needed (see original UnoControlPDFExportContact::do_PaintObject);
+                        // do not process recursively
+                        bDoProcessRecursively = false;
+                    }
+                    else
+                    {
+                        // PDF export did not work, try simple output.
+                        // Fallback to printer output by not setting bDoProcessRecursively
+                        // to false.
+                    }
+                }
+
+                // #i93169# used flag the wrong way; true means that nothing was done yet
+                if(bDoProcessRecursively)
+                {
+                    // printer output
+                    try
+                    {
+                        // remember old graphics and create new
+                        uno::Reference< awt::XView > xControlView(rXControl, uno::UNO_QUERY_THROW);
+                        const uno::Reference< awt::XGraphics > xOriginalGraphics(xControlView->getGraphics());
+                        const uno::Reference< awt::XGraphics > xNewGraphics(mpOutputDevice->CreateUnoGraphics());
+
+                        if(xNewGraphics.is())
+                        {
+                            // link graphics and view
+                            xControlView->setGraphics(xNewGraphics);
+
+                            // get position
+                            const basegfx::B2DHomMatrix aObjectToDiscrete(getViewInformation2D().getObjectToViewTransformation() * rControlPrimitive.getTransform());
+                            const basegfx::B2DPoint aTopLeftDiscrete(aObjectToDiscrete * basegfx::B2DPoint(0.0, 0.0));
+
+                            // draw it
+                            xControlView->draw(basegfx::fround(aTopLeftDiscrete.getX()), basegfx::fround(aTopLeftDiscrete.getY()));
+                            bDoProcessRecursively = false;
+
+                            // restore original graphics
+                            xControlView->setGraphics(xOriginalGraphics);
+                        }
+                    }
+                    catch( const uno::Exception& )
+                    {
+                        OSL_FAIL("VclMetafileProcessor2D: Printing of Control failed, caught an exception!");
+                    }
+                }
+
+                // process recursively if not done yet to export as decomposition (bitmap)
+                if(bDoProcessRecursively)
+                {
+                    process(rControlPrimitive);
+                }
+            }
+        }
+
+        void VclMetafileProcessor2D::processTextHierarchyFieldPrimitive2D(const primitive2d::TextHierarchyFieldPrimitive2D& rFieldPrimitive)
+        {
+            // support for FIELD_SEQ_BEGIN, FIELD_SEQ_END and URL. It wraps text primitives (but is not limited to)
+            // thus do the MetafileAction embedding stuff but just handle recursively.
+            const OString aCommentStringCommon("FIELD_SEQ_BEGIN");
+            const OString aCommentStringPage("FIELD_SEQ_BEGIN;PageField");
+            const OString aCommentStringEnd("FIELD_SEQ_END");
+            OUString aURL;
+
+            switch(rFieldPrimitive.getType())
+            {
+                default : // case drawinglayer::primitive2d::FIELD_TYPE_COMMON :
+                {
+                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon));
+                    break;
+                }
+                case drawinglayer::primitive2d::FIELD_TYPE_PAGE :
+                {
+                    mpMetaFile->AddAction(new MetaCommentAction(aCommentStringPage));
+                    break;
+                }
+                case drawinglayer::primitive2d::FIELD_TYPE_URL :
+                {
+                    aURL = rFieldPrimitive.getValue("URL");
+
+                    if (!aURL.isEmpty())
+                    {
+                        mpMetaFile->AddAction(new MetaCommentAction(aCommentStringCommon, 0, reinterpret_cast<const sal_uInt8*>(aURL.getStr()), 2 * aURL.getLength()));
+                    }
+
+                    break;
+                }
+            }
+
+            // process recursively
+            primitive2d::Primitive2DContainer rContent;
+            rFieldPrimitive.get2DDecomposition(rContent, getViewInformation2D());
+            process(rContent);
+
+            // for the end comment the type is not relevant yet, they are all the same. Just add.
+            mpMetaFile->AddAction(new MetaCommentAction(aCommentStringEnd));
+
+            if(mpPDFExtOutDevData && drawinglayer::primitive2d::FIELD_TYPE_URL == rFieldPrimitive.getType())
+            {
+                // emulate data handling from ImpEditEngine::Paint
+                const basegfx::B2DRange aViewRange(rContent.getB2DRange(getViewInformation2D()));
+                const ::tools::Rectangle aRectLogic(
+                    static_cast<sal_Int32>(floor(aViewRange.getMinX())), static_cast<sal_Int32>(floor(aViewRange.getMinY())),
+                    static_cast<sal_Int32>(ceil(aViewRange.getMaxX())), static_cast<sal_Int32>(ceil(aViewRange.getMaxY())));
+                vcl::PDFExtOutDevBookmarkEntry aBookmark;
+                aBookmark.nLinkId = mpPDFExtOutDevData->CreateLink(aRectLogic);
+                aBookmark.aBookmark = aURL;
+                std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = mpPDFExtOutDevData->GetBookmarks();
+                rBookmarks.push_back( aBookmark );
+            }
+        }
+
+        void VclMetafileProcessor2D::processTextHierarchyLinePrimitive2D(const primitive2d::TextHierarchyLinePrimitive2D& rLinePrimitive)
+        {
+            const OString aCommentString("XTEXT_EOL");
+
+            // process recursively and add MetaFile comment
+            process(rLinePrimitive);
+            mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+        }
+
+        void VclMetafileProcessor2D::processTextHierarchyBulletPrimitive2D(const primitive2d::TextHierarchyBulletPrimitive2D& rBulletPrimitive)
+        {
+            // in Outliner::PaintBullet(), a MetafileComment for bullets is added, too. The
+            // "XTEXT_EOC" is used, use here, too.
+            const OString aCommentString("XTEXT_EOC");
+
+            // process recursively and add MetaFile comment
+            process(rBulletPrimitive);
+            mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+        }
+
+        void VclMetafileProcessor2D::processTextHierarchyParagraphPrimitive2D(const primitive2d::TextHierarchyParagraphPrimitive2D& rParagraphPrimitive)
+        {
+            const OString aCommentString("XTEXT_EOP");
+
+            if(mpPDFExtOutDevData)
+            {
+                // emulate data handling from ImpEditEngine::Paint
+                mpPDFExtOutDevData->BeginStructureElement( vcl::PDFWriter::Paragraph );
+            }
+
+            // process recursively and add MetaFile comment
+            process(rParagraphPrimitive);
+            mpMetaFile->AddAction(new MetaCommentAction(aCommentString));
+
+            if(mpPDFExtOutDevData)
+            {
+                // emulate data handling from ImpEditEngine::Paint
+                mpPDFExtOutDevData->EndStructureElement();
+            }
+        }
+
+        void VclMetafileProcessor2D::processTextHierarchyBlockPrimitive2D(const primitive2d::TextHierarchyBlockPrimitive2D& rBlockPrimitive)
+        {
+            const OString aCommentStringA("XTEXT_PAINTSHAPE_BEGIN");
+            const OString aCommentStringB("XTEXT_PAINTSHAPE_END");
+
+            // add MetaFile comment, process recursively and add MetaFile comment
+            mpMetaFile->AddAction(new MetaCommentAction(aCommentStringA));
+            process(rBlockPrimitive);
+            mpMetaFile->AddAction(new MetaCommentAction(aCommentStringB));
+        }
+
+        void VclMetafileProcessor2D::processTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rTextCandidate)
+        {
+            // Adapt evtl. used special DrawMode
+            const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
+            adaptTextToFillDrawMode();
+
+            // directdraw of text simple portion; use default processing
+            RenderTextSimpleOrDecoratedPortionPrimitive2D(rTextCandidate);
+
+            // restore DrawMode
+            mpOutputDevice->SetDrawMode(nOriginalDrawMode);
+
+            // #i101169# if(pTextDecoratedCandidate)
+            {
+                // support for TEXT_ MetaFile actions only for decorated texts
+                if(!mxBreakIterator.is())
+                {
+                    uno::Reference< uno::XComponentContext > xContext( ::comphelper::getProcessComponentContext() );
+                    mxBreakIterator = i18n::BreakIterator::create(xContext);
+                }
+
+                const OUString& rTxt = rTextCandidate.getText();
+                const sal_Int32 nTextLength(rTextCandidate.getTextLength()); // rTxt.getLength());
+

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list