sw/qa/extras/htmlexport/htmlexport.cxx | 42 +++++++++++++++++++++++++++++ sw/source/filter/html/htmlnumwriter.cxx | 46 ++++++++++++++++++-------------- 2 files changed, 69 insertions(+), 19 deletions(-)
New commits: commit 2466b9fcf20ee61f6fc621298011c0efaa55e7c6 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Mon Feb 21 16:38:51 2022 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Feb 23 11:07:45 2022 +0100 sw HTML export, XHTML mode: fix lost </li> when last list item is not numbered This went wrong in 013a4f1f5c9ea5fb511568c53a7e76d1b365a65d (sw XHTML export: fix handling of list labels, 2021-05-13), where we started to assume that in case the last paragraph of a list is not numbered, then the entire list is not numbered. This lead to loosing the </li> for an <li> in case the list starts with a numbered paragraph, but ends with a non-numbered one. Fix the problem by (if necessary) looking back till the start of the list to see if any paragraph is numbered: that ensures that the <li> and </li> is always in sync. This fixes the new problem and keeps the old problem fixed at the same time. Change-Id: I7d347b37a40dcc727c2080bf8279e33c3ad147e9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130287 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins (cherry picked from commit 8c2607ae3ce143586e623532b8ae5288277ec3ac) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/130310 Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org> (cherry picked from commit 81f90d4ab51ec7528fa2a9b14c0426a634971580) diff --git a/sw/qa/extras/htmlexport/htmlexport.cxx b/sw/qa/extras/htmlexport/htmlexport.cxx index fa40c8d7d04c..7f64c835ce2d 100644 --- a/sw/qa/extras/htmlexport/htmlexport.cxx +++ b/sw/qa/extras/htmlexport/htmlexport.cxx @@ -1491,6 +1491,48 @@ CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testListHeading) assertXPathContent(pXmlDoc, "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:p", "list header"); } +CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testPartiallyNumberedList) +{ + // Given a document with a list, first para is numbered, second is not: + loadURL("private:factory/swriter", nullptr); + SwXTextDocument* pTextDoc = dynamic_cast<SwXTextDocument*>(mxComponent.get()); + SwWrtShell* pWrtShell = pTextDoc->GetDocShell()->GetWrtShell(); + pWrtShell->Insert("list header"); + SwDoc* pDoc = pWrtShell->GetDoc(); + sal_uInt16 nPos = pDoc->MakeNumRule(pDoc->GetUniqueNumRuleName()); + SwNumRule* pNumRule = pDoc->GetNumRuleTable()[nPos]; + { + SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->nNode.GetNode(); + SwTextNode& rTextNode = *rNode.GetTextNode(); + rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName())); + } + pWrtShell->Insert2("numbered"); + pWrtShell->SplitNode(); + pWrtShell->Insert2("not numbered"); + { + SwNode& rNode = pWrtShell->GetCursor()->GetPoint()->nNode.GetNode(); + SwTextNode& rTextNode = *rNode.GetTextNode(); + rTextNode.SetAttr(SwNumRuleItem(pNumRule->GetName())); + rTextNode.SetCountedInList(false); + } + + // When exporting to ReqIF: + ExportToReqif(); + + // Then make sure the output is well-formed xhtml: + SvMemoryStream aStream; + HtmlExportTest::wrapFragment(maTempFile, aStream); + xmlDocUniquePtr pXmlDoc = parseXmlStream(&aStream); + CPPUNIT_ASSERT(pXmlDoc); + // Without the accompanying fix in place, this test would have failed: + // - expected: <li><p>...</p><p>...</p></li> + // - actual : <li><p>...</p><p>...</p> + // because a <li> without a matching </li> is not well-formed, and the </li> was omitted because + // the second para was not numbered. + assertXPath(pXmlDoc, + "/reqif-xhtml:html/reqif-xhtml:div/reqif-xhtml:ol/reqif-xhtml:li/reqif-xhtml:p", 2); +} + CPPUNIT_TEST_FIXTURE(SwHtmlDomExportTest, testBlockQuoteNoMargin) { // Given a document with some text, para style set to Quotations, no bottom margin: diff --git a/sw/source/filter/html/htmlnumwriter.cxx b/sw/source/filter/html/htmlnumwriter.cxx index 7df3402dda35..df15619cd85e 100644 --- a/sw/source/filter/html/htmlnumwriter.cxx +++ b/sw/source/filter/html/htmlnumwriter.cxx @@ -321,25 +321,10 @@ Writer& OutHTML_NumberBulletListEnd( SwHTMLWriter& rWrt, bool bSameRule = rNextInfo.GetNumRule() == rInfo.GetNumRule(); bool bListEnd = !bSameRule || rNextInfo.GetDepth() < rInfo.GetDepth() || rNextInfo.IsRestart(); - if (rWrt.mbXHTML) - { - // XHTML </li> for the list item content. - if ((bListEnd && rInfo.IsNumbered()) || (!bListEnd && rNextInfo.IsNumbered())) - { - HTMLOutFuncs::Out_AsciiTag(rWrt.Strm(), - OStringConcatenation(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_li), false); - } - } - - if (!bListEnd) - { - return rWrt; - } - + std::optional<bool> oAtLeastOneNumbered; if (rWrt.mbXHTML && !rInfo.IsNumbered()) { - // If the list only consisted of non-numbered text nodes, then don't end the list. - bool bAtLeastOneNumbered = false; + oAtLeastOneNumbered = false; SwNodeOffset nPos = rWrt.m_pCurrentPam->GetPoint()->nNode.GetIndex() - 1; SwNumRule* pNumRule = nullptr; while (true) @@ -360,13 +345,36 @@ Writer& OutHTML_NumberBulletListEnd( SwHTMLWriter& rWrt, pNumRule = pTextNode->GetNumRule(); if (pTextNode->IsNumbered()) { - bAtLeastOneNumbered = true; + oAtLeastOneNumbered = true; break; } --nPos; } + } - if (!bAtLeastOneNumbered) + if (rWrt.mbXHTML) + { + // The list is numbered if the previous text node is numbered or any other previous text + // node is numbered. + bool bPrevIsNumbered = rInfo.IsNumbered() || *oAtLeastOneNumbered; + // XHTML </li> for the list item content, if there is an open <li>. + if ((bListEnd && bPrevIsNumbered) || (!bListEnd && rNextInfo.IsNumbered())) + { + HTMLOutFuncs::Out_AsciiTag( + rWrt.Strm(), OStringConcatenation(rWrt.GetNamespace() + OOO_STRING_SVTOOLS_HTML_li), + false); + } + } + + if (!bListEnd) + { + return rWrt; + } + + if (rWrt.mbXHTML && !rInfo.IsNumbered()) + { + // If the list only consisted of non-numbered text nodes, then don't end the list. + if (!*oAtLeastOneNumbered) { return rWrt; }