sw/qa/filter/ww8/ww8.cxx | 31 +++++++++++++++++++++++++++ sw/source/filter/ww8/docxattributeoutput.cxx | 4 +++ sw/source/filter/ww8/docxattributeoutput.hxx | 1 3 files changed, 36 insertions(+)
New commits: commit a825e23a2980fcb3d970834c4ce1f8403fb93054 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Sep 27 14:05:10 2022 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Sep 27 15:43:59 2022 +0200 DOCX export: fix not-well-formed XML when hyperlink end is a textbox anchor We failed to save a document which contained anchored text and the anchor position was inside a hyperlink. The problem was that the hyperlink covered content which has anchored text, so when the text inside the shape ended its paragraph, it wanted to finish the hyperlink that was started outside the shape, which is not well-formed XML. This was a problem since 7246e57216bb20c15af0ecf6a0183f5ffa81e780 (tdf#143591 DOCX import: handle anchored objects as at-char, 2021-09-20), previously we lost the character position of such anchor positions, so in practice this problem was not visible. Fix this similarly how we stash away the current state when entering a table cell: just save / restore the number of hyperlinks we have to close, that'll close the hyperlink outside the shape. Note that the source document has the hyperlink outside the shape's anchor, while we include the shape inside the hyperlink, but that doesn't cause problems in practice. Change-Id: I711fad2336fd78e2ba709c3fc0a4f75de32aae8b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140650 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/qa/filter/ww8/ww8.cxx b/sw/qa/filter/ww8/ww8.cxx index ea8c4d9a9553..8d0b1e7e6dee 100644 --- a/sw/qa/filter/ww8/ww8.cxx +++ b/sw/qa/filter/ww8/ww8.cxx @@ -107,6 +107,37 @@ CPPUNIT_TEST_FIXTURE(Test, testDocxComboBoxContentControlExport) // i.e. the combo box content control was turned into a drop-down one on export. assertXPath(pXmlDoc, "//w:sdt/w:sdtPr/w:comboBox", 1); } + +CPPUNIT_TEST_FIXTURE(Test, testDocxHyperlinkShape) +{ + // Given a document with a hyperlink at char positions 0 -> 6 and a shape with text anchored at + // char position 6: + mxComponent = loadFromDesktop("private:factory/swriter"); + uno::Reference<lang::XMultiServiceFactory> xMSF(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XTextDocument> xTextDocument(mxComponent, uno::UNO_QUERY); + uno::Reference<text::XText> xText = xTextDocument->getText(); + uno::Reference<text::XTextCursor> xCursor = xText->createTextCursor(); + xText->insertString(xCursor, "beforeafter", /*bAbsorb=*/false); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->goRight(/*nCount=*/6, /*bExpand=*/true); + uno::Reference<beans::XPropertySet> xCursorProps(xCursor, uno::UNO_QUERY); + xCursorProps->setPropertyValue("HyperLinkURL", uno::Any(OUString("http://www.example.com/"))); + xCursor->gotoStart(/*bExpand=*/false); + xCursor->goRight(/*nCount=*/6, /*bExpand=*/false); + uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY); + uno::Reference<drawing::XShape> xShape( + xFactory->createInstance("com.sun.star.drawing.RectangleShape"), uno::UNO_QUERY); + xShape->setSize(awt::Size(5000, 5000)); + uno::Reference<beans::XPropertySet> xShapeProps(xShape, uno::UNO_QUERY); + xShapeProps->setPropertyValue("AnchorType", uno::Any(text::TextContentAnchorType_AT_CHARACTER)); + uno::Reference<text::XTextContent> xShapeContent(xShape, uno::UNO_QUERY); + xText->insertTextContent(xCursor, xShapeContent, /*bAbsorb=*/false); + xShapeProps->setPropertyValue("TextBox", uno::Any(true)); + + // When saving this document to DOCX, then make sure we don't crash on export (due to an + // assertion failure for not-well-formed XML output): + save("Office Open XML Text", maTempFile); +} } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx index b4b19cff7088..501d347dc932 100644 --- a/sw/source/filter/ww8/docxattributeoutput.cxx +++ b/sw/source/filter/ww8/docxattributeoutput.cxx @@ -6855,6 +6855,9 @@ void DocxAttributeOutput::pushToTableExportContext(DocxTableExportContext& rCont m_aParagraphSdt.m_bStartedSdt = false; rContext.m_bStartedRunSdt = m_aRunSdt.m_bStartedSdt; m_aRunSdt.m_bStartedSdt = false; + + rContext.m_nHyperLinkCount = m_nHyperLinkCount; + m_nHyperLinkCount = 0; } void DocxAttributeOutput::popFromTableExportContext(DocxTableExportContext const & rContext) @@ -6864,6 +6867,7 @@ void DocxAttributeOutput::popFromTableExportContext(DocxTableExportContext const m_tableReference->m_nTableDepth = rContext.m_nTableDepth; m_aParagraphSdt.m_bStartedSdt = rContext.m_bStartedParaSdt; m_aRunSdt.m_bStartedSdt = rContext.m_bStartedRunSdt; + m_nHyperLinkCount = rContext.m_nHyperLinkCount; } void DocxAttributeOutput::WriteTextBox(uno::Reference<drawing::XShape> xShape) diff --git a/sw/source/filter/ww8/docxattributeoutput.hxx b/sw/source/filter/ww8/docxattributeoutput.hxx index 9de8f6fed332..55794770ac4b 100644 --- a/sw/source/filter/ww8/docxattributeoutput.hxx +++ b/sw/source/filter/ww8/docxattributeoutput.hxx @@ -1095,6 +1095,7 @@ struct DocxTableExportContext bool m_bStartedParaSdt; bool m_bStartedRunSdt; sal_uInt32 m_nTableDepth; + sal_Int32 m_nHyperLinkCount = 0; DocxTableExportContext(DocxAttributeOutput& rOutput) : m_rOutput(rOutput) { m_rOutput.pushToTableExportContext(*this); } ~DocxTableExportContext() { m_rOutput.popFromTableExportContext(*this); } };