sw/qa/core/layout/data/floattable-wrap-on-all-pages.docx |binary
 sw/qa/core/layout/flycnt.cxx                             |   39 +++++++++++++++
 sw/source/core/inc/flyfrms.hxx                           |    1 
 sw/source/core/layout/flycnt.cxx                         |   18 ++++++
 sw/source/core/text/frmform.cxx                          |    5 +
 sw/source/core/text/porrst.cxx                           |    7 ++
 6 files changed, 68 insertions(+), 2 deletions(-)

New commits:
commit 7d7ca347fafa7a06094b00e8fb0d0452c4c81366
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Oct 13 08:48:43 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri Oct 13 10:25:26 2023 +0200

    sw floattable, wrap on all pages: add layout
    
    The anchor text of a floating table is normally wrapped around the table
    only on the last page of the table. This compat flag requests to wrap on
    all pages instead.
    
    First, disable the SwTextFrame::FormatEmpty() optimization in this case,
    so not only the last page has portions inside the text frame.
    
    Second, improve SwTextFrame::FormatAdjust(), so that anchor content from
    the last page can flow to previous pages.
    
    Note that having a dedicated SwFlyAtContentFrame::IsWrapOnAllPages()
    means that later it'll be possible to do per-frame decision on this if
    there is demand for that (this came up on the mailing list, but it's not
    something Word would support).
    
    Change-Id: I75df539df859aaa6c7eaaeddb33f004639b1c004
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157902
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/qa/core/layout/data/floattable-wrap-on-all-pages.docx 
b/sw/qa/core/layout/data/floattable-wrap-on-all-pages.docx
new file mode 100644
index 000000000000..39642002bbed
Binary files /dev/null and 
b/sw/qa/core/layout/data/floattable-wrap-on-all-pages.docx differ
diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx
index 325b0078ecb0..16cd9cda4a57 100644
--- a/sw/qa/core/layout/flycnt.cxx
+++ b/sw/qa/core/layout/flycnt.cxx
@@ -30,6 +30,7 @@
 #include <cellfrm.hxx>
 #include <ndtxt.hxx>
 #include <dflyobj.hxx>
+#include <IDocumentSettingAccess.hxx>
 
 namespace
 {
@@ -1183,6 +1184,44 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyInTableInSection)
     SwSortedObjs& rPage3Objs = *pPage3->GetSortedObjs();
     CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage3Objs.size());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testSplitFlyWrapOnAllPages)
+{
+    // Given a document where we want to wrap on all pages, around a split 
floating table:
+    createSwDoc("floattable-wrap-on-all-pages.docx");
+    SwDoc* pDoc = getSwDoc();
+    
pDoc->getIDocumentSettingAccess().set(DocumentSettingId::ALLOW_TEXT_AFTER_FLOATING_TABLE_BREAK,
+                                          true);
+
+    // When formatting that document:
+    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+    pWrtShell->Reformat();
+
+    // Then make sure that the anchor text is also split between page 1 and 
page 2:
+    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+    pLayout->dumpAsXml();
+    auto pPage1 = pLayout->Lower()->DynCastPageFrame();
+    CPPUNIT_ASSERT(pPage1);
+    auto pPage1Anchor = pPage1->FindLastBodyContent()->DynCastTextFrame();
+    CPPUNIT_ASSERT(pPage1Anchor);
+    OUString aAnchor1Text(pPage1Anchor->GetText().subView(
+        static_cast<sal_Int32>(pPage1Anchor->GetOffset()),
+        static_cast<sal_Int32>(pPage1Anchor->GetFollow()->GetOffset()
+                               - pPage1Anchor->GetOffset())));
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: He heard quiet steps behind him. That
+    // - Actual  :
+    // i.e. the first page had no anchor text, only the second.
+    CPPUNIT_ASSERT_EQUAL(OUString("He heard quiet steps behind him. That "), 
aAnchor1Text);
+    auto pPage2 = pPage1->GetNext()->DynCastPageFrame();
+    CPPUNIT_ASSERT(pPage2);
+    auto pPage2Anchor = pPage2->FindLastBodyContent()->DynCastTextFrame();
+    CPPUNIT_ASSERT(pPage2Anchor);
+    OUString aAnchor2Text(
+        
pPage2Anchor->GetText().subView(static_cast<sal_Int32>(pPage2Anchor->GetOffset())));
+    CPPUNIT_ASSERT(!pPage2Anchor->GetFollow());
+    CPPUNIT_ASSERT_EQUAL(OUString("didn't bode well."), aAnchor2Text);
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/flyfrms.hxx b/sw/source/core/inc/flyfrms.hxx
index fd4fff11b1d5..051d514fd31e 100644
--- a/sw/source/core/inc/flyfrms.hxx
+++ b/sw/source/core/inc/flyfrms.hxx
@@ -202,6 +202,7 @@ public:
     SwFlyAtContentFrame* GetPrecede();
     /// Like Cut(), except that follow chaining is maintained.
     void DelEmpty();
+    bool IsWrapOnAllPages() const;
     void dumpAsXmlAttributes(xmlTextWriterPtr pWriter) const override;
 };
 
diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx
index 98843c2c0d47..c07201f49f43 100644
--- a/sw/source/core/layout/flycnt.cxx
+++ b/sw/source/core/layout/flycnt.cxx
@@ -1784,6 +1784,24 @@ void SwFlyAtContentFrame::DelEmpty()
     }
 }
 
+bool SwFlyAtContentFrame::IsWrapOnAllPages() const
+{
+    const SwRootFrame* pRootFrame = getRootFrame();
+    if (!pRootFrame)
+    {
+        return false;
+    }
+
+    const SwFrameFormat* pFormat = pRootFrame->GetFormat();
+    if (!pFormat)
+    {
+        return false;
+    }
+
+    const IDocumentSettingAccess& rIDSA = pFormat->getIDocumentSettingAccess();
+    return rIDSA.get(DocumentSettingId::ALLOW_TEXT_AFTER_FLOATING_TABLE_BREAK);
+}
+
 void SwFlyAtContentFrame::dumpAsXmlAttributes(xmlTextWriterPtr pWriter) const
 {
     SwFlyFreeFrame::dumpAsXmlAttributes(pWriter);
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx
index 1e20d7e0e9bc..76a1df56210a 100644
--- a/sw/source/core/text/frmform.cxx
+++ b/sw/source/core/text/frmform.cxx
@@ -1215,10 +1215,11 @@ void SwTextFrame::FormatAdjust( SwTextFormatter &rLine,
             }
             ChangeOffset( GetFollow(), nEnd );
 
-            if (HasNonLastSplitFlyDrawObj())
+            SwFlyAtContentFrame* pNonLastSplitFlyDrawObj = 
HasNonLastSplitFlyDrawObj();
+            if (pNonLastSplitFlyDrawObj && 
!pNonLastSplitFlyDrawObj->IsWrapOnAllPages())
             {
                 // Make sure content from the last floating table anchor is 
not shifted to previous
-                // anchors.
+                // anchors, unless we're in the special "wrap on all pages" 
mode.
                 nEnd = TextFrameIndex(0);
             }
 
diff --git a/sw/source/core/text/porrst.cxx b/sw/source/core/text/porrst.cxx
index bd3589b25676..029adca75336 100644
--- a/sw/source/core/text/porrst.cxx
+++ b/sw/source/core/text/porrst.cxx
@@ -416,6 +416,13 @@ bool SwTextFrame::FormatEmpty()
     // content.
     SwFlyAtContentFrame* pNonLastSplitFlyDrawObj = HasNonLastSplitFlyDrawObj();
     bool bHasNonLastSplitFlyDrawObj = pNonLastSplitFlyDrawObj != nullptr;
+
+    if (pNonLastSplitFlyDrawObj && pNonLastSplitFlyDrawObj->IsWrapOnAllPages())
+    {
+        // Split fly: the anchor is non-empty on all pages in the "wrap on all 
pages" case.
+        bHasNonLastSplitFlyDrawObj = false;
+    }
+
     if ((HasFollow() && !bHasNonLastSplitFlyDrawObj) || GetMergedPara() || 
(GetTextNodeFirst()->GetpSwpHints() && !bHasNonLastSplitFlyDrawObj) ||
         nullptr != GetTextNodeForParaProps()->GetNumRule() ||
         GetTextNodeFirst()->HasHiddenCharAttribute(true) ||

Reply via email to