sw/qa/core/layout/data/floattable-footer-2rows.docx |binary sw/qa/core/layout/flycnt.cxx | 49 ++++++++++ sw/source/core/layout/findfrm.cxx | 11 +- sw/source/core/layout/flowfrm.cxx | 5 + sw/source/core/layout/fly.cxx | 2 sw/source/core/layout/tabfrm.cxx | 17 +-- sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx | 15 +++ 7 files changed, 88 insertions(+), 11 deletions(-)
New commits: commit 0b2c50a1c364c4e0bcf4d9ddb2c6db2ffd58d095 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri Mar 3 09:27:05 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Mar 8 09:11:51 2023 +0100 sw floattable: try to grow fly parent when trying section/table The bugdoc is meant to be of 2 pages, but the last row of the table went to a 3rd page, even if there was still space in page 2. SwTabFrame::MakeAll() had a case where it tried to grow section or table parents, that's how a similar case worked for multi-page tables in section frames. Extend this to also consider split fly parents, which avoids the unwanted 3rd page. This broke the rendering floattable-3pages.docx (it had 2 pages), which pointed out that SwFrame::ImplGetNextLayoutLeaf() was buggy for split flys. That function is meant to find the next layout frame which is not a lower of the current frame, but it had to be extended to handle the split anchor frame of split flys. Also, if we're here, remove the other split fly check in SwTabFrame::MakeAll(), which now looks redundant and is odd (there is no similar check for sections). (cherry picked from commit e66632b023ee1cf25a381536f53458f631964bb8) Change-Id: I83090ac04ca27b71f62315e3b9755c8196057b5d diff --git a/sw/qa/core/layout/data/floattable-footer-2rows.docx b/sw/qa/core/layout/data/floattable-footer-2rows.docx new file mode 100644 index 000000000000..72013be28fbd Binary files /dev/null and b/sw/qa/core/layout/data/floattable-footer-2rows.docx differ diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx index 5dfc8d5641bf..d400fd85de0a 100644 --- a/sw/qa/core/layout/flycnt.cxx +++ b/sw/qa/core/layout/flycnt.cxx @@ -360,6 +360,36 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyFooter) // i.e. <w:pgMar w:top="1440"> from the bugdoc was lost, the follow fly had no vertical offset. CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(1440), nPage2FlyTop - nPage2Top); } + +CPPUNIT_TEST_FIXTURE(Test, testSplitFlyFooter2Rows) +{ + // Given a document with a 2nd page that contains the second half of a split row + a last row: + std::shared_ptr<comphelper::ConfigurationChanges> pChanges( + comphelper::ConfigurationChanges::create()); + officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::set(true, + pChanges); + pChanges->commit(); + comphelper::ScopeGuard g([pChanges] { + officecfg::Office::Writer::Filter::Import::DOCX::ImportFloatingTableAsSplitFly::set( + false, pChanges); + pChanges->commit(); + }); + createSwDoc("floattable-footer-2rows.docx"); + + // When laying out that document: + calcLayout(); + + // Then make sure that the table is split to 2 pages: + SwDoc* pDoc = getSwDoc(); + SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + auto pPage1 = dynamic_cast<SwPageFrame*>(pLayout->Lower()); + CPPUNIT_ASSERT(pPage1); + auto pPage2 = dynamic_cast<SwPageFrame*>(pPage1->GetNext()); + CPPUNIT_ASSERT(pPage2); + // Without the accompanying fix in place, this test would have failed. The 2nd page only had the + // 2nd half of the split row and the last row went to a 3rd page. + CPPUNIT_ASSERT(!pPage2->GetNext()); +} } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/findfrm.cxx b/sw/source/core/layout/findfrm.cxx index 07290dee5f2a..0e425e0a1eb5 100644 --- a/sw/source/core/layout/findfrm.cxx +++ b/sw/source/core/layout/findfrm.cxx @@ -338,6 +338,8 @@ const SwLayoutFrame *SwFrame::ImplGetNextLayoutLeaf( bool bFwd ) const const SwLayoutFrame *pLayoutFrame = nullptr; const SwFrame *p = nullptr; bool bGoingUp = !bFwd; // false for forward, true for backward + // The anchor is this frame, unless we traverse the anchor of a split fly. + const SwFrame* pAnchor = this; do { bool bGoingFwdOrBwd = false; @@ -366,7 +368,12 @@ const SwLayoutFrame *SwFrame::ImplGetNextLayoutLeaf( bool bFwd ) const const SwFlyFrame* pFlyFrame = pFrame->FindFlyFrame(); if (pFlyFrame->IsFlySplitAllowed()) { - p = pFlyFrame->GetAnchorFrame(); + p = const_cast<SwFlyFrame*>(pFlyFrame)->FindAnchorCharFrame(); + // Remember the anchor frame, so if we look for the leaf of a frame in a + // split fly (anchored in the master of a text frame, but rendered on the + // next page), we won't return a frame on the next page, rather return + // nullptr. + pAnchor = p; } } @@ -388,7 +395,7 @@ const SwLayoutFrame *SwFrame::ImplGetNextLayoutLeaf( bool bFwd ) const } while( ( p && !p->IsFlowFrame() ) || pFrame == this || nullptr == ( pLayoutFrame = pFrame->IsLayoutFrame() ? static_cast<const SwLayoutFrame*>(pFrame) : nullptr ) || - pLayoutFrame->IsAnLower( this ) ); + pLayoutFrame->IsAnLower( pAnchor ) ); return pLayoutFrame; } diff --git a/sw/source/core/layout/tabfrm.cxx b/sw/source/core/layout/tabfrm.cxx index 177bfa947fb2..b44f31b61d4d 100644 --- a/sw/source/core/layout/tabfrm.cxx +++ b/sw/source/core/layout/tabfrm.cxx @@ -2469,7 +2469,14 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) if ( pFirstNonHeadlineRow->GetNext() || bTryToSplit ) { SwTwips nDeadLine = aRectFnSet.GetPrtBottom(*GetUpper()); - if( IsInSct() || GetUpper()->IsInTab() ) // TABLE IN TABLE) + bool bFlySplit = false; + if (GetUpper()->IsFlyFrame()) + { + // See if this is a split fly that can also grow. + auto pUpperFly = static_cast<SwFlyFrame*>(GetUpper()); + bFlySplit = pUpperFly->IsFlySplitAllowed(); + } + if( IsInSct() || GetUpper()->IsInTab() || bFlySplit ) nDeadLine = aRectFnSet.YInc( nDeadLine, GetUpper()->Grow( LONG_MAX, true ) ); @@ -2736,13 +2743,7 @@ void SwTabFrame::MakeAll(vcl::RenderContext* pRenderContext) // allowed to split. SwTwips nDistToUpperPrtBottom = aRectFnSet.BottomDist( getFrameArea(), aRectFnSet.GetPrtBottom(*GetUpper())); - bool bFlySplit = false; - if (GetUpper()->IsFlyFrame()) - { - auto pUpperFly = static_cast<SwFlyFrame*>(GetUpper()); - bFlySplit = pUpperFly->IsFlySplitAllowed(); - } - if ( nDistToUpperPrtBottom >= 0 || bTryToSplit || bFlySplit ) + if ( nDistToUpperPrtBottom >= 0 || bTryToSplit ) { lcl_RecalcTable( *this, nullptr, aNotify ); m_bLowersFormatted = true; commit 723fe0a30b1fa50b4e0e4844e6a99ed7a78d6b27 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Fri Mar 3 07:51:33 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Mar 8 09:11:32 2023 +0100 sw floattable: undefined behavior in SwFlyFrame::UpdateAttr_() The switch-case handled RES_FRM_SIZE and RES_FMT_CHG together, so when I added RES_FLY_SPLIT as a 3rd case for the same block, it started to handle RES_FLY_SPLIT as RES_FMT_CHG. For multi-page floating tables only the shared code is interesting, so just make the condition in the else branch more strict to avoid the unwanted downcast. (cherry picked from commit edaf6155496d452c67aa191c1d45a0328ef079e0) Change-Id: I5015b06059f05fee400f427514d950d95a49df94 diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx index 8e18ed08aaea..89637ff6f5cf 100644 --- a/sw/source/core/layout/fly.cxx +++ b/sw/source/core/layout/fly.cxx @@ -888,7 +888,7 @@ void SwFlyFrame::UpdateAttr_( const SfxPoolItem *pOld, const SfxPoolItem *pNew, SwFormatChg *pOldFormatChg = nullptr; if (nWhich == RES_FRM_SIZE) pNewFormatFrameSize = const_cast<SwFormatFrameSize*>(static_cast<const SwFormatFrameSize*>(pNew)); - else + else if (nWhich == RES_FMT_CHG) pOldFormatChg = const_cast<SwFormatChg*>(static_cast<const SwFormatChg*>(pOld)); if (aURL.GetMap() && (pNewFormatFrameSize || pOldFormatChg)) commit ae78590f81e9b8bfb085f5ffe4a4e7caf9bb72eb Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Thu Mar 2 09:09:27 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Mar 8 09:11:21 2023 +0100 sw floattable: fix vertical position of follow flys with rel orient = page The problem was that the follow frame's top was the 2nd page's top, because we ignore the vertical offset for follow fly frames. Ignoring the original offset is fine, but follow frames are still inside the body frame in Word, so their offset is effectively the header / top margin area. Fix the problem by improving how nRelPosY is tweaked for follow fly frames: an additional positive offset is wanted when the rel orient is page. With this, this bugdoc now renders perfectly. (cherry picked from commit b9bf9bf9d1d1e0fb9eb765cd5060d611af7176df) Change-Id: Iec4b85339a7b4b69944d25eb2e06a6e3f977f093 diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx index 10a84856da0a..5dfc8d5641bf 100644 --- a/sw/qa/core/layout/flycnt.cxx +++ b/sw/qa/core/layout/flycnt.cxx @@ -336,10 +336,29 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyFooter) SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); auto pPage1 = dynamic_cast<SwPageFrame*>(pLayout->Lower()); CPPUNIT_ASSERT(pPage1); + SwTwips nPage1Top = pPage1->getFrameArea().Top(); + const SwSortedObjs& rPage1Objs = *pPage1->GetSortedObjs(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage1Objs.size()); + auto pPage1Fly = dynamic_cast<SwFlyAtContentFrame*>(rPage1Objs[0]); + CPPUNIT_ASSERT(pPage1Fly); + SwTwips nPage1FlyTop = pPage1Fly->getFrameArea().Top(); + // <w:tblpPr w:tblpY="3286"> from the bugdoc. + CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(3286), nPage1FlyTop - nPage1Top); // Second page: auto pPage2 = dynamic_cast<SwPageFrame*>(pPage1->GetNext()); // Without the accompanying fix in place, this test would have failed, there was no 2nd page. CPPUNIT_ASSERT(pPage2); + SwTwips nPage2Top = pPage2->getFrameArea().Top(); + const SwSortedObjs& rPage2Objs = *pPage2->GetSortedObjs(); + CPPUNIT_ASSERT_EQUAL(static_cast<size_t>(1), rPage2Objs.size()); + auto pPage2Fly = dynamic_cast<SwFlyAtContentFrame*>(rPage2Objs[0]); + CPPUNIT_ASSERT(pPage2Fly); + SwTwips nPage2FlyTop = pPage2Fly->getFrameArea().Top(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected: 1440 + // - Actual : 0 + // i.e. <w:pgMar w:top="1440"> from the bugdoc was lost, the follow fly had no vertical offset. + CPPUNIT_ASSERT_EQUAL(static_cast<SwTwips>(1440), nPage2FlyTop - nPage2Top); } } diff --git a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx index 8756da6a325c..9a9abc9f4dd8 100644 --- a/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx +++ b/sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx @@ -609,6 +609,21 @@ void SwToContentAnchoredObjectPosition::CalcPosition() // This is a follow of a split fly: shift it up to match the anchor position, // because the vertical offset is meant to be handled only on the first page. nRelPosY -= aVert.GetPos(); + + if (aVert.GetRelationOrient() == text::RelOrientation::PAGE_FRAME + && rPageAlignLayFrame.IsPageFrame()) + { + // Master is positioned relative to the edge of the page, with an offset. + // Follow will have no offset, but is relative to the bottom of the header. + auto& rPageFrame = static_cast<const SwPageFrame&>(rPageAlignLayFrame); + const SwLayoutFrame* pBodyFrame = rPageFrame.FindBodyCont(); + if (pBodyFrame) + { + SwTwips nDiff = pBodyFrame->getFrameArea().Top() + - rPageFrame.getFrameArea().Top(); + nRelPosY += nDiff; + } + } } } commit 4e08ec2c074aac46ad0e0f8edb73d31a3229e4e4 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Mar 7 08:42:42 2023 +0100 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Wed Mar 8 08:30:03 2023 +0100 sw: fix crash in GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid() Crashreport signature: program/libswlo.so SwFlowFrame::GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid() const sw/source/core/layout/flowfrm.cxx:1741 program/libswlo.so objectpositioning::SwAnchoredObjectPosition::GetTopForObjPos(SwFrame const&, SwRectFnCollection* const&, bool) const include/svl/itemset.hxx:101 program/libswlo.so objectpositioning::SwToContentAnchoredObjectPosition::CalcPosition() sw/source/core/objectpositioning/tocntntanchoredobjectposition.cxx:1020 program/libswlo.so SwAnchoredDrawObject::MakeObjPosAnchoredAtPara() sw/source/core/layout/anchoreddrawobject.cxx:424 (cherry picked from commit ebc60f5ccab910d6974b5c386b2c0243f9eb030b) Change-Id: If162602f6a1cc2108c0de385652e93e23be920be diff --git a/sw/source/core/layout/flowfrm.cxx b/sw/source/core/layout/flowfrm.cxx index e53d32b9fa20..0aa9c6f14534 100644 --- a/sw/source/core/layout/flowfrm.cxx +++ b/sw/source/core/layout/flowfrm.cxx @@ -1749,6 +1749,11 @@ SwTwips SwFlowFrame::GetUpperSpaceAmountConsideredForPrevFrameAndPageGrid() cons { SwTwips nUpperSpaceAmountConsideredForPrevFrameAndPageGrid = 0; + if (!m_rThis.GetUpper() || !m_rThis.GetUpper()->GetFormat()) + { + return nUpperSpaceAmountConsideredForPrevFrameAndPageGrid; + } + if ( !m_rThis.GetUpper()->GetFormat()->getIDocumentSettingAccess().get(DocumentSettingId::USE_FORMER_OBJECT_POS) ) { nUpperSpaceAmountConsideredForPrevFrameAndPageGrid =