sw/qa/extras/rtfexport/data/tdf159824_gradientAngle1.rtf |   17 ++++
 sw/qa/extras/rtfexport/data/tdf159824_gradientAngle2.rtf |   17 ++++
 sw/qa/extras/rtfexport/rtfexport8.cxx                    |   57 +++++++++++++--
 sw/source/filter/ww8/rtfattributeoutput.cxx              |    9 ++
 writerfilter/source/rtftok/rtfsdrimport.cxx              |    4 +
 5 files changed, 97 insertions(+), 7 deletions(-)

New commits:
commit 64398a41f7d4110b58f0496f1237a6778772b05c
Author:     Justin Luth <jl...@mail.com>
AuthorDate: Wed Feb 21 16:37:31 2024 -0500
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Mon Feb 26 09:06:28 2024 +0100

    related tdf#159824 RTF import/export gradient angle
    
    The fillAngle is important for obvious visual reasons,
    but also significantly because a negative angle
    means that the start/end colors should be swapped
    (which is the normal case since
    LO's 0 degree angle == -180 VML/RTF angle).
    
    There were no existing unit tests with a "fillAngle" specified,
    or with a non-180 angle (0 VML/RTF angle) in LO.
    
    make CppunitTest_sw_rtfexport8 \
        CPPUNIT_TEST_NAME=testTdf159824_gradientAngle1
    make CppunitTest_sw_rtfexport8 \
        CPPUNIT_TEST_NAME=testTdf159824_gradientAngle2
    make CppunitTest_sw_rtfexport8 \
        CPPUNIT_TEST_NAME=testTdf159824_axialGradient
    
    Change-Id: I4bb2c47bd2a79833d11bedac72ba2152b65b7c73
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163714
    Tested-by: Jenkins
    Reviewed-by: Justin Luth <jl...@mail.com>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/163870
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>

diff --git a/sw/qa/extras/rtfexport/data/tdf159824_gradientAngle1.rtf 
b/sw/qa/extras/rtfexport/data/tdf159824_gradientAngle1.rtf
new file mode 100644
index 000000000000..37fd8ae2e339
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/tdf159824_gradientAngle1.rtf
@@ -0,0 +1,17 @@
+{ tf1nsi\deff3deflang1025
+
+\landscape\paperh5940\paperw8391
+
+{
+\shp{\*\shpinst\shptop382\shpbottom2737\shpleft759\shpright5064
+{\sp{\sn shapeType}{\sv 202}}
+{\sp{\sn fillType}{\sv 7}}
+{\sp{\sn fillAngle}{\sv 60000}}
+{\sp{\sn fillFocus}{\sv 0}}
+{\sp{\sn fillColor}{\sv 1758337}}
+{\sp{\sn fillBackColor}{\sv 16777215}}
+
+{\shptxt\par \pard}}
+}
+
+\par }
diff --git a/sw/qa/extras/rtfexport/data/tdf159824_gradientAngle2.rtf 
b/sw/qa/extras/rtfexport/data/tdf159824_gradientAngle2.rtf
new file mode 100644
index 000000000000..223864f3281b
--- /dev/null
+++ b/sw/qa/extras/rtfexport/data/tdf159824_gradientAngle2.rtf
@@ -0,0 +1,17 @@
+{ tf1nsi\deff3deflang1025
+
+\landscape\paperh5940\paperw8391
+
+{
+\shp{\*\shpinst\shptop382\shpbottom2737\shpleft759\shpright5064
+{\sp{\sn shapeType}{\sv 202}}
+{\sp{\sn fillType}{\sv 7}}
+{\sp{\sn fillAngle}{\sv -120000}}
+{\sp{\sn fillFocus}{\sv 0}}
+{\sp{\sn fillColor}{\sv 1758337}}
+{\sp{\sn fillBackColor}{\sv 16777215}}
+
+{\shptxt\par \pard}}
+}
+
+\par }
diff --git a/sw/qa/extras/rtfexport/rtfexport8.cxx 
b/sw/qa/extras/rtfexport/rtfexport8.cxx
index ab787919dfa9..c0b8cbad9a0a 100644
--- a/sw/qa/extras/rtfexport/rtfexport8.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport8.cxx
@@ -195,8 +195,8 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf159824_axialGradient)
                          getProperty<drawing::FillStyle>(xFrame, "FillStyle"));
     awt::Gradient2 aGradient = getProperty<awt::Gradient2>(xFrame, 
"FillGradient");
 
-    //const Color aColA(0x127622); // green
-    //const Color aColB(0xffffff); // white
+    const Color aColA(0x127622); // green
+    const Color aColB(0xffffff); // white
 
     // MCGR: Use the completely imported transparency gradient to check for 
correctness
     basegfx::BColorStops aColorStops = 
model::gradient::getColorStopsFromUno(aGradient.ColorStops);
@@ -205,11 +205,54 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf159824_axialGradient)
     CPPUNIT_ASSERT_EQUAL(size_t(3), aColorStops.size());
     CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_LINEAR, aGradient.Style);
     CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[0].getStopOffset(), 
0.0));
-    //CPPUNIT_ASSERT_EQUAL(aColB, Color(aColorStops[0].getStopColor()));
-    // CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[1].getStopOffset(), 
0.5));
-    // CPPUNIT_ASSERT_EQUAL(aColA, Color(aColorStops[1].getStopColor()));
-    // CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[2].getStopOffset(), 
1.0));
-    // CPPUNIT_ASSERT_EQUAL(aColB, Color(aColorStops[2].getStopColor()));
+    CPPUNIT_ASSERT_EQUAL(aColB, Color(aColorStops[0].getStopColor()));
+    CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[1].getStopOffset(), 
0.5));
+    CPPUNIT_ASSERT_EQUAL(aColA, Color(aColorStops[1].getStopColor()));
+    CPPUNIT_ASSERT(basegfx::fTools::equal(aColorStops[2].getStopOffset(), 
1.0));
+    CPPUNIT_ASSERT_EQUAL(aColB, Color(aColorStops[2].getStopColor()));
+}
+
+DECLARE_RTFEXPORT_TEST(testTdf159824_gradientAngle1, 
"tdf159824_gradientAngle1.rtf")
+{
+    // given a frame with a white (top) to lime (bottom) linear gradient at an 
RTF 1° angle
+    uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> 
xIndexAccess(xTextFramesSupplier->getTextFrames(),
+                                                         uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> xFrame(xIndexAccess->getByIndex(0), 
uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_GRADIENT,
+                         getProperty<drawing::FillStyle>(xFrame, "FillStyle"));
+    awt::Gradient2 aGradient = getProperty<awt::Gradient2>(xFrame, 
"FillGradient");
+
+    // MCGR: Use the completely imported transparency gradient to check for 
correctness
+    basegfx::BColorStops aColorStops = 
model::gradient::getColorStopsFromUno(aGradient.ColorStops);
+
+    CPPUNIT_ASSERT_EQUAL(size_t(2), aColorStops.size());
+    CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_LINEAR, aGradient.Style);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(8508442), aGradient.StartColor);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(COL_WHITE), aGradient.EndColor);
+    // RTF 1° angle (in 1/60,000 degree units = 60,000) == LO 181° (in 1/10 
degree unites)
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(181), sal_Int32(aGradient.Angle / 10));
+}
+
+DECLARE_RTFEXPORT_TEST(testTdf159824_gradientAngle2, 
"tdf159824_gradientAngle2.rtf")
+{
+    // given a frame with a lime (top) to white (bottom) linear gradient at an 
RTF -2° angle.
+    uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, 
uno::UNO_QUERY);
+    uno::Reference<container::XIndexAccess> 
xIndexAccess(xTextFramesSupplier->getTextFrames(),
+                                                         uno::UNO_QUERY);
+    uno::Reference<beans::XPropertySet> xFrame(xIndexAccess->getByIndex(0), 
uno::UNO_QUERY);
+    CPPUNIT_ASSERT_EQUAL(drawing::FillStyle_GRADIENT,
+                         getProperty<drawing::FillStyle>(xFrame, "FillStyle"));
+    awt::Gradient2 aGradient = getProperty<awt::Gradient2>(xFrame, 
"FillGradient");
+
+    // MCGR: Use the completely imported transparency gradient to check for 
correctness
+    basegfx::BColorStops aColorStops = 
model::gradient::getColorStopsFromUno(aGradient.ColorStops);
+    CPPUNIT_ASSERT_EQUAL(size_t(2), aColorStops.size());
+    CPPUNIT_ASSERT_EQUAL(awt::GradientStyle_LINEAR, aGradient.Style);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(8508442), aGradient.StartColor);
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(COL_WHITE), aGradient.EndColor);
+    // RTF -2° angle (in 1/60,000 degree units = -120,000) == LO 358° (in 1/10 
degree unites)
+    CPPUNIT_ASSERT_EQUAL(sal_Int32(358), sal_Int32(aGradient.Angle / 10));
 }
 
 DECLARE_RTFEXPORT_TEST(testTdf158830, "tdf158830.rtf")
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx 
b/sw/source/filter/ww8/rtfattributeoutput.cxx
index 05e1cbc2cd22..3b9127fb2c53 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -3741,6 +3741,15 @@ void RtfAttributeOutput::FormatFillGradient(const 
XFillGradientItem& rFillGradie
     m_aFlyProperties.push_back(std::make_pair<OString, OString>(
         "fillColor"_ostr, OString::number(wwUtility::RGBToBGR(aStartColor))));
 
+    // LO's angle is 180° different from VML/RTF. Copied docxattribute angle 
formula here.
+    sal_Int32 nReverseAngle = toDegrees(4500_deg10 - rGradient.GetAngle());
+    nReverseAngle = (270 - nReverseAngle) % 360;
+    if (nReverseAngle != 0)
+    {
+        m_aFlyProperties.push_back(std::make_pair<OString, OString>(
+            "fillAngle"_ostr, OString::number(nReverseAngle * 60000)));
+    }
+
     if (rColorStops.size() < 3)
     {
         // two-color version, use back as 2nd color
diff --git a/writerfilter/source/rtftok/rtfsdrimport.cxx 
b/writerfilter/source/rtftok/rtfsdrimport.cxx
index c4e0538e2a2c..f263f2a43f77 100644
--- a/writerfilter/source/rtftok/rtfsdrimport.cxx
+++ b/writerfilter/source/rtftok/rtfsdrimport.cxx
@@ -666,6 +666,10 @@ void RTFSdrImport::resolve(RTFShape& rShape, bool bClose, 
ShapeOrPict const shap
                     break;
             }
         }
+        else if (rProperty.first == "fillAngle")
+        {
+            aFillModel.moAngle = rProperty.second.toInt32() / 60000;
+        }
         else if (rProperty.first == "fillFocus")
             aFillModel.moFocus = rProperty.second.toDouble() / 100; // percent
         else if (rProperty.first == "fShadow" && xPropertySet.is())

Reply via email to