]> git.eshelyaron.com Git - emacs.git/commitdiff
Fix bug #9610 with slow cursor motion in buffers with invisible text.
authorEli Zaretskii <eliz@gnu.org>
Tue, 27 Sep 2011 17:18:31 +0000 (20:18 +0300)
committerEli Zaretskii <eliz@gnu.org>
Tue, 27 Sep 2011 17:18:31 +0000 (20:18 +0300)
 src/xdisp.c (handle_invisible_prop): If invisible text ends on a
 newline, reseat the iterator instead of bidi-iterating there one
 character at a time.  (Bug#9610)
 (BUFFER_POS_REACHED_P, move_it_in_display_line_to): Bail when past
 TO_CHARPOS if the bidi iterator is at base embedding level.

src/ChangeLog
src/xdisp.c

index 59169bdcf9fed43bf39b86d7cb6b957f4dd46027..dd2e725647688a8453996004151fca50f177d4fe 100644 (file)
@@ -1,3 +1,11 @@
+2011-09-27  Eli Zaretskii  <eliz@gnu.org>
+
+       * xdisp.c (handle_invisible_prop): If invisible text ends on a
+       newline, reseat the iterator instead of bidi-iterating there one
+       character at a time.  (Bug#9610)
+       (BUFFER_POS_REACHED_P, move_it_in_display_line_to): Bail when past
+       TO_CHARPOS if the bidi iterator is at base embedding level.
+
 2011-09-27  Andreas Schwab  <schwab@linux-m68k.org>
 
        * lread.c (readevalloop): Use correct code for NBSP.
index a556236835c18af7800ee4bba572ef73be15d48d..75f266ff73937049d7714a11cb7d28358ef7c464 100644 (file)
@@ -4056,40 +4056,67 @@ handle_invisible_prop (struct it *it)
          /* The position newpos is now either ZV or on visible text.  */
          if (it->bidi_p && newpos < ZV)
            {
-             /* With bidi iteration, the region of invisible text
-                could start and/or end in the middle of a non-base
-                embedding level.  Therefore, we need to skip
-                invisible text using the bidi iterator, starting at
-                IT's current position, until we find ourselves
-                outside the invisible text.  Skipping invisible text
-                _after_ bidi iteration avoids affecting the visual
-                order of the displayed text when invisible properties
-                are added or removed.  */
-             if (it->bidi_it.first_elt && it->bidi_it.charpos < ZV)
+             EMACS_INT bpos = CHAR_TO_BYTE (newpos);
+
+             if (FETCH_BYTE (bpos) == '\n'
+                 || (newpos > BEGV && FETCH_BYTE (bpos - 1) == '\n'))
                {
-                 /* If we were `reseat'ed to a new paragraph,
-                    determine the paragraph base direction.  We need
-                    to do it now because next_element_from_buffer may
-                    not have a chance to do it, if we are going to
-                    skip any text at the beginning, which resets the
-                    FIRST_ELT flag.  */
-                 bidi_paragraph_init (it->paragraph_embedding,
-                                      &it->bidi_it, 1);
+                 /* If the invisible text ends on a newline or the
+                    character after a newline, we can avoid the
+                    costly, character by character, bidi iteration to
+                    newpos, and instead simply reseat the iterator
+                    there.  That's because all bidi reordering
+                    information is tossed at the newline.  This is a
+                    big win for modes that hide complete lines, like
+                    Outline, Org, etc.  (Implementation note: the
+                    call to reseat_1 is necessary, because it signals
+                    to the bidi iterator that it needs to reinit its
+                    internal information when the next element for
+                    display is requested.  */
+                 struct text_pos tpos;
+
+                 SET_TEXT_POS (tpos, newpos, bpos);
+                 reseat_1 (it, tpos, 0);
                }
-             do
+             else      /* Must use the slow method.  */
                {
-                 bidi_move_to_visually_next (&it->bidi_it);
+                 /* With bidi iteration, the region of invisible text
+                    could start and/or end in the middle of a
+                    non-base embedding level.  Therefore, we need to
+                    skip invisible text using the bidi iterator,
+                    starting at IT's current position, until we find
+                    ourselves outside the invisible text.  Skipping
+                    invisible text _after_ bidi iteration avoids
+                    affecting the visual order of the displayed text
+                    when invisible properties are added or
+                    removed.  */
+                 if (it->bidi_it.first_elt && it->bidi_it.charpos < ZV)
+                   {
+                     /* If we were `reseat'ed to a new paragraph,
+                        determine the paragraph base direction.  We
+                        need to do it now because
+                        next_element_from_buffer may not have a
+                        chance to do it, if we are going to skip any
+                        text at the beginning, which resets the
+                        FIRST_ELT flag.  */
+                     bidi_paragraph_init (it->paragraph_embedding,
+                                          &it->bidi_it, 1);
+                   }
+                 do
+                   {
+                     bidi_move_to_visually_next (&it->bidi_it);
+                   }
+                 while (it->stop_charpos <= it->bidi_it.charpos
+                        && it->bidi_it.charpos < newpos);
+                 IT_CHARPOS (*it) = it->bidi_it.charpos;
+                 IT_BYTEPOS (*it) = it->bidi_it.bytepos;
+                 /* If we overstepped NEWPOS, record its position in
+                    the iterator, so that we skip invisible text if
+                    later the bidi iteration lands us in the
+                    invisible region again. */
+                 if (IT_CHARPOS (*it) >= newpos)
+                   it->prev_stop = newpos;
                }
-             while (it->stop_charpos <= it->bidi_it.charpos
-                    && it->bidi_it.charpos < newpos);
-             IT_CHARPOS (*it) = it->bidi_it.charpos;
-             IT_BYTEPOS (*it) = it->bidi_it.bytepos;
-             /* If we overstepped NEWPOS, record its position in the
-                iterator, so that we skip invisible text if later the
-                bidi iteration lands us in the invisible region
-                again. */
-             if (IT_CHARPOS (*it) >= newpos)
-               it->prev_stop = newpos;
            }
          else
            {
@@ -7880,7 +7907,9 @@ move_it_in_display_line_to (struct it *it,
   ((op & MOVE_TO_POS) != 0                                     \
    && BUFFERP (it->object)                                     \
    && (IT_CHARPOS (*it) == to_charpos                          \
-       || (!it->bidi_p && IT_CHARPOS (*it) > to_charpos)       \
+       || ((!it->bidi_p                                                \
+           || BIDI_AT_BASE_LEVEL (it->bidi_it))                \
+          && IT_CHARPOS (*it) > to_charpos)                    \
        || (it->what == IT_COMPOSITION                          \
           && ((IT_CHARPOS (*it) > to_charpos                   \
                && to_charpos >= it->cmp_it.charpos)            \
@@ -7912,7 +7941,13 @@ move_it_in_display_line_to (struct it *it,
       if ((op & MOVE_TO_POS) != 0
          && BUFFERP (it->object)
          && it->method == GET_FROM_BUFFER
-         && ((!it->bidi_p && IT_CHARPOS (*it) > to_charpos)
+         && (((!it->bidi_p
+               /* When the iterator is at base embedding level, we
+                  are guaranteed that characters are delivered for
+                  display in strictly increasing order of their
+                  buffer positions.  */
+               || BIDI_AT_BASE_LEVEL (it->bidi_it))
+              && IT_CHARPOS (*it) > to_charpos)
              || (it->bidi_p
                  && (prev_method == GET_FROM_IMAGE
                      || prev_method == GET_FROM_STRETCH