diff options
author | Miklos Vajna <vmiklos@collabora.com> | 2023-09-19 08:33:45 +0200 |
---|---|---|
committer | Caolán McNamara <caolan.mcnamara@collabora.com> | 2023-09-22 14:24:29 +0200 |
commit | 9b0c5fe7a78dd93f5ebd31aeb290d09340401f08 (patch) | |
tree | 34e55821cda390f5803fd19812b0ddeff968c50e | |
parent | bb08310014173c968345b2a28b215c8e5294f827 (diff) |
tdf#157005 sw floattable: fix missing format of next row in follow fly
The bugdoc has a multi-page floating table, the B1 cell is on page 1.
Pressing enter at the end of the cell first creates a split cell (on
page 1 and page 2), but then pressing enter once more leads to
overlapping text.
The trouble seems to be that the second row has its
mbFrameAreaPositionValid set to false, but nobody formats the row, that
would recalc its position.
Fix the problem by relaxing the check in SwLayAction::FormatContent(),
so we do a full format not only in case there are to-para anchored
objects to the current content frame, but also do the same in case it's
a follow and the matching master has some draw objects that are
effectively anchored in the current content frame.
Previously this wasn't a problem, because split flys are the only
construct where a follow frame can have to-para anchored objects.
(cherry picked from commit cf2be3754b4c48382a61e044209c077bf59c72f2)
Change-Id: I0893aced3ad59963f87874c5aff0e57ad325c01b
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157093
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-by: Caolán McNamara <caolan.mcnamara@collabora.com>
-rw-r--r-- | sw/CppunitTest_sw_core_layout.mk | 1 | ||||
-rw-r--r-- | sw/qa/core/layout/data/floattable-next-row-invalidate-pos.docx | bin | 0 -> 9281 bytes | |||
-rw-r--r-- | sw/qa/core/layout/layact.cxx | 78 | ||||
-rw-r--r-- | sw/source/core/layout/layact.cxx | 40 |
4 files changed, 118 insertions, 1 deletions
diff --git a/sw/CppunitTest_sw_core_layout.mk b/sw/CppunitTest_sw_core_layout.mk index a86bd78c2cd7..4bbfd23e0887 100644 --- a/sw/CppunitTest_sw_core_layout.mk +++ b/sw/CppunitTest_sw_core_layout.mk @@ -16,6 +16,7 @@ $(eval $(call gb_CppunitTest_use_common_precompiled_header,sw_core_layout)) $(eval $(call gb_CppunitTest_add_exception_objects,sw_core_layout, \ sw/qa/core/layout/flycnt \ sw/qa/core/layout/ftnfrm \ + sw/qa/core/layout/layact \ sw/qa/core/layout/layout \ sw/qa/core/layout/paintfrm \ )) diff --git a/sw/qa/core/layout/data/floattable-next-row-invalidate-pos.docx b/sw/qa/core/layout/data/floattable-next-row-invalidate-pos.docx Binary files differnew file mode 100644 index 000000000000..bbc7114b8e20 --- /dev/null +++ b/sw/qa/core/layout/data/floattable-next-row-invalidate-pos.docx diff --git a/sw/qa/core/layout/layact.cxx b/sw/qa/core/layout/layact.cxx new file mode 100644 index 000000000000..64262977f7fe --- /dev/null +++ b/sw/qa/core/layout/layact.cxx @@ -0,0 +1,78 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + */ + +#include <swmodeltestbase.hxx> + +#include <vcl/scheduler.hxx> + +#include <IDocumentLayoutAccess.hxx> +#include <anchoredobject.hxx> +#include <docsh.hxx> +#include <flyfrm.hxx> +#include <pagefrm.hxx> +#include <rootfrm.hxx> +#include <rowfrm.hxx> +#include <sortedobjs.hxx> +#include <tabfrm.hxx> +#include <wrtsh.hxx> + +namespace +{ +/// Covers sw/source/core/layout/layact.cxx fixes. +class Test : public SwModelTestBase +{ +public: + Test() + : SwModelTestBase("/sw/qa/core/layout/data/") + { + } +}; + +CPPUNIT_TEST_FIXTURE(Test, testSplitFlyNextRowInvalidatePos) +{ + // Given a multi-page floating table, row1 is split, i.e. is both on page 1 and page 2: + createSwDoc("floattable-next-row-invalidate-pos.docx"); + // Make sure the follow anchor's IsCompletePaint() reaches its false state, as it happens in the + // interactive case. + Scheduler::ProcessEventsToIdle(); + SwDoc* pDoc = getSwDoc(); + SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout(); + auto pPage1 = pLayout->Lower()->DynCastPageFrame(); + CPPUNIT_ASSERT(pPage1); + auto pPage2 = pPage1->GetNext()->DynCastPageFrame(); + CPPUNIT_ASSERT(pPage2); + CPPUNIT_ASSERT(pPage2->GetSortedObjs()); + SwSortedObjs& rPage2Objs = *pPage2->GetSortedObjs(); + auto pFly2 = rPage2Objs[0]->DynCastFlyFrame(); + auto pTable2 = pFly2->GetLower()->DynCastTabFrame(); + auto pRow2 = pTable2->GetLastLower()->DynCastRowFrame(); + SwTwips nOldRow2Top = pRow2->getFrameArea().Top(); + + // When adding a new paragraph at the end of B1: + // Go to the table: A1 cell. + SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell(); + pWrtShell->GotoTable("Table1"); + // Go to the column: B1 cell. + pWrtShell->GoNextCell(); + // Go to the end of the B1 cell, on page 2. + pWrtShell->EndOfSection(); + // Add a new paragraph at the cell end. + pWrtShell->SplitNode(); + + // Then make sure row 2 is shifted down: + SwTwips nNewRow2Top = pRow2->getFrameArea().Top(); + // Without the accompanying fix in place, this test would have failed with: + // - Expected greater than: 7121 + // - Actual : 7121 + // i.e. row 2 has to be shifted down to 7390, but this didn't happen. + CPPUNIT_ASSERT_GREATER(nOldRow2Top, nNewRow2Top); +} +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/sw/source/core/layout/layact.cxx b/sw/source/core/layout/layact.cxx index f0ac091d16ea..4e8615cf457c 100644 --- a/sw/source/core/layout/layact.cxx +++ b/sw/source/core/layout/layact.cxx @@ -1701,8 +1701,46 @@ bool SwLayAction::FormatContent(SwPageFrame *const pPage) while ( pContent && pPage->IsAnLower( pContent ) ) { // If the content didn't change, we can use a few shortcuts. - const bool bFull = !pContent->isFrameAreaDefinitionValid() || pContent->IsCompletePaint() || + bool bFull = !pContent->isFrameAreaDefinitionValid() || pContent->IsCompletePaint() || pContent->IsRetouche() || pContent->GetDrawObjs(); + + auto pText = pContent->DynCastTextFrame(); + if (!bFull && !pContent->GetDrawObjs() && pContent->IsFollow() && pText) + { + // This content frame doesn't have to-para anchored objects, but it's a follow, check + // the master. + const SwTextFrame* pMaster = pText; + while (pMaster->IsFollow()) + { + pMaster = pMaster->FindMaster(); + } + if (pMaster && pMaster->GetDrawObjs()) + { + for (SwAnchoredObject* pDrawObj : *pMaster->GetDrawObjs()) + { + auto pFly = pDrawObj->DynCastFlyFrame(); + if (!pFly) + { + continue; + } + + if (!pFly->IsFlySplitAllowed()) + { + continue; + } + + if (pFly->GetAnchorFrameContainingAnchPos() != pContent) + { + continue; + } + + // This fly is effectively anchored to pContent, still format pContent. + bFull = true; + break; + } + } + } + if ( bFull ) { // We do this so we don't have to search later on. |