diff --git a/include/sax/tools/converter.hxx b/include/sax/tools/converter.hxx index bb97acc595ac..e6568faffbd6 100644 --- a/include/sax/tools/converter.hxx +++ b/include/sax/tools/converter.hxx @@ -210,6 +210,14 @@ public: static bool convert10thDegAngle(sal_Int16& rAngle, std::string_view rString, bool isWrongOOo10thDegAngle); + /** convert SVG angle to number, in 1/nFactor of degrees, range [0..nFactor*360[ */ + static bool convertAngle(double& rAngle, std::u16string_view rString, + const sal_uInt16& nFactor = 1); + + /** convert SVG angle to number, in 1/nFactor of degrees, range [0..nFactor*360[ */ + static bool convertAngle(double& rAngle, std::string_view rString, + const sal_uInt16& nFactor = 1); + /** convert double to XMLSchema-2 "duration" string; negative durations allowed */ static void convertDuration(OUStringBuffer& rBuffer, const double fTime); diff --git a/sax/Library_sax.mk b/sax/Library_sax.mk index f65fcf05b669..7188041f1bf4 100644 --- a/sax/Library_sax.mk +++ b/sax/Library_sax.mk @@ -26,6 +26,7 @@ $(eval $(call gb_Library_use_externals,sax,\ )) $(eval $(call gb_Library_use_libraries,sax,\ + basegfx \ comphelper \ cppu \ cppuhelper \ diff --git a/sax/source/tools/converter.cxx b/sax/source/tools/converter.cxx index bc2342d5b508..204033a7e64a 100644 --- a/sax/source/tools/converter.cxx +++ b/sax/source/tools/converter.cxx @@ -802,6 +802,56 @@ bool Converter::convert10thDegAngle(sal_Int16& rAngle, std::string_view rString, return bRet; } +/** convert SVG angle to number, in 1/nFactor of degrees, range [0..nFactor*360[ */ +bool Converter::convertAngle(double& rAngle, std::u16string_view rString, const sal_uInt16& nFactor) +{ + // ODF uses in several places angles in data type 'angle' (18.3.1, ODF 1.3). That is a double + // followed by unit identifier deg, grad or rad or a unitless value in degrees. LO uses angles + // in degrees, 1/10 of degrees and 1/100 of degrees in various data types. + // This method converts ODF 'angle' to double considering nFactor and normalizes it to range + // [0..nFactor*360[. Further type converting and range restriction are done by the caller. + bool bRet = ::sax::Converter::convertDouble(rAngle, rString); + if (bRet) + { + //degrees + if (std::u16string_view::npos != rString.find(u"grad")) + rAngle *= 0.9; // 360deg = 400grad + else if (std::u16string_view::npos != rString.find(u"rad")) + rAngle = basegfx::rad2deg(rAngle); + // 1/nFactor of degrees in range [0..nFactor*360] + if (nFactor > 0) + rAngle = basegfx::snapToZeroRange(rAngle * nFactor, nFactor * 360.0); + else + return false; + } + return bRet; +} + +/** convert SVG angle to number, in 1/nFactor of degrees, range [0..nFactor*360[ */ +bool Converter::convertAngle(double& rAngle, std::string_view rString, const sal_uInt16& nFactor) +{ + // ODF uses in several places angles in data type 'angle' (18.3.1, ODF 1.3). That is a double + // followed by unit identifier deg, grad or rad or a unitless value in degrees. LO uses angles + // in degrees, 1/10 of degrees and 1/100 of degrees in various data types. + // This method converts ODF 'angle' to double considering nFactor and normalizes it to range + // [0..nFactor*360[. Further type converting and range restriction are done by the caller. + bool bRet = ::sax::Converter::convertDouble(rAngle, rString); + if (bRet) + { + // degrees + if (std::u16string_view::npos != rString.find("grad")) + rAngle *= 0.9; // 360deg = 400grad + else if (std::u16string_view::npos != rString.find("rad")) + rAngle = basegfx::rad2deg(rAngle); + // 1/nFactor of degrees in range [0..nFactor*360] + if (nFactor > 0) + rAngle = basegfx::snapToZeroRange(rAngle * nFactor, nFactor * 360.0); + else + return false; + } + return bRet; +} + /** convert double to ISO "duration" string; negative durations allowed */ void Converter::convertDuration(OUStringBuffer& rBuffer, const double fTime) diff --git a/xmloff/qa/unit/data/tdf161483_CircleStartEndAngle.fodg b/xmloff/qa/unit/data/tdf161483_CircleStartEndAngle.fodg new file mode 100644 index 000000000000..66b815322be4 --- /dev/null +++ b/xmloff/qa/unit/data/tdf161483_CircleStartEndAngle.fodg @@ -0,0 +1,397 @@ + + + + + LOmyBuild/25.2.0.0.alpha0$Windows_X86_64 LibreOffice_project/5a7283a0eb880c5273ea48b0d1a6f881c4297b1a + + 24x16 + Regina Henschel + 2024-06-23T16:09:12 + Regina Henschel + 2024-06-23T16:11:32 + + + + + -1494 + -349 + 24728 + 19000 + + + view1 + true + false + false + false + true + false + true + true + true + 1500 + false + Hw== + Hw== + + false + true + true + 0 + 0 + true + true + true + 4 + 0 + -244 + -2551 + 29363 + 16609 + 500 + 500 + 100 + 100 + 500 + 5 + 500 + 5 + false + 1500 + true + false + false + false + false + + + + + 1251 + 0 + 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/data/tdf161483_ShadowSlant.fodg b/xmloff/qa/unit/data/tdf161483_ShadowSlant.fodg new file mode 100644 index 000000000000..c012e03fc6b3 --- /dev/null +++ b/xmloff/qa/unit/data/tdf161483_ShadowSlant.fodg @@ -0,0 +1,419 @@ + + + + + LibreOffice_7.6.7/7.6.7.2$Windows_X86_64 LibreOffice_project/dd47e4b30cb7dab30588d6c79c651f218165e3c5 + 32x24 + Regina Henschel + 2024-06-21T21:28:57 + Regina Henschel + 2024-06-22T18:18:28.827000000 + + PT9M8S3 + + + -3960 + -2799 + 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 + -3960 + -2799 + 37760 + 24821 + 500 + 500 + 100 + 100 + 500 + 5 + 500 + 5 + false + 1500 + true + false + false + false + false + + + + + 1250 + 0 + EPSON6FC99C (WP-4025 Series) + 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 + $(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 bfa279ca120f..f81df002c4ae 100644 --- a/xmloff/qa/unit/draw.cxx +++ b/xmloff/qa/unit/draw.cxx @@ -879,6 +879,58 @@ CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTdf161327_HatchAngle) } } +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTdf161483_ShadowSlant) +{ + // Load document with four 3D-scenes, that differ in the draw:shadow-slant value + loadFromFile(u"tdf161483_ShadowSlant.fodg"); + + // The shadow-slant angle is given in file as + // [0] 36 unitless + // [1] 36deg, + // [2] 40grad, + // [3] 1.628318530717959rad + // The resulting angle should be 36 in all cases. + // Cases [1], [2] and [3] had angle 0 without fix. + + constexpr sal_Int16 nExpectedAngle = 36; // D3DSceneShadowSlant has data type 'short' + for (size_t i = 0; i < 4; ++i) + { + uno::Reference xShape(getShape(i)); + uno::Reference xShapeProps(xShape, uno::UNO_QUERY); + sal_Int16 nActualAngle; + xShapeProps->getPropertyValue(u"D3DSceneShadowSlant"_ustr) >>= nActualAngle; + CPPUNIT_ASSERT_EQUAL(nExpectedAngle, nActualAngle); + } +} + +CPPUNIT_TEST_FIXTURE(XmloffDrawTest, testTdf161483_CircleStartEndAngle) +{ + // Load document with four 'Arc' shapes, which differ in the type of start and end angles + loadFromFile(u"tdf161483_CircleStartEndAngle.fodg"); + + // The start and end angles are given in file as + // [0] unitless: start 337.5 end 306 + // [1] deg: start 337.5deg end 306deg + // [2] grad: start 375grad end 340grad + // [3] rad: start 5.89048622548086rad end 5.34070751110265rad + // The resulting angle should be 33750 and 30600 in all cases. + + // CircleStartAngle and CircleEndAngle have data type 'long', meaning Degree100 + constexpr sal_Int32 nExpectedStartAngle = 33750; + constexpr sal_Int32 nExpectedEndAngle = 30600; + for (size_t i = 0; i < 4; ++i) + { + uno::Reference xShape(getShape(i)); + uno::Reference xShapeProps(xShape, uno::UNO_QUERY); + sal_Int32 nActualStartAngle; + xShapeProps->getPropertyValue(u"CircleStartAngle"_ustr) >>= nActualStartAngle; + CPPUNIT_ASSERT_EQUAL(nExpectedStartAngle, nActualStartAngle); + sal_Int32 nActualEndAngle; + xShapeProps->getPropertyValue(u"CircleEndAngle"_ustr) >>= nActualEndAngle; + CPPUNIT_ASSERT_EQUAL(nExpectedEndAngle, nActualEndAngle); + } +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/xmloff/source/draw/ximp3dscene.cxx b/xmloff/source/draw/ximp3dscene.cxx index a137cc247f4e..8c1648be4490 100644 --- a/xmloff/source/draw/ximp3dscene.cxx +++ b/xmloff/source/draw/ximp3dscene.cxx @@ -284,7 +284,11 @@ void SdXML3DSceneAttributesHelper::processSceneAttribute( const sax_fastparser:: } case XML_SHADOW_SLANT: { - ::sax::Converter::convertNumber(mnShadowSlant, aIter.toView()); + double fAngle = 0.0; + if (::sax::Converter::convertAngle(fAngle, aIter.toView())) + mnShadowSlant = static_cast(basegfx::fround(fAngle)); + else + mnShadowSlant = 0; return; } case XML_SHADE_MODE: diff --git a/xmloff/source/draw/ximpshap.cxx b/xmloff/source/draw/ximpshap.cxx index 27e98821f19b..89bb474f928e 100644 --- a/xmloff/source/draw/ximpshap.cxx +++ b/xmloff/source/draw/ximpshap.cxx @@ -1157,15 +1157,15 @@ bool SdXMLEllipseShapeContext::processAttribute( const sax_fastparser::FastAttri case XML_ELEMENT(DRAW, XML_START_ANGLE): { double dStartAngle; - if (::sax::Converter::convertDouble( dStartAngle, aIter.toView() )) - mnStartAngle = static_cast(dStartAngle * 100.0); + if (::sax::Converter::convertAngle( dStartAngle, aIter.toView(), 100)) + mnStartAngle = static_cast(basegfx::fround(dStartAngle)); break; } case XML_ELEMENT(DRAW, XML_END_ANGLE): { double dEndAngle; - if (::sax::Converter::convertDouble( dEndAngle, aIter.toView() )) - mnEndAngle = static_cast(dEndAngle * 100.0); + if (::sax::Converter::convertAngle( dEndAngle, aIter.toView(), 100)) + mnEndAngle = static_cast(basegfx::fround(dEndAngle)); break; } default: