sw/qa/extras/uiwriter/uiwriter3.cxx                      |    8 ++-
 sw/qa/writerfilter/ooxml/data/floattable-anchorpos.docx  |binary
 sw/qa/writerfilter/ooxml/ooxml.cxx                       |   37 +++++++++++++++
 sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx |   19 +++++++
 4 files changed, 63 insertions(+), 1 deletion(-)

New commits:
commit 3d3d51cd630ab45a61790be27e930e98c3e749e6
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Wed Jul 9 13:37:02 2025 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Jul 11 08:39:29 2025 +0200

    tdf#167379 sw floattable: make dummy paragraph from DOCX import less visible
    
    Open the bugdoc, the text C and D appears to have the same vertical
    position in Word, but D is shifted down in Writer.
    
    What happens is that since commit
    01ad8ec4bb5425446e95dbada81de435646824b4 (sw floattable: fix lost tables
    around a floating table from DOCX, 2023-06-05), an empty paragraph is
    inserted between two floating tables immediately following each other,
    to have a suitable anchor point for all floating tables. But it wasn't
    considered that the anchor point takes vertical space, which has an
    impact on layout.
    
    Fix the problem by keeping the empty paragraph in the model & layout
    (the split fly frame needs those), but setting the paragraph properties
    (spacing, line spacing) in a way that the created text frame has 0
    height, so it has no negative impact on the position of the text after
    the text frame.
    
    This is similar to what the DOC import does in
    WW8TabDesc::CreateSwTable(), though there we set the font size of the
    paragraph to 1pt, which improves the layout but still has a small
    impact. An alternative I considered is to set the "hidden" character
    property on the text node's item set, but that would create no text
    frame at all, so we would again have no anchor point for the floating
    table, so that would not work.
    
    Change-Id: Iceb2f51ad42028434822cb9c0701a7e6d6545845
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187619
    Tested-by: Jenkins
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    (cherry picked from commit 441aed20b95ee40dec1df72fb8e8167d0e48c0c4)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/187645

diff --git a/sw/qa/extras/uiwriter/uiwriter3.cxx 
b/sw/qa/extras/uiwriter/uiwriter3.cxx
index 7362108c18ad..312df2db9d1e 100644
--- a/sw/qa/extras/uiwriter/uiwriter3.cxx
+++ b/sw/qa/extras/uiwriter/uiwriter3.cxx
@@ -844,7 +844,13 @@ CPPUNIT_TEST_FIXTURE(SwUiWriterTest3, testTdf134227)
 
     CPPUNIT_ASSERT_EQUAL(4, getShapes());
 
-    dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
+    // Go to the end of the document, outside the dummy paragraph that just 
serves as an anchor for
+    // the floating table.
+    uno::Reference<frame::XModel> xModel(mxComponent, uno::UNO_QUERY);
+    uno::Reference<text::XTextViewCursorSupplier> xTextViewCursorSupplier(
+        xModel->getCurrentController(), uno::UNO_QUERY);
+    uno::Reference<text::XTextViewCursor> xViewCursor = 
xTextViewCursorSupplier->getViewCursor();
+    xViewCursor->gotoEnd(/*bExpand=*/false);
     dispatchCommand(mxComponent, u".uno:SelectAll"_ustr, {});
 
     // Without the fix in place, it would have crashed here
diff --git a/sw/qa/writerfilter/ooxml/data/floattable-anchorpos.docx 
b/sw/qa/writerfilter/ooxml/data/floattable-anchorpos.docx
new file mode 100644
index 000000000000..d93e5772aa3f
Binary files /dev/null and 
b/sw/qa/writerfilter/ooxml/data/floattable-anchorpos.docx differ
diff --git a/sw/qa/writerfilter/ooxml/ooxml.cxx 
b/sw/qa/writerfilter/ooxml/ooxml.cxx
index c5f9af177a13..9a9d2745ba7c 100644
--- a/sw/qa/writerfilter/ooxml/ooxml.cxx
+++ b/sw/qa/writerfilter/ooxml/ooxml.cxx
@@ -17,6 +17,14 @@
 
 #include <fmtcntnt.hxx>
 #include <ndtxt.hxx>
+#include <docsh.hxx>
+#include <wrtsh.hxx>
+#include <rootfrm.hxx>
+#include <pagefrm.hxx>
+#include <txtfrm.hxx>
+#include <sortedobjs.hxx>
+#include <anchoredobject.hxx>
+#include <flyfrm.hxx>
 
 using namespace ::com::sun::star;
 
@@ -109,6 +117,35 @@ CPPUNIT_TEST_FIXTURE(Test, testNestedRuns)
     // Without the accompanying fix in place, this test would have failed, the 
shape was empty.
     CPPUNIT_ASSERT_EQUAL(u"Test text box"_ustr, pTextNode->GetText());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testFloatingTableAnchorPos)
+{
+    // Given a document with a floating table (text: C) and a visually first 
body paragraph (text:
+    // D):
+    // When loading that document:
+    createSwDoc("floattable-anchorpos.docx");
+
+    // Then make sure that D is not shifted down vertically, compared to C:
+    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+    SwRootFrame* pLayout = pWrtShell->GetLayout();
+    SwPageFrame* pPage = pLayout->GetLower()->DynCastPageFrame();
+    SwTextFrame* pBodyPara1 = 
pPage->FindFirstBodyContent()->DynCastTextFrame();
+    CPPUNIT_ASSERT(pBodyPara1->HasSplitFlyDrawObjs());
+    SwSortedObjs& rFlys1 = *pBodyPara1->GetDrawObjs();
+    SwFlyFrame* pFly1 = rFlys1[0]->DynCastFlyFrame();
+    SwTextFrame* pFly1Text = pFly1->ContainsContent()->DynCastTextFrame();
+    CPPUNIT_ASSERT_EQUAL(u"C"_ustr, pFly1Text->GetText());
+    SwTwips nFlyTop = pFly1Text->getFrameArea().Top();
+    SwTextFrame* pBodyPara2 = pBodyPara1->GetNext()->DynCastTextFrame();
+    CPPUNIT_ASSERT_EQUAL(u"D"_ustr, pBodyPara2->GetText());
+    SwTwips nBodyTop = pBodyPara2->getFrameArea().Top();
+    SwTwips nDiff = std::abs(nBodyTop - nFlyTop);
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected less or equal than: 1
+    // - Actual  : 243
+    // i.e. the vertical position of D was too big.
+    CPPUNIT_ASSERT_LESSEQUAL(static_cast<SwTwips>(1), nDiff);
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx 
b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx
index ab01166040fe..b7381fc84c3b 100644
--- a/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx
+++ b/sw/source/writerfilter/ooxml/OOXMLFastContextHandler.cxx
@@ -1620,6 +1620,25 @@ void 
OOXMLFastContextHandlerTextTable::lcl_startFastElement
         // subset of '<resource name="CT_P" resource="Stream">' in model.xml:
         startParagraphGroup();
         sendTableDepth();
+
+        OOXMLPropertySet::Pointer_t pSprms(new OOXMLPropertySet);
+        {
+            // Configure the dummy paragraph to have a zero height, so it has 
no impact on the
+            // layout.
+            OOXMLPropertySet::Pointer_t pAttributes(new OOXMLPropertySet);
+            OOXMLValue pSBVal = OOXMLValue::createInteger(0);
+            pAttributes->add(NS_ooxml::LN_CT_Spacing_before, pSBVal, 
OOXMLProperty::ATTRIBUTE);
+            OOXMLValue pSAVal = OOXMLValue::createInteger(0);
+            pAttributes->add(NS_ooxml::LN_CT_Spacing_after, pSAVal, 
OOXMLProperty::ATTRIBUTE);
+            OOXMLValue pSLRVal = 
OOXMLValue::createInteger(NS_ooxml::LN_Value_doc_ST_LineSpacingRule_exact);
+            pAttributes->add(NS_ooxml::LN_CT_Spacing_lineRule, pSLRVal, 
OOXMLProperty::ATTRIBUTE);
+            OOXMLValue pSLVal = OOXMLValue::createInteger(0);
+            pAttributes->add(NS_ooxml::LN_CT_Spacing_line, pSLVal, 
OOXMLProperty::ATTRIBUTE);
+            OOXMLValue pSprm = OOXMLValue::createPropertySet(pAttributes);
+            pSprms->add(NS_ooxml::LN_CT_PPrBase_spacing, pSprm, 
OOXMLProperty::SPRM);
+        }
+        mpStream->props(pSprms.get());
+
         endOfParagraph();
     }
 

Reply via email to