officecfg/registry/schema/org/openoffice/Office/Writer.xcs         |    7 
 sw/CppunitTest_sw_core_layout.mk                                   |    1 
 sw/CppunitTest_sw_core_layout_flycnt.mk                            |   82 
----------
 sw/Module_sw.mk                                                    |    1 
 sw/inc/formatflysplit.hxx                                          |    4 
 sw/qa/core/layout/data/floattable-vertoffset.docx                  |binary
 sw/qa/core/layout/flycnt.cxx                                       |   75 
++++++++-
 sw/qa/extras/ooxmlexport/ooxmlexport.cxx                           |   14 +
 sw/source/core/attr/formatflysplit.cxx                             |   28 ---
 sw/source/core/inc/cntfrm.hxx                                      |    3 
 sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx |   11 +
 sw/source/core/text/frmform.cxx                                    |   10 -
 sw/source/core/text/itratr.cxx                                     |   14 +
 sw/source/core/text/porrst.cxx                                     |    5 
 sw/source/core/unocore/unoframe.cxx                                |   10 +
 sw/source/filter/ww8/docxattributeoutput.cxx                       |    8 
 writerfilter/source/dmapper/DomainMapperTableHandler.cxx           |   15 +
 17 files changed, 162 insertions(+), 126 deletions(-)

New commits:
commit 0e98cf7e002757f0b693695598fb1d254ad4f8b1
Author:     Miklos Vajna <[email protected]>
AuthorDate: Fri Feb 17 08:49:59 2023 +0100
Commit:     Miklos Vajna <[email protected]>
CommitDate: Thu Mar 2 09:16:25 2023 +0100

    sw floattable: add ImportFloatingTableAsSplitFly expert setting
    
    Mapping DOCX floating tables to Writer split flys is still disabled by
    default, but now the environment variable affects the DOCX import
    instead of affecting the Writer item pool's default.
    
    This allows mixing ImportFloatingTableAsSplitFly=true and =false tests
    in the same suite, so the sw/CppunitTest_sw_core_layout_flycnt.mk
    boilerplate can be dropped.
    
    It also allows overwriting this default from an xcu file (expert config,
    or the XCU file in online.git) for testing / demo purposes.
    
    Also extend the layout representation comment / doc a bit.
    
    (cherry picked from commit 3282508f8deeafd50f5af45ca0adf760efb114a3)
    
    Change-Id: I239e9c6e9d9c8748ed0846ae336c9c818d59f180

diff --git a/officecfg/registry/schema/org/openoffice/Office/Writer.xcs 
b/officecfg/registry/schema/org/openoffice/Office/Writer.xcs
index 9451792366fe..d6276800c1be 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Writer.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Writer.xcs
@@ -5670,6 +5670,13 @@
             </info>
             <value>true</value>
           </prop>
+          <prop oor:name="ImportFloatingTableAsSplitFly" oor:type="xs:boolean" 
oor:nillable="false">
+            <info>
+              <desc>Specifies whether a floating table should be imported as a 
split text frame.</desc>
+              <label>Import floating table as split frame.</label>
+            </info>
+            <value>false</value>
+          </prop>
         </group>
       </group>
     </group>
diff --git a/sw/CppunitTest_sw_core_layout.mk b/sw/CppunitTest_sw_core_layout.mk
index 9a7a4710dfb7..1a7aeb649887 100644
--- a/sw/CppunitTest_sw_core_layout.mk
+++ b/sw/CppunitTest_sw_core_layout.mk
@@ -14,6 +14,7 @@ $(eval $(call gb_CppunitTest_CppunitTest,sw_core_layout))
 $(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_core_layout))
 
 $(eval $(call gb_CppunitTest_add_exception_objects,sw_core_layout, \
+    sw/qa/core/layout/flycnt \
     sw/qa/core/layout/layout \
 ))
 
diff --git a/sw/CppunitTest_sw_core_layout_flycnt.mk 
b/sw/CppunitTest_sw_core_layout_flycnt.mk
deleted file mode 100644
index c9668afbc9b8..000000000000
--- a/sw/CppunitTest_sw_core_layout_flycnt.mk
+++ /dev/null
@@ -1,82 +0,0 @@
-# -*- Mode: makefile-gmake; tab-width: 4; indent-tabs-mode: t -*-
-#*************************************************************************
-#
-# This file is part of the LibreOffice project.
-#
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-#
-#*************************************************************************
-
-$(eval $(call gb_CppunitTest_CppunitTest,sw_core_layout_flycnt))
-
-$(eval $(call 
gb_CppunitTest_use_common_precompiled_header,sw_core_layout_flycnt))
-
-# TODO merge this with sw_core_layout once SwFormatFlySplit::SetForce() is 
gone.
-$(eval $(call gb_CppunitTest_add_exception_objects,sw_core_layout_flycnt, \
-    sw/qa/core/layout/flycnt \
-))
-
-$(eval $(call gb_CppunitTest_use_libraries,sw_core_layout_flycnt, \
-    editeng \
-    comphelper \
-    cppu \
-    cppuhelper \
-    sal \
-    sfx \
-    subsequenttest \
-    sw \
-       swqahelper \
-    test \
-    unotest \
-    utl \
-    vcl \
-    svt \
-    tl \
-    svl \
-    svxcore \
-))
-
-$(eval $(call gb_CppunitTest_use_externals,sw_core_layout_flycnt,\
-    boost_headers \
-    libxml2 \
-))
-
-$(eval $(call gb_CppunitTest_set_include,sw_core_layout_flycnt,\
-    -I$(SRCDIR)/sw/inc \
-    -I$(SRCDIR)/sw/source/core/inc \
-    -I$(SRCDIR)/sw/source/uibase/inc \
-    -I$(SRCDIR)/sw/qa/inc \
-    $$(INCLUDE) \
-))
-
-$(eval $(call gb_CppunitTest_use_api,sw_core_layout_flycnt,\
-       udkapi \
-       offapi \
-       oovbaapi \
-))
-
-$(eval $(call gb_CppunitTest_use_ure,sw_core_layout_flycnt))
-$(eval $(call gb_CppunitTest_use_vcl,sw_core_layout_flycnt))
-
-$(eval $(call gb_CppunitTest_use_rdb,sw_core_layout_flycnt,services))
-
-$(eval $(call gb_CppunitTest_use_custom_headers,sw_core_layout_flycnt,\
-    officecfg/registry \
-))
-
-$(eval $(call gb_CppunitTest_use_configuration,sw_core_layout_flycnt))
-
-$(eval $(call gb_CppunitTest_use_uiconfigs,sw_core_layout_flycnt, \
-    modules/swriter \
-    svt \
-    svx \
-))
-
-# assert if font/glyph fallback occurs
-$(eval $(call 
gb_CppunitTest_set_non_application_font_use,sw_core_layout_flycnt,abort))
-
-$(eval $(call gb_CppunitTest_use_more_fonts,sw_core_layout_flycnt))
-
-# vim: set noet sw=4 ts=4:
diff --git a/sw/Module_sw.mk b/sw/Module_sw.mk
index f875935dac9e..44d5bc4e8d22 100644
--- a/sw/Module_sw.mk
+++ b/sw/Module_sw.mk
@@ -138,7 +138,6 @@ $(eval $(call gb_Module_add_slowcheck_targets,sw,\
     CppunitTest_sw_uibase_wrtsh \
     CppunitTest_sw_core_accessibilitycheck \
     CppunitTest_sw_core_layout \
-    CppunitTest_sw_core_layout_flycnt \
     CppunitTest_sw_core_fields \
     CppunitTest_sw_core_tox \
     CppunitTest_sw_core_frmedt \
diff --git a/sw/inc/formatflysplit.hxx b/sw/inc/formatflysplit.hxx
index 1db9587752b6..5f7dda675ed2 100644
--- a/sw/inc/formatflysplit.hxx
+++ b/sw/inc/formatflysplit.hxx
@@ -34,10 +34,6 @@ public:
     SwFormatFlySplit* Clone(SfxItemPool* pPool = nullptr) const override;
 
     void dumpAsXml(xmlTextWriterPtr pWriter) const override;
-
-    // Force-enable for test purposes.
-    static void SetForce(bool bForce);
-    static bool GetForce();
 };
 
 inline const SwFormatFlySplit& SwAttrSet::GetFlySplit(bool bInP) const
diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx
index f305c19ec5c1..a41fb17ef54d 100644
--- a/sw/qa/core/layout/flycnt.cxx
+++ b/sw/qa/core/layout/flycnt.cxx
@@ -9,7 +9,9 @@
 
 #include <swmodeltestbase.hxx>
 
+#include <comphelper/configuration.hxx>
 #include <comphelper/scopeguard.hxx>
+#include <officecfg/Office/Writer.hxx>
 
 #include <IDocumentLayoutAccess.hxx>
 #include <anchoredobject.hxx>
@@ -36,8 +38,16 @@ public:
 CPPUNIT_TEST_FIXTURE(Test, testSplitFlyWithTable)
 {
     // Given a document with a multi-page floating table:
-    SwFormatFlySplit::SetForce(true);
-    comphelper::ScopeGuard g([] { SwFormatFlySplit::SetForce(false); });
+    std::shared_ptr<comphelper::ConfigurationChanges> pChanges(
+        comphelper::ConfigurationChanges::create());
+    
officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::set(true,
+                                                                               
         pChanges);
+    pChanges->commit();
+    comphelper::ScopeGuard g([pChanges] {
+        
officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::set(
+            false, pChanges);
+        pChanges->commit();
+    });
     createSwDoc("floattable.docx");
 
     // When laying out that document:
@@ -86,8 +96,16 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyWithTable)
 CPPUNIT_TEST_FIXTURE(Test, testSplitFlyVertoffset)
 {
     // Given a document with a floattable, split on 2 pages and a positive 
vertical offset:
-    SwFormatFlySplit::SetForce(true);
-    comphelper::ScopeGuard g([] { SwFormatFlySplit::SetForce(false); });
+    std::shared_ptr<comphelper::ConfigurationChanges> pChanges(
+        comphelper::ConfigurationChanges::create());
+    
officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::set(true,
+                                                                               
         pChanges);
+    pChanges->commit();
+    comphelper::ScopeGuard g([pChanges] {
+        
officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::set(
+            false, pChanges);
+        pChanges->commit();
+    });
     createSwDoc("floattable-vertoffset.docx");
 
     // When laying out that document:
@@ -129,6 +147,4 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyVertoffset)
 }
 }
 
-CPPUNIT_PLUGIN_IMPLEMENT();
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/attr/formatflysplit.cxx 
b/sw/source/core/attr/formatflysplit.cxx
index 7bc8a75594d7..6bcfd74390e1 100644
--- a/sw/source/core/attr/formatflysplit.cxx
+++ b/sw/source/core/attr/formatflysplit.cxx
@@ -21,8 +21,6 @@
 
 #include <libxml/xmlwriter.h>
 
-static std::optional<bool> g_oForce;
-
 SwFormatFlySplit::SwFormatFlySplit(bool bSplit)
     : SfxBoolItem(RES_FLY_SPLIT, bSplit)
 {
@@ -31,17 +29,19 @@ SwFormatFlySplit::SwFormatFlySplit(bool bSplit)
     //
     // The layout representation is the following:
     //
-    // - We assume that the anchor type is at-para for such fly frames, and 
SwFlyAtContentFrame
-    // derives from SwFlowFrame to be able to split in general.
+    // - We assume that the anchor type is at-para for such fly frames.
+    //
+    // - We also assume that AutoSize is true for such fly frames.
+    //
+    // - SwFlyAtContentFrame derives from SwFlowFrame to be able to split in 
general.
     //
     // - Both the master fly and the follow flys need an anchor. At the same 
time, we want all text
     // of the anchor frame to be wrapped around the last follow fly frame, for 
Word compatibility.
     // These are solved by splitting the anchor frame as many times as needed, 
always at
     // TextFrameIndex 0.
-    if (SwFormatFlySplit::GetForce())
-    {
-        SetValue(true);
-    }
+    //
+    // - The vertical offset is only considered on the master fly, all the 
follow flys ignore it, so
+    // they start at the top of a next page.
 }
 
 SwFormatFlySplit* SwFormatFlySplit::Clone(SfxItemPool*) const
@@ -59,16 +59,4 @@ void SwFormatFlySplit::dumpAsXml(xmlTextWriterPtr pWriter) 
const
     (void)xmlTextWriterEndElement(pWriter);
 }
 
-void SwFormatFlySplit::SetForce(bool bForce) { g_oForce = bForce; }
-
-bool SwFormatFlySplit::GetForce()
-{
-    if (g_oForce.has_value())
-    {
-        return *g_oForce;
-    }
-
-    return getenv("SW_FORCE_FLY_SPLIT") != nullptr;
-}
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/unocore/unoframe.cxx 
b/sw/source/core/unocore/unoframe.cxx
index cf1c9575c987..0f26e0463cd3 100644
--- a/sw/source/core/unocore/unoframe.cxx
+++ b/sw/source/core/unocore/unoframe.cxx
@@ -134,6 +134,7 @@
 #include <svx/xfltrit.hxx>
 #include <swunohelper.hxx>
 #include <fefly.hxx>
+#include <formatflysplit.hxx>
 
 using namespace ::com::sun::star;
 
@@ -959,6 +960,15 @@ bool 
BaseFrameProperties_Impl::FillBaseProperties(SfxItemSet& rToSet, const SfxI
         rToSet.Put(item);
     }
 
+    const ::uno::Any* pFlySplit = nullptr;
+    GetProperty(RES_FLY_SPLIT, 0, pFlySplit);
+    if (pFlySplit)
+    {
+        SwFormatFlySplit aSplit(true);
+        bRet &= aSplit.PutValue(*pFlySplit, 0);
+        rToSet.Put(aSplit);
+    }
+
     return bRet;
 }
 
diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx 
b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
index 042cc142c71d..df4e3fb5424e 100644
--- a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
+++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
@@ -51,6 +51,7 @@
 #include <comphelper/propertyvalue.hxx>
 #include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
 #include <boost/lexical_cast.hpp>
+#include <officecfg/Office/Writer.hxx>
 
 #ifdef DBG_UTIL
 #include "PropertyMapHelper.hxx"
@@ -1565,6 +1566,16 @@ void DomainMapperTableHandler::endTable(unsigned int 
nestedTableLevel, bool bTab
                     comphelper::makePropertyValue("IsFollowingTextFlow", 
true));
             }
 
+            bool bSplitAllowed = 
officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::get();
+            if (!bSplitAllowed)
+            {
+                bSplitAllowed = getenv("SW_FORCE_FLY_SPLIT") != nullptr;
+            }
+            if (bSplitAllowed)
+            {
+                
aFrameProperties.push_back(comphelper::makePropertyValue("IsSplitAllowed", 
true));
+            }
+
             // In case the document ends with a table, we're called after
             // SectionPropertyMap::CloseSectionGroup(), so we'll have no idea
             // about the text area width, nor can fix this by delaying the text
commit c652886b1be32cfe7d247d124ff91ada8735eea6
Author:     Miklos Vajna <[email protected]>
AuthorDate: Thu Feb 16 08:49:47 2023 +0100
Commit:     Miklos Vajna <[email protected]>
CommitDate: Thu Mar 2 09:13:48 2023 +0100

    sw floattable: limit vertical position for the follows of split flys
    
    The bugdoc has 2 pages and the 2nd page had a fly frame with an
    unexpected vertical shift towards the bottom.
    
    The problem is that the floattable has a vertical offset defined, but
    Word only handles that on the first page of the split table, not on
    later pages. This makes sense: we split the table to multiple pages so
    that the content fits, an additional offset on follow pages would result
    in a lot of additional pages.
    
    Fix the problem by adjusting
    SwToContentAnchoredObjectPosition::CalcPosition(), so that the vertical
    offset is only applied on master flys, not on follow flys.
    
    This implicitly means that the behavior is unchanged for non-split flys,
    since those always have a first page, which is nicely consistent.
    
    (cherry picked from commit 2f0b16a6a9bfff1646b14412e5918b6d483b9cdc)
    
    Change-Id: I8c86cd2df6868cc5c1a10dfec359f3e02f5c1102

diff --git a/sw/qa/core/layout/data/floattable-vertoffset.docx 
b/sw/qa/core/layout/data/floattable-vertoffset.docx
new file mode 100644
index 000000000000..d71a587f9c1e
Binary files /dev/null and b/sw/qa/core/layout/data/floattable-vertoffset.docx 
differ
diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx
index 2f1e1e54deac..f305c19ec5c1 100644
--- a/sw/qa/core/layout/flycnt.cxx
+++ b/sw/qa/core/layout/flycnt.cxx
@@ -82,6 +82,51 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyWithTable)
     // This failed, page 1 anchor had unexpected, leftover text.
     CPPUNIT_ASSERT(!pPage1Anchor->HasPara());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testSplitFlyVertoffset)
+{
+    // Given a document with a floattable, split on 2 pages and a positive 
vertical offset:
+    SwFormatFlySplit::SetForce(true);
+    comphelper::ScopeGuard g([] { SwFormatFlySplit::SetForce(false); });
+    createSwDoc("floattable-vertoffset.docx");
+
+    // When laying out that document:
+    calcLayout();
+
+    // Then make sure that the vert offset has an effect on the master fly, 
but not on follow flys:
+    SwDoc* pDoc = getSwDoc();
+    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+    auto pPage1 = dynamic_cast<SwPageFrame*>(pLayout->Lower());
+    CPPUNIT_ASSERT(pPage1);
+    const SwSortedObjs& rPage1Objs = *pPage1->GetSortedObjs();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage1Objs.size());
+    auto pPage1Fly = dynamic_cast<SwFlyAtContentFrame*>(rPage1Objs[0]);
+    CPPUNIT_ASSERT(pPage1Fly);
+    auto pPage1Anchor = 
dynamic_cast<SwTextFrame*>(pPage1->FindLastBodyContent());
+    CPPUNIT_ASSERT(pPage1Anchor);
+    SwTwips nPage1AnchorTop = pPage1Anchor->getFrameArea().Top();
+    SwTwips nPage1FlyTop = pPage1Fly->getFrameArea().Top();
+    // First page, the vert offset should be there. This comes from 
word/document.xml:
+    // <w:tblpPr ... w:tblpY="1135"/>
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(1135), nPage1FlyTop - 
nPage1AnchorTop);
+
+    // Also verify that the 2nd page has no such offset:
+    auto pPage2 = dynamic_cast<SwPageFrame*>(pPage1->GetNext());
+    CPPUNIT_ASSERT(pPage2);
+    const SwSortedObjs& rPage2Objs = *pPage2->GetSortedObjs();
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage2Objs.size());
+    auto pPage2Fly = dynamic_cast<SwFlyAtContentFrame*>(rPage2Objs[0]);
+    CPPUNIT_ASSERT(pPage2Fly);
+    auto pPage2Anchor = 
dynamic_cast<SwTextFrame*>(pPage2->FindLastBodyContent());
+    CPPUNIT_ASSERT(pPage2Anchor);
+    SwTwips nPage2AnchorTop = pPage2Anchor->getFrameArea().Top();
+    SwTwips nPage2FlyTop = pPage2Fly->getFrameArea().Top();
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 0
+    // - Actual  : 1135
+    // i.e. the fly frame on the 2nd page was also shifted down in Writer, but 
not in Word.
+    CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(0), nPage2FlyTop - 
nPage2AnchorTop);
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx 
b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
index 7a9dd8546a3a..1a58d3a650dd 100644
--- a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
+++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx
@@ -190,6 +190,9 @@ void SwToContentAnchoredObjectPosition::CalcPosition()
     // determine frame the object position has to be oriented at.
     const SwTextFrame* pOrientFrame = &rAnchorTextFrame;
     const SwTextFrame* pAnchorFrameForVertPos;
+    // If true, this means that the anchored object is a split fly frame and 
it's not a master but
+    // one of the follows.
+    bool bFollowSplitFly = false;
     {
         // if object is at-character anchored, determine character-rectangle
         // and frame, position has to be oriented at.
@@ -239,6 +242,8 @@ void SwToContentAnchoredObjectPosition::CalcPosition()
                     if (pFollow)
                     {
                         pOrientFrame = pFollow;
+                        // Anchored object has a precede, so it's a follow.
+                        bFollowSplitFly = true;
                     }
                 }
             }
@@ -588,6 +593,12 @@ void SwToContentAnchoredObjectPosition::CalcPosition()
                     nVertOffsetToFrameAnchorPos += 
aRectFnSet.YDiff(nPageBottom, nTopOfOrient);
                 }
                 nRelPosY = nVertOffsetToFrameAnchorPos + aVert.GetPos();
+                if (bFollowSplitFly)
+                {
+                    // This is a follow of a split fly: shift it up to match 
the anchor position,
+                    // because the vertical offset is meant to be handled only 
on the first page.
+                    nRelPosY -= aVert.GetPos();
+                }
             }
 
             // <pUpperOfOrientFrame>: layout frame, at which the position has 
to
commit 09f6cd19a8f1a073d002e2835c67ea4f4739bf83
Author:     Miklos Vajna <[email protected]>
AuthorDate: Wed Feb 15 08:28:27 2023 +0100
Commit:     Miklos Vajna <[email protected]>
CommitDate: Thu Mar 2 09:11:44 2023 +0100

    DOCX filter: fix horizontal pos of floattables with compat mode >= 15
    
    The floating table in the bugdoc has a small negative horizontal indent,
    which carefully aligns it so that the contained paragraph lines up with
    the text above the table.
    
    It turns out that compatibilityMode >= 15 doesn't do this anymore in
    Word, so we should at least avoid this tweak on import/export when we
    know the compat mode.
    
    Fix the problem by avoiding the <w:tblpPr w:tblpX="..."> decrease during
    import and the matching increase on export. This is similar to what
    commit 9a31d1c83e08600507689dc18f6f0973bc7e4389 (tdf#106742: OOXML
    import/export: treat "tblInd" properly., 2017-04-04) did for
    non-floating tables.
    
    I discovered this while working on multi-page sw floattables, but this
    is relevant for single-page sw floattables as well. Next to the modified
    testcase, sw/qa/core/layout/data/floattable.docx is also a good test
    file, which shows how the left border now lines up with the body frame,
    and there used to be a noticeable gap there. Now
    sw/qa/core/layout/data/floattable.docx gets rendered ~perfectly (with
    SW_FORCE_FLY_SPLIT=1).
    
    (cherry picked from commit 7fb8b73ad320e32af130ceddec80a9ff08407eab)
    
    Change-Id: Ia52202f1bc3274f4ce2b7ee02c85d07589454ae9

diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
index 43c4c926ae50..5b5001878eb1 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport.cxx
@@ -31,6 +31,7 @@
 #include <comphelper/sequenceashashmap.hxx>
 #include <comphelper/processfactory.hxx>
 #include <tools/UnitConversion.hxx>
+#include <frameformats.hxx>
 
 class Test : public SwModelTestBase
 {
@@ -1105,7 +1106,18 @@ DECLARE_OOXMLEXPORT_TEST(testTdf106953, "tdf106953.docx")
 
 CPPUNIT_TEST_FIXTURE(Test, testTdf115094v3)
 {
-    loadAndSave("tdf115094v3.docx");
+    createSwDoc("tdf115094v3.docx");
+    {
+        SwDoc* pDoc = getSwDoc();
+        SwFrameFormats& rSpzFormats = *pDoc->GetSpzFrameFormats();
+        SwFrameFormat* pFormat = rSpzFormats[0];
+        // Without the fix, this has failed with:
+        // - Expected: 1991
+        // - Actual  : 1883
+        // i.e. some unwanted ~-2mm left margin appeared.
+        CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(1991), 
pFormat->GetHoriOrient().GetPos());
+    }
+    save(OUString::createFromAscii(mpFilter));
     // floating table is now exported directly without surrounding frame
     xmlDocUniquePtr pXmlDoc = parseExport("word/document.xml");
 
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 27eb7d959c3c..11a35b8bd55e 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -4764,8 +4764,12 @@ void DocxAttributeOutput::TableDefinition( 
ww8::WW8TableNodeInfoInner::Pointer_t
                     const SwTableBox * pTabBox = 
pTableTextNodeInfoInner->getTableBox();
                     const SwFrameFormat * pFrameFormat = 
pTabBox->GetFrameFormat();
                     const SvxBoxItem& rBox = pFrameFormat->GetBox( );
-                    sal_uInt16 nLeftDistance = 
rBox.GetDistance(SvxBoxItemLine::LEFT);
-                    nValue += nLeftDistance;
+                    sal_Int32 nMode = lcl_getWordCompatibilityMode(m_rExport);
+                    if (nMode < 15)
+                    {
+                        sal_uInt16 nLeftDistance = 
rBox.GetDistance(SvxBoxItemLine::LEFT);
+                        nValue += nLeftDistance;
+                    }
 
                     // 2nd: if a left border is given, revert the shift by 
half the width
                     // from lcl_DecrementHoriOrientPosition() in writerfilter
diff --git a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx 
b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
index 58d96a9cd8f5..042cc142c71d 100644
--- a/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
+++ b/writerfilter/source/dmapper/DomainMapperTableHandler.cxx
@@ -536,7 +536,8 @@ TableStyleSheetEntry * 
DomainMapperTableHandler::endTableGetTableStyle(TableInfo
 
         m_aTableProperties->Insert( PROP_TABLE_BORDER_DISTANCES, uno::Any( 
aDistances ) );
 
-        if (!rFrameProperties.empty())
+        sal_Int32 nMode = 
m_rDMapper_Impl.GetSettingsTable()->GetWordCompatibilityMode();
+        if (!rFrameProperties.empty() && nMode < 15)
             lcl_DecrementHoriOrientPosition(rFrameProperties, 
rInfo.nLeftBorderDistance);
 
         // Set table above/bottom spacing to 0.
@@ -613,7 +614,6 @@ TableStyleSheetEntry * 
DomainMapperTableHandler::endTableGetTableStyle(TableInfo
 
         // tdf#106742: since MS Word 2013 (compatibilityMode >= 15), top-level 
tables are handled the same as nested tables;
         // the default behavior when DOCX doesn't define "compatibilityMode" 
option is to add the cell spacing
-        sal_Int32 nMode = 
m_rDMapper_Impl.GetSettingsTable()->GetWordCompatibilityMode();
 
         if (0 < nMode && nMode <= 14 && rInfo.nNestLevel == 1)
         {
commit f823b3a0c004129450fa2e39fd8241362e4ea6a0
Author:     Miklos Vajna <[email protected]>
AuthorDate: Tue Feb 14 08:12:40 2023 +0100
Commit:     Miklos Vajna <[email protected]>
CommitDate: Thu Mar 2 09:08:53 2023 +0100

    sw floattable: improve handling of split flys in SwTextFrame::FormatEmpty()
    
    The bugdoc had a non-empty paragraph after the floating table, we
    painted that text on both page 1 and page 2, while only page 2 is
    expected.
    
    We want that paragraph to be on both pages, but we want to split it
    before the first char, so apart from providing a place to serve as an
    anchor, it should be invisible on page 1.
    
    Fix the problem by extending SwTextFrame::FormatEmpty() to consider the
    master anchor text frame as empty in case it has no text, just
    intersects with a fly frame.
    
    Also improve SwTextFrame::HasNonLastSplitFlyDrawObj() a bit, so it
    returns early when the own and the follow offset is not the same. These
    are cheap checks and some callers already did it before iterating over
    all the draw objects of the text frame, but other callers didn't do
    this. Now we check for this consistently, everywhere.
    
    (cherry picked from commit 1cf13b8b11e7c122631394e308b66b46ffaae718)
    
    Change-Id: I4b399ae3f9e9f364c61d977359f6c9b16c648629

diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx
index a006ecb54f00..2f1e1e54deac 100644
--- a/sw/qa/core/layout/flycnt.cxx
+++ b/sw/qa/core/layout/flycnt.cxx
@@ -19,6 +19,7 @@
 #include <rootfrm.hxx>
 #include <sortedobjs.hxx>
 #include <tabfrm.hxx>
+#include <txtfrm.hxx>
 
 namespace
 {
@@ -75,6 +76,11 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyWithTable)
     CPPUNIT_ASSERT(pPage2Table);
     CPPUNIT_ASSERT(pPage2Table->GetPrecede());
     CPPUNIT_ASSERT(!pPage2Table->GetFollow());
+    // Page 1 anchor has no text:
+    auto pPage1Anchor = 
dynamic_cast<SwTextFrame*>(pPage1->FindLastBodyContent());
+    CPPUNIT_ASSERT(pPage1Anchor);
+    // This failed, page 1 anchor had unexpected, leftover text.
+    CPPUNIT_ASSERT(!pPage1Anchor->HasPara());
 }
 }
 
diff --git a/sw/source/core/inc/cntfrm.hxx b/sw/source/core/inc/cntfrm.hxx
index b972a7aaafd8..2f6c8b5ba3e4 100644
--- a/sw/source/core/inc/cntfrm.hxx
+++ b/sw/source/core/inc/cntfrm.hxx
@@ -20,6 +20,7 @@
 #ifndef INCLUDED_SW_SOURCE_CORE_INC_CNTFRM_HXX
 #define INCLUDED_SW_SOURCE_CORE_INC_CNTFRM_HXX
 
+#include <swdllapi.h>
 #include "frame.hxx"
 #include "flowfrm.hxx"
 #include <cshtyp.hxx>
@@ -54,7 +55,7 @@ namespace o3tl {
  * SwContentFrame is the layout for content nodes: a common base class for 
text (paragraph) and
  * non-text (e.g. graphic) frames.
  */
-class SAL_DLLPUBLIC_RTTI SwContentFrame: public SwFrame, public SwFlowFrame
+class SW_DLLPUBLIC SwContentFrame: public SwFrame, public SwFlowFrame
 {
     friend void MakeNxt( SwFrame *pFrame, SwFrame *pNxt );    // calls 
MakePrtArea
 
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx
index 1975840aa1d3..13ca7f71494c 100644
--- a/sw/source/core/text/frmform.cxx
+++ b/sw/source/core/text/frmform.cxx
@@ -1846,14 +1846,10 @@ void SwTextFrame::Format( vcl::RenderContext* 
pRenderContext, const SwBorderAttr
 
     TextFrameIndex nStrLen(GetText().getLength());
 
-    SwTextFrame* pFollow = GetFollow();
-    if (pFollow && pFollow->GetOffset() == mnOffset)
+    if (HasNonLastSplitFlyDrawObj())
     {
-        if (HasNonLastSplitFlyDrawObj())
-        {
-            // Non-last part of split fly anchor: consider this empty.
-            nStrLen = TextFrameIndex(0);
-        }
+        // Non-last part of split fly anchor: consider this empty.
+        nStrLen = TextFrameIndex(0);
     }
 
     if ( nStrLen || !FormatEmpty() )
diff --git a/sw/source/core/text/itratr.cxx b/sw/source/core/text/itratr.cxx
index eb643f2a1264..995481ceb97e 100644
--- a/sw/source/core/text/itratr.cxx
+++ b/sw/source/core/text/itratr.cxx
@@ -1482,6 +1482,20 @@ std::vector<SwFlyAtContentFrame*> 
SwTextFrame::GetSplitFlyDrawObjs() const
 
 bool SwTextFrame::HasNonLastSplitFlyDrawObj() const
 {
+    const SwTextFrame* pFollow = GetFollow();
+    if (!pFollow)
+    {
+        return false;
+    }
+
+    if (mnOffset != pFollow->GetOffset())
+    {
+        return false;
+    }
+
+    // At this point we know what we're part of a chain that is an anchor for 
split fly frames, but
+    // we're not the last one. See if we have a matching fly.
+
     for (const auto& pFly : GetSplitFlyDrawObjs())
     {
         if (pFly->GetFollow())
diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx
index eb128eaa662e..90f4d763578d 100644
--- a/sw/source/core/text/porrst.cxx
+++ b/sw/source/core/text/porrst.cxx
@@ -412,7 +412,8 @@ bool SwTextFrame::FormatEmpty()
     // sw_redlinehide: just disable FormatEmpty optimisation for now
     // Split fly frames: non-last parts of the anchor want this optimization 
to clear the old
     // content.
-    if ((HasFollow() && mnOffset != GetFollow()->GetOffset()) || 
GetMergedPara() || GetTextNodeFirst()->GetpSwpHints() ||
+    bool bHasNonLastSplitFlyDrawObj = HasNonLastSplitFlyDrawObj();
+    if ((HasFollow() && !bHasNonLastSplitFlyDrawObj) || GetMergedPara() || 
GetTextNodeFirst()->GetpSwpHints() ||
         nullptr != GetTextNodeForParaProps()->GetNumRule() ||
         GetTextNodeFirst()->HasHiddenCharAttribute(true) ||
          IsInFootnote() || ( HasPara() && GetPara()->IsPrepMustFit() ) )
@@ -433,7 +434,7 @@ bool SwTextFrame::FormatEmpty()
     SwRect aRect;
     bool bFirstFlyCheck = 0 != getFramePrintArea().Height();
     if ( !bCollapse && bFirstFlyCheck &&
-            aTextFly.IsOn() && aTextFly.IsAnyObj( aRect ) )
+            aTextFly.IsOn() && aTextFly.IsAnyObj( aRect ) && 
!bHasNonLastSplitFlyDrawObj )
         return false;
 
     // only need to check one node because of early return on GetMerged()

Reply via email to