sw/CppunitTest_sw_core_layout.mk | 1 sw/qa/core/layout/data/floattable-next-row-invalidate-pos.docx |binary sw/qa/core/layout/layact.cxx | 78 ++++++++++ sw/source/core/layout/layact.cxx | 40 +++++ 4 files changed, 118 insertions(+), 1 deletion(-)
New commits: commit 9b0c5fe7a78dd93f5ebd31aeb290d09340401f08 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Sep 19 08:33:45 2023 +0200 Commit: Caolán McNamara <caolan.mcnam...@collabora.com> CommitDate: Fri Sep 22 14:24:29 2023 +0200 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 <jenkinscollaboraoff...@gmail.com> Reviewed-by: Caolán McNamara <caolan.mcnam...@collabora.com> 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 new file mode 100644 index 000000000000..bbc7114b8e20 Binary files /dev/null and b/sw/qa/core/layout/data/floattable-next-row-invalidate-pos.docx differ 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.