[evince/gnome-3-28] EvView: Fix cursor movement when logical and visual line order differs



commit 1946b06fc75beb232891a6bdc65bcf97b2ea571d
Author: Colomban Wendling <cwendling hypra fr>
Date:   Tue Sep 4 14:22:04 2018 +0200

    EvView: Fix cursor movement when logical and visual line order differs
    
    Make sure not to move the caret in the wrong direction when restoring
    the visual line X offset, in case the visual and logical order is
    slightly different.
    
    The algorithm used to move the cursor on the next line and restore the
    X position across lines works as follows:
    
    1. Move `cursor_offset` to the next line by incrementing it until
       reaching a line break;
    2. Find the Y coordinate corresponding to the new cursor_offset;
    3. Find the text closest to the new Y coordinate and the previous X
       coordinate.
    4. Move cursor_offset to the text at this new (X, Y) location.
    
    The issue lies in step 3, which can find a position on a different line
    than expected in case several lines have a nearly the same Y position.
    
    Closes #889.

 libview/ev-view.c | 10 ++++++++++
 1 file changed, 10 insertions(+)
---
diff --git a/libview/ev-view.c b/libview/ev-view.c
index 0bae3019..d0f9894a 100644
--- a/libview/ev-view.c
+++ b/libview/ev-view.c
@@ -6208,6 +6208,7 @@ ev_view_move_cursor (EvView         *view,
        gint            prev_page;
        cairo_region_t *damage_region;
        gboolean        clear_selections = FALSE;
+       const gboolean  forward = count >= 0;
 
        if (!view->caret_enabled || view->rotation != 0)
                return FALSE;
@@ -6283,9 +6284,18 @@ ev_view_move_cursor (EvView         *view,
                return TRUE;
 
        if (step == GTK_MOVEMENT_DISPLAY_LINES) {
+               const gint prev_cursor_offset = view->cursor_offset;
+
                position_caret_cursor_at_location (view,
                                                   MAX (rect.x, view->cursor_line_offset),
                                                   rect.y + (rect.height / 2));
+               /* Make sure we didn't move the cursor in the wrong direction
+                * in case the visual order isn't the same as the logical one,
+                * in order to avoid cursor movement loops */
+               if ((forward && prev_cursor_offset > view->cursor_offset) ||
+                   (!forward && prev_cursor_offset < view->cursor_offset)) {
+                       view->cursor_offset = prev_cursor_offset;
+               }
                if (!clear_selections &&
                    prev_offset == view->cursor_offset && prev_page == view->cursor_page) {
                        gtk_widget_error_bell (GTK_WIDGET (view));


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]