summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-02-11 16:18:26 +0100
committerAndras Timar <andras.timar@collabora.com>2022-02-14 15:26:07 +0100
commita1ffa65e0fa7464db651a4d063e589f4a343f828 (patch)
tree872faeac54e4c18b6de72f88caf3bb1f38df0665 /sw
parent0bedd49cde41646585f4f2fa068a23c94a15a2df (diff)
sw XHTML / ReqIF filter: avoid adding and removing <br>s for trailing <br>s
The sw/ HTML export writes two <br>s for a <br> in the doc model at the end of a paragraph, because the last <br> would be ignored by browsers. But then the import ignores all <br>s at the end of paragraphs, so the import and the export are not a 1:1 mapping; but at least the layout of the exported HTML is close to the Writer layout. ReqIF focuses on the preserving the semantics of the doc model instead: it already doesn't open the document in "web view", and it's not expected that the number of <br>s change on import or export. Fix the problem by disabling both the import and the export tweaks in the ReqIF case. It would perhaps make sense to do this in general, but for users who only care about the export layout (and never import the result again), that would be probably a regression, so don't change this unconditionally for now. Change-Id: Iabd4a462185493c1ece0352069077e04c293816b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129820 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins (cherry picked from commit b86679ea6bd2bb053c3822c4642a62a49e381909) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129834 Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Diffstat (limited to 'sw')
-rw-r--r--sw/qa/extras/htmlexport/htmlexport.cxx79
-rw-r--r--sw/source/filter/html/htmlatr.cxx18
-rw-r--r--sw/source/filter/html/htmltab.cxx6
3 files changed, 74 insertions, 29 deletions
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index 641a1e1560c8..fa40c8d7d04c 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -279,6 +279,8 @@ public:
void ParseOle1FromRtfUrl(const OUString& rRtfUrl, SvMemoryStream& rOle1);
/// Export using the C++ HTML export filter, with xhtmlns=reqif-xhtml.
void ExportToReqif();
+ /// Import using the C++ HTML import filter, with xhtmlns=reqif-xhtml.
+ void ImportFromReqif(const OUString& rUrl);
};
OUString SwHtmlDomExportTest::GetOlePath()
@@ -333,6 +335,15 @@ void SwHtmlDomExportTest::ExportToReqif()
xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
}
+void SwHtmlDomExportTest::ImportFromReqif(const OUString& rUrl)
+{
+ uno::Sequence<beans::PropertyValue> aLoadProperties = {
+ comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
+ comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
+ };
+ mxComponent = loadFromDesktop(rUrl, "com.sun.star.text.TextDocument", aLoadProperties);
+}
+
constexpr OUStringLiteral DATA_DIRECTORY = u"/sw/qa/extras/htmlexport/data/";
DECLARE_HTMLEXPORT_ROUNDTRIP_TEST(testFdo81276, "fdo81276.html")
@@ -757,11 +768,7 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIfPngImg)
};
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "reqif-png-img.xhtml";
- uno::Sequence<beans::PropertyValue> aLoadProperties = {
- comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
- comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
- };
- mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument", aLoadProperties);
+ ImportFromReqif(aURL);
verify(/*bExported=*/false);
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
uno::Sequence<beans::PropertyValue> aStoreProperties = {
@@ -771,8 +778,7 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIfPngImg)
};
xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties);
mxComponent->dispose();
- mxComponent
- = loadFromDesktop(maTempFile.GetURL(), "com.sun.star.text.TextDocument", aLoadProperties);
+ ImportFromReqif(maTempFile.GetURL());
verify(/*bExported=*/true);
}
@@ -1088,12 +1094,8 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testRTFOLEMimeType)
{
// Import a document with an embedded object.
OUString aType("test/rtf");
- uno::Sequence<beans::PropertyValue> aLoadProperties = {
- comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
- comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
- };
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "reqif-ole-data.xhtml";
- mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument", aLoadProperties);
+ ImportFromReqif(aURL);
// Export it.
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
@@ -1234,12 +1236,7 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1PDF)
// Now import this back and check the ODT result.
mxComponent->dispose();
mxComponent.clear();
- uno::Sequence<beans::PropertyValue> aLoadProperties = {
- comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
- comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
- };
- mxComponent
- = loadFromDesktop(maTempFile.GetURL(), "com.sun.star.text.TextDocument", aLoadProperties);
+ ImportFromReqif(maTempFile.GetURL());
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
utl::TempFile aTempFile;
aTempFile.EnableKillingFile();
@@ -1267,11 +1264,7 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqifOle1Paint)
{
// Load the bug document, which has OLE1 data in it, which is not a wrapper around OLE2 data.
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "paint-ole.xhtml";
- uno::Sequence<beans::PropertyValue> aLoadProperties = {
- comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")),
- comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")),
- };
- mxComponent = loadFromDesktop(aURL, "com.sun.star.text.TextDocument", aLoadProperties);
+ ImportFromReqif(aURL);
// Save it as ODT to inspect the result of the OLE1 -> OLE2 conversion.
uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY);
@@ -2044,6 +2037,46 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testNestedBullets)
"second");
}
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTrailingLineBreak)
+{
+ // Given a document with a trailing line-break:
+ SwDoc* pDoc = createSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ pWrtShell->Insert("test\n");
+
+ // When exporting to reqif-xhtml:
+ ExportToReqif();
+
+ // Then make sure that we still have a single line-break:
+ SvMemoryStream aStream;
+ HtmlExportTest::wrapFragment(maTempFile, aStream);
+ xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream);
+ CPPUNIT_ASSERT(pDoc);
+ // Without the accompanying fix in place, this test would have failed with:
+ // - Expected: 1
+ // - Actual : 2
+ // - XPath '//reqif-xhtml:br' number of nodes is incorrect
+ assertXPath(pXmlDoc, "//reqif-xhtml:br", 1);
+
+ // Then test the import side:
+
+ // Given an empty document:
+ mxComponent->dispose();
+
+ // When importing a <br> from reqif-xhtml:
+ ImportFromReqif(maTempFile.GetURL());
+
+ // Then make sure that line-break is not lost:
+ SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get());
+ CPPUNIT_ASSERT(pTextDoc);
+ pDoc = pTextDoc->GetDocShell()->GetDoc();
+ pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ OUString aActual = pWrtShell->GetCursor()->GetNode().GetTextNode()->GetText();
+ // Without the accompanying fix in place, this test would have failed, as the trailing
+ // line-break was lost.
+ CPPUNIT_ASSERT_EQUAL(OUString("test\n"), aActual);
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/htmlatr.cxx b/sw/source/filter/html/htmlatr.cxx
index 457e8483ec37..a78c5e272d56 100644
--- a/sw/source/filter/html/htmlatr.cxx
+++ b/sw/source/filter/html/htmlatr.cxx
@@ -2348,8 +2348,11 @@ Writer& OutHTML_SwTextNode( Writer& rWrt, const SwContentNode& rNode )
}
bool bWriteBreak = (HtmlTokenId::PREFORMTXT_ON != rHTMLWrt.m_nLastParaToken);
- if( bWriteBreak && pNd->GetNumRule() )
+ if (bWriteBreak && (pNd->GetNumRule() || rHTMLWrt.mbReqIF))
+ {
+ // One line-break is exactly one <br> in the ReqIF case.
bWriteBreak = false;
+ }
{
HTMLOutContext aContext( rHTMLWrt.m_eDestEnc );
@@ -2490,11 +2493,14 @@ Writer& OutHTML_SwTextNode( Writer& rWrt, const SwContentNode& rNode )
else
HTMLOutFuncs::Out_Char( rWrt.Strm(), c, aContext, &rHTMLWrt.m_aNonConvertableCharacters );
- // if a paragraph's last character is a hard line break
- // then we need to add an extra <br>
- // because browsers like Mozilla wouldn't add a line for the next paragraph
- bWriteBreak = (0x0a == c) &&
- (HtmlTokenId::PREFORMTXT_ON != rHTMLWrt.m_nLastParaToken);
+ if (!rHTMLWrt.mbReqIF)
+ {
+ // if a paragraph's last character is a hard line break
+ // then we need to add an extra <br>
+ // because browsers like Mozilla wouldn't add a line for the next paragraph
+ bWriteBreak = (0x0a == c) &&
+ (HtmlTokenId::PREFORMTXT_ON != rHTMLWrt.m_nLastParaToken);
+ }
}
}
}
diff --git a/sw/source/filter/html/htmltab.cxx b/sw/source/filter/html/htmltab.cxx
index 1276d2a69654..1167e6b55c49 100644
--- a/sw/source/filter/html/htmltab.cxx
+++ b/sw/source/filter/html/htmltab.cxx
@@ -2663,6 +2663,12 @@ sal_Int32 SwHTMLParser::StripTrailingLF()
{
sal_Int32 nStripped = 0;
+ if (IsReqIF())
+ {
+ // One <br> is exactly one line-break in the ReqIF case.
+ return nStripped;
+ }
+
const sal_Int32 nLen = m_pPam->GetPoint()->nContent.GetIndex();
if( nLen )
{