sw/qa/extras/layout/data/tdf152298.docx |binary
 sw/qa/extras/layout/layout3.cxx         |   23 ++++++++++
 sw/source/core/layout/tabfrm.cxx        |   67 +++++++++++++++++++++++++++-----
 3 files changed, 81 insertions(+), 9 deletions(-)

New commits:
commit 0a5fff7bb409db38088c79811f4280b9a41ee5e2
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Wed Sep 18 18:07:25 2024 +0500
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Sep 23 09:33:44 2024 +0200

    tdf#152298: Handle "keep with next, allow split, span some rows" case
    
    All the rows on the table in bugdoc require to be kept with next
    (their first cells' first paragraphs have that flag). The layout
    finds the table break position after row 39;  but then it checks
    that that row should be kept with row 38,  that with row 37, and
    so on.  The layout loop happens because the search for the break
    position can't find a row.
    
    But cell A38 spans over four rows;  in this case, Word checks if
    this row can split, and splits the spanning cells, apparently as
    keeping "part" of the row with next.
    
    This change implements that algorithm.
    
    Change-Id: I234694138ac6b660781ad773cef20151daf874eb
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173675
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Tested-by: Jenkins
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173706

diff --git a/sw/qa/extras/layout/data/tdf152298.docx 
b/sw/qa/extras/layout/data/tdf152298.docx
new file mode 100644
index 000000000000..22c3de81a038
Binary files /dev/null and b/sw/qa/extras/layout/data/tdf152298.docx differ
diff --git a/sw/qa/extras/layout/layout3.cxx b/sw/qa/extras/layout/layout3.cxx
index 45d5b91cfbe0..a1ccbb0385c3 100644
--- a/sw/qa/extras/layout/layout3.cxx
+++ b/sw/qa/extras/layout/layout3.cxx
@@ -3496,6 +3496,29 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, 
TestTdf152142DoNotMirrorRtlDrawObjs)
     CPPUNIT_ASSERT_LESS(nShapeEnd, nTextBoxEnd);
 }
 
+CPPUNIT_TEST_FIXTURE(SwLayoutWriter3, testTdf152298)
+{
+    createSwDoc("tdf152298.docx");
+    auto pDump = parseLayoutDump();
+
+    assertXPath(pDump, "//page"_ostr, 2);
+    // Without the fix, this was 39
+    assertXPath(pDump, "//page[1]/body/tab/row"_ostr, 38);
+    assertXPath(pDump, "//page[1]/body/tab/row[38]/cell[1]"_ostr, 
"rowspan"_ostr, u"4"_ustr);
+    OUString a38_id = getXPath(pDump, 
"//page[1]/body/tab/row[38]/cell[1]"_ostr, "id"_ostr);
+    OUString follow_id = getXPath(pDump, 
"//page[1]/body/tab/row[38]/cell[1]"_ostr, "follow"_ostr);
+    // The text of A38, that spans four rows, must be split: empty paragraph 
here
+    assertXPathContent(pDump, "//page[1]/body/tab/row[38]/cell[1]/txt"_ostr, 
u""_ustr);
+    // First row is the repeating line
+    assertXPathContent(pDump, "//page[2]/body/tab/row[1]/cell[1]/txt"_ostr, 
u"1"_ustr);
+    assertXPathContent(pDump, "//page[2]/body/tab/row[1]/cell[2]/txt"_ostr, 
u"2"_ustr);
+    assertXPathContent(pDump, "//page[2]/body/tab/row[1]/cell[3]/txt"_ostr, 
u"3"_ustr);
+    // The text in the follow row's first cell is the second paragraph of A38, 
"10"
+    assertXPath(pDump, "//page[2]/body/tab/row[2]/cell[1]"_ostr, "id"_ostr, 
follow_id);
+    assertXPath(pDump, "//page[2]/body/tab/row[2]/cell[1]"_ostr, 
"precede"_ostr, a38_id);
+    assertXPathContent(pDump, "//page[2]/body/tab/row[2]/cell[1]/txt"_ostr, 
u"10"_ustr);
+}
+
 } // end of anonymous namespace
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index f753113287fb..fad21eebcce9 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -1248,6 +1248,26 @@ bool SwTabFrame::Split(const SwTwips nCutPos, bool 
bTryToSplit,
         while ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() &&
                 nRowCount > nRepeat )
         {
+            // Special case: pTmpRow wants to keep with pRow, but allows 
splitting, and some its
+            // cells span several rows, including pRow. In this case, the 
"split" of the spanning
+            // cells of the pTmpRow may still happen by moving pRow to the 
next page, even here
+            // with !bSplitRowAllowed.
+            if (pTmpRow->IsRowSplitAllowed())
+            {
+                bool bCellSpanCanSplit = false;
+                for (auto pCellFrame = static_cast<const 
SwCellFrame*>(pTmpRow->GetLower());
+                     pCellFrame;
+                     pCellFrame = static_cast<const 
SwCellFrame*>(pCellFrame->GetNext()))
+                {
+                    if (pCellFrame->GetTabBox()->getRowSpan() > 1) // Master 
cell
+                    {
+                        bCellSpanCanSplit = true;
+                        break;
+                    }
+                }
+                if (bCellSpanCanSplit)
+                    break;
+            }
             pRow = pTmpRow;
             --nRowCount;
             pTmpRow = static_cast<SwRowFrame*>(pTmpRow->GetPrev());
@@ -2251,9 +2271,31 @@ void SwTabFrame::MakeAll(vcl::RenderContext* 
pRenderContext)
         const SwRowFrame* pTmpRow = static_cast<const 
SwRowFrame*>(GetLastLower());
         if ( pTmpRow && pTmpRow->ShouldRowKeepWithNext() )
         {
-            if ( HasFollowFlowLine() )
-                RemoveFollowFlowLine();
-            Join();
+            // Special case: pTmpRow wants to keep with next, but allows 
splitting, and some its
+            // cells span several rows - i.e., also the next row. In this 
case, the "split" of the
+            // spanning cells of the pTmpRow may still happen by moving next 
row to the next page,
+            // even here with bTableRowKeep.
+            bool bCellSpanCanSplit = false;
+            if (pTmpRow->IsRowSplitAllowed())
+            {
+                for (auto pCellFrame = static_cast<const 
SwCellFrame*>(pTmpRow->GetLower());
+                     pCellFrame;
+                     pCellFrame = static_cast<const 
SwCellFrame*>(pCellFrame->GetNext()))
+                {
+                    if (pCellFrame->GetTabBox()->getRowSpan() > 1) // Master 
cell
+                    {
+                        bCellSpanCanSplit = true;
+                        break;
+                    }
+                }
+            }
+
+            if (!bCellSpanCanSplit)
+            {
+                if (HasFollowFlowLine())
+                    RemoveFollowFlowLine();
+                Join();
+            }
         }
     }
 
@@ -2936,8 +2978,18 @@ void SwTabFrame::MakeAll(vcl::RenderContext* 
pRenderContext)
 
                     oAccess.reset();
                     bool isFootnoteGrowth(false);
+                    bool bEffectiveTableRowKeep;
+                    if (bTryToSplit == true)
+                    {
+                        bEffectiveTableRowKeep = bTableRowKeep && 
!(bAllowSplitOfRow || bEmulateTableKeepSplitAllowed);
+                    }
+                    else
+                    {
+                        // The second attempt; ignore all the flags allowing 
to split the row
+                        bEffectiveTableRowKeep = bTableRowKeep;
+                    }
                     const bool bSplitError = !Split(nDeadLine, bTryToSplit,
-                        (bTableRowKeep && !(bAllowSplitOfRow || 
bEmulateTableKeepSplitAllowed)),
+                        bEffectiveTableRowKeep,
                         isFootnoteGrowth);
 
                     // tdf#130639 don't start table on a new page after the 
fallback "switch off repeating header"
commit d1a4d4c7b44d45818169322ad61e3063cfcc1da1
Author:     Mike Kaganski <mike.kagan...@collabora.com>
AuthorDate: Wed Sep 18 13:01:44 2024 +0500
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Sep 23 09:33:01 2024 +0200

    Related: tdf#152298 Consider bottom margin in remaining space calculation
    
    The value passed to lcl_RecalcSplitLine could be too large; then
    the call to rTab.Shrink succeeds, and the height of rTab changes
    as requested;  but then the values of  nDistanceToUpperPrtBottom
    and nDistanceToFootnoteBodyPrtBottom are negative,  resulting in
    failed split and layout loop.
    
    Change-Id: I797baee701b6a07e0c9310ea8cf902795c053642
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173595
    Tested-by: Jenkins
    Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com>
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173705

diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index e8fa6a39da53..f753113287fb 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -1096,14 +1096,11 @@ bool SwTabFrame::Split(const SwTwips nCutPos, bool 
bTryToSplit,
 
     SwTwips nRemainingSpaceForLastRow =
         aRectFnSet.YDiff(nCutPos, aRectFnSet.GetTop(getFrameArea()));
-    nRemainingSpaceForLastRow -= aRectFnSet.GetTopMargin(*this);
+    nRemainingSpaceForLastRow -= aRectFnSet.GetTopMargin(*this) + 
aRectFnSet.GetBottomMargin(*this);
 
     // Make pRow point to the line that does not fit anymore:
     while( pRow->GetNext() &&
-           nRemainingSpaceForLastRow >= ( 
aRectFnSet.GetHeight(pRow->getFrameArea()) +
-                                           (IsCollapsingBorders() ?
-                                            pRow->GetBottomLineSize() :
-                                            0 ) ) )
+           nRemainingSpaceForLastRow >= ( 
aRectFnSet.GetHeight(pRow->getFrameArea()) ) )
     {
         if( bTryToSplit || !pRow->IsRowSpanLine() ||
             0 != aRectFnSet.GetHeight(pRow->getFrameArea()) )

Reply via email to