[Libreoffice-commits] core.git: basegfx/source drawinglayer/source include/basegfx include/vcl sd/source vcl/headless vcl/inc vcl/opengl vcl/qt5 vcl/quartz vcl/source vcl/unx vcl/win

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Thu Sep 13 06:50:02 UTC 2018


 basegfx/source/polygon/b2dpolygon.cxx                          |    3 
 basegfx/source/polygon/b2dpolypolygon.cxx                      |   69 ++
 drawinglayer/source/processor2d/vclpixelprocessor2d.cxx        |    8 
 include/basegfx/polygon/b2dpolypolygon.hxx                     |   20 
 include/vcl/outdev.hxx                                         |    7 
 sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx |    1 
 vcl/headless/svpgdi.cxx                                        |  152 +++---
 vcl/inc/headless/svpgdi.hxx                                    |   10 
 vcl/inc/openglgdiimpl.hxx                                      |    6 
 vcl/inc/qt5/Qt5Graphics.hxx                                    |    3 
 vcl/inc/quartz/salgdi.h                                        |    5 
 vcl/inc/salgdi.hxx                                             |   12 
 vcl/inc/salgdiimpl.hxx                                         |    6 
 vcl/inc/svdata.hxx                                             |    6 
 vcl/inc/unx/genpspgraphics.h                                   |    8 
 vcl/inc/unx/salgdi.h                                           |    5 
 vcl/inc/win/salgdi.h                                           |    5 
 vcl/opengl/gdiimpl.cxx                                         |   28 +
 vcl/qt5/Qt5Graphics_GDI.cxx                                    |    9 
 vcl/quartz/salgdicommon.cxx                                    |   14 
 vcl/source/app/scheduler.cxx                                   |    2 
 vcl/source/app/svdata.cxx                                      |  132 +++++
 vcl/source/app/svmain.cxx                                      |    6 
 vcl/source/gdi/salgdilayout.cxx                                |  175 +------
 vcl/source/outdev/line.cxx                                     |   10 
 vcl/source/outdev/polygon.cxx                                  |   67 +-
 vcl/source/outdev/polyline.cxx                                 |   28 -
 vcl/source/outdev/transparent.cxx                              |   45 +
 vcl/unx/generic/gdi/gdiimpl.cxx                                |   27 -
 vcl/unx/generic/gdi/gdiimpl.hxx                                |    6 
 vcl/unx/generic/gdi/salgdi.cxx                                 |   21 
 vcl/unx/generic/print/genpspgraphics.cxx                       |    5 
 vcl/win/gdi/gdiimpl.cxx                                        |  238 ++++++----
 vcl/win/gdi/gdiimpl.hxx                                        |    6 
 vcl/win/gdi/salbmp.cxx                                         |    2 
 vcl/win/gdi/salgdi_gdiplus.cxx                                 |   10 
 36 files changed, 733 insertions(+), 424 deletions(-)

New commits:
commit 7034311dce663c895577267110baadbec312d491
Author:     Armin Le Grand <Armin.Le.Grand at cib.de>
AuthorDate: Thu Sep 6 18:15:02 2018 +0200
Commit:     Armin Le Grand <Armin.Le.Grand at cib.de>
CommitDate: Thu Sep 13 08:49:35 2018 +0200

    Support buffering SystemDependent GraphicData (II)
    
    In this step I have changed all calls that use a
    B2DPolyPolygon and do filled graphics, added support for
    providing needed transformation which will -if supported-
    be used. Added buffering of SystemDependentData at
    B2DPolyPolygon for that purpose, see comments describing
    the current possibilities in the Gdiplus implementation.
    
    Moved lifetime creation/cleanup of SystemDependentDataManager
    to ImplSVData due to cleanup problems in the clang build
    
    Tried to use a std::unique_ptr to hold the instance
    of a SystemDependentDataBuffer at ImplSVData and cleanup
    inside DeInitVCL() right before ::ImplDeInitScheduler. This
    works in principle, but scheduler shutdown triggers
    ProcessEventsToIdle which leads to repaints and re-creates
    the buffer. Will now do exactly as was done with GdiPlusBuffer
    before, a simple local static incarnation and a call to
    SetStatic() in constructor
    
    Splitted SystemDependentDataBuffer and Timer due to
    different LifeTimes. Timer needs to be destructed
    earlier than SystemDependentDataBuffer, before
    Scheduler::ImplDeInitScheduler() is called from
    DeInitVCL()
    
    Change-Id: I2134e4346a183a4cee1be3428c51541cc8867c11
    Reviewed-on: https://gerrit.libreoffice.org/60102
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <Armin.Le.Grand at cib.de>

diff --git a/basegfx/source/polygon/b2dpolygon.cxx b/basegfx/source/polygon/b2dpolygon.cxx
index c94f262d6600..3638424a52e4 100644
--- a/basegfx/source/polygon/b2dpolygon.cxx
+++ b/basegfx/source/polygon/b2dpolygon.cxx
@@ -467,7 +467,8 @@ private:
 
 public:
     ImplBufferedData()
-    :   mpDefaultSubdivision(),
+    :   basegfx::SystemDependentDataHolder(),
+        mpDefaultSubdivision(),
         mpB2DRange()
     {
     }
diff --git a/basegfx/source/polygon/b2dpolypolygon.cxx b/basegfx/source/polygon/b2dpolypolygon.cxx
index a1ac5301c178..0901eafee63b 100644
--- a/basegfx/source/polygon/b2dpolypolygon.cxx
+++ b/basegfx/source/polygon/b2dpolypolygon.cxx
@@ -22,22 +22,63 @@
 #include <basegfx/polygon/b2dpolygon.hxx>
 #include <basegfx/polygon/b2dpolypolygontools.hxx>
 #include <basegfx/matrix/b2dhommatrix.hxx>
-
+#include <basegfx/utils/systemdependentdata.hxx>
 #include <functional>
 #include <algorithm>
 
 class ImplB2DPolyPolygon
 {
-    basegfx::B2DPolygonVector                   maPolygons;
+    basegfx::B2DPolygonVector                               maPolygons;
+    std::unique_ptr< basegfx::SystemDependentDataHolder >   mpSystemDependentDataHolder;
 
 public:
-    ImplB2DPolyPolygon() : maPolygons()
+    ImplB2DPolyPolygon()
+    :   maPolygons(),
+        mpSystemDependentDataHolder()
+    {
+    }
+
+    explicit ImplB2DPolyPolygon(const ImplB2DPolyPolygon& rSource)
+    :   maPolygons(rSource.maPolygons),
+        mpSystemDependentDataHolder()
+    {
+    }
+
+    explicit ImplB2DPolyPolygon(const basegfx::B2DPolygon& rToBeCopied)
+    :   maPolygons(1,rToBeCopied),
+        mpSystemDependentDataHolder()
+    {
+    }
+
+    ImplB2DPolyPolygon& operator=(const ImplB2DPolyPolygon& rSource)
+    {
+        if (this != &rSource)
+        {
+            maPolygons = rSource.maPolygons;
+            mpSystemDependentDataHolder.reset();
+        }
+
+        return *this;
+    }
+
+    void addOrReplaceSystemDependentData(basegfx::SystemDependentData_SharedPtr& rData)
     {
+        if(!mpSystemDependentDataHolder)
+        {
+            mpSystemDependentDataHolder.reset(new basegfx::SystemDependentDataHolder());
+        }
+
+        mpSystemDependentDataHolder->addOrReplaceSystemDependentData(rData);
     }
 
-    explicit ImplB2DPolyPolygon(const basegfx::B2DPolygon& rToBeCopied) :
-        maPolygons(1,rToBeCopied)
+    basegfx::SystemDependentData_SharedPtr getSystemDependentData(size_t hash_code) const
     {
+        if(!mpSystemDependentDataHolder)
+        {
+            return basegfx::SystemDependentData_SharedPtr();
+        }
+
+        return mpSystemDependentDataHolder->getSystemDependentData(hash_code);
     }
 
     bool operator==(const ImplB2DPolyPolygon& rPolygonList) const
@@ -385,6 +426,24 @@ namespace basegfx
     {
         return mpPolyPolygon->end();
     }
+
+    void B2DPolyPolygon::addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr& rData) const
+    {
+        // Need to get ImplB2DPolyPolygon* from cow_wrapper *without*
+        // calling make_unique() here - we do not want to
+        // 'modify' the ImplB2DPolyPolygon, but add buffered data that
+        // is valid for all referencing instances
+        const B2DPolyPolygon* pMe(this);
+        const ImplB2DPolyPolygon* pMyImpl(pMe->mpPolyPolygon.get());
+
+        const_cast<ImplB2DPolyPolygon*>(pMyImpl)->addOrReplaceSystemDependentData(rData);
+    }
+
+    SystemDependentData_SharedPtr B2DPolyPolygon::getSystemDependantDataInternal(size_t hash_code) const
+    {
+        return mpPolyPolygon->getSystemDependentData(hash_code);
+    }
+
 } // end of namespace basegfx
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index 3295a97129f3..002ae53c6560 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -107,9 +107,7 @@ namespace drawinglayer
 
         void VclPixelProcessor2D::tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency)
         {
-            basegfx::B2DPolyPolygon aLocalPolyPolygon(rSource.getB2DPolyPolygon());
-
-            if(!aLocalPolyPolygon.count())
+            if(!rSource.getB2DPolyPolygon().count())
             {
                 // no geometry, done
                 return;
@@ -119,9 +117,9 @@ namespace drawinglayer
 
             mpOutputDevice->SetFillColor(Color(aPolygonColor));
             mpOutputDevice->SetLineColor();
-            aLocalPolyPolygon.transform(maCurrentTransformation);
             mpOutputDevice->DrawTransparent(
-                aLocalPolyPolygon,
+                maCurrentTransformation,
+                rSource.getB2DPolyPolygon(),
                 fTransparency);
         }
 
diff --git a/include/basegfx/polygon/b2dpolypolygon.hxx b/include/basegfx/polygon/b2dpolypolygon.hxx
index fff49fb86c45..65e3b97cfc96 100644
--- a/include/basegfx/polygon/b2dpolypolygon.hxx
+++ b/include/basegfx/polygon/b2dpolypolygon.hxx
@@ -126,6 +126,26 @@ namespace basegfx
         const B2DPolygon* end() const;
         B2DPolygon* begin();
         B2DPolygon* end();
+
+        // exclusive management op's for SystemDependentData at B2DPolygon
+        template<class T>
+        std::shared_ptr<T> getSystemDependentData() const
+        {
+            return std::static_pointer_cast<T>(getSystemDependantDataInternal(typeid(T).hash_code()));
+        }
+
+        template<class T, class... Args>
+        std::shared_ptr<T> addOrReplaceSystemDependentData(SystemDependentDataManager& manager, Args&&... args) const
+        {
+            std::shared_ptr<T> r = std::make_shared<T>(manager, std::forward<Args>(args)...);
+            basegfx::SystemDependentData_SharedPtr r2(r);
+            addOrReplaceSystemDependentDataInternal(r2);
+            return r;
+        }
+
+    private:
+        void addOrReplaceSystemDependentDataInternal(SystemDependentData_SharedPtr& rData) const;
+        SystemDependentData_SharedPtr getSystemDependantDataInternal(size_t hash_code) const;
     };
 
     // typedef for a vector of B2DPolyPolygons
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index f015f52488d8..13ac5a5d05d4 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -1611,7 +1611,12 @@ public:
 
 
     void                        DrawTransparent( const tools::PolyPolygon& rPolyPoly, sal_uInt16 nTransparencePercent );
-    void                        DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency);
+
+    void                        DrawTransparent(
+                                    const basegfx::B2DHomMatrix& rObjectTransform,
+                                    const basegfx::B2DPolyPolygon& rB2DPolyPoly,
+                                    double fTransparency);
+
     void                        DrawTransparent(
                                         const GDIMetaFile& rMtf, const Point& rPos, const Size& rSize,
                                         const Gradient& rTransparenceGradient );
diff --git a/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx b/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx
index 5615003f89ec..af3fa0a2566e 100644
--- a/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx
+++ b/sd/source/ui/slidesorter/view/SlsInsertionIndicatorOverlay.cxx
@@ -215,6 +215,7 @@ Point InsertionIndicatorOverlay::PaintRepresentatives (
         rContent.SetFillColor(COL_BLACK);
         rContent.SetLineColor();
         rContent.DrawTransparent(
+            basegfx::B2DHomMatrix(),
             ::basegfx::B2DPolyPolygon(::basegfx::utils::createPolygonFromRect(
                 ::basegfx::B2DRectangle(aBox.Left(), aBox.Top(), aBox.Right()+1, aBox.Bottom()+1),
                 0,
diff --git a/vcl/headless/svpgdi.cxx b/vcl/headless/svpgdi.cxx
index 5acd288e8787..56bd740dbe40 100644
--- a/vcl/headless/svpgdi.cxx
+++ b/vcl/headless/svpgdi.cxx
@@ -714,7 +714,10 @@ void SvpSalGraphics::drawPixel( long nX, long nY, Color nColor )
     m_aLineColor = SALCOLOR_NONE;
     m_aFillColor = nColor;
 
-    drawPolyPolygon(basegfx::B2DPolyPolygon(aRect));
+    drawPolyPolygon(
+        basegfx::B2DHomMatrix(),
+        basegfx::B2DPolyPolygon(aRect),
+        0.0);
 
     m_aFillColor = aOrigFillColor;
     m_aLineColor = aOrigLineColor;
@@ -732,7 +735,12 @@ void SvpSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
     {
         basegfx::B2DPolygon aRect = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle(nX, nY, nX+nWidth, nY+nHeight));
         m_aFillColor = aOrigFillColor;
-        drawPolyPolygon(basegfx::B2DPolyPolygon(aRect));
+
+        drawPolyPolygon(
+            basegfx::B2DHomMatrix(),
+            basegfx::B2DPolyPolygon(aRect),
+            0.0);
+
         m_aFillColor = SALCOLOR_NONE;
     }
 
@@ -741,7 +749,12 @@ void SvpSalGraphics::drawRect( long nX, long nY, long nWidth, long nHeight )
         // need same -1 hack as X11SalGraphicsImpl::drawRect
         basegfx::B2DPolygon aRect = basegfx::utils::createPolygonFromRect(basegfx::B2DRectangle( nX, nY, nX+nWidth-1, nY+nHeight-1));
         m_aLineColor = aOrigLineColor;
-        drawPolyPolygon(basegfx::B2DPolyPolygon(aRect));
+
+        drawPolyPolygon(
+            basegfx::B2DHomMatrix(),
+            basegfx::B2DPolyPolygon(aRect),
+            0.0);
+
         m_aLineColor = SALCOLOR_NONE;
     }
 
@@ -775,7 +788,10 @@ void SvpSalGraphics::drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry)
     for (sal_uInt32 i = 1; i < nPoints; ++i)
         aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY));
 
-    drawPolyPolygon(basegfx::B2DPolyPolygon(aPoly));
+    drawPolyPolygon(
+        basegfx::B2DHomMatrix(),
+        basegfx::B2DPolyPolygon(aPoly),
+        0.0);
 }
 
 void SvpSalGraphics::drawPolyPolygon(sal_uInt32 nPoly,
@@ -798,7 +814,10 @@ void SvpSalGraphics::drawPolyPolygon(sal_uInt32 nPoly,
         }
     }
 
-    drawPolyPolygon(aPolyPoly);
+    drawPolyPolygon(
+        basegfx::B2DHomMatrix(),
+        aPolyPoly,
+        0.0);
 }
 
 basegfx::B2DPoint impPixelSnap(
@@ -1061,7 +1080,7 @@ bool SvpSalGraphics::drawPolyLine(
     bool bPixelSnapHairline)
 {
     // short circuit if there is nothing to do
-    if(0 == rPolyLine.count())
+    if(0 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0)
     {
         return true;
     }
@@ -1111,7 +1130,7 @@ bool SvpSalGraphics::drawPolyLine(
     bool bPixelSnapHairline)
 {
     // short circuit if there is nothing to do
-    if(0 == rPolyLine.count())
+    if(0 == rPolyLine.count() || fTransparency < 0.0 || fTransparency >= 1.0)
     {
         return true;
     }
@@ -1283,7 +1302,7 @@ bool SvpSalGraphics::drawPolyLine(
 
         // copy and add to buffering mechanism
         pSystemDependentData_CairoPath = rPolyLine.addOrReplaceSystemDependentData<SystemDependentData_CairoPath>(
-            SalGraphics::getSystemDependentDataManager(),
+            ImplGetSystemDependentDataManager(),
             cairo_copy_path(cr));
 
         // fill data of buffered data
@@ -1337,36 +1356,68 @@ bool SvpSalGraphics::drawPolyPolygonBezier( sal_uInt32,
     return false;
 }
 
-void SvpSalGraphics::setupPolyPolygon(cairo_t* cr, const basegfx::B2DPolyPolygon& rPolyPoly)
-{
-    clipRegion(cr);
-
-    for (const auto & rPoly : rPolyPoly)
-    {
-        // PixelOffset used: Was dependent of 'm_aLineColor != SALCOLOR_NONE'
-        // Adapt setupPolyPolygon-users to set a linear transformation to achieve PixelOffset
-        AddPolygonToPath(
-            cr,
-            rPoly,
-            basegfx::B2DHomMatrix(),
-            !getAntiAliasB2DDraw(),
-            false);
-    }
-}
-
-bool SvpSalGraphics::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPoly, double fTransparency)
+bool SvpSalGraphics::drawPolyPolygon(
+    const basegfx::B2DHomMatrix& rObjectToDevice,
+    const basegfx::B2DPolyPolygon& rPolyPolygon,
+    double fTransparency)
 {
     const bool bHasFill(m_aFillColor != SALCOLOR_NONE);
     const bool bHasLine(m_aLineColor != SALCOLOR_NONE);
 
-    if(0 == rPolyPoly.count() || !(bHasFill || bHasLine))
+    if(0 == rPolyPolygon.count() || !(bHasFill || bHasLine) || fTransparency < 0.0 || fTransparency >= 1.0)
     {
         return true;
     }
 
     cairo_t* cr = getCairoContext(true);
+    clipRegion(cr);
+
+    // Set full (Object-to-Device) transformation - if used
+    if(!rObjectToDevice.isIdentity())
+    {
+        cairo_matrix_t aMatrix;
+
+        cairo_matrix_init(
+            &aMatrix,
+            rObjectToDevice.get( 0, 0 ),
+            rObjectToDevice.get( 1, 0 ),
+            rObjectToDevice.get( 0, 1 ),
+            rObjectToDevice.get( 1, 1 ),
+            rObjectToDevice.get( 0, 2 ),
+            rObjectToDevice.get( 1, 2 ));
+        cairo_set_matrix(cr, &aMatrix);
+    }
 
-    setupPolyPolygon(cr, rPolyPoly);
+    // try to access buffered data
+    std::shared_ptr<SystemDependentData_CairoPath> pSystemDependentData_CairoPath(
+        rPolyPolygon.getSystemDependentData<SystemDependentData_CairoPath>());
+
+    if(pSystemDependentData_CairoPath)
+    {
+        // re-use data
+        cairo_append_path(cr, pSystemDependentData_CairoPath->getCairoPath());
+    }
+    else
+    {
+        // create data
+        for (const auto & rPoly : rPolyPolygon)
+        {
+            // PixelOffset used: Was dependent of 'm_aLineColor != SALCOLOR_NONE'
+            // Adapt setupPolyPolygon-users to set a linear transformation to achieve PixelOffset
+            AddPolygonToPath(
+                cr,
+                rPoly,
+                rObjectToDevice,
+                !getAntiAliasB2DDraw(),
+                false);
+        }
+
+        // copy and add to buffering mechanism
+        // for decisions how/what to buffer, see Note in WinSalGraphicsImpl::drawPolyPolygon
+        pSystemDependentData_CairoPath = rPolyPolygon.addOrReplaceSystemDependentData<SystemDependentData_CairoPath>(
+            ImplGetSystemDependentDataManager(),
+            cairo_copy_path(cr));
+    }
 
     // To make releaseCairoContext work, use empty extents
     basegfx::B2DRange extents;
@@ -1426,51 +1477,6 @@ void SvpSalGraphics::applyColor(cairo_t *cr, Color aColor)
     }
 }
 
-void SvpSalGraphics::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPoly)
-{
-    const bool bHasFill(m_aFillColor != SALCOLOR_NONE);
-    const bool bHasLine(m_aLineColor != SALCOLOR_NONE);
-
-    if(0 == rPolyPoly.count() || !(bHasFill || bHasLine))
-    {
-        return;
-    }
-
-    cairo_t* cr = getCairoContext(true);
-
-    setupPolyPolygon(cr, rPolyPoly);
-
-    // To make releaseCairoContext work, use empty extents
-    basegfx::B2DRange extents;
-
-    if (bHasFill)
-    {
-        applyColor(cr, m_aFillColor);
-
-        // Get FillDamage (will be extended for LineDamage below)
-        extents = getClippedFillDamage(cr);
-
-        cairo_fill_preserve(cr);
-    }
-
-    if (bHasLine)
-    {
-        // PixelOffset used: Set PixelOffset as linear transformation
-        cairo_matrix_t aMatrix;
-        cairo_matrix_init_translate(&aMatrix, 0.5, 0.5);
-        cairo_set_matrix(cr, &aMatrix);
-
-        applyColor(cr, m_aLineColor);
-
-        // expand with possible StrokeDamage
-        extents.expand(getClippedStrokeDamage(cr));
-
-        cairo_stroke_preserve(cr);
-    }
-
-    releaseCairoContext(cr, true, extents);
-}
-
 void SvpSalGraphics::copyArea( long nDestX,
                                long nDestY,
                                long nSrcX,
diff --git a/vcl/inc/headless/svpgdi.hxx b/vcl/inc/headless/svpgdi.hxx
index 158c331eded6..9c7ee0391f47 100644
--- a/vcl/inc/headless/svpgdi.hxx
+++ b/vcl/inc/headless/svpgdi.hxx
@@ -122,9 +122,8 @@ private:
     void copySource(const SalTwoRect& rTR, cairo_surface_t* source);
     void copyWithOperator(const SalTwoRect& rTR, cairo_surface_t* source,
                           cairo_operator_t eOp = CAIRO_OPERATOR_SOURCE);
-    void setupPolyPolygon(cairo_t* cr, const basegfx::B2DPolyPolygon& rPolyPoly);
     void applyColor(cairo_t *cr, Color rColor);
-    void drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPoly);
+
 protected:
     vcl::Region                         m_aClipRegion;
     SvpCairoTextRender                  m_aTextRenderImpl;
@@ -200,7 +199,12 @@ public:
     virtual void            drawPixel( long nX, long nY, Color nColor ) override;
     virtual void            drawLine( long nX1, long nY1, long nX2, long nY2 ) override;
     virtual void            drawRect( long nX, long nY, long nWidth, long nHeight ) override;
-    virtual bool            drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override;
+
+    virtual bool            drawPolyPolygon(
+                                const basegfx::B2DHomMatrix& rObjectToDevice,
+                                const basegfx::B2DPolyPolygon&,
+                                double fTransparency ) override;
+
     virtual bool            drawPolyLine(
                                 const basegfx::B2DHomMatrix& rObjectToDevice,
                                 const basegfx::B2DPolygon&,
diff --git a/vcl/inc/openglgdiimpl.hxx b/vcl/inc/openglgdiimpl.hxx
index f2fd9b7819dd..bc19dcd338fb 100644
--- a/vcl/inc/openglgdiimpl.hxx
+++ b/vcl/inc/openglgdiimpl.hxx
@@ -249,7 +249,11 @@ public:
     virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override;
 
     virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override;
-    virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override;
+
+    virtual bool drawPolyPolygon(
+                const basegfx::B2DHomMatrix& rObjectToDevice,
+                const basegfx::B2DPolyPolygon&,
+                double fTransparency) override;
 
     virtual bool drawPolyLine(
                 const basegfx::B2DHomMatrix& rObjectToDevice,
diff --git a/vcl/inc/qt5/Qt5Graphics.hxx b/vcl/inc/qt5/Qt5Graphics.hxx
index 6bde41ffa27f..76c39146728c 100644
--- a/vcl/inc/qt5/Qt5Graphics.hxx
+++ b/vcl/inc/qt5/Qt5Graphics.hxx
@@ -108,7 +108,8 @@ public:
     virtual void drawPolygon(sal_uInt32 nPoints, const SalPoint* pPtAry) override;
     virtual void drawPolyPolygon(sal_uInt32 nPoly, const sal_uInt32* pPoints,
                                  PCONSTSALPOINT* pPtAry) override;
-    virtual bool drawPolyPolygon(const basegfx::B2DPolyPolygon&, double fTransparency) override;
+    virtual bool drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice,
+                                 const basegfx::B2DPolyPolygon&, double fTransparency) override;
     virtual bool drawPolyLineBezier(sal_uInt32 nPoints, const SalPoint* pPtAry,
                                     const PolyFlags* pFlgAry) override;
     virtual bool drawPolygonBezier(sal_uInt32 nPoints, const SalPoint* pPtAry,
diff --git a/vcl/inc/quartz/salgdi.h b/vcl/inc/quartz/salgdi.h
index b03fa5b6b3b2..24b5268493de 100644
--- a/vcl/inc/quartz/salgdi.h
+++ b/vcl/inc/quartz/salgdi.h
@@ -224,7 +224,10 @@ public:
     virtual void            drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) override;
     virtual void            drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override;
     virtual void            drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override;
-    virtual bool            drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override;
+    virtual bool            drawPolyPolygon(
+                                const basegfx::B2DHomMatrix& rObjectToDevice,
+                                const basegfx::B2DPolyPolygon&,
+                                double fTransparency) override;
     virtual bool            drawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry ) override;
     virtual bool            drawPolygonBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry ) override;
     virtual bool            drawPolyPolygonBezier( sal_uInt32 nPoly, const sal_uInt32* pPoints, const SalPoint* const* pPtAry, const PolyFlags* const* pFlgAry ) override;
diff --git a/vcl/inc/salgdi.hxx b/vcl/inc/salgdi.hxx
index 31c484885a2b..19fac921d2fb 100644
--- a/vcl/inc/salgdi.hxx
+++ b/vcl/inc/salgdi.hxx
@@ -55,7 +55,6 @@ namespace basegfx {
     class B2DVector;
     class B2DPolygon;
     class B2DPolyPolygon;
-    class SystemDependentDataManager;
 }
 
 typedef sal_Unicode sal_Ucs; // TODO: use sal_UCS4 instead of sal_Unicode
@@ -78,10 +77,6 @@ public:
 
     virtual SalGraphicsImpl*    GetImpl() const = 0;
 
-    // access to single global managing instance of a basegfx::SystemDependentDataManager,
-    // used to handle graphic data in system-dependent form
-    static basegfx::SystemDependentDataManager& getSystemDependentDataManager();
-
     /// Check that our mpImpl is OpenGL and return the context, otherwise NULL.
     rtl::Reference<OpenGLContext> GetOpenGLContext() const;
 
@@ -244,6 +239,7 @@ public:
                                     const OutputDevice *pOutDev );
 
     bool                        DrawPolyPolygon(
+                                    const basegfx::B2DHomMatrix& rObjectToDevice,
                                     const basegfx::B2DPolyPolygon &i_rPolyPolygon,
                                     double i_fTransparency,
                                     const OutputDevice *i_pOutDev);
@@ -464,7 +460,11 @@ protected:
     virtual void                drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) = 0;
 
     virtual void                drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) = 0;
-    virtual bool                drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) = 0;
+
+    virtual bool                drawPolyPolygon(
+                                    const basegfx::B2DHomMatrix& rObjectToDevice,
+                                    const basegfx::B2DPolyPolygon&,
+                                    double fTransparency) = 0;
 
     virtual bool                drawPolyLine(
                                     const basegfx::B2DHomMatrix& rObjectToDevice,
diff --git a/vcl/inc/salgdiimpl.hxx b/vcl/inc/salgdiimpl.hxx
index 8e545d093d20..d4023bd52947 100644
--- a/vcl/inc/salgdiimpl.hxx
+++ b/vcl/inc/salgdiimpl.hxx
@@ -100,7 +100,11 @@ public:
     virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) = 0;
 
     virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) = 0;
-    virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) = 0;
+
+    virtual bool drawPolyPolygon(
+        const basegfx::B2DHomMatrix& rObjectToDevice,
+        const basegfx::B2DPolyPolygon&,
+        double fTransparency) = 0;
 
     virtual bool drawPolyLine(
                 const basegfx::B2DHomMatrix& rObjectToDevice,
diff --git a/vcl/inc/svdata.hxx b/vcl/inc/svdata.hxx
index 679debce188e..6ef279586ea1 100644
--- a/vcl/inc/svdata.hxx
+++ b/vcl/inc/svdata.hxx
@@ -106,6 +106,11 @@ namespace vcl
     class Window;
 }
 
+namespace basegfx
+{
+    class SystemDependentDataManager;
+}
+
 class LocaleConfigurationListener : public utl::ConfigurationListener
 {
 public:
@@ -372,6 +377,7 @@ struct ImplSVData
 css::uno::Reference<css::i18n::XCharacterClassification> const& ImplGetCharClass();
 
 void        ImplDeInitSVData();
+VCL_PLUGIN_PUBLIC basegfx::SystemDependentDataManager& ImplGetSystemDependentDataManager();
 VCL_PLUGIN_PUBLIC vcl::Window* ImplGetDefaultWindow();
 VCL_PLUGIN_PUBLIC vcl::Window* ImplGetDefaultContextWindow();
 VCL_PLUGIN_PUBLIC const std::locale& ImplGetResLocale();
diff --git a/vcl/inc/unx/genpspgraphics.h b/vcl/inc/unx/genpspgraphics.h
index 3f6bae6c0744..bddcb888ebc6 100644
--- a/vcl/inc/unx/genpspgraphics.h
+++ b/vcl/inc/unx/genpspgraphics.h
@@ -126,8 +126,12 @@ public:
     virtual void            drawPolyPolygon( sal_uInt32 nPoly,
                                              const sal_uInt32* pPoints,
                                              PCONSTSALPOINT* pPtAry ) override;
-    virtual bool            drawPolyPolygon( const basegfx::B2DPolyPolygon&,
-                                             double fTransparency ) override;
+
+    virtual bool            drawPolyPolygon(
+                                const basegfx::B2DHomMatrix& rObjectToDevice,
+                                const basegfx::B2DPolyPolygon&,
+                                double fTransparency) override;
+
     virtual bool            drawPolyLine(
                                 const basegfx::B2DHomMatrix& rObjectToDevice,
                                 const basegfx::B2DPolygon&,
diff --git a/vcl/inc/unx/salgdi.h b/vcl/inc/unx/salgdi.h
index 8b73c4583243..d6054eae4b4c 100644
--- a/vcl/inc/unx/salgdi.h
+++ b/vcl/inc/unx/salgdi.h
@@ -160,7 +160,10 @@ public:
                                         const sal_uInt32* pPoints,
                                         PCONSTSALPOINT* pPtAry ) override;
 
-    virtual bool                    drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override;
+    virtual bool                    drawPolyPolygon(
+                                        const basegfx::B2DHomMatrix& rObjectToDevice,
+                                        const basegfx::B2DPolyPolygon&,
+                                        double fTransparency) override;
 
     virtual bool                    drawPolyLine(
                                         const basegfx::B2DHomMatrix& rObjectToDevice,
diff --git a/vcl/inc/win/salgdi.h b/vcl/inc/win/salgdi.h
index 9f30f57ecac8..e8fe72cc4ca7 100644
--- a/vcl/inc/win/salgdi.h
+++ b/vcl/inc/win/salgdi.h
@@ -221,7 +221,10 @@ protected:
     virtual void        drawPolyLine( sal_uInt32 nPoints, const SalPoint* pPtAry ) override;
     virtual void        drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override;
     virtual void        drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override;
-    virtual bool        drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override;
+    virtual bool        drawPolyPolygon(
+        const basegfx::B2DHomMatrix& rObjectToDevice,
+        const basegfx::B2DPolyPolygon&,
+        double fTransparency) override;
     virtual bool        drawPolyLine(
         const basegfx::B2DHomMatrix& rObjectToDevice,
         const basegfx::B2DPolygon&,
diff --git a/vcl/opengl/gdiimpl.cxx b/vcl/opengl/gdiimpl.cxx
index 4c966bd408ef..082c8d66b7b0 100644
--- a/vcl/opengl/gdiimpl.cxx
+++ b/vcl/opengl/gdiimpl.cxx
@@ -1567,7 +1567,10 @@ void OpenGLSalGraphicsImpl::drawPolygon( sal_uInt32 nPoints, const SalPoint* pPt
     for (sal_uInt32 i = 1; i < nPoints; ++i)
         aPoly.setB2DPoint(i, basegfx::B2DPoint(pPtAry[i].mnX, pPtAry[i].mnY));
 
-    drawPolyPolygon(basegfx::B2DPolyPolygon(aPoly), 0.0);
+    drawPolyPolygon(
+        basegfx::B2DHomMatrix(),
+        basegfx::B2DPolyPolygon(aPoly),
+        0.0);
 }
 
 void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPointCounts, PCONSTSALPOINT* pPtAry )
@@ -1589,13 +1592,30 @@ void OpenGLSalGraphicsImpl::drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32*
         }
     }
 
-    drawPolyPolygon(aPolyPoly, 0.0);
+    drawPolyPolygon(
+        basegfx::B2DHomMatrix(),
+        aPolyPoly,
+        0.0);
 }
 
-bool OpenGLSalGraphicsImpl::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency)
+bool OpenGLSalGraphicsImpl::drawPolyPolygon(
+    const basegfx::B2DHomMatrix& rObjectToDevice,
+    const basegfx::B2DPolyPolygon& rPolyPolygon,
+    double fTransparency)
 {
     VCL_GL_INFO("::drawPolyPolygon " << rPolyPolygon.getB2DRange());
-    mpRenderList->addDrawPolyPolygon(rPolyPolygon, fTransparency, mnLineColor, mnFillColor, mrParent.getAntiAliasB2DDraw());
+
+    // Fallback: Transform to DeviceCoordinates
+    basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
+    aPolyPolygon.transform(rObjectToDevice);
+
+    mpRenderList->addDrawPolyPolygon(
+        aPolyPolygon,
+        fTransparency,
+        mnLineColor,
+        mnFillColor,
+        mrParent.getAntiAliasB2DDraw());
+
     PostBatchDraw();
     return true;
 }
diff --git a/vcl/qt5/Qt5Graphics_GDI.cxx b/vcl/qt5/Qt5Graphics_GDI.cxx
index 3b8d2ee80d3c..f8ab00ea1494 100644
--- a/vcl/qt5/Qt5Graphics_GDI.cxx
+++ b/vcl/qt5/Qt5Graphics_GDI.cxx
@@ -279,7 +279,8 @@ void Qt5Graphics::drawPolyPolygon(sal_uInt32 nPolyCount, const sal_uInt32* pPoin
     aPainter.update(aPath.boundingRect());
 }
 
-bool Qt5Graphics::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPoly, double fTransparency)
+bool Qt5Graphics::drawPolyPolygon(const basegfx::B2DHomMatrix& rObjectToDevice,
+                                  const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency)
 {
     // ignore invisible polygons
     if (SALCOLOR_NONE == m_aFillColor && SALCOLOR_NONE == m_aLineColor)
@@ -287,9 +288,13 @@ bool Qt5Graphics::drawPolyPolygon(const basegfx::B2DPolyPolygon& rPolyPoly, doub
     if ((fTransparency >= 1.0) || (fTransparency < 0))
         return true;
 
+    // Fallback: Transform to DeviceCoordinates
+    basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
+    aPolyPolygon.transform(rObjectToDevice);
+
     QPainterPath aPath;
     // ignore empty polygons
-    if (!AddPolyPolygonToPath(aPath, rPolyPoly, !getAntiAliasB2DDraw(),
+    if (!AddPolyPolygonToPath(aPath, aPolyPolygon, !getAntiAliasB2DDraw(),
                               m_aLineColor != SALCOLOR_NONE))
         return true;
 
diff --git a/vcl/quartz/salgdicommon.cxx b/vcl/quartz/salgdicommon.cxx
index 09adf784d2ad..59d836506b52 100644
--- a/vcl/quartz/salgdicommon.cxx
+++ b/vcl/quartz/salgdicommon.cxx
@@ -1072,13 +1072,15 @@ bool AquaSalGraphics::drawPolyLineBezier( sal_uInt32, const SalPoint*, const Pol
     return false;
 }
 
-bool AquaSalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly,
-                                       double fTransparency )
+bool AquaSalGraphics::drawPolyPolygon(
+    const basegfx::B2DHomMatrix& rObjectToDevice,
+    const basegfx::B2DPolyPolygon& rPolyPolygon,
+    double fTransparency)
 {
     DBG_DRAW_OPERATION("drawPolyPolygon", true);
 
     // short circuit if there is nothing to do
-    const int nPolyCount = rPolyPoly.count();
+    const int nPolyCount = rPolyPolygon.count();
     if( nPolyCount <= 0 )
     {
         DBG_DRAW_OPERATION_EXIT_EARLY("drawPolyPolygon");
@@ -1092,12 +1094,16 @@ bool AquaSalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPoly,
         return true;
     }
 
+    // Fallback: Transform to DeviceCoordinates
+    basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
+    aPolyPolygon.transform(rObjectToDevice);
+
     // setup poly-polygon path
     CGMutablePathRef xPath = CGPathCreateMutable();
     SAL_INFO( "vcl.cg", "CGPathCreateMutable() = " << xPath );
     for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
     {
-        const basegfx::B2DPolygon rPolygon = rPolyPoly.getB2DPolygon( nPolyIdx );
+        const basegfx::B2DPolygon rPolygon = rPolyPolygon.getB2DPolygon( nPolyIdx );
         AddPolygonToPath( xPath, rPolygon, true, !getAntiAliasB2DDraw(), IsPenVisible() );
     }
 
diff --git a/vcl/source/app/scheduler.cxx b/vcl/source/app/scheduler.cxx
index 93fcfeca7df9..9e5c3bc8db72 100644
--- a/vcl/source/app/scheduler.cxx
+++ b/vcl/source/app/scheduler.cxx
@@ -155,7 +155,7 @@ void Scheduler::ImplDeInitScheduler()
                         || !strcmp( pTask->GetDebugName(), "svtools::GraphicCache maReleaseTimer" )
                         || !strcmp( pTask->GetDebugName(), "svtools::GraphicObject mpSwapOutTimer" )
                         || !strcmp( pTask->GetDebugName(), "svx OLEObjCache pTimer UnloadCheck" )
-                        || !strcmp( pTask->GetDebugName(), "vcl::win GdiPlusBuffer aGdiPlusBuffer" )
+                        || !strcmp( pTask->GetDebugName(), "vcl SystemDependentDataBuffer aSystemDependentDataBuffer" )
                         ))
                 {
                     sIgnored = " (ignored)";
diff --git a/vcl/source/app/svdata.cxx b/vcl/source/app/svdata.cxx
index ce3ed1393729..251da9e6b1a5 100644
--- a/vcl/source/app/svdata.cxx
+++ b/vcl/source/app/svdata.cxx
@@ -60,6 +60,9 @@
 #if HAVE_FEATURE_OPENGL
 #include <vcl/opengl/OpenGLContext.hxx>
 #endif
+#include <basegfx/utils/systemdependentdata.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <o3tl/make_unique.hxx>
 
 using namespace com::sun::star::uno;
 using namespace com::sun::star::lang;
@@ -97,6 +100,135 @@ void ImplDeInitSVData()
     pSVData->maPaperNames.clear();
 }
 
+namespace
+{
+    typedef ::std::map< basegfx::SystemDependentData_SharedPtr, sal_uInt32 > EntryMap;
+
+    class SystemDependentDataBuffer : public basegfx::SystemDependentDataManager, protected cppu::BaseMutex
+    {
+    private:
+        std::unique_ptr<Timer>  maTimer;
+        EntryMap                maEntries;
+
+        DECL_LINK(implTimeoutHdl, Timer *, void);
+
+    public:
+        SystemDependentDataBuffer(const sal_Char* pDebugName)
+        :   basegfx::SystemDependentDataManager(),
+            maTimer(o3tl::make_unique<Timer>(pDebugName)),
+            maEntries()
+        {
+            maTimer->SetTimeout(1000);
+            maTimer->SetInvokeHandler(LINK(this, SystemDependentDataBuffer, implTimeoutHdl));
+        }
+
+        virtual ~SystemDependentDataBuffer() override
+        {
+            flushAll();
+        }
+
+        void startUsage(basegfx::SystemDependentData_SharedPtr& rData) override
+        {
+            ::osl::MutexGuard aGuard(m_aMutex);
+            EntryMap::iterator aFound(maEntries.find(rData));
+
+            if(aFound == maEntries.end())
+            {
+                if(maEntries.empty() && maTimer)
+                {
+                    maTimer->Start();
+                }
+
+                maEntries[rData] = rData->getHoldCycles();
+            }
+        }
+
+        void endUsage(basegfx::SystemDependentData_SharedPtr& rData) override
+        {
+            ::osl::MutexGuard aGuard(m_aMutex);
+            EntryMap::iterator aFound(maEntries.find(rData));
+
+            if(aFound != maEntries.end())
+            {
+                maEntries.erase(aFound);
+
+                if(maEntries.empty() && maTimer)
+                {
+                    maTimer->Stop();
+                }
+            }
+        }
+
+        void touchUsage(basegfx::SystemDependentData_SharedPtr& rData) override
+        {
+            ::osl::MutexGuard aGuard(m_aMutex);
+            EntryMap::iterator aFound(maEntries.find(rData));
+
+            if(aFound != maEntries.end())
+            {
+                aFound->second = rData->getHoldCycles();
+            }
+        }
+
+        void flushAll() override
+        {
+            ::osl::MutexGuard aGuard(m_aMutex);
+            EntryMap::iterator aIter(maEntries.begin());
+
+            if(maTimer)
+            {
+                maTimer->Stop();
+                maTimer.reset();
+            }
+
+            while(aIter != maEntries.end())
+            {
+                EntryMap::iterator aDelete(aIter);
+                ++aIter;
+                maEntries.erase(aDelete);
+            }
+        }
+    };
+
+    IMPL_LINK_NOARG(SystemDependentDataBuffer, implTimeoutHdl, Timer *, void)
+    {
+        ::osl::MutexGuard aGuard(m_aMutex);
+        EntryMap::iterator aIter(maEntries.begin());
+
+        while(aIter != maEntries.end())
+        {
+            if(aIter->second)
+            {
+                aIter->second--;
+                ++aIter;
+            }
+            else
+            {
+                EntryMap::iterator aDelete(aIter);
+                ++aIter;
+                maEntries.erase(aDelete);
+
+                if(maEntries.empty() && maTimer)
+                {
+                    maTimer->Stop();
+                }
+            }
+        }
+
+        if(!maEntries.empty() && maTimer)
+        {
+            maTimer->Start();
+        }
+    }
+}
+
+basegfx::SystemDependentDataManager& ImplGetSystemDependentDataManager()
+{
+    static SystemDependentDataBuffer aSystemDependentDataBuffer("vcl SystemDependentDataBuffer aSystemDependentDataBuffer");
+
+    return aSystemDependentDataBuffer;
+}
+
 /// Returns either the application window, or the default GL context window
 vcl::Window* ImplGetDefaultWindow()
 {
diff --git a/vcl/source/app/svmain.cxx b/vcl/source/app/svmain.cxx
index beed24273e0d..b4cfa736792c 100644
--- a/vcl/source/app/svmain.cxx
+++ b/vcl/source/app/svmain.cxx
@@ -428,9 +428,6 @@ void DeInitVCL()
     }
     ImplSVData* pSVData = ImplGetSVData();
 
-    // cleanup SystemDependentData
-    SalGraphics::getSystemDependentDataManager().flushAll();
-
     // lp#1560328: clear cache before disposing rest of VCL
     if(pSVData->mpBlendFrameCache)
         pSVData->mpBlendFrameCache->m_aLastResult.Clear();
@@ -481,6 +478,9 @@ void DeInitVCL()
 
     pSVData->mpSettingsConfigItem.reset();
 
+    // empty and deactivate the SystemDependentDataManager
+    ImplGetSystemDependentDataManager().flushAll();
+
     Scheduler::ImplDeInitScheduler();
 
     pSVData->maWinData.maMsgBoxImgList.clear();
diff --git a/vcl/source/gdi/salgdilayout.cxx b/vcl/source/gdi/salgdilayout.cxx
index d39bd333a9cf..d28c751f42a9 100644
--- a/vcl/source/gdi/salgdilayout.cxx
+++ b/vcl/source/gdi/salgdilayout.cxx
@@ -31,11 +31,8 @@
 #include <salgdi.hxx>
 #include <salframe.hxx>
 #include <basegfx/numeric/ftools.hxx> //for F_PI180
-#include <basegfx/utils/systemdependentdata.hxx>
-#include <cppuhelper/basemutex.hxx>
 #include <basegfx/matrix/b2dhommatrix.hxx>
 #include <basegfx/matrix/b2dhommatrixtools.hxx>
-#include <o3tl/make_unique.hxx>
 
 // The only common SalFrame method
 
@@ -69,131 +66,6 @@ SalGraphics::~SalGraphics()
 {
 }
 
-basegfx::SystemDependentDataManager& SalGraphics::getSystemDependentDataManager()
-{
-    typedef ::std::map< basegfx::SystemDependentData_SharedPtr, sal_uInt32 > EntryMap;
-
-    class SystemDependentDataBuffer : public basegfx::SystemDependentDataManager, protected cppu::BaseMutex, public Timer
-    {
-    private:
-        EntryMap        maEntries;
-
-    public:
-        SystemDependentDataBuffer( const sal_Char *pDebugName )
-        :   basegfx::SystemDependentDataManager(),
-            Timer( pDebugName ),
-            maEntries()
-        {
-            SetTimeout(1000);
-            SetStatic();
-        }
-
-        virtual ~SystemDependentDataBuffer() override
-        {
-            Stop();
-        }
-
-        void startUsage(basegfx::SystemDependentData_SharedPtr& rData) override
-        {
-            ::osl::MutexGuard aGuard(m_aMutex);
-            EntryMap::iterator aFound(maEntries.find(rData));
-
-            if(aFound == maEntries.end())
-            {
-                if(maEntries.empty())
-                {
-                    Start();
-                }
-
-                maEntries[rData] = rData->getHoldCycles();
-            }
-        }
-
-        void endUsage(basegfx::SystemDependentData_SharedPtr& rData) override
-        {
-            ::osl::MutexGuard aGuard(m_aMutex);
-            EntryMap::iterator aFound(maEntries.find(rData));
-
-            if(aFound != maEntries.end())
-            {
-                maEntries.erase(aFound);
-
-                if(maEntries.empty())
-                {
-                    Stop();
-                }
-            }
-        }
-
-        void touchUsage(basegfx::SystemDependentData_SharedPtr& rData) override
-        {
-            ::osl::MutexGuard aGuard(m_aMutex);
-            EntryMap::iterator aFound(maEntries.find(rData));
-
-            if(aFound != maEntries.end())
-            {
-                aFound->second = rData->getHoldCycles();
-            }
-        }
-
-        void flushAll() override
-        {
-            ::osl::MutexGuard aGuard(m_aMutex);
-            EntryMap::iterator aIter(maEntries.begin());
-
-            Stop();
-
-            while(aIter != maEntries.end())
-            {
-                EntryMap::iterator aDelete(aIter);
-                ++aIter;
-                maEntries.erase(aDelete);
-            }
-        }
-
-        // from parent Timer
-        virtual void Invoke() override
-        {
-            ::osl::MutexGuard aGuard(m_aMutex);
-            EntryMap::iterator aIter(maEntries.begin());
-
-            while(aIter != maEntries.end())
-            {
-                if(aIter->second)
-                {
-                    aIter->second--;
-                    ++aIter;
-                }
-                else
-                {
-                    EntryMap::iterator aDelete(aIter);
-                    ++aIter;
-                    maEntries.erase(aDelete);
-
-                    if(maEntries.empty())
-                    {
-                        Stop();
-                    }
-                }
-            }
-
-            if(!maEntries.empty())
-            {
-                Start();
-            }
-        }
-    };
-
-    static std::unique_ptr<SystemDependentDataBuffer> aSystemDependentDataBuffer;
-
-    if(!aSystemDependentDataBuffer)
-    {
-        aSystemDependentDataBuffer = o3tl::make_unique<SystemDependentDataBuffer>(nullptr);
-    }
-
-    return *aSystemDependentDataBuffer.get();
-}
-
 #if HAVE_FEATURE_OPENGL
 
 namespace
@@ -589,17 +461,50 @@ void SalGraphics::DrawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints,
         drawPolyPolygon( nPoly, pPoints, pPtAry );
 }
 
-bool SalGraphics::DrawPolyPolygon( const basegfx::B2DPolyPolygon& i_rPolyPolygon, double i_fTransparency, const OutputDevice* i_pOutDev )
+bool SalGraphics::DrawPolyPolygon(
+    const basegfx::B2DHomMatrix& rObjectToDevice,
+    const basegfx::B2DPolyPolygon& i_rPolyPolygon,
+    double i_fTransparency,
+    const OutputDevice* i_pOutDev)
 {
-    bool bRet = false;
     if( (m_nLayout & SalLayoutFlags::BiDiRtl) || (i_pOutDev && i_pOutDev->IsRTLEnabled()) )
     {
-        basegfx::B2DPolyPolygon aMirror( mirror( i_rPolyPolygon, i_pOutDev ) );
-        bRet = drawPolyPolygon( aMirror, i_fTransparency );
+        // mirroring set
+        const basegfx::B2DHomMatrix& rMirror(getMirror(i_pOutDev));
+
+        if(!rMirror.isIdentity())
+        {
+            if(rObjectToDevice.isIdentity())
+            {
+                // There is no ObjectToDevice transformation set. We can just
+                // use rMirror, that would be the result of the linear combination
+                return drawPolyPolygon(
+                    rMirror,
+                    i_rPolyPolygon,
+                    i_fTransparency);
+            }
+            else
+            {
+                // Create the linear combination
+                basegfx::B2DHomMatrix aLinearCombination(rObjectToDevice);
+                basegfx::B2DHomMatrix aObjectToDeviceInv(rObjectToDevice);
+
+                aLinearCombination = rMirror * aLinearCombination;
+                aObjectToDeviceInv.invert();
+                aLinearCombination = aObjectToDeviceInv * aLinearCombination;
+
+                return drawPolyPolygon(
+                    aLinearCombination,
+                    i_rPolyPolygon,
+                    i_fTransparency);
+            }
+        }
     }
-    else
-        bRet = drawPolyPolygon( i_rPolyPolygon, i_fTransparency );
-    return bRet;
+
+    return drawPolyPolygon(
+        rObjectToDevice,
+        i_rPolyPolygon,
+        i_fTransparency);
 }
 
 bool SalGraphics::DrawPolyLineBezier( sal_uInt32 nPoints, const SalPoint* pPtAry, const PolyFlags* pFlgAry, const OutputDevice* pOutDev )
diff --git a/vcl/source/outdev/line.cxx b/vcl/source/outdev/line.cxx
index fe16d676c29f..fecacba8f641 100644
--- a/vcl/source/outdev/line.cxx
+++ b/vcl/source/outdev/line.cxx
@@ -133,10 +133,6 @@ void OutputDevice::DrawLine( const Point& rStartPt, const Point& rEndPt )
         aB2DPolyLine.transform( aTransform );
 
         const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
-        // if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline)
-        // {
-        //     aB2DPolyLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine);
-        // }
 
         if( mpGraphics->DrawPolyLine(
             basegfx::B2DHomMatrix(),
@@ -287,7 +283,11 @@ void OutputDevice::drawLine( basegfx::B2DPolyPolygon aLinePolyPolygon, const Lin
 
         if(bTryAA)
         {
-            bDone = mpGraphics->DrawPolyPolygon(aFillPolyPolygon, 0.0, this);
+            bDone = mpGraphics->DrawPolyPolygon(
+                basegfx::B2DHomMatrix(),
+                aFillPolyPolygon,
+                0.0,
+                this);
         }
 
         if(!bDone)
diff --git a/vcl/source/outdev/polygon.cxx b/vcl/source/outdev/polygon.cxx
index 94ad52a79dbd..1496b1a1daf8 100644
--- a/vcl/source/outdev/polygon.cxx
+++ b/vcl/source/outdev/polygon.cxx
@@ -70,17 +70,23 @@ void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& rPolyPoly )
        RasterOp::OverPaint == GetRasterOp() &&
        (IsLineColor() || IsFillColor()))
     {
-        const basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
+        const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation());
         basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPoly.getB2DPolyPolygon());
         bool bSuccess(true);
 
-        // transform the polygon and ensure closed
-        aB2DPolyPolygon.transform(aTransform);
-        aB2DPolyPolygon.setClosed(true);
+        // ensure closed - may be asserted, will prevent buffering
+        if(!aB2DPolyPolygon.isClosed())
+        {
+            aB2DPolyPolygon.setClosed(true);
+        }
 
         if(IsFillColor())
         {
-            bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this);
+            bSuccess = mpGraphics->DrawPolyPolygon(
+                aTransform,
+                aB2DPolyPolygon,
+                0.0,
+                this);
         }
 
         if(bSuccess && IsLineColor())
@@ -88,15 +94,10 @@ void OutputDevice::DrawPolyPolygon( const tools::PolyPolygon& rPolyPoly )
             const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
             const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
 
-            // if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline)
-            // {
-            //     aB2DPolyPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon);
-            // }
-
             for(sal_uInt32 a(0); bSuccess && a < aB2DPolyPolygon.count(); a++)
             {
                 bSuccess = mpGraphics->DrawPolyLine(
-                    basegfx::B2DHomMatrix(),
+                    aTransform,
                     aB2DPolyPolygon.getB2DPolygon(a),
                     0.0,
                     aB2DLineWidth,
@@ -187,17 +188,23 @@ void OutputDevice::DrawPolygon( const tools::Polygon& rPoly )
        RasterOp::OverPaint == GetRasterOp() &&
        (IsLineColor() || IsFillColor()))
     {
-        const basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
+        const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation());
         basegfx::B2DPolygon aB2DPolygon(rPoly.getB2DPolygon());
         bool bSuccess(true);
 
-        // transform the polygon and ensure closed
-        aB2DPolygon.transform(aTransform);
-        aB2DPolygon.setClosed(true);
+        // ensure closed - maybe assert, hinders bufering
+        if(!aB2DPolygon.isClosed())
+        {
+            aB2DPolygon.setClosed(true);
+        }
 
         if(IsFillColor())
         {
-            bSuccess = mpGraphics->DrawPolyPolygon(basegfx::B2DPolyPolygon(aB2DPolygon), 0.0, this);
+            bSuccess = mpGraphics->DrawPolyPolygon(
+                aTransform,
+                basegfx::B2DPolyPolygon(aB2DPolygon),
+                0.0,
+                this);
         }
 
         if(bSuccess && IsLineColor())
@@ -205,13 +212,8 @@ void OutputDevice::DrawPolygon( const tools::Polygon& rPoly )
             const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
             const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
 
-            // if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline)
-            // {
-            //     aB2DPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon);
-            // }
-
             bSuccess = mpGraphics->DrawPolyLine(
-                basegfx::B2DHomMatrix(),
+                aTransform,
                 aB2DPolygon,
                 0.0,
                 aB2DLineWidth,
@@ -298,13 +300,19 @@ void OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyP
         basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly);
         bool bSuccess(true);
 
-        // transform the polygon and ensure closed
-        aB2DPolyPolygon.transform(aTransform);
-        aB2DPolyPolygon.setClosed(true);
+        // ensure closed - maybe assert, hinders buffering
+        if(!aB2DPolyPolygon.isClosed())
+        {
+            aB2DPolyPolygon.setClosed(true);
+        }
 
         if(IsFillColor())
         {
-            bSuccess = mpGraphics->DrawPolyPolygon(aB2DPolyPolygon, 0.0, this);
+            bSuccess = mpGraphics->DrawPolyPolygon(
+                aTransform,
+                aB2DPolyPolygon,
+                0.0,
+                this);
         }
 
         if(bSuccess && IsLineColor())
@@ -312,15 +320,10 @@ void OutputDevice::ImplDrawPolyPolygonWithB2DPolyPolygon(const basegfx::B2DPolyP
             const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
             const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
 
-            // if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline)
-            // {
-            //     aB2DPolyPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyPolygon);
-            // }
-
             for(sal_uInt32 a(0);bSuccess && a < aB2DPolyPolygon.count(); a++)
             {
                 bSuccess = mpGraphics->DrawPolyLine(
-                    basegfx::B2DHomMatrix(),
+                    aTransform,
                     aB2DPolyPolygon.getB2DPolygon(a),
                     0.0,
                     aB2DLineWidth,
diff --git a/vcl/source/outdev/polyline.cxx b/vcl/source/outdev/polyline.cxx
index b5c06b9aa411..da8be42cd304 100644
--- a/vcl/source/outdev/polyline.cxx
+++ b/vcl/source/outdev/polyline.cxx
@@ -71,14 +71,6 @@ void OutputDevice::DrawPolyLine( const tools::Polygon& rPoly )
     const basegfx::B2DVector aB2DLineWidth( 1.0, 1.0 );
     const bool bPixelSnapHairline(mnAntialiasing & AntialiasingFlags::PixelSnapHairline);
 
-    // transform the polygon - do not (!)
-    // aB2DPolyLine.transform( aTransform );
-
-    // if(mnAntialiasing & AntialiasingFlags::PixelSnapHairline)
-    // {
-    //     aB2DPolyLine = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aB2DPolyLine);
-    // }
-
     if(mpGraphics->DrawPolyLine(
         aTransform,
         aB2DPolyLine,
@@ -350,27 +342,7 @@ bool OutputDevice::DrawPolyLineDirect(
         const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation() * rObjectTransform);
         const bool bLineWidthZero(basegfx::fTools::equalZero(fLineWidth));
         const basegfx::B2DVector aB2DLineWidth(bLineWidthZero ? 1.0 : fLineWidth, bLineWidthZero ? 1.0 : fLineWidth);
-
-        // transform the line width if used
-        // if( fLineWidth != 0.0 )
-        // {
-        //     aB2DLineWidth = aTransform * basegfx::B2DVector( fLineWidth, fLineWidth );
-        // }
-
-        // transform the polygon - no!
-        // basegfx::B2DPolygon aB2DPolygon(rB2DPolygon);
-        // aB2DPolygon.transform(aTransform);
-
         const bool bPixelSnapHairline((mnAntialiasing & AntialiasingFlags::PixelSnapHairline) && rB2DPolygon.count() < 1000);
-        // if((mnAntialiasing & AntialiasingFlags::PixelSnapHairline) &&
-        //    aB2DPolygon.count() < 1000)
-        // {
-        //     // #i98289#, #i101491#
-        //     // better to remove doubles on device coordinates. Also assume from a given amount
-        //     // of points that the single edges are not long enough to smooth
-        //     aB2DPolygon.removeDoublePoints();
-        //     aB2DPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aB2DPolygon);
-        // }
 
         // draw the polyline
         bool bDrawSuccess = mpGraphics->DrawPolyLine(
diff --git a/vcl/source/outdev/transparent.cxx b/vcl/source/outdev/transparent.cxx
index ecd63b642b47..5a9bd599a6ff 100644
--- a/vcl/source/outdev/transparent.cxx
+++ b/vcl/source/outdev/transparent.cxx
@@ -212,7 +212,10 @@ void OutputDevice::ImplPrintTransparent( const Bitmap& rBmp, const Bitmap& rMask
 // void OutputDevice::DrawPolyPolygon( const basegfx::B2DPolyPolygon& rB2DPolyPoly )
 // so when changes are made here do not forget to make changes there, too
 
-void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly, double fTransparency)
+void OutputDevice::DrawTransparent(
+    const basegfx::B2DHomMatrix& rObjectTransform,
+    const basegfx::B2DPolyPolygon& rB2DPolyPoly,
+    double fTransparency)
 {
     assert(!is_double_buffered_window());
 
@@ -241,16 +244,27 @@ void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly,
        (RasterOp::OverPaint == GetRasterOp()) )
     {
         // b2dpolygon support not implemented yet on non-UNX platforms
-        const basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
         basegfx::B2DPolyPolygon aB2DPolyPolygon(rB2DPolyPoly);
 
-        // transform the polygon into device space and ensure it is closed
-        aB2DPolyPolygon.transform( aTransform );
-        aB2DPolyPolygon.setClosed( true );
+        // ensure it is closed
+        if(!aB2DPolyPolygon.isClosed())
+        {
+            // maybe assert, prevents buffering due to making a copy
+            aB2DPolyPolygon.setClosed( true );
+        }
+
+        // create ObjectToDevice transformation
+        const basegfx::B2DHomMatrix aFullTransform(ImplGetDeviceTransformation() * rObjectTransform);
+        bool bDrawnOk(true);
 
-        bool bDrawnOk = true;
         if( IsFillColor() )
-            bDrawnOk = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this );
+        {
+            bDrawnOk = mpGraphics->DrawPolyPolygon(
+                aFullTransform,
+                aB2DPolyPolygon,
+                fTransparency,
+                this);
+        }
 
         if( bDrawnOk && IsLineColor() )
         {
@@ -263,7 +277,7 @@ void OutputDevice::DrawTransparent( const basegfx::B2DPolyPolygon& rB2DPolyPoly,
                 const basegfx::B2DPolygon aOnePoly(aB2DPolyPolygon.getB2DPolygon(nPolyIdx));
 
                 mpGraphics->DrawPolyLine(
-                    basegfx::B2DHomMatrix(),
+                    aFullTransform,
                     aOnePoly,
                     fTransparency,
                     aHairlineWidth,
@@ -338,9 +352,8 @@ bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly
             InitFillColor();
 
         // get the polygon in device coordinates
-        basegfx::B2DPolyPolygon aB2DPolyPolygon( rPolyPoly.getB2DPolyPolygon() );
-        const basegfx::B2DHomMatrix aTransform = ImplGetDeviceTransformation();
-        aB2DPolyPolygon.transform( aTransform );
+        basegfx::B2DPolyPolygon aB2DPolyPolygon(rPolyPoly.getB2DPolyPolygon());
+        const basegfx::B2DHomMatrix aTransform(ImplGetDeviceTransformation());
 
         const double fTransparency = 0.01 * nTransparencePercent;
         if( mbFillColor )
@@ -354,13 +367,18 @@ bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly
             // functionality and we use the fallback some lines below (which is not very good,
             // though. For now, WinSalGraphics::drawPolyPolygon will detect printer usage and
             // correct the wrong mapping (see there for details)
-            bDrawn = mpGraphics->DrawPolyPolygon( aB2DPolyPolygon, fTransparency, this );
+            bDrawn = mpGraphics->DrawPolyPolygon(
+                aTransform,
+                aB2DPolyPolygon,
+                fTransparency,
+                this);
         }
 
         if( mbLineColor )
         {
             // disable the fill color for now
             mpGraphics->SetFillColor();
+
             // draw the border line
             const basegfx::B2DVector aLineWidths( 1, 1 );
             const sal_uInt32 nPolyCount(aB2DPolyPolygon.count());
@@ -371,7 +389,7 @@ bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly
                 const basegfx::B2DPolygon aPolygon(aB2DPolyPolygon.getB2DPolygon(nPolyIdx));
 
                 bDrawn = mpGraphics->DrawPolyLine(
-                    basegfx::B2DHomMatrix(),
+                    aTransform,
                     aPolygon,
                     fTransparency,
                     aLineWidths,
@@ -381,6 +399,7 @@ bool OutputDevice::DrawTransparentNatively ( const tools::PolyPolygon& rPolyPoly
                     bPixelSnapHairline,
                     this );
             }
+
             // prepare to restore the fill color
             mbInitFillColor = mbFillColor;
         }
diff --git a/vcl/unx/generic/gdi/gdiimpl.cxx b/vcl/unx/generic/gdi/gdiimpl.cxx
index c650f9dd4dad..a5fcf86cd3a7 100644
--- a/vcl/unx/generic/gdi/gdiimpl.cxx
+++ b/vcl/unx/generic/gdi/gdiimpl.cxx
@@ -1442,10 +1442,13 @@ bool X11SalGraphicsImpl::drawEPS( long,long,long,long,void*,sal_uLong )
 }
 
 // draw a poly-polygon
-bool X11SalGraphicsImpl::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency )
+bool X11SalGraphicsImpl::drawPolyPolygon(
+    const basegfx::B2DHomMatrix& rObjectToDevice,
+    const basegfx::B2DPolyPolygon& rPolyPolygon,
+    double fTransparency)
 {
     // nothing to do for empty polypolygons
-    const int nOrigPolyCount = rOrigPolyPoly.count();
+    const int nOrigPolyCount = rPolyPolygon.count();
     if( nOrigPolyCount <= 0 )
         return true;
 
@@ -1464,21 +1467,24 @@ bool X11SalGraphicsImpl::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPo
     if( pRenderEnv )
         return false;
 
+    // Fallback: Transform to DeviceCoordinates
+    basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
+    aPolyPolygon.transform(rObjectToDevice);
+
     // snap to raster if requested
-    basegfx::B2DPolyPolygon aPolyPoly = rOrigPolyPoly;
     const bool bSnapToRaster = !mrParent.getAntiAliasB2DDraw();
     if( bSnapToRaster )
-        aPolyPoly = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges( aPolyPoly );
+        aPolyPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges( aPolyPolygon );
 
     // don't bother with polygons outside of visible area
     const basegfx::B2DRange aViewRange( 0, 0, GetGraphicsWidth(), GetGraphicsHeight() );
-    aPolyPoly = basegfx::utils::clipPolyPolygonOnRange( aPolyPoly, aViewRange, true, false );
-    if( !aPolyPoly.count() )
+    aPolyPolygon = basegfx::utils::clipPolyPolygonOnRange( aPolyPolygon, aViewRange, true, false );
+    if( !aPolyPolygon.count() )
         return true;
 
     // tessellate the polypolygon into trapezoids
     basegfx::B2DTrapezoidVector aB2DTrapVector;
-    basegfx::utils::trapezoidSubdivide( aB2DTrapVector, aPolyPoly );
+    basegfx::utils::trapezoidSubdivide( aB2DTrapVector, aPolyPolygon );
     const int nTrapCount = aB2DTrapVector.size();
     if( !nTrapCount )
         return true;
@@ -1654,7 +1660,12 @@ bool X11SalGraphicsImpl::drawPolyLine(
     for( int nPolyIdx = 0; nPolyIdx < nPolyCount; ++nPolyIdx )
     {
         const basegfx::B2DPolyPolygon aOnePoly( aAreaPolyPoly.getB2DPolygon( nPolyIdx ) );
-        bDrawnOk = drawPolyPolygon( aOnePoly, fTransparency );
+
+        bDrawnOk = drawPolyPolygon(
+            basegfx::B2DHomMatrix(),
+            aOnePoly,
+            fTransparency);
+
         if( !bDrawnOk )
             break;
     }
diff --git a/vcl/unx/generic/gdi/gdiimpl.hxx b/vcl/unx/generic/gdi/gdiimpl.hxx
index f738e1e996ea..ac80ec6f0c40 100644
--- a/vcl/unx/generic/gdi/gdiimpl.hxx
+++ b/vcl/unx/generic/gdi/gdiimpl.hxx
@@ -157,7 +157,11 @@ public:
     virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override;
 
     virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override;
-    virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override;
+
+    virtual bool drawPolyPolygon(
+                const basegfx::B2DHomMatrix& rObjectToDevice,
+                const basegfx::B2DPolyPolygon&,
+                double fTransparency) override;
 
     virtual bool drawPolyLine(
                 const basegfx::B2DHomMatrix& rObjectToDevice,
diff --git a/vcl/unx/generic/gdi/salgdi.cxx b/vcl/unx/generic/gdi/salgdi.cxx
index c6eff6d45304..632d08d1a35b 100644
--- a/vcl/unx/generic/gdi/salgdi.cxx
+++ b/vcl/unx/generic/gdi/salgdi.cxx
@@ -577,14 +577,17 @@ css::uno::Any X11SalGraphics::GetNativeSurfaceHandle(cairo::SurfaceSharedPtr& rS
 #endif // ENABLE_CAIRO_CANVAS
 
 // draw a poly-polygon
-bool X11SalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPoly, double fTransparency )
+bool X11SalGraphics::drawPolyPolygon(
+    const basegfx::B2DHomMatrix& rObjectToDevice,
+    const basegfx::B2DPolyPolygon& rPolyPolygon,
+    double fTransparency)
 {
     if(fTransparency >= 1.0)
     {
         return true;
     }
 
-    const sal_uInt32 nPolyCount(rOrigPolyPoly.count());
+    const sal_uInt32 nPolyCount(rPolyPolygon.count());
 
     if(nPolyCount <= 0)
     {
@@ -592,6 +595,10 @@ bool X11SalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPo
     }
 
 #if ENABLE_CAIRO_CANVAS
+    // Fallback: Transform to DeviceCoordinates
+    basegfx::B2DPolyPolygon aPolyPolygon(rPolyPolygon);
+    aPolyPolygon.transform(rObjectToDevice);
+
     if(SALCOLOR_NONE == mnFillColor && SALCOLOR_NONE == mnPenColor)
     {
         return true;
@@ -602,12 +609,11 @@ bool X11SalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPo
     if (!m_bOpenGL && bUseCairoForPolygons && SupportsCairo())
     {
         // snap to raster if requested
-        basegfx::B2DPolyPolygon aPolyPoly(rOrigPolyPoly);
         const bool bSnapPoints(!getAntiAliasB2DDraw());
 
         if(bSnapPoints)
         {
-            aPolyPoly = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPoly);
+            aPolyPolygon = basegfx::utils::snapPointsOfHorizontalOrVerticalEdges(aPolyPolygon);
         }
 
         cairo_t* cr = getCairoContext();
@@ -615,7 +621,7 @@ bool X11SalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPo
 
         for(sal_uInt32 a(0); a < nPolyCount; ++a)
         {
-            const basegfx::B2DPolygon aPolygon(aPolyPoly.getB2DPolygon(a));
+            const basegfx::B2DPolygon aPolygon(aPolyPolygon.getB2DPolygon(a));
             const sal_uInt32 nPointCount(aPolygon.count());
 
             if(nPointCount)
@@ -684,7 +690,10 @@ bool X11SalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rOrigPolyPo
     }
 #endif // ENABLE_CAIRO_CANVAS
 
-    return mxImpl->drawPolyPolygon( rOrigPolyPoly, fTransparency );
+    return mxImpl->drawPolyPolygon(
+        rObjectToDevice,
+        rPolyPolygon,
+        fTransparency);
 }
 
 #if ENABLE_CAIRO_CANVAS
diff --git a/vcl/unx/generic/print/genpspgraphics.cxx b/vcl/unx/generic/print/genpspgraphics.cxx
index 4ee35c8b72eb..3a8f951ea03a 100644
--- a/vcl/unx/generic/print/genpspgraphics.cxx
+++ b/vcl/unx/generic/print/genpspgraphics.cxx
@@ -404,7 +404,10 @@ void GenPspGraphics::drawPolyPolygon( sal_uInt32           nPoly,
     m_pPrinterGfx->DrawPolyPolygon (nPoly, pPoints, reinterpret_cast<const Point**>(pPtAry));
 }
 
-bool GenPspGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon&, double /*fTransparency*/ )
+bool GenPspGraphics::drawPolyPolygon(
+    const basegfx::B2DHomMatrix& /*rObjectToDevice*/,
+    const basegfx::B2DPolyPolygon&,
+    double /*fTransparency*/)
 {
         // TODO: implement and advertise OutDevSupportType::B2DDraw support
         return false;
diff --git a/vcl/win/gdi/gdiimpl.cxx b/vcl/win/gdi/gdiimpl.cxx
index 33d89b6c94e1..4dcd86a4f405 100644
--- a/vcl/win/gdi/gdiimpl.cxx
+++ b/vcl/win/gdi/gdiimpl.cxx
@@ -1951,71 +1951,6 @@ void impAddB2DPolygonToGDIPlusGraphicsPathReal(
     }
 }
 
-bool WinSalGraphicsImpl::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency)
-{
-    const sal_uInt32 nCount(rPolyPolygon.count());
-
-    if(mbBrush && nCount && (fTransparency >= 0.0 && fTransparency < 1.0))
-    {
-        Gdiplus::Graphics aGraphics(mrParent.getHDC());
-        const sal_uInt8 aTrans(sal_uInt8(255) - static_cast<sal_uInt8>(basegfx::fround(fTransparency * 255.0)));
-        const Gdiplus::Color aTestColor(aTrans, maFillColor.GetRed(), maFillColor.GetGreen(), maFillColor.GetBlue());
-        const Gdiplus::SolidBrush aSolidBrush(aTestColor.GetValue());
-        Gdiplus::GraphicsPath aGraphicsPath(Gdiplus::FillModeAlternate);
-
-        for(sal_uInt32 a(0); a < nCount; a++)
-        {
-            if(0 != a)
-            {
-                // #i101491# not needed for first run
-                aGraphicsPath.StartFigure();
-            }
-
-            impAddB2DPolygonToGDIPlusGraphicsPathReal(
-                aGraphicsPath,
-                rPolyPolygon.getB2DPolygon(a),
-                basegfx::B2DHomMatrix(),
-                false,
-                false);
-
-            aGraphicsPath.CloseFigure();
-        }
-
-        if(mrParent.getAntiAliasB2DDraw())
-        {
-            aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
-        }
-        else
-        {
-            aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
-        }
-
-        if(mrParent.isPrinter())
-        {
-            // #i121591#
-            // Normally GdiPlus should not be used for printing at all since printers cannot
-            // print transparent filled polygon geometry and normally this does not happen
-            // since OutputDevice::RemoveTransparenciesFromMetaFile is used as preparation
-            // and no transparent parts should remain for printing. But this can be overridden
-            // by the user and thus happens. This call can only come (currently) from
-            // OutputDevice::DrawTransparent, see comments there with the same TaskID.
-            // If it is used, the mapping for the printer is wrong and needs to be corrected. I
-            // checked that there is *no* transformation set and estimated that a stable factor
-            // dependent of the printer's DPI is used. Create and set a transformation here to
-            // correct this.
-            const Gdiplus::REAL aDpiX(aGraphics.GetDpiX());
-            const Gdiplus::REAL aDpiY(aGraphics.GetDpiY());
-
-            aGraphics.ResetTransform();
-            aGraphics.ScaleTransform(Gdiplus::REAL(100.0) / aDpiX, Gdiplus::REAL(100.0) / aDpiY, Gdiplus::MatrixOrderAppend);
-        }
-
-        aGraphics.FillPath(&aSolidBrush, &aGraphicsPath);
-    }
-
-     return true;
-}
-
 class SystemDependentData_GraphicsPath : public basegfx::SystemDependentData
 {
 private:
@@ -2040,6 +1975,150 @@ SystemDependentData_GraphicsPath::SystemDependentData_GraphicsPath(
 {
 }
 
+bool WinSalGraphicsImpl::drawPolyPolygon(
+    const basegfx::B2DHomMatrix& rObjectToDevice,
+    const basegfx::B2DPolyPolygon& rPolyPolygon,
+    double fTransparency)
+{
+    const sal_uInt32 nCount(rPolyPolygon.count());
+
+    if(!mbBrush || 0 == nCount || fTransparency < 0.0 || fTransparency > 1.0)
+    {
+        return true;
+    }
+
+    Gdiplus::Graphics aGraphics(mrParent.getHDC());
+    const sal_uInt8 aTrans(sal_uInt8(255) - static_cast<sal_uInt8>(basegfx::fround(fTransparency * 255.0)));
+    const Gdiplus::Color aTestColor(aTrans, maFillColor.GetRed(), maFillColor.GetGreen(), maFillColor.GetBlue());
+    const Gdiplus::SolidBrush aSolidBrush(aTestColor.GetValue());
+
+    // Set full (Object-to-Device) transformation - if used
+    if(rObjectToDevice.isIdentity())
+    {
+        aGraphics.ResetTransform();
+    }
+    else
+    {
+        Gdiplus::Matrix aMatrix;
+
+        aMatrix.SetElements(
+            rObjectToDevice.get(0, 0),
+            rObjectToDevice.get(1, 0),
+            rObjectToDevice.get(0, 1),
+            rObjectToDevice.get(1, 1),
+            rObjectToDevice.get(0, 2),
+            rObjectToDevice.get(1, 2));
+        aGraphics.SetTransform(&aMatrix);
+    }
+
+    // try to access buffered data
+    std::shared_ptr<SystemDependentData_GraphicsPath> pSystemDependentData_GraphicsPath(
+        rPolyPolygon.getSystemDependentData<SystemDependentData_GraphicsPath>());
+
+    if(!pSystemDependentData_GraphicsPath)
+    {
+        // add to buffering mechanism
+        pSystemDependentData_GraphicsPath = rPolyPolygon.addOrReplaceSystemDependentData<SystemDependentData_GraphicsPath>(
+            ImplGetSystemDependentDataManager());
+
+        // Note: In principle we could use the same buffered geometry at line
+        // and fill polygons. Checked that in a first try, used
+        // GraphicsPath::AddPath from Gdiplus combined with below used
+        // StartFigure/CloseFigure, worked well (thus the line-draw version
+        // may create non-cloded partial Polygon data).
+        //
+        // But in current reality it gets not used due to e.g.
+        // SdrPathPrimitive2D::create2DDecomposition creating transformed
+        // line and fill polygon-primitives (what could be changed).
+        //
+        // There will probably be more hindrances here in other rendering paths
+        // which could all be found - intention to do this would be: Use more
+        // transformations, less modifications of B2DPolygons/B2DPolyPolygons.
+        //
+        // A fix for SdrPathPrimitive2D would be to create the sub-geometry
+        // and embed into a TransformPrimitive2D containing the transformation.
+        //
+        // A 2nd problem is that the NoLineJoin mode (basegfx::B2DLineJoin::NONE
+        // && rLineWidths > 0.0) creates polygon fill infos that are not reusable
+        // for the fill case (see ::drawPolyLine bnelow) - thus we would need a
+        // bool and/or two system-dependent paths buffered - doable, but complicated.
+        //
+        // All in all: Make B2DPolyPolygon a SystemDependentDataProvider and buffer
+        // the whole to-be-filled PolyPolygon independent from evtl. line-polygon
+        // (at least for now...)
+
+        // create data
+        for(sal_uInt32 a(0); a < nCount; a++)
+        {
+            if(0 != a)
+            {
+                // #i101491# not needed for first run
+                pSystemDependentData_GraphicsPath->getGraphicsPath().StartFigure();
+            }
+
+            impAddB2DPolygonToGDIPlusGraphicsPathReal(
+                pSystemDependentData_GraphicsPath->getGraphicsPath(),
+                rPolyPolygon.getB2DPolygon(a),
+                rObjectToDevice, // not used due to the two 'false' values below, but to not forget later
+                false,
+                false);
+
+            pSystemDependentData_GraphicsPath->getGraphicsPath().CloseFigure();
+        }
+    }
+
+    if(mrParent.getAntiAliasB2DDraw())
+    {
+        aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeAntiAlias);
+    }
+    else
+    {
+        aGraphics.SetSmoothingMode(Gdiplus::SmoothingModeNone);
+    }
+
+    if(mrParent.isPrinter())
+    {
+        // #i121591#
+        // Normally GdiPlus should not be used for printing at all since printers cannot
+        // print transparent filled polygon geometry and normally this does not happen
+        // since OutputDevice::RemoveTransparenciesFromMetaFile is used as preparation
+        // and no transparent parts should remain for printing. But this can be overridden
+        // by the user and thus happens. This call can only come (currently) from
+        // OutputDevice::DrawTransparent, see comments there with the same TaskID.
+        // If it is used, the mapping for the printer is wrong and needs to be corrected. I
+        // checked that there is *no* transformation set and estimated that a stable factor
+        // dependent of the printer's DPI is used. Create and set a transformation here to
+        // correct this.
+        const Gdiplus::REAL aDpiX(aGraphics.GetDpiX());
+        const Gdiplus::REAL aDpiY(aGraphics.GetDpiY());
+
+        // Now the transformation maybe/is already used (see above), so do
+        // modify it without resetting to not destroy it.
+        // I double-checked with MS docu that Gdiplus::MatrixOrderAppend does what
+        // we need - in our notation, would be a multiply from left to execute
+        // current transform first and this scale last.
+        // I tried to trigger this code using Print from the menu and various
+        // targets, but got no hit, thus maybe obsolete anyways. If someone knows
+        // more, feel free to remove it.
+        // One more hint: This *may* also be needed now in ::drawPolyLine below
+        // since it also uses transformations now.
+        //
+        // aGraphics.ResetTransform();
+
+        aGraphics.ScaleTransform(
+            Gdiplus::REAL(100.0) / aDpiX,
+            Gdiplus::REAL(100.0) / aDpiY,
+            Gdiplus::MatrixOrderAppend);
+    }
+
+    // use created or buffered data
+    aGraphics.FillPath(
+        &aSolidBrush,
+        &pSystemDependentData_GraphicsPath->getGraphicsPath());
+
+    return true;
+}
+
 bool WinSalGraphicsImpl::drawPolyLine(
     const basegfx::B2DHomMatrix& rObjectToDevice,
     const basegfx::B2DPolygon& rPolygon,
@@ -2062,15 +2141,24 @@ bool WinSalGraphicsImpl::drawPolyLine(
     bool bNoLineJoin(false);
     Gdiplus::Matrix aMatrix;
 
-    // Set full (Object-to-Device) transformation
-    aMatrix.SetElements(
-        rObjectToDevice.get(0, 0),
-        rObjectToDevice.get(1, 0),
-        rObjectToDevice.get(0, 1),
-        rObjectToDevice.get(1, 1),
-        rObjectToDevice.get(0, 2),
-        rObjectToDevice.get(1, 2));
-    aGraphics.SetTransform(&aMatrix);
+    // Set full (Object-to-Device) transformation - if used
+    if(rObjectToDevice.isIdentity())
+    {
+        aGraphics.ResetTransform();
+    }
+    else
+    {
+        Gdiplus::Matrix aMatrix;
+
+        aMatrix.SetElements(
+            rObjectToDevice.get(0, 0),
+            rObjectToDevice.get(1, 0),
+            rObjectToDevice.get(0, 1),
+            rObjectToDevice.get(1, 1),
+            rObjectToDevice.get(0, 2),
+            rObjectToDevice.get(1, 2));
+        aGraphics.SetTransform(&aMatrix);
+    }
 
     switch(eLineJoin)
     {
@@ -2145,7 +2233,7 @@ bool WinSalGraphicsImpl::drawPolyLine(
     {
         // add to buffering mechanism
         pSystemDependentData_GraphicsPath = rPolygon.addOrReplaceSystemDependentData<SystemDependentData_GraphicsPath>(
-            SalGraphics::getSystemDependentDataManager());
+            ImplGetSystemDependentDataManager());
 
         // fill data of buffered data
         pSystemDependentData_GraphicsPath->setPixelSnapHairline(bPixelSnapHairline);
diff --git a/vcl/win/gdi/gdiimpl.hxx b/vcl/win/gdi/gdiimpl.hxx
index 83d4125207a2..94a6de0e1e44 100644
--- a/vcl/win/gdi/gdiimpl.hxx
+++ b/vcl/win/gdi/gdiimpl.hxx
@@ -106,7 +106,11 @@ public:
     virtual void drawPolygon( sal_uInt32 nPoints, const SalPoint* pPtAry ) override;
 
     virtual void drawPolyPolygon( sal_uInt32 nPoly, const sal_uInt32* pPoints, PCONSTSALPOINT* pPtAry ) override;
-    virtual bool drawPolyPolygon( const basegfx::B2DPolyPolygon&, double fTransparency ) override;
+
+    virtual bool drawPolyPolygon(
+                const basegfx::B2DHomMatrix& rObjectToDevice,
+                const basegfx::B2DPolyPolygon&,
+                double fTransparency) override;
 
     virtual bool drawPolyLine(
                 const basegfx::B2DHomMatrix& rObjectToDevice,
diff --git a/vcl/win/gdi/salbmp.cxx b/vcl/win/gdi/salbmp.cxx
index b61103e17067..664eedb6d269 100644
--- a/vcl/win/gdi/salbmp.cxx
+++ b/vcl/win/gdi/salbmp.cxx
@@ -146,7 +146,7 @@ std::shared_ptr< Gdiplus::Bitmap > WinSalBitmap::ImplGetGdiPlusBitmap(const WinS
     {
         // add to buffering mechanism
         pSystemDependentData_GdiPlusBitmap = addOrReplaceSystemDependentData<SystemDependentData_GdiPlusBitmap>(
-            SalGraphics::getSystemDependentDataManager());
+            ImplGetSystemDependentDataManager());
 
         // create and set data
         if(pAlphaSource)
diff --git a/vcl/win/gdi/salgdi_gdiplus.cxx b/vcl/win/gdi/salgdi_gdiplus.cxx
index 1f536e1843e6..99c7d0e506e9 100644
--- a/vcl/win/gdi/salgdi_gdiplus.cxx
+++ b/vcl/win/gdi/salgdi_gdiplus.cxx
@@ -26,9 +26,15 @@
 
 #include "gdiimpl.hxx"
 
-bool WinSalGraphics::drawPolyPolygon( const basegfx::B2DPolyPolygon& rPolyPolygon, double fTransparency)
+bool WinSalGraphics::drawPolyPolygon(
+    const basegfx::B2DHomMatrix& rObjectToDevice,
+    const basegfx::B2DPolyPolygon& rPolyPolygon,
+    double fTransparency)
 {
-    return mpImpl->drawPolyPolygon( rPolyPolygon, fTransparency );
+    return mpImpl->drawPolyPolygon(
+        rObjectToDevice,
+        rPolyPolygon,
+        fTransparency);
 }
 
 bool WinSalGraphics::drawPolyLine(


More information about the Libreoffice-commits mailing list