diff options
-rw-r--r-- | sw/qa/extras/htmlexport/htmlexport.cxx | 38 | ||||
-rw-r--r-- | sw/source/filter/html/htmlatr.cxx | 30 | ||||
-rw-r--r-- | sw/source/filter/html/wrthtml.cxx | 8 | ||||
-rw-r--r-- | sw/source/filter/html/wrthtml.hxx | 3 |
4 files changed, 78 insertions, 1 deletions
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index cb2d697d7664..25583638aa44 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -1669,6 +1669,44 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTableBackground) assertXPathNoAttribute(pXmlDoc, "//reqif-xhtml:table[2]/reqif-xhtml:tr[2]", "style"); } +CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testLeadingTab) +{ + // Given a document with leading tabs: + loadURL("private:factory/swriter", nullptr); + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + SwDoc* pDoc = pTextDoc->GetDocShell()->GetDoc(); + SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell(); + pWrtShell->Insert("\t first"); + pWrtShell->SplitNode(); + pWrtShell->Insert("\t\t second"); + pWrtShell->SplitNode(); + pWrtShell->Insert("thi \t rd"); + + // When exporting to HTML, using LeadingTabWidth=2: + uno::Reference<frame::XStorable> xStorable(mxComponent, uno::UNO_QUERY); + uno::Sequence<beans::PropertyValue> aStoreProperties = { + comphelper::makePropertyValue("FilterName", OUString("HTML (StarWriter)")), + comphelper::makePropertyValue("FilterOptions", OUString("xhtmlns=reqif-xhtml")), + comphelper::makePropertyValue("LeadingTabWidth", static_cast<sal_Int32>(2)), + }; + xStorable->storeToURL(maTempFile.GetURL(), aStoreProperties); + + // Then make sure that leading tabs are replaced with 2 nbsps: + 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: <nbsp><nbsp><space>first + // - Actual : <tab><space>first + // i.e. the leading tab was not replaced by 2 nbsps. + assertXPathContent(pXmlDoc, "//reqif-xhtml:p[1]", u"\xa0\xa0 first"); + // Test a leading tab that is not at the start of the paragraph: + assertXPathContent(pXmlDoc, "//reqif-xhtml:p[2]", u"\xa0\xa0\xa0\xa0 second"); + // Test a tab which is not leading: + assertXPathContent(pXmlDoc, "//reqif-xhtml:p[3]", u"thi \t rd"); +} + 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 46abffd664a9..31a28db4f9b3 100644 --- a/sw/source/filter/html/htmlatr.cxx +++ b/sw/source/filter/html/htmlatr.cxx @@ -2358,6 +2358,8 @@ Writer& OutHTML_SwTextNode( Writer& rWrt, const SwContentNode& rNode ) { HTMLOutContext aContext( rHTMLWrt.m_eDestEnc ); + // Tabs are leading till there is a non-tab since the start of the paragraph. + bool bLeadingTab = true; for( ; nStrPos < nEnd; nStrPos++ ) { // output the frames that are anchored to the current position @@ -2491,7 +2493,33 @@ Writer& OutHTML_SwTextNode( Writer& rWrt, const SwContentNode& rNode ) rHTMLWrt.OutPointFieldmarks(aMarkPos); } else - HTMLOutFuncs::Out_Char( rWrt.Strm(), c, aContext, &rHTMLWrt.m_aNonConvertableCharacters ); + { + bool bConsumed = false; + if (c == '\t') + { + if (bLeadingTab && rHTMLWrt.m_nLeadingTabWidth.has_value()) + { + // Consume a tab if it's leading and we know the number of NBSPs to + // be used as a replacement. + for (sal_Int32 i = 0; i < *rHTMLWrt.m_nLeadingTabWidth; ++i) + { + rWrt.Strm().WriteCharPtr(" "); + } + bConsumed = true; + } + } + else + { + // Not a tab -> later tabs are no longer leading. + bLeadingTab = false; + } + + if (!bConsumed) + { + 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> diff --git a/sw/source/filter/html/wrthtml.cxx b/sw/source/filter/html/wrthtml.cxx index e5ac25005de0..62e43946a49c 100644 --- a/sw/source/filter/html/wrthtml.cxx +++ b/sw/source/filter/html/wrthtml.cxx @@ -306,6 +306,14 @@ void SwHTMLWriter::SetupFilterFromPropertyValues( // XHTML namespace implies XHTML. mbXHTML = true; } + + it = aStoreMap.find("LeadingTabWidth"); + if (it != aStoreMap.end()) + { + sal_Int32 nVal{}; + it->second >>= nVal; + m_nLeadingTabWidth.emplace(nVal); + } } ErrCode SwHTMLWriter::WriteStream() diff --git a/sw/source/filter/html/wrthtml.hxx b/sw/source/filter/html/wrthtml.hxx index 0774efc41da1..592a403c57de 100644 --- a/sw/source/filter/html/wrthtml.hxx +++ b/sw/source/filter/html/wrthtml.hxx @@ -423,6 +423,9 @@ public: OUString m_aRTFOLEMimeType; + /// If set, replace leading tabs with this many non-breaking spaces. + std::optional<sal_Int32> m_nLeadingTabWidth; + /// Construct an instance of SwHTMLWriter and optionally give it /// the filter options directly, which can also be set via SetupFilterOptions(). explicit SwHTMLWriter( const OUString& rBaseURL, const OUString& rFilterOptions = "" ); |