summaryrefslogtreecommitdiff
path: root/sw/source/core
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2023-10-20 08:57:08 +0200
committerMiklos Vajna <vmiklos@collabora.com>2023-10-20 11:53:29 +0200
commit8e03dfd6a4bff4eabf779ace9b758b49cf80f8ba (patch)
tree78d67e35744e7eaf3809c414ebe1c45f28a4a138 /sw/source/core
parent2f1a650b68161cbaed95b8e38392663abd5f1d80 (diff)
tdf#157590 sw floattable: avoid hang in the nested + row span case
Regression from commit 905962db870e9d1cf1dcf3bd1be44c347cddafe1 (sw floattable: handle AllowOverlap==false in the layout, 2023-08-10), the document load resulted in a hang due to a layout loop. What happens is that SwTabFrame::MakeAll() first does a Split(), but the problematic row has cells with rowspans, and once this is combined with multi-page nested floating tables, we move all the content to the next page (we only leave a stub table frame on the old page), so the next time SwTabFrame::MakeAll() is called, we do a Join(), and this leads to a loop. The traditional Writer way here would be to add a loop control, but we can do a little bit better: nobody really asked for row span handling with nested floating tables, so just don't split rows with row span in this case, move the entire row forward instead. This is enough to avoid the layout loop, and a next iteration can still use SwFlowFrame::MoveBwd() / SwFlowFrame::MoveFwd() to split the complex row. The bug is fairly hard to hit, any naive simplification to the original bugdoc leads to a working layout. Carefully keeping the size of the document, it's possible to at least simplify the content of the table cells (while keeping their size unchanged), so we avoid half of the tables and half of the shapes for a faster test case. Change-Id: Ib14154200c45ecb7f59e85f9f4f1fe0124c4256e Reviewed-on: https://gerrit.libreoffice.org/c/core/+/158228 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
Diffstat (limited to 'sw/source/core')
-rw-r--r--sw/source/core/layout/tabfrm.cxx37
1 files changed, 37 insertions, 0 deletions
diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx
index 183c5114178a..688f1e9770a2 100644
--- a/sw/source/core/layout/tabfrm.cxx
+++ b/sw/source/core/layout/tabfrm.cxx
@@ -2644,6 +2644,43 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext)
// See if this is a split fly that can also grow.
auto pUpperFly = static_cast<SwFlyFrame*>(GetUpper());
bFlySplit = pUpperFly->IsFlySplitAllowed();
+
+ if (bFlySplit)
+ {
+ // See if this is a nested split fly where the inner table also has
+ // rowspans.
+ SwTextFrame* pAnchorCharFrame = pUpperFly->FindAnchorCharFrame();
+ if (pAnchorCharFrame && pAnchorCharFrame->IsInFly())
+ {
+ // Find the row we'll split.
+ SwTwips nRemaining
+ = aRectFnSet.YDiff(nDeadLine, aRectFnSet.GetTop(getFrameArea()));
+ nRemaining -= aRectFnSet.GetTopMargin(*this);
+ const SwFrame* pRow = Lower();
+ for (; pRow->GetNext(); pRow = pRow->GetNext())
+ {
+ if (nRemaining < aRectFnSet.GetHeight(pRow->getFrameArea()))
+ {
+ break;
+ }
+
+ nRemaining -= aRectFnSet.GetHeight(pRow->getFrameArea());
+ }
+ // See if any cells have rowspans.
+ for (const SwFrame* pLower = pRow->GetLower(); pLower;
+ pLower = pLower->GetNext())
+ {
+ auto pCellFrame = static_cast<const SwCellFrame*>(pLower);
+ if (pCellFrame->GetTabBox()->getRowSpan() != 1)
+ {
+ // The cell has a rowspan, don't split the row itself in this
+ // case (but just move it forward, i.e. split between the rows).
+ bTryToSplit = false;
+ break;
+ }
+ }
+ }
+ }
}
if( IsInSct() || GetUpper()->IsInTab() || bFlySplit )
nDeadLine = aRectFnSet.YInc( nDeadLine,