Inline functions to examine and change buffer intervals.
[bpt/emacs.git] / src / bidi.c
index a2d8574..4df585d 100644 (file)
@@ -59,8 +59,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 #include <setjmp.h>
 
 #include "lisp.h"
-#include "buffer.h"
 #include "character.h"
+#include "buffer.h"
 #include "dispextern.h"
 
 static int bidi_initialized = 0;
@@ -149,7 +149,7 @@ bidi_get_type (int ch, bidi_dir_t override)
 static inline void
 bidi_check_type (bidi_type_t type)
 {
-  xassert (UNKNOWN_BT <= type && type <= NEUTRAL_ON);
+  eassert (UNKNOWN_BT <= type && type <= NEUTRAL_ON);
 }
 
 /* Given a bidi TYPE of a character, return its category.  */
@@ -204,8 +204,16 @@ bidi_mirror_char (int c)
   val = CHAR_TABLE_REF (bidi_mirror_table, c);
   if (INTEGERP (val))
     {
-      EMACS_INT v = XINT (val);
+      int v;
+
+      /* When debugging, check before assigning to V, so that the check
+        isn't broken by undefined behavior due to int overflow.  */
+      eassert (CHAR_VALID_P (XINT (val)));
+
+      v = XINT (val);
 
+      /* Minimal test we must do in optimized builds, to prevent weird
+        crashes further down the road.  */
       if (v < 0 || v > MAX_CHAR)
        abort ();
 
@@ -255,7 +263,7 @@ bidi_push_embedding_level (struct bidi_it *bidi_it,
                           int level, bidi_dir_t override)
 {
   bidi_it->stack_idx++;
-  xassert (bidi_it->stack_idx < BIDI_MAXLEVEL);
+  eassert (bidi_it->stack_idx < BIDI_MAXLEVEL);
   bidi_it->level_stack[bidi_it->stack_idx].level = level;
   bidi_it->level_stack[bidi_it->stack_idx].override = override;
 }
@@ -353,8 +361,7 @@ bidi_cache_shrink (void)
 {
   if (bidi_cache_size > BIDI_CACHE_CHUNK)
     {
-      bidi_cache
-       = (struct bidi_it *) xrealloc (bidi_cache, BIDI_CACHE_CHUNK * elsz);
+      bidi_cache = xrealloc (bidi_cache, BIDI_CACHE_CHUNK * elsz);
       bidi_cache_size = BIDI_CACHE_CHUNK;
     }
   bidi_cache_reset ();
@@ -450,7 +457,7 @@ bidi_cache_find_level_change (int level, int dir, int before)
       ptrdiff_t i = dir ? bidi_cache_last_idx : bidi_cache_idx - 1;
       int incr = before ? 1 : 0;
 
-      xassert (!dir || bidi_cache_last_idx >= 0);
+      eassert (!dir || bidi_cache_last_idx >= 0);
 
       if (!dir)
        dir = -1;
@@ -572,7 +579,7 @@ bidi_cache_find (ptrdiff_t charpos, int level, struct bidi_it *bidi_it)
 
       bidi_copy_it (bidi_it, &bidi_cache[i]);
       bidi_cache_last_idx = i;
-      /* Don't let scan direction from from the cached state override
+      /* Don't let scan direction from the cached state override
         the current scan direction.  */
       bidi_it->scan_dir = current_scan_dir;
       return bidi_it->type;
@@ -608,7 +615,7 @@ bidi_push_it (struct bidi_it *bidi_it)
   memcpy (&bidi_cache[bidi_cache_idx++], bidi_it, sizeof (struct bidi_it));
 
   /* Push the current cache start onto the stack.  */
-  xassert (bidi_cache_sp < IT_STACK_SIZE);
+  eassert (bidi_cache_sp < IT_STACK_SIZE);
   bidi_cache_start_stack[bidi_cache_sp++] = bidi_cache_start;
 
   /* Start a new level of cache, and make it empty.  */
@@ -932,6 +939,7 @@ bidi_fetch_char (ptrdiff_t bytepos, ptrdiff_t charpos, ptrdiff_t *disp_pos,
   ptrdiff_t endpos
     = (string->s || STRINGP (string->lstring)) ? string->schars : ZV;
   struct text_pos pos;
+  int len;
 
   /* If we got past the last known position of display string, compute
      the position of the next one.  That position could be at CHARPOS.  */
@@ -1003,7 +1011,6 @@ bidi_fetch_char (ptrdiff_t bytepos, ptrdiff_t charpos, ptrdiff_t *disp_pos,
     normal_char:
       if (string->s)
        {
-         int len;
 
          if (!string->unibyte)
            {
@@ -1018,8 +1025,6 @@ bidi_fetch_char (ptrdiff_t bytepos, ptrdiff_t charpos, ptrdiff_t *disp_pos,
        }
       else if (STRINGP (string->lstring))
        {
-         int len;
-
          if (!string->unibyte)
            {
              ch = STRING_CHAR_AND_LENGTH (SDATA (string->lstring) + bytepos,
@@ -1034,8 +1039,8 @@ bidi_fetch_char (ptrdiff_t bytepos, ptrdiff_t charpos, ptrdiff_t *disp_pos,
        }
       else
        {
-         ch = FETCH_MULTIBYTE_CHAR (bytepos);
-         *ch_len = CHAR_BYTES (ch);
+         ch = STRING_CHAR_AND_LENGTH (BYTE_POS_ADDR (bytepos), len);
+         *ch_len = len;
        }
       *nchars = 1;
     }
@@ -1118,6 +1123,12 @@ bidi_find_paragraph_start (ptrdiff_t pos, ptrdiff_t pos_byte)
   return pos_byte;
 }
 
+/* On a 3.4 GHz machine, searching forward for a strong directional
+   character in a long paragraph full of weaks or neutrals takes about
+   1 ms for each 20K characters.  The number below limits each call to
+   bidi_paragraph_init to less than 10 ms even on slow machines.  */
+#define MAX_STRONG_CHAR_SEARCH 100000
+
 /* Determine the base direction, a.k.a. base embedding level, of the
    paragraph we are about to iterate through.  If DIR is either L2R or
    R2L, just use that.  Otherwise, determine the paragraph direction
@@ -1213,6 +1224,8 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
       /* The following loop is run more than once only if NO_DEFAULT_P
         is non-zero, and only if we are iterating on a buffer.  */
       do {
+       ptrdiff_t pos1;
+
        bytepos = pstartbyte;
        if (!string_p)
          pos = BYTE_TO_CHAR (bytepos);
@@ -1221,11 +1234,15 @@ bidi_paragraph_init (bidi_dir_t dir, struct bidi_it *bidi_it, int no_default_p)
                              bidi_it->frame_window_p, &ch_len, &nchars);
        type = bidi_get_type (ch, NEUTRAL_DIR);
 
+       pos1 = pos;
        for (pos += nchars, bytepos += ch_len;
-            (bidi_get_category (type) != STRONG)
-              || (bidi_ignore_explicit_marks_for_paragraph_level
-                  && (type == RLE || type == RLO
-                      || type == LRE || type == LRO));
+            ((bidi_get_category (type) != STRONG)
+             || (bidi_ignore_explicit_marks_for_paragraph_level
+                 && (type == RLE || type == RLO
+                     || type == LRE || type == LRO)))
+              /* Stop when searched too far into an abnormally large
+                 paragraph full of weak or neutral characters.  */
+              && pos - pos1 < MAX_STRONG_CHAR_SEARCH;
             type = bidi_get_type (ch, NEUTRAL_DIR))
          {
            if (pos >= end)
@@ -1952,7 +1969,7 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
              case STRONG_AL:
                /* Actually, STRONG_AL cannot happen here, because
                   bidi_resolve_weak converts it to STRONG_R, per W3.  */
-               xassert (type != STRONG_AL);
+               eassert (type != STRONG_AL);
                next_type = type;
                break;
              case WEAK_EN: