[Libreoffice-commits] core.git: Branch 'feature/drawinglayercore' - 2 commits - drawinglayer/source solenv/clang-format vcl/qa

Tomaž Vajngerl (via logerrit) logerrit at kemper.freedesktop.org
Thu Apr 30 06:51:32 UTC 2020


 drawinglayer/source/processor2d/vclpixelprocessor2d.cxx | 1557 ++++++++--------
 solenv/clang-format/blacklist                           |    1 
 vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf    |binary
 vcl/qa/cppunit/pdfexport/pdfexport.cxx                  |  134 +
 4 files changed, 945 insertions(+), 747 deletions(-)

New commits:
commit f6fb4a0b2127b12ebb904659259de216c6a9b2d2
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Thu Apr 30 07:54:46 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Thu Apr 30 08:50:29 2020 +0200

    test import and export of multi-page PDF with PDFium filter
    
    The test checks that the exported PDFs contain embedded PDF for
    different pages.
    
    Change-Id: I4e5cd108d8597851d86aa774efbde0d4f2b9d2ac

diff --git a/vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf b/vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf
new file mode 100644
index 000000000000..af665fcba8a0
Binary files /dev/null and b/vcl/qa/cppunit/pdfexport/data/SimpleMultiPagePDF.pdf differ
diff --git a/vcl/qa/cppunit/pdfexport/pdfexport.cxx b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
index 313dbdd278b4..c228cc7945a6 100644
--- a/vcl/qa/cppunit/pdfexport/pdfexport.cxx
+++ b/vcl/qa/cppunit/pdfexport/pdfexport.cxx
@@ -26,6 +26,7 @@
 #include <com/sun/star/document/XExporter.hpp>
 #include <com/sun/star/io/XOutputStream.hpp>
 
+#include <comphelper/scopeguard.hxx>
 #include <comphelper/processfactory.hxx>
 #include <comphelper/propertysequence.hxx>
 #include <test/bootstrapfixture.hxx>
@@ -146,6 +147,8 @@ public:
     void testLargePage();
     void testVersion15();
     void testDefaultVersion();
+    void testMultiPagePDF();
+
 
     CPPUNIT_TEST_SUITE(PdfExportTest);
     CPPUNIT_TEST(testTdf106059);
@@ -189,6 +192,7 @@ public:
     CPPUNIT_TEST(testLargePage);
     CPPUNIT_TEST(testVersion15);
     CPPUNIT_TEST(testDefaultVersion);
+    CPPUNIT_TEST(testMultiPagePDF);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -2154,6 +2158,136 @@ void PdfExportTest::testVersion15()
     CPPUNIT_ASSERT_EQUAL(15, nFileVersion);
 }
 
+// Check round-trip of importing and exporting the PDF with PDFium filter,
+// which imports the PDF document as multiple PDFs as graphic object.
+// Each page in the document has one PDF graphic object which content is
+// the correcponding page in the PDF. When such a document is exported,
+// the PDF graphic gets embedded into the exported PDF document (as a
+// Form XObject).
+void PdfExportTest::testMultiPagePDF()
+{
+    // We need to enable PDFium import (and make sure to disable after the test)
+    bool bResetEnvVar = false;
+    if (getenv("LO_IMPORT_USE_PDFIUM") == nullptr)
+    {
+        bResetEnvVar = true;
+        setenv("LO_IMPORT_USE_PDFIUM", "1", false);
+    }
+    comphelper::ScopeGuard aPDFiumEnvVarGuard([&]() {
+        if (bResetEnvVar)
+            unsetenv("LO_IMPORT_USE_PDFIUM");
+    });
+
+    // Load the PDF and save as PDF
+    OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "SimpleMultiPagePDF.pdf";
+    mxComponent = loadFromDesktop(aURL);
+    CPPUNIT_ASSERT(mxComponent.is());
+
+    uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
+    utl::MediaDescriptor aMediaDescriptor;
+    aMediaDescriptor["FilterName"] <<= OUString("writer_pdf_Export");
+    xStorable->storeToURL(maTempFile.GetURL(), aMediaDescriptor.getAsConstPropertyValueList());
+
+    // Parse the export result.
+    vcl::filter::PDFDocument aDocument;
+    SvFileStream aStream(maTempFile.GetURL(), StreamMode::READ);
+    CPPUNIT_ASSERT(aDocument.Read(aStream));
+
+    std::vector<vcl::filter::PDFObjectElement*> aPages = aDocument.GetPages();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), aPages.size());
+
+    vcl::filter::PDFObjectElement* pResources = aPages[0]->LookupObject("Resources");
+    CPPUNIT_ASSERT(pResources);
+
+    auto pXObjects = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pResources->Lookup("XObject"));
+    CPPUNIT_ASSERT(pXObjects);
+
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(3), pXObjects->GetItems().size()); // 3 PDFs as Form XObjects
+
+    std::vector<OString> rIDs;
+    for (auto const & rPair : pXObjects->GetItems()) {
+        rIDs.push_back(rPair.first);
+    }
+
+    // Let's check the embedded PDF pages - just make sure the size differs,
+    // which should indicate we don't have 3 times the same page.
+
+    {   // embedded PDF page 1
+        vcl::filter::PDFObjectElement* pXObject1 = pXObjects->LookupObject(rIDs[0]);
+        CPPUNIT_ASSERT(pXObject1);
+        CPPUNIT_ASSERT_EQUAL(OString("Im19"), rIDs[0]);
+
+        auto pSubtype1 = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject1->Lookup("Subtype"));
+        CPPUNIT_ASSERT(pSubtype1);
+        CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype1->GetValue());
+
+        auto pXObjectResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject1->Lookup("Resources"));
+        CPPUNIT_ASSERT(pXObjectResources);
+        auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObjectResources->LookupElement("XObject"));
+        CPPUNIT_ASSERT(pXObjectForms);
+        vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first);
+        CPPUNIT_ASSERT(pForm);
+
+        vcl::filter::PDFStreamElement* pStream = pForm->GetStream();
+        CPPUNIT_ASSERT(pStream);
+        SvMemoryStream& rObjectStream = pStream->GetMemory();
+        rObjectStream.Seek(STREAM_SEEK_TO_BEGIN);
+
+        // Just check that the size of the page stream is what is expected.
+        CPPUNIT_ASSERT_EQUAL(sal_uInt64(230), rObjectStream.remainingSize());
+    }
+
+    {   // embedded PDF page 2
+        vcl::filter::PDFObjectElement* pXObject2 = pXObjects->LookupObject(rIDs[1]);
+        CPPUNIT_ASSERT(pXObject2);
+        CPPUNIT_ASSERT_EQUAL(OString("Im34"), rIDs[1]);
+
+        auto pSubtype2 = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject2->Lookup("Subtype"));
+        CPPUNIT_ASSERT(pSubtype2);
+        CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype2->GetValue());
+
+        auto pXObjectResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject2->Lookup("Resources"));
+        CPPUNIT_ASSERT(pXObjectResources);
+        auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObjectResources->LookupElement("XObject"));
+        CPPUNIT_ASSERT(pXObjectForms);
+        vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first);
+        CPPUNIT_ASSERT(pForm);
+
+        vcl::filter::PDFStreamElement* pStream = pForm->GetStream();
+        CPPUNIT_ASSERT(pStream);
+        SvMemoryStream& rObjectStream = pStream->GetMemory();
+        rObjectStream.Seek(STREAM_SEEK_TO_BEGIN);
+
+        // Just check that the size of the page stream is what is expected
+        CPPUNIT_ASSERT_EQUAL(sal_uInt64(309), rObjectStream.remainingSize());
+    }
+
+    {   // embedded PDF page 3
+        vcl::filter::PDFObjectElement* pXObject3 = pXObjects->LookupObject(rIDs[2]);
+        CPPUNIT_ASSERT(pXObject3);
+        CPPUNIT_ASSERT_EQUAL(OString("Im4"), rIDs[2]);
+
+        auto pSubtype3 = dynamic_cast<vcl::filter::PDFNameElement*>(pXObject3->Lookup("Subtype"));
+        CPPUNIT_ASSERT(pSubtype3);
+        CPPUNIT_ASSERT_EQUAL(OString("Form"), pSubtype3->GetValue());
+
+        auto pXObjectResources = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObject3->Lookup("Resources"));
+        CPPUNIT_ASSERT(pXObjectResources);
+        auto pXObjectForms = dynamic_cast<vcl::filter::PDFDictionaryElement*>(pXObjectResources->LookupElement("XObject"));
+        CPPUNIT_ASSERT(pXObjectForms);
+        vcl::filter::PDFObjectElement* pForm = pXObjectForms->LookupObject(pXObjectForms->GetItems().begin()->first);
+        CPPUNIT_ASSERT(pForm);
+
+        vcl::filter::PDFStreamElement* pStream = pForm->GetStream();
+        CPPUNIT_ASSERT(pStream);
+        SvMemoryStream& rObjectStream = pStream->GetMemory();
+        rObjectStream.Seek(STREAM_SEEK_TO_BEGIN);
+
+        // Just check that the size of the page stream is what is expected
+        CPPUNIT_ASSERT_EQUAL(sal_uInt64(193), rObjectStream.remainingSize());
+    }
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(PdfExportTest);
 
 }
commit 38b0be5834a306f808eee980bf0f22131ed72580
Author:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
AuthorDate: Wed Apr 29 17:50:06 2020 +0200
Commit:     Tomaž Vajngerl <tomaz.vajngerl at collabora.co.uk>
CommitDate: Wed Apr 29 17:50:06 2020 +0200

    remove vclpixelprocessor2d.cxx from clang-format blacklist
    
    Change-Id: I03ad72d0754cb8c180f4eab0e8040c3dab533ef9

diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index 654fa6e6168f..f09c6ad0fd76 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -65,826 +65,891 @@ using namespace com::sun::star;
 
 namespace drawinglayer::processor2d
 {
-        struct VclPixelProcessor2D::Impl
-        {
-            AntialiasingFlags m_nOrigAntiAliasing;
+struct VclPixelProcessor2D::Impl
+{
+    AntialiasingFlags m_nOrigAntiAliasing;
+
+    explicit Impl(OutputDevice const& rOutDev)
+        : m_nOrigAntiAliasing(rOutDev.GetAntialiasing())
+    {
+    }
+};
+
+VclPixelProcessor2D::VclPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation,
+                                         OutputDevice& rOutDev)
+    : VclProcessor2D(rViewInformation, rOutDev)
+    , m_pImpl(new Impl(rOutDev))
+{
+    // prepare maCurrentTransformation matrix with viewTransformation to target directly to pixels
+    maCurrentTransformation = rViewInformation.getObjectToViewTransformation();
+
+    // prepare output directly to pixels
+    mpOutputDevice->Push(PushFlags::MAPMODE);
+    mpOutputDevice->SetMapMode();
+
+    // react on AntiAliasing settings
+    if (getOptionsDrawinglayer().IsAntiAliasing())
+    {
+        mpOutputDevice->SetAntialiasing(m_pImpl->m_nOrigAntiAliasing
+                                        | AntialiasingFlags::EnableB2dDraw);
+    }
+    else
+    {
+        mpOutputDevice->SetAntialiasing(m_pImpl->m_nOrigAntiAliasing
+                                        & ~AntialiasingFlags::EnableB2dDraw);
+    }
+}
+
+VclPixelProcessor2D::~VclPixelProcessor2D()
+{
+    // restore MapMode
+    mpOutputDevice->Pop();
 
-            explicit Impl(OutputDevice const& rOutDev)
-                : m_nOrigAntiAliasing(rOutDev.GetAntialiasing())
-            { }
-        };
+    // restore AntiAliasing
+    mpOutputDevice->SetAntialiasing(m_pImpl->m_nOrigAntiAliasing);
+}
 
-        VclPixelProcessor2D::VclPixelProcessor2D(const geometry::ViewInformation2D& rViewInformation, OutputDevice& rOutDev)
-            :   VclProcessor2D(rViewInformation, rOutDev)
-            ,   m_pImpl(new Impl(rOutDev))
-        {
-            // prepare maCurrentTransformation matrix with viewTransformation to target directly to pixels
-            maCurrentTransformation = rViewInformation.getObjectToViewTransformation();
+void VclPixelProcessor2D::tryDrawPolyPolygonColorPrimitive2DDirect(
+    const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency)
+{
+    if (!rSource.getB2DPolyPolygon().count() || fTransparency < 0.0 || fTransparency >= 1.0)
+    {
+        // no geometry, done
+        return;
+    }
+
+    const basegfx::BColor aPolygonColor(
+        maBColorModifierStack.getModifiedColor(rSource.getBColor()));
+
+    mpOutputDevice->SetFillColor(Color(aPolygonColor));
+    mpOutputDevice->SetLineColor();
+    mpOutputDevice->DrawTransparent(maCurrentTransformation, rSource.getB2DPolyPolygon(),
+                                    fTransparency);
+}
+
+bool VclPixelProcessor2D::tryDrawPolygonHairlinePrimitive2DDirect(
+    const drawinglayer::primitive2d::PolygonHairlinePrimitive2D& rSource, double fTransparency)
+{
+    const basegfx::B2DPolygon& rLocalPolygon(rSource.getB2DPolygon());
 
-            // prepare output directly to pixels
-            mpOutputDevice->Push(PushFlags::MAPMODE);
-            mpOutputDevice->SetMapMode();
+    if (!rLocalPolygon.count() || fTransparency < 0.0 || fTransparency >= 1.0)
+    {
+        // no geometry, done
+        return true;
+    }
 
-            // react on AntiAliasing settings
-            if(getOptionsDrawinglayer().IsAntiAliasing())
-            {
-                mpOutputDevice->SetAntialiasing(
-                   m_pImpl->m_nOrigAntiAliasing | AntialiasingFlags::EnableB2dDraw);
-            }
-            else
-            {
-                mpOutputDevice->SetAntialiasing(
-                   m_pImpl->m_nOrigAntiAliasing & ~AntialiasingFlags::EnableB2dDraw);
-            }
-        }
+    const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rSource.getBColor()));
 
-        VclPixelProcessor2D::~VclPixelProcessor2D()
-        {
-            // restore MapMode
-            mpOutputDevice->Pop();
+    mpOutputDevice->SetFillColor();
+    mpOutputDevice->SetLineColor(Color(aLineColor));
+    //aLocalPolygon.transform(maCurrentTransformation);
 
-            // restore AntiAliasing
-            mpOutputDevice->SetAntialiasing(m_pImpl->m_nOrigAntiAliasing);
-        }
+    // try drawing; if it did not work, use standard fallback
+    return mpOutputDevice->DrawPolyLineDirect(maCurrentTransformation, rLocalPolygon, 0.0,
+                                              fTransparency);
+}
 
-        void VclPixelProcessor2D::tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency)
+bool VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect(
+    const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency)
+{
+    const basegfx::B2DPolygon& rLocalPolygon(rSource.getB2DPolygon());
+
+    if (!rLocalPolygon.count() || fTransparency < 0.0 || fTransparency >= 1.0)
+    {
+        // no geometry, done
+        return true;
+    }
+
+    if (basegfx::B2DLineJoin::NONE == rSource.getLineAttribute().getLineJoin()
+        && css::drawing::LineCap_BUTT != rSource.getLineAttribute().getLineCap())
+    {
+        // better use decompose to get that combination done for now, see discussion
+        // at https://bugs.documentfoundation.org/show_bug.cgi?id=130478#c17 and ff
+        return false;
+    }
+
+    // MM01: Radically change here - no dismantle/applyLineDashing,
+    // let that happen low-level at DrawPolyLineDirect implementations
+    // to open up for buffering and evtl. direct draw with sys-dep
+    // graphic systems. Check for stroke is in use
+    const bool bStrokeAttributeNotUsed(rSource.getStrokeAttribute().isDefault()
+                                       || 0.0 == rSource.getStrokeAttribute().getFullDotDashLen());
+
+    const basegfx::BColor aLineColor(
+        maBColorModifierStack.getModifiedColor(rSource.getLineAttribute().getColor()));
+
+    mpOutputDevice->SetFillColor();
+    mpOutputDevice->SetLineColor(Color(aLineColor));
+
+    // MM01 draw direct, hand over dash data if available
+    return mpOutputDevice->DrawPolyLineDirect(
+        maCurrentTransformation, rLocalPolygon,
+        // tdf#124848 use LineWidth direct, do not try to solve for zero-case (aka hairline)
+        rSource.getLineAttribute().getWidth(), fTransparency,
+        bStrokeAttributeNotUsed ? nullptr : &rSource.getStrokeAttribute().getDotDashArray(),
+        rSource.getLineAttribute().getLineJoin(), rSource.getLineAttribute().getLineCap(),
+        rSource.getLineAttribute().getMiterMinimumAngle()
+        /* false bBypassAACheck, default*/);
+}
+
+void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+{
+    switch (rCandidate.getPrimitive2DID())
+    {
+        case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D:
         {
-            if(!rSource.getB2DPolyPolygon().count() || fTransparency < 0.0 || fTransparency >= 1.0)
-            {
-                // no geometry, done
-                return;
-            }
-
-            const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rSource.getBColor()));
-
-            mpOutputDevice->SetFillColor(Color(aPolygonColor));
-            mpOutputDevice->SetLineColor();
-            mpOutputDevice->DrawTransparent(
-                maCurrentTransformation,
-                rSource.getB2DPolyPolygon(),
-                fTransparency);
+            processWrongSpellPrimitive2D(
+                static_cast<const primitive2d::WrongSpellPrimitive2D&>(rCandidate));
+            break;
         }
-
-        bool VclPixelProcessor2D::tryDrawPolygonHairlinePrimitive2DDirect(const drawinglayer::primitive2d::PolygonHairlinePrimitive2D& rSource, double fTransparency)
+        case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D:
         {
-            const basegfx::B2DPolygon& rLocalPolygon(rSource.getB2DPolygon());
-
-            if(!rLocalPolygon.count() || fTransparency < 0.0 || fTransparency >= 1.0)
-            {
-                // no geometry, done
-                return true;
-            }
-
-            const basegfx::BColor aLineColor(maBColorModifierStack.getModifiedColor(rSource.getBColor()));
-
-            mpOutputDevice->SetFillColor();
-            mpOutputDevice->SetLineColor(Color(aLineColor));
-            //aLocalPolygon.transform(maCurrentTransformation);
-
-            // try drawing; if it did not work, use standard fallback
-            return mpOutputDevice->DrawPolyLineDirect(
-                maCurrentTransformation,
-                rLocalPolygon,
-                0.0,
-                fTransparency);
+            processTextSimplePortionPrimitive2D(
+                static_cast<const primitive2d::TextSimplePortionPrimitive2D&>(rCandidate));
+            break;
         }
-
-        bool VclPixelProcessor2D::tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency)
+        case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D:
         {
-            const basegfx::B2DPolygon& rLocalPolygon(rSource.getB2DPolygon());
-
-            if(!rLocalPolygon.count() || fTransparency < 0.0 || fTransparency >= 1.0)
-            {
-                // no geometry, done
-                return true;
-            }
-
-            if (basegfx::B2DLineJoin::NONE == rSource.getLineAttribute().getLineJoin()
-                && css::drawing::LineCap_BUTT != rSource.getLineAttribute().getLineCap())
-            {
-                // better use decompose to get that combination done for now, see discussion
-                // at https://bugs.documentfoundation.org/show_bug.cgi?id=130478#c17 and ff
-                return false;
-            }
-
-            // MM01: Radically change here - no dismantle/applyLineDashing,
-            // let that happen low-level at DrawPolyLineDirect implementations
-            // to open up for buffering and evtl. direct draw with sys-dep
-            // graphic systems. Check for stroke is in use
-            const bool bStrokeAttributeNotUsed(rSource.getStrokeAttribute().isDefault()
-                || 0.0 == rSource.getStrokeAttribute().getFullDotDashLen());
-
-            const basegfx::BColor aLineColor(
-                maBColorModifierStack.getModifiedColor(
-                    rSource.getLineAttribute().getColor()));
-
-            mpOutputDevice->SetFillColor();
-            mpOutputDevice->SetLineColor(Color(aLineColor));
-
-            // MM01 draw direct, hand over dash data if available
-            return mpOutputDevice->DrawPolyLineDirect(
-                maCurrentTransformation,
-                rLocalPolygon,
-                // tdf#124848 use LineWidth direct, do not try to solve for zero-case (aka hairline)
-                rSource.getLineAttribute().getWidth(),
-                fTransparency,
-                bStrokeAttributeNotUsed ? nullptr : &rSource.getStrokeAttribute().getDotDashArray(),
-                rSource.getLineAttribute().getLineJoin(),
-                rSource.getLineAttribute().getLineCap(),
-                rSource.getLineAttribute().getMiterMinimumAngle()
-                /* false bBypassAACheck, default*/);
-        }
-
-        void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
-        {
-            switch(rCandidate.getPrimitive2DID())
-            {
-                case PRIMITIVE2D_ID_WRONGSPELLPRIMITIVE2D :
-                {
-                    processWrongSpellPrimitive2D(static_cast<const primitive2d::WrongSpellPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TEXTSIMPLEPORTIONPRIMITIVE2D :
-                {
-                    processTextSimplePortionPrimitive2D(static_cast<const primitive2d::TextSimplePortionPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TEXTDECORATEDPORTIONPRIMITIVE2D :
-                {
-                    processTextDecoratedPortionPrimitive2D(static_cast<const primitive2d::TextSimplePortionPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D :
-                {
-                    processPolygonHairlinePrimitive2D(static_cast<const primitive2d::PolygonHairlinePrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D :
-                {
-                    // direct draw of transformed BitmapEx primitive
-                    processBitmapPrimitive2D(static_cast<const primitive2d::BitmapPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D :
-                {
-                    // direct draw of fillBitmapPrimitive
-                    RenderFillGraphicPrimitive2D(static_cast< const primitive2d::FillGraphicPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D :
-                {
-                    processPolyPolygonGradientPrimitive2D(static_cast<const primitive2d::PolyPolygonGradientPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D :
-                {
-                    // direct draw of bitmap
-                    RenderPolyPolygonGraphicPrimitive2D(static_cast< const primitive2d::PolyPolygonGraphicPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D :
-                {
-                    processPolyPolygonColorPrimitive2D(static_cast<const primitive2d::PolyPolygonColorPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D :
-                {
-                    processMetaFilePrimitive2D(rCandidate);
-                    break;
-                }
-                case PRIMITIVE2D_ID_MASKPRIMITIVE2D :
-                {
-                    // mask group.
-                    RenderMaskPrimitive2DPixel(static_cast< const primitive2d::MaskPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D :
-                {
-                    // modified color group. Force output to unified color.
-                    RenderModifiedColorPrimitive2D(static_cast< const primitive2d::ModifiedColorPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D :
-                {
-                    processUnifiedTransparencePrimitive2D(static_cast<const primitive2d::UnifiedTransparencePrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D :
-                {
-                    // sub-transparence group. Draw to VDev first.
-                    RenderTransparencePrimitive2D(static_cast< const primitive2d::TransparencePrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D :
-                {
-                    // transform group.
-                    RenderTransformPrimitive2D(static_cast< const primitive2d::TransformPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D :
-                {
-                    // new XDrawPage for ViewInformation2D
-                    RenderPagePreviewPrimitive2D(static_cast< const primitive2d::PagePreviewPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D :
-                {
-                    // marker array
-                    RenderMarkerArrayPrimitive2D(static_cast< const primitive2d::MarkerArrayPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D :
-                {
-                    // point array
-                    RenderPointArrayPrimitive2D(static_cast< const primitive2d::PointArrayPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D :
-                {
-                    processControlPrimitive2D(static_cast<const primitive2d::ControlPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
-                {
-                    processPolygonStrokePrimitive2D(static_cast<const primitive2d::PolygonStrokePrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D :
-                {
-                    processFillHatchPrimitive2D(static_cast<const primitive2d::FillHatchPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D :
-                {
-                    processBackgroundColorPrimitive2D(static_cast<const primitive2d::BackgroundColorPrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_TEXTHIERARCHYEDITPRIMITIVE2D :
-                {
-                    // #i97628#
-                    // This primitive means that the content is derived from an active text edit,
-                    // not from model data itself. Some renderers need to suppress this content, e.g.
-                    // the pixel renderer used for displaying the edit view (like this one). It's
-                    // not to be suppressed by the MetaFile renderers, so that the edited text is
-                    // part of the MetaFile, e.g. needed for presentation previews.
-                    // Action: Ignore here, do nothing.
-                    break;
-                }
-                case PRIMITIVE2D_ID_INVERTPRIMITIVE2D :
-                {
-                    processInvertPrimitive2D(rCandidate);
-                    break;
-                }
-                case PRIMITIVE2D_ID_EPSPRIMITIVE2D :
-                {
-                    RenderEpsPrimitive2D(static_cast< const primitive2d::EpsPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D:
-                {
-                    RenderSvgLinearAtomPrimitive2D(static_cast< const primitive2d::SvgLinearAtomPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D:
-                {
-                    RenderSvgRadialAtomPrimitive2D(static_cast< const primitive2d::SvgRadialAtomPrimitive2D& >(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D:
-                {
-                    processBorderLinePrimitive2D(static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate));
-                    break;
-                }
-                case PRIMITIVE2D_ID_GLOWPRIMITIVE2D:
-                {
-                    processGlowPrimitive2D(static_cast<const drawinglayer::primitive2d::GlowPrimitive2D&>(rCandidate));
-                    break;
-                }
-                default :
-                {
-                    SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString(rCandidate.getPrimitive2DID()));
-                    // process recursively
-                    process(rCandidate);
-                    break;
-                }
-            }
+            processTextDecoratedPortionPrimitive2D(
+                static_cast<const primitive2d::TextSimplePortionPrimitive2D&>(rCandidate));
+            break;
         }
-
-        void VclPixelProcessor2D::processWrongSpellPrimitive2D(const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive)
+        case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D:
         {
-            if(!renderWrongSpellPrimitive2D(
-                rWrongSpellPrimitive,
-                *mpOutputDevice,
-                maCurrentTransformation,
-                maBColorModifierStack))
-            {
-                // fallback to decomposition (MetaFile)
-                process(rWrongSpellPrimitive);
-            }
+            processPolygonHairlinePrimitive2D(
+                static_cast<const primitive2d::PolygonHairlinePrimitive2D&>(rCandidate));
+            break;
         }
-
-        void VclPixelProcessor2D::processTextSimplePortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rCandidate)
+        case PRIMITIVE2D_ID_BITMAPPRIMITIVE2D:
         {
-            // Adapt evtl. used special DrawMode
-            const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
-            adaptTextToFillDrawMode();
-
-            if(getOptionsDrawinglayer().IsRenderSimpleTextDirect())
-            {
-                RenderTextSimpleOrDecoratedPortionPrimitive2D(rCandidate);
-            }
-            else
-            {
-                process(rCandidate);
-            }
-
-            // restore DrawMode
-            mpOutputDevice->SetDrawMode(nOriginalDrawMode);
+            // direct draw of transformed BitmapEx primitive
+            processBitmapPrimitive2D(
+                static_cast<const primitive2d::BitmapPrimitive2D&>(rCandidate));
+            break;
         }
-
-        void VclPixelProcessor2D::processTextDecoratedPortionPrimitive2D(const primitive2d::TextSimplePortionPrimitive2D& rCandidate)
+        case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D:
         {
-            // Adapt evtl. used special DrawMode
-            const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
-            adaptTextToFillDrawMode();
-
-            if(getOptionsDrawinglayer().IsRenderDecoratedTextDirect())
-            {
-                RenderTextSimpleOrDecoratedPortionPrimitive2D(rCandidate);
-            }
-            else
-            {
-                process(rCandidate);
-            }
-
-            // restore DrawMode
-            mpOutputDevice->SetDrawMode(nOriginalDrawMode);
+            // direct draw of fillBitmapPrimitive
+            RenderFillGraphicPrimitive2D(
+                static_cast<const primitive2d::FillGraphicPrimitive2D&>(rCandidate));
+            break;
         }
-
-        void VclPixelProcessor2D::processPolygonHairlinePrimitive2D(const primitive2d::PolygonHairlinePrimitive2D& rPolygonHairlinePrimitive2D)
+        case PRIMITIVE2D_ID_POLYPOLYGONGRADIENTPRIMITIVE2D:
         {
-            if(tryDrawPolygonHairlinePrimitive2DDirect(rPolygonHairlinePrimitive2D, 0.0))
-            {
-                return;
-            }
-
-            // direct draw of hairline
-            RenderPolygonHairlinePrimitive2D(rPolygonHairlinePrimitive2D, true);
+            processPolyPolygonGradientPrimitive2D(
+                static_cast<const primitive2d::PolyPolygonGradientPrimitive2D&>(rCandidate));
+            break;
         }
-
-        void VclPixelProcessor2D::processBitmapPrimitive2D(const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
+        case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D:
         {
-            // check if graphic content is inside discrete local ViewPort
-            const basegfx::B2DRange& rDiscreteViewPort(getViewInformation2D().getDiscreteViewport());
-            const basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation * rBitmapCandidate.getTransform());
-
-            if(!rDiscreteViewPort.isEmpty())
-            {
-                basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
-
-                aUnitRange.transform(aLocalTransform);
-
-                if(!aUnitRange.overlaps(rDiscreteViewPort))
-                {
-                    // content is outside discrete local ViewPort
-                    return;
-                }
-            }
-
-            RenderBitmapPrimitive2D(rBitmapCandidate);
+            // direct draw of bitmap
+            RenderPolyPolygonGraphicPrimitive2D(
+                static_cast<const primitive2d::PolyPolygonGraphicPrimitive2D&>(rCandidate));
+            break;
         }
-
-        void VclPixelProcessor2D::processPolyPolygonGradientPrimitive2D(const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate)
+        case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D:
         {
-            // direct draw of gradient
-            const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient());
-            basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor()));
-            basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor()));
-            basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
-
-            if(!aLocalPolyPolygon.count())
-                return;
-
-            aLocalPolyPolygon.transform(maCurrentTransformation);
-
-            if(aStartColor == aEndColor)
-            {
-                // no gradient at all, draw as polygon in AA and non-AA case
-                mpOutputDevice->SetLineColor();
-                mpOutputDevice->SetFillColor(Color(aStartColor));
-                mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
-            }
-            else
-            {
-                // use the primitive decomposition of the metafile
-                process(rPolygonCandidate);
-            }
+            processPolyPolygonColorPrimitive2D(
+                static_cast<const primitive2d::PolyPolygonColorPrimitive2D&>(rCandidate));
+            break;
         }
-
-        void VclPixelProcessor2D::processPolyPolygonColorPrimitive2D(const primitive2d::PolyPolygonColorPrimitive2D& rPolyPolygonColorPrimitive2D)
+        case PRIMITIVE2D_ID_METAFILEPRIMITIVE2D:
         {
-            // try to use directly
-            basegfx::B2DPolyPolygon aLocalPolyPolygon;
-
-            tryDrawPolyPolygonColorPrimitive2DDirect(rPolyPolygonColorPrimitive2D, 0.0);
-            // okay, done. In this case no gaps should have to be repaired, too
-
-            // when AA is on and this filled polygons are the result of stroked line geometry,
-            // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons
-            // Caution: This is needed in both cases (!)
-            if(!(mnPolygonStrokePrimitive2D
-                && getOptionsDrawinglayer().IsAntiAliasing()
-                && (mpOutputDevice->GetAntialiasing() & AntialiasingFlags::EnableB2dDraw)))
-                return;
-
-            const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPolyPolygonColorPrimitive2D.getBColor()));
-            sal_uInt32 nCount(aLocalPolyPolygon.count());
-
-            if(!nCount)
-            {
-                aLocalPolyPolygon = rPolyPolygonColorPrimitive2D.getB2DPolyPolygon();
-                aLocalPolyPolygon.transform(maCurrentTransformation);
-                nCount = aLocalPolyPolygon.count();
-            }
-
-            mpOutputDevice->SetFillColor();
-            mpOutputDevice->SetLineColor(Color(aPolygonColor));
-
-            for(sal_uInt32 a(0); a < nCount; a++)
-            {
-                mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0);
-            }
+            processMetaFilePrimitive2D(rCandidate);
+            break;
         }
-
-        void VclPixelProcessor2D::processUnifiedTransparencePrimitive2D(const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate)
+        case PRIMITIVE2D_ID_MASKPRIMITIVE2D:
         {
-            // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case,
-            // use the faster OutputDevice::DrawTransparent method
-            const primitive2d::Primitive2DContainer& rContent = rUniTransparenceCandidate.getChildren();
-
-            if(rContent.empty())
-                return;
-
-            if(0.0 == rUniTransparenceCandidate.getTransparence())
-            {
-                // not transparent at all, use content
-                process(rUniTransparenceCandidate.getChildren());
-            }
-            else if(rUniTransparenceCandidate.getTransparence() > 0.0 && rUniTransparenceCandidate.getTransparence() < 1.0)
-            {
-                bool bDrawTransparentUsed(false);
-
-                if(1 == rContent.size())
-                {
-                    const primitive2d::Primitive2DReference xReference(rContent[0]);
-                    const primitive2d::BasePrimitive2D* pBasePrimitive = dynamic_cast< const primitive2d::BasePrimitive2D* >(xReference.get());
-
-                    if(pBasePrimitive)
-                    {
-                        switch(pBasePrimitive->getPrimitive2DID())
-                        {
-                            case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D:
-                            {
-                                // single transparent tools::PolyPolygon identified, use directly
-                                const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor = static_cast< const primitive2d::PolyPolygonColorPrimitive2D* >(pBasePrimitive);
-                                SAL_WARN_IF(!pPoPoColor, "drawinglayer", "OOps, PrimitiveID and PrimitiveType do not match (!)");
-                                bDrawTransparentUsed = true;
-                                tryDrawPolyPolygonColorPrimitive2DDirect(*pPoPoColor, rUniTransparenceCandidate.getTransparence());
-                                break;
-                            }
-                            case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D:
-                            {
-                                // single transparent PolygonHairlinePrimitive2D identified, use directly
-                                const primitive2d::PolygonHairlinePrimitive2D* pPoHair = static_cast< const primitive2d::PolygonHairlinePrimitive2D* >(pBasePrimitive);
-                                SAL_WARN_IF(!pPoHair, "drawinglayer", "OOps, PrimitiveID and PrimitiveType do not match (!)");
-
-                                // do no tallow by default - problem is that self-overlapping parts of this geometry will
-                                // not be in an all-same transparency but will already alpha-cover themselves with blending.
-                                // This is not what the UnifiedTransparencePrimitive2D defines: It requires all its
-                                // content to be uniformly transparent.
-                                // For hairline the effect is pretty minimal, but still not correct.
-                                bDrawTransparentUsed = false;
-                                break;
-                            }
-                            case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
-                            {
-                                // single transparent PolygonStrokePrimitive2D identified, use directly
-                                const primitive2d::PolygonStrokePrimitive2D* pPoStroke = static_cast< const primitive2d::PolygonStrokePrimitive2D* >(pBasePrimitive);
-                                SAL_WARN_IF(!pPoStroke, "drawinglayer", "OOps, PrimitiveID and PrimitiveType do not match (!)");
-
-                                // do no tallow by default - problem is that self-overlapping parts of this geometry will
-                                // not be in an all-same transparency but will already alpha-cover themselves with blending.
-                                // This is not what the UnifiedTransparencePrimitive2D defines: It requires all its
-                                // content to be uniformly transparent.
-                                // To check, activate and draw a wide transparent self-crossing line/curve
-                                bDrawTransparentUsed = false;
-                                break;
-                            }
-                        default:
-                            SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString(rUniTransparenceCandidate.getPrimitive2DID()));
-                            break;
-                        }
-                    }
-                }
-
-                if(!bDrawTransparentUsed)
-                {
-                    // unified sub-transparence. Draw to VDev first.
-                    RenderUnifiedTransparencePrimitive2D(rUniTransparenceCandidate);
-                }
-            }
+            // mask group.
+            RenderMaskPrimitive2DPixel(
+                static_cast<const primitive2d::MaskPrimitive2D&>(rCandidate));
+            break;
         }
-
-        void VclPixelProcessor2D::processControlPrimitive2D(const primitive2d::ControlPrimitive2D& rControlPrimitive)
+        case PRIMITIVE2D_ID_MODIFIEDCOLORPRIMITIVE2D:
         {
-            // control primitive
-            const uno::Reference< awt::XControl >& rXControl(rControlPrimitive.getXControl());
-
-            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 aObjectToPixel(maCurrentTransformation * rControlPrimitive.getTransform());
-                    const basegfx::B2DPoint aTopLeftPixel(aObjectToPixel * basegfx::B2DPoint(0.0, 0.0));
-
-                    // find out if the control is already visualized as a VCL-ChildWindow. If yes,
-                    // it does not need to be painted at all.
-                    uno::Reference< awt::XWindow2 > xControlWindow(rXControl, uno::UNO_QUERY_THROW);
-                    const bool bControlIsVisibleAsChildWindow(rXControl->getPeer().is() && xControlWindow->isVisible());
-
-                    if(!bControlIsVisibleAsChildWindow)
-                    {
-                        // draw it. Do not forget to use the evtl. offsetted origin of the target device,
-                        // e.g. when used with mask/transparence buffer device
-                        const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin());
-                        xControlView->draw(
-                            aOrigin.X() + basegfx::fround(aTopLeftPixel.getX()),
-                            aOrigin.Y() + basegfx::fround(aTopLeftPixel.getY()));
-                    }
-
-                    // restore original graphics
-                    xControlView->setGraphics(xOriginalGraphics);
-                }
-            }
-            catch(const uno::Exception&)
-            {
-                // #i116763# removing since there is a good alternative when the xControlView
-                // is not found and it is allowed to happen
-                // DBG_UNHANDLED_EXCEPTION();
-
-                // process recursively and use the decomposition as Bitmap
-                process(rControlPrimitive);
-            }
+            // modified color group. Force output to unified color.
+            RenderModifiedColorPrimitive2D(
+                static_cast<const primitive2d::ModifiedColorPrimitive2D&>(rCandidate));
+            break;
         }
-
-        void VclPixelProcessor2D::processPolygonStrokePrimitive2D(const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive2D)
+        case PRIMITIVE2D_ID_UNIFIEDTRANSPARENCEPRIMITIVE2D:
         {
-            // try to use directly
-            if(tryDrawPolygonStrokePrimitive2DDirect(rPolygonStrokePrimitive2D, 0.0))
-            {
-                return;
-            }
+            processUnifiedTransparencePrimitive2D(
+                static_cast<const primitive2d::UnifiedTransparencePrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_TRANSPARENCEPRIMITIVE2D:
+        {
+            // sub-transparence group. Draw to VDev first.
+            RenderTransparencePrimitive2D(
+                static_cast<const primitive2d::TransparencePrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D:
+        {
+            // transform group.
+            RenderTransformPrimitive2D(
+                static_cast<const primitive2d::TransformPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_PAGEPREVIEWPRIMITIVE2D:
+        {
+            // new XDrawPage for ViewInformation2D
+            RenderPagePreviewPrimitive2D(
+                static_cast<const primitive2d::PagePreviewPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_MARKERARRAYPRIMITIVE2D:
+        {
+            // marker array
+            RenderMarkerArrayPrimitive2D(
+                static_cast<const primitive2d::MarkerArrayPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_POINTARRAYPRIMITIVE2D:
+        {
+            // point array
+            RenderPointArrayPrimitive2D(
+                static_cast<const primitive2d::PointArrayPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_CONTROLPRIMITIVE2D:
+        {
+            processControlPrimitive2D(
+                static_cast<const primitive2d::ControlPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
+        {
+            processPolygonStrokePrimitive2D(
+                static_cast<const primitive2d::PolygonStrokePrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_FILLHATCHPRIMITIVE2D:
+        {
+            processFillHatchPrimitive2D(
+                static_cast<const primitive2d::FillHatchPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_BACKGROUNDCOLORPRIMITIVE2D:
+        {
+            processBackgroundColorPrimitive2D(
+                static_cast<const primitive2d::BackgroundColorPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_TEXTHIERARCHYEDITPRIMITIVE2D:
+        {
+            // #i97628#
+            // This primitive means that the content is derived from an active text edit,
+            // not from model data itself. Some renderers need to suppress this content, e.g.
+            // the pixel renderer used for displaying the edit view (like this one). It's
+            // not to be suppressed by the MetaFile renderers, so that the edited text is
+            // part of the MetaFile, e.g. needed for presentation previews.
+            // Action: Ignore here, do nothing.
+            break;
+        }
+        case PRIMITIVE2D_ID_INVERTPRIMITIVE2D:
+        {
+            processInvertPrimitive2D(rCandidate);
+            break;
+        }
+        case PRIMITIVE2D_ID_EPSPRIMITIVE2D:
+        {
+            RenderEpsPrimitive2D(static_cast<const primitive2d::EpsPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_SVGLINEARATOMPRIMITIVE2D:
+        {
+            RenderSvgLinearAtomPrimitive2D(
+                static_cast<const primitive2d::SvgLinearAtomPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_SVGRADIALATOMPRIMITIVE2D:
+        {
+            RenderSvgRadialAtomPrimitive2D(
+                static_cast<const primitive2d::SvgRadialAtomPrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D:
+        {
+            processBorderLinePrimitive2D(
+                static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate));
+            break;
+        }
+        case PRIMITIVE2D_ID_GLOWPRIMITIVE2D:
+        {
+            processGlowPrimitive2D(
+                static_cast<const drawinglayer::primitive2d::GlowPrimitive2D&>(rCandidate));
+            break;
+        }
+        default:
+        {
+            SAL_INFO("drawinglayer", "default case for " << drawinglayer::primitive2d::idToString(
+                                         rCandidate.getPrimitive2DID()));
+            // process recursively
+            process(rCandidate);
+            break;
+        }
+    }
+}
 
-            // the stroke primitive may be decomposed to filled polygons. To keep
-            // evtl. set DrawModes aka DrawModeFlags::BlackLine, DrawModeFlags::GrayLine,
-            // DrawModeFlags::GhostedLine, DrawModeFlags::WhiteLine or DrawModeFlags::SettingsLine
-            // working, these need to be copied to the corresponding fill modes
-            const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
-            adaptLineToFillDrawMode();
+void VclPixelProcessor2D::processWrongSpellPrimitive2D(
+    const primitive2d::WrongSpellPrimitive2D& rWrongSpellPrimitive)
+{
+    if (!renderWrongSpellPrimitive2D(rWrongSpellPrimitive, *mpOutputDevice, maCurrentTransformation,
+                                     maBColorModifierStack))
+    {
+        // fallback to decomposition (MetaFile)
+        process(rWrongSpellPrimitive);
+    }
+}
+
+void VclPixelProcessor2D::processTextSimplePortionPrimitive2D(
+    const primitive2d::TextSimplePortionPrimitive2D& rCandidate)
+{
+    // Adapt evtl. used special DrawMode
+    const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
+    adaptTextToFillDrawMode();
+
+    if (getOptionsDrawinglayer().IsRenderSimpleTextDirect())
+    {
+        RenderTextSimpleOrDecoratedPortionPrimitive2D(rCandidate);
+    }
+    else
+    {
+        process(rCandidate);
+    }
+
+    // restore DrawMode
+    mpOutputDevice->SetDrawMode(nOriginalDrawMode);
+}
+
+void VclPixelProcessor2D::processTextDecoratedPortionPrimitive2D(
+    const primitive2d::TextSimplePortionPrimitive2D& rCandidate)
+{
+    // Adapt evtl. used special DrawMode
+    const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
+    adaptTextToFillDrawMode();
+
+    if (getOptionsDrawinglayer().IsRenderDecoratedTextDirect())
+    {
+        RenderTextSimpleOrDecoratedPortionPrimitive2D(rCandidate);
+    }
+    else
+    {
+        process(rCandidate);
+    }
+
+    // restore DrawMode
+    mpOutputDevice->SetDrawMode(nOriginalDrawMode);
+}
+
+void VclPixelProcessor2D::processPolygonHairlinePrimitive2D(
+    const primitive2d::PolygonHairlinePrimitive2D& rPolygonHairlinePrimitive2D)
+{
+    if (tryDrawPolygonHairlinePrimitive2DDirect(rPolygonHairlinePrimitive2D, 0.0))
+    {
+        return;
+    }
 
-            // polygon stroke primitive
+    // direct draw of hairline
+    RenderPolygonHairlinePrimitive2D(rPolygonHairlinePrimitive2D, true);
+}
 
-            // Lines with 1 and 2 pixel width without AA need special treatment since their visualization
-            // as filled polygons is geometrically correct but looks wrong since polygon filling avoids
-            // the right and bottom pixels. The used method evaluates that and takes the correct action,
-            // including calling recursively with decomposition if line is wide enough
-            RenderPolygonStrokePrimitive2D(rPolygonStrokePrimitive2D);
+void VclPixelProcessor2D::processBitmapPrimitive2D(
+    const primitive2d::BitmapPrimitive2D& rBitmapCandidate)
+{
+    // check if graphic content is inside discrete local ViewPort
+    const basegfx::B2DRange& rDiscreteViewPort(getViewInformation2D().getDiscreteViewport());
+    const basegfx::B2DHomMatrix aLocalTransform(maCurrentTransformation
+                                                * rBitmapCandidate.getTransform());
 
-            // restore DrawMode
-            mpOutputDevice->SetDrawMode(nOriginalDrawMode);
-        }
+    if (!rDiscreteViewPort.isEmpty())
+    {
+        basegfx::B2DRange aUnitRange(0.0, 0.0, 1.0, 1.0);
 
-        void VclPixelProcessor2D::processFillHatchPrimitive2D(const primitive2d::FillHatchPrimitive2D& rFillHatchPrimitive)
-        {
-            if(getOptionsDrawinglayer().IsAntiAliasing())
-            {
-                // if AA is used (or ignore smoothing is on), there is no need to smooth
-                // hatch painting, use decomposition
-                process(rFillHatchPrimitive);
-            }
-            else
-            {
-                // without AA, use VCL to draw the hatch. It snaps hatch distances to the next pixel
-                // and forces hatch distance to be >= 3 pixels to make the hatch display look smoother.
-                // This is wrong in principle, but looks nicer. This could also be done here directly
-                // without VCL usage if needed
-                const attribute::FillHatchAttribute& rFillHatchAttributes = rFillHatchPrimitive.getFillHatch();
-
-                // create hatch polygon in range size and discrete coordinates
-                basegfx::B2DRange aHatchRange(rFillHatchPrimitive.getOutputRange());
-                aHatchRange.transform(maCurrentTransformation);
-                const basegfx::B2DPolygon aHatchPolygon(basegfx::utils::createPolygonFromRect(aHatchRange));
-
-                if(rFillHatchAttributes.isFillBackground())
-                {
-                    // #i111846# background fill is active; draw fill polygon
-                    const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor()));
+        aUnitRange.transform(aLocalTransform);
 
-                    mpOutputDevice->SetFillColor(Color(aPolygonColor));
-                    mpOutputDevice->SetLineColor();
-                    mpOutputDevice->DrawPolygon(aHatchPolygon);
-                }
+        if (!aUnitRange.overlaps(rDiscreteViewPort))
+        {
+            // content is outside discrete local ViewPort
+            return;
+        }
+    }
 
-                // set hatch line color
-                const basegfx::BColor aHatchColor(maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor()));
-                mpOutputDevice->SetFillColor();
-                mpOutputDevice->SetLineColor(Color(aHatchColor));
+    RenderBitmapPrimitive2D(rBitmapCandidate);
+}
 
-                // get hatch style
-                HatchStyle eHatchStyle(HatchStyle::Single);
+void VclPixelProcessor2D::processPolyPolygonGradientPrimitive2D(
+    const primitive2d::PolyPolygonGradientPrimitive2D& rPolygonCandidate)
+{
+    // direct draw of gradient
+    const attribute::FillGradientAttribute& rGradient(rPolygonCandidate.getFillGradient());
+    basegfx::BColor aStartColor(maBColorModifierStack.getModifiedColor(rGradient.getStartColor()));
+    basegfx::BColor aEndColor(maBColorModifierStack.getModifiedColor(rGradient.getEndColor()));
+    basegfx::B2DPolyPolygon aLocalPolyPolygon(rPolygonCandidate.getB2DPolyPolygon());
+
+    if (!aLocalPolyPolygon.count())
+        return;
+
+    aLocalPolyPolygon.transform(maCurrentTransformation);
+
+    if (aStartColor == aEndColor)
+    {
+        // no gradient at all, draw as polygon in AA and non-AA case
+        mpOutputDevice->SetLineColor();
+        mpOutputDevice->SetFillColor(Color(aStartColor));
+        mpOutputDevice->DrawPolyPolygon(aLocalPolyPolygon);
+    }
+    else
+    {
+        // use the primitive decomposition of the metafile
+        process(rPolygonCandidate);
+    }
+}
+
+void VclPixelProcessor2D::processPolyPolygonColorPrimitive2D(
+    const primitive2d::PolyPolygonColorPrimitive2D& rPolyPolygonColorPrimitive2D)
+{
+    // try to use directly
+    basegfx::B2DPolyPolygon aLocalPolyPolygon;
+
+    tryDrawPolyPolygonColorPrimitive2DDirect(rPolyPolygonColorPrimitive2D, 0.0);
+    // okay, done. In this case no gaps should have to be repaired, too
+
+    // when AA is on and this filled polygons are the result of stroked line geometry,
+    // draw the geometry once extra as lines to avoid AA 'gaps' between partial polygons
+    // Caution: This is needed in both cases (!)
+    if (!(mnPolygonStrokePrimitive2D && getOptionsDrawinglayer().IsAntiAliasing()
+          && (mpOutputDevice->GetAntialiasing() & AntialiasingFlags::EnableB2dDraw)))
+        return;
+
+    const basegfx::BColor aPolygonColor(
+        maBColorModifierStack.getModifiedColor(rPolyPolygonColorPrimitive2D.getBColor()));
+    sal_uInt32 nCount(aLocalPolyPolygon.count());
+
+    if (!nCount)
+    {
+        aLocalPolyPolygon = rPolyPolygonColorPrimitive2D.getB2DPolyPolygon();
+        aLocalPolyPolygon.transform(maCurrentTransformation);
+        nCount = aLocalPolyPolygon.count();
+    }
+
+    mpOutputDevice->SetFillColor();
+    mpOutputDevice->SetLineColor(Color(aPolygonColor));
+
+    for (sal_uInt32 a(0); a < nCount; a++)
+    {
+        mpOutputDevice->DrawPolyLine(aLocalPolyPolygon.getB2DPolygon(a), 0.0);
+    }
+}
+
+void VclPixelProcessor2D::processUnifiedTransparencePrimitive2D(
+    const primitive2d::UnifiedTransparencePrimitive2D& rUniTransparenceCandidate)
+{
+    // Detect if a single PolyPolygonColorPrimitive2D is contained; in that case,
+    // use the faster OutputDevice::DrawTransparent method
+    const primitive2d::Primitive2DContainer& rContent = rUniTransparenceCandidate.getChildren();
+
+    if (rContent.empty())
+        return;
+
+    if (0.0 == rUniTransparenceCandidate.getTransparence())
+    {
+        // not transparent at all, use content
+        process(rUniTransparenceCandidate.getChildren());
+    }
+    else if (rUniTransparenceCandidate.getTransparence() > 0.0
+             && rUniTransparenceCandidate.getTransparence() < 1.0)
+    {
+        bool bDrawTransparentUsed(false);
+
+        if (1 == rContent.size())
+        {
+            const primitive2d::Primitive2DReference xReference(rContent[0]);
+            const primitive2d::BasePrimitive2D* pBasePrimitive
+                = dynamic_cast<const primitive2d::BasePrimitive2D*>(xReference.get());
 
-                switch(rFillHatchAttributes.getStyle())
+            if (pBasePrimitive)
+            {
+                switch (pBasePrimitive->getPrimitive2DID())
                 {
-                    default : // HatchStyle::Single
+                    case PRIMITIVE2D_ID_POLYPOLYGONCOLORPRIMITIVE2D:
                     {
+                        // single transparent tools::PolyPolygon identified, use directly
+                        const primitive2d::PolyPolygonColorPrimitive2D* pPoPoColor
+                            = static_cast<const primitive2d::PolyPolygonColorPrimitive2D*>(
+                                pBasePrimitive);
+                        SAL_WARN_IF(!pPoPoColor, "drawinglayer",
+                                    "OOps, PrimitiveID and PrimitiveType do not match (!)");
+                        bDrawTransparentUsed = true;
+                        tryDrawPolyPolygonColorPrimitive2DDirect(
+                            *pPoPoColor, rUniTransparenceCandidate.getTransparence());
                         break;
                     }
-                    case attribute::HatchStyle::Double :
+                    case PRIMITIVE2D_ID_POLYGONHAIRLINEPRIMITIVE2D:
                     {
-                        eHatchStyle = HatchStyle::Double;
+                        // single transparent PolygonHairlinePrimitive2D identified, use directly
+                        const primitive2d::PolygonHairlinePrimitive2D* pPoHair
+                            = static_cast<const primitive2d::PolygonHairlinePrimitive2D*>(
+                                pBasePrimitive);
+                        SAL_WARN_IF(!pPoHair, "drawinglayer",
+                                    "OOps, PrimitiveID and PrimitiveType do not match (!)");
+
+                        // do no tallow by default - problem is that self-overlapping parts of this geometry will
+                        // not be in an all-same transparency but will already alpha-cover themselves with blending.
+                        // This is not what the UnifiedTransparencePrimitive2D defines: It requires all its
+                        // content to be uniformly transparent.
+                        // For hairline the effect is pretty minimal, but still not correct.
+                        bDrawTransparentUsed = false;
                         break;
                     }
-                    case attribute::HatchStyle::Triple :
+                    case PRIMITIVE2D_ID_POLYGONSTROKEPRIMITIVE2D:
                     {
-                        eHatchStyle = HatchStyle::Triple;
+                        // single transparent PolygonStrokePrimitive2D identified, use directly
+                        const primitive2d::PolygonStrokePrimitive2D* pPoStroke
+                            = static_cast<const primitive2d::PolygonStrokePrimitive2D*>(
+                                pBasePrimitive);
+                        SAL_WARN_IF(!pPoStroke, "drawinglayer",
+                                    "OOps, PrimitiveID and PrimitiveType do not match (!)");
+
+                        // do no tallow by default - problem is that self-overlapping parts of this geometry will
+                        // not be in an all-same transparency but will already alpha-cover themselves with blending.
+                        // This is not what the UnifiedTransparencePrimitive2D defines: It requires all its
+                        // content to be uniformly transparent.
+                        // To check, activate and draw a wide transparent self-crossing line/curve
+                        bDrawTransparentUsed = false;
                         break;
                     }
+                    default:
+                        SAL_INFO("drawinglayer",
+                                 "default case for " << drawinglayer::primitive2d::idToString(
+                                     rUniTransparenceCandidate.getPrimitive2DID()));
+                        break;
                 }
-
-                // create hatch
-                const basegfx::B2DVector aDiscreteDistance(maCurrentTransformation * basegfx::B2DVector(rFillHatchAttributes.getDistance(), 0.0));
-                const sal_uInt32 nDistance(basegfx::fround(aDiscreteDistance.getLength()));
-                const sal_uInt16 nAngle10(static_cast<sal_uInt16>(basegfx::fround(rFillHatchAttributes.getAngle() / F_PI1800)));
-                ::Hatch aVCLHatch(eHatchStyle, Color(rFillHatchAttributes.getColor()), nDistance, nAngle10);
-
-                // draw hatch using VCL
-                mpOutputDevice->DrawHatch(::tools::PolyPolygon(::tools::Polygon(aHatchPolygon)), aVCLHatch);
             }
         }
 
-        void VclPixelProcessor2D::processBackgroundColorPrimitive2D(const primitive2d::BackgroundColorPrimitive2D& rPrimitive)
+        if (!bDrawTransparentUsed)
         {
-            // #i98404# Handle directly, especially when AA is active
-            const AntialiasingFlags nOriginalAA(mpOutputDevice->GetAntialiasing());
+            // unified sub-transparence. Draw to VDev first.
+            RenderUnifiedTransparencePrimitive2D(rUniTransparenceCandidate);
+        }
+    }
+}
 
-            // switch AA off in all cases
-            mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing() & ~AntialiasingFlags::EnableB2dDraw);
+void VclPixelProcessor2D::processControlPrimitive2D(
+    const primitive2d::ControlPrimitive2D& rControlPrimitive)
+{
+    // control primitive
+    const uno::Reference<awt::XControl>& rXControl(rControlPrimitive.getXControl());
 
-            // create color for fill
-            const basegfx::BColor aPolygonColor(maBColorModifierStack.getModifiedColor(rPrimitive.getBColor()));
-            Color aFillColor(aPolygonColor);
-            aFillColor.SetTransparency(sal_uInt8((rPrimitive.getTransparency() * 255.0) + 0.5));
-            mpOutputDevice->SetFillColor(aFillColor);
-            mpOutputDevice->SetLineColor();
+    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());
 
-            // create rectangle for fill
-            const basegfx::B2DRange& aViewport(getViewInformation2D().getDiscreteViewport());
-            const ::tools::Rectangle aRectangle(
-                static_cast<sal_Int32>(floor(aViewport.getMinX())), static_cast<sal_Int32>(floor(aViewport.getMinY())),
-                static_cast<sal_Int32>(ceil(aViewport.getMaxX())), static_cast<sal_Int32>(ceil(aViewport.getMaxY())));
-            mpOutputDevice->DrawRect(aRectangle);
-
-            // restore AA setting
-            mpOutputDevice->SetAntialiasing(nOriginalAA);
-        }
-
-        void VclPixelProcessor2D::processBorderLinePrimitive2D(const drawinglayer::primitive2d::BorderLinePrimitive2D& rBorder)
-        {
-            // Process recursively, but switch off AntiAliasing for
-            // horizontal/vertical lines (*not* diagonal lines).
-            // Checked using AntialiasingFlags::PixelSnapHairline instead,
-            // but with AntiAliasing on the display really is too 'ghosty' when
-            // using fine stroking. Correct, but 'ghosty'.
-
-            // It has shown that there are quite some problems here:
-            // - vcl OutDev renderer methods still use fallbacks to paint
-            //   multiple single lines between discrete sizes of < 3.5 what
-            //   looks bad and does not match
-            // - mix of filled Polygons and Lines is bad when AA switched off
-            // - Alignment of AA with non-AA may be bad in diverse different
-            //   renderers
-            //
-            // Due to these reasons I change the strategy: Always draw AAed, but
-            // allow fallback to test/check and if needed. The normal case
-            // where BorderLines will be system-dependently snapped to have at
-            // least a single discrete width per partial line (there may be up to
-            // three) works well nowadays due to most renderers moving the AA stuff
-            // by 0.5 pixels (discrete units) to match well with the non-AAed parts.
-            //
-            // Env-Switch for steering this, default is off.
-            // Enable by setting at all (and to something)
-            static const char* pSwitchOffAntiAliasingForHorVerBorderlines(getenv("SAL_SWITCH_OFF_ANTIALIASING_FOR_HOR_VER_BORTDERLINES"));
-            static bool bSwitchOffAntiAliasingForHorVerBorderlines(nullptr != pSwitchOffAntiAliasingForHorVerBorderlines);
-
-            if (bSwitchOffAntiAliasingForHorVerBorderlines && rBorder.isHorizontalOrVertical(getViewInformation2D()))
-            {
-                AntialiasingFlags nAntiAliasing = mpOutputDevice->GetAntialiasing();
-                mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::EnableB2dDraw);
-                process(rBorder);
-                mpOutputDevice->SetAntialiasing(nAntiAliasing);
-            }
-            else
+        if (xNewGraphics.is())
+        {
+            // link graphics and view
+            xControlView->setGraphics(xNewGraphics);
+
+            // get position
+            const basegfx::B2DHomMatrix aObjectToPixel(maCurrentTransformation
+                                                       * rControlPrimitive.getTransform());
+            const basegfx::B2DPoint aTopLeftPixel(aObjectToPixel * basegfx::B2DPoint(0.0, 0.0));
+
+            // find out if the control is already visualized as a VCL-ChildWindow. If yes,
+            // it does not need to be painted at all.
+            uno::Reference<awt::XWindow2> xControlWindow(rXControl, uno::UNO_QUERY_THROW);
+            const bool bControlIsVisibleAsChildWindow(rXControl->getPeer().is()
+                                                      && xControlWindow->isVisible());
+
+            if (!bControlIsVisibleAsChildWindow)
             {
-                process(rBorder);
+                // draw it. Do not forget to use the evtl. offsetted origin of the target device,
+                // e.g. when used with mask/transparence buffer device
+                const Point aOrigin(mpOutputDevice->GetMapMode().GetOrigin());
+                xControlView->draw(aOrigin.X() + basegfx::fround(aTopLeftPixel.getX()),
+                                   aOrigin.Y() + basegfx::fround(aTopLeftPixel.getY()));
             }
-        }
 
-        void VclPixelProcessor2D::processInvertPrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+            // restore original graphics
+            xControlView->setGraphics(xOriginalGraphics);
+        }
+    }
+    catch (const uno::Exception&)
+    {
+        // #i116763# removing since there is a good alternative when the xControlView
+        // is not found and it is allowed to happen
+        // DBG_UNHANDLED_EXCEPTION();
+
+        // process recursively and use the decomposition as Bitmap
+        process(rControlPrimitive);
+    }
+}
+
+void VclPixelProcessor2D::processPolygonStrokePrimitive2D(
+    const primitive2d::PolygonStrokePrimitive2D& rPolygonStrokePrimitive2D)
+{
+    // try to use directly
+    if (tryDrawPolygonStrokePrimitive2DDirect(rPolygonStrokePrimitive2D, 0.0))
+    {
+        return;
+    }
+
+    // the stroke primitive may be decomposed to filled polygons. To keep
+    // evtl. set DrawModes aka DrawModeFlags::BlackLine, DrawModeFlags::GrayLine,
+    // DrawModeFlags::GhostedLine, DrawModeFlags::WhiteLine or DrawModeFlags::SettingsLine
+    // working, these need to be copied to the corresponding fill modes
+    const DrawModeFlags nOriginalDrawMode(mpOutputDevice->GetDrawMode());
+    adaptLineToFillDrawMode();
+
+    // polygon stroke primitive
+
+    // Lines with 1 and 2 pixel width without AA need special treatment since their visualization
+    // as filled polygons is geometrically correct but looks wrong since polygon filling avoids
+    // the right and bottom pixels. The used method evaluates that and takes the correct action,
+    // including calling recursively with decomposition if line is wide enough
+    RenderPolygonStrokePrimitive2D(rPolygonStrokePrimitive2D);
+
+    // restore DrawMode
+    mpOutputDevice->SetDrawMode(nOriginalDrawMode);
+}
+
+void VclPixelProcessor2D::processFillHatchPrimitive2D(
+    const primitive2d::FillHatchPrimitive2D& rFillHatchPrimitive)
+{
+    if (getOptionsDrawinglayer().IsAntiAliasing())
+    {
+        // if AA is used (or ignore smoothing is on), there is no need to smooth
+        // hatch painting, use decomposition
+        process(rFillHatchPrimitive);
+    }
+    else
+    {
+        // without AA, use VCL to draw the hatch. It snaps hatch distances to the next pixel
+        // and forces hatch distance to be >= 3 pixels to make the hatch display look smoother.
+        // This is wrong in principle, but looks nicer. This could also be done here directly
+        // without VCL usage if needed
+        const attribute::FillHatchAttribute& rFillHatchAttributes
+            = rFillHatchPrimitive.getFillHatch();
+
+        // create hatch polygon in range size and discrete coordinates
+        basegfx::B2DRange aHatchRange(rFillHatchPrimitive.getOutputRange());
+        aHatchRange.transform(maCurrentTransformation);
+        const basegfx::B2DPolygon aHatchPolygon(basegfx::utils::createPolygonFromRect(aHatchRange));
+
+        if (rFillHatchAttributes.isFillBackground())
         {
-            // invert primitive (currently only used for HighContrast fallback for selection in SW and SC).
-            // (Not true, also used at least for the drawing of dragged column and row boundaries in SC.)
-            // Set OutDev to XOR and switch AA off (XOR does not work with AA)
-            mpOutputDevice->Push();
-            mpOutputDevice->SetRasterOp( RasterOp::Xor );
-            const AntialiasingFlags nAntiAliasing(mpOutputDevice->GetAntialiasing());
-            mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::EnableB2dDraw);
-
-            // process content recursively
-            process(rCandidate);
+            // #i111846# background fill is active; draw fill polygon
+            const basegfx::BColor aPolygonColor(
+                maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor()));
 
-            // restore OutDev
-            mpOutputDevice->Pop();
-            mpOutputDevice->SetAntialiasing(nAntiAliasing);
+            mpOutputDevice->SetFillColor(Color(aPolygonColor));
+            mpOutputDevice->SetLineColor();
+            mpOutputDevice->DrawPolygon(aHatchPolygon);
         }
 
-        void VclPixelProcessor2D::processMetaFilePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
-        {
-            // #i98289#
-            const bool bForceLineSnap(getOptionsDrawinglayer().IsAntiAliasing() && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete());
-            const AntialiasingFlags nOldAntiAliase(mpOutputDevice->GetAntialiasing());
+        // set hatch line color
+        const basegfx::BColor aHatchColor(
+            maBColorModifierStack.getModifiedColor(rFillHatchPrimitive.getBColor()));
+        mpOutputDevice->SetFillColor();
+        mpOutputDevice->SetLineColor(Color(aHatchColor));
+
+        // get hatch style
+        HatchStyle eHatchStyle(HatchStyle::Single);
 
-            if(bForceLineSnap)
+        switch (rFillHatchAttributes.getStyle())
+        {
+            default: // HatchStyle::Single
             {
-                mpOutputDevice->SetAntialiasing(nOldAntiAliase | AntialiasingFlags::PixelSnapHairline);
+                break;
             }
-
-            process(rCandidate);
-
-            if(bForceLineSnap)
+            case attribute::HatchStyle::Double:
             {
-                mpOutputDevice->SetAntialiasing(nOldAntiAliase);
+                eHatchStyle = HatchStyle::Double;
+                break;
             }
-        }
-
-        void VclPixelProcessor2D::processGlowPrimitive2D(const primitive2d::GlowPrimitive2D& rCandidate)
-        {
-            basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D()));
-            aRange.transform(maCurrentTransformation);
-            aRange.grow(10.0);
-            impBufferDevice aBufferDevice(*mpOutputDevice, aRange);
-            if (aBufferDevice.isVisible())
+            case attribute::HatchStyle::Triple:
             {
-                // remember last OutDev and set to content
-                OutputDevice* pLastOutputDevice = mpOutputDevice;
-                mpOutputDevice = &aBufferDevice.getTransparence();
-                // paint content to virtual device
-                mpOutputDevice->Erase();
-                process(rCandidate);
-
-                // obtain result as a bitmap
-                auto bitmap = mpOutputDevice->GetBitmapEx(Point(aRange.getMinX(), aRange.getMinY()), Size(aRange.getWidth(), aRange.getHeight()));
-                constexpr double nRadius = 5.0;
-                bitmap.Scale(Size(aRange.getWidth()-nRadius, aRange.getHeight()-nRadius));
-                // use bitmap later as mask
-                auto mask = bitmap.GetBitmap();
-
-                mpOutputDevice = &aBufferDevice.getContent();
-                process(rCandidate);
-                bitmap = mpOutputDevice->GetBitmapEx(Point(aRange.getMinX(), aRange.getMinY()), Size(aRange.getWidth(), aRange.getHeight()));
-                bitmap.Scale(Size(aRange.getWidth()-nRadius, aRange.getHeight()-nRadius));
-
-                // calculate blurry effect
-                BitmapFilterStackBlur glowFilter(nRadius);
-                BitmapFilter::Filter(bitmap, glowFilter);
-                // back to old OutDev
-                mpOutputDevice = pLastOutputDevice;
-                mpOutputDevice->DrawBitmapEx(Point(aRange.getMinX()-nRadius/2, aRange.getMinY()-nRadius/2), BitmapEx(bitmap.GetBitmap(), mask));
-
-                // paint result
-                //aBufferDevice.paint();
+                eHatchStyle = HatchStyle::Triple;
+                break;
             }
-            else
-                SAL_WARN("drawinglayer", "Temporary buffered virtual device is not visible");
         }
+
+        // create hatch
+        const basegfx::B2DVector aDiscreteDistance(
+            maCurrentTransformation * basegfx::B2DVector(rFillHatchAttributes.getDistance(), 0.0));
+        const sal_uInt32 nDistance(basegfx::fround(aDiscreteDistance.getLength()));
+        const sal_uInt16 nAngle10(
+            static_cast<sal_uInt16>(basegfx::fround(rFillHatchAttributes.getAngle() / F_PI1800)));
+        ::Hatch aVCLHatch(eHatchStyle, Color(rFillHatchAttributes.getColor()), nDistance, nAngle10);
+
+        // draw hatch using VCL
+        mpOutputDevice->DrawHatch(::tools::PolyPolygon(::tools::Polygon(aHatchPolygon)), aVCLHatch);
+    }
+}
+
+void VclPixelProcessor2D::processBackgroundColorPrimitive2D(
+    const primitive2d::BackgroundColorPrimitive2D& rPrimitive)
+{
+    // #i98404# Handle directly, especially when AA is active
+    const AntialiasingFlags nOriginalAA(mpOutputDevice->GetAntialiasing());
+
+    // switch AA off in all cases
+    mpOutputDevice->SetAntialiasing(mpOutputDevice->GetAntialiasing()
+                                    & ~AntialiasingFlags::EnableB2dDraw);
+
+    // create color for fill
+    const basegfx::BColor aPolygonColor(
+        maBColorModifierStack.getModifiedColor(rPrimitive.getBColor()));
+    Color aFillColor(aPolygonColor);
+    aFillColor.SetTransparency(sal_uInt8((rPrimitive.getTransparency() * 255.0) + 0.5));
+    mpOutputDevice->SetFillColor(aFillColor);
+    mpOutputDevice->SetLineColor();
+
+    // create rectangle for fill
+    const basegfx::B2DRange& aViewport(getViewInformation2D().getDiscreteViewport());
+    const ::tools::Rectangle aRectangle(static_cast<sal_Int32>(floor(aViewport.getMinX())),
+                                        static_cast<sal_Int32>(floor(aViewport.getMinY())),
+                                        static_cast<sal_Int32>(ceil(aViewport.getMaxX())),
+                                        static_cast<sal_Int32>(ceil(aViewport.getMaxY())));
+    mpOutputDevice->DrawRect(aRectangle);
+
+    // restore AA setting
+    mpOutputDevice->SetAntialiasing(nOriginalAA);
+}
+
+void VclPixelProcessor2D::processBorderLinePrimitive2D(
+    const drawinglayer::primitive2d::BorderLinePrimitive2D& rBorder)
+{
+    // Process recursively, but switch off AntiAliasing for
+    // horizontal/vertical lines (*not* diagonal lines).
+    // Checked using AntialiasingFlags::PixelSnapHairline instead,
+    // but with AntiAliasing on the display really is too 'ghosty' when
+    // using fine stroking. Correct, but 'ghosty'.
+
+    // It has shown that there are quite some problems here:
+    // - vcl OutDev renderer methods still use fallbacks to paint
+    //   multiple single lines between discrete sizes of < 3.5 what
+    //   looks bad and does not match
+    // - mix of filled Polygons and Lines is bad when AA switched off
+    // - Alignment of AA with non-AA may be bad in diverse different
+    //   renderers
+    //
+    // Due to these reasons I change the strategy: Always draw AAed, but
+    // allow fallback to test/check and if needed. The normal case
+    // where BorderLines will be system-dependently snapped to have at
+    // least a single discrete width per partial line (there may be up to
+    // three) works well nowadays due to most renderers moving the AA stuff
+    // by 0.5 pixels (discrete units) to match well with the non-AAed parts.
+    //
+    // Env-Switch for steering this, default is off.
+    // Enable by setting at all (and to something)
+    static const char* pSwitchOffAntiAliasingForHorVerBorderlines(
+        getenv("SAL_SWITCH_OFF_ANTIALIASING_FOR_HOR_VER_BORTDERLINES"));
+    static bool bSwitchOffAntiAliasingForHorVerBorderlines(
+        nullptr != pSwitchOffAntiAliasingForHorVerBorderlines);
+
+    if (bSwitchOffAntiAliasingForHorVerBorderlines
+        && rBorder.isHorizontalOrVertical(getViewInformation2D()))
+    {
+        AntialiasingFlags nAntiAliasing = mpOutputDevice->GetAntialiasing();
+        mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::EnableB2dDraw);
+        process(rBorder);
+        mpOutputDevice->SetAntialiasing(nAntiAliasing);
+    }
+    else
+    {
+        process(rBorder);
+    }
+}
+
+void VclPixelProcessor2D::processInvertPrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+{
+    // invert primitive (currently only used for HighContrast fallback for selection in SW and SC).
+    // (Not true, also used at least for the drawing of dragged column and row boundaries in SC.)
+    // Set OutDev to XOR and switch AA off (XOR does not work with AA)
+    mpOutputDevice->Push();
+    mpOutputDevice->SetRasterOp(RasterOp::Xor);
+    const AntialiasingFlags nAntiAliasing(mpOutputDevice->GetAntialiasing());
+    mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::EnableB2dDraw);
+
+    // process content recursively
+    process(rCandidate);
+
+    // restore OutDev
+    mpOutputDevice->Pop();
+    mpOutputDevice->SetAntialiasing(nAntiAliasing);
+}
+
+void VclPixelProcessor2D::processMetaFilePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
+{
+    // #i98289#
+    const bool bForceLineSnap(getOptionsDrawinglayer().IsAntiAliasing()
+                              && getOptionsDrawinglayer().IsSnapHorVerLinesToDiscrete());
+    const AntialiasingFlags nOldAntiAliase(mpOutputDevice->GetAntialiasing());
+
+    if (bForceLineSnap)
+    {
+        mpOutputDevice->SetAntialiasing(nOldAntiAliase | AntialiasingFlags::PixelSnapHairline);
+    }
+
+    process(rCandidate);
+
+    if (bForceLineSnap)
+    {
+        mpOutputDevice->SetAntialiasing(nOldAntiAliase);
+    }
+}
+
+void VclPixelProcessor2D::processGlowPrimitive2D(const primitive2d::GlowPrimitive2D& rCandidate)
+{
+    basegfx::B2DRange aRange(rCandidate.getB2DRange(getViewInformation2D()));
+    aRange.transform(maCurrentTransformation);
+    aRange.grow(10.0);
+    impBufferDevice aBufferDevice(*mpOutputDevice, aRange);
+    if (aBufferDevice.isVisible())
+    {
+        // remember last OutDev and set to content
+        OutputDevice* pLastOutputDevice = mpOutputDevice;
+        mpOutputDevice = &aBufferDevice.getTransparence();
+        // paint content to virtual device
+        mpOutputDevice->Erase();
+        process(rCandidate);
+
+        // obtain result as a bitmap
+        auto bitmap = mpOutputDevice->GetBitmapEx(Point(aRange.getMinX(), aRange.getMinY()),
+                                                  Size(aRange.getWidth(), aRange.getHeight()));
+        constexpr double nRadius = 5.0;
+        bitmap.Scale(Size(aRange.getWidth() - nRadius, aRange.getHeight() - nRadius));
+        // use bitmap later as mask
+        auto mask = bitmap.GetBitmap();
+
+        mpOutputDevice = &aBufferDevice.getContent();
+        process(rCandidate);
+        bitmap = mpOutputDevice->GetBitmapEx(Point(aRange.getMinX(), aRange.getMinY()),
+                                             Size(aRange.getWidth(), aRange.getHeight()));
+        bitmap.Scale(Size(aRange.getWidth() - nRadius, aRange.getHeight() - nRadius));
+
+        // calculate blurry effect
+        BitmapFilterStackBlur glowFilter(nRadius);
+        BitmapFilter::Filter(bitmap, glowFilter);
+        // back to old OutDev
+        mpOutputDevice = pLastOutputDevice;
+        mpOutputDevice->DrawBitmapEx(
+            Point(aRange.getMinX() - nRadius / 2, aRange.getMinY() - nRadius / 2),
+            BitmapEx(bitmap.GetBitmap(), mask));
+
+        // paint result
+        //aBufferDevice.paint();
+    }
+    else
+        SAL_WARN("drawinglayer", "Temporary buffered virtual device is not visible");
+}
 } // end of namespace
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/solenv/clang-format/blacklist b/solenv/clang-format/blacklist
index 298369ee7da6..375ed4dd1647 100644
--- a/solenv/clang-format/blacklist
+++ b/solenv/clang-format/blacklist
@@ -3756,7 +3756,6 @@ drawinglayer/source/processor2d/vclhelperbufferdevice.cxx
 drawinglayer/source/processor2d/vclhelperbufferdevice.hxx
 drawinglayer/source/processor2d/vclmetafileprocessor2d.cxx
 drawinglayer/source/processor2d/vclmetafileprocessor2d.hxx
-drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
 drawinglayer/source/processor3d/baseprocessor3d.cxx
 drawinglayer/source/processor3d/cutfindprocessor3d.cxx
 drawinglayer/source/processor3d/defaultprocessor3d.cxx


More information about the Libreoffice-commits mailing list