sw/qa/filter/ww8/ww8.cxx                     |   33 +++++++++++++++++++++++++++
 sw/source/filter/ww8/docxattributeoutput.cxx |    4 +++
 sw/source/filter/ww8/docxattributeoutput.hxx |    1 
 3 files changed, 38 insertions(+)

New commits:
commit b9f80c6d2779e3e4ea4096653fe5f01e33d05ea8
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Sep 27 14:05:10 2022 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Oct 3 12:40:16 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
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/140662

diff --git a/sw/qa/filter/ww8/ww8.cxx b/sw/qa/filter/ww8/ww8.cxx
index 7ccb1299769e..ab9e456be695 100644
--- a/sw/qa/filter/ww8/ww8.cxx
+++ b/sw/qa/filter/ww8/ww8.cxx
@@ -9,6 +9,8 @@
 
 #include <swmodeltestbase.hxx>
 
+#include <com/sun/star/text/XTextDocument.hpp>
+
 namespace
 {
 constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/filter/ww8/data/";
@@ -48,6 +50,37 @@ CPPUNIT_TEST_FIXTURE(Test, testNegativePageBorderDocImport)
     auto nTopBorderDistance = 
xStyle->getPropertyValue("TopBorderDistance").get<sal_Int32>();
     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-646), nTopBorderDistance);
 }
+
+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 94d1f19294d0..8020576cfcab 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -6808,6 +6808,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)
@@ -6817,6 +6820,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 09dcc375a3b9..09c6f8079e9d 100644
--- a/sw/source/filter/ww8/docxattributeoutput.hxx
+++ b/sw/source/filter/ww8/docxattributeoutput.hxx
@@ -1104,6 +1104,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); }
 };

Reply via email to