diff options
-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); |