summaryrefslogtreecommitdiff
path: root/sw/source
diff options
context:
space:
mode:
authorMiklos Vajna <vmiklos@collabora.com>2020-12-21 17:55:02 +0100
committerMiklos Vajna <vmiklos@collabora.com>2020-12-21 23:28:39 +0100
commit160db4bf0fc391b2ded635d0bd998d5352541742 (patch)
treef3f7de645745556046a1dd22be53b5c4defca7f6 /sw/source
parentb01310567d93d2cea068c55ff8e2ce0582d0fd3a (diff)
sw: fix layout loop due to a keep-with-next vs 100% image height conflict
The document in question has a landscape page, the last paragraph has an image where the width is 100% and the height is set to keep the ratio (which 1:1). This means that SwFlyFreeFrame::CheckClip() will scale the image down, so the image fits the page (and give up that 100% width was requested). The next problem is that this image has a wrap type set to none, so not only the total height of the page is taken, but also no content is allowed on the left/right side, effectively taking the entire body frame. Combine this with a previous paragraph, which is a heading, so keep-with-next is set for it. Layout loops because keep-with-next and take-the-entire-page are conflicting requirements and we used to have no explicit code to relax one of them when both are present: SwFlowFrame::MoveBwd: frame is 4, old upper is 10, new upper is 2 SwFlowFrame::MoveFwd: frame is 4, old upper is 2, new upper is 10 SwFlowFrame::MoveBwd: frame is 4, old upper is 10, new upper is 2 SwFlowFrame::MoveFwd: frame is 4, old upper is 2, new upper is 10 SwFlowFrame::MoveBwd: loop control, frame is 4, old upper is 10, new upper would be 2, but not moving there Fix the problem by giving up keep-with-next to stop the loop, mostly because we have to give up one of the requirements and Word resolves the conflict this way. Change-Id: I7da1ebcff9302cd144887f63efb94e0b2b2be8fd Reviewed-on: https://gerrit.libreoffice.org/c/core/+/108119 Reviewed-by: Miklos Vajna <vmiklos@collabora.com> Tested-by: Jenkins
Diffstat (limited to 'sw/source')
-rw-r--r--sw/source/core/layout/flowfrm.cxx58
1 files changed, 57 insertions, 1 deletions
diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx
index 7b91a1bc74cc..aeeb9df158cf 100644
--- a/sw/source/core/layout/flowfrm.cxx
+++ b/sw/source/core/layout/flowfrm.cxx
@@ -176,6 +176,61 @@ void SwFlowFrame::CheckKeep()
pPre->InvalidatePos();
}
+namespace
+{
+/**
+ * Determines if the next content frame after rThis will require the full area of the parent body
+ * frame.
+ */
+bool IsNextContentFullPage(const SwFrame& rThis)
+{
+ const SwFrame* pNext = rThis.FindNextCnt();
+ if (!pNext)
+ {
+ return false;
+ }
+
+ const SwSortedObjs* pNextDrawObjs = pNext->GetDrawObjs();
+ if (!pNextDrawObjs || !pNextDrawObjs->size())
+ {
+ return false;
+ }
+
+ for (const auto& pDrawObj : *pNextDrawObjs)
+ {
+ if (!pDrawObj)
+ {
+ continue;
+ }
+
+ SwTwips nDrawObjHeight = pDrawObj->GetObjRectWithSpaces().Height();
+ const SwPageFrame* pPageFrame = pDrawObj->GetPageFrame();
+ if (!pPageFrame)
+ {
+ continue;
+ }
+
+ SwTwips nBodyHeight = pPageFrame->GetLower()->getFrameArea().Height();
+ if (nDrawObjHeight < nBodyHeight)
+ {
+ continue;
+ }
+
+ const SwFormatSurround& rSurround = pDrawObj->GetFrameFormat().GetSurround();
+ if (rSurround.GetSurround() != text::WrapTextMode_NONE)
+ {
+ continue;
+ }
+
+ // At this point the height of the draw object will use all the vertical available space,
+ // and also no wrapping will be performed, so all horizontal space will be taken as well.
+ return true;
+ }
+
+ return false;
+}
+}
+
bool SwFlowFrame::IsKeep(SvxFormatKeepItem const& rKeep,
SvxFormatBreakItem const& rBreak,
bool const bCheckIfLastRowShouldKeep) const
@@ -186,10 +241,11 @@ bool SwFlowFrame::IsKeep(SvxFormatKeepItem const& rKeep,
// 3. If bBreakCheck is set to true, this function only checks
// if there are any break after attributes set at rAttrs
// or break before attributes set for the next content (or next table)
+ // 4. Keep is ignored if the next frame will require its own page.
bool bKeep = bCheckIfLastRowShouldKeep ||
( !m_rThis.IsInFootnote() &&
( !m_rThis.IsInTab() || m_rThis.IsTabFrame() ) &&
- rKeep.GetValue() );
+ rKeep.GetValue() && !IsNextContentFullPage(m_rThis));
OSL_ENSURE( !bCheckIfLastRowShouldKeep || m_rThis.IsTabFrame(),
"IsKeep with bCheckIfLastRowShouldKeep should only be used for tabfrms" );