From f461853b11439c4e485a79174d34735395e5bf52 Mon Sep 17 00:00:00 2001 From: Miklos Vajna Date: Fri, 1 Dec 2023 08:40:40 +0100 Subject: 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. Change-Id: I761b211c1b5468d9d8996c59a32ac9be5b83a777 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/160194 Reviewed-by: Miklos Vajna Tested-by: Jenkins --- sw/CppunitTest_sw_core_layout.mk | 1 + ...e-model-position-for-view-point-correction.docx | Bin 0 -> 12696 bytes sw/qa/core/layout/trvlfrm.cxx | 56 +++++++++++++++++++++ sw/source/core/layout/trvlfrm.cxx | 25 ++++++++- 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 sw/qa/core/layout/data/floattable-model-position-for-view-point-correction.docx create mode 100644 sw/qa/core/layout/trvlfrm.cxx 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 + +#include +#include +#include +#include +#include + +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 d79ffab813aa..5f8e3aa995a3 100644 --- a/sw/source/core/layout/trvlfrm.cxx +++ b/sw/source/core/layout/trvlfrm.cxx @@ -51,6 +51,7 @@ #include "../text/itrpaint.hxx" #include #include +#include #include #include @@ -166,8 +167,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(); @@ -218,6 +228,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; -- cgit v1.2.3