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 <wp:wrapTopAndBottom/> 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 <mike.kaganski@collabora.com> Change-Id: I00eed5401b5981b0f3eb9b40e7be920bf71b15b3 Reviewed-on: https://gerrit.collaboraoffice.com/c/online/+/8826 Tested-by: Jenkins CPCI <releng@collaboraoffice.com> Reviewed-by: Miklos Vajna <vmiklos@collabora.com> (cherry picked from commit b356ac63ed2824e20906b26f337d7852994c1a6b) Reviewed-on: https://gerrit.libreoffice.org/c/core/+/209266 Tested-by: Xisco Fauli <xiscofauli@libreoffice.org> Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
This commit is contained in:
committed by
Xisco Fauli
parent
139f436078
commit
0b151e25c8
Binary file not shown.
Binary file not shown.
@@ -2447,6 +2447,59 @@ CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testTdf171708)
|
||||
u"Content after the table.");
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testFloatTableOverFooterObject)
|
||||
{
|
||||
// A floating table split over three pages, and a footer picture reaching up into the body of
|
||||
// every page.
|
||||
createSwDoc("floattable-footer-object.docx");
|
||||
|
||||
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
|
||||
CPPUNIT_ASSERT(pXmlDoc);
|
||||
CPPUNIT_ASSERT_EQUAL(4, countXPathNodes(pXmlDoc, "//page"));
|
||||
|
||||
// All three parts of the fly are dumped below the master anchor, on page 1.
|
||||
const sal_Int32 nFlyBottom
|
||||
= getXPath(pXmlDoc, "//page[1]/body/txt/anchored/fly[1]/infos/bounds", "bottom").toInt32();
|
||||
const sal_Int32 nFlyTop
|
||||
= getXPath(pXmlDoc, "//page[1]/body/txt/anchored/fly[1]/infos/bounds", "top").toInt32();
|
||||
const sal_Int32 nPictureTop
|
||||
= getXPath(pXmlDoc, "//page[1]/footer/txt/anchored/fly/infos/bounds", "top").toInt32();
|
||||
const sal_Int32 nBodyTop = getXPath(pXmlDoc, "//page[1]/body/infos/bounds", "top").toInt32();
|
||||
|
||||
// Without the fix, the fly stayed at the top of the body and ran over the picture: it was
|
||||
// 1725..7235 against a picture at 6059.
|
||||
CPPUNIT_ASSERT_LESS(nPictureTop, nFlyBottom);
|
||||
// It clears the picture by reaching into the top margin area, as Word does, rather than by
|
||||
// giving up a row.
|
||||
CPPUNIT_ASSERT_LESS(nBodyTop, nFlyTop);
|
||||
CPPUNIT_ASSERT_EQUAL(5, countXPathNodes(pXmlDoc, "//page[1]/body/txt/anchored/fly[1]/tab/row"));
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_FIXTURE(SwLayoutWriter6, testFloatTableOverFooterObjectNoFit)
|
||||
{
|
||||
// Same as testFloatTableOverFooterObject, but the picture reaches so far up that clearing it
|
||||
// would take the fly off the page.
|
||||
createSwDoc("floattable-footer-object-nofit.docx");
|
||||
|
||||
xmlDocUniquePtr pXmlDoc = parseLayoutDump();
|
||||
CPPUNIT_ASSERT(pXmlDoc);
|
||||
CPPUNIT_ASSERT_EQUAL(4, countXPathNodes(pXmlDoc, "//page"));
|
||||
|
||||
const sal_Int32 nFlyTop
|
||||
= getXPath(pXmlDoc, "//page[1]/body/txt/anchored/fly[1]/infos/bounds", "top").toInt32();
|
||||
const sal_Int32 nFlyBottom
|
||||
= getXPath(pXmlDoc, "//page[1]/body/txt/anchored/fly[1]/infos/bounds", "bottom").toInt32();
|
||||
const sal_Int32 nPictureTop
|
||||
= getXPath(pXmlDoc, "//page[1]/footer/txt/anchored/fly/infos/bounds", "top").toInt32();
|
||||
const sal_Int32 nBodyTop = getXPath(pXmlDoc, "//page[1]/body/infos/bounds", "top").toInt32();
|
||||
|
||||
// There is nowhere to shift to, so the fly keeps its place and the overlap, rather than
|
||||
// dropping a row or climbing off the page. Word does the same.
|
||||
CPPUNIT_ASSERT_GREATEREQUAL(nBodyTop, nFlyTop);
|
||||
CPPUNIT_ASSERT_GREATER(nPictureTop, nFlyBottom);
|
||||
CPPUNIT_ASSERT_EQUAL(5, countXPathNodes(pXmlDoc, "//page[1]/body/txt/anchored/fly[1]/tab/row"));
|
||||
}
|
||||
|
||||
} // end of anonymous namespace
|
||||
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
|
||||
@@ -1276,6 +1276,10 @@ void SwToContentAnchoredObjectPosition::CalcOverlap(const SwTextFrame* pAnchorFr
|
||||
continue;
|
||||
}
|
||||
|
||||
// Set for an object which the header or footer pushes into the body: it is not part of the
|
||||
// body's flow, so it cannot be resolved by moving down past it.
|
||||
bool bObjectFromHeaderOrFooter = false;
|
||||
|
||||
if (bSplitFly)
|
||||
{
|
||||
SwFlyFrame* pAnchoredObjFly = pAnchoredObj->DynCastFlyFrame();
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user