cppcanvas/source/mtfrenderer/implrenderer.cxx |    5 
 filter/source/svg/svgwriter.cxx               |    8 
 include/vcl/gradient.hxx                      |    9 
 include/vcl/outdev.hxx                        |   10 
 sc/inc/unonames.hxx                           |    1 
 sc/source/ui/unoobj/confuno.cxx               |   14 
 vcl/CppunitTest_vcl_gradient.mk               |   50 +++
 vcl/Module_vcl.mk                             |    1 
 vcl/qa/cppunit/gradient.cxx                   |  256 +++++++++++++++++
 vcl/qa/cppunit/outdev.cxx                     |  218 --------------
 vcl/source/filter/eps/eps.cxx                 |    3 
 vcl/source/filter/wmf/emfwr.cxx               |    3 
 vcl/source/filter/wmf/wmfwr.cxx               |    3 
 vcl/source/gdi/gradient.cxx                   |  382 ++++++++++++++++++++++++++
 vcl/source/gdi/pdfwriter_impl2.cxx            |    3 
 vcl/source/outdev/gradient.cxx                |  382 --------------------------
 16 files changed, 728 insertions(+), 620 deletions(-)

New commits:
commit 22f52db0be81ceec2aa7a61f7092b54f36e2d00c
Author:     Chris Sherlock <chris.sherloc...@gmail.com>
AuthorDate: Sat Dec 18 23:39:25 2021 +1100
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Wed Jan 5 05:42:32 2022 +0100

    vcl: migrate AddGradientActions() from OutputDevice to Gradient
    
    Change-Id: I815fb3ce366c93b81f60d19eeed906dc7288708a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127030
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/cppcanvas/source/mtfrenderer/implrenderer.cxx 
b/cppcanvas/source/mtfrenderer/implrenderer.cxx
index 8aa1d1675fa9..f7fe8db551f0 100644
--- a/cppcanvas/source/mtfrenderer/implrenderer.cxx
+++ b/cppcanvas/source/mtfrenderer/implrenderer.cxx
@@ -720,9 +720,8 @@ namespace cppcanvas::internal
             }
 
             GDIMetaFile aTmpMtf;
-            rParms.mrVDev.AddGradientActions( rPoly.GetBoundRect(),
-                                              rGradient,
-                                               aTmpMtf );
+            Gradient aGradient(rGradient);
+            aGradient.AddGradientActions( rPoly.GetBoundRect(), aTmpMtf );
 
             createActions( aTmpMtf, rParms, bSubsettableActions );
 
diff --git a/filter/source/svg/svgwriter.cxx b/filter/source/svg/svgwriter.cxx
index 014de0a808b0..a9dcfccbb627 100644
--- a/filter/source/svg/svgwriter.cxx
+++ b/filter/source/svg/svgwriter.cxx
@@ -2255,9 +2255,15 @@ void SVGActionWriter::ImplWritePattern( const 
tools::PolyPolygon& rPolyPoly,
 
                 GDIMetaFile aTmpMtf;
                 if( pHatch )
+                {
                     mpVDev->AddHatchActions( rPolyPoly, *pHatch, aTmpMtf );
+                }
                 else if ( pGradient )
-                    mpVDev->AddGradientActions( rPolyPoly.GetBoundRect(), 
*pGradient, aTmpMtf );
+                {
+                    Gradient aGradient(*pGradient);
+                    aGradient.AddGradientActions( rPolyPoly.GetBoundRect(), 
aTmpMtf );
+                }
+
                 ImplWriteActions( aTmpMtf, nWriteFlags, "" );
             }
         }
diff --git a/include/vcl/gradient.hxx b/include/vcl/gradient.hxx
index 5a04616adda5..f7c2bd2ec5f9 100644
--- a/include/vcl/gradient.hxx
+++ b/include/vcl/gradient.hxx
@@ -33,6 +33,7 @@ namespace tools { class Rectangle; }
 
 class Point;
 class SvStream;
+class GDIMetaFile;
 
 class VCL_DLLPUBLIC Gradient
 {
@@ -78,11 +79,19 @@ public:
 
     void            GetBoundRect( const tools::Rectangle& rRect, 
tools::Rectangle &rBoundRect, Point& rCenter ) const;
 
+    void AddGradientActions(tools::Rectangle const& rRect, GDIMetaFile& 
rMetaFile);
+
     Gradient&       operator=( const Gradient& rGradient );
     Gradient&       operator=( Gradient&& rGradient );
     bool            operator==( const Gradient& rGradient ) const;
     bool            operator!=( const Gradient& rGradient ) const
                         { return !(Gradient::operator==( rGradient )); }
+
+private:
+    tools::Long GetMetafileSteps(tools::Rectangle const& rRect) const;
+
+    void DrawComplexGradientToMetafile(tools::Rectangle const& rRect, 
GDIMetaFile& rMetaFile) const;
+    void DrawLinearGradientToMetafile(tools::Rectangle const& rRect, 
GDIMetaFile& rMetaFile) const;
 };
 
 #endif // INCLUDED_VCL_GRADIENT_HXX
diff --git a/include/vcl/outdev.hxx b/include/vcl/outdev.hxx
index 9c86567865ba..13c8c49064b7 100644
--- a/include/vcl/outdev.hxx
+++ b/include/vcl/outdev.hxx
@@ -795,11 +795,6 @@ public:
     void                        DrawGradient( const tools::Rectangle& rRect, 
const Gradient& rGradient );
     void                        DrawGradient( const tools::PolyPolygon& 
rPolyPoly, const Gradient& rGradient );
 
-    void                        AddGradientActions(
-                                    const tools::Rectangle& rRect,
-                                    const Gradient& rGradient,
-                                    GDIMetaFile& rMtf );
-
 protected:
 
     virtual bool                UsePolyPolygonForComplexGradient() = 0;
@@ -810,13 +805,8 @@ private:
 
     SAL_DLLPRIVATE void         DrawLinearGradient( const tools::Rectangle& 
rRect, const Gradient& rGradient, const tools::PolyPolygon* pClipPolyPoly );
     SAL_DLLPRIVATE void         DrawComplexGradient( const tools::Rectangle& 
rRect, const Gradient& rGradient, const tools::PolyPolygon* pClipPolyPoly );
-
     SAL_DLLPRIVATE void         DrawGradientToMetafile( const 
tools::PolyPolygon& rPolyPoly, const Gradient& rGradient );
-    SAL_DLLPRIVATE void         DrawLinearGradientToMetafile( const 
tools::Rectangle& rRect, const Gradient& rGradient );
-    SAL_DLLPRIVATE void         DrawComplexGradientToMetafile( const 
tools::Rectangle& rRect, const Gradient& rGradient );
-
     SAL_DLLPRIVATE tools::Long  GetGradientSteps(Gradient const& rGradient, 
tools::Rectangle const& rRect);
-
     SAL_DLLPRIVATE Color        GetSingleColorGradientFill();
     ///@}
 
diff --git a/vcl/CppunitTest_vcl_gradient.mk b/vcl/CppunitTest_vcl_gradient.mk
new file mode 100644
index 000000000000..64c7e1e2b9df
--- /dev/null
+++ b/vcl/CppunitTest_vcl_gradient.mk
@@ -0,0 +1,50 @@
+# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
+#
+# This file is part of the LibreOffice project.
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+#
+
+$(eval $(call gb_CppunitTest_CppunitTest,vcl_gradient))
+
+$(eval $(call gb_CppunitTest_set_include,vcl_gradient,\
+    $$(INCLUDE) \
+    -I$(SRCDIR)/vcl/inc \
+    -I$(SRCDIR)/vcl/source/window \
+))
+
+$(eval $(call gb_CppunitTest_add_exception_objects,vcl_gradient, \
+       vcl/qa/cppunit/gradient \
+))
+
+$(eval $(call gb_CppunitTest_use_externals,vcl_gradient,boost_headers))
+
+$(eval $(call gb_CppunitTest_use_libraries,vcl_gradient, \
+       basegfx \
+       comphelper \
+       cppu \
+       cppuhelper \
+       sal \
+       svt \
+       test \
+       tl \
+       unotest \
+       vcl \
+))
+
+$(eval $(call gb_CppunitTest_use_sdk_api,vcl_gradient))
+
+$(eval $(call gb_CppunitTest_use_ure,vcl_gradient))
+$(eval $(call gb_CppunitTest_use_vcl,vcl_gradient))
+
+$(eval $(call gb_CppunitTest_use_components,vcl_gradient,\
+       configmgr/source/configmgr \
+       i18npool/util/i18npool \
+       ucb/source/core/ucb1 \
+))
+
+$(eval $(call gb_CppunitTest_use_configuration,vcl_gradient))
+
+# vim: set noet sw=4 ts=4:
diff --git a/vcl/Module_vcl.mk b/vcl/Module_vcl.mk
index 22536d89af42..1c3c5902c7d4 100644
--- a/vcl/Module_vcl.mk
+++ b/vcl/Module_vcl.mk
@@ -198,6 +198,7 @@ $(eval $(call gb_Module_add_check_targets,vcl,\
     CppunitTest_vcl_filters_test \
     CppunitTest_vcl_mnemonic \
     CppunitTest_vcl_outdev \
+    CppunitTest_vcl_gradient \
     CppunitTest_vcl_app_test \
     CppunitTest_vcl_jpeg_read_write_test \
     CppunitTest_vcl_svm_test \
diff --git a/vcl/qa/cppunit/gradient.cxx b/vcl/qa/cppunit/gradient.cxx
new file mode 100644
index 000000000000..474c619bef72
--- /dev/null
+++ b/vcl/qa/cppunit/gradient.cxx
@@ -0,0 +1,256 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <test/bootstrapfixture.hxx>
+#include <test/outputdevice.hxx>
+
+#include <sal/log.hxx>
+#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/numeric/ftools.hxx>
+#include <basegfx/polygon/b2dpolygon.hxx>
+#include <basegfx/polygon/b2dpolypolygon.hxx>
+#include <basegfx/vector/b2enums.hxx>
+
+#include <vcl/gradient.hxx>
+#include <vcl/lineinfo.hxx>
+#include <vcl/print.hxx>
+#include <vcl/rendercontext/RasterOp.hxx>
+#include <vcl/virdev.hxx>
+#include <vcl/window.hxx>
+#include <vcl/gdimtf.hxx>
+#include <vcl/metaact.hxx>
+
+#include <bitmap/BitmapWriteAccess.hxx>
+#include <bufferdevice.hxx>
+#include <window.h>
+
+class VclGradientTest : public test::BootstrapFixture
+{
+public:
+    VclGradientTest()
+        : BootstrapFixture(true, false)
+    {
+    }
+
+    void testAddGradientActions_rect_linear();
+    void testAddGradientActions_rect_axial();
+    void testAddGradientActions_rect_complex();
+
+    CPPUNIT_TEST_SUITE(VclGradientTest);
+    CPPUNIT_TEST(testAddGradientActions_rect_linear);
+    CPPUNIT_TEST(testAddGradientActions_rect_axial);
+    CPPUNIT_TEST(testAddGradientActions_rect_complex);
+    CPPUNIT_TEST_SUITE_END();
+};
+
+static size_t TestLinearStripes(GDIMetaFile& rMtf, size_t nTimes, size_t 
nIndex)
+{
+    nIndex++;
+    MetaAction* pAction = rMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action (start)", 
MetaActionType::FILLCOLOR,
+                                 pAction->GetType());
+
+    nIndex++;
+    pAction = rMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action (start)", 
MetaActionType::POLYGON,
+                                 pAction->GetType());
+
+    for (size_t i = 0; i < nTimes - 1; i++)
+    {
+        nIndex++;
+        pAction = rMtf.GetAction(nIndex);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
+                                     pAction->GetType());
+
+        nIndex++;
+        pAction = rMtf.GetAction(nIndex);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action", 
MetaActionType::POLYGON,
+                                     pAction->GetType());
+    }
+
+    nIndex++;
+    pAction = rMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action (end)", 
MetaActionType::FILLCOLOR,
+                                 pAction->GetType());
+
+    nIndex++;
+    pAction = rMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action (end)", 
MetaActionType::POLYGON,
+                                 pAction->GetType());
+
+    return nIndex;
+}
+
+void VclGradientTest::testAddGradientActions_rect_linear()
+{
+    GDIMetaFile aMtf;
+    tools::Rectangle aRect(Point(10, 10), Size(40, 40));
+    Gradient aGradient(GradientStyle::Linear, COL_RED, COL_WHITE);
+    aGradient.SetBorder(100);
+
+    aGradient.AddGradientActions(aRect, aMtf);
+
+    size_t nIndex = 0;
+
+    MetaAction* pAction = aMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a push action", MetaActionType::PUSH, 
pAction->GetType());
+
+    nIndex++;
+    pAction = aMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a rectangular intersect clip action",
+                                 MetaActionType::ISECTRECTCLIPREGION, 
pAction->GetType());
+
+    nIndex++;
+    pAction = aMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a line color action", 
MetaActionType::LINECOLOR,
+                                 pAction->GetType());
+
+    TestLinearStripes(aMtf, 3, nIndex);
+}
+
+static size_t TestAxialStripes(GDIMetaFile& rMtf, size_t nTimes, size_t nIndex)
+{
+    nIndex++;
+    MetaAction* pAction = rMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
+                                 pAction->GetType());
+
+    nIndex++;
+    pAction = rMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action", 
MetaActionType::POLYGON,
+                                 pAction->GetType());
+
+    nIndex++;
+    pAction = rMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action", 
MetaActionType::POLYGON,
+                                 pAction->GetType());
+
+    for (size_t i = 0; i < nTimes - 1; i++)
+    {
+        nIndex++;
+        pAction = rMtf.GetAction(nIndex);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
+                                     pAction->GetType());
+
+        nIndex++;
+        pAction = rMtf.GetAction(nIndex);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action", 
MetaActionType::POLYGON,
+                                     pAction->GetType());
+
+        nIndex++;
+        pAction = rMtf.GetAction(nIndex);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action", 
MetaActionType::POLYGON,
+                                     pAction->GetType());
+    }
+
+    nIndex++;
+    pAction = rMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
+                                 pAction->GetType());
+
+    nIndex++;
+    pAction = rMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action", 
MetaActionType::POLYGON,
+                                 pAction->GetType());
+
+    return nIndex;
+}
+
+void VclGradientTest::testAddGradientActions_rect_axial()
+{
+    GDIMetaFile aMtf;
+    tools::Rectangle aRect(Point(10, 10), Size(40, 40));
+    Gradient aGradient(GradientStyle::Axial, COL_RED, COL_WHITE);
+    aGradient.SetBorder(100);
+
+    aGradient.AddGradientActions(aRect, aMtf);
+
+    size_t nIndex = 0;
+
+    MetaAction* pAction = aMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a push action", MetaActionType::PUSH, 
pAction->GetType());
+
+    nIndex++;
+    pAction = aMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a rectangular intersect clip action",
+                                 MetaActionType::ISECTRECTCLIPREGION, 
pAction->GetType());
+
+    nIndex++;
+    pAction = aMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a line color action", 
MetaActionType::LINECOLOR,
+                                 pAction->GetType());
+
+    TestAxialStripes(aMtf, 3, nIndex);
+}
+
+static size_t TestComplexStripes(GDIMetaFile& rMtf, size_t nTimes, size_t 
nIndex)
+{
+    nIndex++;
+    MetaAction* pAction = rMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
+                                 pAction->GetType());
+
+    for (size_t i = 1; i < nTimes; i++)
+    {
+        nIndex++;
+        pAction = rMtf.GetAction(nIndex);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polypolygon action", 
MetaActionType::POLYPOLYGON,
+                                     pAction->GetType());
+
+        nIndex++;
+        pAction = rMtf.GetAction(nIndex);
+        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
+                                     pAction->GetType());
+    }
+
+    nIndex++;
+    pAction = rMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
+                                 pAction->GetType());
+
+    nIndex++;
+    pAction = rMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polypolygon action", 
MetaActionType::POLYGON,
+                                 pAction->GetType());
+
+    return nIndex;
+}
+
+void VclGradientTest::testAddGradientActions_rect_complex()
+{
+    GDIMetaFile aMtf;
+    tools::Rectangle aRect(Point(10, 10), Size(40, 40));
+    Gradient aGradient(GradientStyle::Square, COL_RED, COL_WHITE);
+    aGradient.SetBorder(10);
+
+    aGradient.AddGradientActions(aRect, aMtf);
+
+    size_t nIndex = 0;
+
+    MetaAction* pAction = aMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a push action", MetaActionType::PUSH, 
pAction->GetType());
+
+    nIndex++;
+    pAction = aMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a rectangular intersect clip action",
+                                 MetaActionType::ISECTRECTCLIPREGION, 
pAction->GetType());
+
+    nIndex++;
+    pAction = aMtf.GetAction(nIndex);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a line color action", 
MetaActionType::LINECOLOR,
+                                 pAction->GetType());
+
+    TestComplexStripes(aMtf, 40, nIndex);
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(VclGradientTest);
+
+CPPUNIT_PLUGIN_IMPLEMENT();
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/qa/cppunit/outdev.cxx b/vcl/qa/cppunit/outdev.cxx
index dc2ea8ad2ed2..79fe71431f87 100644
--- a/vcl/qa/cppunit/outdev.cxx
+++ b/vcl/qa/cppunit/outdev.cxx
@@ -94,12 +94,9 @@ public:
     void testDrawGradient_drawmode();
     void testDrawGradient_rect_linear();
     void testDrawGradient_rect_axial();
-    void testAddGradientActions_rect_linear();
-    void testAddGradientActions_rect_axial();
     void testDrawGradient_polygon_linear();
     void testDrawGradient_polygon_axial();
     void testDrawGradient_rect_complex();
-    void testAddGradientActions_rect_complex();
 
     CPPUNIT_TEST_SUITE(VclOutdevTest);
     CPPUNIT_TEST(testVirtualDevice);
@@ -156,12 +153,9 @@ public:
     CPPUNIT_TEST(testDrawGradient_drawmode);
     CPPUNIT_TEST(testDrawGradient_rect_linear);
     CPPUNIT_TEST(testDrawGradient_rect_axial);
-    CPPUNIT_TEST(testAddGradientActions_rect_linear);
-    CPPUNIT_TEST(testAddGradientActions_rect_axial);
     CPPUNIT_TEST(testDrawGradient_polygon_linear);
     CPPUNIT_TEST(testDrawGradient_polygon_axial);
     CPPUNIT_TEST(testDrawGradient_rect_complex);
-    CPPUNIT_TEST(testAddGradientActions_rect_complex);
     CPPUNIT_TEST_SUITE_END();
 };
 
@@ -2138,92 +2132,6 @@ void VclOutdevTest::testDrawGradient_drawmode()
                                  MetaActionType::POP, pAction->GetType());
 }
 
-static size_t TestLinearStripes(GDIMetaFile& rMtf, size_t nTimes, size_t 
nIndex)
-{
-    nIndex++;
-    MetaAction* pAction = rMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action (start)", 
MetaActionType::FILLCOLOR,
-                                 pAction->GetType());
-
-    nIndex++;
-    pAction = rMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action (start)", 
MetaActionType::POLYGON,
-                                 pAction->GetType());
-
-    for (size_t i = 0; i < nTimes - 1; i++)
-    {
-        nIndex++;
-        pAction = rMtf.GetAction(nIndex);
-        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
-                                     pAction->GetType());
-
-        nIndex++;
-        pAction = rMtf.GetAction(nIndex);
-        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action", 
MetaActionType::POLYGON,
-                                     pAction->GetType());
-    }
-
-    nIndex++;
-    pAction = rMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action (end)", 
MetaActionType::FILLCOLOR,
-                                 pAction->GetType());
-
-    nIndex++;
-    pAction = rMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action (end)", 
MetaActionType::POLYGON,
-                                 pAction->GetType());
-
-    return nIndex;
-}
-
-static size_t TestAxialStripes(GDIMetaFile& rMtf, size_t nTimes, size_t nIndex)
-{
-    nIndex++;
-    MetaAction* pAction = rMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
-                                 pAction->GetType());
-
-    nIndex++;
-    pAction = rMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action", 
MetaActionType::POLYGON,
-                                 pAction->GetType());
-
-    nIndex++;
-    pAction = rMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action", 
MetaActionType::POLYGON,
-                                 pAction->GetType());
-
-    for (size_t i = 0; i < nTimes - 1; i++)
-    {
-        nIndex++;
-        pAction = rMtf.GetAction(nIndex);
-        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
-                                     pAction->GetType());
-
-        nIndex++;
-        pAction = rMtf.GetAction(nIndex);
-        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action", 
MetaActionType::POLYGON,
-                                     pAction->GetType());
-
-        nIndex++;
-        pAction = rMtf.GetAction(nIndex);
-        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action", 
MetaActionType::POLYGON,
-                                     pAction->GetType());
-    }
-
-    nIndex++;
-    pAction = rMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
-                                 pAction->GetType());
-
-    nIndex++;
-    pAction = rMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polygon action", 
MetaActionType::POLYGON,
-                                 pAction->GetType());
-
-    return nIndex;
-}
-
 void VclOutdevTest::testDrawGradient_rect_linear()
 {
     ScopedVclPtrInstance<VirtualDevice> pVDev;
@@ -2245,37 +2153,6 @@ void VclOutdevTest::testDrawGradient_rect_linear()
                                  pAction->GetType());
 }
 
-void VclOutdevTest::testAddGradientActions_rect_linear()
-{
-    ScopedVclPtrInstance<VirtualDevice> pVDev;
-    GDIMetaFile aMtf;
-
-    tools::Rectangle aRect(Point(10, 10), Size(40, 40));
-    pVDev->SetOutputSizePixel(Size(100, 100));
-
-    Gradient aGradient(GradientStyle::Linear, COL_RED, COL_WHITE);
-    aGradient.SetBorder(100);
-
-    pVDev->AddGradientActions(aRect, aGradient, aMtf);
-
-    size_t nIndex = 0;
-
-    MetaAction* pAction = aMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a push action", MetaActionType::PUSH, 
pAction->GetType());
-
-    nIndex++;
-    pAction = aMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a rectangular intersect clip action",
-                                 MetaActionType::ISECTRECTCLIPREGION, 
pAction->GetType());
-
-    nIndex++;
-    pAction = aMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a line color action", 
MetaActionType::LINECOLOR,
-                                 pAction->GetType());
-
-    TestLinearStripes(aMtf, 3, nIndex);
-}
-
 void VclOutdevTest::testDrawGradient_rect_axial()
 {
     ScopedVclPtrInstance<VirtualDevice> pVDev;
@@ -2297,37 +2174,6 @@ void VclOutdevTest::testDrawGradient_rect_axial()
                                  pAction->GetType());
 }
 
-void VclOutdevTest::testAddGradientActions_rect_axial()
-{
-    ScopedVclPtrInstance<VirtualDevice> pVDev;
-    GDIMetaFile aMtf;
-
-    tools::Rectangle aRect(Point(10, 10), Size(40, 40));
-    pVDev->SetOutputSizePixel(Size(100, 100));
-
-    Gradient aGradient(GradientStyle::Axial, COL_RED, COL_WHITE);
-    aGradient.SetBorder(100);
-
-    pVDev->AddGradientActions(aRect, aGradient, aMtf);
-
-    size_t nIndex = 0;
-
-    MetaAction* pAction = aMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a push action", MetaActionType::PUSH, 
pAction->GetType());
-
-    nIndex++;
-    pAction = aMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a rectangular intersect clip action",
-                                 MetaActionType::ISECTRECTCLIPREGION, 
pAction->GetType());
-
-    nIndex++;
-    pAction = aMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a line color action", 
MetaActionType::LINECOLOR,
-                                 pAction->GetType());
-
-    TestAxialStripes(aMtf, 3, nIndex);
-}
-
 void VclOutdevTest::testDrawGradient_polygon_linear()
 {
     ScopedVclPtrInstance<VirtualDevice> pVDev;
@@ -2364,39 +2210,6 @@ void VclOutdevTest::testDrawGradient_polygon_axial()
     ClipGradientTest(aMtf, INITIAL_SETUP_ACTION_COUNT);
 }
 
-static size_t TestComplexStripes(GDIMetaFile& rMtf, size_t nTimes, size_t 
nIndex)
-{
-    nIndex++;
-    MetaAction* pAction = rMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
-                                 pAction->GetType());
-
-    for (size_t i = 1; i < nTimes; i++)
-    {
-        nIndex++;
-        pAction = rMtf.GetAction(nIndex);
-        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polypolygon action", 
MetaActionType::POLYPOLYGON,
-                                     pAction->GetType());
-
-        nIndex++;
-        pAction = rMtf.GetAction(nIndex);
-        CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
-                                     pAction->GetType());
-    }
-
-    nIndex++;
-    pAction = rMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a fill color action", 
MetaActionType::FILLCOLOR,
-                                 pAction->GetType());
-
-    nIndex++;
-    pAction = rMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a polypolygon action", 
MetaActionType::POLYGON,
-                                 pAction->GetType());
-
-    return nIndex;
-}
-
 void VclOutdevTest::testDrawGradient_rect_complex()
 {
     ScopedVclPtrInstance<VirtualDevice> pVDev;
@@ -2417,37 +2230,6 @@ void VclOutdevTest::testDrawGradient_rect_complex()
                                  pAction->GetType());
 }
 
-void VclOutdevTest::testAddGradientActions_rect_complex()
-{
-    ScopedVclPtrInstance<VirtualDevice> pVDev;
-    GDIMetaFile aMtf;
-
-    tools::Rectangle aRect(Point(10, 10), Size(40, 40));
-    pVDev->SetOutputSizePixel(Size(1000, 1000));
-
-    Gradient aGradient(GradientStyle::Square, COL_RED, COL_WHITE);
-    aGradient.SetBorder(10);
-
-    pVDev->AddGradientActions(aRect, aGradient, aMtf);
-
-    size_t nIndex = 0;
-
-    MetaAction* pAction = aMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a push action", MetaActionType::PUSH, 
pAction->GetType());
-
-    nIndex++;
-    pAction = aMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a rectangular intersect clip action",
-                                 MetaActionType::ISECTRECTCLIPREGION, 
pAction->GetType());
-
-    nIndex++;
-    pAction = aMtf.GetAction(nIndex);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("Not a line color action", 
MetaActionType::LINECOLOR,
-                                 pAction->GetType());
-
-    TestComplexStripes(aMtf, 40, nIndex);
-}
-
 CPPUNIT_TEST_SUITE_REGISTRATION(VclOutdevTest);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/vcl/source/filter/eps/eps.cxx b/vcl/source/filter/eps/eps.cxx
index ced4d9be1a9e..1a73c682adf1 100644
--- a/vcl/source/filter/eps/eps.cxx
+++ b/vcl/source/filter/eps/eps.cxx
@@ -1515,7 +1515,8 @@ void PSWriter::ImplWriteGradient( const 
tools::PolyPolygon& rPolyPoly, const Gra
     ScopedVclPtrInstance< VirtualDevice > l_pVDev;
     GDIMetaFile     aTmpMtf;
     l_pVDev->SetMapMode( rVDev.GetMapMode() );
-    l_pVDev->AddGradientActions( rPolyPoly.GetBoundRect(), rGradient, aTmpMtf 
);
+    Gradient aGradient(rGradient);
+    aGradient.AddGradientActions( rPolyPoly.GetBoundRect(), aTmpMtf );
     ImplWriteActions( aTmpMtf, rVDev );
 }
 
diff --git a/vcl/source/filter/wmf/emfwr.cxx b/vcl/source/filter/wmf/emfwr.cxx
index 8f545a7b07a0..b2782847b1b1 100644
--- a/vcl/source/filter/wmf/emfwr.cxx
+++ b/vcl/source/filter/wmf/emfwr.cxx
@@ -1170,7 +1170,8 @@ void EMFWriter::ImplWrite( const GDIMetaFile& rMtf )
                 const MetaGradientAction*   pA = static_cast<const 
MetaGradientAction*>(pAction);
                 GDIMetaFile                 aTmpMtf;
 
-                maVDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), 
aTmpMtf );
+                Gradient aGradient = pA->GetGradient();
+                aGradient.AddGradientActions( pA->GetRect(), aTmpMtf );
                 ImplWrite( aTmpMtf );
             }
             break;
diff --git a/vcl/source/filter/wmf/wmfwr.cxx b/vcl/source/filter/wmf/wmfwr.cxx
index 6abd9f95d490..22230ba4666e 100644
--- a/vcl/source/filter/wmf/wmfwr.cxx
+++ b/vcl/source/filter/wmf/wmfwr.cxx
@@ -1302,7 +1302,8 @@ void WMFWriter::WriteRecords( const GDIMetaFile & rMTF )
                 const MetaGradientAction*   pA = static_cast<const 
MetaGradientAction*>(pMA);
                 GDIMetaFile                 aTmpMtf;
 
-                pVirDev->AddGradientActions( pA->GetRect(), pA->GetGradient(), 
aTmpMtf );
+                Gradient aGradient = pA->GetGradient();
+                aGradient.AddGradientActions( pA->GetRect(), aTmpMtf );
                 WriteRecords( aTmpMtf );
             }
             break;
diff --git a/vcl/source/gdi/gradient.cxx b/vcl/source/gdi/gradient.cxx
index b94223a427c4..cf751abffa97 100644
--- a/vcl/source/gdi/gradient.cxx
+++ b/vcl/source/gdi/gradient.cxx
@@ -18,7 +18,9 @@
  */
 
 #include <tools/gen.hxx>
+
 #include <vcl/gradient.hxx>
+#include <vcl/metaact.hxx>
 
 class Gradient::Impl
 {
@@ -295,4 +297,384 @@ bool Gradient::operator==( const Gradient& rGradient ) 
const
     return mpImplGradient == rGradient.mpImplGradient;
 }
 
+const sal_uInt32 GRADIENT_DEFAULT_STEPCOUNT = 0;
+
+void Gradient::AddGradientActions(tools::Rectangle const& rRect, GDIMetaFile& 
rMetaFile)
+{
+    tools::Rectangle aRect(rRect);
+    aRect.Justify();
+
+    // do nothing if the rectangle is empty
+    if (aRect.IsEmpty())
+        return;
+
+    rMetaFile.AddAction(new MetaPushAction(vcl::PushFlags::ALL));
+    rMetaFile.AddAction(new MetaISectRectClipRegionAction( aRect));
+    rMetaFile.AddAction(new MetaLineColorAction(Color(), false));
+
+    // because we draw with no border line, we have to expand gradient
+    // rect to avoid missing lines on the right and bottom edge
+    aRect.AdjustLeft( -1 );
+    aRect.AdjustTop( -1 );
+    aRect.AdjustRight( 1 );
+    aRect.AdjustBottom( 1 );
+
+    // calculate step count if necessary
+    if (!GetSteps())
+        SetSteps(GRADIENT_DEFAULT_STEPCOUNT);
+
+    if (GetStyle() == GradientStyle::Linear || GetStyle() == 
GradientStyle::Axial)
+        DrawLinearGradientToMetafile(aRect, rMetaFile);
+    else
+        DrawComplexGradientToMetafile(aRect, rMetaFile);
+
+    rMetaFile.AddAction(new MetaPopAction());
+}
+
+tools::Long Gradient::GetMetafileSteps(tools::Rectangle const& rRect) const
+{
+    // calculate step count
+    tools::Long nStepCount = GetSteps();
+
+    if (nStepCount)
+        return nStepCount;
+
+    if (GetStyle() == GradientStyle::Linear || GetStyle() == 
GradientStyle::Axial)
+        return rRect.GetHeight();
+    else
+        return std::min(rRect.GetWidth(), rRect.GetHeight());
+}
+
+
+static sal_uInt8 GetGradientColorValue(tools::Long nValue)
+{
+    if ( nValue < 0 )
+        return 0;
+    else if ( nValue > 0xFF )
+        return 0xFF;
+    else
+        return static_cast<sal_uInt8>(nValue);
+}
+
+void Gradient::DrawLinearGradientToMetafile(tools::Rectangle const& rRect, 
GDIMetaFile& rMetaFile) const
+{
+    // get BoundRect of rotated rectangle
+    tools::Rectangle aRect;
+    Point aCenter;
+    Degree10 nAngle = GetAngle() % 3600_deg10;
+
+    GetBoundRect(rRect, aRect, aCenter);
+
+    bool bLinear = (GetStyle() == GradientStyle::Linear);
+    double fBorder = GetBorder() * aRect.GetHeight() / 100.0;
+    if ( !bLinear )
+    {
+        fBorder /= 2.0;
+    }
+    tools::Rectangle aMirrorRect = aRect; // used in style axial
+    aMirrorRect.SetTop( ( aRect.Top() + aRect.Bottom() ) / 2 );
+    if ( !bLinear )
+    {
+        aRect.SetBottom( aMirrorRect.Top() );
+    }
+
+    // colour-intensities of start- and finish; change if needed
+    tools::Long    nFactor;
+    Color   aStartCol   = GetStartColor();
+    Color   aEndCol     = GetEndColor();
+    tools::Long    nStartRed   = aStartCol.GetRed();
+    tools::Long    nStartGreen = aStartCol.GetGreen();
+    tools::Long    nStartBlue  = aStartCol.GetBlue();
+    tools::Long    nEndRed     = aEndCol.GetRed();
+    tools::Long    nEndGreen   = aEndCol.GetGreen();
+    tools::Long    nEndBlue    = aEndCol.GetBlue();
+    nFactor     = GetStartIntensity();
+    nStartRed   = (nStartRed   * nFactor) / 100;
+    nStartGreen = (nStartGreen * nFactor) / 100;
+    nStartBlue  = (nStartBlue  * nFactor) / 100;
+    nFactor     = GetEndIntensity();
+    nEndRed     = (nEndRed   * nFactor) / 100;
+    nEndGreen   = (nEndGreen * nFactor) / 100;
+    nEndBlue    = (nEndBlue  * nFactor) / 100;
+
+    // gradient style axial has exchanged start and end colors
+    if ( !bLinear)
+    {
+        tools::Long nTempColor = nStartRed;
+        nStartRed = nEndRed;
+        nEndRed = nTempColor;
+        nTempColor = nStartGreen;
+        nStartGreen = nEndGreen;
+        nEndGreen = nTempColor;
+        nTempColor = nStartBlue;
+        nStartBlue = nEndBlue;
+        nEndBlue = nTempColor;
+    }
+
+    sal_uInt8   nRed;
+    sal_uInt8   nGreen;
+    sal_uInt8   nBlue;
+
+    // Create border
+    tools::Rectangle aBorderRect = aRect;
+    tools::Polygon aPoly( 4 );
+    if (fBorder > 0.0)
+    {
+        nRed        = static_cast<sal_uInt8>(nStartRed);
+        nGreen      = static_cast<sal_uInt8>(nStartGreen);
+        nBlue       = static_cast<sal_uInt8>(nStartBlue);
+
+        rMetaFile.AddAction( new MetaFillColorAction( Color( nRed, nGreen, 
nBlue ), true ) );
+
+        aBorderRect.SetBottom( static_cast<tools::Long>( aBorderRect.Top() + 
fBorder ) );
+        aRect.SetTop( aBorderRect.Bottom() );
+        aPoly[0] = aBorderRect.TopLeft();
+        aPoly[1] = aBorderRect.TopRight();
+        aPoly[2] = aBorderRect.BottomRight();
+        aPoly[3] = aBorderRect.BottomLeft();
+        aPoly.Rotate( aCenter, nAngle );
+
+        rMetaFile.AddAction( new MetaPolygonAction( aPoly ) );
+
+        if ( !bLinear)
+        {
+            aBorderRect = aMirrorRect;
+            aBorderRect.SetTop( static_cast<tools::Long>( aBorderRect.Bottom() 
- fBorder ) );
+            aMirrorRect.SetBottom( aBorderRect.Top() );
+            aPoly[0] = aBorderRect.TopLeft();
+            aPoly[1] = aBorderRect.TopRight();
+            aPoly[2] = aBorderRect.BottomRight();
+            aPoly[3] = aBorderRect.BottomLeft();
+            aPoly.Rotate( aCenter, nAngle );
+
+            rMetaFile.AddAction( new MetaPolygonAction( aPoly ) );
+        }
+    }
+
+    tools::Long nStepCount = GetMetafileSteps(aRect);
+
+    // minimal three steps and maximal as max color steps
+    tools::Long   nAbsRedSteps   = std::abs( nEndRed   - nStartRed );
+    tools::Long   nAbsGreenSteps = std::abs( nEndGreen - nStartGreen );
+    tools::Long   nAbsBlueSteps  = std::abs( nEndBlue  - nStartBlue );
+    tools::Long   nMaxColorSteps = std::max( nAbsRedSteps , nAbsGreenSteps );
+    nMaxColorSteps = std::max( nMaxColorSteps, nAbsBlueSteps );
+    tools::Long nSteps = std::min( nStepCount, nMaxColorSteps );
+    if ( nSteps < 3)
+    {
+        nSteps = 3;
+    }
+
+    double fScanInc = static_cast<double>(aRect.GetHeight()) / 
static_cast<double>(nSteps);
+    double fGradientLine = static_cast<double>(aRect.Top());
+    double fMirrorGradientLine = static_cast<double>(aMirrorRect.Bottom());
+
+    const double fStepsMinus1 = static_cast<double>(nSteps) - 1.0;
+    if ( !bLinear)
+    {
+        nSteps -= 1; // draw middle polygons as one polygon after loop to 
avoid gap
+    }
+    for ( tools::Long i = 0; i < nSteps; i++ )
+    {
+        // linear interpolation of color
+        double fAlpha = static_cast<double>(i) / fStepsMinus1;
+        double fTempColor = static_cast<double>(nStartRed) * (1.0-fAlpha) + 
static_cast<double>(nEndRed) * fAlpha;
+        nRed = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
+        fTempColor = static_cast<double>(nStartGreen) * (1.0-fAlpha) + 
static_cast<double>(nEndGreen) * fAlpha;
+        nGreen = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
+        fTempColor = static_cast<double>(nStartBlue) * (1.0-fAlpha) + 
static_cast<double>(nEndBlue) * fAlpha;
+        nBlue = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
+
+        rMetaFile.AddAction( new MetaFillColorAction( Color( nRed, nGreen, 
nBlue ), true ) );
+
+        // Polygon for this color step
+        aRect.SetTop( static_cast<tools::Long>( fGradientLine + 
static_cast<double>(i) * fScanInc ) );
+        aRect.SetBottom( static_cast<tools::Long>( fGradientLine + ( 
static_cast<double>(i) + 1.0 ) * fScanInc ) );
+        aPoly[0] = aRect.TopLeft();
+        aPoly[1] = aRect.TopRight();
+        aPoly[2] = aRect.BottomRight();
+        aPoly[3] = aRect.BottomLeft();
+        aPoly.Rotate( aCenter, nAngle );
+
+        rMetaFile.AddAction( new MetaPolygonAction( aPoly ) );
+
+        if ( !bLinear )
+        {
+            aMirrorRect.SetBottom( static_cast<tools::Long>( 
fMirrorGradientLine - static_cast<double>(i) * fScanInc ) );
+            aMirrorRect.SetTop( static_cast<tools::Long>( fMirrorGradientLine 
- (static_cast<double>(i) + 1.0)* fScanInc ) );
+            aPoly[0] = aMirrorRect.TopLeft();
+            aPoly[1] = aMirrorRect.TopRight();
+            aPoly[2] = aMirrorRect.BottomRight();
+            aPoly[3] = aMirrorRect.BottomLeft();
+            aPoly.Rotate( aCenter, nAngle );
+
+            rMetaFile.AddAction( new MetaPolygonAction( aPoly ) );
+        }
+    }
+    if ( bLinear)
+        return;
+
+    // draw middle polygon with end color
+    nRed = GetGradientColorValue(nEndRed);
+    nGreen = GetGradientColorValue(nEndGreen);
+    nBlue = GetGradientColorValue(nEndBlue);
+
+    rMetaFile.AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue 
), true ) );
+
+    aRect.SetTop( static_cast<tools::Long>( fGradientLine + 
static_cast<double>(nSteps) * fScanInc ) );
+    aRect.SetBottom( static_cast<tools::Long>( fMirrorGradientLine - 
static_cast<double>(nSteps) * fScanInc ) );
+    aPoly[0] = aRect.TopLeft();
+    aPoly[1] = aRect.TopRight();
+    aPoly[2] = aRect.BottomRight();
+    aPoly[3] = aRect.BottomLeft();
+    aPoly.Rotate( aCenter, nAngle );
+
+    rMetaFile.AddAction( new MetaPolygonAction( aPoly ) );
+
+}
+
+void Gradient::DrawComplexGradientToMetafile(tools::Rectangle const& rRect, 
GDIMetaFile& rMetaFile) const
+{
+    // Determine if we output via Polygon or PolyPolygon
+    // For all rasteroperations other than Overpaint always use PolyPolygon,
+    // as we will get wrong results if we output multiple times on top of each 
other.
+    // Also for printers always use PolyPolygon, as not all printers
+    // can print polygons on top of each other.
+
+    tools::Rectangle aRect;
+    Point aCenter;
+    GetBoundRect(rRect, aRect, aCenter);
+
+    std::optional<tools::PolyPolygon> xPolyPoly;
+    xPolyPoly = tools::PolyPolygon( 2 );
+
+    // last parameter - true if complex gradient, false if linear
+    tools::Long nStepCount = GetMetafileSteps(rRect);
+
+    // at least three steps and at most the number of colour differences
+    tools::Long nSteps = std::max(nStepCount, tools::Long(2));
+
+    Color aStartCol(GetStartColor());
+    Color aEndCol(GetEndColor());
+
+    tools::Long nStartRed = (static_cast<tools::Long>(aStartCol.GetRed()) * 
GetStartIntensity()) / 100;
+    tools::Long nStartGreen = (static_cast<tools::Long>(aStartCol.GetGreen()) 
* GetStartIntensity()) / 100;
+    tools::Long nStartBlue = (static_cast<tools::Long>(aStartCol.GetBlue()) * 
GetStartIntensity()) / 100;
+
+    tools::Long nEndRed = (static_cast<tools::Long>(aEndCol.GetRed()) * 
GetEndIntensity()) / 100;
+    tools::Long nEndGreen = (static_cast<tools::Long>(aEndCol.GetGreen()) * 
GetEndIntensity()) / 100;
+    tools::Long nEndBlue = (static_cast<tools::Long>(aEndCol.GetBlue()) * 
GetEndIntensity()) / 100;
+
+    tools::Long nRedSteps = nEndRed - nStartRed;
+    tools::Long nGreenSteps = nEndGreen - nStartGreen;
+    tools::Long nBlueSteps = nEndBlue - nStartBlue;
+
+    tools::Long nCalcSteps  = std::abs(nRedSteps);
+    tools::Long nTempSteps = std::abs(nGreenSteps);
+
+    if (nTempSteps > nCalcSteps)
+        nCalcSteps = nTempSteps;
+
+    nTempSteps = std::abs( nBlueSteps );
+
+    if (nTempSteps > nCalcSteps)
+        nCalcSteps = nTempSteps;
+
+    if (nCalcSteps < nSteps)
+        nSteps = nCalcSteps;
+
+    if ( !nSteps )
+        nSteps = 1;
+
+    // determine output limits and stepsizes for all directions
+    tools::Polygon aPoly;
+    double  fScanLeft = aRect.Left();
+    double  fScanTop = aRect.Top();
+    double  fScanRight = aRect.Right();
+    double  fScanBottom = aRect.Bottom();
+    double fScanIncX = static_cast<double>(aRect.GetWidth()) / 
static_cast<double>(nSteps) * 0.5;
+    double fScanIncY = static_cast<double>(aRect.GetHeight()) / 
static_cast<double>(nSteps) * 0.5;
+
+    // all gradients are rendered as nested rectangles which shrink
+    // equally in each dimension - except for 'square' gradients
+    // which shrink to a central vertex but are not per-se square.
+    if (GetStyle() != GradientStyle::Square)
+    {
+        fScanIncY = std::min( fScanIncY, fScanIncX );
+        fScanIncX = fScanIncY;
+    }
+    sal_uInt8   nRed = static_cast<sal_uInt8>(nStartRed), nGreen = 
static_cast<sal_uInt8>(nStartGreen), nBlue = static_cast<sal_uInt8>(nStartBlue);
+    bool    bPaintLastPolygon( false ); // #107349# Paint last polygon only if 
loop has generated any output
+
+    rMetaFile.AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue 
), true ) );
+
+    aPoly = rRect;
+    xPolyPoly->Insert( aPoly );
+    xPolyPoly->Insert( aPoly );
+
+    // loop to output Polygon/PolyPolygon sequentially
+    for( tools::Long i = 1; i < nSteps; i++ )
+    {
+        // calculate new Polygon
+        fScanLeft += fScanIncX;
+        aRect.SetLeft( static_cast<tools::Long>( fScanLeft ) );
+        fScanTop += fScanIncY;
+        aRect.SetTop( static_cast<tools::Long>( fScanTop ) );
+        fScanRight -= fScanIncX;
+        aRect.SetRight( static_cast<tools::Long>( fScanRight ) );
+        fScanBottom -= fScanIncY;
+        aRect.SetBottom( static_cast<tools::Long>( fScanBottom ) );
+
+        if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
+            break;
+
+        if (GetStyle() == GradientStyle::Radial || GetStyle() == 
GradientStyle::Elliptical)
+            aPoly = tools::Polygon( aRect.Center(), aRect.GetWidth() >> 1, 
aRect.GetHeight() >> 1 );
+        else
+            aPoly = tools::Polygon( aRect );
+
+        aPoly.Rotate(aCenter, GetAngle() % 3600_deg10);
+
+        // adapt colour accordingly
+        const tools::Long nStepIndex = ( xPolyPoly ? i : ( i + 1 ) );
+        nRed = GetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) 
/ nSteps ) );
+        nGreen = GetGradientColorValue( nStartGreen + ( ( nGreenSteps * 
nStepIndex ) / nSteps ) );
+        nBlue = GetGradientColorValue( nStartBlue + ( ( nBlueSteps * 
nStepIndex ) / nSteps ) );
+
+        bPaintLastPolygon = true; // #107349# Paint last polygon only if loop 
has generated any output
+
+        xPolyPoly->Replace( xPolyPoly->GetObject( 1 ), 0 );
+        xPolyPoly->Replace( aPoly, 1 );
+
+        rMetaFile.AddAction( new MetaPolyPolygonAction( *xPolyPoly ) );
+
+        // #107349# Set fill color _after_ geometry painting:
+        // xPolyPoly's geometry is the band from last iteration's
+        // aPoly to current iteration's aPoly. The window outdev
+        // path (see else below), on the other hand, paints the
+        // full aPoly. Thus, here, we're painting the band before
+        // the one painted in the window outdev path below. To get
+        // matching colors, have to delay color setting here.
+        rMetaFile.AddAction( new MetaFillColorAction( Color( nRed, nGreen, 
nBlue ), true ) );
+    }
+
+    const tools::Polygon& rPoly = xPolyPoly->GetObject( 1 );
+
+    if( rPoly.GetBoundRect().IsEmpty() )
+        return;
+
+    // #107349# Paint last polygon with end color only if loop
+    // has generated output. Otherwise, the current
+    // (i.e. start) color is taken, to generate _any_ output.
+    if( bPaintLastPolygon )
+    {
+        nRed = GetGradientColorValue( nEndRed );
+        nGreen = GetGradientColorValue( nEndGreen );
+        nBlue = GetGradientColorValue( nEndBlue );
+    }
+
+    rMetaFile.AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue 
), true ) );
+    rMetaFile.AddAction( new MetaPolygonAction( rPoly ) );
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/vcl/source/gdi/pdfwriter_impl2.cxx 
b/vcl/source/gdi/pdfwriter_impl2.cxx
index e472dbd52cef..69ac8708f4f1 100644
--- a/vcl/source/gdi/pdfwriter_impl2.cxx
+++ b/vcl/source/gdi/pdfwriter_impl2.cxx
@@ -60,8 +60,9 @@ void PDFWriterImpl::implWriteGradient( const 
tools::PolyPolygon& i_rPolyPoly, co
                                        VirtualDevice* i_pDummyVDev, const 
vcl::PDFWriter::PlayMetafileContext& i_rContext )
 {
     GDIMetaFile        aTmpMtf;
+    Gradient aGradient(i_rGradient);
 
-    i_pDummyVDev->AddGradientActions( i_rPolyPoly.GetBoundRect(), i_rGradient, 
aTmpMtf );
+    aGradient.AddGradientActions( i_rPolyPoly.GetBoundRect(), aTmpMtf );
 
     m_rOuterFace.Push();
     m_rOuterFace.IntersectClipRegion( i_rPolyPoly.getB2DPolyPolygon() );
diff --git a/vcl/source/outdev/gradient.cxx b/vcl/source/outdev/gradient.cxx
index 9d8e6d8b1830..eb2fd4645323 100644
--- a/vcl/source/outdev/gradient.cxx
+++ b/vcl/source/outdev/gradient.cxx
@@ -581,347 +581,6 @@ void OutputDevice::DrawComplexGradient( const 
tools::Rectangle& rRect,
     ImplDrawPolygon( rPoly, pClixPolyPoly );
 }
 
-static tools::Long GetGradientMetafileSteps(Gradient const& rGradient, 
tools::Rectangle const& rRect)
-{
-    // calculate step count
-    tools::Long nStepCount = rGradient.GetSteps();
-
-    if (nStepCount)
-        return nStepCount;
-
-    if (rGradient.GetStyle() == GradientStyle::Linear || rGradient.GetStyle() 
== GradientStyle::Axial)
-        return rRect.GetHeight();
-    else
-        return std::min(rRect.GetWidth(), rRect.GetHeight());
-}
-
-void OutputDevice::DrawLinearGradientToMetafile( const tools::Rectangle& rRect,
-                                                 const Gradient& rGradient )
-{
-    assert(!is_double_buffered_window());
-
-    // get BoundRect of rotated rectangle
-    tools::Rectangle aRect;
-    Point     aCenter;
-    Degree10  nAngle = rGradient.GetAngle() % 3600_deg10;
-
-    rGradient.GetBoundRect( rRect, aRect, aCenter );
-
-    bool bLinear = (rGradient.GetStyle() == GradientStyle::Linear);
-    double fBorder = rGradient.GetBorder() * aRect.GetHeight() / 100.0;
-    if ( !bLinear )
-    {
-        fBorder /= 2.0;
-    }
-    tools::Rectangle aMirrorRect = aRect; // used in style axial
-    aMirrorRect.SetTop( ( aRect.Top() + aRect.Bottom() ) / 2 );
-    if ( !bLinear )
-    {
-        aRect.SetBottom( aMirrorRect.Top() );
-    }
-
-    // colour-intensities of start- and finish; change if needed
-    tools::Long    nFactor;
-    Color   aStartCol   = rGradient.GetStartColor();
-    Color   aEndCol     = rGradient.GetEndColor();
-    tools::Long    nStartRed   = aStartCol.GetRed();
-    tools::Long    nStartGreen = aStartCol.GetGreen();
-    tools::Long    nStartBlue  = aStartCol.GetBlue();
-    tools::Long    nEndRed     = aEndCol.GetRed();
-    tools::Long    nEndGreen   = aEndCol.GetGreen();
-    tools::Long    nEndBlue    = aEndCol.GetBlue();
-    nFactor     = rGradient.GetStartIntensity();
-    nStartRed   = (nStartRed   * nFactor) / 100;
-    nStartGreen = (nStartGreen * nFactor) / 100;
-    nStartBlue  = (nStartBlue  * nFactor) / 100;
-    nFactor     = rGradient.GetEndIntensity();
-    nEndRed     = (nEndRed   * nFactor) / 100;
-    nEndGreen   = (nEndGreen * nFactor) / 100;
-    nEndBlue    = (nEndBlue  * nFactor) / 100;
-
-    // gradient style axial has exchanged start and end colors
-    if ( !bLinear)
-    {
-        tools::Long nTempColor = nStartRed;
-        nStartRed = nEndRed;
-        nEndRed = nTempColor;
-        nTempColor = nStartGreen;
-        nStartGreen = nEndGreen;
-        nEndGreen = nTempColor;
-        nTempColor = nStartBlue;
-        nStartBlue = nEndBlue;
-        nEndBlue = nTempColor;
-    }
-
-    sal_uInt8   nRed;
-    sal_uInt8   nGreen;
-    sal_uInt8   nBlue;
-
-    // Create border
-    tools::Rectangle aBorderRect = aRect;
-    tools::Polygon aPoly( 4 );
-    if (fBorder > 0.0)
-    {
-        nRed        = static_cast<sal_uInt8>(nStartRed);
-        nGreen      = static_cast<sal_uInt8>(nStartGreen);
-        nBlue       = static_cast<sal_uInt8>(nStartBlue);
-
-        mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, 
nBlue ), true ) );
-
-        aBorderRect.SetBottom( static_cast<tools::Long>( aBorderRect.Top() + 
fBorder ) );
-        aRect.SetTop( aBorderRect.Bottom() );
-        aPoly[0] = aBorderRect.TopLeft();
-        aPoly[1] = aBorderRect.TopRight();
-        aPoly[2] = aBorderRect.BottomRight();
-        aPoly[3] = aBorderRect.BottomLeft();
-        aPoly.Rotate( aCenter, nAngle );
-
-        mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
-
-        if ( !bLinear)
-        {
-            aBorderRect = aMirrorRect;
-            aBorderRect.SetTop( static_cast<tools::Long>( aBorderRect.Bottom() 
- fBorder ) );
-            aMirrorRect.SetBottom( aBorderRect.Top() );
-            aPoly[0] = aBorderRect.TopLeft();
-            aPoly[1] = aBorderRect.TopRight();
-            aPoly[2] = aBorderRect.BottomRight();
-            aPoly[3] = aBorderRect.BottomLeft();
-            aPoly.Rotate( aCenter, nAngle );
-
-            mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
-        }
-    }
-
-    tools::Long nStepCount  = GetGradientMetafileSteps(rGradient, aRect);
-
-    // minimal three steps and maximal as max color steps
-    tools::Long   nAbsRedSteps   = std::abs( nEndRed   - nStartRed );
-    tools::Long   nAbsGreenSteps = std::abs( nEndGreen - nStartGreen );
-    tools::Long   nAbsBlueSteps  = std::abs( nEndBlue  - nStartBlue );
-    tools::Long   nMaxColorSteps = std::max( nAbsRedSteps , nAbsGreenSteps );
-    nMaxColorSteps = std::max( nMaxColorSteps, nAbsBlueSteps );
-    tools::Long nSteps = std::min( nStepCount, nMaxColorSteps );
-    if ( nSteps < 3)
-    {
-        nSteps = 3;
-    }
-
-    double fScanInc = static_cast<double>(aRect.GetHeight()) / 
static_cast<double>(nSteps);
-    double fGradientLine = static_cast<double>(aRect.Top());
-    double fMirrorGradientLine = static_cast<double>(aMirrorRect.Bottom());
-
-    const double fStepsMinus1 = static_cast<double>(nSteps) - 1.0;
-    if ( !bLinear)
-    {
-        nSteps -= 1; // draw middle polygons as one polygon after loop to 
avoid gap
-    }
-    for ( tools::Long i = 0; i < nSteps; i++ )
-    {
-        // linear interpolation of color
-        double fAlpha = static_cast<double>(i) / fStepsMinus1;
-        double fTempColor = static_cast<double>(nStartRed) * (1.0-fAlpha) + 
static_cast<double>(nEndRed) * fAlpha;
-        nRed = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
-        fTempColor = static_cast<double>(nStartGreen) * (1.0-fAlpha) + 
static_cast<double>(nEndGreen) * fAlpha;
-        nGreen = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
-        fTempColor = static_cast<double>(nStartBlue) * (1.0-fAlpha) + 
static_cast<double>(nEndBlue) * fAlpha;
-        nBlue = GetGradientColorValue(static_cast<tools::Long>(fTempColor));
-
-        mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, 
nBlue ), true ) );
-
-        // Polygon for this color step
-        aRect.SetTop( static_cast<tools::Long>( fGradientLine + 
static_cast<double>(i) * fScanInc ) );
-        aRect.SetBottom( static_cast<tools::Long>( fGradientLine + ( 
static_cast<double>(i) + 1.0 ) * fScanInc ) );
-        aPoly[0] = aRect.TopLeft();
-        aPoly[1] = aRect.TopRight();
-        aPoly[2] = aRect.BottomRight();
-        aPoly[3] = aRect.BottomLeft();
-        aPoly.Rotate( aCenter, nAngle );
-
-        mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
-
-        if ( !bLinear )
-        {
-            aMirrorRect.SetBottom( static_cast<tools::Long>( 
fMirrorGradientLine - static_cast<double>(i) * fScanInc ) );
-            aMirrorRect.SetTop( static_cast<tools::Long>( fMirrorGradientLine 
- (static_cast<double>(i) + 1.0)* fScanInc ) );
-            aPoly[0] = aMirrorRect.TopLeft();
-            aPoly[1] = aMirrorRect.TopRight();
-            aPoly[2] = aMirrorRect.BottomRight();
-            aPoly[3] = aMirrorRect.BottomLeft();
-            aPoly.Rotate( aCenter, nAngle );
-
-            mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
-        }
-    }
-    if ( bLinear)
-        return;
-
-    // draw middle polygon with end color
-    nRed = GetGradientColorValue(nEndRed);
-    nGreen = GetGradientColorValue(nEndGreen);
-    nBlue = GetGradientColorValue(nEndBlue);
-
-    mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue 
), true ) );
-
-    aRect.SetTop( static_cast<tools::Long>( fGradientLine + 
static_cast<double>(nSteps) * fScanInc ) );
-    aRect.SetBottom( static_cast<tools::Long>( fMirrorGradientLine - 
static_cast<double>(nSteps) * fScanInc ) );
-    aPoly[0] = aRect.TopLeft();
-    aPoly[1] = aRect.TopRight();
-    aPoly[2] = aRect.BottomRight();
-    aPoly[3] = aRect.BottomLeft();
-    aPoly.Rotate( aCenter, nAngle );
-
-    mpMetaFile->AddAction( new MetaPolygonAction( aPoly ) );
-
-}
-
-void OutputDevice::DrawComplexGradientToMetafile( const tools::Rectangle& 
rRect,
-                                                  const Gradient& rGradient )
-{
-    assert(!is_double_buffered_window());
-
-    // Determine if we output via Polygon or PolyPolygon
-    // For all rasteroperations other than Overpaint always use PolyPolygon,
-    // as we will get wrong results if we output multiple times on top of each 
other.
-    // Also for printers always use PolyPolygon, as not all printers
-    // can print polygons on top of each other.
-
-    tools::Rectangle aRect;
-    Point aCenter;
-    rGradient.GetBoundRect(rRect, aRect, aCenter);
-
-    std::optional<tools::PolyPolygon> xPolyPoly;
-    xPolyPoly = tools::PolyPolygon( 2 );
-
-    // last parameter - true if complex gradient, false if linear
-    tools::Long nStepCount = GetGradientMetafileSteps(rGradient, rRect);
-
-    // at least three steps and at most the number of colour differences
-    tools::Long nSteps = std::max(nStepCount, tools::Long(2));
-
-    Color aStartCol(rGradient.GetStartColor());
-    Color aEndCol(rGradient.GetEndColor());
-
-    tools::Long nStartRed = (static_cast<tools::Long>(aStartCol.GetRed()) * 
rGradient.GetStartIntensity()) / 100;
-    tools::Long nStartGreen = (static_cast<tools::Long>(aStartCol.GetGreen()) 
* rGradient.GetStartIntensity()) / 100;
-    tools::Long nStartBlue = (static_cast<tools::Long>(aStartCol.GetBlue()) * 
rGradient.GetStartIntensity()) / 100;
-
-    tools::Long nEndRed = (static_cast<tools::Long>(aEndCol.GetRed()) * 
rGradient.GetEndIntensity()) / 100;
-    tools::Long nEndGreen = (static_cast<tools::Long>(aEndCol.GetGreen()) * 
rGradient.GetEndIntensity()) / 100;
-    tools::Long nEndBlue = (static_cast<tools::Long>(aEndCol.GetBlue()) * 
rGradient.GetEndIntensity()) / 100;
-
-    tools::Long nRedSteps = nEndRed - nStartRed;
-    tools::Long nGreenSteps = nEndGreen - nStartGreen;
-    tools::Long nBlueSteps = nEndBlue - nStartBlue;
-
-    tools::Long nCalcSteps  = std::abs(nRedSteps);
-    tools::Long nTempSteps = std::abs(nGreenSteps);
-
-    if (nTempSteps > nCalcSteps)
-        nCalcSteps = nTempSteps;
-
-    nTempSteps = std::abs( nBlueSteps );
-
-    if (nTempSteps > nCalcSteps)
-        nCalcSteps = nTempSteps;
-
-    if (nCalcSteps < nSteps)
-        nSteps = nCalcSteps;
-
-    if ( !nSteps )
-        nSteps = 1;
-
-    // determine output limits and stepsizes for all directions
-    tools::Polygon aPoly;
-    double  fScanLeft = aRect.Left();
-    double  fScanTop = aRect.Top();
-    double  fScanRight = aRect.Right();
-    double  fScanBottom = aRect.Bottom();
-    double fScanIncX = static_cast<double>(aRect.GetWidth()) / 
static_cast<double>(nSteps) * 0.5;
-    double fScanIncY = static_cast<double>(aRect.GetHeight()) / 
static_cast<double>(nSteps) * 0.5;
-
-    // all gradients are rendered as nested rectangles which shrink
-    // equally in each dimension - except for 'square' gradients
-    // which shrink to a central vertex but are not per-se square.
-    if( rGradient.GetStyle() != GradientStyle::Square )
-    {
-        fScanIncY = std::min( fScanIncY, fScanIncX );
-        fScanIncX = fScanIncY;
-    }
-    sal_uInt8   nRed = static_cast<sal_uInt8>(nStartRed), nGreen = 
static_cast<sal_uInt8>(nStartGreen), nBlue = static_cast<sal_uInt8>(nStartBlue);
-    bool    bPaintLastPolygon( false ); // #107349# Paint last polygon only if 
loop has generated any output
-
-    mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue 
), true ) );
-
-    aPoly = rRect;
-    xPolyPoly->Insert( aPoly );
-    xPolyPoly->Insert( aPoly );
-
-    // loop to output Polygon/PolyPolygon sequentially
-    for( tools::Long i = 1; i < nSteps; i++ )
-    {
-        // calculate new Polygon
-        fScanLeft += fScanIncX;
-        aRect.SetLeft( static_cast<tools::Long>( fScanLeft ) );
-        fScanTop += fScanIncY;
-        aRect.SetTop( static_cast<tools::Long>( fScanTop ) );
-        fScanRight -= fScanIncX;
-        aRect.SetRight( static_cast<tools::Long>( fScanRight ) );
-        fScanBottom -= fScanIncY;
-        aRect.SetBottom( static_cast<tools::Long>( fScanBottom ) );
-
-        if( ( aRect.GetWidth() < 2 ) || ( aRect.GetHeight() < 2 ) )
-            break;
-
-        if( rGradient.GetStyle() == GradientStyle::Radial || 
rGradient.GetStyle() == GradientStyle::Elliptical )
-            aPoly = tools::Polygon( aRect.Center(), aRect.GetWidth() >> 1, 
aRect.GetHeight() >> 1 );
-        else
-            aPoly = tools::Polygon( aRect );
-
-        aPoly.Rotate(aCenter, rGradient.GetAngle() % 3600_deg10);
-
-        // adapt colour accordingly
-        const tools::Long nStepIndex = ( xPolyPoly ? i : ( i + 1 ) );
-        nRed = GetGradientColorValue( nStartRed + ( ( nRedSteps * nStepIndex ) 
/ nSteps ) );
-        nGreen = GetGradientColorValue( nStartGreen + ( ( nGreenSteps * 
nStepIndex ) / nSteps ) );
-        nBlue = GetGradientColorValue( nStartBlue + ( ( nBlueSteps * 
nStepIndex ) / nSteps ) );
-
-        bPaintLastPolygon = true; // #107349# Paint last polygon only if loop 
has generated any output
-
-        xPolyPoly->Replace( xPolyPoly->GetObject( 1 ), 0 );
-        xPolyPoly->Replace( aPoly, 1 );
-
-        mpMetaFile->AddAction( new MetaPolyPolygonAction( *xPolyPoly ) );
-
-        // #107349# Set fill color _after_ geometry painting:
-        // xPolyPoly's geometry is the band from last iteration's
-        // aPoly to current iteration's aPoly. The window outdev
-        // path (see else below), on the other hand, paints the
-        // full aPoly. Thus, here, we're painting the band before
-        // the one painted in the window outdev path below. To get
-        // matching colors, have to delay color setting here.
-        mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, 
nBlue ), true ) );
-    }
-
-    const tools::Polygon& rPoly = xPolyPoly->GetObject( 1 );
-
-    if( rPoly.GetBoundRect().IsEmpty() )
-        return;
-
-    // #107349# Paint last polygon with end color only if loop
-    // has generated output. Otherwise, the current
-    // (i.e. start) color is taken, to generate _any_ output.
-    if( bPaintLastPolygon )
-    {
-        nRed = GetGradientColorValue( nEndRed );
-        nGreen = GetGradientColorValue( nEndGreen );
-        nBlue = GetGradientColorValue( nEndBlue );
-    }
-
-    mpMetaFile->AddAction( new MetaFillColorAction( Color( nRed, nGreen, nBlue 
), true ) );
-    mpMetaFile->AddAction( new MetaPolygonAction( rPoly ) );
-}
-
 tools::Long OutputDevice::GetGradientStepCount( tools::Long nMinRect )
 {
     tools::Long nInc = (nMinRect < 50) ? 2 : 4;
@@ -969,45 +628,4 @@ Color OutputDevice::GetSingleColorGradientFill()
     return aColor;
 }
 
-void OutputDevice::AddGradientActions( const tools::Rectangle& rRect, const 
Gradient& rGradient,
-                                       GDIMetaFile& rMtf )
-{
-
-    tools::Rectangle aRect( rRect );
-
-    aRect.Justify();
-
-    // do nothing if the rectangle is empty
-    if ( aRect.IsEmpty() )
-        return;
-
-    Gradient        aGradient( rGradient );
-    GDIMetaFile*    pOldMtf = mpMetaFile;
-
-    mpMetaFile = &rMtf;
-    mpMetaFile->AddAction( new MetaPushAction( vcl::PushFlags::ALL ) );
-    mpMetaFile->AddAction( new MetaISectRectClipRegionAction( aRect ) );
-    mpMetaFile->AddAction( new MetaLineColorAction( Color(), false ) );
-
-    // because we draw with no border line, we have to expand gradient
-    // rect to avoid missing lines on the right and bottom edge
-    aRect.AdjustLeft( -1 );
-    aRect.AdjustTop( -1 );
-    aRect.AdjustRight( 1 );
-    aRect.AdjustBottom( 1 );
-
-    // calculate step count if necessary
-    if ( !aGradient.GetSteps() )
-        aGradient.SetSteps( GRADIENT_DEFAULT_STEPCOUNT );
-
-    if( aGradient.GetStyle() == GradientStyle::Linear || aGradient.GetStyle() 
== GradientStyle::Axial )
-        DrawLinearGradientToMetafile( aRect, aGradient );
-    else
-        DrawComplexGradientToMetafile( aRect, aGradient );
-
-    mpMetaFile->AddAction( new MetaPopAction() );
-    mpMetaFile = pOldMtf;
-
-}
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit 88d8c9af7140ec25dfbcd9323b870a2da7b6f7e0
Author:     Tomaž Vajngerl <tomaz.vajng...@collabora.co.uk>
AuthorDate: Tue Jan 4 21:39:20 2022 +0900
Commit:     Tomaž Vajngerl <qui...@gmail.com>
CommitDate: Wed Jan 5 05:42:14 2022 +0100

    sc: fix crash with document properties dialog
    
    "ImagePreferredDPI" property was added for impress and writer,
    but it was not handled in calc, so it document properties dialog
    crashed (exception because of a non existent property).
    
    Change-Id: I9eb3f6aa7cf6d8ab48930b3071b993e073117688
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127942
    Tested-by: Jenkins
    Reviewed-by: Tomaž Vajngerl <qui...@gmail.com>

diff --git a/sc/inc/unonames.hxx b/sc/inc/unonames.hxx
index 81e849fc7fa0..556f003d2a33 100644
--- a/sc/inc/unonames.hxx
+++ b/sc/inc/unonames.hxx
@@ -574,6 +574,7 @@ inline constexpr OUStringLiteral 
SC_SERVICENAME_CHART_PIVOTTABLE_DATAPROVIDER =
 #define SC_UNO_UPDTEMPL             "UpdateFromTemplate"
 #define SC_UNO_FILTERED_RANGE_SELECTION       "FilteredRangeSelection"
 #define SC_UNO_VISAREASCREEN        "VisibleAreaOnScreen"
+#define SC_UNO_IMAGE_PREFERRED_DPI  "ImagePreferredDPI"
 
 /*Stampit enable/disable print cancel */
 #define SC_UNO_ALLOWPRINTJOBCANCEL  "AllowPrintJobCancel"
diff --git a/sc/source/ui/unoobj/confuno.cxx b/sc/source/ui/unoobj/confuno.cxx
index 9fa7ca85a25b..c71f2f28fd04 100644
--- a/sc/source/ui/unoobj/confuno.cxx
+++ b/sc/source/ui/unoobj/confuno.cxx
@@ -89,6 +89,7 @@ static const SfxItemPropertyMapEntry* 
lcl_GetConfigPropertyMap()
         { SC_UNO_EMBED_FONT_SCRIPT_LATIN,   0,  cppu::UnoType<bool>::get(), 0, 
0},
         { SC_UNO_EMBED_FONT_SCRIPT_ASIAN,   0,  cppu::UnoType<bool>::get(), 0, 
0},
         { SC_UNO_EMBED_FONT_SCRIPT_COMPLEX, 0,  cppu::UnoType<bool>::get(), 0, 
0},
+        { SC_UNO_IMAGE_PREFERRED_DPI,       0,  
cppu::UnoType<sal_Int32>::get(), 0, 0},
         { SC_UNO_SYNTAXSTRINGREF, 0,  cppu::UnoType<sal_Int16>::get(),     0, 
0},
         { u"", 0, css::uno::Type(), 0, 0 }
     };
@@ -396,7 +397,13 @@ void SAL_CALL ScDocumentConfiguration::setPropertyValue(
             rDoc.SetCalcConfig( aCalcConfig );
         }
     }
-
+    else if (aPropertyName == SC_UNO_IMAGE_PREFERRED_DPI)
+    {
+        if (aValue.has<sal_Int32>())
+        {
+            rDoc.SetImagePreferredDPI(aValue.get<sal_Int32>());
+        }
+    }
     else
     {
         ScGridOptions aGridOpt(aViewOpt.GetGridOptions());
@@ -599,7 +606,10 @@ uno::Any SAL_CALL 
ScDocumentConfiguration::getPropertyValue( const OUString& aPr
              }
         }
     }
-
+    else if (aPropertyName == SC_UNO_IMAGE_PREFERRED_DPI)
+    {
+        aRet <<= rDoc.GetImagePreferredDPI();
+    }
     else
     {
         const ScGridOptions& aGridOpt = aViewOpt.GetGridOptions();

Reply via email to