From 0b151e25c8e155ebc9700cef2c089502a17376b1 Mon Sep 17 00:00:00 2001 From: Mike Kaganski Date: Sat, 8 Aug 2026 17:13:07 +0500 Subject: [PATCH] Related: tdf#171708 sw: keep floattable clear of a header/footer object To see the problem, open that bug's document, https://bugs.documentfoundation.org/attachment.cgi?id=206628 - its body starts with a floating table spanning three pages (w:tblpPr, w:tblOverlap val="never"), and its footer holds a picture with and a negative positionV offset, so the picture reaches up into the body. Writer put every page's part of the table at the top of the body and painted its last rows over the picture, and it left the table lower on the page than Word leaves it. What Word does, measured from its print output over hand-authored probes with exact row heights: - how much of the table goes on a page comes from the full body height, with nothing in the way taken into account; - the part is then shifted up as a whole until its bottom clears the object below it, which may take it into the top margin area; - the page edge is the limit - where clearing the object would take the part off the page, it stays put and keeps the overlap. The low placement and the overlap are therefore one behaviour: the shift is what avoids the object. CalcOverlap already avoids overlaps for split flys, but a header/footer object is anchored outside the body and so was dismissed as a fly from another upper, and the one conflict it knows how to resolve is by moving down - which here would push the fly off the page. So consider such an object too, and resolve a conflict with one that starts below the fly by shifting the fly up until its bottom clears it, as far as the page frame allows. Where the page cannot hold the shifted fly, keep the overlap, and in no case give up a row to fit. Signed-off-by: Mike Kaganski Change-Id: I00eed5401b5981b0f3eb9b40e7be920bf71b15b3 Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/8826 Tested-by: Jenkins CPCI Reviewed-by: Miklos Vajna (cherry picked from commit b356ac63ed2824e20906b26f337d7852994c1a6b) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/209266 Tested-by: Xisco Fauli Reviewed-by: Xisco Fauli --- .../data/floattable-footer-object-nofit.docx | Bin 0 -> 3777 bytes .../layout/data/floattable-footer-object.docx | Bin 0 -> 3777 bytes sw/qa/extras/layout/layout6.cxx | 53 ++++++++++++++++++ .../tocntntanchoredobjectposition.cxx | 32 ++++++++++- 4 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 sw/qa/extras/layout/data/floattable-footer-object-nofit.docx create mode 100644 sw/qa/extras/layout/data/floattable-footer-object.docx diff --git a/sw/qa/extras/layout/data/floattable-footer-object-nofit.docx b/sw/qa/extras/layout/data/floattable-footer-object-nofit.docx new file mode 100644 index 0000000000000000000000000000000000000000..ee570d8ae0bebfff339c7c427eb63dc4be585bd2 GIT binary patch literal 3777 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 F>0g{lE|&lR literal 0 HcmV?d00001 diff --git a/sw/qa/extras/layout/data/floattable-footer-object.docx b/sw/qa/extras/layout/data/floattable-footer-object.docx new file mode 100644 index 0000000000000000000000000000000000000000..06f0c1d2690639eda2e0cf0df03eafb905e79af6 GIT binary patch literal 3777 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 @@ -1303,8 +1307,13 @@ void SwToContentAnchoredObjectPosition::CalcOverlap(const SwTextFrame* pAnchorFr if (pAnchoredObjFlyAnchor && pAnchoredObjFlyAnchor->GetUpper() != pAnchorUpper) { - // A fly overlapping with a fly from another upper is fine. - continue; + // A fly overlapping with a fly from another upper is fine, except for a header or + // footer object reaching into the body we are in. + if (pAnchorUpper && pAnchorUpper->IsInDocBody() + && pAnchoredObjFlyAnchor->FindFooterOrHeader()) + bObjectFromHeaderOrFooter = true; + else + continue; } bool bAnchoredObjFlyAnchorInTable @@ -1331,6 +1340,25 @@ void SwToContentAnchoredObjectPosition::CalcOverlap(const SwTextFrame* pAnchorFr continue; } + if (bObjectFromHeaderOrFooter + && pAnchoredObj->GetObjRect().Top() > GetAnchoredObj().GetObjRect().Top()) + { + // The other object starts below us, so shifting down would push us off the page: + // shift up instead, until our bottom clears it. The page is the limit - a split fly + // may reach into the top margin area, but not past the page edge; where even that is + // not enough, keep the overlap. + const SwTwips nUp + = GetAnchoredObj().GetObjRect().Bottom() - pAnchoredObj->GetObjRect().Top() + 1; + const SwPageFrame* pPageFrame = pAnchorFrameForVertPos->FindPageFrame(); + if (pPageFrame + && GetAnchoredObj().GetObjRect().Top() - nUp >= pPageFrame->getFrameArea().Top()) + { + rRelPos.setY(rRelPos.getY() - nUp); + GetAnchoredObj().SetObjTop(nTopOfAnch + rRelPos.Y()); + } + continue; + } + // Already formatted, overlaps: resolve the conflict by shifting ourselves down. SwTwips nYDiff = pAnchoredObj->GetObjRect().Bottom() - GetAnchoredObj().GetObjRect().Top(); rRelPos.setY(rRelPos.getY() + nYDiff + 1);