summaryrefslogtreecommitdiff
path: root/sw
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2022-02-15 17:07:45 +0100
committerLuboš Luňák <l.lunak@collabora.com>2022-07-07 17:04:49 +0200
commitbafe6d1c933a6256a348e9a9d9c5b68cfd46887b (patch)
treec969e909ab3cbb45a35a27b75f2e78a780e029fd /sw
parent533b2385022843274a619a788e2a1594ae9090fd (diff)
sw HTML export: add a new LeadingTabWidth option
This is a simple way to not loose indentation done with tabs (e.g. source code) during the HTML export. A more complex way would be ask the layout for the tab portion width, ask VCL what's the size of an nbsp glyph and then act accordingly, which is is not done here. (cherry picked from commit 505f5db522f8406715f455d8007d014073a99097) Change-Id: I2a5c0512e9e5541e55e10f29952679bf05d63f1b (cherry picked from commit 5fa9481a203edf21bd7fe2373fdc51312bb357a4)
Diffstat (limited to 'sw')
-rw-r--r--sw/qa/extras/htmlexport/htmlexport.cxx38
-rw-r--r--sw/source/filter/html/htmlatr.cxx30
-rw-r--r--sw/source/filter/html/wrthtml.cxx8
-rw-r--r--sw/source/filter/html/wrthtml.hxx3
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("&#160;");
+ }
+ 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 = "" );