summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Kaganski <mike.kaganski@collabora.com>2023-10-23 19:52:14 +0300
committerMike Kaganski <mike.kaganski@collabora.com>2023-10-23 22:10:06 +0200
commit926826e40955175a8c115472e0d2f6c7f2f1a453 (patch)
treeba914ce7dcb96fa5f8ddb36a1b40e8d5bc1bb805
parentbae0736bf0ec54828766c3d903e2a27458643395 (diff)
Implement PreserveSpaces boolean HTML/ReqIF export filter option
This option changes how HTML/ReqIF export handles paragraphs with leading/trailing spaces, or multiple sequential spaces. Normally export may insert newlines every ~256 characters, in place of normal space characters; this relies on default processing of spaces, where leading/trailing spaces are trimmed, and runs of spaces are reduced to a single space. When PreserveSpaces is true, HTML/ReqIF export takes care to not alter spaces inside paragraphs. For that, it checks if paragraphs contain sequences of spaces that normally would be reduced; and for those paragraphs, it adds "white-space: pre-wrap" to style (in HTML), or 'xml::space="preserve"' attribute (in ReqIF). Import of 'xml::space' attribute and "white-space: pre-wrap" style is implemented; when paragraph has these, it keeps the spaces read from HTML/ReqIF intact. Import does not currently support this attribute/style in elements other than 'p'. Change-Id: I62dba5eaf313b965bf37d8fa5e3f5bbb8f5e8357 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158362 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kaganski@collabora.com>
-rw-r--r--include/svtools/htmlkywd.hxx1
-rw-r--r--include/svtools/htmltokn.h1
-rw-r--r--include/svtools/parhtml.hxx4
-rw-r--r--svtools/source/svhtml/htmlkywd.cxx1
-rw-r--r--svtools/source/svhtml/parhtml.cxx59
-rw-r--r--sw/qa/extras/htmlexport/htmlexport.cxx61
-rw-r--r--sw/source/filter/html/css1atr.cxx20
-rw-r--r--sw/source/filter/html/css1kywd.hxx2
-rw-r--r--sw/source/filter/html/htmlatr.cxx97
-rw-r--r--sw/source/filter/html/htmlfldw.cxx4
-rw-r--r--sw/source/filter/html/htmlflywriter.cxx28
-rw-r--r--sw/source/filter/html/htmlforw.cxx16
-rw-r--r--sw/source/filter/html/htmlftn.cxx8
-rw-r--r--sw/source/filter/html/htmlnumwriter.cxx4
-rw-r--r--sw/source/filter/html/htmlplug.cxx6
-rw-r--r--sw/source/filter/html/htmltabw.cxx18
-rw-r--r--sw/source/filter/html/svxcss1.cxx27
-rw-r--r--sw/source/filter/html/svxcss1.hxx1
-rw-r--r--sw/source/filter/html/swhtml.cxx9
-rw-r--r--sw/source/filter/html/wrthtml.cxx24
-rw-r--r--sw/source/filter/html/wrthtml.hxx15
21 files changed, 287 insertions, 119 deletions
diff --git a/include/svtools/htmlkywd.hxx b/include/svtools/htmlkywd.hxx
index cdcee168acba..00c8260749bd 100644
--- a/include/svtools/htmlkywd.hxx
+++ b/include/svtools/htmlkywd.hxx
@@ -523,6 +523,7 @@
#define OOO_STRING_SVTOOLS_HTML_O_valign "valign"
#define OOO_STRING_SVTOOLS_HTML_O_valuetype "valuetype"
#define OOO_STRING_SVTOOLS_HTML_O_wrap "wrap"
+#define OOO_STRING_SVTOOLS_XHTML_O_xml_space "xml:space"
// attributes with script code as value
#define OOO_STRING_SVTOOLS_HTML_O_onblur "onblur"
diff --git a/include/svtools/htmltokn.h b/include/svtools/htmltokn.h
index 9dca8a8f3ea7..4a333ee2f6d9 100644
--- a/include/svtools/htmltokn.h
+++ b/include/svtools/htmltokn.h
@@ -429,6 +429,7 @@ ENUM_START = NUMBER_END,
VALIGN,
VALUETYPE,
WRAP,
+ XML_SPACE,
ENUM_END,
// attributes with script code as value
diff --git a/include/svtools/parhtml.hxx b/include/svtools/parhtml.hxx
index b4fee63e311a..5ce3d27cb61d 100644
--- a/include/svtools/parhtml.hxx
+++ b/include/svtools/parhtml.hxx
@@ -162,6 +162,8 @@ private:
bool bReadNextChar : 1; // true: read NextChar again(JavaScript!)
bool bReadComment : 1; // true: read NextChar again (JavaScript!)
+ bool m_bPreserveSpaces : 1 = false;
+
sal_uInt32 nPre_LinePos; // Pos in the line in the PRE-Tag
HtmlTokenId mnPendingOffToken; ///< OFF token pending for a <XX.../> ON/OFF ON token
@@ -187,6 +189,8 @@ protected:
void SetNamespace(std::u16string_view rNamespace);
+ void SetPreserveSpaces(bool val) { m_bPreserveSpaces = val; }
+
public:
HTMLParser( SvStream& rIn, bool bReadNewDoc = true );
diff --git a/svtools/source/svhtml/htmlkywd.cxx b/svtools/source/svhtml/htmlkywd.cxx
index 5f81b3e3ca30..d1b0ea2ee03e 100644
--- a/svtools/source/svhtml/htmlkywd.cxx
+++ b/svtools/source/svhtml/htmlkywd.cxx
@@ -599,6 +599,7 @@ static HTML_OptionEntry aHTMLOptionTab[] = {
{std::u16string_view(u"" OOO_STRING_SVTOOLS_HTML_O_valign), HtmlOptionId::VALIGN},
{std::u16string_view(u"" OOO_STRING_SVTOOLS_HTML_O_valuetype), HtmlOptionId::VALUETYPE},
{std::u16string_view(u"" OOO_STRING_SVTOOLS_HTML_O_wrap), HtmlOptionId::WRAP},
+ {std::u16string_view(u"" OOO_STRING_SVTOOLS_XHTML_O_xml_space), HtmlOptionId::XML_SPACE},
// Attributes with script code value
{std::u16string_view(u"" OOO_STRING_SVTOOLS_HTML_O_onblur), HtmlOptionId::ONBLUR}, // JavaScript
diff --git a/svtools/source/svhtml/parhtml.cxx b/svtools/source/svhtml/parhtml.cxx
index 7e8ac63fc61e..d94a24632779 100644
--- a/svtools/source/svhtml/parhtml.cxx
+++ b/svtools/source/svhtml/parhtml.cxx
@@ -377,9 +377,14 @@ namespace {
constexpr bool HTML_ISPRINTABLE(sal_Unicode c) { return c >= 32 && c != 127; }
+constexpr bool HTML_ISSPACE(sal_uInt32 c)
+{
+ return ' ' == c || '\t' == c || '\r' == c || '\n' == c || '\x0b' == c;
+}
+
}
-HtmlTokenId HTMLParser::ScanText( const sal_Unicode cBreak )
+HtmlTokenId HTMLParser::ScanText(const sal_Unicode cBreak)
{
OUStringBuffer sTmpBuffer( MAX_LEN );
bool bContinue = true;
@@ -705,37 +710,39 @@ HtmlTokenId HTMLParser::ScanText( const sal_Unicode cBreak )
{
break;
}
- nNextCh = ' ';
+ if (!m_bPreserveSpaces)
+ nNextCh = ' ';
[[fallthrough]];
case ' ':
- sTmpBuffer.appendUtf32( nNextCh );
- if( '>'!=cBreak && (!bReadListing && !bReadXMP &&
- !bReadPRE && !bReadTextArea) )
+ if (!m_bPreserveSpaces)
{
- // Reduce sequences of Blanks/Tabs/CR/LF to a single blank
- do {
- nNextCh = GetNextChar();
- if( sal_Unicode(EOF) == nNextCh && rInput.eof() )
+ sTmpBuffer.appendUtf32(nNextCh);
+ if ('>' != cBreak && (!bReadListing && !bReadXMP && !bReadPRE && !bReadTextArea))
+ {
+ // Reduce sequences of Blanks/Tabs/CR/LF to a single blank
+ do
{
- if( !aToken.isEmpty() || sTmpBuffer.getLength() > 1 )
+ nNextCh = GetNextChar();
+ if (sal_Unicode(EOF) == nNextCh && rInput.eof())
{
- // Have seen s.th. aside from blanks?
- aToken.append( sTmpBuffer );
- sTmpBuffer.setLength(0);
- return HtmlTokenId::TEXTTOKEN;
+ if (!aToken.isEmpty() || sTmpBuffer.getLength() > 1)
+ {
+ // Have seen s.th. aside from blanks?
+ aToken.append(sTmpBuffer);
+ sTmpBuffer.setLength(0);
+ return HtmlTokenId::TEXTTOKEN;
+ }
+ else
+ // Only read blanks: no text must be returned
+ // and GetNextToken_ has to read until EOF
+ return HtmlTokenId::NONE;
}
- else
- // Only read blanks: no text must be returned
- // and GetNextToken_ has to read until EOF
- return HtmlTokenId::NONE;
- }
- } while ( ' ' == nNextCh || '\t' == nNextCh ||
- '\r' == nNextCh || '\n' == nNextCh ||
- '\x0b' == nNextCh );
- bNextCh = false;
+ } while (HTML_ISSPACE(nNextCh));
+ bNextCh = false;
+ }
+ break;
}
- break;
-
+ [[fallthrough]];
default:
bEqSignFound = false;
if (nNextCh == cBreak && !cQuote)
@@ -743,7 +750,7 @@ HtmlTokenId HTMLParser::ScanText( const sal_Unicode cBreak )
else
{
do {
- if (!linguistic::IsControlChar(nNextCh))
+ if (!linguistic::IsControlChar(nNextCh) || HTML_ISSPACE(nNextCh))
{
// All remaining characters make their way into the text.
sTmpBuffer.appendUtf32( nNextCh );
diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx
index be3c67fb0bba..a106dd53bf14 100644
--- a/sw/qa/extras/htmlexport/htmlexport.cxx
+++ b/sw/qa/extras/htmlexport/htmlexport.cxx
@@ -2762,6 +2762,67 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testTdf157643_WideHBorder)
assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:table/reqif-xhtml:tr", 2);
}
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testHTML_PreserveSpaces)
+{
+ // Given a document with leading, trailing, and repeating intermediate spaces:
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ constexpr OUString paraText = u"\t test \t more text \t"_ustr;
+ pWrtShell->Insert(paraText);
+
+ // When exporting to plain HTML, using PreserveSpaces:
+ saveWithParams({
+ comphelper::makePropertyValue("FilterName", u"HTML (StarWriter)"_ustr),
+ comphelper::makePropertyValue("PreserveSpaces", true),
+ });
+
+ // Then make sure that "white-space: pre-wrap" is written into the paragraph's style:
+ htmlDocUniquePtr pHtmlDoc = parseHtml(maTempFile);
+ CPPUNIT_ASSERT(pHtmlDoc);
+ const OUString style = getXPath(pHtmlDoc, "/html/body/p", "style"_ostr);
+ CPPUNIT_ASSERT(style.indexOf("white-space: pre-wrap") >= 0);
+ // Also check that the paragraph text is correct, without modifications in whitespace
+ assertXPathContent(pHtmlDoc, "/html/body/p", paraText);
+
+ // Test import
+
+ setImportFilterName("HTML (StarWriter)");
+ load(maTempFile.GetURL());
+ CPPUNIT_ASSERT_EQUAL(paraText, getParagraph(1)->getString());
+}
+
+CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testReqIF_PreserveSpaces)
+{
+ // Given a document with leading, trailing, and repeating intermediate spaces:
+ createSwDoc();
+ SwDoc* pDoc = getSwDoc();
+ SwWrtShell* pWrtShell = pDoc->GetDocShell()->GetWrtShell();
+ constexpr OUString paraText = u"\t test \t more text \t"_ustr;
+ pWrtShell->Insert(paraText);
+
+ // When exporting to ReqIF, using PreserveSpaces:
+ saveWithParams({
+ comphelper::makePropertyValue("FilterName", u"HTML (StarWriter)"_ustr),
+ comphelper::makePropertyValue("FilterOptions", u"xhtmlns=reqif-xhtml"_ustr),
+ comphelper::makePropertyValue("PreserveSpaces", true),
+ });
+
+ // Then make sure that xml:space="preserve" attribute exists in the paragraph element:
+ xmlDocUniquePtr pXmlDoc = WrapReqifFromTempFile();
+ assertXPath(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p", "space"_ostr,
+ u"preserve"_ustr);
+ // Also check that the paragraph text is correct, without modifications in whitespace
+ assertXPathContent(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p", paraText);
+
+ // Test import
+
+ setImportFilterOptions("xhtmlns=reqif-xhtml");
+ setImportFilterName("HTML (StarWriter)");
+ load(maTempFile.GetURL());
+ CPPUNIT_ASSERT_EQUAL(paraText, getParagraph(1)->getString());
+}
+
CPPUNIT_PLUGIN_IMPLEMENT();
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/css1atr.cxx b/sw/source/filter/html/css1atr.cxx
index a922be479841..b98ba5cf73d1 100644
--- a/sw/source/filter/html/css1atr.cxx
+++ b/sw/source/filter/html/css1atr.cxx
@@ -1782,11 +1782,11 @@ SwHTMLWriter& OutCSS1_BodyTagStyleOpt( SwHTMLWriter& rWrt, const SfxItemSet& rIt
return rWrt;
}
-SwHTMLWriter& OutCSS1_ParaTagStyleOpt( SwHTMLWriter& rWrt, const SfxItemSet& rItemSet )
+SwHTMLWriter& OutCSS1_ParaTagStyleOpt( SwHTMLWriter& rWrt, const SfxItemSet& rItemSet, std::string_view rAdd )
{
SwCSS1OutMode aMode( rWrt, rWrt.m_nCSS1Script|CSS1_OUTMODE_STYLE_OPT |
CSS1_OUTMODE_ENCODE|CSS1_OUTMODE_PARA, nullptr );
- rWrt.OutCSS1_SfxItemSet( rItemSet, false );
+ rWrt.OutCSS1_SfxItemSet( rItemSet, false, rAdd );
return rWrt;
}
@@ -3571,7 +3571,7 @@ SwAttrFnTab const aCSS1AttrFnTab = {
static_assert(SAL_N_ELEMENTS(aCSS1AttrFnTab) == RES_BOXATR_END);
void SwHTMLWriter::OutCSS1_SfxItemSet( const SfxItemSet& rItemSet,
- bool bDeep )
+ bool bDeep, std::string_view rAdd )
{
// print ItemSet, including all attributes
Out_SfxItemSet( aCSS1AttrFnTab, *this, rItemSet, bDeep );
@@ -3603,6 +3603,20 @@ void SwHTMLWriter::OutCSS1_SfxItemSet( const SfxItemSet& rItemSet,
OutCSS1_SvxFormatBreak_SwFormatPDesc_SvxFormatKeep( *this, rItemSet, bDeep );
}
+ if (!rAdd.empty())
+ {
+ for (std::size_t index = 0; index != std::string_view::npos;)
+ {
+ std::string_view attr = o3tl::trim(o3tl::getToken(rAdd, ':', index));
+ assert(!attr.empty());
+ assert(index != std::string_view::npos);
+
+ std::string_view val = o3tl::trim(o3tl::getToken(rAdd, ':', index));
+ assert(!val.empty());
+ OutCSS1_PropertyAscii(attr, val);
+ }
+ }
+
if( m_bFirstCSS1Property )
return;
diff --git a/sw/source/filter/html/css1kywd.hxx b/sw/source/filter/html/css1kywd.hxx
index 5d84e3825191..42ad28da9259 100644
--- a/sw/source/filter/html/css1kywd.hxx
+++ b/sw/source/filter/html/css1kywd.hxx
@@ -217,6 +217,8 @@ constexpr inline std::string_view sCSS1_PV_inherit = "inherit";
constexpr inline std::string_view sCSS1_P_display = "display";
+constexpr inline std::string_view sCSS1_white_space = "white-space";
+
#endif
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/filter/html/htmlatr.cxx b/sw/source/filter/html/htmlatr.cxx
index d38f759acb84..da610d7ceccb 100644
--- a/sw/source/filter/html/htmlatr.cxx
+++ b/sw/source/filter/html/htmlatr.cxx
@@ -133,12 +133,12 @@ void SwHTMLWriter::OutAndSetDefList( sal_uInt16 nNewLvl )
// write according to the level difference
for( sal_uInt16 i=m_nDefListLvl; i<nNewLvl; i++ )
{
- if( m_bLFPossible )
+ if (IsLFPossible())
OutNewLine();
HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_deflist) );
HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_dd) );
IncIndentLevel();
- m_bLFPossible = true;
+ SetLFPossible(true);
}
}
else if( m_nDefListLvl > nNewLvl )
@@ -146,11 +146,11 @@ void SwHTMLWriter::OutAndSetDefList( sal_uInt16 nNewLvl )
for( sal_uInt16 i=nNewLvl ; i < m_nDefListLvl; i++ )
{
DecIndentLevel();
- if( m_bLFPossible )
+ if (IsLFPossible())
OutNewLine();
HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_dd), false );
HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_deflist), false );
- m_bLFPossible = true;
+ SetLFPossible(true);
}
}
@@ -162,7 +162,7 @@ void SwHTMLWriter::ChangeParaToken( HtmlTokenId nNew )
if( nNew != m_nLastParaToken && HtmlTokenId::PREFORMTXT_ON == m_nLastParaToken )
{
HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_preformtxt), false );
- m_bLFPossible = true;
+ SetLFPossible(true);
}
m_nLastParaToken = nNew;
}
@@ -749,7 +749,7 @@ static void OutHTML_SwFormat( SwHTMLWriter& rWrt, const SwFormat& rFormat,
(rWrt.m_nDefListLvl-1) * rWrt.m_nDefListMargin;
}
- if( rWrt.m_bLFPossible && !rWrt.m_bFirstLine )
+ if (rWrt.IsLFPossible() && !rWrt.m_bFirstLine)
rWrt.OutNewLine(); // paragraph tag on a new line
rInfo.bOutPara = false;
@@ -811,7 +811,7 @@ static void OutHTML_SwFormat( SwHTMLWriter& rWrt, const SwFormat& rFormat,
rWrt.m_bNoAlign = false;
rInfo.bOutDiv = true;
rWrt.IncIndentLevel();
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
rWrt.OutNewLine();
}
@@ -925,6 +925,15 @@ static void OutHTML_SwFormat( SwHTMLWriter& rWrt, const SwFormat& rFormat,
rWrt.Strm().WriteOString( sOut );
sOut = "";
+ std::string_view sStyle;
+ if (rWrt.IsSpacePreserve())
+ {
+ if (rWrt.mbXHTML)
+ rWrt.Strm().WriteOString(" xml:space=\"preserve\"");
+ else
+ sStyle = "white-space: pre-wrap";
+ }
+
// if necessary, output alignment
if( !rWrt.m_bNoAlign && pAdjItem )
OutHTML_SvxAdjust( rWrt, *pAdjItem );
@@ -935,7 +944,7 @@ static void OutHTML_SwFormat( SwHTMLWriter& rWrt, const SwFormat& rFormat,
// and now, if necessary, the STYLE options
if (rWrt.m_bCfgOutStyles && rInfo.moItemSet)
{
- OutCSS1_ParaTagStyleOpt( rWrt, *rInfo.moItemSet );
+ OutCSS1_ParaTagStyleOpt(rWrt, *rInfo.moItemSet, sStyle);
}
if (rWrt.m_bParaDotLeaders) {
@@ -1005,7 +1014,7 @@ static void OutHTML_SwFormatOff( SwHTMLWriter& rWrt, const SwHTMLTextCollOutputI
if( rInfo.ShouldOutputToken() )
{
- if( rWrt.m_bPrettyPrint && rWrt.m_bLFPossible )
+ if (rWrt.m_bPrettyPrint && rWrt.IsLFPossible())
rWrt.OutNewLine( true );
// if necessary, for BLOCKQUOTE, ADDRESS and DD another paragraph token
@@ -1016,18 +1025,18 @@ static void OutHTML_SwFormatOff( SwHTMLWriter& rWrt, const SwHTMLTextCollOutputI
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_parabreak), false );
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + rInfo.aToken), false );
- rWrt.m_bLFPossible =
+ rWrt.SetLFPossible(
rInfo.aToken != OOO_STRING_SVTOOLS_HTML_dt &&
rInfo.aToken != OOO_STRING_SVTOOLS_HTML_dd &&
- rInfo.aToken != OOO_STRING_SVTOOLS_HTML_li;
+ rInfo.aToken != OOO_STRING_SVTOOLS_HTML_li);
}
if( rInfo.bOutDiv )
{
rWrt.DecIndentLevel();
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine();
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_division), false );
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
}
// if necessary, close the list item, then close a bulleted or numbered list
@@ -2002,6 +2011,30 @@ void HTMLEndPosLst::OutEndAttrs( SwHTMLWriter& rWrt, sal_Int32 nPos )
}
}
+static bool NeedPreserveWhitespace(std::u16string_view str)
+{
+ if (str.empty())
+ return false;
+ // leading / trailing spaces
+ if (o3tl::internal::implIsWhitespace(str.front())
+ || o3tl::internal::implIsWhitespace(str.back()))
+ return true;
+ bool bWasSpace = false;
+ for (auto ch : str)
+ {
+ if (o3tl::internal::implIsWhitespace(ch))
+ {
+ if (bWasSpace)
+ return true; // Second whitespace in a row
+ else
+ bWasSpace = true;
+ }
+ else
+ bWasSpace = false;
+ }
+ return false;
+}
+
/* Output of the nodes*/
SwHTMLWriter& OutHTML_SwTextNode( SwHTMLWriter& rWrt, const SwContentNode& rNode )
{
@@ -2027,10 +2060,10 @@ SwHTMLWriter& OutHTML_SwTextNode( SwHTMLWriter& rWrt, const SwContentNode& rNode
// Output all the nodes that are anchored to a frame
rWrt.OutFlyFrame( rNode.GetIndex(), 0, HtmlPosition::Any );
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine(); // paragraph tag on a new line
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
HtmlWriter aHtml(rWrt.Strm(), rWrt.maNamespace);
aHtml.prettyPrint(rWrt.m_bPrettyPrint);
@@ -2138,11 +2171,11 @@ SwHTMLWriter& OutHTML_SwTextNode( SwHTMLWriter& rWrt, const SwContentNode& rNode
{
// ... and it is located before a table or a section
rWrt.OutBookmarks();
- rWrt.m_bLFPossible = rWrt.m_nLastParaToken == HtmlTokenId::NONE;
+ rWrt.SetLFPossible(rWrt.m_nLastParaToken == HtmlTokenId::NONE);
// Output all frames that are anchored to this node
rWrt.OutFlyFrame( rNode.GetIndex(), 0, HtmlPosition::Any );
- rWrt.m_bLFPossible = false;
+ rWrt.SetLFPossible(false);
return rWrt;
}
@@ -2213,12 +2246,15 @@ SwHTMLWriter& OutHTML_SwTextNode( SwHTMLWriter& rWrt, const SwContentNode& rNode
// now, output the tag of the paragraph
const SwFormat& rFormat = pNd->GetAnyFormatColl();
SwHTMLTextCollOutputInfo aFormatInfo;
- bool bOldLFPossible = rWrt.m_bLFPossible;
+ bool bOldLFPossible = rWrt.IsLFPossible();
+ bool bOldSpacePreserve = rWrt.IsSpacePreserve();
+ if (rWrt.IsPreserveSpacesOnWritePrefSet())
+ rWrt.SetSpacePreserve(NeedPreserveWhitespace(rStr));
OutHTML_SwFormat( rWrt, rFormat, pNd->GetpSwAttrSet(), aFormatInfo );
// If we didn't open a new line before the paragraph tag, we do that now
- rWrt.m_bLFPossible = rWrt.m_nLastParaToken == HtmlTokenId::NONE;
- if( !bOldLFPossible && rWrt.m_bLFPossible )
+ rWrt.SetLFPossible(rWrt.m_nLastParaToken == HtmlTokenId::NONE);
+ if (!bOldLFPossible && rWrt.IsLFPossible())
rWrt.OutNewLine();
// then, the bookmarks (including end tag)
@@ -2228,12 +2264,12 @@ SwHTMLWriter& OutHTML_SwTextNode( SwHTMLWriter& rWrt, const SwContentNode& rNode
// now it's a good opportunity again for an LF - if it is still allowed
// FIXME: for LOK case we set rWrt.m_nWishLineLen as -1, for now keep old flow
// when LOK side will be fixed - don't insert new line at the beginning
- if( rWrt.m_bLFPossible && rWrt.m_bPrettyPrint && rWrt.m_nWishLineLen >= 0 &&
+ if( rWrt.IsLFPossible() && rWrt.m_bPrettyPrint && rWrt.m_nWishLineLen >= 0 &&
rWrt.GetLineLen() >= rWrt.m_nWishLineLen )
{
rWrt.OutNewLine();
}
- rWrt.m_bLFPossible = false;
+ rWrt.SetLFPossible(false);
// find text that originates from an outline numbering
sal_Int32 nOffset = 0;
@@ -2430,16 +2466,16 @@ SwHTMLWriter& OutHTML_SwTextNode( SwHTMLWriter& rWrt, const SwContentNode& rNode
if( pTextHt )
{
- rWrt.m_bLFPossible = rWrt.m_nLastParaToken == HtmlTokenId::NONE &&
+ rWrt.SetLFPossible(rWrt.m_nLastParaToken == HtmlTokenId::NONE &&
nStrPos > 0 &&
- rStr[nStrPos-1] == ' ';
+ rStr[nStrPos-1] == ' ');
sal_uInt16 nCSS1Script = rWrt.m_nCSS1Script;
rWrt.m_nCSS1Script = aEndPosLst.GetScriptAtPos(
nStrPos + nOffset, nCSS1Script );
HTMLOutFuncs::FlushToAscii( rWrt.Strm() );
Out( aHTMLAttrFnTab, pTextHt->GetAttr(), rWrt );
rWrt.m_nCSS1Script = nCSS1Script;
- rWrt.m_bLFPossible = false;
+ rWrt.SetLFPossible(false);
}
if( bOutChar )
@@ -2457,7 +2493,7 @@ SwHTMLWriter& OutHTML_SwTextNode( SwHTMLWriter& rWrt, const SwContentNode& rNode
// try to split a line after about 255 characters
// at a space character unless in a PRE-context
- if( ' ' == c && rWrt.m_nLastParaToken == HtmlTokenId::NONE )
+ if( ' ' == c && rWrt.m_nLastParaToken == HtmlTokenId::NONE && !rWrt.IsSpacePreserve() )
{
sal_Int32 nLineLen;
nLineLen = rWrt.GetLineLen();
@@ -2569,7 +2605,7 @@ SwHTMLWriter& OutHTML_SwTextNode( SwHTMLWriter& rWrt, const SwContentNode& rNode
{
aHtml.single(OOO_STRING_SVTOOLS_HTML_linebreak);
}
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
}
}
@@ -2597,15 +2633,15 @@ SwHTMLWriter& OutHTML_SwTextNode( SwHTMLWriter& rWrt, const SwContentNode& rNode
rWrt.m_bClearLeft = false;
rWrt.m_bClearRight = false;
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
}
// if an LF is not allowed already, it is allowed once the paragraphs
// ends with a ' '
- if( !rWrt.m_bLFPossible &&
+ if (!rWrt.IsLFPossible() &&
rWrt.m_nLastParaToken == HtmlTokenId::NONE &&
nEnd > 0 && ' ' == rStr[nEnd-1] )
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
// dot leaders: print the skipped page number in a different span element
if (nIndexTab > -1) {
@@ -2615,6 +2651,7 @@ SwHTMLWriter& OutHTML_SwTextNode( SwHTMLWriter& rWrt, const SwContentNode& rNode
rWrt.m_bTagOn = false;
OutHTML_SwFormatOff( rWrt, aFormatInfo );
+ rWrt.SetSpacePreserve(bOldSpacePreserve);
// if necessary, close a form
rWrt.OutForm( false );
diff --git a/sw/source/filter/html/htmlfldw.cxx b/sw/source/filter/html/htmlfldw.cxx
index 04f5dad8dbdc..e8d38608b42c 100644
--- a/sw/source/filter/html/htmlfldw.cxx
+++ b/sw/source/filter/html/htmlfldw.cxx
@@ -519,7 +519,7 @@ SwHTMLWriter& OutHTML_SwFormatField( SwHTMLWriter& rWrt, const SfxPoolItem& rHt
}
else if( SwFieldIds::Script == pFieldTyp->Which() )
{
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine( true );
bool bURL = static_cast<const SwScriptField *>(pField)->IsCodeURL();
@@ -535,7 +535,7 @@ SwHTMLWriter& OutHTML_SwFormatField( SwHTMLWriter& rWrt, const SfxPoolItem& rHt
HTMLOutFuncs::OutScript( rWrt.Strm(), rWrt.GetBaseURL(), aContents, rType, JAVASCRIPT,
aURL, nullptr, nullptr );
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine( true );
}
else
diff --git a/sw/source/filter/html/htmlflywriter.cxx b/sw/source/filter/html/htmlflywriter.cxx
index ed25c65d162e..1f19eb77a6c7 100644
--- a/sw/source/filter/html/htmlflywriter.cxx
+++ b/sw/source/filter/html/htmlflywriter.cxx
@@ -415,7 +415,7 @@ void SwHTMLWriter::OutFrameFormat( AllHtmlFlags nMode, const SwFrameFormat& rFra
if( HtmlContainerFlags::NONE != nCntnrMode )
{
- if( m_bLFPossible && HtmlContainerFlags::Div == nCntnrMode )
+ if (IsLFPossible() && HtmlContainerFlags::Div == nCntnrMode)
OutNewLine();
OStringBuffer sOut;
@@ -443,7 +443,7 @@ void SwHTMLWriter::OutFrameFormat( AllHtmlFlags nMode, const SwFrameFormat& rFra
if( HtmlContainerFlags::Div == nCntnrMode )
{
IncIndentLevel();
- m_bLFPossible = true;
+ SetLFPossible(true);
}
}
@@ -495,10 +495,10 @@ void SwHTMLWriter::OutFrameFormat( AllHtmlFlags nMode, const SwFrameFormat& rFra
if( HtmlContainerFlags::Div == nCntnrMode )
{
DecIndentLevel();
- if( m_bLFPossible )
+ if (IsLFPossible())
OutNewLine();
HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_division), false );
- m_bLFPossible = true;
+ SetLFPossible(true);
}
else if( HtmlContainerFlags::Span == nCntnrMode )
HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_span), false );
@@ -1163,7 +1163,7 @@ OUString lclWriteOutImap(SwHTMLWriter& rWrt, const SfxItemSet& rItemSet, const S
OString aIndMap, aIndArea;
const char *pIndArea = nullptr, *pIndMap = nullptr;
- if (rWrt.m_bLFPossible)
+ if (rWrt.IsLFPossible())
{
rWrt.OutNewLine( true );
aIndMap = rWrt.GetIndentString();
@@ -1253,7 +1253,7 @@ SwHTMLWriter& OutHTML_ImageStart( HtmlWriter& rHtml, SwHTMLWriter& rWrt, const S
OUString aIMapName = lclWriteOutImap(rWrt, rItemSet, rFrameFormat, rRealSize, pAltImgMap, pURLItem);
// put img into new line
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine( true );
// <a name=...></a>...<img ...>
@@ -1594,7 +1594,7 @@ static SwHTMLWriter & OutHTML_FrameFormatAsMulticol( SwHTMLWriter& rWrt,
rWrt.OutAndSetDefList( 0 );
// output as Multicol
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine();
OStringBuffer sOut("<" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_multicol);
@@ -1631,7 +1631,7 @@ static SwHTMLWriter & OutHTML_FrameFormatAsMulticol( SwHTMLWriter& rWrt,
rWrt.Strm().WriteChar( '>' );
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
rWrt.IncIndentLevel(); // indent the content of Multicol
const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
@@ -1650,10 +1650,10 @@ static SwHTMLWriter & OutHTML_FrameFormatAsMulticol( SwHTMLWriter& rWrt,
}
rWrt.DecIndentLevel(); // indent the content of Multicol;
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine();
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_multicol), false );
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
return rWrt;
}
@@ -1661,7 +1661,7 @@ static SwHTMLWriter & OutHTML_FrameFormatAsMulticol( SwHTMLWriter& rWrt,
static SwHTMLWriter& OutHTML_FrameFormatAsSpacer( SwHTMLWriter& rWrt, const SwFrameFormat& rFrameFormat )
{
// if possible, output a line break before the graphic
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine( true );
OString sOut =
@@ -1696,7 +1696,7 @@ static SwHTMLWriter& OutHTML_FrameFormatAsDivOrSpan( SwHTMLWriter& rWrt,
aTag = OOO_STRING_SVTOOLS_HTML_span;
// output as DIV
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine();
OStringBuffer sOut("<" + rWrt.GetNamespace() + aTag);
@@ -1711,7 +1711,7 @@ static SwHTMLWriter& OutHTML_FrameFormatAsDivOrSpan( SwHTMLWriter& rWrt,
rWrt.Strm().WriteChar( '>' );
rWrt.IncIndentLevel(); // indent the content
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
const SwFormatContent& rFlyContent = rFrameFormat.GetContent();
SwNodeOffset nStt = rFlyContent.GetContentIdx()->GetIndex();
@@ -1733,7 +1733,7 @@ static SwHTMLWriter& OutHTML_FrameFormatAsDivOrSpan( SwHTMLWriter& rWrt,
}
rWrt.DecIndentLevel(); // indent the content of Multicol;
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine();
HTMLOutFuncs::Out_AsciiTag( rWrt.Strm(), Concat2View(rWrt.GetNamespace() + aTag), false );
diff --git a/sw/source/filter/html/htmlforw.cxx b/sw/source/filter/html/htmlforw.cxx
index b35cd76a24a8..e5a1efa8af1e 100644
--- a/sw/source/filter/html/htmlforw.cxx
+++ b/sw/source/filter/html/htmlforw.cxx
@@ -433,16 +433,16 @@ void SwHTMLWriter::OutForm( bool bOn,
if( !bOn )
{
DecIndentLevel(); // indent content of form
- if( m_bLFPossible )
+ if (IsLFPossible())
OutNewLine();
HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_form), false );
- m_bLFPossible = true;
+ SetLFPossible(true);
return;
}
// the new form is opened
- if( m_bLFPossible )
+ if (IsLFPossible())
OutNewLine();
OString sOut = "<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_form;
@@ -524,7 +524,7 @@ void SwHTMLWriter::OutForm( bool bOn,
Strm().WriteChar( '>' );
IncIndentLevel(); // indent content of form
- m_bLFPossible = true;
+ SetLFPossible(true);
}
void SwHTMLWriter::OutHiddenControls(
@@ -569,7 +569,7 @@ void SwHTMLWriter::OutHiddenControls(
if( form::FormComponentType::HIDDENCONTROL == *n )
{
- if( m_bLFPossible )
+ if (IsLFPossible())
OutNewLine( true );
OString sOut = "<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_input " "
OOO_STRING_SVTOOLS_HTML_O_type "=\""
@@ -769,7 +769,7 @@ SwHTMLWriter& OutHTML_DrawFrameFormatAsControl( SwHTMLWriter& rWrt,
break;
case form::FormComponentType::LISTBOX:
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine( true );
eTag = TAG_SELECT;
aTmp = xPropSet->getPropertyValue( "Dropdown" );
@@ -815,7 +815,7 @@ SwHTMLWriter& OutHTML_DrawFrameFormatAsControl( SwHTMLWriter& rWrt,
if( bMultiLine )
{
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine( true );
eTag = TAG_TEXTAREA;
@@ -1244,7 +1244,7 @@ SwHTMLWriter& OutHTML_DrawFrameFormatAsControl( SwHTMLWriter& rWrt,
rWrt.Strm().WriteOString( aEndTags );
// Controls aren't bound to a paragraph, therefore don't output LF anymore!
- rWrt.m_bLFPossible = false;
+ rWrt.SetLFPossible(false);
if( rWrt.mxFormComps.is() )
rWrt.OutHiddenControls( rWrt.mxFormComps, xPropSet );
diff --git a/sw/source/filter/html/htmlftn.cxx b/sw/source/filter/html/htmlftn.cxx
index 10b909d1df41..ed222e4e457d 100644
--- a/sw/source/filter/html/htmlftn.cxx
+++ b/sw/source/filter/html/htmlftn.cxx
@@ -355,7 +355,7 @@ void SwHTMLWriter::OutFootEndNotes()
sFootnoteName = OOO_STRING_SVTOOLS_HTML_sdfootnote + OUString::number(static_cast<sal_Int32>(++m_nFootNote));
}
- if( m_bLFPossible )
+ if (IsLFPossible())
OutNewLine();
OString sOut =
"<" + GetNamespace() + OOO_STRING_SVTOOLS_HTML_division
@@ -364,7 +364,7 @@ void SwHTMLWriter::OutFootEndNotes()
HTMLOutFuncs::Out_String( Strm(), sFootnoteName );
Strm().WriteOString( "\">" );
- m_bLFPossible = true;
+ SetLFPossible(true);
IncIndentLevel(); // indent content of <DIV>
OSL_ENSURE( pTextFootnote, "SwHTMLWriter::OutFootEndNotes: SwTextFootnote is missing" );
@@ -379,10 +379,10 @@ void SwHTMLWriter::OutFootEndNotes()
}
DecIndentLevel(); // indent content of <DIV>
- if( m_bLFPossible )
+ if (IsLFPossible())
OutNewLine();
HTMLOutFuncs::Out_AsciiTag( Strm(), Concat2View(GetNamespace() + OOO_STRING_SVTOOLS_HTML_division), false );
- m_bLFPossible = true;
+ SetLFPossible(true);
OSL_ENSURE( !m_pFormatFootnote,
"SwHTMLWriter::OutFootEndNotes: Footnote was not output" );
diff --git a/sw/source/filter/html/htmlnumwriter.cxx b/sw/source/filter/html/htmlnumwriter.cxx
index 6640f8f9376b..a4115ae7b4b8 100644
--- a/sw/source/filter/html/htmlnumwriter.cxx
+++ b/sw/source/filter/html/htmlnumwriter.cxx
@@ -309,7 +309,7 @@ SwHTMLWriter& OutHTML_NumberBulletListEnd( SwHTMLWriter& rWrt,
for( sal_uInt16 i=rInfo.GetDepth(); i>nNextDepth; i-- )
{
rWrt.DecIndentLevel(); // indent content of <OL>
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine(); // </OL>/</UL> in a new line
// a list is started or ended:
@@ -327,7 +327,7 @@ SwHTMLWriter& OutHTML_NumberBulletListEnd( SwHTMLWriter& rWrt,
rWrt.Strm(), Concat2View(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_li),
/*bOn=*/false);
}
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
}
return rWrt;
diff --git a/sw/source/filter/html/htmlplug.cxx b/sw/source/filter/html/htmlplug.cxx
index e078b00e2d3b..0216a6929dbf 100644
--- a/sw/source/filter/html/htmlplug.cxx
+++ b/sw/source/filter/html/htmlplug.cxx
@@ -1240,7 +1240,7 @@ SwHTMLWriter& OutHTML_FrameFormatOLENode( SwHTMLWriter& rWrt, const SwFrameForma
HtmlFrmOpts nFrameOpts;
// if possible output a line break before the "object"
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine( true );
if( !rFrameFormat.GetName().isEmpty() )
@@ -1635,7 +1635,7 @@ SwHTMLWriter& OutHTML_FrameFormatOLENodeGrf( SwHTMLWriter& rWrt, const SwFrameFo
aFileName = URIHelper::simpleNormalizedMakeRelative(rWrt.GetBaseURL(), aFileName);
// Refer to this data.
- if (rWrt.m_bLFPossible)
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine();
rWrt.Strm().WriteOString(Concat2View("<" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_object));
rWrt.Strm().WriteOString(Concat2View(" data=\"" + aFileName.toUtf8() + "\""));
@@ -1643,7 +1643,7 @@ SwHTMLWriter& OutHTML_FrameFormatOLENodeGrf( SwHTMLWriter& rWrt, const SwFrameFo
rWrt.Strm().WriteOString(Concat2View(" type=\"" + aFileType.toUtf8() + "\""));
rWrt.Strm().WriteOString(">");
bObjectOpened = true;
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
}
if (!bObjectOpened || bWriteReplacementGraphic)
diff --git a/sw/source/filter/html/htmltabw.cxx b/sw/source/filter/html/htmltabw.cxx
index d55512e1a44a..89fc247b8b7c 100644
--- a/sw/source/filter/html/htmltabw.cxx
+++ b/sw/source/filter/html/htmltabw.cxx
@@ -449,7 +449,7 @@ void SwHTMLWrtTable::OutTableCell( SwHTMLWriter& rWrt,
sOut.append('>');
rWrt.Strm().WriteOString( sOut );
sOut.setLength(0);
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
rWrt.IncIndentLevel(); // indent the content of <TD>...</TD>
@@ -486,11 +486,11 @@ void SwHTMLWrtTable::OutTableCell( SwHTMLWriter& rWrt,
rWrt.DecIndentLevel(); // indent the content of <TD>...</TD>
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine();
aTag = bHead ? OOO_STRING_SVTOOLS_HTML_tableheader : OOO_STRING_SVTOOLS_HTML_tabledata;
HTMLOutFuncs::Out_AsciiTag(rWrt.Strm(), Concat2View(rWrt.GetNamespace() + aTag), false);
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
}
// output a line as lines
@@ -614,7 +614,7 @@ void SwHTMLWrtTable::Write( SwHTMLWriter& rWrt, sal_Int16 eAlign,
// close previous numbering, etc
rWrt.ChangeParaToken( HtmlTokenId::NONE );
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine(); // <TABLE> in new line
OStringBuffer sOut("<" + rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_table);
@@ -1047,7 +1047,7 @@ SwHTMLWriter& OutHTML_SwTableNode( SwHTMLWriter& rWrt, SwTableNode & rNode,
if( text::HoriOrientation::NONE!=eDivHoriOri )
{
- if( rWrt.m_bLFPossible )
+ if (rWrt.IsLFPossible())
rWrt.OutNewLine(); // <CENTER> in new line
if( text::HoriOrientation::CENTER==eDivHoriOri )
{
@@ -1075,12 +1075,12 @@ SwHTMLWriter& OutHTML_SwTableNode( SwHTMLWriter& rWrt, SwTableNode & rNode,
}
}
rWrt.IncIndentLevel(); // indent content of <CENTER>
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
}
// If the table isn't in a frame, then you always can output a LF.
if( text::HoriOrientation::NONE==eTabHoriOri )
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
const SwHTMLTableLayout *pLayout = rTable.GetHTMLTableLayout();
@@ -1110,7 +1110,7 @@ SwHTMLWriter& OutHTML_SwTableNode( SwHTMLWriter& rWrt, SwTableNode & rNode,
// If the table wasn't in a frame, then you always can output a LF.
if( text::HoriOrientation::NONE==eTabHoriOri )
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
if( text::HoriOrientation::NONE!=eDivHoriOri )
{
@@ -1124,7 +1124,7 @@ SwHTMLWriter& OutHTML_SwTableNode( SwHTMLWriter& rWrt, SwTableNode & rNode,
// Not XHTML's css center: end <center>.
HTMLOutFuncs::Out_AsciiTag(rWrt.Strm(), Concat2View(rWrt.GetNamespace() + aTag), false);
}
- rWrt.m_bLFPossible = true;
+ rWrt.SetLFPossible(true);
}
// move Pam behind the table
diff --git a/sw/source/filter/html/svxcss1.cxx b/sw/source/filter/html/svxcss1.cxx
index 0150971144fe..d75cc487dab1 100644
--- a/sw/source/filter/html/svxcss1.cxx
+++ b/sw/source/filter/html/svxcss1.cxx
@@ -3044,6 +3044,19 @@ static void ParseCSS1_visibility(const CSS1Expression* pExpr, SfxItemSet& /*rIte
rPropInfo.m_bVisible = pExpr->GetString() != "hidden";
}
+static void ParseCSS1_white_space(const CSS1Expression* pExpr, SfxItemSet& /*rItemSet*/,
+ SvxCSS1PropertyInfo& rPropInfo, const SvxCSS1Parser& /*rParser*/)
+{
+ if (pExpr->GetType() == CSS1_IDENT)
+ {
+ if (pExpr->GetString().equalsIgnoreAsciiCase("pre")
+ || pExpr->GetString().equalsIgnoreAsciiCase("pre-wrap"))
+ {
+ rPropInfo.m_bPreserveSpace = true;
+ }
+ }
+}
+
namespace {
// the assignment of property to parsing function
@@ -3056,7 +3069,7 @@ struct CSS1PropEntry
}
// the table with assignments
-CSS1PropEntry const aCSS1PropFnTab[] =
+CSS1PropEntry constexpr aCSS1PropFnTab[] =
{
{ sCSS1_P_background, ParseCSS1_background },
{ sCSS1_P_background_color, ParseCSS1_background_color },
@@ -3110,10 +3123,15 @@ CSS1PropEntry const aCSS1PropFnTab[] =
{ sCSS1_P_text_transform, ParseCSS1_text_transform },
{ sCSS1_P_top, ParseCSS1_top },
{ sCSS1_P_visibility, ParseCSS1_visibility },
+ { sCSS1_white_space, ParseCSS1_white_space },
{ sCSS1_P_widows, ParseCSS1_widows },
{ sCSS1_P_width, ParseCSS1_width },
};
+static_assert(std::is_sorted(std::begin(aCSS1PropFnTab), std::end(aCSS1PropFnTab),
+ [](const auto& lhs, const auto& rhs) constexpr
+ { return lhs.pName < rhs.pName; }));
+
static bool CSS1PropEntryFindCompare(CSS1PropEntry const & lhs, OUString const & s)
{
return s.compareToIgnoreAsciiCaseAscii(lhs.pName) > 0;
@@ -3124,13 +3142,6 @@ void SvxCSS1Parser::DeclarationParsed( const OUString& rProperty,
{
OSL_ENSURE( m_pItemSet, "DeclarationParsed() without ItemSet" );
- // TODO: convert to static_assert, when C++20 constexpr std::is_sorted is available
- [[maybe_unused]] static const bool bSortedPropFns = []() {
- assert( std::is_sorted( std::begin(aCSS1PropFnTab), std::end(aCSS1PropFnTab),
- [](const auto& lhs, const auto& rhs) constexpr { return lhs.pName < rhs.pName; } ) );
- return true;
- }();
-
auto it = std::lower_bound( std::begin(aCSS1PropFnTab), std::end(aCSS1PropFnTab), rProperty,
CSS1PropEntryFindCompare );
if( it != std::end(aCSS1PropFnTab) && !CSS1PropEntryFindCompare(*it,rProperty) )
diff --git a/sw/source/filter/html/svxcss1.hxx b/sw/source/filter/html/svxcss1.hxx
index 985f98a079b7..669ed92a5b95 100644
--- a/sw/source/filter/html/svxcss1.hxx
+++ b/sw/source/filter/html/svxcss1.hxx
@@ -115,6 +115,7 @@ public:
bool m_bTextIndent : 1;
bool m_bNumbering : 1;
bool m_bBullet : 1;
+ bool m_bPreserveSpace : 1 = false;
SvxAdjust m_eFloat;
diff --git a/sw/source/filter/html/swhtml.cxx b/sw/source/filter/html/swhtml.cxx
index 2ef2105995db..17c0da4e25c2 100644
--- a/sw/source/filter/html/swhtml.cxx
+++ b/sw/source/filter/html/swhtml.cxx
@@ -3977,6 +3977,11 @@ void SwHTMLParser::NewPara()
case HtmlOptionId::DIR:
aDir = rOption.GetString();
break;
+ case HtmlOptionId::XML_SPACE:
+ if (rOption.GetString() == "preserve")
+ SetPreserveSpaces(true);
+ break;
+
default: break;
}
}
@@ -4000,6 +4005,9 @@ void SwHTMLParser::NewPara()
"Class is not considered" );
DoPositioning( aItemSet, aPropInfo, xCntxt.get() );
InsertAttrs( aItemSet, aPropInfo, xCntxt.get() );
+
+ if (aPropInfo.m_bPreserveSpace)
+ SetPreserveSpaces(true);
}
}
@@ -4065,6 +4073,7 @@ void SwHTMLParser::EndPara( bool bReal )
SetTextCollAttrs();
m_nOpenParaToken = HtmlTokenId::NONE;
+ SetPreserveSpaces(false);
}
void SwHTMLParser::NewHeading( HtmlTokenId nToken )
diff --git a/sw/source/filter/html/wrthtml.cxx b/sw/source/filter/html/wrthtml.cxx
index 32cdb1ba5271..0578bbbf6682 100644
--- a/sw/source/filter/html/wrthtml.cxx
+++ b/sw/source/filter/html/wrthtml.cxx
@@ -146,7 +146,6 @@ SwHTMLWriter::SwHTMLWriter( const OUString& rBaseURL, std::u16string_view rFilte
, m_bNoAlign( false )
, m_bClearLeft( false )
, m_bClearRight( false )
- , m_bLFPossible( false )
, m_bPreserveForm( false )
, m_bCfgNetscape4( false )
, mbSkipImages(false)
@@ -348,6 +347,16 @@ void SwHTMLWriter::SetupFilterFromPropertyValues(
it->second >>= nVal;
m_nLeadingTabWidth.emplace(nVal);
}
+
+ it = aStoreMap.find("PreserveSpaces");
+ if (it != aStoreMap.end())
+ {
+ // Paragraphs with leading/trailing/repeated whitespace will have "white-space: pre-wrap"
+ // style; whitespace in content will not be altered (except for "LeadingTabWidth" effects)
+ bool bVal = false;
+ it->second >>= bVal;
+ m_bPreserveSpacesOnWrite = bVal;
+ }
}
ErrCode SwHTMLWriter::WriteStream()
@@ -455,6 +464,7 @@ ErrCode SwHTMLWriter::WriteStream()
m_bPreserveForm = false;
m_bClearLeft = m_bClearRight = false;
m_bLFPossible = false;
+ m_bSpacePreserve = false;
m_nLeftMargin = m_nDfltLeftMargin = m_nDfltRightMargin = 0;
m_nDfltTopMargin = m_nDfltBottomMargin = 0;
@@ -561,7 +571,7 @@ ErrCode SwHTMLWriter::WriteStream()
sal_uInt16 nHeaderAttrs = 0;
m_pCurrPageDesc = MakeHeader( nHeaderAttrs );
- m_bLFPossible = true;
+ SetLFPossible(true);
// output forms which contain only HiddenControls
OutHiddenForms();
@@ -601,7 +611,7 @@ ErrCode SwHTMLWriter::WriteStream()
OutHTML_HeaderFooter( *this, *pFooterFormat, false );
}
- if( m_bLFPossible )
+ if (IsLFPossible())
OutNewLine();
if (!mbSkipHeaderFooter)
{
@@ -721,7 +731,7 @@ static void lcl_html_OutSectionStartTag( SwHTMLWriter& rHTMLWrt,
{
OSL_ENSURE( pCol || !bContinued, "Continuation of DIV" );
- if( rHTMLWrt.m_bLFPossible )
+ if (rHTMLWrt.IsLFPossible())
rHTMLWrt.OutNewLine();
OStringBuffer sOut("<" + rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_division);
@@ -793,7 +803,7 @@ static void lcl_html_OutSectionStartTag( SwHTMLWriter& rHTMLWrt,
rHTMLWrt.Strm().WriteChar( '>' );
- rHTMLWrt.m_bLFPossible = true;
+ rHTMLWrt.SetLFPossible(true);
if( !rName.isEmpty() && !bContinued )
rHTMLWrt.OutImplicitMark( rName, "region" );
@@ -803,10 +813,10 @@ static void lcl_html_OutSectionStartTag( SwHTMLWriter& rHTMLWrt,
static void lcl_html_OutSectionEndTag( SwHTMLWriter& rHTMLWrt )
{
rHTMLWrt.DecIndentLevel();
- if( rHTMLWrt.m_bLFPossible )
+ if (rHTMLWrt.IsLFPossible())
rHTMLWrt.OutNewLine();
HTMLOutFuncs::Out_AsciiTag( rHTMLWrt.Strm(), Concat2View(rHTMLWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_division), false );
- rHTMLWrt.m_bLFPossible = true;
+ rHTMLWrt.SetLFPossible(true);
}
static SwHTMLWriter& OutHTML_Section( SwHTMLWriter& rWrt, const SwSectionNode& rSectNd )
diff --git a/sw/source/filter/html/wrthtml.hxx b/sw/source/filter/html/wrthtml.hxx
index 5dc00bbb982a..6b49fe984119 100644
--- a/sw/source/filter/html/wrthtml.hxx
+++ b/sw/source/filter/html/wrthtml.hxx
@@ -278,6 +278,10 @@ class SW_DLLPUBLIC SwHTMLWriter : public Writer
FieldUnit m_eCSS1Unit;
+ bool m_bLFPossible = false; // a line break can be inserted
+ bool m_bSpacePreserve = false; // Using xml::space="preserve", or "white-space: pre-wrap" style
+ bool m_bPreserveSpacesOnWrite = false; // If export should use m_bSpacePreserve
+
sal_uInt16 OutHeaderAttrs();
const SwPageDesc *MakeHeader( sal_uInt16& rHeaderAtrs );
void GetControls();
@@ -392,7 +396,6 @@ public:
bool m_bNoAlign : 1; // HTML tag doesn't allow ALIGN=...
bool m_bClearLeft : 1; // <BR CLEAR=LEFT> write at end of paragraph
bool m_bClearRight : 1; // <BR CLEAR=RIGHT> write at end of paragraph
- bool m_bLFPossible : 1; // a line break can be inserted
// others
@@ -485,7 +488,7 @@ public:
const OUString *pSVal, std::optional<sw::Css1Background> oBackground = std::nullopt );
void OutCSS1_UnitProperty( std::string_view pProp, tools::Long nVal );
void OutCSS1_PixelProperty( std::string_view pProp, tools::Long nTwips );
- void OutCSS1_SfxItemSet( const SfxItemSet& rItemSet, bool bDeep=true );
+ void OutCSS1_SfxItemSet( const SfxItemSet& rItemSet, bool bDeep=true, std::string_view rAdd = {} );
// events of BODY tag from SFX configuration
void OutBasicBodyEvents();
@@ -616,6 +619,12 @@ public:
/// Determines the prefix string needed to respect the requested namespace alias.
OString GetNamespace() const;
+
+ bool IsLFPossible() const { return !m_bSpacePreserve && m_bLFPossible; }
+ void SetLFPossible(bool val) { m_bLFPossible = val; }
+ bool IsSpacePreserve() const { return m_bSpacePreserve; }
+ void SetSpacePreserve(bool val) { m_bSpacePreserve = val; }
+ bool IsPreserveSpacesOnWritePrefSet() const { return m_bPreserveSpacesOnWrite; }
};
inline bool SwHTMLWriter::IsCSS1Source( sal_uInt16 n ) const
@@ -706,7 +715,7 @@ SwHTMLWriter& OutHTML_SwFormatLineBreak(SwHTMLWriter& rWrt, const SfxPoolItem& r
SwHTMLWriter& OutHTML_INetFormat( SwHTMLWriter&, const SwFormatINetFormat& rINetFormat, bool bOn );
SwHTMLWriter& OutCSS1_BodyTagStyleOpt( SwHTMLWriter& rWrt, const SfxItemSet& rItemSet );
-SwHTMLWriter& OutCSS1_ParaTagStyleOpt( SwHTMLWriter& rWrt, const SfxItemSet& rItemSet );
+SwHTMLWriter& OutCSS1_ParaTagStyleOpt( SwHTMLWriter& rWrt, const SfxItemSet& rItemSet, std::string_view rAdd = {} );
SwHTMLWriter& OutCSS1_HintSpanTag( SwHTMLWriter& rWrt, const SfxPoolItem& rHt );
SwHTMLWriter& OutCSS1_HintStyleOpt( SwHTMLWriter& rWrt, const SfxPoolItem& rHt );