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 695f8fb19d839efe03a402d2a7e7ef73b6d8f436 Author: Justin Luth <jl...@mail.com> AuthorDate: Wed Feb 21 16:37:31 2024 -0500 Commit: Justin Luth <jl...@mail.com> CommitDate: Fri Feb 23 20:28:05 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> 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 b3fbec75a8f5..1d28ccabed8b 100644 --- a/sw/source/filter/ww8/rtfattributeoutput.cxx +++ b/sw/source/filter/ww8/rtfattributeoutput.cxx @@ -3752,6 +3752,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 15f0393bc90f..031f24117d00 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())