sw/qa/core/layout/data/floattable-hori-pos.docx |binary
 sw/qa/core/layout/flycnt.cxx                    |   34 ++++++++++++++++++++++++
 sw/source/core/text/frmform.cxx                 |   34 ++++++++++++++----------
 3 files changed, 54 insertions(+), 14 deletions(-)

New commits:
commit 12a9009a1c19ee26c65fb44fc90f3432c88ab6a5
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Thu Mar 23 08:09:01 2023 +0100
Commit:     Miklos Vajna <vmik...@collabora.com>
CommitDate: Thu Mar 23 09:48:29 2023 +0000

    sw floattable: fix bad position of follow fly if anchor is positioned late
    
    The bugdoc has a split fly, the master is centered horizontally. That
    means the follow should be centered as well, but it was aligned to the
    left.
    
    The problem is that the follow fly was positioned when the anchor was
    not positioned at all (its top left was 0,0) and then there was no
    invalidation of the fly position to recalc it later when the anchor got
    positioned. The existing InvalidatePos() call is not enough because once
    a fly is formatted, its position gets locked and only
    unlockPositionOfObjects() at the end of the layout process will unlock
    it.
    
    Fix the problem similar to what lcl_InvalidateLowerObjs() for SwTabFrame
    does: if we know that the position of the anchor changed, then unlock
    the position before invalidating it.
    
    If this leads to unwanted re-positioning of flys, it would be perhaps
    possible to do this when the anchor position changes from 0,0 to a valid
    position, but for now just do this all time the anchor position changes.
    
    Change-Id: I811bdfa1eb6705ff3de6ec77111e9500617e8bee
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/149367
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins

diff --git a/sw/qa/core/layout/data/floattable-hori-pos.docx 
b/sw/qa/core/layout/data/floattable-hori-pos.docx
new file mode 100644
index 000000000000..7a5e033a4928
Binary files /dev/null and b/sw/qa/core/layout/data/floattable-hori-pos.docx 
differ
diff --git a/sw/qa/core/layout/flycnt.cxx b/sw/qa/core/layout/flycnt.cxx
index 528b3bc4cbc8..b9ab0ac116cb 100644
--- a/sw/qa/core/layout/flycnt.cxx
+++ b/sw/qa/core/layout/flycnt.cxx
@@ -509,6 +509,40 @@ CPPUNIT_TEST_FIXTURE(Test, testSplitFlyCompat14Body)
     SwFrame* pRow2 = pTab2->GetLower();
     CPPUNIT_ASSERT(!pRow2->GetNext());
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testSplitFlyFollowHorizontalPosition)
+{
+    // Given a document with 2 pages, master fly on page 1, follow fly on page 
2:
+    SwModelTestBase::FlySplitGuard aGuard;
+    createSwDoc("floattable-hori-pos.docx");
+
+    // When laying out that document:
+    calcLayout();
+
+    // Then make sure that the follow fly doesn't have a different horizontal 
position:
+    SwDoc* pDoc = getSwDoc();
+    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+    auto pPage1 = dynamic_cast<SwPageFrame*>(pLayout->Lower());
+    CPPUNIT_ASSERT(pPage1);
+    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);
+    tools::Long nPage1FlyLeft = pPage1Fly->getFrameArea().Left();
+    auto pPage2 = dynamic_cast<SwPageFrame*>(pPage1->GetNext());
+    CPPUNIT_ASSERT(pPage2);
+    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);
+    tools::Long nPage2FlyLeft = pPage2Fly->getFrameArea().Left();
+    // Without the accompanying fix in place, this test would have failed with:
+    // - Expected: 5528
+    // - Actual  : 284
+    // i.e. the follow fly was pushed towards the left, instead of having the 
same position as the
+    // master fly.
+    CPPUNIT_ASSERT_EQUAL(nPage1FlyLeft, nPage2FlyLeft);
+}
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/text/frmform.cxx b/sw/source/core/text/frmform.cxx
index 25bd98bec92e..41b18363aed2 100644
--- a/sw/source/core/text/frmform.cxx
+++ b/sw/source/core/text/frmform.cxx
@@ -340,25 +340,31 @@ bool SwTextFrame::CalcFollow(TextFrameIndex const 
nTextOfst)
 
 void SwTextFrame::MakePos()
 {
+    Point aOldPos = getFrameArea().Pos();
     SwFrame::MakePos();
 
-    // Find the master frame.
-    const SwTextFrame* pMaster = this;
-    while (pMaster->IsFollow())
+    // Recalc split flys if our position changed.
+    if (aOldPos != getFrameArea().Pos())
     {
-        pMaster = pMaster->FindMaster();
-    }
-    // Find which flys are effectively anchored to this frame.
-    for (const auto& pFly : pMaster->GetSplitFlyDrawObjs())
-    {
-        SwTextFrame* pFlyAnchor = pFly->FindAnchorCharFrame();
-        if (pFlyAnchor != this)
+        // Find the master frame.
+        const SwTextFrame* pMaster = this;
+        while (pMaster->IsFollow())
+        {
+            pMaster = pMaster->FindMaster();
+        }
+        // Find which flys are effectively anchored to this frame.
+        for (const auto& pFly : pMaster->GetSplitFlyDrawObjs())
         {
-            continue;
+            SwTextFrame* pFlyAnchor = pFly->FindAnchorCharFrame();
+            if (pFlyAnchor != this)
+            {
+                continue;
+            }
+            // Possibly this fly was positioned relative to us, invalidate its 
position now that our
+            // position is changed.
+            pFly->UnlockPosition();
+            pFly->InvalidatePos();
         }
-        // Possibly this fly was positioned relative to us, invalidate its 
position now that our
-        // position is changed.
-        pFly->InvalidatePos();
     }
 
     // Inform LOK clients about change in position of redlines (if any)

Reply via email to