sw/qa/core/objectpositioning/data/as_char_image.docx |binary
 sw/qa/core/objectpositioning/objectpositioning.cxx   |   23 +++++++++++++++++++
 sw/source/core/crsr/crsrsh.cxx                       |   13 ++++++----
 sw/source/core/text/itrcrsr.cxx                      |    7 ++++-
 4 files changed, 36 insertions(+), 7 deletions(-)

New commits:
commit 3fb0973b7b5620e637c04b067a870fb611be4b35
Author:     Jaume Pujantell <jaume.pujant...@collabora.com>
AuthorDate: Tue Nov 19 16:26:24 2024 +0100
Commit:     Michael Stahl <michael.st...@allotropia.de>
CommitDate: Mon Mar 3 12:49:05 2025 +0100

    tdf#163890 sw: fix anchor inserted shape to paragraph
    
    Since the commit 651527b4efe9700c8c8dff58ce5aa86ad5681f16 "sw: fix
    double-click opening frame dialog, not graphic dialog on images", when
    GetModelPositionForViewPoint is called on an "as-char" graphic it
    returns the graphic node. This makes inserted shapes anchor to page as a
    fallback since they don't find a text node to anchor to.
    
    With this change, the function returns the anchor text node as before if
    the caller explicitly asks for only text frames.
    
    This change breaks testTdf157129 in sw_uiwriter8. After pasting content
    ending with a hidden paragraph, SwCursorShell::UpdateCursorPos() should
    only move the cursor outside the hidden content. Before this change, the
    call to GetLayout()->GetModelPositionForViewPoint didn't change the
    cursor position because SwTextCursor::GetModelPositionForViewPoint
    called pFlyPor->GetFlyCursorOfst and returned success even when it
    failed to get a text node and therefore the cursor didn't change. Now it
    finds a valid text node and changes the cursor to that. But this is the
    wrong behavior, GetModelPositionForViewPoint should not be called if a
    non-hidden paragraph can trivially be found.
    
    Change-Id: I8cf9f0c7dcfe6f4be46435c8506e67606ce8fe9c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176775
    Reviewed-by: Miklos Vajna <vmik...@collabora.com>
    Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com>
    (cherry picked from commit 7ee34038b12c18b34261beb303f1f945d690761c)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/176863
    Tested-by: Jenkins
    (cherry picked from commit dd5f718c4b621313c406ea6ed4d7141b8db78e61)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/182421
    Reviewed-by: Michael Stahl <michael.st...@allotropia.de>

diff --git a/sw/qa/core/objectpositioning/data/as_char_image.docx 
b/sw/qa/core/objectpositioning/data/as_char_image.docx
new file mode 100644
index 000000000000..e5e02d2168e1
Binary files /dev/null and 
b/sw/qa/core/objectpositioning/data/as_char_image.docx differ
diff --git a/sw/qa/core/objectpositioning/objectpositioning.cxx 
b/sw/qa/core/objectpositioning/objectpositioning.cxx
index 565a3fe4fca6..ae228ebaf7fb 100644
--- a/sw/qa/core/objectpositioning/objectpositioning.cxx
+++ b/sw/qa/core/objectpositioning/objectpositioning.cxx
@@ -12,6 +12,7 @@
 #include <com/sun/star/text/VertOrientation.hpp>
 #include <com/sun/star/drawing/XDrawPageSupplier.hpp>
 
+#include <comphelper/propertysequence.hxx>
 #include <editeng/ulspitem.hxx>
 
 #include <wrtsh.hxx>
@@ -489,6 +490,28 @@ CPPUNIT_TEST_FIXTURE(Test, 
testDoNotCaptureDrawObjsOnPageDrawWrapNone)
     // some <1px difference).
     CPPUNIT_ASSERT_GREATER(nPage2Top - MINFLY, nDrawObjTop);
 }
+
+CPPUNIT_TEST_FIXTURE(Test, testInsertShapeOnAsCharImg_tdf16890)
+{
+    // Given a document with an image anchored as character
+    createSwDoc("as_char_image.docx");
+    SwDoc* pDoc = getSwDoc();
+
+    // Insert a shape over it
+    uno::Sequence<beans::PropertyValue> aArgs(
+        comphelper::InitPropertySequence({ { "KeyModifier", uno::Any(KEY_MOD1) 
} }));
+    dispatchCommand(mxComponent, ".uno:BasicShapes.rectangle", aArgs);
+
+    // Check that hte new shape is anchored at para (i.e. has an anchor node)
+    const auto& rFrmFormats = *pDoc->GetSpzFrameFormats();
+    CPPUNIT_ASSERT_EQUAL(size_t(o3tl::make_unsigned(2)), rFrmFormats.size());
+    auto pShape = rFrmFormats[1];
+    CPPUNIT_ASSERT(pShape);
+    // Without the accompanying fix in place, this test would have failed with:
+    // assertion failed
+    // - Expression: pShape->GetAnchor().GetAnchorNode()
+    CPPUNIT_ASSERT(pShape->GetAnchor().GetAnchorNode());
+}
 }
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/sw/source/core/crsr/crsrsh.cxx b/sw/source/core/crsr/crsrsh.cxx
index f2945f306a2c..54f03657ef53 100644
--- a/sw/source/core/crsr/crsrsh.cxx
+++ b/sw/source/core/crsr/crsrsh.cxx
@@ -1851,11 +1851,6 @@ void SwCursorShell::UpdateCursorPos()
 
     if (isInHiddenFrame(pShellCursor) && !ExtendedSelectedAll())
     {
-        SwCursorMoveState aTmpState(CursorMoveState::SetOnlyText);
-        aTmpState.m_bSetInReadOnly = IsReadOnlyAvailable();
-        GetLayout()->GetModelPositionForViewPoint( pShellCursor->GetPoint(), 
pShellCursor->GetPtPos(),
-                                     &aTmpState );
-        pShellCursor->DeleteMark();
         // kde45196-1.html: try to get to a non-hidden paragraph, there must
         // be one in the document body
         while (isInHiddenFrame(pShellCursor))
@@ -1872,6 +1867,14 @@ void SwCursorShell::UpdateCursorPos()
                 break;
             }
         }
+        if (isInHiddenFrame(pShellCursor))
+        {
+            SwCursorMoveState aTmpState(CursorMoveState::SetOnlyText);
+            aTmpState.m_bSetInReadOnly = IsReadOnlyAvailable();
+            GetLayout()->GetModelPositionForViewPoint(pShellCursor->GetPoint(),
+                                                      
pShellCursor->GetPtPos(), &aTmpState);
+            pShellCursor->DeleteMark();
+        }
     }
     auto* pDoc = GetDoc();
     if (pDoc)
diff --git a/sw/source/core/text/itrcrsr.cxx b/sw/source/core/text/itrcrsr.cxx
index ddb54f8eb0d6..a96433017296 100644
--- a/sw/source/core/text/itrcrsr.cxx
+++ b/sw/source/core/text/itrcrsr.cxx
@@ -1874,8 +1874,11 @@ TextFrameIndex 
SwTextCursor::GetModelPositionForViewPoint( SwPosition *pPos, con
                 SwFrame* pLower = pTmp->GetLower();
                 // Allow non-text-frames to get SwGrfNode for as-char anchored 
images into pPos
                 // instead of the closest SwTextNode, to be consistent with 
at-char behavior.
-                bool bChgNodeInner = pLower
-                    && (pLower->IsTextFrame() || pLower->IsLayoutFrame() || 
pLower->IsNoTextFrame());
+                bool bChgNodeInner
+                    = pLower
+                      && (pLower->IsTextFrame() || pLower->IsLayoutFrame()
+                          || (pLower->IsNoTextFrame()
+                              && (!pCMS || pCMS->m_eState != 
CursorMoveState::SetOnlyText)));
                 Point aTmpPoint( rPoint );
 
                 if ( m_pFrame->IsRightToLeft() )

Reply via email to