sw/qa/extras/layout/data/tdf152298.docx |binary sw/qa/extras/layout/layout3.cxx | 23 +++++++++++ sw/source/core/layout/tabfrm.cxx | 62 +++++++++++++++++++++++++++++--- 3 files changed, 80 insertions(+), 5 deletions(-)
New commits: commit f0baab027df46d4e74b7808ff5d976b8efb1ea33 Author: Mike Kaganski <[email protected]> AuthorDate: Wed Sep 18 18:07:25 2024 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Fri Sep 20 04:05: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 <[email protected]> Tested-by: Jenkins 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 cc27f66e3127..1f9358147e9f 100644 --- a/sw/qa/extras/layout/layout3.cxx +++ b/sw/qa/extras/layout/layout3.cxx @@ -3670,6 +3670,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 fea11a76497f..9948b1be0c5c 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -1254,6 +1254,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()); @@ -2255,9 +2275,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(); + } } } @@ -2947,8 +2989,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 afb6671d669120f213da0aa9f3973a02905a4088 Author: Mike Kaganski <[email protected]> AuthorDate: Wed Sep 18 14:19:33 2024 +0500 Commit: Mike Kaganski <[email protected]> CommitDate: Fri Sep 20 04:05:35 2024 +0200 Check if split is forced when calculating fixed-height row's min height Change-Id: Ib5780d229041823e9aa7ba1c086655eb7c8590eb Reviewed-on: https://gerrit.libreoffice.org/c/core/+/173601 Tested-by: Jenkins Reviewed-by: Mike Kaganski <[email protected]> diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index 0ebdd4cb17cc..fea11a76497f 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -4826,7 +4826,7 @@ static SwTwips lcl_CalcMinRowHeight( const SwRowFrame* _pRow, if ( !_pRow->IsRowSpanLine() ) { const SwFormatFrameSize &rSz = _pRow->GetFormat()->GetFrameSize(); - if ( _pRow->HasFixSize() ) + if (_pRow->HasFixSize() && !_pRow->IsForceRowSplitAllowed()) { OSL_ENSURE(SwFrameSize::Fixed == rSz.GetHeightSizeType(), "pRow claims to have fixed size"); return rSz.GetHeight();
