Kaydet (Commit) 76a4665a authored tarafından Michael Stahl's avatar Michael Stahl Kaydeden (comit) Eike Rathke

xmloff: fix ODF import of gradient draw:angle attribute a bit

ODF 1.2 part 3, 18.3.1 angle, says "An angle, as defined in §4.1 of
[SVG]" and "If no unit identifier is specified, the value is assumed to
be in degrees."

Unfortunately OOo could only read and write 10th of degree here.

See also https://issues.oasis-open.org/browse/OFFICE-3774

As the first step towards fixing that, implement the import for
draw:angle values with an angle unit identifier, but leave the import
as-is if the angle identifier is missing.

Change-Id: Ib88d417c03998ebcfc569b01492f0e1f851bbc85
(cherry picked from commit aadda5d1)
Reviewed-on: https://gerrit.libreoffice.org/19283Tested-by: 's avatarJenkins <ci@libreoffice.org>
Reviewed-by: 's avatarEike Rathke <erack@redhat.com>
üst a54f0d6c
...@@ -139,6 +139,12 @@ public: ...@@ -139,6 +139,12 @@ public:
/** convert string to double number (using ::rtl::math) without unit conversion */ /** convert string to double number (using ::rtl::math) without unit conversion */
static bool convertDouble(double& rValue, const OUString& rString); static bool convertDouble(double& rValue, const OUString& rString);
/** convert number, 10th of degrees with range [0..3600] to SVG angle */
static void convertAngle(OUStringBuffer& rBuffer, sal_Int16 nAngle);
/** convert SVG angle to number, 10th of degrees with range [0..3600] */
static bool convertAngle(sal_Int16& rAngle, OUString const& rString);
/** convert double to ISO "duration" string; negative durations allowed */ /** convert double to ISO "duration" string; negative durations allowed */
static void convertDuration(OUStringBuffer& rBuffer, static void convertDuration(OUStringBuffer& rBuffer,
const double fTime); const double fTime);
......
...@@ -640,6 +640,62 @@ bool Converter::convertDouble(double& rValue, const OUString& rString) ...@@ -640,6 +640,62 @@ bool Converter::convertDouble(double& rValue, const OUString& rString)
return ( eStatus == rtl_math_ConversionStatus_Ok ); return ( eStatus == rtl_math_ConversionStatus_Ok );
} }
/** convert number, 10th of degrees with range [0..3600] to SVG angle */
void Converter::convertAngle(OUStringBuffer& rBuffer, sal_Int16 const nAngle)
{
#if 1
// wrong, but backward compatible with OOo/LO < 4.4
::sax::Converter::convertNumber(rBuffer, nAngle);
#else
// maybe in the future... (see other convertAngle)
double fAngle(double(nAngle) / 10.0);
::sax::Converter::convertDouble(rBuffer, fAngle);
rBuffer.append("deg");
#endif
}
/** convert SVG angle to number, 10th of degrees with range [0..3600] */
bool Converter::convertAngle(sal_Int16& rAngle, OUString const& rString)
{
// 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 :(
// So import degrees when we see the "deg" suffix but continue with 10th of
// 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 (-1 != rString.indexOf("deg"))
{
nValue = fValue * 10.0;
}
else if (-1 != rString.indexOf("grad"))
{
nValue = (fValue * 9.0 / 10.0) * 10.0;
}
else if (-1 != rString.indexOf("rad"))
{
nValue = (fValue * 180.0 / M_PI) * 10.0;
}
else // no explicit unit
{
nValue = fValue; // wrong, but backward compatible with OOo/LO < 4.4
}
// limit to valid range [0..3600]
nValue = nValue % 3600;
if (nValue < 0)
{
nValue += 3600;
}
assert(0 <= nValue && nValue <= 3600);
if (bRet)
{
rAngle = sal::static_int_cast<sal_Int16>(nValue);
}
return bRet;
}
/** convert double to ISO "duration" string; negative durations allowed */ /** convert double to ISO "duration" string; negative durations allowed */
void Converter::convertDuration(OUStringBuffer& rBuffer, void Converter::convertDuration(OUStringBuffer& rBuffer,
const double fTime) const double fTime)
......
...@@ -76,8 +76,10 @@ $(eval $(call gb_CppunitTest_use_components,sd_import_tests,\ ...@@ -76,8 +76,10 @@ $(eval $(call gb_CppunitTest_use_components,sd_import_tests,\
desktop/source/deployment/deployment \ desktop/source/deployment/deployment \
embeddedobj/util/embobj \ embeddedobj/util/embobj \
filter/source/config/cache/filterconfig1 \ filter/source/config/cache/filterconfig1 \
filter/source/odfflatxml/odfflatxml \
filter/source/svg/svgfilter \ filter/source/svg/svgfilter \
filter/source/xmlfilteradaptor/xmlfa \ filter/source/xmlfilteradaptor/xmlfa \
filter/source/xmlfilterdetect/xmlfd \
forms/util/frm \ forms/util/frm \
framework/util/fwk \ framework/util/fwk \
i18npool/util/i18npool \ i18npool/util/i18npool \
......
This diff is collapsed.
...@@ -73,6 +73,7 @@ public: ...@@ -73,6 +73,7 @@ public:
void testN759180(); void testN759180();
void testN778859(); void testN778859();
void testMasterPageStyleParent(); void testMasterPageStyleParent();
void testGradientAngle();
void testFdo64512(); void testFdo64512();
void testFdo71075(); void testFdo71075();
void testN828390_2(); void testN828390_2();
...@@ -114,6 +115,7 @@ public: ...@@ -114,6 +115,7 @@ public:
CPPUNIT_TEST(testN759180); CPPUNIT_TEST(testN759180);
CPPUNIT_TEST(testN778859); CPPUNIT_TEST(testN778859);
CPPUNIT_TEST(testMasterPageStyleParent); CPPUNIT_TEST(testMasterPageStyleParent);
CPPUNIT_TEST(testGradientAngle);
CPPUNIT_TEST(testFdo64512); CPPUNIT_TEST(testFdo64512);
CPPUNIT_TEST(testFdo71075); CPPUNIT_TEST(testFdo71075);
CPPUNIT_TEST(testN828390_2); CPPUNIT_TEST(testN828390_2);
...@@ -440,6 +442,62 @@ void SdImportTest::testMasterPageStyleParent() ...@@ -440,6 +442,62 @@ void SdImportTest::testMasterPageStyleParent()
xDocShRef->DoClose(); xDocShRef->DoClose();
} }
void SdImportTest::testGradientAngle()
{
sd::DrawDocShellRef xDocShRef = loadURL(getURLFromSrc("/sd/qa/unit/data/odg/gradient-angle.fodg"), FODG);
uno::Reference<lang::XMultiServiceFactory> const xDoc(
xDocShRef->GetDoc()->getUnoModel(), uno::UNO_QUERY);
awt::Gradient gradient;
uno::Reference<container::XNameAccess> const xGradients(
xDoc->createInstance("com.sun.star.drawing.GradientTable"),
uno::UNO_QUERY);
CPPUNIT_ASSERT(xGradients->getByName("Gradient 38") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(0), gradient.Angle); // was: 3600
CPPUNIT_ASSERT(xGradients->getByName("Gradient 10") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(270), gradient.Angle); // 27deg
CPPUNIT_ASSERT(xGradients->getByName("Gradient 11") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(1145), gradient.Angle); // 2rad
CPPUNIT_ASSERT(xGradients->getByName("Gradient 12") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(900), gradient.Angle); // 100grad
CPPUNIT_ASSERT(xGradients->getByName("Gradient 13") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(3599), gradient.Angle); // -1
CPPUNIT_ASSERT(xGradients->getByName("Gradient 14") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(3028), gradient.Angle); // -1rad
CPPUNIT_ASSERT(xGradients->getByName("Gradient 15") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(300), gradient.Angle); // 3900
CPPUNIT_ASSERT(xGradients->getByName("Gradient 16") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(105), gradient.Angle); // 10.5deg
CPPUNIT_ASSERT(xGradients->getByName("Gradient 17") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(1800), gradient.Angle); // \pi rad
uno::Reference<container::XNameAccess> const xTranspGradients(
xDoc->createInstance("com.sun.star.drawing.TransparencyGradientTable"),
uno::UNO_QUERY);
CPPUNIT_ASSERT(xTranspGradients->getByName("Transparency 2") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(10), gradient.Angle); // 1
CPPUNIT_ASSERT(xTranspGradients->getByName("Transparency 1") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(900), gradient.Angle); // 90deg
CPPUNIT_ASSERT(xTranspGradients->getByName("Transparency 3") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(572), gradient.Angle); // 1.0rad
CPPUNIT_ASSERT(xTranspGradients->getByName("Transparency 4") >>= gradient);
CPPUNIT_ASSERT_EQUAL(sal_Int16(1800), gradient.Angle); // 1000grad
}
void SdImportTest::testN778859() void SdImportTest::testN778859()
{ {
::sd::DrawDocShellRef xDocShRef = loadURL(getURLFromSrc("/sd/qa/unit/data/pptx/n778859.pptx"), PPTX); ::sd::DrawDocShellRef xDocShRef = loadURL(getURLFromSrc("/sd/qa/unit/data/pptx/n778859.pptx"), PPTX);
......
...@@ -48,6 +48,7 @@ struct FileFormat ...@@ -48,6 +48,7 @@ struct FileFormat
#define PPTX_FORMAT_TYPE ( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::ALIEN | SfxFilterFlags::STARONEFILTER | SfxFilterFlags::PREFERED ) #define PPTX_FORMAT_TYPE ( SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT | SfxFilterFlags::ALIEN | SfxFilterFlags::STARONEFILTER | SfxFilterFlags::PREFERED )
#define HTML_FORMAT_TYPE ( SfxFilterFlags::EXPORT | SfxFilterFlags::ALIEN ) #define HTML_FORMAT_TYPE ( SfxFilterFlags::EXPORT | SfxFilterFlags::ALIEN )
#define PDF_FORMAT_TYPE ( SfxFilterFlags::STARONEFILTER | SfxFilterFlags::ALIEN | SfxFilterFlags::IMPORT | SfxFilterFlags::PREFERED ) #define PDF_FORMAT_TYPE ( SfxFilterFlags::STARONEFILTER | SfxFilterFlags::ALIEN | SfxFilterFlags::IMPORT | SfxFilterFlags::PREFERED )
#define FODG_FORMAT_TYPE (SfxFilterFlags::STARONEFILTER | SfxFilterFlags::OWN | SfxFilterFlags::IMPORT | SfxFilterFlags::EXPORT)
/** List of file formats we support in Impress unit tests. /** List of file formats we support in Impress unit tests.
...@@ -64,6 +65,7 @@ FileFormat aFileFormats[] = ...@@ -64,6 +65,7 @@ FileFormat aFileFormats[] =
{ "pptx", "Impress Office Open XML", "Office Open XML Presentation", "", PPTX_FORMAT_TYPE }, { "pptx", "Impress Office Open XML", "Office Open XML Presentation", "", PPTX_FORMAT_TYPE },
{ "html", "graphic_HTML", "graphic_HTML", "", HTML_FORMAT_TYPE }, { "html", "graphic_HTML", "graphic_HTML", "", HTML_FORMAT_TYPE },
{ "pdf", "draw_pdf_import", "pdf_Portable_Document_Format", "", PDF_FORMAT_TYPE }, { "pdf", "draw_pdf_import", "pdf_Portable_Document_Format", "", PDF_FORMAT_TYPE },
{ "fodg", "OpenDocument Drawing Flat XML", "Flat XML ODF Drawing", "", FODG_FORMAT_TYPE },
{ 0, 0, 0, 0, SfxFilterFlags::NONE } { 0, 0, 0, 0, SfxFilterFlags::NONE }
}; };
...@@ -72,6 +74,7 @@ FileFormat aFileFormats[] = ...@@ -72,6 +74,7 @@ FileFormat aFileFormats[] =
#define PPTX 2 #define PPTX 2
#define HTML 3 #define HTML 3
#define PDF 4 #define PDF 4
#define FODG 5
/// Base class for filter tests loading or roundtriping a document, and asserting the document model. /// Base class for filter tests loading or roundtriping a document, and asserting the document model.
class SdModelTestBase : public test::BootstrapFixture, public unotest::MacrosTest class SdModelTestBase : public test::BootstrapFixture, public unotest::MacrosTest
......
...@@ -178,9 +178,9 @@ bool XMLGradientStyleImport::importXML( ...@@ -178,9 +178,9 @@ bool XMLGradientStyleImport::importXML(
break; break;
case XML_TOK_GRADIENT_ANGLE: case XML_TOK_GRADIENT_ANGLE:
{ {
sal_Int32 nValue; bool const bSuccess =
::sax::Converter::convertNumber( nValue, rStrValue, 0, 3600 ); ::sax::Converter::convertAngle(aGradient.Angle, rStrValue);
aGradient.Angle = sal_Int16( nValue ); SAL_INFO_IF(!bSuccess, "xmloff.style", "failed to import draw:angle");
} }
break; break;
case XML_TOK_GRADIENT_BORDER: case XML_TOK_GRADIENT_BORDER:
...@@ -288,7 +288,7 @@ bool XMLGradientStyleExport::exportXML( ...@@ -288,7 +288,7 @@ bool XMLGradientStyleExport::exportXML(
// Angle // Angle
if( aGradient.Style != awt::GradientStyle_RADIAL ) if( aGradient.Style != awt::GradientStyle_RADIAL )
{ {
::sax::Converter::convertNumber(aOut, sal_Int32(aGradient.Angle)); ::sax::Converter::convertAngle(aOut, aGradient.Angle);
aStrValue = aOut.makeStringAndClear(); aStrValue = aOut.makeStringAndClear();
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue ); rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue );
} }
......
...@@ -178,9 +178,9 @@ bool XMLTransGradientStyleImport::importXML( ...@@ -178,9 +178,9 @@ bool XMLTransGradientStyleImport::importXML(
break; break;
case XML_TOK_GRADIENT_ANGLE: case XML_TOK_GRADIENT_ANGLE:
{ {
sal_Int32 nValue; bool const bSuccess =
::sax::Converter::convertNumber( nValue, rStrValue, 0, 3600 ); ::sax::Converter::convertAngle(aGradient.Angle, rStrValue);
aGradient.Angle = sal_Int16( nValue ); SAL_INFO_IF(!bSuccess, "xmloff.style", "failed to import draw:angle");
} }
break; break;
case XML_TOK_GRADIENT_BORDER: case XML_TOK_GRADIENT_BORDER:
...@@ -285,8 +285,7 @@ bool XMLTransGradientStyleExport::exportXML( ...@@ -285,8 +285,7 @@ bool XMLTransGradientStyleExport::exportXML(
// Angle // Angle
if( aGradient.Style != awt::GradientStyle_RADIAL ) if( aGradient.Style != awt::GradientStyle_RADIAL )
{ {
::sax::Converter::convertNumber( ::sax::Converter::convertAngle(aOut, aGradient.Angle);
aOut, sal_Int32(aGradient.Angle));
aStrValue = aOut.makeStringAndClear(); aStrValue = aOut.makeStringAndClear();
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue ); rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_GRADIENT_ANGLE, aStrValue );
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment