From 567dbcf68711402736f65f4a0a47ef57549fe50f Mon Sep 17 00:00:00 2001 From: Regina Henschel Date: Sat, 1 Jun 2024 19:50:47 +0200 Subject: [PATCH] tdf#161327 Interpret angle units in dr3d:end-angle .. .. and draw:rotation in element. ODF 1.1 has not specified the syntax of datatype 'angle'. Since ODF 1.2 it is specified as double with unit "deg", "grad" or "rad", or without unit. The unit-less value is specified to be in degrees. But OOo, AOO and all LO versions had written the value unit-less in 1/10th of a degree in some cases. To fix it, LibreOffic will be enabled to read units. When then the active versions are able to read units, starting with the then actual version, LibreOffice will write angles with unit 'deg'. This has already be done for gradients, see tdf#89475. This patch starts the first step to make LibreOffice able to read units for dr3d:end-angle (UNO D3DEndAngle) and for draw:rotation (UNO FillHatch.Angle). I have not found further cases of writing 1/10deg. The patch still writes unit-less 1/10th of a degree for export to ODF 1.3 and earlier. When it is time to write unit degree or when LibreOffice supports the next ODF versions, some places need to be adapted. They are marked. The converter convertAngle is renamed to convert10thDegAngle() to indicate, that it is special. The parts, which were specific to gradients are moved to the gradients, so that it is now usable for dr3d:angle and draw:rotation too. I intend to write next a patch that enables LibreOffice to read angle units for cases where LibreOffice already writes unit-less values in degree. That is not so urgent, but to bring LibreOffice nearer to ODF, reading angle units should be implemented nevertheless. The file xmlbahdl.hxx is moved from xmloff/source/style to xmloff/inc to have access to it from xmloff/source/draw. Change-Id: I8ffc2735f8bcfefb86efa80eb05f900c32403f31 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/168336 Tested-by: Jenkins Reviewed-by: Michael Stahl Reviewed-by: Regina Henschel --- include/sax/tools/converter.hxx | 16 +- sax/source/tools/converter.cxx | 117 ++--- sd/qa/unit/import-tests.cxx | 8 +- solenv/clang-format/excludelist | 2 +- xmloff/{source/style => inc}/xmlbahdl.hxx | 0 xmloff/inc/xmlsdtypes.hxx | 1 + xmloff/qa/unit/data/tdf161327_HatchAngle.fodg | 404 ++++++++++++++++++ .../qa/unit/data/tdf161327_LatheEndAngle.fodg | 359 ++++++++++++++++ xmloff/qa/unit/draw.cxx | 57 +++ xmloff/source/draw/sdpropls.cxx | 64 ++- xmloff/source/style/GradientStyle.cxx | 32 +- xmloff/source/style/HatchStyle.cxx | 28 +- .../source/style/PageMasterPropHdlFactory.cxx | 2 +- xmloff/source/style/TransGradientStyle.cxx | 36 +- xmloff/source/style/prhdlfac.cxx | 2 +- xmloff/source/style/xmlbahdl.cxx | 2 +- 16 files changed, 1013 insertions(+), 117 deletions(-) rename xmloff/{source/style => inc}/xmlbahdl.hxx (100%) create mode 100644 xmloff/qa/unit/data/tdf161327_HatchAngle.fodg create mode 100644 xmloff/qa/unit/data/tdf161327_LatheEndAngle.fodg diff --git a/include/sax/tools/converter.hxx b/include/sax/tools/converter.hxx index d797eace3042..bb97acc595ac 100644 --- a/include/sax/tools/converter.hxx +++ b/include/sax/tools/converter.hxx @@ -199,16 +199,16 @@ public: static bool convertDouble(double& rValue, std::string_view rString); /** convert number, 10th of degrees with range [0..3600] to SVG angle */ - static void convertAngle(OUStringBuffer& rBuffer, sal_Int16 nAngle, - SvtSaveOptions::ODFSaneDefaultVersion nVersion); + static void convert10thDegAngle(OUStringBuffer& rBuffer, sal_Int16 nAngle, + const bool isWrongOOo10thDegAngle); - /** convert SVG angle to number, 10th of degrees with range [0..3600] */ - static bool convertAngle(sal_Int16& rAngle, std::u16string_view rString, - bool isWrongOOo10thDegAngle); + /** convert SVG angle to number in 10th of degrees */ + static bool convert10thDegAngle(sal_Int16& rAngle, std::u16string_view rString, + bool isWrongOOo10thDegAngle); - /** convert SVG angle to number, 10th of degrees with range [0..3600] */ - static bool convertAngle(sal_Int16& rAngle, std::string_view rString, - bool isWrongOOo10thDegAngle); + /** convert SVG angle to number in 10th of degrees */ + static bool convert10thDegAngle(sal_Int16& rAngle, std::string_view rString, + bool isWrongOOo10thDegAngle); /** convert double to XMLSchema-2 "duration" string; negative durations allowed */ static void convertDuration(OUStringBuffer& rBuffer, diff --git a/sax/source/tools/converter.cxx b/sax/source/tools/converter.cxx index 09156a0a9405..bc2342d5b508 100644 --- a/sax/source/tools/converter.cxx +++ b/sax/source/tools/converter.cxx @@ -725,25 +725,24 @@ bool Converter::convertDouble(double& rValue, std::string_view rString) } /** convert number, 10th of degrees with range [0..3600] to SVG angle */ -void Converter::convertAngle(OUStringBuffer& rBuffer, sal_Int16 const nAngle, - SvtSaveOptions::ODFSaneDefaultVersion const nVersion) +void Converter::convert10thDegAngle(OUStringBuffer& rBuffer, sal_Int16 const nAngle, + const bool isWrongOOo10thDegAngle) { - if (nVersion < SvtSaveOptions::ODFSVER_012 || nVersion == SvtSaveOptions::ODFSVER_012_EXT_COMPAT) + if (isWrongOOo10thDegAngle) { - // wrong, but backward compatible with OOo/LO < 4.4 rBuffer.append(static_cast(nAngle)); } else - { // OFFICE-3774 tdf#89475 write valid ODF 1.2 angle; needs LO 4.4 to import + { double fAngle(double(nAngle) / 10.0); ::sax::Converter::convertDouble(rBuffer, fAngle); rBuffer.append("deg"); } } -/** convert SVG angle to number, 10th of degrees with range [0..3600] */ -bool Converter::convertAngle(sal_Int16& rAngle, std::u16string_view rString, - bool const isWrongOOo10thDegAngle) +/** convert SVG angle to number in 10th of degrees */ +bool Converter::convert10thDegAngle(sal_Int16& rAngle, std::u16string_view rString, + bool const isWrongOOo10thDegAngle) { // ODF 1.1 leaves it undefined what the number means, but ODF 1.2 says it's // degrees, while OOo has historically used 10th of degrees :( @@ -751,49 +750,30 @@ bool Converter::convertAngle(sal_Int16& rAngle, std::u16string_view rString, // degrees for now for the sake of existing OOo/LO documents, until the // new versions that can read "deg" suffix are widely deployed and we can // start to write the "deg" suffix. - sal_Int32 nValue(0); - double fValue(0.0); - bool bRet = ::sax::Converter::convertDouble(fValue, rString); - if (std::u16string_view::npos != rString.find(u"deg")) - { - nValue = fValue * 10.0; - } - else if (std::u16string_view::npos != rString.find(u"grad")) - { - nValue = (fValue * 9.0 / 10.0) * 10.0; - } - else if (std::u16string_view::npos != rString.find(u"rad")) - { - nValue = basegfx::rad2deg<10>(fValue); - } - else // no explicit unit - { - if (isWrongOOo10thDegAngle) - { - nValue = fValue; // wrong, but backward compatible with OOo/LO < 7.0 - } - else - { - nValue = fValue * 10.0; // ODF 1.2 - } - } - // limit to valid range [0..3600] - nValue = nValue % 3600; - if (nValue < 0) - { - nValue += 3600; - } - assert(0 <= nValue && nValue <= 3600); + double fAngle(0.0); + bool bRet = ::sax::Converter::convertDouble(fAngle, rString); if (bRet) { - rAngle = sal::static_int_cast(nValue); + if (std::u16string_view::npos != rString.find(u"deg")) + fAngle *= 10.0; + else if (std::u16string_view::npos != rString.find(u"grad")) + fAngle *= 9.0; // 360deg = 400grad + else if (std::u16string_view::npos != rString.find(u"rad")) + fAngle = basegfx::rad2deg<10>(fAngle); + else // no explicit unit + { // isWrongOOo10thDegAngle = true: nothing to do here. Wrong, but backward compatible. + if (!isWrongOOo10thDegAngle) + fAngle *= 10.0; // conform to ODF 1.2 and newer + } + fAngle = std::clamp(basegfx::fround(fAngle), SHRT_MIN, SHRT_MAX); + rAngle = static_cast(fAngle); } return bRet; } /** convert SVG angle to number, 10th of degrees with range [0..3600] */ -bool Converter::convertAngle(sal_Int16& rAngle, std::string_view rString, - bool const isWrongOOo10thDegAngle) +bool Converter::convert10thDegAngle(sal_Int16& rAngle, std::string_view rString, + bool const isWrongOOo10thDegAngle) { // ODF 1.1 leaves it undefined what the number means, but ODF 1.2 says it's // degrees, while OOo has historically used 10th of degrees :( @@ -801,42 +781,23 @@ bool Converter::convertAngle(sal_Int16& rAngle, std::string_view rString, // degrees for now for the sake of existing OOo/LO documents, until the // new versions that can read "deg" suffix are widely deployed and we can // start to write the "deg" suffix. - sal_Int32 nValue(0); - double fValue(0.0); - bool bRet = ::sax::Converter::convertDouble(fValue, rString); - if (std::string_view::npos != rString.find("deg")) - { - nValue = fValue * 10.0; - } - else if (std::string_view::npos != rString.find("grad")) - { - nValue = (fValue * 9.0 / 10.0) * 10.0; - } - else if (std::string_view::npos != rString.find("rad")) - { - nValue = basegfx::rad2deg<10>(fValue); - } - else // no explicit unit - { - if (isWrongOOo10thDegAngle) - { - nValue = fValue; // wrong, but backward compatible with OOo/LO < 7.0 - } - else - { - nValue = fValue * 10.0; // ODF 1.2 - } - } - // limit to valid range [0..3600] - nValue = nValue % 3600; - if (nValue < 0) - { - nValue += 3600; - } - assert(0 <= nValue && nValue <= 3600); + double fAngle(0.0); + bool bRet = ::sax::Converter::convertDouble(fAngle, rString); if (bRet) { - rAngle = sal::static_int_cast(nValue); + if (std::string_view::npos != rString.find("deg")) + fAngle *= 10.0; + else if (std::string_view::npos != rString.find("grad")) + fAngle *= 9.0; // 360deg = 400grad + else if (std::string_view::npos != rString.find("rad")) + fAngle = basegfx::rad2deg<10>(fAngle); + else // no explicit unit + { // isWrongOOo10thDegAngle = true: nothing to do here. Wrong, but backward compatible. + if (!isWrongOOo10thDegAngle) + fAngle *= 10.0; // conform to ODF 1.2 and newer + } + fAngle = std::clamp(basegfx::fround(fAngle), SHRT_MIN, SHRT_MAX); + rAngle = static_cast(fAngle); } return bRet; } diff --git a/sd/qa/unit/import-tests.cxx b/sd/qa/unit/import-tests.cxx index d865b4752b83..bbde4f833efb 100644 --- a/sd/qa/unit/import-tests.cxx +++ b/sd/qa/unit/import-tests.cxx @@ -1040,7 +1040,7 @@ CPPUNIT_TEST_FIXTURE(SdImportTest, testGradientAngle) CPPUNIT_ASSERT_EQUAL(sal_Int16(270), gradient.Angle); // 27deg CPPUNIT_ASSERT(xGradients->getByName(u"Gradient 11"_ustr) >>= gradient); - CPPUNIT_ASSERT_EQUAL(sal_Int16(1145), gradient.Angle); // 2rad + CPPUNIT_ASSERT_EQUAL(sal_Int16(1146), gradient.Angle); // 2rad = 114.591deg CPPUNIT_ASSERT(xGradients->getByName(u"Gradient 12"_ustr) >>= gradient); CPPUNIT_ASSERT_EQUAL(sal_Int16(900), gradient.Angle); // 100grad @@ -1049,7 +1049,7 @@ CPPUNIT_TEST_FIXTURE(SdImportTest, testGradientAngle) CPPUNIT_ASSERT_EQUAL(sal_Int16(3599), gradient.Angle); // -1 CPPUNIT_ASSERT(xGradients->getByName(u"Gradient 14"_ustr) >>= gradient); - CPPUNIT_ASSERT_EQUAL(sal_Int16(3028), gradient.Angle); // -1rad + CPPUNIT_ASSERT_EQUAL(sal_Int16(3027), gradient.Angle); // -1rad = -57.295deg -> 302.704deg CPPUNIT_ASSERT(xGradients->getByName(u"Gradient 15"_ustr) >>= gradient); CPPUNIT_ASSERT_EQUAL(sal_Int16(300), gradient.Angle); // 3900 @@ -1071,10 +1071,10 @@ CPPUNIT_TEST_FIXTURE(SdImportTest, testGradientAngle) CPPUNIT_ASSERT_EQUAL(sal_Int16(900), gradient.Angle); // 90deg CPPUNIT_ASSERT(xTranspGradients->getByName(u"Transparency 3"_ustr) >>= gradient); - CPPUNIT_ASSERT_EQUAL(sal_Int16(572), gradient.Angle); // 1.0rad + CPPUNIT_ASSERT_EQUAL(sal_Int16(573), gradient.Angle); // 1.0rad = 57.295deg CPPUNIT_ASSERT(xTranspGradients->getByName(u"Transparency 4"_ustr) >>= gradient); - CPPUNIT_ASSERT_EQUAL(sal_Int16(1800), gradient.Angle); // 1000grad + CPPUNIT_ASSERT_EQUAL(sal_Int16(1800), gradient.Angle); // 1000grad = 900deg -> 180deg } CPPUNIT_TEST_FIXTURE(SdImportTest, testN778859) diff --git a/solenv/clang-format/excludelist b/solenv/clang-format/excludelist index 8a02d8bab2d0..05b7c938fd3c 100644 --- a/solenv/clang-format/excludelist +++ b/solenv/clang-format/excludelist @@ -15221,6 +15221,7 @@ xmloff/inc/txtfldi.hxx xmloff/inc/txtlists.hxx xmloff/inc/txtvfldi.hxx xmloff/inc/xexptran.hxx +xmloff/inc/xmlbahdl.hxx xmloff/inc/xmlmultiimagehelper.hxx xmloff/inc/xmlsdtypes.hxx xmloff/inc/xmltabe.hxx @@ -15521,7 +15522,6 @@ xmloff/source/style/weighhdl.cxx xmloff/source/style/weighhdl.hxx xmloff/source/style/xmlaustp.cxx xmloff/source/style/xmlbahdl.cxx -xmloff/source/style/xmlbahdl.hxx xmloff/source/style/xmlexppr.cxx xmloff/source/style/xmlimppr.cxx xmloff/source/style/xmlnume.cxx diff --git a/xmloff/source/style/xmlbahdl.hxx b/xmloff/inc/xmlbahdl.hxx similarity index 100% rename from xmloff/source/style/xmlbahdl.hxx rename to xmloff/inc/xmlbahdl.hxx diff --git a/xmloff/inc/xmlsdtypes.hxx b/xmloff/inc/xmlsdtypes.hxx index c6e0ad315e22..42bf8b865f81 100644 --- a/xmloff/inc/xmlsdtypes.hxx +++ b/xmloff/inc/xmlsdtypes.hxx @@ -119,6 +119,7 @@ #define XML_SD_TYPE_CELL_ROTATION_ANGLE (XML_SD_TYPES_START + 79 ) #define XML_SD_TYPE_WRITINGMODE2 (XML_SD_TYPES_START + 80 ) +#define XML_SD_TYPE_LATHE_ENDANGLE (XML_SD_TYPES_START + 81 ) #define CTF_NUMBERINGRULES 1000 #define CTF_CONTROLWRITINGMODE 1001 diff --git a/xmloff/qa/unit/data/tdf161327_HatchAngle.fodg b/xmloff/qa/unit/data/tdf161327_HatchAngle.fodg new file mode 100644 index 000000000000..a3042373f822 --- /dev/null +++ b/xmloff/qa/unit/data/tdf161327_HatchAngle.fodg @@ -0,0 +1,404 @@ + + + + 2024-06-08T22:15:21.57700000024cm x 16cmPT24M13S2LODev_daily_installed/24.8.0.0.alpha1$Windows_X86_64 LibreOffice_project/fbe57382eef1138999f63e01b6152d4d05749807Regina Henschel2024-06-08T22:50:25.268000000Regina Henschel + + + -2233 + -250 + 21500 + 3967 + + + view1 + true + false + true + false + true + false + false + true + true + 1500 + false + Hw== + Hw== + + false + true + true + 0 + 0 + true + true + false + 4 + 0 + -2233 + -250 + 21501 + 11534 + 500 + 500 + 100 + 100 + 500 + 5 + 500 + 5 + false + 1500 + false + false + false + false + false + + + + + 1251 + 0 + EPSON6FC99C (WP-4025 Series) + iAv+/0VQU09ONkZDOTlDIChXUC00MDI1IFNlcmllcykAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARVBTT04gV1AtNDAyNSBTZXJpZXMAAAAAAAAAAAAAAAAWAAEAWgoAAAAAAAAEAAhSAAAEdAAAM1ROVwAAAAAKAEUAUABTAE8ATgA2AEYAQwA5ADkAQwAgACgAVwBQAC0ANAAwADIANQAgAFMAZQByAGkAZQBzACkAAAAAAAAAAAABBAAB3AB0CQ+bgAcBAAkAmgs0CGQAAQAHAFgCAgABAFgCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0CQAAAQEBAQABAAABAAAAAAAAAAAAAAA4AAAAfAgAALQIAABAAAAA9AgAAIAAAAAAAAAAAAAAAAMACQRFAFAAUwBPAE4AIABXAFAALQA0ADAAMgA1ACAAUwBlAHIAaQBlAHMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABYAgAAAAAAAAAAAAABAAAAAgAAAAAAAQBYAlgCBwAAAAAACQA0CJoLHgAeAB4AHgA0CJoLOwORBAEAAAAOABYAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAYAAAAAAAAAAAACAAAAAAIAAAMAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABkAGQANAiaCx4AHgAeAB4ACQAAAAAAAAAAAAAA//8AAAAAAAAAAB4AHgABAAAAAwDgAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAQAAgAAAAAAAAAAAAEAMgAyANT+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYACoAAAAgAAEAAAAgAAAAQAAAAAYAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs/wAAAAAAAAAAAABCAAAAAQAAALAAAAAAAAAAAAAAAAAAAAAeAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBARIAQ09NUEFUX0RVUExFWF9NT0RFDwBEdXBsZXhNb2RlOjpPZmYMAFBSSU5URVJfTkFNRRwARVBTT042RkM5OUMgKFdQLTQwMjUgU2VyaWVzKQsARFJJVkVSX05BTUUUAEVQU09OIFdQLTQwMjUgU2VyaWVz + false + false + false + false + false + true + false + true + false + true + true + true + 0 + $(inst)/share/palette%3B$(user)/config/standard.sod + $(inst)/share/palette/html.soc + false + $(inst)/share/palette%3B$(user)/config/standard.soe + $(user)/config/standard.soh + true + $(inst)/share/palette%3B$(user)/config/standard.sog + $(inst)/share/palette%3B$(user)/config/standard.sob + true + true + 4 + 0 + false + low-resolution + false + false + false + false + true + 2 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xmloff/qa/unit/data/tdf161327_LatheEndAngle.fodg b/xmloff/qa/unit/data/tdf161327_LatheEndAngle.fodg new file mode 100644 index 000000000000..f150bc182abc --- /dev/null +++ b/xmloff/qa/unit/data/tdf161327_LatheEndAngle.fodg @@ -0,0 +1,359 @@ + + + + 2024-06-01T13:16:26.90600000032x24PT2M18S3buildLO2/24.8.0.0.alpha1$Windows_X86_64 LibreOffice_project/010551e5c1277ed32e8b279660c27490bace0767Regina Henschel2024-06-01T13:22:05.137000000Regina Henschel + + + -346 + -2078 + 36561 + 24977 + + + view1 + true + false + false + true + true + false + false + true + true + 1500 + false + Hw== + Hw== + + false + true + true + 0 + 0 + true + true + true + 4 + 0 + -346 + -2078 + 36562 + 24978 + 500 + 500 + 100 + 100 + 500 + 5 + 500 + 5 + false + 1500 + true + false + false + false + false + + + + + 1250 + 0 + EPSON6FC99C (WP-4025 Series) + iAv+/0VQU09ONkZDOTlDIChXUC00MDI1IFNlcmllcykAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAARVBTT04gV1AtNDAyNSBTZXJpZXMAAAAAAAAAAAAAAAAWAAEAWgoAAAAAAAAEAAhSAAAEdAAAM1ROVwAAAAAKAEUAUABTAE8ATgA2AEYAQwA5ADkAQwAgACgAVwBQAC0ANAAwADIANQAgAFMAZQByAGkAZQBzACkAAAAAAAAAAAABBAAB3AB0CQ+bgAcBAAkAmgs0CGQAAQAHAFgCAgABAFgCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAAAAIAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAB0CQAAAQEBAQABAAABAAAAAAAAAAAAAAA4AAAAfAgAALQIAABAAAAA9AgAAIAAAAAAAAAAAAAAAAMACQRFAFAAUwBPAE4AIABXAFAALQA0ADAAMgA1ACAAUwBlAHIAaQBlAHMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABYAgAAAAAAAAAAAAABAAAAAgAAAAAAAQBYAlgCBwAAAAAACQA0CJoLHgAeAB4AHgA0CJoLOwORBAEAAAAOABYAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAYAAAAAAAAAAAACAAAAAAIAAAMAAAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAAAAABkAGQANAiaCx4AHgAeAB4ACQAAAAAAAAAAAAAA//8AAAAAAAAAAB4AHgABAAAAAwDgAgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAQAAgAAAAAAAAAAAAEAMgAyANT+AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/////wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABYACoAAAAgAAEAAAAgAAAAQAAAAAYAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADs/wAAAAAAAAAAAABCAAAAAQAAALAAAAAAAAAAAAAAAAAAAAAeAB4AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBARIAQ09NUEFUX0RVUExFWF9NT0RFDwBEdXBsZXhNb2RlOjpPZmYMAFBSSU5URVJfTkFNRRwARVBTT042RkM5OUMgKFdQLTQwMjUgU2VyaWVzKQsARFJJVkVSX05BTUUUAEVQU09OIFdQLTQwMjUgU2VyaWVz + false + false + false + false + false + true + false + true + false + true + true + true + 0 + $(inst)/share/palette%3B$(user)/config/standard.sod + $(inst)/share/palette%3B$(user)/config/html.soc + false + $(inst)/share/palette%3B$(user)/config/standard.soe + $(inst)/share/palette%3B$(user)/config/standard.soh + true + $(inst)/share/palette%3B$(user)/config/standard.sog + $(inst)/share/palette%3B$(user)/config/standard.sob + true + true + 4 + 0 + false + low-resolution + false + false + false + false + true + 2 + 1 + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/xmloff/qa/unit/draw.cxx b/xmloff/qa/unit/draw.cxx index 05d5a756d6e9..bfa279ca120f 100644 --- a/xmloff/qa/unit/draw.cxx +++ b/xmloff/qa/unit/draw.cxx @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include #include @@ -822,6 +824,61 @@ CPPUNIT_TEST_FIXTURE(XmloffDrawTest, test_scene3d_ooxml_light) save(u"impress8"_ustr); } +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTdf161327_LatheEndAngle) +{ + // Load document with 3D-Scene with 4 rotation objects + loadFromFile(u"tdf161327_LatheEndAngle.fodg"); + + // get scene object + uno::Reference xSceneShape(getShape(0)); + constexpr OUString sExpected(u"com.sun.star.drawing.Shape3DSceneObject"_ustr); + CPPUNIT_ASSERT_EQUAL(sExpected, xSceneShape->getShapeType()); + + // Examine child objects + // [0] dr3d:end-angle="1512" + // [1] dr3d:end-angle="151.2deg" + // [2] dr3d:end-angle="168.0grad" + // [3] dr3d:end-angle="2.638937829015430rad" + // All cases should result in D3DEndAngle = 1512. Without fix, cases [1], [2] and [3] + // could not be read and default 3600 was used, although the values are valid in ODF. + for (size_t i = 0; i < 4; ++i) + { + uno::Reference xGroup(xSceneShape, uno::UNO_QUERY); + uno::Reference xShape(xGroup->getByIndex(i), uno::UNO_QUERY); + uno::Reference xShapeProps(xShape, uno::UNO_QUERY); + sal_Int16 nEndAngle; + xShapeProps->getPropertyValue(u"D3DEndAngle"_ustr) >>= nEndAngle; + CPPUNIT_ASSERT_EQUAL(sal_Int16(1512), nEndAngle); + } +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTdf161327_HatchAngle) +{ + // Load document with four rectangles with linear hatch background fill + loadFromFile(u"tdf161327_HatchAngle.fodg"); + + // The hatch angle is given in file as + // [0] 585 unit less + // [1] 58.5deg, + // [2] 65grad, + // [3] 1.01201761241668rad + // The resulting angle should be 585 (meaning 1/10 of a degree) in all cases. + // Cases [1], [2] and [3] had angle 0 without fix. + for (size_t i = 0; i < 4; ++i) + { + uno::Reference xShape(getShape(i)); + uno::Reference xShapeProps(xShape, uno::UNO_QUERY); + constexpr css::drawing::FillStyle eExpectedStyle = css::drawing::FillStyle_HATCH; + css::drawing::FillStyle aActualStyle; + xShapeProps->getPropertyValue(u"FillStyle"_ustr) >>= aActualStyle; + CPPUNIT_ASSERT_EQUAL(eExpectedStyle, aActualStyle); + sal_Int32 nExpectedAngle = 585; // FillHatch.Angle has data type 'long' + css::drawing::Hatch aActualHatch; + xShapeProps->getPropertyValue(u"FillHatch"_ustr) >>= aActualHatch; + CPPUNIT_ASSERT_EQUAL(nExpectedAngle, aActualHatch.Angle); + } +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/sdpropls.cxx b/xmloff/source/draw/sdpropls.cxx index 62235bf73bc8..ce07c078e60a 100644 --- a/xmloff/source/draw/sdpropls.cxx +++ b/xmloff/source/draw/sdpropls.cxx @@ -65,6 +65,9 @@ #include #include #include +#include +#include +#include using ::com::sun::star::uno::Any; @@ -219,7 +222,7 @@ const XMLPropertyMapEntry aXMLSDProperties[] = GMAP( PROP_D3DVerticalSegments, XML_NAMESPACE_DR3D, XML_VERTICAL_SEGMENTS, XML_TYPE_NUMBER, 0 ), GMAP( PROP_D3DPercentDiagonal, XML_NAMESPACE_DR3D, XML_EDGE_ROUNDING, XML_TYPE_PERCENT, 0 ), GMAP( PROP_D3DBackscale, XML_NAMESPACE_DR3D, XML_BACK_SCALE, XML_TYPE_PERCENT, 0 ), - GMAP( PROP_D3DEndAngle, XML_NAMESPACE_DR3D, XML_END_ANGLE, XML_TYPE_NUMBER, 0 ), + GMAP( PROP_D3DEndAngle, XML_NAMESPACE_DR3D, XML_END_ANGLE, XML_SD_TYPE_LATHE_ENDANGLE, 0 ), GMAP( PROP_D3DDepth, XML_NAMESPACE_DR3D, XML_DEPTH, XML_TYPE_MEASURE, 0 ), GMAP( PROP_D3DDoubleSided, XML_NAMESPACE_DR3D, XML_BACKFACE_CULLING, XML_SD_TYPE_BACKFACE_CULLING, 0 ), @@ -990,7 +993,61 @@ public: return true; } }; +} +namespace +{ +class XMLLatheEndAngleHdl : public XMLDoublePropHdl +{ +public: + virtual bool importXML(const OUString& rStrImpValue, css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter) const override; + virtual bool exportXML(OUString& rStrExpValue, const css::uno::Any& rValue, + const SvXMLUnitConverter& rUnitConverter) const override; +}; +} + +bool XMLLatheEndAngleHdl::importXML(const OUString& rStrImpValue, uno::Any& rValue, + const SvXMLUnitConverter& rUC) const +{ + // tdf#161327. We keep reading unit-less values as being in 1/10th of a degree for backward + // compatibility for now. Values with unit are interpreted correctly. + SAL_WARN_IF( + SvtSaveOptions::ODFSaneDefaultVersion::ODFSVER_013_EXTENDED < rUC.getSaneDefaultVersion(), + "xmloff.draw", + "Check whether parameter isWrongOOo10thDegAngle can be false for newer LO version."); + sal_Int16 nAngle; // Angles are limited to 'short' in UNO property D3DEndAngle. + bool const bRet = ::sax::Converter::convert10thDegAngle(nAngle, rStrImpValue, true); + if (bRet) + { + rValue <<= nAngle; + return true; + } + else + return false; +} + +bool XMLLatheEndAngleHdl::exportXML(OUString& rStrExpValue, const uno::Any& rValue, + const SvXMLUnitConverter& rUC) const +{ + sal_Int16 nAngle; // type of D3DEndAngle is 'short'. + bool bRet = rValue >>= nAngle; + if (bRet) + { + // tdf#161327. Adapt version to write unit deg, when most users have a LO version, that can + // read angle units. Write 1/10 of a degree for all versions for backward compatibility till + // then. Adapt test when LO writes a new default ODF version. + if (SvtSaveOptions::ODFSaneDefaultVersion::ODFSVER_013_EXTENDED + >= rUC.getSaneDefaultVersion()) + rStrExpValue = OUString::number(nAngle); // wrong, but backward compatible + else + { + SAL_WARN("xmloff.draw", "Check whether writing unit is indeed possible now."); + double fAngle = static_cast(nAngle) / 10.0; + rStrExpValue = OUString::number(fAngle) + "deg"; + } + } + return bRet; } XMLSdPropHdlFactory::XMLSdPropHdlFactory( uno::Reference< frame::XModel > xModel, SvXMLImport& rImport ) @@ -1136,6 +1193,11 @@ const XMLPropertyHandler* XMLSdPropHdlFactory::GetPropertyHandler( sal_Int32 nTy pHdl = new XMLEnumPropertyHdl( aXML_TexMode_EnumMap ); break; } + case XML_SD_TYPE_LATHE_ENDANGLE: + { + pHdl = new XMLLatheEndAngleHdl; + break; + } case XML_SD_TYPE_NUMBULLET: { uno::Reference xCompareFac( mxModel, uno::UNO_QUERY ); diff --git a/xmloff/source/style/GradientStyle.cxx b/xmloff/source/style/GradientStyle.cxx index 2356075bcaed..3c6e8bec7dff 100644 --- a/xmloff/source/style/GradientStyle.cxx +++ b/xmloff/source/style/GradientStyle.cxx @@ -115,13 +115,24 @@ void XMLGradientStyleImport::importXML( case XML_ELEMENT(DRAW, XML_GRADIENT_ANGLE): { auto const cmp12(m_rImport.GetODFVersion().compareTo(ODFVER_012_TEXT)); - bool const bSuccess = - ::sax::Converter::convertAngle(aGradient.Angle, aIter.toView(), - // tdf#89475 try to detect borked OOo angles - (cmp12 < 0) || (cmp12 == 0 - && (m_rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x) - // also for AOO 4.x, assume there won't ever be a 4.2 - || m_rImport.getGeneratorVersion() == SvXMLImport::AOO_4x))); + // tdf#89475 try to detect borked OOo angles + bool const bIsWrongOOo10thDegAngle( + (cmp12 < 0) + || (cmp12 == 0 + && (m_rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, + SvXMLImport::LO_7x) + // also for AOO 4.x, assume there won't ever be a 4.2 + || m_rImport.getGeneratorVersion() == SvXMLImport::AOO_4x))); + sal_Int16 nAngle; + bool const bSuccess = ::sax::Converter::convert10thDegAngle( + nAngle, aIter.toView(), bIsWrongOOo10thDegAngle); + if (bSuccess) + { // limit to valid range [0..3600[ + nAngle = nAngle % 3600; + if (nAngle < 0) + nAngle += 3600; + aGradient.Angle = nAngle; + } SAL_INFO_IF(!bSuccess, "xmloff.style", "failed to import draw:angle"); } break; @@ -307,7 +318,12 @@ void XMLGradientStyleExport::exportXML( // Angle if( aGradient.GetGradientStyle() != awt::GradientStyle_RADIAL ) { - ::sax::Converter::convertAngle(aOut, static_cast(aGradient.GetAngle()), m_rExport.getSaneDefaultVersion()); + // true: wrong, but backward compatible with OOo/LO < 4.4 + // false: OFFICE-3774 tdf#89475 write valid ODF 1.2 angle; needs LO 4.4 to import + bool bIsWrongOOo10thDegAngle(m_rExport.getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_012 + || m_rExport.getSaneDefaultVersion() == SvtSaveOptions::ODFSVER_012_EXT_COMPAT); + ::sax::Converter::convert10thDegAngle(aOut, static_cast(aGradient.GetAngle()), + bIsWrongOOo10thDegAngle); aStrValue = aOut.makeStringAndClear(); m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue ); } diff --git a/xmloff/source/style/HatchStyle.cxx b/xmloff/source/style/HatchStyle.cxx index bc544c97011d..bf24da77ef40 100644 --- a/xmloff/source/style/HatchStyle.cxx +++ b/xmloff/source/style/HatchStyle.cxx @@ -94,9 +94,19 @@ void XMLHatchStyleImport::importXML( case XML_ELEMENT(DRAW, XML_ROTATION): case XML_ELEMENT(DRAW_OOO, XML_ROTATION): { - sal_Int32 nValue; - if (::sax::Converter::convertNumber(nValue, aIter.toView(), 0, 3600)) - aHatch.Angle = sal_Int16(nValue); + // tdf#161327. We keep reading unit-less values as being in 1/10th of a degree for + // backward compatibility for now. Values with unit are imported correctly. + // For how to make it version dependend see import of XML_GRADIENT_ANGLE, for example. + sal_Int16 nAngle; + bool const bRet + = ::sax::Converter::convert10thDegAngle(nAngle, aIter.toView(), true); + if (bRet) + { // limit to valid range [0..3600[ + nAngle = nAngle % 3600; + if (nAngle < 0) + nAngle += 3600; + aHatch.Angle = nAngle; + } break; } default: @@ -166,7 +176,17 @@ void XMLHatchStyleExport::exportXML( m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_DISTANCE, aStrValue ); // Angle - m_rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_ROTATION, OUString::number(aHatch.Angle) ); + // tdf#161327. Start writing unit deg, when most users have a LO version, that can read angle + // units. Write 1/10 of a degree for all versions for backward compatibility till then. + // Adapt test when LO writes a new default ODF version. + SAL_WARN_IF( + SvtSaveOptions::ODFSaneDefaultVersion::ODFSVER_013_EXTENDED + < m_rExport.getSaneDefaultVersion(), + "xmloff.style", + "Check whether parameter isWrongOOo10thDegAngle can be false for newer LO version."); + ::sax::Converter::convert10thDegAngle(aOut, aHatch.Angle, true); + aStrValue = aOut.makeStringAndClear(); + m_rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_ROTATION, aStrValue); // Do Write SvXMLElementExport rElem( m_rExport, XML_NAMESPACE_DRAW, XML_HATCH, diff --git a/xmloff/source/style/PageMasterPropHdlFactory.cxx b/xmloff/source/style/PageMasterPropHdlFactory.cxx index 1617584839ab..378160ec68d0 100644 --- a/xmloff/source/style/PageMasterPropHdlFactory.cxx +++ b/xmloff/source/style/PageMasterPropHdlFactory.cxx @@ -22,7 +22,7 @@ #include #include #include -#include "xmlbahdl.hxx" +#include #include #include #include diff --git a/xmloff/source/style/TransGradientStyle.cxx b/xmloff/source/style/TransGradientStyle.cxx index 385c92194404..0cb88cb238eb 100644 --- a/xmloff/source/style/TransGradientStyle.cxx +++ b/xmloff/source/style/TransGradientStyle.cxx @@ -128,13 +128,24 @@ void XMLTransGradientStyleImport::importXML( case XML_ELEMENT(DRAW, XML_GRADIENT_ANGLE): { auto const cmp12(rImport.GetODFVersion().compareTo(ODFVER_012_TEXT)); - bool const bSuccess = - ::sax::Converter::convertAngle(aGradient.Angle, aIter.toView(), - // tdf#89475 try to detect borked OOo angles - (cmp12 < 0) || (cmp12 == 0 - && (rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, SvXMLImport::LO_7x) - // also for AOO 4.x, assume there won't ever be a 4.2 - || rImport.getGeneratorVersion() == SvXMLImport::AOO_4x))); + // tdf#89475 try to detect borked OOo angles + bool const bIsWrongOOo10thDegAngle( + (cmp12 < 0) + || (cmp12 == 0 + && (rImport.isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, + SvXMLImport::LO_7x) + // also for AOO 4.x, assume there won't ever be a 4.2 + || rImport.getGeneratorVersion() == SvXMLImport::AOO_4x))); + sal_Int16 nAngle; + bool const bSuccess = ::sax::Converter::convert10thDegAngle( + nAngle, aIter.toView(), bIsWrongOOo10thDegAngle); + if (bSuccess) + { // limit to valid range [0..3600[ + nAngle = nAngle % 3600; + if (nAngle < 0) + nAngle += 3600; + aGradient.Angle = nAngle; + } SAL_INFO_IF(!bSuccess, "xmloff.style", "failed to import draw:angle"); } break; @@ -240,10 +251,15 @@ void XMLTransGradientStyleExport::exportXML( // Angle if (awt::GradientStyle_RADIAL != aGradient.GetGradientStyle()) { - ::sax::Converter::convertAngle(aOut, aGradient.GetAngle().get(), - rExport.getSaneDefaultVersion()); + // true: wrong, but backward compatible with OOo/LO < 4.4 + // false: OFFICE-3774 tdf#89475 write valid ODF 1.2 angle; needs LO 4.4 to import + bool bIsWrongOOo10thDegAngle(rExport.getSaneDefaultVersion() < SvtSaveOptions::ODFSVER_012 + || rExport.getSaneDefaultVersion() + == SvtSaveOptions::ODFSVER_012_EXT_COMPAT); + ::sax::Converter::convert10thDegAngle(aOut, aGradient.GetAngle().get(), + bIsWrongOOo10thDegAngle); aStrValue = aOut.makeStringAndClear(); - rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue ); + rExport.AddAttribute(XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue); } // Border diff --git a/xmloff/source/style/prhdlfac.cxx b/xmloff/source/style/prhdlfac.cxx index a3ab3290bef2..a14d61ea31c2 100644 --- a/xmloff/source/style/prhdlfac.cxx +++ b/xmloff/source/style/prhdlfac.cxx @@ -30,7 +30,7 @@ #include #include #include -#include "xmlbahdl.hxx" +#include #include #include #include "cdouthdl.hxx" diff --git a/xmloff/source/style/xmlbahdl.cxx b/xmloff/source/style/xmlbahdl.cxx index 36bc1037cbaa..a0aea8ccb1a4 100644 --- a/xmloff/source/style/xmlbahdl.cxx +++ b/xmloff/source/style/xmlbahdl.cxx @@ -17,7 +17,7 @@ * the License at http://www.apache.org/licenses/LICENSE-2.0 . */ -#include "xmlbahdl.hxx" +#include #include #include