]> code.delx.au - gnu-emacs/blobdiff - src/bidi.c
Have 'make' output better GEN names
[gnu-emacs] / src / bidi.c
index a1fe68faab4ec6969e281461553feeb7f1ad7ddc..cbc1820c2a5dfe3d67b5a4dca11dc0445540b49f 100644 (file)
@@ -1,5 +1,5 @@
 /* Low-level bidirectional buffer/string-scanning functions for GNU Emacs.
-   Copyright (C) 2000-2001, 2004-2005, 2009-2014 Free Software
+   Copyright (C) 2000-2001, 2004-2005, 2009-2015 Free Software
    Foundation, Inc.
 
 This file is part of GNU Emacs.
@@ -76,6 +76,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
      bidi_fetch_char         -- fetch next character
      bidi_resolve_explicit   -- resolve explicit levels and directions
      bidi_resolve_weak       -- resolve weak types
+     bidi_resolve_brackets   -- resolve "paired brackets" neutral types
      bidi_resolve_neutral    -- resolve neutral types
      bidi_level_of_next_char -- resolve implicit levels
 
@@ -261,7 +262,6 @@ typedef enum {
 } bidi_category_t;
 
 static Lisp_Object paragraph_start_re, paragraph_separate_re;
-static Lisp_Object Qparagraph_start, Qparagraph_separate;
 
 \f
 /***********************************************************************
@@ -358,6 +358,12 @@ bidi_get_category (bidi_type_t type)
     }
 }
 
+static bool
+bidi_isolate_fmt_char (bidi_type_t ch_type)
+{
+  return (ch_type == LRI || ch_type == RLI || ch_type == PDI || ch_type == FSI);
+}
+
 /* Return the mirrored character of C, if it has one.  If C has no
    mirrored counterpart, return C.
    Note: The conditions in UAX#9 clause L4 regarding the surrounding
@@ -394,6 +400,18 @@ bidi_mirror_char (int c)
   return c;
 }
 
+/* Return the Bidi_Paired_Bracket_Type property of the character C.  */
+static bidi_bracket_type_t
+bidi_paired_bracket_type (int c)
+{
+  if (c == BIDI_EOB)
+    return BIDI_BRACKET_NONE;
+  if (c < 0 || c > MAX_CHAR)
+    emacs_abort ();
+
+  return (bidi_bracket_type_t) XINT (CHAR_TABLE_REF (bidi_brackets_table, c));
+}
+
 /* Determine the start-of-sequence (sos) directional type given the two
    embedding levels on either side of the run boundary.  Also, update
    the saved info about previously seen characters, since that info is
@@ -406,16 +424,17 @@ bidi_set_sos_type (struct bidi_it *bidi_it, int level_before, int level_after)
   /* FIXME: should the default sos direction be user selectable?  */
   bidi_it->sos = ((higher_level & 1) != 0 ? R2L : L2R); /* X10 */
 
-  bidi_it->prev.type = bidi_it->prev.type_after_w1 = UNKNOWN_BT;
-  bidi_it->last_strong.type = bidi_it->last_strong.type_after_w1
-    = bidi_it->last_strong.orig_type = UNKNOWN_BT;
+  bidi_it->prev.type = UNKNOWN_BT;
+  bidi_it->last_strong.type = bidi_it->last_strong.orig_type = UNKNOWN_BT;
   bidi_it->prev_for_neutral.type = (bidi_it->sos == R2L ? STRONG_R : STRONG_L);
   bidi_it->prev_for_neutral.charpos = bidi_it->charpos;
-  bidi_it->prev_for_neutral.bytepos = bidi_it->bytepos;
-  bidi_it->next_for_neutral.type = bidi_it->next_for_neutral.type_after_w1
+  bidi_it->next_for_neutral.type
     = bidi_it->next_for_neutral.orig_type = UNKNOWN_BT;
 }
 
+#define ISOLATE_STATUS(BIDI_IT, IDX)  ((BIDI_IT)->level_stack[IDX].flags & 1)
+#define OVERRIDE(BIDI_IT, IDX)  (((BIDI_IT)->level_stack[IDX].flags >> 1) & 3)
+
 /* Push the current embedding level and override status; reset the
    current level to LEVEL and the current override status to OVERRIDE.  */
 static void
@@ -430,14 +449,14 @@ bidi_push_embedding_level (struct bidi_it *bidi_it,
   st = &bidi_it->level_stack[bidi_it->stack_idx];
   eassert (level <= (1 << 7));
   st->level = level;
-  st->override = override;
-  st->isolate_status = isolate_status;
+  st->flags = (((override & 3) << 1) | (isolate_status != 0));
   if (isolate_status)
     {
-      st->last_strong = bidi_it->last_strong;
-      st->prev_for_neutral = bidi_it->prev_for_neutral;
-      st->next_for_neutral = bidi_it->next_for_neutral;
-      st->sos = bidi_it->sos;
+      st->last_strong_type = bidi_it->last_strong.type;
+      st->prev_for_neutral_type = bidi_it->prev_for_neutral.type;
+      st->next_for_neutral_type = bidi_it->next_for_neutral.type;
+      st->next_for_neutral_pos = bidi_it->next_for_neutral.charpos;
+      st->flags |= ((bidi_it->sos == L2R ? 0 : 1) << 3);
     }
   /* We've got a new isolating sequence, compute the directional type
      of sos and initialize per-sequence variables (UAX#9, clause X10).  */
@@ -456,8 +475,7 @@ bidi_pop_embedding_level (struct bidi_it *bidi_it)
      and PDIs (X6a, 2nd bullet).  */
   if (bidi_it->stack_idx > 0)
     {
-      bool isolate_status
-       = bidi_it->level_stack[bidi_it->stack_idx].isolate_status;
+      bool isolate_status = ISOLATE_STATUS (bidi_it, bidi_it->stack_idx);
       int old_level = bidi_it->level_stack[bidi_it->stack_idx].level;
 
       struct bidi_stack st;
@@ -465,6 +483,7 @@ bidi_pop_embedding_level (struct bidi_it *bidi_it)
       st = bidi_it->level_stack[bidi_it->stack_idx];
       if (isolate_status)
        {
+         bidi_dir_t sos = ((st.flags >> 3) & 1);
          /* PREV is used in W1 for resolving WEAK_NSM.  By the time
             we get to an NSM, we must have gotten past at least one
             character: the PDI that ends the isolate from which we
@@ -472,12 +491,12 @@ bidi_pop_embedding_level (struct bidi_it *bidi_it)
             the time we first use it.  We initialize it here to
             UNKNOWN_BT to be able to catch any blunders in this
             logic.  */
-         bidi_it->prev.orig_type = bidi_it->prev.type_after_w1
-           = bidi_it->prev.type = UNKNOWN_BT;
-         bidi_it->last_strong = st.last_strong;
-         bidi_it->prev_for_neutral = st.prev_for_neutral;
-         bidi_it->next_for_neutral = st.next_for_neutral;
-         bidi_it->sos = st.sos;
+         bidi_it->prev.orig_type = bidi_it->prev.type = UNKNOWN_BT;
+         bidi_it->last_strong.type = st.last_strong_type;
+         bidi_it->prev_for_neutral.type = st.prev_for_neutral_type;
+         bidi_it->next_for_neutral.type = st.next_for_neutral_type;
+         bidi_it->next_for_neutral.charpos = st.next_for_neutral_pos;
+         bidi_it->sos = (sos == 0 ? L2R : R2L);
        }
       else
        bidi_set_sos_type (bidi_it, old_level,
@@ -493,17 +512,16 @@ bidi_pop_embedding_level (struct bidi_it *bidi_it)
 /* Record in SAVED_INFO the information about the current character.  */
 static void
 bidi_remember_char (struct bidi_saved_info *saved_info,
-                   struct bidi_it *bidi_it)
+                   struct bidi_it *bidi_it, bool from_type)
 {
   saved_info->charpos = bidi_it->charpos;
-  saved_info->bytepos = bidi_it->bytepos;
-  saved_info->type = bidi_it->type;
-  bidi_check_type (bidi_it->type);
-  saved_info->type_after_w1 = bidi_it->type_after_w1;
-  bidi_check_type (bidi_it->type_after_w1);
+  if (from_type)
+    saved_info->type = bidi_it->type;
+  else
+    saved_info->type = bidi_it->type_after_wn;
+  bidi_check_type (saved_info->type);
   saved_info->orig_type = bidi_it->orig_type;
-  bidi_check_type (bidi_it->orig_type);
-  saved_info->bracket_resolved = bidi_it->bracket_resolved;
+  bidi_check_type (saved_info->orig_type);
 }
 
 /* Copy the bidi iterator from FROM to TO.  To save cycles, this only
@@ -527,6 +545,30 @@ bidi_copy_it (struct bidi_it *to, struct bidi_it *from)
    characters).  200 was chosen as an upper limit for reasonably-long
    lines in a text file/buffer.  */
 #define BIDI_CACHE_CHUNK 200
+/* Maximum size we allow the cache to become, per iterator stack slot,
+   in units of struct bidi_it size.  If we allow unlimited growth, we
+   could run out of memory for pathologically long bracketed text or
+   very long text lines that need to be reordered.  This is aggravated
+   when word-wrap is in effect, since then functions display_line and
+   move_it_in_display_line_to need to keep up to 4 copies of the
+   cache.
+
+   This limitation means there can be no more than that amount of
+   contiguous RTL text on any single physical line in a LTR paragraph,
+   and similarly with contiguous LTR + numeric text in a RTL
+   paragraph.  (LTR text in a LTR paragraph and RTL text in a RTL
+   paragraph are not reordered, and so don't need the cache, and
+   cannot hit this limit.)  More importantly, no single line can have
+   text longer than this inside paired brackets (because bracket pairs
+   resolution uses the cache).  If the limit is exceeded, the fallback
+   code will produce visual order that will be incorrect if there are
+   RTL characters in the offending line of text.  */
+/* Do we need to allow customization of this limit?  */
+#define BIDI_CACHE_MAX_ELTS_PER_SLOT 50000
+#if BIDI_CACHE_CHUNK >= BIDI_CACHE_MAX_ELTS_PER_SLOT
+# error BIDI_CACHE_CHUNK must be less than BIDI_CACHE_MAX_ELTS_PER_SLOT
+#endif
+static ptrdiff_t bidi_cache_max_elts = BIDI_CACHE_MAX_ELTS_PER_SLOT;
 static struct bidi_it *bidi_cache;
 static ptrdiff_t bidi_cache_size = 0;
 enum { elsz = sizeof (struct bidi_it) };
@@ -547,9 +589,19 @@ enum
     bidi_shelve_header_size
       = (sizeof (bidi_cache_idx) + sizeof (bidi_cache_start_stack)
         + sizeof (bidi_cache_sp) + sizeof (bidi_cache_start)
-        + sizeof (bidi_cache_last_idx))
+        + sizeof (bidi_cache_last_idx) + sizeof (bidi_cache_max_elts))
   };
 
+/* Effectively remove the cached states beyond the Nth state from the
+   part of the cache relevant to iteration of the current object
+   (buffer or string).  */
+static void
+bidi_cache_reset_to (int n)
+{
+  bidi_cache_idx = bidi_cache_start + n;
+  bidi_cache_last_idx = -1;
+}
+
 /* Reset the cache state to the empty state.  We only reset the part
    of the cache relevant to iteration of the current object.  Previous
    objects, which are pushed on the display iterator's stack, are left
@@ -559,8 +611,7 @@ enum
 static void
 bidi_cache_reset (void)
 {
-  bidi_cache_idx = bidi_cache_start;
-  bidi_cache_last_idx = -1;
+  bidi_cache_reset_to (0);
 }
 
 /* Shrink the cache to its minimal size.  Called when we init the bidi
@@ -576,6 +627,7 @@ bidi_cache_shrink (void)
       bidi_cache_size = BIDI_CACHE_CHUNK;
     }
   bidi_cache_reset ();
+  bidi_cache_max_elts = BIDI_CACHE_MAX_ELTS_PER_SLOT;
 }
 
 static void
@@ -594,7 +646,9 @@ bidi_cache_fetch_state (ptrdiff_t idx, struct bidi_it *bidi_it)
 /* Find a cached state with a given CHARPOS and resolved embedding
    level less or equal to LEVEL.  If LEVEL is -1, disregard the
    resolved levels in cached states.  DIR, if non-zero, means search
-   in that direction from the last cache hit.  */
+   in that direction from the last cache hit.
+
+   Value is the index of the cached state, or -1 if not found.  */
 static ptrdiff_t
 bidi_cache_search (ptrdiff_t charpos, int level, int dir)
 {
@@ -668,7 +722,8 @@ bidi_cache_find_level_change (int level, int dir, bool before)
       ptrdiff_t i = dir ? bidi_cache_last_idx : bidi_cache_idx - 1;
       int incr = before ? 1 : 0;
 
-      eassert (!dir || bidi_cache_last_idx >= 0);
+      if (i < 0)  /* cache overflowed? */
+       i = 0;
 
       if (!dir)
        dir = -1;
@@ -706,24 +761,39 @@ bidi_cache_ensure_space (ptrdiff_t idx)
   /* Enlarge the cache as needed.  */
   if (idx >= bidi_cache_size)
     {
-      /* The bidi cache cannot be larger than the largest Lisp string
-        or buffer.  */
-      ptrdiff_t string_or_buffer_bound
-       = max (BUF_BYTES_MAX, STRING_BYTES_BOUND);
+      ptrdiff_t chunk_size = BIDI_CACHE_CHUNK;
 
-      /* Also, it cannot be larger than what C can represent.  */
-      ptrdiff_t c_bound
-       = (min (PTRDIFF_MAX, SIZE_MAX) - bidi_shelve_header_size) / elsz;
+      if (bidi_cache_size > bidi_cache_max_elts - chunk_size)
+       chunk_size = bidi_cache_max_elts - bidi_cache_size;
 
-      bidi_cache
-       = xpalloc (bidi_cache, &bidi_cache_size,
-                  max (BIDI_CACHE_CHUNK, idx - bidi_cache_size + 1),
-                  min (string_or_buffer_bound, c_bound), elsz);
+      if (max (idx + 1,
+              bidi_cache_size + chunk_size) <= bidi_cache_max_elts)
+       {
+         /* The bidi cache cannot be larger than the largest Lisp
+            string or buffer.  */
+         ptrdiff_t string_or_buffer_bound
+           = max (BUF_BYTES_MAX, STRING_BYTES_BOUND);
+
+         /* Also, it cannot be larger than what C can represent.  */
+         ptrdiff_t c_bound
+           = (min (PTRDIFF_MAX, SIZE_MAX) - bidi_shelve_header_size) / elsz;
+         ptrdiff_t max_elts = bidi_cache_max_elts;
+
+         max_elts = min (max_elts, min (string_or_buffer_bound, c_bound));
+
+         /* Force xpalloc not to over-allocate by passing it MAX_ELTS
+            as its 4th argument.  */
+         bidi_cache = xpalloc (bidi_cache, &bidi_cache_size,
+                               max (chunk_size, idx - bidi_cache_size + 1),
+                               max_elts, elsz);
+         eassert (bidi_cache_size > idx);
+       }
     }
 }
 
-static void
-bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved)
+static int
+bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved,
+                          bool update_only)
 {
   ptrdiff_t idx;
 
@@ -732,6 +802,9 @@ bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved)
     emacs_abort ();
   idx = bidi_cache_search (bidi_it->charpos, -1, 1);
 
+  if (idx < 0 && update_only)
+    return 0;
+
   if (idx < 0)
     {
       idx = bidi_cache_idx;
@@ -739,19 +812,23 @@ bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved)
       /* Character positions should correspond to cache positions 1:1.
         If we are outside the range of cached positions, the cache is
         useless and must be reset.  */
-      if (idx > bidi_cache_start &&
-         (bidi_it->charpos > (bidi_cache[idx - 1].charpos
-                              + bidi_cache[idx - 1].nchars)
-          || bidi_it->charpos < bidi_cache[bidi_cache_start].charpos))
+      if (bidi_cache_start < idx && idx < bidi_cache_size
+         && (bidi_it->charpos > (bidi_cache[idx - 1].charpos
+                                 + bidi_cache[idx - 1].nchars)
+             || bidi_it->charpos < bidi_cache[bidi_cache_start].charpos))
        {
          bidi_cache_reset ();
          idx = bidi_cache_start;
        }
       if (bidi_it->nchars <= 0)
        emacs_abort ();
-      bidi_copy_it (&bidi_cache[idx], bidi_it);
-      if (!resolved)
-       bidi_cache[idx].resolved_level = -1;
+      /* Don't cache if no available space in the cache.  */
+      if (bidi_cache_size > idx)
+       {
+         bidi_copy_it (&bidi_cache[idx], bidi_it);
+         if (!resolved)
+           bidi_cache[idx].resolved_level = -1;
+       }
     }
   else
     {
@@ -759,8 +836,8 @@ bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved)
         costly copying of the entire struct.  */
       bidi_cache[idx].type = bidi_it->type;
       bidi_check_type (bidi_it->type);
-      bidi_cache[idx].type_after_w1 = bidi_it->type_after_w1;
-      bidi_check_type (bidi_it->type_after_w1);
+      bidi_cache[idx].type_after_wn = bidi_it->type_after_wn;
+      bidi_check_type (bidi_it->type_after_wn);
       if (resolved)
        bidi_cache[idx].resolved_level = bidi_it->resolved_level;
       else
@@ -770,31 +847,43 @@ bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved)
       bidi_cache[idx].next_for_ws = bidi_it->next_for_ws;
       bidi_cache[idx].disp_pos = bidi_it->disp_pos;
       bidi_cache[idx].disp_prop = bidi_it->disp_prop;
-      bidi_cache[idx].bracket_resolved = bidi_it->bracket_resolved;
+      bidi_cache[idx].bracket_pairing_pos = bidi_it->bracket_pairing_pos;
+      bidi_cache[idx].bracket_enclosed_type = bidi_it->bracket_enclosed_type;
     }
 
-  bidi_cache_last_idx = idx;
-  if (idx >= bidi_cache_idx)
-    bidi_cache_idx = idx + 1;
+  if (bidi_cache_size > idx)
+    {
+      bidi_cache_last_idx = idx;
+      if (idx >= bidi_cache_idx)
+       bidi_cache_idx = idx + 1;
+      return 1;
+    }
+  else
+    {
+      /* The cache overflowed.  */
+      bidi_cache_last_idx = -1;
+      return 0;
+    }
 }
 
 /* Look for a cached iterator state that corresponds to CHARPOS.  If
    found, copy the cached state into BIDI_IT and return the type of
-   the cached entry.  If not found, return UNKNOWN_BT.  NEUTRALS_OK
-   non-zero means it is OK to return cached state for neutral
-   characters that have no valid next_for_neutral member, and
-   therefore cannot be resolved.  This can happen if the state was
-   cached before it was resolved in bidi_resolve_neutral.  */
+   the cached entry.  If not found, return UNKNOWN_BT.  RESOLVED_ONLY
+   zero means it is OK to return cached states that were not fully
+   resolved yet.  This can happen if the state was cached before it
+   was resolved in bidi_resolve_neutral.  */
 static bidi_type_t
-bidi_cache_find (ptrdiff_t charpos, bool neutrals_ok, struct bidi_it *bidi_it)
+bidi_cache_find (ptrdiff_t charpos, bool resolved_only, struct bidi_it *bidi_it)
 {
   ptrdiff_t i = bidi_cache_search (charpos, -1, bidi_it->scan_dir);
 
   if (i >= bidi_cache_start
-      && (neutrals_ok
-         || !(bidi_cache[i].resolved_level == -1
-              && bidi_get_category (bidi_cache[i].type) == NEUTRAL
-              && bidi_cache[i].next_for_neutral.type == UNKNOWN_BT)))
+      && (!resolved_only
+         /* Callers that want only fully resolved states (and set
+            resolved_only = true) need to be sure that there's enough
+            info in the cached state to return the state as final,
+            and if not, they don't want the cached state.  */
+         || bidi_cache[i].resolved_level >= 0))
     {
       bidi_dir_t current_scan_dir = bidi_it->scan_dir;
 
@@ -812,8 +901,13 @@ bidi_cache_find (ptrdiff_t charpos, bool neutrals_ok, struct bidi_it *bidi_it)
 static int
 bidi_peek_at_next_level (struct bidi_it *bidi_it)
 {
-  if (bidi_cache_idx == bidi_cache_start || bidi_cache_last_idx == -1)
+  if (bidi_cache_idx == bidi_cache_start)
     emacs_abort ();
+  /* If the cache overflowed, return the level of the last cached
+     character.  */
+  if (bidi_cache_last_idx == -1
+      || (bidi_cache_last_idx >= bidi_cache_idx - 1 && bidi_it->scan_dir > 0))
+    return bidi_cache[bidi_cache_idx - 1].resolved_level;
   return bidi_cache[bidi_cache_last_idx + bidi_it->scan_dir].resolved_level;
 }
 
@@ -830,6 +924,8 @@ bidi_peek_at_next_level (struct bidi_it *bidi_it)
 void
 bidi_push_it (struct bidi_it *bidi_it)
 {
+  /* Give this stack slot its cache room.  */
+  bidi_cache_max_elts += BIDI_CACHE_MAX_ELTS_PER_SLOT;
   /* Save the current iterator state in its entirety after the last
      used cache slot.  */
   bidi_cache_ensure_space (bidi_cache_idx);
@@ -866,6 +962,9 @@ bidi_pop_it (struct bidi_it *bidi_it)
 
   /* Invalidate the last-used cache slot data.  */
   bidi_cache_last_idx = -1;
+
+  bidi_cache_max_elts -= BIDI_CACHE_MAX_ELTS_PER_SLOT;
+  eassert (bidi_cache_max_elts > 0);
 }
 
 static ptrdiff_t bidi_cache_total_alloc;
@@ -905,6 +1004,11 @@ bidi_shelve_cache (void)
          + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp)
          + sizeof (bidi_cache_start),
          &bidi_cache_last_idx, sizeof (bidi_cache_last_idx));
+  memcpy (databuf + sizeof (bidi_cache_idx)
+         + bidi_cache_idx * sizeof (struct bidi_it)
+         + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp)
+         + sizeof (bidi_cache_start) + sizeof (bidi_cache_last_idx),
+         &bidi_cache_max_elts, sizeof (bidi_cache_max_elts));
 
   return databuf;
 }
@@ -926,6 +1030,7 @@ bidi_unshelve_cache (void *databuf, bool just_free)
          /* A NULL pointer means an empty cache.  */
          bidi_cache_start = 0;
          bidi_cache_sp = 0;
+         bidi_cache_max_elts = BIDI_CACHE_MAX_ELTS_PER_SLOT;
          bidi_cache_reset ();
        }
     }
@@ -965,6 +1070,12 @@ bidi_unshelve_cache (void *databuf, bool just_free)
                  + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp)
                  + sizeof (bidi_cache_start),
                  sizeof (bidi_cache_last_idx));
+         memcpy (&bidi_cache_max_elts,
+                 p + sizeof (bidi_cache_idx)
+                 + bidi_cache_idx * sizeof (struct bidi_it)
+                 + sizeof (bidi_cache_start_stack) + sizeof (bidi_cache_sp)
+                 + sizeof (bidi_cache_start) + sizeof (bidi_cache_last_idx),
+                 sizeof (bidi_cache_max_elts));
          bidi_cache_total_alloc
            -= (bidi_shelve_header_size
                + bidi_cache_idx * sizeof (struct bidi_it));
@@ -996,14 +1107,12 @@ bidi_initialize (void)
     emacs_abort ();
   staticpro (&bidi_brackets_table);
 
-  Qparagraph_start = intern ("paragraph-start");
-  staticpro (&Qparagraph_start);
+  DEFSYM (Qparagraph_start, "paragraph-start");
   paragraph_start_re = Fsymbol_value (Qparagraph_start);
   if (!STRINGP (paragraph_start_re))
     paragraph_start_re = build_string ("\f\\|[ \t]*$");
   staticpro (&paragraph_start_re);
-  Qparagraph_separate = intern ("paragraph-separate");
-  staticpro (&Qparagraph_separate);
+  DEFSYM (Qparagraph_separate, "paragraph-separate");
   paragraph_separate_re = Fsymbol_value (Qparagraph_separate);
   if (!STRINGP (paragraph_separate_re))
     paragraph_separate_re = build_string ("[ \t\f]*$");
@@ -1011,6 +1120,7 @@ bidi_initialize (void)
 
   bidi_cache_sp = 0;
   bidi_cache_total_alloc = 0;
+  bidi_cache_max_elts = BIDI_CACHE_MAX_ELTS_PER_SLOT;
 
   bidi_initialized = 1;
 }
@@ -1044,21 +1154,18 @@ bidi_init_it (ptrdiff_t charpos, ptrdiff_t bytepos, bool frame_window_p,
   bidi_it->new_paragraph = 1;
   bidi_it->separator_limit = -1;
   bidi_it->type = NEUTRAL_B;
-  bidi_it->type_after_w1 = NEUTRAL_B;
+  bidi_it->type_after_wn = NEUTRAL_B;
   bidi_it->orig_type = NEUTRAL_B;
   /* FIXME: Review this!!! */
-  bidi_it->prev.type = bidi_it->prev.type_after_w1
-    = bidi_it->prev.orig_type = UNKNOWN_BT;
-  bidi_it->last_strong.type = bidi_it->last_strong.type_after_w1
-    = bidi_it->last_strong.orig_type = UNKNOWN_BT;
+  bidi_it->prev.type = bidi_it->prev.orig_type = UNKNOWN_BT;
+  bidi_it->last_strong.type = bidi_it->last_strong.orig_type = UNKNOWN_BT;
   bidi_it->next_for_neutral.charpos = -1;
   bidi_it->next_for_neutral.type
-    = bidi_it->next_for_neutral.type_after_w1
     = bidi_it->next_for_neutral.orig_type = UNKNOWN_BT;
   bidi_it->prev_for_neutral.charpos = -1;
   bidi_it->prev_for_neutral.type
-    = bidi_it->prev_for_neutral.type_after_w1
     = bidi_it->prev_for_neutral.orig_type = UNKNOWN_BT;
+  bidi_it->bracket_pairing_pos = -1;
   bidi_it->sos = L2R;   /* FIXME: should it be user-selectable? */
   bidi_it->disp_pos = -1;      /* invalid/unknown */
   bidi_it->disp_prop = 0;
@@ -1077,8 +1184,7 @@ bidi_line_init (struct bidi_it *bidi_it)
   bidi_it->scan_dir = 1; /* FIXME: do we need to have control on this? */
   bidi_it->stack_idx = 0;
   bidi_it->resolved_level = bidi_it->level_stack[0].level;
-  bidi_it->level_stack[0].override = NEUTRAL_DIR; /* X1 */
-  bidi_it->level_stack[0].isolate_status = false; /* X1 */
+  bidi_it->level_stack[0].flags = 0; /* NEUTRAL_DIR, false per X1 */
   bidi_it->invalid_levels = 0;
   bidi_it->isolate_level = 0;   /* X1 */
   bidi_it->invalid_isolates = 0; /* X1 */
@@ -1086,7 +1192,9 @@ bidi_line_init (struct bidi_it *bidi_it)
      we need it for W5.  */
   bidi_it->next_en_pos = 0;
   bidi_it->next_en_type = UNKNOWN_BT;
+  bidi_it->next_for_ws.charpos = -1;
   bidi_it->next_for_ws.type = UNKNOWN_BT;
+  bidi_it->bracket_pairing_pos = -1;
   bidi_set_sos_type (bidi_it,
                     (bidi_it->paragraph_dir == R2L ? 1 : 0),
                     bidi_it->level_stack[0].level); /* X10 */
@@ -1714,6 +1822,58 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
   bool string_p = bidi_it->string.s || STRINGP (bidi_it->string.lstring);
   ptrdiff_t ch_len, nchars, disp_pos, end;
   int disp_prop;
+  ptrdiff_t eob
+    = ((bidi_it->string.s || STRINGP (bidi_it->string.lstring))
+       ? bidi_it->string.schars : ZV);
+
+  /* Record the info about the previous character.  */
+  if (bidi_it->type_after_wn != WEAK_BN /* W1/Retaining */
+      && bidi_it->type != WEAK_BN)
+    {
+      /* This special case is needed in support of Unicode 8.0
+        correction to N0, as implemented in bidi_resolve_weak/W1
+        below.  */
+      if (bidi_it->type_after_wn == NEUTRAL_ON
+         && bidi_get_category (bidi_it->type) == STRONG
+         && bidi_paired_bracket_type (bidi_it->ch) == BIDI_BRACKET_CLOSE)
+       bidi_remember_char (&bidi_it->prev, bidi_it, 1);
+      else
+       bidi_remember_char (&bidi_it->prev, bidi_it, 0);
+    }
+  if (bidi_it->type_after_wn == STRONG_R
+      || bidi_it->type_after_wn == STRONG_L
+      || bidi_it->type_after_wn == STRONG_AL)
+    bidi_remember_char (&bidi_it->last_strong, bidi_it, 0);
+  if (bidi_it->type == STRONG_R || bidi_it->type == STRONG_L
+      || bidi_it->type == WEAK_EN || bidi_it->type == WEAK_AN)
+    bidi_remember_char (&bidi_it->prev_for_neutral, bidi_it, 1);
+
+  /* If we overstepped the characters used for resolving neutrals
+     and whitespace, invalidate their info in the iterator.  */
+  if (bidi_it->charpos >= bidi_it->next_for_neutral.charpos)
+    {
+      bidi_it->next_for_neutral.type = UNKNOWN_BT;
+      /* If needed, reset the "magical" value of pairing bracket
+        position, so that bidi_resolve_brackets will resume
+        resolution of brackets according to BPA.  */
+      if (bidi_it->bracket_pairing_pos == eob)
+       bidi_it->bracket_pairing_pos = -1;
+    }
+  if (bidi_it->next_en_pos >= 0
+      && bidi_it->charpos >= bidi_it->next_en_pos)
+    {
+      bidi_it->next_en_pos = 0;
+      bidi_it->next_en_type = UNKNOWN_BT;
+    }
+
+  /* Reset the bracket resolution info, unless we previously decided
+     (in bidi_find_bracket_pairs) that brackets in this level run
+     should be resolved as neutrals.  */
+  if (bidi_it->bracket_pairing_pos != eob)
+    {
+      bidi_it->bracket_pairing_pos = -1;
+      bidi_it->bracket_enclosed_type = UNKNOWN_BT;
+    }
 
   /* If reseat()'ed, don't advance, so as to start iteration from the
      position where we were reseated.  bidi_it->bytepos can be less
@@ -1744,9 +1904,9 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
            }
          eassert (bidi_it->bytepos == CHAR_TO_BYTE (bidi_it->charpos));
        }
-      /* Determine the orginal bidi type of the previous character,
+      /* Determine the original bidi type of the previous character,
         which is needed for handling isolate initiators and PDF.  The
-        type of the previous character will only be non-trivial if
+        type of the previous character will be non-trivial only if
         our caller moved through some previous text in
         get_visually_first_element, in which case bidi_it->prev holds
         the information we want.  */
@@ -1755,7 +1915,7 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
          eassert (bidi_it->prev.charpos == bidi_it->charpos - 1);
          prev_type = bidi_it->prev.orig_type;
          if (prev_type == FSI)
-           prev_type = bidi_it->type_after_w1;
+           prev_type = bidi_it->type_after_wn;
        }
     }
   /* Don't move at end of buffer/string.  */
@@ -1771,14 +1931,14 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
       bidi_it->bytepos += bidi_it->ch_len;
       prev_type = bidi_it->orig_type;
       if (prev_type == FSI)
-       prev_type = bidi_it->type_after_w1;
+       prev_type = bidi_it->type_after_wn;
     }
   else /* EOB or end of string */
     prev_type = NEUTRAL_B;
 
   current_level = bidi_it->level_stack[bidi_it->stack_idx].level; /* X1 */
-  override = bidi_it->level_stack[bidi_it->stack_idx].override;
-  isolate_status = bidi_it->level_stack[bidi_it->stack_idx].isolate_status;
+  isolate_status = ISOLATE_STATUS (bidi_it, bidi_it->stack_idx);
+  override = OVERRIDE (bidi_it, bidi_it->stack_idx);
   new_level = current_level;
 
   if (bidi_it->charpos >= (string_p ? bidi_it->string.schars : ZV))
@@ -1857,14 +2017,14 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
   bidi_it->orig_type = type;
   bidi_check_type (bidi_it->orig_type);
 
-  bidi_it->type_after_w1 = UNKNOWN_BT;
+  bidi_it->type_after_wn = UNKNOWN_BT;
 
   switch (type)
     {
     case RLE:  /* X2 */
     case RLO:  /* X4 */
-      bidi_it->type_after_w1 = type;
-      bidi_check_type (bidi_it->type_after_w1);
+      bidi_it->type_after_wn = type;
+      bidi_check_type (bidi_it->type_after_wn);
       type = WEAK_BN; /* X9/Retaining */
       if (new_level < BIDI_MAXDEPTH
          && bidi_it->invalid_levels == 0
@@ -1873,7 +2033,7 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
          /* Compute the least odd embedding level greater than
             the current level.  */
          new_level = ((new_level + 1) & ~1) + 1;
-         if (bidi_it->type_after_w1 == RLE)
+         if (bidi_it->type_after_wn == RLE)
            override = NEUTRAL_DIR;
          else
            override = R2L;
@@ -1888,8 +2048,8 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
       break;
     case LRE:  /* X3 */
     case LRO:  /* X5 */
-      bidi_it->type_after_w1 = type;
-      bidi_check_type (bidi_it->type_after_w1);
+      bidi_it->type_after_wn = type;
+      bidi_check_type (bidi_it->type_after_wn);
       type = WEAK_BN; /* X9/Retaining */
       if (new_level < BIDI_MAXDEPTH - 1
          && bidi_it->invalid_levels == 0
@@ -1898,7 +2058,7 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
          /* Compute the least even embedding level greater than
             the current level.  */
          new_level = ((new_level + 2) & ~1);
-         if (bidi_it->type_after_w1 == LRE)
+         if (bidi_it->type_after_wn == LRE)
            override = NEUTRAL_DIR;
          else
            override = L2R;
@@ -1933,18 +2093,18 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
       /* FALLTHROUGH */
     case RLI:  /* X5a */
       if (override == NEUTRAL_DIR)
-       bidi_it->type_after_w1 = type;
+       bidi_it->type_after_wn = type;
       else     /* Unicode 8.0 correction.  */
-       bidi_it->type_after_w1 = (override == L2R ? STRONG_L : STRONG_R);
-      bidi_check_type (bidi_it->type_after_w1);
+       bidi_it->type_after_wn = (override == L2R ? STRONG_L : STRONG_R);
+      bidi_check_type (bidi_it->type_after_wn);
       break;
     case LRI:  /* X5b */
     fsi_as_lri:
       if (override == NEUTRAL_DIR)
-       bidi_it->type_after_w1 = type;
+       bidi_it->type_after_wn = type;
       else     /* Unicode 8.0 correction.  */
-       bidi_it->type_after_w1 = (override == L2R ? STRONG_L : STRONG_R);
-      bidi_check_type (bidi_it->type_after_w1);
+       bidi_it->type_after_wn = (override == L2R ? STRONG_L : STRONG_R);
+      bidi_check_type (bidi_it->type_after_wn);
       break;
     case PDI:  /* X6a */
       if (bidi_it->invalid_isolates)
@@ -1952,7 +2112,7 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
       else if (bidi_it->isolate_level > 0)
        {
          bidi_it->invalid_levels = 0;
-         while (!bidi_it->level_stack[bidi_it->stack_idx].isolate_status)
+         while (!ISOLATE_STATUS (bidi_it, bidi_it->stack_idx))
            bidi_pop_embedding_level (bidi_it);
          eassert (bidi_it->stack_idx > 0);
          new_level = bidi_pop_embedding_level (bidi_it);
@@ -1960,16 +2120,19 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
        }
       bidi_it->resolved_level = new_level;
       /* Unicode 8.0 correction.  */
-      if (bidi_it->level_stack[bidi_it->stack_idx].override == L2R)
-       bidi_it->type_after_w1 = STRONG_L;
-      else if (bidi_it->level_stack[bidi_it->stack_idx].override == R2L)
-       bidi_it->type_after_w1 = STRONG_R;
-      else
-       bidi_it->type_after_w1 = type;
+      {
+       bidi_dir_t stack_override = OVERRIDE (bidi_it, bidi_it->stack_idx);
+       if (stack_override == L2R)
+         bidi_it->type_after_wn = STRONG_L;
+       else if (stack_override == R2L)
+         bidi_it->type_after_wn = STRONG_R;
+       else
+         bidi_it->type_after_wn = type;
+      }
       break;
     case PDF:  /* X7 */
-      bidi_it->type_after_w1 = type;
-      bidi_check_type (bidi_it->type_after_w1);
+      bidi_it->type_after_wn = type;
+      bidi_check_type (bidi_it->type_after_wn);
       type = WEAK_BN; /* X9/Retaining */
       break;
     default:
@@ -1984,19 +2147,13 @@ bidi_resolve_explicit (struct bidi_it *bidi_it)
     {
       bidi_set_paragraph_end (bidi_it);
       /* This is needed by bidi_resolve_weak below, and in L1.  */
-      bidi_it->type_after_w1 = bidi_it->type;
+      bidi_it->type_after_wn = bidi_it->type;
     }
 
   eassert (bidi_it->resolved_level >= 0);
   return bidi_it->resolved_level;
 }
 
-static bool
-bidi_isolate_fmt_char (bidi_type_t ch_type)
-{
-  return (ch_type == LRI || ch_type == RLI || ch_type == PDI || ch_type == FSI);
-}
-
 /* Advance in the buffer/string, resolve weak types and return the
    type of the next character after weak type resolution.  */
 static bidi_type_t
@@ -2014,7 +2171,7 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
        ? bidi_it->string.schars : ZV);
 
   type = bidi_it->type;
-  override = bidi_it->level_stack[bidi_it->stack_idx].override;
+  override = OVERRIDE (bidi_it, bidi_it->stack_idx);
 
   eassert (!(type == UNKNOWN_BT
             || type == LRE
@@ -2033,8 +2190,8 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
     }
   if (type == NEUTRAL_S || type == NEUTRAL_WS
       || type == WEAK_BN || type == STRONG_AL)
-    bidi_it->type_after_w1 = type;     /* needed in L1 */
-  bidi_check_type (bidi_it->type_after_w1);
+    bidi_it->type_after_wn = type;     /* needed in L1 */
+  bidi_check_type (bidi_it->type_after_wn);
 
   /* Level and directional override status are already recorded in
      bidi_it, and do not need any change; see X6.  */
@@ -2051,14 +2208,14 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
             because then either the type of this NSM would have been
             also overridden, or the previous character is outside the
             current level run, and thus not relevant to this NSM.
-            This is why NSM gets the type_after_w1 of the previous
+            This is why NSM gets the type_after_wn of the previous
             character.  */
-         /* bidi_set_sos_type sets type_after_w1 to UNKNOWN_BT.  */
-         if (bidi_it->prev.type_after_w1 != UNKNOWN_BT
-             /* If type_after_w1 is NEUTRAL_B, this NSM is at sos.  */
-             && bidi_it->prev.type_after_w1 != NEUTRAL_B)
+         /* bidi_set_sos_type sets type_after_wn to UNKNOWN_BT.  */
+         if (bidi_it->prev.type != UNKNOWN_BT
+             /* If type_after_wn is NEUTRAL_B, this NSM is at sos.  */
+             && bidi_it->prev.type != NEUTRAL_B)
            {
-             if (bidi_isolate_fmt_char (bidi_it->prev.type_after_w1))
+             if (bidi_isolate_fmt_char (bidi_it->prev.type))
                {
                  /* From W1: "Note that in an isolating run sequence,
                     an isolate initiator followed by an NSM or any
@@ -2069,13 +2226,10 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
                }
              else
                {
-                 type = bidi_it->prev.type_after_w1;
-                 /* Unicode 8.0 correction for N0.  */
-                 if (type == NEUTRAL_ON
-                     && bidi_it->prev.bracket_resolved
-                     && (bidi_it->prev.type == STRONG_L
-                         || bidi_it->prev.type == STRONG_R))
-                   type = bidi_it->prev.type;
+                 /* This includes the Unicode 8.0 correction for N0,
+                    due to how we set prev.type in bidi_resolve_explicit,
+                    which see.  */
+                 type = bidi_it->prev.type;
                }
            }
          else if (bidi_it->sos == R2L)
@@ -2086,17 +2240,17 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
            emacs_abort ();
        }
       if (type == WEAK_EN      /* W2 */
-         && bidi_it->last_strong.type_after_w1 == STRONG_AL)
+         && bidi_it->last_strong.type == STRONG_AL)
        type = WEAK_AN;
       else if (type == STRONG_AL) /* W3 */
        type = STRONG_R;
       else if ((type == WEAK_ES        /* W4 */
-               && bidi_it->prev.type_after_w1 == WEAK_EN
+               && bidi_it->prev.type == WEAK_EN
                && bidi_it->prev.orig_type == WEAK_EN)
               || (type == WEAK_CS
-                  && ((bidi_it->prev.type_after_w1 == WEAK_EN
+                  && ((bidi_it->prev.type == WEAK_EN
                        && bidi_it->prev.orig_type == WEAK_EN)
-                      || bidi_it->prev.type_after_w1 == WEAK_AN)))
+                      || bidi_it->prev.type == WEAK_AN)))
        {
          const unsigned char *s
            = (STRINGP (bidi_it->string.lstring)
@@ -2125,11 +2279,11 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
             should not be changed into EN.  */
          if (type == WEAK_ES
              && type_of_next == WEAK_EN
-             && bidi_it->last_strong.type_after_w1 != STRONG_AL)
+             && bidi_it->last_strong.type != STRONG_AL)
            type = WEAK_EN;
          else if (type == WEAK_CS)
            {
-             if (bidi_it->prev.type_after_w1 == WEAK_AN
+             if (bidi_it->prev.type == WEAK_AN
                  && (type_of_next == WEAK_AN
                      /* If the next character is EN, but the last
                         strong-type character is AL, EN will be later
@@ -2137,18 +2291,18 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
                         So in that case, this ES should not be
                         changed into EN.  */
                      || (type_of_next == WEAK_EN
-                         && bidi_it->last_strong.type_after_w1 == STRONG_AL)))
+                         && bidi_it->last_strong.type == STRONG_AL)))
                type = WEAK_AN;
-             else if (bidi_it->prev.type_after_w1 == WEAK_EN
+             else if (bidi_it->prev.type == WEAK_EN
                       && type_of_next == WEAK_EN
-                      && bidi_it->last_strong.type_after_w1 != STRONG_AL)
+                      && bidi_it->last_strong.type != STRONG_AL)
                type = WEAK_EN;
            }
        }
       else if (type == WEAK_ET /* W5: ET with EN before or after it */
               || type == WEAK_BN)      /* W5/Retaining */
        {
-         if (bidi_it->prev.type_after_w1 == WEAK_EN) /* ET/BN w/EN before it */
+         if (bidi_it->prev.type == WEAK_EN) /* ET/BN w/EN before it */
            type = WEAK_EN;
          else if (bidi_it->next_en_pos > bidi_it->charpos
                   && bidi_it->next_en_type != WEAK_BN)
@@ -2209,7 +2363,7 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
                {
                  /* If the last strong character is AL, the EN we've
                     found will become AN when we get to it (W2). */
-                 if (bidi_it->last_strong.type_after_w1 == STRONG_AL)
+                 if (bidi_it->last_strong.type == STRONG_AL)
                    type_of_next = WEAK_AN;
                  else if (type == WEAK_BN)
                    type = NEUTRAL_ON; /* W6/Retaining */
@@ -2229,22 +2383,22 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
 
   if (type == WEAK_ES || type == WEAK_ET || type == WEAK_CS /* W6 */
       || (type == WEAK_BN
-         && (bidi_it->prev.type_after_w1 == WEAK_CS        /* W6/Retaining */
-             || bidi_it->prev.type_after_w1 == WEAK_ES
-             || bidi_it->prev.type_after_w1 == WEAK_ET)))
+         && (bidi_it->prev.type == WEAK_CS         /* W6/Retaining */
+             || bidi_it->prev.type == WEAK_ES
+             || bidi_it->prev.type == WEAK_ET)))
     type = NEUTRAL_ON;
 
   /* Store the type we've got so far, before we clobber it with strong
      types in W7 and while resolving neutral types.  But leave alone
      the original types that were recorded above, because we will need
      them for the L1 clause.  */
-  if (bidi_it->type_after_w1 == UNKNOWN_BT)
-    bidi_it->type_after_w1 = type;
-  bidi_check_type (bidi_it->type_after_w1);
+  if (bidi_it->type_after_wn == UNKNOWN_BT)
+    bidi_it->type_after_wn = type;
+  bidi_check_type (bidi_it->type_after_wn);
 
   if (type == WEAK_EN) /* W7 */
     {
-      if ((bidi_it->last_strong.type_after_w1 == STRONG_L)
+      if ((bidi_it->last_strong.type == STRONG_L)
          || (bidi_it->last_strong.type == UNKNOWN_BT && bidi_it->sos == L2R))
        type = STRONG_L;
     }
@@ -2274,36 +2428,58 @@ bidi_resolve_neutral_1 (bidi_type_t prev_type, bidi_type_t next_type, int lev)
     return STRONG_R;
 }
 
-static bidi_bracket_type_t
-bidi_paired_bracket_type (int c)
-{
-  if (c == BIDI_EOB)
-    return BIDI_BRACKET_NONE;
-  if (c < 0 || c > MAX_CHAR)
-    emacs_abort ();
-
-  return (bidi_bracket_type_t) XINT (CHAR_TABLE_REF (bidi_brackets_table, c));
-}
-
 #define FLAG_EMBEDDING_INSIDE  1
 #define FLAG_OPPOSITE_INSIDE   2
-#define FLAG_EMBEDDING_OUTSIDE 4
-#define FLAG_OPPOSITE_OUTSIDE  8
 
 /* A data type used in the stack maintained by
-   bidi_resolve_bracket_pairs below.  */
+   bidi_find_bracket_pairs below.  */
 typedef struct bpa_stack_entry {
   int close_bracket_char;
   int open_bracket_idx;
 #ifdef ENABLE_CHECKING
   ptrdiff_t open_bracket_pos;
 #endif
-  unsigned flags : 4;
+  unsigned flags : 2;
 } bpa_stack_entry;
 
 /* With MAX_ALLOCA of 16KB, this should allow at least 1K slots in the
    BPA stack, which should be more than enough for actual bidi text.  */
-#define MAX_BPA_STACK (max (MAX_ALLOCA / sizeof (bpa_stack_entry), 1))
+#define MAX_BPA_STACK ((int)max (MAX_ALLOCA / sizeof (bpa_stack_entry), 1))
+
+/* UAX#9 says to match opening brackets with the matching closing
+   brackets or their canonical equivalents.  As of Unicode 7.0, there
+   are only 2 bracket characters that have canonical equivalence
+   decompositions: u+2329 and u+232A.  So instead of accessing the
+   table in uni-decomposition.el, we just handle these 2 characters
+   with this simple macro.  Note that ASCII characters don't have
+   canonical equivalents by definition.  */
+
+/* To find all the characters that need to be processed by
+   CANONICAL_EQU, first find all the characters which have
+   decompositions in UnicodeData.txt, with this Awk script:
+
+    awk -F ";" " {if ($6 != \"\") print $1, $6}" UnicodeData.txt
+
+   Then produce a list of all the bracket characters in BidiBrackets.txt:
+
+    awk -F "[ ;]" " {if ($1 != \"#\" && $1 != \"\") print $1}" BidiBrackets.txt
+
+   And finally, cross-reference these two:
+
+    fgrep -w -f brackets.txt decompositions.txt
+
+   where "decompositions.txt" was produced by the 1st script, and
+   "brackets.txt" by the 2nd script.  In the output of fgrep, look
+   only for decompositions that don't begin with some compatibility
+   formatting tag, such as "<compat>".  Only decompositions that
+   consist solely of character codepoints are relevant to bidi
+   brackets processing.  */
+
+#define CANONICAL_EQU(c)                                       \
+  ( ASCII_CHAR_P (c) ? c                                       \
+    : (c) == 0x2329 ? 0x3008                                   \
+    : (c) == 0x232a ? 0x3009                                   \
+    : c )
 
 #ifdef ENABLE_CHECKING
 # define STORE_BRACKET_CHARPOS \
@@ -2312,32 +2488,34 @@ typedef struct bpa_stack_entry {
 # define STORE_BRACKET_CHARPOS /* nothing */
 #endif
 
-#define PUSH_BPA_STACK(EMBEDDING_LEVEL, LAST_STRONG) \
+#define PUSH_BPA_STACK                                                 \
   do {                                                                 \
-   bpa_sp++;                                                           \
-   if (bpa_sp >= MAX_BPA_STACK)                                                \
-     goto bpa_give_up;                                                 \
-   bpa_stack[bpa_sp].close_bracket_char = bidi_mirror_char (bidi_it->ch); \
-   bpa_stack[bpa_sp].open_bracket_idx = bidi_cache_last_idx;           \
-   STORE_BRACKET_CHARPOS;                                              \
-   if (((EMBEDDING_LEVEL) & 1) == 0)                                   \
-     bpa_stack[bpa_sp].flags = ((LAST_STRONG) == STRONG_L              \
-                               ? FLAG_EMBEDDING_OUTSIDE                \
-                               : FLAG_OPPOSITE_OUTSIDE);               \
-   else                                                                        \
-     bpa_stack[bpa_sp].flags = ((LAST_STRONG) == STRONG_L              \
-                               ? FLAG_OPPOSITE_OUTSIDE                 \
-                               : FLAG_EMBEDDING_OUTSIDE);              \
+    int ch;                                                            \
+    if (bpa_sp < MAX_BPA_STACK - 1)                                    \
+      {                                                                        \
+       bpa_sp++;                                                       \
+       ch = CANONICAL_EQU (bidi_it->ch);                               \
+       bpa_stack[bpa_sp].close_bracket_char = bidi_mirror_char (ch);   \
+       bpa_stack[bpa_sp].open_bracket_idx = bidi_cache_last_idx;       \
+       bpa_stack[bpa_sp].flags = 0;                                    \
+       STORE_BRACKET_CHARPOS;                                          \
+      }                                                                        \
   } while (0)
 
 
 /* This function implements BPA, the Bidi Parenthesis Algorithm,
-   described in BD16 and N0 of UAX#9.  */
-static bidi_type_t
-bidi_resolve_bracket_pairs (struct bidi_it *bidi_it)
+   described in BD16 and N0 of UAX#9.  It finds all the bracket pairs
+   in the current isolating sequence, and records the enclosed type
+   and the position of the matching bracket in the cache.  It returns
+   non-zero if called with the iterator on the opening bracket which
+   has a matching closing bracket in the current isolating sequence,
+   zero otherwise.  */
+static bool
+bidi_find_bracket_pairs (struct bidi_it *bidi_it)
 {
   bidi_bracket_type_t btype;
   bidi_type_t type = bidi_it->type;
+  bool retval = false;
 
   /* When scanning backwards, we don't expect any unresolved bidi
      bracket characters.  */
@@ -2350,74 +2528,103 @@ bidi_resolve_bracket_pairs (struct bidi_it *bidi_it)
       bpa_stack_entry bpa_stack[MAX_BPA_STACK];
       int bpa_sp = -1;
       struct bidi_it saved_it;
-      bidi_type_t last_strong;
+      int base_level = bidi_it->level_stack[0].level;
       int embedding_level = bidi_it->level_stack[bidi_it->stack_idx].level;
+      int maxlevel = embedding_level;
+      bidi_type_t embedding_type = (embedding_level & 1) ? STRONG_R : STRONG_L;
+      struct bidi_it tem_it;
+      bool l2r_seen = false, r2l_seen = false;
+      ptrdiff_t pairing_pos;
+      int idx_at_entry = bidi_cache_idx;
 
       eassert (MAX_BPA_STACK >= 100);
       bidi_copy_it (&saved_it, bidi_it);
-      last_strong = bidi_it->prev_for_neutral.type;
+      /* bidi_cache_iterator_state refuses to cache on backward scans,
+        and bidi_cache_fetch_state doesn't bring scan_dir from the
+        cache, so we must initialize this explicitly.  */
+      tem_it.scan_dir = 1;
 
       while (1)
        {
          int old_sidx, new_sidx;
          int current_level = bidi_it->level_stack[bidi_it->stack_idx].level;
 
-         bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B);
+         if (maxlevel < current_level)
+           maxlevel = current_level;
+         /* Mark every opening bracket character we've traversed by
+            putting its own position into bracket_pairing_pos.  This
+            is examined in bidi_resolve_brackets to distinguish
+            brackets that were already resolved to stay NEUTRAL_ON,
+            and those that were not yet processed by this function
+            (because they were skipped when we skip higher embedding
+            levels below).  */
+         if (btype == BIDI_BRACKET_OPEN && bidi_it->bracket_pairing_pos == -1)
+           bidi_it->bracket_pairing_pos = bidi_it->charpos;
+         if (!bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B, 0))
+           {
+             /* No more space in cache -- give up and let the opening
+                bracket that started this be processed as a
+                NEUTRAL_ON.  */
+             bidi_cache_reset_to (idx_at_entry - bidi_cache_start);
+             bidi_copy_it (bidi_it, &saved_it);
+             goto give_up;
+           }
          if (btype == BIDI_BRACKET_OPEN)
-           PUSH_BPA_STACK (embedding_level, last_strong);
+           PUSH_BPA_STACK;
          else if (btype == BIDI_BRACKET_CLOSE)
            {
              int sp = bpa_sp;
-             int curchar = bidi_it->ch;
+             int curchar = CANONICAL_EQU (bidi_it->ch);
 
              eassert (sp >= 0);
              while (sp >= 0 && bpa_stack[sp].close_bracket_char != curchar)
                sp--;
              if (sp >= 0)
                {
-                 /* Resolve the bracket type according to N0.  */
-                 if (bpa_stack[sp].flags & FLAG_EMBEDDING_INSIDE) /* N0b */
-                   type = ((embedding_level & 1) ? STRONG_R : STRONG_L);
-                 else if ((bpa_stack[sp].flags /* N0c1 */
-                           & (FLAG_OPPOSITE_INSIDE | FLAG_OPPOSITE_OUTSIDE))
-                          == (FLAG_OPPOSITE_INSIDE | FLAG_OPPOSITE_OUTSIDE))
-                   type = ((embedding_level & 1) ? STRONG_L : STRONG_R);
-                 else if (bpa_stack[sp].flags & FLAG_OPPOSITE_INSIDE) /* N0c2 */
-                   type = ((embedding_level & 1) ? STRONG_R : STRONG_L);
-
-                 /* Update and cache the closing bracket.  */
-                 bidi_it->type = type;
-                 bidi_it->bracket_resolved = 1;
-                 bidi_cache_iterator_state (bidi_it, 0);
                  /* Update and cache the corresponding opening bracket.  */
                  bidi_cache_fetch_state (bpa_stack[sp].open_bracket_idx,
-                                         bidi_it);
+                                         &tem_it);
 #ifdef ENABLE_CHECKING
-                 eassert (bpa_stack[sp].open_bracket_pos == bidi_it->charpos);
+                 eassert (bpa_stack[sp].open_bracket_pos == tem_it.charpos);
 #endif
-                 bidi_it->type = type;
-                 bidi_it->bracket_resolved = 1;
-                 bidi_cache_iterator_state (bidi_it, 0);
+                 /* Determine the enclosed type for this bracket
+                    pair's type resolution according to N0.  */
+                 if (bpa_stack[sp].flags & FLAG_EMBEDDING_INSIDE)
+                   tem_it.bracket_enclosed_type = embedding_type; /* N0b */
+                 else if (bpa_stack[sp].flags & FLAG_OPPOSITE_INSIDE)
+                   tem_it.bracket_enclosed_type                   /* N0c */
+                     = (embedding_type == STRONG_L ? STRONG_R : STRONG_L);
+                 else                                             /* N0d */
+                   tem_it.bracket_enclosed_type = UNKNOWN_BT;
+
+                 /* Record the position of the matching closing
+                    bracket, and update the cache.  */
+                 tem_it.bracket_pairing_pos = bidi_it->charpos;
+                 bidi_cache_iterator_state (&tem_it, 0, 1);
+
+                 /* Pop the BPA stack.  */
                  bpa_sp = sp - 1;
-                 if (bpa_sp < 0)
-                   break;
                }
-             else
-               bidi_it->bracket_resolved = 1;
+             if (bpa_sp < 0)
+               {
+                 retval = true;
+                 break;
+               }
            }
-         else if (bidi_get_category (bidi_it->type_after_w1) != NEUTRAL)
+         else if (bidi_get_category (bidi_it->type_after_wn) != NEUTRAL)
            {
-             unsigned flag;
+             unsigned flag = 0;
              int sp;
 
-             /* Update the "inside" flags of all the slots on the stack.  */
+             /* Whenever we see a strong type, update the flags of
+                all the slots on the stack.  */
              switch (bidi_it->type)
                {
                case STRONG_L:
                  flag = ((embedding_level & 1) == 0
                          ? FLAG_EMBEDDING_INSIDE
                          : FLAG_OPPOSITE_INSIDE);
-                 last_strong = STRONG_L;
+                 l2r_seen = true;
                  break;
                case STRONG_R:
                case WEAK_EN:
@@ -2425,35 +2632,41 @@ bidi_resolve_bracket_pairs (struct bidi_it *bidi_it)
                  flag = ((embedding_level & 1) == 1
                          ? FLAG_EMBEDDING_INSIDE
                          : FLAG_OPPOSITE_INSIDE);
-                 last_strong = STRONG_R;
+                 r2l_seen = true;
                  break;
                default:
                  break;
                }
-             for (sp = bpa_sp; sp >= 0; sp--)
-               bpa_stack[sp].flags |= flag;
-             /* FIXME: Pay attention to types that can be
-                next_for_neutral, and when found, update cached
-                states for which it is relevant.  */
+             if (flag)
+               {
+                 for (sp = bpa_sp; sp >= 0; sp--)
+                   bpa_stack[sp].flags |= flag;
+               }
            }
-         /* Record the info about the previous character, so that it
-            will be cached with this state.  */
-         if (bidi_it->type_after_w1 != WEAK_BN /* W1/Retaining */
-             && bidi_it->type != WEAK_BN)
-           bidi_remember_char (&bidi_it->prev, bidi_it);
          old_sidx = bidi_it->stack_idx;
          type = bidi_resolve_weak (bidi_it);
          /* Skip level runs excluded from this isolating run sequence.  */
          new_sidx = bidi_it->stack_idx;
          if (bidi_it->level_stack[new_sidx].level > current_level
-             && (bidi_it->level_stack[new_sidx].isolate_status
+             && (ISOLATE_STATUS (bidi_it, new_sidx)
                  || (new_sidx > old_sidx + 1
-                     && bidi_it->level_stack[new_sidx - 1].isolate_status)))
+                     && ISOLATE_STATUS (bidi_it, new_sidx - 1))))
            {
              while (bidi_it->level_stack[bidi_it->stack_idx].level
                     > current_level)
                {
-                 bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B);
+                 if (maxlevel < bidi_it->level_stack[bidi_it->stack_idx].level)
+                   maxlevel = bidi_it->level_stack[bidi_it->stack_idx].level;
+                 if (!bidi_cache_iterator_state (bidi_it,
+                                                 type == NEUTRAL_B, 0))
+                   {
+                     /* No more space in cache -- give up and let the
+                        opening bracket that started this be
+                        processed as any other NEUTRAL_ON.  */
+                     bidi_cache_reset_to (idx_at_entry - bidi_cache_start);
+                     bidi_copy_it (bidi_it, &saved_it);
+                     goto give_up;
+                   }
                  type = bidi_resolve_weak (bidi_it);
                }
            }
@@ -2461,37 +2674,242 @@ bidi_resolve_bracket_pairs (struct bidi_it *bidi_it)
              || (bidi_it->level_stack[bidi_it->stack_idx].level
                  != current_level))
            {
-           bpa_give_up:
              /* We've marched all the way to the end of this
                 isolating run sequence, and didn't find matching
-                closing brackets for some opening brackets.  Unwind
-                whatever is left on the BPA stack, and mark each
-                bracket there as BPA-resolved.  */
-             while (bpa_sp >= 0)
-               {
-                 bidi_cache_fetch_state (bpa_stack[bpa_sp].open_bracket_idx,
-                                         bidi_it);
-#ifdef ENABLE_CHECKING
-                 eassert (bpa_stack[bpa_sp].open_bracket_pos
-                          == bidi_it->charpos);
-#endif
-                 bidi_it->bracket_resolved = 1;
-                 bidi_cache_iterator_state (bidi_it, 0);
-                 bpa_sp--;
-               }
-             type = saved_it.type;
+                closing brackets for some opening brackets.  Leave
+                their type unchanged.  */
+             pairing_pos = bidi_it->charpos;
              break;
            }
-         if (bidi_it->type_after_w1 == NEUTRAL_ON) /* Unicode 8.0 correction */
+         if (bidi_it->type_after_wn == NEUTRAL_ON) /* Unicode 8.0 correction */
            btype = bidi_paired_bracket_type (bidi_it->ch);
          else
            btype = BIDI_BRACKET_NONE;
        }
-      bidi_check_type (type);
 
-      bidi_copy_it (bidi_it, &saved_it);
-      bidi_it->type = type;
-      bidi_it->bracket_resolved = 1;
+      /* Restore bidi_it from the cache, which should have the bracket
+        resolution members set as determined by the above loop.  */
+      type = bidi_cache_find (saved_it.charpos, 0, bidi_it);
+      eassert (type == NEUTRAL_ON);
+
+      /* The following is an optimization for bracketed text that has
+        only one level which is equal to the paragraph's base
+        embedding level.  That is, only L2R and weak/neutral
+        characters in a L2R paragraph, or only R2L and weak/neutral
+        characters in a R2L paragraph.  Such brackets can be resolved
+        by bidi_resolve_neutral, which has a further shortcut for
+        this case.  So we pretend we did not resolve the brackets in
+        this case, set up next_for_neutral for the entire bracketed
+        text, and reset the cache to the character before the opening
+        bracket.  The upshot is to allow bidi_move_to_visually_next
+        reset the cache when it returns this opening bracket, thus
+        cutting significantly on the size of the cache, which is
+        important with long lines, especially if word-wrap is non-nil
+        (which requires the display engine to copy the cache back and
+        forth many times).  */
+      if (maxlevel == base_level
+         && ((base_level == 0 && !r2l_seen)
+             || (base_level == 1 && !l2r_seen)))
+       {
+         ptrdiff_t eob
+           = ((bidi_it->string.s || STRINGP (bidi_it->string.lstring))
+              ? bidi_it->string.schars : ZV);
+
+         if (retval)
+           pairing_pos = bidi_it->bracket_pairing_pos;
+
+         /* This special value (which cannot possibly happen when
+            brackets are resolved, since there's no character at ZV)
+            will be noticed by bidi_resolve_explicit, and will be
+            copied to the following iterator states, instead of being
+            reset to -1.  */
+         bidi_it->bracket_pairing_pos = eob;
+         /* This type value will be used for resolving the outermost
+            closing bracket in bidi_resolve_brackets.  */
+         bidi_it->bracket_enclosed_type = embedding_type;
+         /* bidi_cache_last_idx is set to the index of the current
+            state, because we just called bidi_cache_find above.
+            That state describes the outermost opening bracket, the
+            one with which we entered this function.  Force the cache
+            to "forget" all the cached states starting from that state.  */
+         bidi_cache_reset_to (bidi_cache_last_idx - bidi_cache_start);
+         /* Set up the next_for_neutral member, to help
+            bidi_resolve_neutral.  */
+         bidi_it->next_for_neutral.type = embedding_type;
+         bidi_it->next_for_neutral.charpos = pairing_pos;
+         /* Pretend we didn't resolve this bracket.  */
+         retval = false;
+       }
+    }
+
+ give_up:
+  return retval;
+}
+
+static void
+bidi_record_type_for_neutral (struct bidi_saved_info *info, int level,
+                             bool nextp)
+{
+  int idx;
+
+  for (idx = bidi_cache_last_idx + 1; idx < bidi_cache_idx; idx++)
+    {
+      int lev = bidi_cache[idx].level_stack[bidi_cache[idx].stack_idx].level;
+
+      if (lev <= level)
+       {
+         eassert (lev == level);
+         if (nextp)
+           bidi_cache[idx].next_for_neutral = *info;
+         else
+           bidi_cache[idx].prev_for_neutral = *info;
+         break;
+       }
+    }
+}
+
+static bidi_type_t
+bidi_resolve_brackets (struct bidi_it *bidi_it)
+{
+  int prev_level = bidi_it->level_stack[bidi_it->stack_idx].level;
+  bool resolve_bracket = false;
+  bidi_type_t type = UNKNOWN_BT;
+  int ch;
+  struct bidi_saved_info prev_for_neutral, next_for_neutral;
+  ptrdiff_t eob
+    = ((bidi_it->string.s || STRINGP (bidi_it->string.lstring))
+       ? bidi_it->string.schars : ZV);
+
+  /* Record the prev_for_neutral type either from the previous
+     character, if it was a strong or AN/EN, or from the
+     prev_for_neutral information recorded previously.  */
+  if (bidi_it->type == STRONG_L || bidi_it->type == STRONG_R
+      || bidi_it->type == WEAK_AN || bidi_it->type == WEAK_EN)
+    bidi_remember_char (&prev_for_neutral, bidi_it, 1);
+  else
+    prev_for_neutral = bidi_it->prev_for_neutral;
+  /* Record the next_for_neutral type information.  */
+  if (bidi_it->next_for_neutral.charpos > bidi_it->charpos)
+    next_for_neutral = bidi_it->next_for_neutral;
+  else
+    next_for_neutral.charpos = -1;
+  if (!bidi_it->first_elt)
+    {
+      type = bidi_cache_find (bidi_it->charpos + bidi_it->nchars, 0, bidi_it);
+      ch = bidi_it->ch;
+    }
+  if (type == UNKNOWN_BT)
+    {
+      type = bidi_resolve_weak (bidi_it);
+      if (type == NEUTRAL_ON)
+       {
+         /* bracket_pairing_pos == eob means this bracket does not
+            need to be resolved as a bracket, but as a neutral, see
+            the optimization trick we play near the end of
+            bidi_find_bracket_pairs.  */
+         if (bidi_it->bracket_pairing_pos == eob)
+           {
+             /* If this is the outermost closing bracket of a run of
+                characters in which we decided to resolve brackets as
+                neutrals, use the embedding level's type, recorded in
+                bracket_enclosed_type, to resolve the bracket.  */
+             if (bidi_it->next_for_neutral.charpos == bidi_it->charpos
+                 && bidi_paired_bracket_type (bidi_it->ch) == BIDI_BRACKET_CLOSE)
+               type = bidi_it->bracket_enclosed_type;
+           }
+         else if (bidi_find_bracket_pairs (bidi_it))
+           resolve_bracket = true;
+       }
+    }
+  else if (bidi_it->bracket_pairing_pos != eob)
+    {
+      eassert (bidi_it->resolved_level == -1);
+      /* If the cached state shows an increase of embedding level due
+        to an isolate initiator, we need to update the 1st cached
+        state of the next run of the current isolating sequence with
+        the prev_for_neutral and next_for_neutral information, so
+        that it will be picked up when we advance to that next run.  */
+      if (bidi_it->level_stack[bidi_it->stack_idx].level > prev_level
+         && ISOLATE_STATUS (bidi_it, bidi_it->stack_idx))
+       {
+         bidi_record_type_for_neutral (&prev_for_neutral, prev_level, 0);
+         bidi_record_type_for_neutral (&next_for_neutral, prev_level, 1);
+       }
+      if (type == NEUTRAL_ON
+         && bidi_paired_bracket_type (ch) == BIDI_BRACKET_OPEN)
+       {
+         if (bidi_it->bracket_pairing_pos > bidi_it->charpos)
+           {
+             /* A cached opening bracket that wasn't completely
+                resolved yet.  */
+             resolve_bracket = true;
+           }
+         else if (bidi_it->bracket_pairing_pos == -1)
+           {
+             /* Higher levels were not BPA-resolved yet, even if
+                cached by bidi_find_bracket_pairs.  Force application
+                of BPA to the new level now.  */
+             if (bidi_find_bracket_pairs (bidi_it))
+               resolve_bracket = true;
+           }
+       }
+      /* Keep track of the prev_for_neutral and next_for_neutral
+        types, needed for resolving brackets below and for resolving
+        neutrals in bidi_resolve_neutral.  */
+      if (bidi_it->level_stack[bidi_it->stack_idx].level == prev_level)
+       {
+         bidi_it->prev_for_neutral = prev_for_neutral;
+         if (next_for_neutral.charpos > 0)
+           bidi_it->next_for_neutral = next_for_neutral;
+       }
+    }
+
+  /* If needed, resolve the bracket type according to N0.  */
+  if (resolve_bracket)
+    {
+      int embedding_level = bidi_it->level_stack[bidi_it->stack_idx].level;
+      bidi_type_t embedding_type = (embedding_level & 1) ? STRONG_R : STRONG_L;
+
+      eassert (bidi_it->prev_for_neutral.type != UNKNOWN_BT);
+      eassert (bidi_it->bracket_pairing_pos > bidi_it->charpos);
+      if (bidi_it->bracket_enclosed_type == embedding_type) /* N0b */
+       type = embedding_type;
+      else
+       {
+         switch (bidi_it->prev_for_neutral.type)
+           {
+           case STRONG_R:
+           case WEAK_EN:
+           case WEAK_AN:
+             type =
+               (bidi_it->bracket_enclosed_type == STRONG_R) /* N0c */
+               ? STRONG_R                                   /* N0c1 */
+               : embedding_type;                            /* N0c2 */
+             break;
+           case STRONG_L:
+             type =
+               (bidi_it->bracket_enclosed_type == STRONG_L) /* N0c */
+               ? STRONG_L                                   /* N0c1 */
+               : embedding_type;                            /* N0c2 */
+             break;
+           default:
+             /* N0d: Do not set the type for that bracket pair.  */
+             break;
+           }
+       }
+      eassert (type == STRONG_L || type == STRONG_R || type == NEUTRAL_ON);
+
+      /* Update the type of the paired closing bracket to the same
+        type as for the resolved opening bracket.  */
+      if (type != NEUTRAL_ON)
+       {
+         ptrdiff_t idx = bidi_cache_search (bidi_it->bracket_pairing_pos,
+                                            -1, 1);
+
+         if (idx < bidi_cache_start)
+           emacs_abort ();
+         bidi_cache[idx].type = type;
+       }
     }
 
   return type;
@@ -2500,11 +2918,9 @@ bidi_resolve_bracket_pairs (struct bidi_it *bidi_it)
 static bidi_type_t
 bidi_resolve_neutral (struct bidi_it *bidi_it)
 {
-  int prev_level = bidi_it->level_stack[bidi_it->stack_idx].level;
-  bidi_type_t type = bidi_resolve_weak (bidi_it);
-  int current_level = bidi_it->level_stack[bidi_it->stack_idx].level;
+  bidi_type_t type = bidi_resolve_brackets (bidi_it);
+  int current_level;
   bool is_neutral;
-  int ch = bidi_it->ch;
 
   eassert (type == STRONG_R
           || type == STRONG_L
@@ -2519,21 +2935,8 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
           || type == RLI
           || type == PDI);
 
-  eassert (prev_level >= 0);
+  current_level = bidi_it->level_stack[bidi_it->stack_idx].level;
   eassert (current_level >= 0);
-
-  /* FIXME: Insert the code for N0 here.  */
-  if (type == NEUTRAL_ON
-      && bidi_paired_bracket_type (ch) != BIDI_BRACKET_NONE)
-    {
-      if (bidi_cache_idx > bidi_cache_start
-         && bidi_cache_find (bidi_it->charpos, 1, bidi_it) != UNKNOWN_BT
-         && bidi_it->bracket_resolved)
-       type = bidi_it->type;
-      else
-       type = bidi_resolve_bracket_pairs (bidi_it);
-    }
-
   is_neutral = bidi_get_category (type) == NEUTRAL;
 
   if ((type != NEUTRAL_B /* Don't risk entering the long loop below if
@@ -2543,9 +2946,18 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
       || (type == WEAK_BN && bidi_explicit_dir_char (bidi_it->ch)))
     {
       if (bidi_it->next_for_neutral.type != UNKNOWN_BT)
-       type = bidi_resolve_neutral_1 (bidi_it->prev_for_neutral.type,
-                                      bidi_it->next_for_neutral.type,
-                                      current_level);
+       {
+         /* Make sure the data for resolving neutrals we are
+            about to use is valid.  */
+         eassert (bidi_it->next_for_neutral.charpos > bidi_it->charpos
+                  /* PDI defines an eos, so it's OK for it to
+                     serve as its own next_for_neutral.  */
+                  || (bidi_it->next_for_neutral.charpos == bidi_it->charpos
+                      && bidi_it->type == PDI));
+         type = bidi_resolve_neutral_1 (bidi_it->prev_for_neutral.type,
+                                        bidi_it->next_for_neutral.type,
+                                        current_level);
+       }
       /* The next two "else if" clauses are shortcuts for the
         important special case when we have a long sequence of
         neutral or WEAK_BN characters, such as whitespace or nulls or
@@ -2592,9 +3004,6 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
          bidi_type_t next_type;
          bool adjacent_to_neutrals = is_neutral;
 
-         if (bidi_it->scan_dir == -1)
-           emacs_abort ();
-
          bidi_copy_it (&saved_it, bidi_it);
          /* Scan the text forward until we find the first non-neutral
             character, and then use that to resolve the neutral we
@@ -2605,31 +3014,26 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
 
            /* Paragraph separators have their levels fully resolved
               at this point, so cache them as resolved.  */
-           bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B);
-           /* Record the info about the previous character, so that
-              it will be cached with this state.  */
-           if (bidi_it->type_after_w1 != WEAK_BN /* W1/Retaining */
-               && bidi_it->type != WEAK_BN)
-             bidi_remember_char (&bidi_it->prev, bidi_it);
+           bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B, 0);
            old_sidx = bidi_it->stack_idx;
-           type = bidi_resolve_weak (bidi_it);
+           type = bidi_resolve_brackets (bidi_it);
            /* Skip level runs excluded from this isolating run sequence.  */
            new_sidx = bidi_it->stack_idx;
            if (bidi_it->level_stack[new_sidx].level > current_level
-               && (bidi_it->level_stack[new_sidx].isolate_status
+               && (ISOLATE_STATUS (bidi_it, new_sidx)
                    /* This is for when we have an isolate initiator
                       immediately followed by an embedding or
                       override initiator, in which case we get the
                       level stack pushed twice by the single call to
                       bidi_resolve_weak above.  */
                    || (new_sidx > old_sidx + 1
-                       && bidi_it->level_stack[new_sidx - 1].isolate_status)))
+                       && ISOLATE_STATUS (bidi_it, new_sidx - 1))))
              {
                while (bidi_it->level_stack[bidi_it->stack_idx].level
                       > current_level)
                  {
-                   bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B);
-                   type = bidi_resolve_weak (bidi_it);
+                   bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B, 0);
+                   type = bidi_resolve_brackets (bidi_it);
                  }
              }
            if (!adjacent_to_neutrals
@@ -2646,7 +3050,7 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
                         != current_level)));
 
          /* Record the character we stopped at.  */
-         bidi_remember_char (&saved_it.next_for_neutral, bidi_it);
+         bidi_remember_char (&saved_it.next_for_neutral, bidi_it, 1);
 
          if ((bidi_it->level_stack[bidi_it->stack_idx].level != current_level)
              || type == NEUTRAL_B)
@@ -2730,11 +3134,9 @@ bidi_type_of_next_char (struct bidi_it *bidi_it)
 static int
 bidi_level_of_next_char (struct bidi_it *bidi_it)
 {
-  bidi_type_t type;
-  int level, prev_level = -1;
-  struct bidi_saved_info next_for_neutral;
+  bidi_type_t type = UNKNOWN_BT;
+  int level;
   ptrdiff_t next_char_pos = -2;
-  bool need_to_update_cache = false;
 
   if (bidi_it->scan_dir == 1)
     {
@@ -2742,61 +3144,22 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
        = ((bidi_it->string.s || STRINGP (bidi_it->string.lstring))
           ? bidi_it->string.schars : ZV);
 
-      /* There's no sense in trying to advance if we hit end of text.  */
+      /* There's no sense in trying to advance if we've already hit
+        the end of text.  */
       if (bidi_it->charpos >= eob)
        {
          eassert (bidi_it->resolved_level >= 0);
          return bidi_it->resolved_level;
        }
+    }
 
-      /* Record the info about the previous character.  */
-      if (bidi_it->type_after_w1 != WEAK_BN /* W1/Retaining */
-         && bidi_it->type != WEAK_BN)
-       bidi_remember_char (&bidi_it->prev, bidi_it);
-      if (bidi_it->type_after_w1 == STRONG_R
-         || bidi_it->type_after_w1 == STRONG_L
-         || bidi_it->type_after_w1 == STRONG_AL)
-       bidi_remember_char (&bidi_it->last_strong, bidi_it);
-      /* FIXME: it sounds like we don't need both prev and
-        prev_for_neutral members, but I'm leaving them both for now.  */
-      if (bidi_it->type == STRONG_R || bidi_it->type == STRONG_L
-         || bidi_it->type == WEAK_EN || bidi_it->type == WEAK_AN)
-       bidi_remember_char (&bidi_it->prev_for_neutral, bidi_it);
-
-      /* If we overstepped the characters used for resolving neutrals
-        and whitespace, invalidate their info in the iterator.  */
-      if (bidi_it->charpos >= bidi_it->next_for_neutral.charpos)
-       bidi_it->next_for_neutral.type = UNKNOWN_BT;
-      if (bidi_it->next_en_pos >= 0
-         && bidi_it->charpos >= bidi_it->next_en_pos)
-       {
-         bidi_it->next_en_pos = 0;
-         bidi_it->next_en_type = UNKNOWN_BT;
-       }
-      if (bidi_it->next_for_ws.type != UNKNOWN_BT
-         && bidi_it->charpos >= bidi_it->next_for_ws.charpos)
-       bidi_it->next_for_ws.type = UNKNOWN_BT;
-
-      /* This must be taken before we fill the iterator with the info
-        about the next char.  If we scan backwards, the iterator
-        state must be already cached, so there's no need to know the
-        embedding level of the previous character, since we will be
-        returning to our caller shortly.  */
-      prev_level = bidi_it->level_stack[bidi_it->stack_idx].level;
-      eassert (prev_level >= 0);
-    }
-  next_for_neutral = bidi_it->next_for_neutral;
-
-  /* Perhaps the character we want is already cached.  If it is, the
-     call to bidi_cache_find below will return a type other than
-     UNKNOWN_BT.  */
+  /* Perhaps the character we want is already cached s fully resolved.
+     If it is, the call to bidi_cache_find below will return a type
+     other than UNKNOWN_BT.  */
   if (bidi_cache_idx > bidi_cache_start && !bidi_it->first_elt)
     {
       int bob = ((bidi_it->string.s || STRINGP (bidi_it->string.lstring))
                 ? 0 : 1);
-      bidi_type_t prev_type = bidi_it->type;
-      bidi_type_t type_for_neutral = bidi_it->next_for_neutral.type;
-      ptrdiff_t pos_for_neutral = bidi_it->next_for_neutral.charpos;
 
       if (bidi_it->scan_dir > 0)
        {
@@ -2811,58 +3174,15 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
           cached at the beginning of the iteration.  */
        next_char_pos = bidi_it->charpos - 1;
       if (next_char_pos >= bob - 1)
-       type = bidi_cache_find (next_char_pos, 0, bidi_it);
-      else
-       type = UNKNOWN_BT;
-
-      /* For a sequence of BN and NI, copy the type from the previous
-        character.  This is because the loop in bidi_resolve_neutral
-        that handles such sequences caches the characters it
-        traverses, but does not (and cannot) store the
-        next_for_neutral member for them, because it is only known
-        when the loop ends.  So when we find them in the cache, their
-        type needs to be updated, but we don't have next_for_neutral
-        to do that.  However, whatever type is resolved as result of
-        that loop, it will be the same for all the traversed
-        characters, by virtue of N1 and N2.  */
-      if (type == WEAK_BN && bidi_it->scan_dir > 0
-         && bidi_explicit_dir_char (bidi_it->ch)
-         && type_for_neutral != UNKNOWN_BT
-         && bidi_it->charpos < pos_for_neutral)
-       {
-         type = prev_type;
-         eassert (type != UNKNOWN_BT);
-       }
-    }
-  else
-    type = UNKNOWN_BT;
-  if (type != UNKNOWN_BT)
-    {
-      /* Don't lose the information for resolving neutrals!  The
-        cached states could have been cached before their
-        next_for_neutral member was computed.  If we are on our way
-        forward, we can simply take the info from the previous
-        state.  */
-      if (bidi_it->scan_dir == 1
-         && bidi_it->next_for_neutral.type == UNKNOWN_BT)
-       bidi_it->next_for_neutral = next_for_neutral;
-
-      /* If resolved_level is -1, it means this state was cached
-        before it was completely resolved, so we cannot return
-        it.  */
-      if (bidi_it->resolved_level != -1)
+       type = bidi_cache_find (next_char_pos, 1, bidi_it);
+      if (type != UNKNOWN_BT)
        {
+         /* We asked the cache for fully resolved states.  */
          eassert (bidi_it->resolved_level >= 0);
          return bidi_it->resolved_level;
        }
-      else
-       {
-         /* Take note when we've got a cached state that is not fully
-            resolved, so that we could make sure we update the cache
-            below, when we do resolve it.  */
-         need_to_update_cache = true;
-       }
     }
+
   if (bidi_it->scan_dir == -1)
     /* If we are going backwards, the iterator state is already cached
        from previous scans, and should be fully resolved.  */
@@ -2878,18 +3198,6 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
     }
 
   level = bidi_it->level_stack[bidi_it->stack_idx].level;
-  if (bidi_get_category (type) == NEUTRAL /* && type != NEUTRAL_B */
-      || bidi_isolate_fmt_char (type))
-    {
-      if (bidi_it->next_for_neutral.type == UNKNOWN_BT)
-       emacs_abort ();
-
-      /* If the cached state shows a neutral character, it was not
-        resolved by bidi_resolve_neutral, so do it now.  */
-      type = bidi_resolve_neutral_1 (bidi_it->prev_for_neutral.type,
-                                    bidi_it->next_for_neutral.type,
-                                    level);
-    }
 
   eassert ((type == STRONG_R
            || type == STRONG_L
@@ -2904,7 +3212,7 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
      or a TAB or a paragraph separator.  */
   if ((bidi_it->orig_type == NEUTRAL_WS
        || bidi_isolate_fmt_char (bidi_it->orig_type))
-      && bidi_it->next_for_ws.type == UNKNOWN_BT)
+      && bidi_it->next_for_ws.charpos < bidi_it->charpos)
     {
       int ch;
       ptrdiff_t clen = bidi_it->ch_len;
@@ -2929,9 +3237,11 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
       bidi_it->next_for_ws.type = chtype;
       bidi_check_type (bidi_it->next_for_ws.type);
       bidi_it->next_for_ws.charpos = cpos;
-      bidi_it->next_for_ws.bytepos = bpos;
     }
 
+  /* Update the cache, but only if this state was already cached.  */
+  bidi_cache_iterator_state (bidi_it, 1, 1);
+
   /* Resolve implicit levels.  */
   if (bidi_it->orig_type == NEUTRAL_B /* L1 */
           || bidi_it->orig_type == NEUTRAL_S
@@ -2954,8 +3264,6 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
     }
 
   bidi_it->resolved_level = level;
-  if (need_to_update_cache)
-    bidi_cache_iterator_state (bidi_it, 1);
   return level;
 }
 
@@ -2997,10 +3305,35 @@ bidi_find_other_level_edge (struct bidi_it *bidi_it, int level, bool end_flag)
       if (end_flag)
        emacs_abort ();
 
-      bidi_cache_iterator_state (bidi_it, 1);
+      if (!bidi_cache_iterator_state (bidi_it, 1, 0))
+       {
+         /* Can't happen: if the cache needs to grow, it means we
+            were at base embedding level, so the cache should have
+            been either empty or already large enough to cover this
+            character position.  */
+         emacs_abort ();
+       }
       do {
        new_level = bidi_level_of_next_char (bidi_it);
-       bidi_cache_iterator_state (bidi_it, 1);
+       /* If the cache is full, perform an emergency return by
+          pretending that the level ended.  */
+       if (!bidi_cache_iterator_state (bidi_it, 1, 0))
+         {
+           new_level = level - 1;
+           /* Since the cache should only grow when we are scanning
+              forward looking for the edge of the level that is one
+              above the base embedding level, we can only have this
+              contingency when LEVEL - 1 is the base embedding
+              level.  */
+           eassert (new_level == bidi_it->level_stack[0].level);
+           /* Plan B, for when the cache overflows: Back up to the
+              previous character by fetching the last cached state,
+              and force the resolved level of that character be the
+              base embedding level.  */
+           bidi_cache_fetch_state (bidi_cache_idx - 1, bidi_it);
+           bidi_it->resolved_level = new_level;
+           bidi_cache_iterator_state (bidi_it, 1, 1);
+         }
       } while (new_level >= level);
     }
 }
@@ -3044,7 +3377,7 @@ bidi_move_to_visually_next (struct bidi_it *bidi_it)
          sentinel.ch_len = 1;
          sentinel.nchars = 1;
        }
-      bidi_cache_iterator_state (&sentinel, 1);
+      bidi_cache_iterator_state (&sentinel, 1, 0);
     }
 
   old_level = bidi_it->resolved_level;
@@ -3154,18 +3487,54 @@ bidi_move_to_visually_next (struct bidi_it *bidi_it)
          && bidi_it->charpos > (bidi_cache[bidi_cache_idx - 1].charpos
                                 + bidi_cache[bidi_cache_idx - 1].nchars - 1))
        bidi_cache_reset ();
+      /* Also reset the cache if it overflowed and we have just
+        emergency-exited using Plan B.  */
+      else if (bidi_it->resolved_level == bidi_it->level_stack[0].level
+              && bidi_cache_idx >= bidi_cache_size
+              && bidi_it->charpos == bidi_cache[bidi_cache_idx - 1].charpos)
+       bidi_cache_reset ();
        /* But as long as we are caching during forward scan, we must
           cache each state, or else the cache integrity will be
           compromised: it assumes cached states correspond to buffer
           positions 1:1.  */
       else
-       bidi_cache_iterator_state (bidi_it, 1);
+       bidi_cache_iterator_state (bidi_it, 1, 0);
     }
 
+  eassert (bidi_it->resolved_level >= 0
+          && bidi_it->resolved_level <= BIDI_MAXDEPTH + 2);
+
   if (STRINGP (bidi_it->string.lstring))
     UNGCPRO;
 }
 
+/* Utility function for looking for strong directional characters
+   whose bidi type was overridden by a directional override.  */
+ptrdiff_t
+bidi_find_first_overridden (struct bidi_it *bidi_it)
+{
+  ptrdiff_t found_pos = ZV;
+
+  do
+    {
+      /* Need to call bidi_resolve_weak, not bidi_resolve_explicit,
+        because the directional overrides are applied by the
+        former.  */
+      bidi_type_t type = bidi_resolve_weak (bidi_it);
+
+      if ((type == STRONG_R && bidi_it->orig_type == STRONG_L)
+         || (type == STRONG_L
+             && (bidi_it->orig_type == STRONG_R
+                 || bidi_it->orig_type == STRONG_AL)))
+       found_pos = bidi_it->charpos;
+    } while (found_pos == ZV
+            && bidi_it->charpos < ZV
+            && bidi_it->ch != BIDI_EOB
+            && bidi_it->ch != '\n');
+
+  return found_pos;
+}
+
 /* This is meant to be called from within the debugger, whenever you
    wish to examine the cache contents.  */
 void bidi_dump_cached_states (void) EXTERNALLY_VISIBLE;