diff options
author | Regina Henschel <rb.henschel@t-online.de> | 2022-09-18 14:41:32 +0200 |
---|---|---|
committer | Regina Henschel <rb.henschel@t-online.de> | 2022-09-19 10:38:30 +0200 |
commit | 439eaa8efdd8179f93f7aaf44d25ceced6ab1665 (patch) | |
tree | a972d244c55cdebffed0bf4b7975628a7964c900 | |
parent | 95684fb99ebed5b53bda99957c43466541597b2f (diff) |
tdf#151008 adapt anchor for eaVert and mongolianVert
MS Office and LibreOffice act different whether anchor positions are
rotated for vertical writing modes eaVert and mongolianVert. The patch
converts the position on import and export.
Currently shapes are not able to render mongolianVert. Nevertheless it
is included so that the text block has already the correct position
and the original position is restored on export.
LibreOffice has vertical anchor alignments BOTTOM, that would require
a third horizontal position in MS Office, which does not exist. It is
mapped to anchorCtr='1' instead. Such does not occur in pptx-LO-pptx
round-trip.
Change-Id: I1b0e42a39ce3aba12cdb271b2aa8023dacb9c53d
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140118
Tested-by: Jenkins
Reviewed-by: Regina Henschel <rb.henschel@t-online.de>
-rw-r--r-- | oox/qa/unit/data/tdf151008_eaVertAnchor.pptx | bin | 0 -> 19773 bytes | |||
-rw-r--r-- | oox/qa/unit/export.cxx | 30 | ||||
-rw-r--r-- | oox/qa/unit/shape.cxx | 58 | ||||
-rw-r--r-- | oox/source/drawingml/textbodypropertiescontext.cxx | 46 | ||||
-rw-r--r-- | oox/source/export/drawingml.cxx | 78 |
5 files changed, 165 insertions, 47 deletions
diff --git a/oox/qa/unit/data/tdf151008_eaVertAnchor.pptx b/oox/qa/unit/data/tdf151008_eaVertAnchor.pptx Binary files differnew file mode 100644 index 000000000000..999cd220408c --- /dev/null +++ b/oox/qa/unit/data/tdf151008_eaVertAnchor.pptx diff --git a/oox/qa/unit/export.cxx b/oox/qa/unit/export.cxx index 09cf5cb5ef48..64e1cfaa47e7 100644 --- a/oox/qa/unit/export.cxx +++ b/oox/qa/unit/export.cxx @@ -808,6 +808,36 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf149538upright) assertXPath(pXmlDoc, "//p:spTree/p:sp/p:txBody/a:bodyPr", "upright", "1"); assertXPathNoAttribute(pXmlDoc, "//p:spTree/p:sp/p:txBody/a:bodyPr", "rot"); } + +CPPUNIT_TEST_FIXTURE(Test, testTdf151008VertAnchor) +{ + OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "tdf151008_eaVertAnchor.pptx"; + loadAndSave(aURL, "Impress Office Open XML"); + std::unique_ptr<SvStream> pStream = parseExportStream(getTempFile(), "ppt/slides/slide1.xml"); + xmlDocUniquePtr pXmlDoc = parseXmlStream(pStream.get()); + // The order of the shapes in the file is by name "Right", "Center", "Left", "RightMiddle", + // "CenterMiddle" and "LeftMiddle". I access the shapes here by index, because the XPath is + // easier then. + // As of Sep 2022 LibreOffice does not write the default anchorCtr="0" + // Right + assertXPath(pXmlDoc, "//p:spTree/p:sp[1]/p:txBody/a:bodyPr", "anchor", "t"); + assertXPathNoAttribute(pXmlDoc, "//p:spTree/p:sp[1]/p:txBody/a:bodyPr", "anchorCtr"); + // Center + assertXPath(pXmlDoc, "//p:spTree/p:sp[2]/p:txBody/a:bodyPr", "anchor", "ctr"); + assertXPathNoAttribute(pXmlDoc, "//p:spTree/p:sp[2]/p:txBody/a:bodyPr", "anchorCtr"); + // Left + assertXPath(pXmlDoc, "//p:spTree/p:sp[3]/p:txBody/a:bodyPr", "anchor", "b"); + assertXPathNoAttribute(pXmlDoc, "//p:spTree/p:sp[3]/p:txBody/a:bodyPr", "anchorCtr"); + // RightMiddle + assertXPath(pXmlDoc, "//p:spTree/p:sp[4]/p:txBody/a:bodyPr", "anchor", "t"); + assertXPath(pXmlDoc, "//p:spTree/p:sp[4]/p:txBody/a:bodyPr", "anchorCtr", "1"); + // CenterMiddle + assertXPath(pXmlDoc, "//p:spTree/p:sp[5]/p:txBody/a:bodyPr", "anchor", "ctr"); + assertXPath(pXmlDoc, "//p:spTree/p:sp[5]/p:txBody/a:bodyPr", "anchorCtr", "1"); + // LeftMiddle + assertXPath(pXmlDoc, "//p:spTree/p:sp[6]/p:txBody/a:bodyPr", "anchor", "b"); + assertXPath(pXmlDoc, "//p:spTree/p:sp[6]/p:txBody/a:bodyPr", "anchorCtr", "1"); +} } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/oox/qa/unit/shape.cxx b/oox/qa/unit/shape.cxx index 345ebb215ad6..c741ff84d4da 100644 --- a/oox/qa/unit/shape.cxx +++ b/oox/qa/unit/shape.cxx @@ -15,6 +15,7 @@ #include <unotest/macros_test.hxx> #include <com/sun/star/awt/Size.hpp> +#include <com/sun/star/drawing/TextHorizontalAdjust.hpp> #include <com/sun/star/drawing/TextVerticalAdjust.hpp> #include <com/sun/star/drawing/XDrawPagesSupplier.hpp> #include <com/sun/star/frame/Desktop.hpp> @@ -55,6 +56,7 @@ public: void tearDown() override; uno::Reference<lang::XComponent>& getComponent() { return mxComponent; } void load(std::u16string_view rURL); + uno::Reference<drawing::XShape> getShapeByName(std::u16string_view aName); }; void OoxShapeTest::setUp() @@ -78,6 +80,26 @@ void OoxShapeTest::load(std::u16string_view rFileName) mxComponent = loadFromDesktop(aURL); } +uno::Reference<drawing::XShape> OoxShapeTest::getShapeByName(std::u16string_view aName) +{ + uno::Reference<drawing::XShape> xRet; + + uno::Reference<drawing::XDrawPagesSupplier> xDrawPagesSupplier(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XDrawPage> xDrawPage(xDrawPagesSupplier->getDrawPages()->getByIndex(0), + uno::UNO_QUERY); + for (sal_Int32 i = 0; i < xDrawPage->getCount(); ++i) + { + uno::Reference<container::XNamed> xShape(xDrawPage->getByIndex(i), uno::UNO_QUERY); + if (xShape->getName() == aName) + { + xRet.set(xShape, uno::UNO_QUERY); + break; + } + } + + return xRet; +} + CPPUNIT_TEST_FIXTURE(OoxShapeTest, testGroupTransform) { load(u"tdf141463_GroupTransform.pptx"); @@ -175,6 +197,42 @@ CPPUNIT_TEST_FIXTURE(OoxShapeTest, testTdf125582_TextOnCircle) CPPUNIT_ASSERT_EQUAL_MESSAGE("TextVerticalAdjust", drawing::TextVerticalAdjust_BOTTOM, eAdjust); } +CPPUNIT_TEST_FIXTURE(OoxShapeTest, testTdf151008VertAnchor) +{ + // The document contains shapes with all six kind of anchor positions in pptx. The text in the + // shapes is larger than the shape and has no word wrap. That way anchor position is visible + // in case you inspect the file manually. + load(u"tdf151008_eaVertAnchor.pptx"); + + struct anchorDesc + { + OUString sShapeName; + drawing::TextHorizontalAdjust eAnchorHori; + drawing::TextVerticalAdjust eAnchorVert; + }; + anchorDesc aExpected[6] = { + { u"Right", drawing::TextHorizontalAdjust_RIGHT, drawing::TextVerticalAdjust_TOP }, + { u"Center", drawing::TextHorizontalAdjust_CENTER, drawing::TextVerticalAdjust_TOP }, + { u"Left", drawing::TextHorizontalAdjust_LEFT, drawing::TextVerticalAdjust_TOP }, + { u"RightMiddle", drawing::TextHorizontalAdjust_RIGHT, drawing::TextVerticalAdjust_CENTER }, + { u"CenterMiddle", drawing::TextHorizontalAdjust_CENTER, + drawing::TextVerticalAdjust_CENTER }, + { u"LeftMiddle", drawing::TextHorizontalAdjust_LEFT, drawing::TextVerticalAdjust_CENTER } + }; + // without the fix horizontal and vertical anchor positions were exchanged + for (size_t i = 0; i < 6; ++i) + { + uno::Reference<beans::XPropertySet> xShape(getShapeByName(aExpected[i].sShapeName), + uno::UNO_QUERY); + drawing::TextHorizontalAdjust eHori; + CPPUNIT_ASSERT(xShape->getPropertyValue("TextHorizontalAdjust") >>= eHori); + drawing::TextVerticalAdjust eVert; + CPPUNIT_ASSERT(xShape->getPropertyValue("TextVerticalAdjust") >>= eVert); + CPPUNIT_ASSERT_EQUAL(aExpected[i].eAnchorHori, eHori); + CPPUNIT_ASSERT_EQUAL(aExpected[i].eAnchorVert, eVert); + } +} + CPPUNIT_PLUGIN_IMPLEMENT(); /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/oox/source/drawingml/textbodypropertiescontext.cxx b/oox/source/drawingml/textbodypropertiescontext.cxx index 9d221a18ffbe..47ef04797c93 100644 --- a/oox/source/drawingml/textbodypropertiescontext.cxx +++ b/oox/source/drawingml/textbodypropertiescontext.cxx @@ -75,10 +75,6 @@ TextBodyPropertiesContext::TextBodyPropertiesContext( ContextHandler2Helper cons mrTextBodyProp.moInsets[i] = GetCoordinate( sValue ); } - mrTextBodyProp.mbAnchorCtr = rAttribs.getBool( XML_anchorCtr, false ); - if( mrTextBodyProp.mbAnchorCtr ) - mrTextBodyProp.maPropertyMap.setProperty( PROP_TextHorizontalAdjust, TextHorizontalAdjust_CENTER ); - // bool bCompatLineSpacing = rAttribs.getBool( XML_compatLnSpc, false ); // bool bForceAA = rAttribs.getBool( XML_forceAA, false ); bool bFromWordArt = rAttribs.getBool(XML_fromWordArt, false); @@ -148,10 +144,46 @@ TextBodyPropertiesContext::TextBodyPropertiesContext( ContextHandler2Helper cons } // ST_TextAnchoringType - if( rAttribs.hasAttribute( XML_anchor ) ) + mrTextBodyProp.mbAnchorCtr = rAttribs.getBool(XML_anchorCtr, false ); + if (rAttribs.hasAttribute(XML_anchor)) + mrTextBodyProp.meVA = GetTextVerticalAdjust( rAttribs.getToken(XML_anchor, XML_t)); + // else meVA is initialized to TextVerticalAdjust_TOP + + sal_Int32 tVert = mrTextBodyProp.moVert.value_or(XML_horz); + if (tVert == XML_eaVert || tVert == XML_mongolianVert) + { + if (mrTextBodyProp.mbAnchorCtr) + mrTextBodyProp.maPropertyMap.setProperty(PROP_TextVerticalAdjust, + TextVerticalAdjust_CENTER); + else + mrTextBodyProp.maPropertyMap.setProperty(PROP_TextVerticalAdjust, + TextVerticalAdjust_TOP); + + if (mrTextBodyProp.meVA == TextVerticalAdjust_CENTER) + mrTextBodyProp.maPropertyMap.setProperty(PROP_TextHorizontalAdjust, + TextHorizontalAdjust_CENTER); + else if (mrTextBodyProp.meVA == TextVerticalAdjust_TOP) + { + mrTextBodyProp.maPropertyMap.setProperty( + PROP_TextHorizontalAdjust, + tVert == XML_eaVert ? TextHorizontalAdjust_RIGHT : TextHorizontalAdjust_LEFT); + } + else // meVA == TextVerticalAdjust_BOTTOM + { + mrTextBodyProp.maPropertyMap.setProperty( + PROP_TextHorizontalAdjust, + tVert == XML_eaVert ? TextHorizontalAdjust_LEFT : TextHorizontalAdjust_RIGHT); + } + } + else { - mrTextBodyProp.meVA = GetTextVerticalAdjust( rAttribs.getToken( XML_anchor, XML_t ) ); - mrTextBodyProp.maPropertyMap.setProperty( PROP_TextVerticalAdjust, mrTextBodyProp.meVA); + if (mrTextBodyProp.mbAnchorCtr) + mrTextBodyProp.maPropertyMap.setProperty(PROP_TextHorizontalAdjust, + TextHorizontalAdjust_CENTER); + else // BLOCK is nearer to rendering in MS Office than LEFT, see tdf#137023 + mrTextBodyProp.maPropertyMap.setProperty(PROP_TextHorizontalAdjust, + TextHorizontalAdjust_BLOCK); + mrTextBodyProp.maPropertyMap.setProperty(PROP_TextVerticalAdjust, mrTextBodyProp.meVA); } // Push defaults diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx index 47c8903093b1..85e73eb35c85 100644 --- a/oox/source/export/drawingml.cxx +++ b/oox/source/export/drawingml.cxx @@ -3318,22 +3318,12 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo } } - TextVerticalAdjust eVerticalAlignment( TextVerticalAdjust_TOP ); - const char* sVerticalAlignment = nullptr; - if (GetProperty(rXPropSet, "TextVerticalAdjust")) - mAny >>= eVerticalAlignment; - sVerticalAlignment = GetTextVerticalAdjust(eVerticalAlignment); - std::optional<OString> sWritingMode; - bool bVertical = false; if (GetProperty(rXPropSet, "TextWritingMode")) { WritingMode eMode; if( ( mAny >>= eMode ) && eMode == WritingMode_TB_RL ) - { sWritingMode = "eaVert"; - bVertical = true; - } } if (GetProperty(rXPropSet, "WritingMode")) { @@ -3341,25 +3331,13 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo if (mAny >>= nWritingMode) { if (nWritingMode == text::WritingMode2::TB_RL) - { sWritingMode = "eaVert"; - bVertical = true; - } else if (nWritingMode == text::WritingMode2::BT_LR) - { sWritingMode = "vert270"; - bVertical = true; - } else if (nWritingMode == text::WritingMode2::TB_RL90) - { sWritingMode = "vert"; - bVertical = true; - } else if (nWritingMode == text::WritingMode2::TB_LR) - { sWritingMode = "mongolianVert"; - bVertical = true; - } } } @@ -3423,19 +3401,15 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo { case WritingMode2::TB_RL: sWritingMode = "eaVert"; - bVertical = true; break; case WritingMode2::BT_LR: sWritingMode = "vert270"; - bVertical = true; break; case WritingMode2::TB_RL90: sWritingMode = "vert"; - bVertical = true; break; case WritingMode2::TB_LR: sWritingMode = "mongolianVert"; - bVertical = true; break; default: break; @@ -3529,15 +3503,9 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo if (nTextPreRotateAngle != 0 && !sWritingMode) { if (nTextPreRotateAngle == -90 || nTextPreRotateAngle == 270) - { sWritingMode = "vert"; - bVertical = true; - } else if (nTextPreRotateAngle == -270 || nTextPreRotateAngle == 90) - { sWritingMode = "vert270"; - bVertical = true; - } else if (nTextPreRotateAngle == -180 || nTextPreRotateAngle == 180) { #if defined __GNUC__ && !defined __clang__ && __GNUC__ == 12 @@ -3600,14 +3568,44 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo #pragma GCC diagnostic pop #endif - TextHorizontalAdjust eHorizontalAlignment( TextHorizontalAdjust_CENTER ); - bool bHorizontalCenter = false; + // Prepare attributes 'anchor' and 'anchorCtr' + // LibreOffice has 12 value sets, MS Office only 6. We map them so, that it reverses the + // 6 mappings from import, and we assign the others approximately. + TextVerticalAdjust eVerticalAlignment(TextVerticalAdjust_TOP); + if (GetProperty(rXPropSet, "TextVerticalAdjust")) + mAny >>= eVerticalAlignment; + TextHorizontalAdjust eHorizontalAlignment(TextHorizontalAdjust_CENTER); if (GetProperty(rXPropSet, "TextHorizontalAdjust")) mAny >>= eHorizontalAlignment; - if( eHorizontalAlignment == TextHorizontalAdjust_CENTER ) - bHorizontalCenter = true; - else if( bVertical && eHorizontalAlignment == TextHorizontalAdjust_LEFT ) - sVerticalAlignment = "b"; + + const char* sAnchor = nullptr; + bool bAnchorCtr = false; + if (sWritingMode.has_value() + && (sWritingMode.value() == "eaVert" || sWritingMode.value() == "mongolianVert")) + { + bAnchorCtr = eVerticalAlignment == TextVerticalAdjust_CENTER + || eVerticalAlignment == TextVerticalAdjust_BOTTOM + || eVerticalAlignment == TextVerticalAdjust_BLOCK; + switch (eHorizontalAlignment) + { + case TextHorizontalAdjust_CENTER: + sAnchor = "ctr"; + break; + case TextHorizontalAdjust_LEFT: + sAnchor = sWritingMode.value() == "eaVert" ? "b" : "t"; + break; + case TextHorizontalAdjust_RIGHT: + default: // TextHorizontalAdjust_BLOCK, should not happen + sAnchor = sWritingMode.value() == "eaVert" ? "t" : "b"; + break; + } + } + else + { + bAnchorCtr = eHorizontalAlignment == TextHorizontalAdjust_CENTER + || eHorizontalAlignment == TextHorizontalAdjust_RIGHT; + sAnchor = GetTextVerticalAdjust(eVerticalAlignment); + } bool bHasWrap = false; bool bWrap = false; @@ -3658,8 +3656,8 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo XML_rIns, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nRight)), nRight != constDefaultLeftRightInset), XML_tIns, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nTop)), nTop != constDefaultTopBottomInset), XML_bIns, sax_fastparser::UseIf(OString::number(oox::drawingml::convertHmmToEmu(nBottom)), nBottom != constDefaultTopBottomInset), - XML_anchor, sVerticalAlignment, - XML_anchorCtr, sax_fastparser::UseIf("1", bHorizontalCenter), + XML_anchor, sAnchor, + XML_anchorCtr, sax_fastparser::UseIf("1", bAnchorCtr), XML_vert, sWritingMode, XML_upright, isUpright, XML_rot, sTextRotateAngleMSUnit); |