sw/inc/ndtxt.hxx | 3 +++ sw/qa/extras/layout/data/tdf167526.docx |binary sw/qa/extras/layout/layout5.cxx | 12 ++++++++++++ sw/source/core/inc/txtfrm.hxx | 3 +++ sw/source/core/text/txtfrm.cxx | 8 +++++++- sw/source/core/txtnode/ndtxt.cxx | 13 +++++++++++++ sw/source/filter/ww8/docxexport.cxx | 19 +------------------ 7 files changed, 39 insertions(+), 19 deletions(-)
New commits: commit 14f4ea109d4cd8fe50fd419f51e3370c74169343 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Thu Jul 17 12:13:14 2025 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Thu Jul 17 10:23:24 2025 +0200 tdf#167535: Ignore dummy anchor nodes in line numbering Commit 441aed20b95ee40dec1df72fb8e8167d0e48c0c4 (tdf#167379 sw floattable: make dummy paragraph from DOCX import less visible, 2025-07-10) introduced dummy nodes as invisible anchors for floating tables without normal anchor nodes. These nodes are not part of actual content; take that into account in SwTextFrame::ChgThisLines, which calculates line numbering. Added SwTextNode::IsDummyAnchorNode and SwTextFrame::IsDummyAnchorFrame to avoid code duplication. Change-Id: I872df4d1f02a4abc75f7bd6316795cae2f951b0e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187982 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/sw/inc/ndtxt.hxx b/sw/inc/ndtxt.hxx index 78115ffadf8b..4086a8fdb8dc 100644 --- a/sw/inc/ndtxt.hxx +++ b/sw/inc/ndtxt.hxx @@ -893,6 +893,9 @@ public: { TriggerNodeUpdate(sw::LegacyModifyHint(&rDrop, &rDrop)); }; void SetInSwUndo(bool bInUndo); + + // For nodes created to provide anchor points for floating tables + bool IsDummyAnchorNode() const; }; inline SwpHints & SwTextNode::GetSwpHints() diff --git a/sw/qa/extras/layout/data/tdf167526.docx b/sw/qa/extras/layout/data/tdf167526.docx index 050f081ff8e3..47c0fe5d2a01 100644 Binary files a/sw/qa/extras/layout/data/tdf167526.docx and b/sw/qa/extras/layout/data/tdf167526.docx differ diff --git a/sw/qa/extras/layout/layout5.cxx b/sw/qa/extras/layout/layout5.cxx index 50212f60cf19..8cc0fe737155 100644 --- a/sw/qa/extras/layout/layout5.cxx +++ b/sw/qa/extras/layout/layout5.cxx @@ -1867,6 +1867,18 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter5, testTdf167526) // Without a fix, this would fail, because the third element was the wrongly emitted <w:p> assertXPathNodeName(pXmlDoc, "/w:document/w:body/*[3]", "tbl"); } + + // tdf#167535: check line numbering; the dummy node must not interfere with it + { + // Dump the rendering of the first page as an XML file. + SwDocShell* pShell = getSwDocShell(); + std::shared_ptr<GDIMetaFile> xMetaFile = pShell->GetPreviewMetaFile(); + MetafileXmlDump dumper; + xmlDocUniquePtr pXmlDoc = dumpAndParse(dumper, *xMetaFile); + // Without a fix, this was 3 + assertXPathContent( + pXmlDoc, "/metafile/push/push/push/textarray[@index=0 and @length=1][2]/text", u"2"); + } } CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/source/core/inc/txtfrm.hxx b/sw/source/core/inc/txtfrm.hxx index 7b61c8029d82..acc4c2c4f390 100644 --- a/sw/source/core/inc/txtfrm.hxx +++ b/sw/source/core/inc/txtfrm.hxx @@ -345,6 +345,9 @@ class SW_DLLPUBLIC SwTextFrame final : public SwContentFrame /// Like GetDrawObjs(), but limit to fly frames which are allowed to split. std::vector<SwFlyAtContentFrame*> GetSplitFlyDrawObjs() const; + // For zero-height frames created to provide anchor points for floating tables + bool IsDummyAnchorFrame() const; + public: virtual const SvxFormatBreakItem& GetBreakItem() const override; diff --git a/sw/source/core/text/txtfrm.cxx b/sw/source/core/text/txtfrm.cxx index bea6d81e3b44..2f6780af0f97 100644 --- a/sw/source/core/text/txtfrm.cxx +++ b/sw/source/core/text/txtfrm.cxx @@ -4038,6 +4038,12 @@ SwTwips SwTextFrame::FirstLineHeight() const return nHeight; } +bool SwTextFrame::IsDummyAnchorFrame() const +{ + // I *think* that when there is m_pMergedPara, it can't be a dummy frame. + return !GetMergedPara() && GetTextNodeForParaProps()->IsDummyAnchorNode(); +} + sal_Int32 SwTextFrame::GetLineCount(TextFrameIndex const nPos) { sal_Int32 nRet = 0; @@ -4082,7 +4088,7 @@ void SwTextFrame::ChgThisLines() } while ( aLine.NextLine() ); } } - else if ( rInf.IsCountBlankLines() ) + else if (!IsDummyAnchorFrame() && rInf.IsCountBlankLines()) nNew = 1; if ( nNew == mnThisLines ) diff --git a/sw/source/core/txtnode/ndtxt.cxx b/sw/source/core/txtnode/ndtxt.cxx index 91edfd7ee129..cdb46a3f644b 100644 --- a/sw/source/core/txtnode/ndtxt.cxx +++ b/sw/source/core/txtnode/ndtxt.cxx @@ -4950,6 +4950,19 @@ bool SwTextNode::IsHidden() const return pSectNd && pSectNd->GetSection().IsHiddenFlag(); } +bool SwTextNode::IsDummyAnchorNode() const +{ + // See OOXMLFastContextHandlerTextTable::lcl_startFastElement + + if (!HasSwAttrSet()) + return false; + + const SwAttrSet& rAttrSet = GetSwAttrSet(); + const SvxLineSpacingItem& rLineSpacing = rAttrSet.GetLineSpacing(); + return rLineSpacing.GetLineSpaceRule() == SvxLineSpaceRule::Fix + && rLineSpacing.GetLineHeight() == 0; +} + namespace { // Helper class for special handling of setting attributes at text node: // In constructor an instance of the helper class recognize whose attributes diff --git a/sw/source/filter/ww8/docxexport.cxx b/sw/source/filter/ww8/docxexport.cxx index 87d906b75970..5d58a02f7289 100644 --- a/sw/source/filter/ww8/docxexport.cxx +++ b/sw/source/filter/ww8/docxexport.cxx @@ -552,24 +552,7 @@ void DocxExport::CollectFloatingTables() SwNode& rNode = pContentAnchor->GetNode(); SwTextNode* pTextNode = rNode.GetTextNode(); - if (!pTextNode) - { - continue; - } - - if (!pTextNode->HasSwAttrSet()) - { - continue; - } - - const SwAttrSet& rAttrSet = pTextNode->GetSwAttrSet(); - const SvxLineSpacingItem& rLineSpacing = rAttrSet.GetLineSpacing(); - if (rLineSpacing.GetLineSpaceRule() != SvxLineSpaceRule::Fix) - { - continue; - } - - if (rLineSpacing.GetLineHeight() != 0) + if (!pTextNode || !pTextNode->IsDummyAnchorNode()) { continue; }