summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2021-03-01 20:57:38 +0100
committerXisco Fauli <xiscofauli@libreoffice.org>2021-03-03 12:16:24 +0100
commita4bdd833a252ed4d942e4478fc820f9f2ee725fe (patch)
treebabfa9bb0b27a22f2a0aedba0bf09160039fbc72
parent4ddde32ea6807eaa686ad25aa18ea24a8b834df8 (diff)
tdf#140552 RTF export: fix hyperlink, in footnote, in hyperlink
Regression from commit 7d42346ba77c9c4df241ea40eaf550993ca18783 (tdf#90421 RTF export: ignore hyperlinks without an URL, 2015-04-21), URLs can be nested in the footnote case, which requires a stack. Otherwise the inner URL clears "the" URL and we don't close the outer field as we believe it's empty, so it was not started. Change-Id: I9f87ddbb7e597c413bf836eb9b58beb76722361f Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111794 Tested-by: Jenkins Reviewed-by: Miklos Vajna <vmiklos@collabora.com> (cherry picked from commit 5a74baa4f033f84c4bbcec869a68eef149f77161) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111778 Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org> Signed-off-by: Xisco Fauli <xiscofauli@libreoffice.org> Reviewed-on: https://gerrit.libreoffice.org/c/core/+/111823 Reviewed-by: Michael Stahl <michael.stahl@allotropia.de>
-rw-r--r--sw/qa/extras/rtfexport/rtfexport3.cxx47
-rw-r--r--sw/source/filter/ww8/rtfattributeoutput.cxx12
-rw-r--r--sw/source/filter/ww8/rtfattributeoutput.hxx2
3 files changed, 57 insertions, 4 deletions
diff --git a/sw/qa/extras/rtfexport/rtfexport3.cxx b/sw/qa/extras/rtfexport/rtfexport3.cxx
index 7bb20cbb410e..45f84f5c5089 100644
--- a/sw/qa/extras/rtfexport/rtfexport3.cxx
+++ b/sw/qa/extras/rtfexport/rtfexport3.cxx
@@ -13,6 +13,7 @@
#include <com/sun/star/text/XFootnotesSupplier.hpp>
#include <com/sun/star/text/TextContentAnchorType.hpp>
#include <com/sun/star/awt/FontWeight.hpp>
+#include <com/sun/star/text/XTextDocument.hpp>
class Test : public SwModelTestBase
{
@@ -236,6 +237,52 @@ DECLARE_RTFEXPORT_TEST(testTdf112520, "tdf112520.docx")
getProperty<text::TextContentAnchorType>(getShape(3), "AnchorType"));
}
+CPPUNIT_TEST_FIXTURE(Test, testNestedHyperlink)
+{
+ // Given a hyperlink contains a footnote which contains a hyperlink:
+ {
+ createSwDoc();
+ uno::Reference<lang::XMultiServiceFactory> xFactory(mxComponent, uno::UNO_QUERY);
+ uno::Reference<text::XTextContent> xFootnote(
+ xFactory->createInstance("com.sun.star.text.Footnote"), 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, "a", /*bAbsorb=*/false);
+ xText->insertTextContent(xCursor, xFootnote, /*bAbsorb=*/false);
+ xText->insertString(xCursor, "b", /*bAbsorb=*/false);
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->gotoEnd(/*bExpand=*/true);
+ uno::Reference<beans::XPropertySet> xCursorProps(xCursor, uno::UNO_QUERY);
+ xCursorProps->setPropertyValue("HyperLinkURL", uno::makeAny(OUString("http://body.com/")));
+ uno::Reference<text::XText> xFootnoteText(xFootnote, uno::UNO_QUERY);
+ xCursor = xFootnoteText->createTextCursor();
+ xFootnoteText->insertString(xCursor, "x", /*bAbsorb=*/false);
+ xCursor->gotoStart(/*bExpand=*/false);
+ xCursor->gotoEnd(/*bExpand=*/true);
+ xCursorProps.set(xCursor, uno::UNO_QUERY);
+ xCursorProps->setPropertyValue("HyperLinkURL",
+ uno::makeAny(OUString("http://footnote.com/")));
+ }
+
+ // When exporting to RTF:
+ // Without the accompanying fix in place, this test would have failed with:
+ // assertion failed
+ // - Expression: xComponent.is()
+ // i.e. the RTF output was not well-formed, loading failed.
+ reload(mpFilter, "nested-hyperlink.rtf");
+
+ // Then make sure both hyperlinks are have the correct URLs.
+ uno::Reference<text::XTextRange> xParagraph = getParagraph(1);
+ uno::Reference<text::XTextRange> xPortion = getRun(xParagraph, 1);
+ CPPUNIT_ASSERT_EQUAL(OUString("http://body.com/"),
+ getProperty<OUString>(xPortion, "HyperLinkURL"));
+ auto xFootnote = getProperty<uno::Reference<text::XText>>(getRun(xParagraph, 2), "Footnote");
+ uno::Reference<text::XTextRange> xFootnotePortion = getRun(getParagraphOfText(1, xFootnote), 1);
+ CPPUNIT_ASSERT_EQUAL(OUString("http://footnote.com/"),
+ getProperty<OUString>(xFootnotePortion, "HyperLinkURL"));
+}
+
DECLARE_RTFEXPORT_TEST(testTdf121623, "tdf121623.rtf")
{
// This was 2, multicolumn section was ignored at the table.
diff --git a/sw/source/filter/ww8/rtfattributeoutput.cxx b/sw/source/filter/ww8/rtfattributeoutput.cxx
index 10d38a569e92..fe7f24e474be 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.cxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.cxx
@@ -530,7 +530,7 @@ void RtfAttributeOutput::EndRuby(const SwTextNode& rNode, sal_Int32 nPos)
bool RtfAttributeOutput::StartURL(const OUString& rUrl, const OUString& rTarget)
{
- m_sURL = rUrl;
+ m_aURLs.push(rUrl);
// Ignore hyperlink without a URL.
if (!rUrl.isEmpty())
{
@@ -560,7 +560,13 @@ bool RtfAttributeOutput::StartURL(const OUString& rUrl, const OUString& rTarget)
bool RtfAttributeOutput::EndURL(bool const isAtEndOfParagraph)
{
- if (!m_sURL.isEmpty())
+ if (m_aURLs.empty())
+ {
+ return true;
+ }
+
+ const OUString& rURL = m_aURLs.top();
+ if (!rURL.isEmpty())
{
// UGLY: usually EndRun is called earlier, but there is an extra
// call to OutAttrWithRange() when at the end of the paragraph,
@@ -580,8 +586,8 @@ bool RtfAttributeOutput::EndURL(bool const isAtEndOfParagraph)
// close the field group
m_aRun->append('}');
}
- m_sURL.clear();
}
+ m_aURLs.pop();
return true;
}
diff --git a/sw/source/filter/ww8/rtfattributeoutput.hxx b/sw/source/filter/ww8/rtfattributeoutput.hxx
index 2493ce38fbb0..2a739a330f1e 100644
--- a/sw/source/filter/ww8/rtfattributeoutput.hxx
+++ b/sw/source/filter/ww8/rtfattributeoutput.hxx
@@ -617,7 +617,7 @@ private:
std::optional<css::drawing::FillStyle> m_oFillStyle;
/// If we're in the process of exporting a hyperlink, then its URL.
- OUString m_sURL;
+ std::stack<OUString> m_aURLs;
/// If original file had \sbauto.
bool m_bParaBeforeAutoSpacing;