sw/qa/core/layout/data/floattable-tab-join.docx |binary
 sw/qa/core/layout/flycnt.cxx                    |   30 ++++++++++++++++++++++++
 sw/source/core/layout/tabfrm.cxx                |   24 +++++++++++++++++++
 3 files changed, 54 insertions(+)

New commits:
commit 4cb6e54a3dcdd771ef76bd98b58f0bf1c4be4c45
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu May 18 13:55:08 2023 +0200
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Fri May 19 09:45:59 2023 +0200

    sw floattable: fix missing table join when moving master fly to next page
    
    A reduced bugdoc from tdf#155002 has 2 floating tables: one table on the
    first page, second table on the second page. The second page had 2 fly
    frames: the first row of the 2nd table in the first fly and the
    remaining rows from the 2nd table in the second fly, and they were not
    joined, which lead to overlapping text.
    
    It seems what happens is that the fly is split: first row goes to the
    first page, rest goes to the second page. Later we move the master fly
    to the 2nd page as well, but we don't try to join the table, since the
    master fly has no additional space. It's a circular problem: once we
    split the fly, we limit the master fly size to what's necessary, so once
    the 2 flys are on the same page, we don't move content from the follow
    fly to the master fly because we believe it has no space... but it has
    no space because the content is not moved.
    
    Solve this problem similar to what the web view already does: in case a
    table frame has a follow and the table frame is in a split fly that can
    grow to host at least one follow, then try to grow it to host all
    follows. This prevents layout loops, since we don't move content from a
    follow fly to a master fly when it would not fit anyway, but allows
    large enough master flys so table joining happens.
    
    The crash with the original tdf#155002 bugdoc needs more work, still.
    
    Change-Id: I411b21d796be82ab5600d66b600cb50c116db4e9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151956
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/qa/core/layout/data/floattable-tab-join.docx 
b/sw/qa/core/layout/data/floattable-tab-join.docx
new file mode 100644
index 000000000000..cb1990c2a8ea
Binary files /dev/null and b/sw/qa/core/layout/data/floattable-tab-join.docx 
differ
diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx
index 6f580c40a8c5..b35c5731d5ab 100644
--- a/sw/qa/core/layout/flycnt.cxx
+++ b/sw/qa/core/layout/flycnt.cxx
@@ -825,6 +825,36 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyMultiCol)
     // then hit an assertion failure.
     CPPUNIT_ASSERT(!pPage1Fly->GetFollow());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testSplitFlyTabJoin)
+{
+    // Given a document with 3 pages and 2 tables: table on first and second 
page, 3rd page has no
+    // table:
+    createSwDoc("floattable-tab-join.docx");
+
+    // When laying out that document:
+    calcLayout();
+
+    // Then make sure that all pages have the expected amount of fly frames:
+    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 pPage2 = dynamic_cast<SwPageFrame*>(pPage1->GetNext());
+    CPPUNIT_ASSERT(pPage2);
+    const SwSortedObjs& rPage2Objs = *pPage2->GetSortedObjs();
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 1
+    // - Actual  : 2
+    // i.e. the 2nd page had 2 fly frames, hosting a split table, instead of 
joining that table and
+    // having 1 fly frame.
+    CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage2Objs.size());
+    auto pPage3 = dynamic_cast<SwPageFrame*>(pPage2->GetNext());
+    CPPUNIT_ASSERT(pPage3);
+    CPPUNIT_ASSERT(!pPage3->GetSortedObjs());
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index c711f62ba67c..bcc46c521b85 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -2259,6 +2259,30 @@ void SwTabFrame::MakeAll(vcl::RenderContext* 
pRenderContext)
             }
         }
 
+        if (GetFollow() && GetUpper()->IsFlyFrame())
+        {
+            auto pUpper = static_cast<SwFlyFrame*>(GetUpper());
+            if (pUpper->IsFlySplitAllowed())
+            {
+                // We have a follow tab frame that may be joined, and we're 
directly in a split fly.
+                // See if the fly could grow.
+                SwTwips nTest = GetUpper()->Grow(LONG_MAX, /*bTst=*/true);
+                if (nTest >= aRectFnSet.GetHeight(GetFollow()->getFrameArea()))
+                {
+                    // We have space to to join at least one follow tab frame.
+                    SwTwips nRequest = 0;
+                    for (SwTabFrame* pFollow = GetFollow(); pFollow; pFollow = 
pFollow->GetFollow())
+                    {
+                        nRequest += 
aRectFnSet.GetHeight(pFollow->getFrameArea());
+                    }
+                    // Try to grow the split fly to join all follows.
+                    pUpper->Grow(nRequest);
+                    // Determine what is space we actually got from the 
requested space.
+                    nDistanceToUpperPrtBottom = 
aRectFnSet.BottomDist(getFrameArea(), aRectFnSet.GetPrtBottom(*pUpper));
+                }
+            }
+        }
+
         // If there is still some space left in the upper, we check if we
         // can join some rows of the follow.
         // Setting bLastRowHasToMoveToFollow to true means we want to force

Reply via email to