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;
         }

Reply via email to