summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Sherlock <chris.sherlock79@gmail.com>2021-12-18 23:39:25 +1100
committerTomaž Vajngerl <quikee@gmail.com>2022-01-05 05:42:32 +0100
commit22f52db0be81ceec2aa7a61f7092b54f36e2d00c (patch)
treef1f2a02824321d53f949146a480db12186ca45ee
parent88d8c9af7140ec25dfbcd9323b870a2da7b6f7e0 (diff)
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 <quikee@gmail.com>
-rw-r--r--cppcanvas/source/mtfrenderer/implrenderer.cxx5
-rw-r--r--filter/source/svg/svgwriter.cxx8
-rw-r--r--include/vcl/gradient.hxx9
-rw-r--r--include/vcl/outdev.hxx10
-rw-r--r--vcl/CppunitTest_vcl_gradient.mk50
-rw-r--r--vcl/Module_vcl.mk1
-rw-r--r--vcl/qa/cppunit/gradient.cxx256
-rw-r--r--vcl/qa/cppunit/outdev.cxx218
-rw-r--r--vcl/source/filter/eps/eps.cxx3
-rw-r--r--vcl/source/filter/wmf/emfwr.cxx3
-rw-r--r--vcl/source/filter/wmf/wmfwr.cxx3
-rw-r--r--vcl/source/gdi/gradient.cxx382
-rw-r--r--vcl/source/gdi/pdfwriter_impl2.cxx3
-rw-r--r--vcl/source/outdev/gradient.cxx382
14 files changed, 715 insertions, 618 deletions
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: */