From: Eli Zaretskii Date: Tue, 27 Sep 2011 17:18:31 +0000 (+0300) Subject: Fix bug #9610 with slow cursor motion in buffers with invisible text. X-Git-Tag: emacs-pretest-24.0.91~262 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=88652fd58c34b494ef5e7139e317e0d8b0980200;p=emacs.git Fix bug #9610 with slow cursor motion in buffers with invisible text. 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. --- diff --git a/src/ChangeLog b/src/ChangeLog index 59169bdcf9f..dd2e7256476 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,11 @@ +2011-09-27 Eli Zaretskii + + * 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 * lread.c (readevalloop): Use correct code for NBSP. diff --git a/src/xdisp.c b/src/xdisp.c index a556236835c..75f266ff739 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -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