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 1b6ed32cd87c40e3b3de4dac4efa035c6394a1d5
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Tue Sep 19 08:33:45 2023 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Mon Sep 25 14:06:45 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
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/157132

diff --git a/sw/CppunitTest_sw_core_layout.mk b/sw/CppunitTest_sw_core_layout.mk
index 9431b6b83526..ae945c89ee43 100644
--- a/sw/CppunitTest_sw_core_layout.mk
+++ b/sw/CppunitTest_sw_core_layout.mk
@@ -15,6 +15,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/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 c157476cd3b1..52774e52f0fa 100644
--- a/sw/source/core/layout/layact.cxx
+++ b/sw/source/core/layout/layact.cxx
@@ -1720,8 +1720,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.

Reply via email to