sw/CppunitTest_sw_core_layout.mk                                               
 |    1 
 
sw/qa/core/layout/data/floattable-model-position-for-view-point-correction.docx 
|binary
 sw/qa/core/layout/trvlfrm.cxx                                                  
 |   56 ++++++++++
 sw/source/core/layout/trvlfrm.cxx                                              
 |   25 ++++
 4 files changed, 81 insertions(+), 1 deletion(-)

New commits:
commit 02db94e6a9d78fd56873bcca687e0b4b668bf828
Author:     Miklos Vajna <vmik...@collabora.com>
AuthorDate: Fri Dec 1 08:40:40 2023 +0100
Commit:     Caolán McNamara <caolan.mcnam...@collabora.com>
CommitDate: Mon Dec 4 13:06:08 2023 +0100

    sw floattable: fix finding the nearest text in split flys on mouse click
    
    Clicking on the right of the floating table on the page 1 resulted
    in a cursor position on page 2 instead of a position inside the floating
    table on page 1.
    
    What happens is that the anchor text frame on page 1 is wide enough to
    contain the mouse click position, but then "before the first character
    of the paragraph" is on page 2, so a page 1 click results in a page 2
    cursor position, which is unexpected.
    
    Fix the problem by first ignoring which dummy anchor frames (all
    non-last ones) in SwLayoutFrame, so
    SwLayoutFrame::GetModelPositionForViewPoint() in
    SwPageFrame::GetModelPositionForViewPoint() fails for the perfect match
    case, and then later looking for split flys explicitly, so the corrected
    case finds the split fly on the page.
    
    I imagine this is not only useful for mouse clicks, but it's also good
    for everything else that uses GetModelPositionForViewPoint(), e.g.
    keyboard page-down.
    
    (cherry picked from commit f461853b11439c4e485a79174d34735395e5bf52)
    
    Change-Id: I761b211c1b5468d9d8996c59a32ac9be5b83a777
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160298
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    Tested-by: Caolán McNamara <caolan.mcnam...@collabora.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 b77cf51e2799..5eb874400d53 100644
--- a/sw/CppunitTest_sw_core_layout.mk
+++ b/sw/CppunitTest_sw_core_layout.mk
@@ -23,6 +23,7 @@ $(eval $(call 
gb_CppunitTest_add_exception_objects,sw_core_layout, \
     sw/qa/core/layout/paintfrm \
     sw/qa/core/layout/sortedobjs \
     sw/qa/core/layout/tabfrm \
+    sw/qa/core/layout/trvlfrm \
 ))
 
 $(eval $(call gb_CppunitTest_use_libraries,sw_core_layout, \
diff --git 
a/sw/qa/core/layout/data/floattable-model-position-for-view-point-correction.docx
 
b/sw/qa/core/layout/data/floattable-model-position-for-view-point-correction.docx
new file mode 100644
index 000000000000..1de36c6e0c1f
Binary files /dev/null and 
b/sw/qa/core/layout/data/floattable-model-position-for-view-point-correction.docx
 differ
diff --git a/sw/qa/core/layout/trvlfrm.cxx b/sw/qa/core/layout/trvlfrm.cxx
new file mode 100644
index 000000000000..dc8ba54f4feb
--- /dev/null
+++ b/sw/qa/core/layout/trvlfrm.cxx
@@ -0,0 +1,56 @@
+/* -*- 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 <wrtsh.hxx>
+#include <docsh.hxx>
+#include <IDocumentLayoutAccess.hxx>
+#include <rootfrm.hxx>
+#include <node.hxx>
+
+namespace
+{
+/// Covers sw/source/core/layout/trvlfrm.cxx fixes.
+class Test : public SwModelTestBase
+{
+public:
+    Test()
+        : SwModelTestBase("/sw/qa/core/layout/data/")
+    {
+    }
+};
+
+CPPUNIT_TEST_FIXTURE(Test, testSplitFlyModelPositionForViewPointCorrection)
+{
+    // Given a 2 page floating table, 40% width, positioned on the left of the 
page:
+    createSwDoc("floattable-model-position-for-view-point-correction.docx");
+
+    // When clicking on the right side of the table:
+    SwWrtShell* pWrtShell = getSwDocShell()->GetWrtShell();
+    SwDoc* pDoc = getSwDocShell()->GetDoc();
+    SwRootFrame* pLayout = pDoc->getIDocumentLayoutAccess().GetCurrentLayout();
+    SwFrame* pPage = pLayout->GetLower();
+    SwFrame* pBody = pPage->GetLower();
+    const SwRect& rBodyRect = pBody->getFrameArea();
+    // 1 line below the top center of the body frame.
+    Point aDocPos(rBodyRect.Left() + rBodyRect.Width() / 2, rBodyRect.Top() + 
220);
+    bool bOnlyText = false;
+    pWrtShell->CallSetCursor(&aDocPos, bOnlyText);
+
+    // Then make sure the cursor gets inside the table, and doesn't go to the 
anchor on page 2:
+    SwCursor& rCursor = pWrtShell->GetCurrentShellCursor();
+    SwTableNode* pTableNode = rCursor.GetPointNode().FindTableNode();
+    // Without the accompanying fix in place, this test would have failed, the 
cursor was in the
+    // anchor text node, not inside the split fly.
+    CPPUNIT_ASSERT(pTableNode);
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/layout/trvlfrm.cxx 
b/sw/source/core/layout/trvlfrm.cxx
index dfcfad57cef5..3d3b43ea3eaa 100644
--- a/sw/source/core/layout/trvlfrm.cxx
+++ b/sw/source/core/layout/trvlfrm.cxx
@@ -49,6 +49,7 @@
 #include <frmtool.hxx>
 #include <ndtxt.hxx>
 #include <undobj.hxx>
+#include <flyfrms.hxx>
 
 #include <swselectionlist.hxx>
 #include <comphelper/lok.hxx>
@@ -164,8 +165,17 @@ bool SwLayoutFrame::GetModelPositionForViewPoint( 
SwPosition *pPos, Point &rPoin
                                  pFrame->UnionFrame() :
                                  pFrame->GetPaintArea() );
 
+        auto pTextFrame = pFrame->DynCastTextFrame();
+        bool bSplitFly = false;
+        if (pTextFrame && pTextFrame->HasNonLastSplitFlyDrawObj())
+        {
+            // Don't consider a non-last anchor of the split fly, so the view 
point can be corrected
+            // to go to the nearest fly, instead of the last anchor on a later 
page.
+            bSplitFly = true;
+        }
+
         if ( aPaintRect.Contains( rPoint ) &&
-             ( bContentCheck || pFrame->GetModelPositionForViewPoint( pPos, 
rPoint, pCMS ) ) )
+             ( bContentCheck || pFrame->GetModelPositionForViewPoint( pPos, 
rPoint, pCMS ) ) && !bSplitFly )
             bRet = true;
         else
             pFrame = pFrame->GetNext();
@@ -217,6 +227,19 @@ bool SwPageFrame::GetModelPositionForViewPoint( SwPosition 
*pPos, Point &rPoint,
             }
 
             const SwContentFrame *pCnt = GetContentPos( aPoint, false, false, 
pCMS, false );
+
+            auto pTextFrame = pCnt ? pCnt->DynCastTextFrame() : nullptr;
+            if (pTextFrame)
+            {
+                SwFlyAtContentFrame* pFly = 
pTextFrame->HasNonLastSplitFlyDrawObj();
+                if (pFly)
+                {
+                    // No exact match, looking for a nearest doc model 
position. Consider our fly
+                    // frame.
+                    pCnt = pFly->GetContentPos( aPoint, false, false, pCMS, 
false );
+                }
+            }
+
             // GetContentPos may have modified pCMS
             if ( pCMS && pCMS->m_bStop )
                 return false;

Reply via email to