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 cf2be3754b4c48382a61e044209c077bf59c72f2 Author: Miklos Vajna <vmik...@collabora.com> AuthorDate: Tue Sep 19 08:33:45 2023 +0200 Commit: Miklos Vajna <vmik...@collabora.com> CommitDate: Tue Sep 19 09:37:23 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. Change-Id: I0893aced3ad59963f87874c5aff0e57ad325c01b Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157039 Reviewed-by: Miklos Vajna <vmik...@collabora.com> Tested-by: Jenkins diff --git a/sw/CppunitTest_sw_core_layout.mk b/sw/CppunitTest_sw_core_layout.mk index e965ae6f71aa..82f7dc87e695 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 \ sw/qa/core/layout/tabfrm \ 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 316549f17d57..84481981fd6e 100644 --- a/sw/source/core/layout/layact.cxx +++ b/sw/source/core/layout/layact.cxx @@ -1713,8 +1713,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.