From a1ffa65e0fa7464db651a4d063e589f4a343f828 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Fri, 11 Feb 2022 16:18:26 +0100 Subject: sw XHTML / ReqIF filter: avoid adding and removing
s for trailing
s The sw/ HTML export writes two
s for a
in the doc model at the end of a paragraph, because the last
would be ignored by browsers. But then the import ignores all
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
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 Tested-by: Jenkins (cherry picked from commit b86679ea6bd2bb053c3822c4642a62a49e381909) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/129834 Reviewed-by: Xisco Fauli --- sw/qa/extras/htmlexport/htmlexport.cxx | 79 ++++++++++++++++++++++++---------- sw/source/filter/html/htmlatr.cxx | 18 +++++--- sw/source/filter/html/htmltab.cxx | 6 +++ 3 files changed, 74 insertions(+), 29 deletions(-) (limited to 'sw') 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 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 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 xStorable(mxComponent, uno::UNO_QUERY); uno::Sequence 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 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 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 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 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 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 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
from reqif-xhtml: + ImportFromReqif(maTempFile.GetURL()); + + // Then make sure that line-break is not lost: + SwXTextDocument* pTextDoc = dynamic_cast(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
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
- // 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
+ // 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
is exactly one line-break in the ReqIF case. + return nStripped; + } + const sal_Int32 nLen = m_pPam->GetPoint()->nContent.GetIndex(); if( nLen ) { -- cgit