editeng/source/editeng/impedit.hxx  |    3 +-
 editeng/source/editeng/impedit2.cxx |   44 ++++++++++++++++++++++++++++++++++--
 editeng/source/editeng/impedit5.cxx |    7 -----
 3 files changed, 45 insertions(+), 9 deletions(-)

New commits:
commit 1d70690e304cd3321d6c5a14e28df717e3d315d9
Author:     Jonathan Clark <jonat...@libreoffice.org>
AuthorDate: Thu May 15 06:40:07 2025 -0600
Commit:     Jonathan Clark <jonat...@libreoffice.org>
CommitDate: Fri May 16 11:15:32 2025 +0200

    tdf#151336 editeng: Fix bad cursor pos when moving to RTL paragraph
    
    This change fixes a bug causing incorrect visual cursor positioning when
    advancing the cursor from an LTR paragraph to an RTL paragraph that
    starts with an LTR run.
    
    When advancing the cursor past the end of a paragraph, the cursor should
    be placed at the conceptual start of the following paragraph.
    Previously, Edit Engine did this by placing the cursor immediately
    before the character at index 0. The result looks correct in many
    situations, but it fails in the case of bidi text: the conceptual start
    of an RTL paragraph is the right edge of the text area, but when the
    paragraph begins with LTR characters, the character at position 0 may
    start arbitrarily far to the left of the expected cursor position.
    
    Edit Engine already contains logic to correctly position the cursor for
    the home/end keys. This change extends that logic to include cases where
    the cursor is moved between paragraphs.
    
    Change-Id: I0d23b87beacd53d7508b74445d25f9024dbaf89c
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185367
    Tested-by: Jenkins
    Reviewed-by: Jonathan Clark <jonat...@libreoffice.org>

diff --git a/editeng/source/editeng/impedit.hxx 
b/editeng/source/editeng/impedit.hxx
index 36804880cd23..b8a48c195154 100644
--- a/editeng/source/editeng/impedit.hxx
+++ b/editeng/source/editeng/impedit.hxx
@@ -1059,7 +1059,8 @@ public:
     void            SetText( const EditTextObject& rTextObject );
     EditSelection   InsertText( const EditTextObject& rTextObject, 
EditSelection aSel );
 
-    EditSelection const & MoveCursor( const KeyEvent& rKeyEvent, EditView* 
pEditView );
+    EditSelection const& MoveCursor(const KeyEvent& rKeyEvent, EditView* 
pEditView,
+                                    CursorFlags* pOutCursorFlags = nullptr);
 
     EditSelection   MoveParagraphs( Range aParagraphs, sal_Int32 nNewPos, 
EditView* pCurView );
 
diff --git a/editeng/source/editeng/impedit2.cxx 
b/editeng/source/editeng/impedit2.cxx
index cb68da749b71..c9b9143b7b8f 100644
--- a/editeng/source/editeng/impedit2.cxx
+++ b/editeng/source/editeng/impedit2.cxx
@@ -806,8 +806,8 @@ void ImpEditEngine::ParaAttribsChanged( ContentNode const * 
pNode, bool bIgnoreU
 
 //  Cursor movements
 
-
-EditSelection const & ImpEditEngine::MoveCursor( const KeyEvent& rKeyEvent, 
EditView* pEditView )
+EditSelection const& ImpEditEngine::MoveCursor(const KeyEvent& rKeyEvent, 
EditView* pEditView,
+                                               CursorFlags* pOutCursorFlags)
 {
     // Actually, only necessary for up/down, but whatever.
     CheckIdleFormatter();
@@ -816,6 +816,40 @@ EditSelection const & ImpEditEngine::MoveCursor( const 
KeyEvent& rKeyEvent, Edit
 
     EditPaM aOldPaM( aPaM );
 
+    // tdf#151336: Moving the cursor may advance to another paragraph. When 
that happens,
+    // special handling is needed for correct visual cursor placement in RTL 
text.
+    auto fnSetStartOfLineFlag = [&]
+    {
+        if (pOutCursorFlags)
+        {
+            pOutCursorFlags->bStartOfLine = true;
+        }
+    };
+
+    auto fnSetParaChangeStartOfLineFlag = [&]
+    {
+        if (pOutCursorFlags && aPaM.GetNode() != aOldPaM.GetNode())
+        {
+            pOutCursorFlags->bStartOfLine = true;
+        }
+    };
+
+    auto fnSetEndOfLineFlag = [&]
+    {
+        if (pOutCursorFlags)
+        {
+            pOutCursorFlags->bEndOfLine = true;
+        }
+    };
+
+    auto fnSetParaChangeEndOfLineFlag = [&]
+    {
+        if (pOutCursorFlags && aPaM.GetNode() != aOldPaM.GetNode())
+        {
+            pOutCursorFlags->bEndOfLine = true;
+        }
+    };
+
     TextDirectionality eTextDirection = 
TextDirectionality::LeftToRight_TopToBottom;
     if (IsEffectivelyVertical() && IsTopToBottom())
         eTextDirection = TextDirectionality::TopToBottom_RightToLeft;
@@ -847,12 +881,16 @@ EditSelection const & ImpEditEngine::MoveCursor( const 
KeyEvent& rKeyEvent, Edit
         case KEY_DOWN:      aPaM = CursorDown( aPaM, pEditView );
                             break;
         case KEY_LEFT:      aPaM = bCtrl ? WordLeft( aPaM ) : CursorLeft( 
aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? 
i18n::CharacterIteratorMode::SKIPCHARACTER : 
i18n::CharacterIteratorMode::SKIPCELL );
+                            fnSetParaChangeEndOfLineFlag();
                             break;
         case KEY_RIGHT:     aPaM = bCtrl ? WordRight( aPaM ) : CursorRight( 
aPaM, aTranslatedKeyEvent.GetKeyCode().IsMod2() ? 
i18n::CharacterIteratorMode::SKIPCHARACTER : 
i18n::CharacterIteratorMode::SKIPCELL );
+                            fnSetParaChangeStartOfLineFlag();
                             break;
         case KEY_HOME:      aPaM = bCtrl ? CursorStartOfDoc() : 
CursorStartOfLine( aPaM );
+                            fnSetStartOfLineFlag();
                             break;
         case KEY_END:       aPaM = bCtrl ? CursorEndOfDoc() : CursorEndOfLine( 
aPaM );
+                            fnSetEndOfLineFlag();
                             break;
         case KEY_PAGEUP:    aPaM = bCtrl ? CursorStartOfDoc() : PageUp( aPaM, 
pEditView );
                             break;
@@ -860,10 +898,12 @@ EditSelection const & ImpEditEngine::MoveCursor( const 
KeyEvent& rKeyEvent, Edit
                             break;
         case css::awt::Key::MOVE_TO_BEGIN_OF_LINE:
                             aPaM = CursorStartOfLine( aPaM );
+                            fnSetStartOfLineFlag();
                             bKeyModifySelection = false;
                             break;
         case css::awt::Key::MOVE_TO_END_OF_LINE:
                             aPaM = CursorEndOfLine( aPaM );
+                            fnSetEndOfLineFlag();
                             bKeyModifySelection = false;
                             break;
         case css::awt::Key::MOVE_WORD_BACKWARD:
diff --git a/editeng/source/editeng/impedit5.cxx 
b/editeng/source/editeng/impedit5.cxx
index 84668f0fa942..5a356281ac76 100644
--- a/editeng/source/editeng/impedit5.cxx
+++ b/editeng/source/editeng/impedit5.cxx
@@ -1030,7 +1030,7 @@ bool ImpEditEngine::PostKeyEvent( const KeyEvent& 
rKeyEvent, EditView* pEditView
                     if ( ImpEditEngine::DoVisualCursorTraveling() && ( ( nCode 
== KEY_LEFT ) || ( nCode == KEY_RIGHT ) /* || ( nCode == KEY_HOME ) || ( nCode 
== KEY_END ) */ ) )
                         bSetCursorFlags = false;    // Will be manipulated 
within visual cursor move
 
-                    aCurSel = MoveCursor( rKeyEvent, pEditView );
+                    aCurSel = MoveCursor(rKeyEvent, pEditView, 
&aNewCursorFlags);
 
                     if ( aCurSel.HasRange() ) {
                         
css::uno::Reference<css::datatransfer::clipboard::XClipboard> 
aSelection(GetSystemPrimarySelection());
@@ -1038,11 +1038,6 @@ bool ImpEditEngine::PostKeyEvent( const KeyEvent& 
rKeyEvent, EditView* pEditView
                     }
 
                     bMoved = true;
-                    if ( nCode == KEY_HOME )
-                        aNewCursorFlags.bStartOfLine = true;
-                    else if ( nCode == KEY_END )
-                        aNewCursorFlags.bEndOfLine = true;
-
                 }
 #if OSL_DEBUG_LEVEL > 1
                 GetLanguage(getImpl().GetEditDoc().GetPos( 
aCurSel.Max().GetNode() ), aCurSel.Max().GetIndex());

Reply via email to