]> code.delx.au - gnu-emacs/blobdiff - src/bidi.c
Have 'make' output better GEN names
[gnu-emacs] / src / bidi.c
index 3c204a82b7867036281fa605e97a99d91d5fc9ab..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
 
@@ -247,7 +248,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
 
 static bool bidi_initialized = 0;
 
-static Lisp_Object bidi_type_table, bidi_mirror_table;
+static Lisp_Object bidi_type_table, bidi_mirror_table, bidi_brackets_table;
 
 #define BIDI_EOB   (-1)
 
@@ -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
@@ -407,16 +425,16 @@ bidi_set_sos_type (struct bidi_it *bidi_it, int level_before, int level_after)
   bidi_it->sos = ((higher_level & 1) != 0 ? R2L : L2R); /* X10 */
 
   bidi_it->prev.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->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;
-  bidi_it->ignore_bn_limit = -1; /* meaning it's unknown */
 }
 
+#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
@@ -424,22 +442,25 @@ bidi_push_embedding_level (struct bidi_it *bidi_it,
                           int level, bidi_dir_t override, bool isolate_status)
 {
   struct bidi_stack *st;
+  int prev_level = bidi_it->level_stack[bidi_it->stack_idx].level;
 
   bidi_it->stack_idx++;
   eassert (bidi_it->stack_idx < BIDI_MAXDEPTH+2+1);
   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->next_for_ws = bidi_it->next_for_ws;
-      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).  */
+  bidi_set_sos_type (bidi_it, prev_level, level);
 }
 
 /* Pop from the stack the embedding level, the directional override
@@ -454,13 +475,15 @@ 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;
 
       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
@@ -468,14 +491,17 @@ 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->next_for_ws = st.next_for_ws;
-         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,
+                          bidi_it->level_stack[bidi_it->stack_idx - 1].level);
+
       bidi_it->stack_idx--;
     }
   level = bidi_it->level_stack[bidi_it->stack_idx].level;
@@ -486,16 +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);
+  bidi_check_type (saved_info->orig_type);
 }
 
 /* Copy the bidi iterator from FROM to TO.  To save cycles, this only
@@ -519,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) };
@@ -539,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
@@ -551,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
@@ -568,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
@@ -584,9 +644,11 @@ 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
+   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)
 {
@@ -660,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;
@@ -698,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;
 
@@ -724,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;
@@ -731,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
     {
@@ -751,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
@@ -760,22 +845,45 @@ bidi_cache_iterator_state (struct bidi_it *bidi_it, bool resolved)
       bidi_cache[idx].invalid_levels = bidi_it->invalid_levels;
       bidi_cache[idx].next_for_neutral = bidi_it->next_for_neutral;
       bidi_cache[idx].next_for_ws = bidi_it->next_for_ws;
-      bidi_cache[idx].ignore_bn_limit = bidi_it->ignore_bn_limit;
       bidi_cache[idx].disp_pos = bidi_it->disp_pos;
       bidi_cache[idx].disp_prop = bidi_it->disp_prop;
+      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.  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, int level, 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, level, bidi_it->scan_dir);
-
-  if (i >= bidi_cache_start)
+  ptrdiff_t i = bidi_cache_search (charpos, -1, bidi_it->scan_dir);
+
+  if (i >= bidi_cache_start
+      && (!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;
 
@@ -793,8 +901,13 @@ bidi_cache_find (ptrdiff_t charpos, int level, 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;
 }
 
@@ -811,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);
@@ -847,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;
@@ -886,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;
 }
@@ -907,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 ();
        }
     }
@@ -946,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));
@@ -972,14 +1102,17 @@ bidi_initialize (void)
     emacs_abort ();
   staticpro (&bidi_mirror_table);
 
-  Qparagraph_start = intern ("paragraph-start");
-  staticpro (&Qparagraph_start);
+  bidi_brackets_table = uniprop_table (intern ("bracket-type"));
+  if (NILP (bidi_brackets_table))
+    emacs_abort ();
+  staticpro (&bidi_brackets_table);
+
+  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]*$");
@@ -987,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;
 }
@@ -1014,27 +1148,24 @@ bidi_init_it (ptrdiff_t charpos, ptrdiff_t bytepos, bool frame_window_p,
   if (bytepos >= 0)
     bidi_it->bytepos = bytepos;
   bidi_it->frame_window_p = frame_window_p;
-  bidi_it->nchars = -1;        /* to be computed in bidi_resolve_explicit_1 */
+  bidi_it->nchars = -1;        /* to be computed in bidi_resolve_explicit */
   bidi_it->first_elt = 1;
   bidi_set_paragraph_end (bidi_it);
   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;
@@ -1053,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 */
@@ -1062,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 */
@@ -1673,15 +1805,16 @@ bidi_explicit_dir_char (int ch)
          || ch_type == PDF);
 }
 
-/* A helper function for bidi_resolve_explicit.  It advances to the
-   next character in logical order and determines the new embedding
-   level and directional override, but does not take into account
-   empty embeddings.  */
+/* Given an iterator state in BIDI_IT, advance one character position
+   in the buffer/string to the next character (in the logical order),
+   resolve any explicit embeddings, directional overrides, and isolate
+   initiators and terminators, and return the embedding level of the
+   character after resolving these explicit directives.  */
 static int
-bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
+bidi_resolve_explicit (struct bidi_it *bidi_it)
 {
   int curchar;
-  bidi_type_t type, typ1;
+  bidi_type_t type, typ1, prev_type = UNKNOWN_BT;
   int current_level;
   int new_level;
   bidi_dir_t override;
@@ -1689,6 +1822,58 @@ bidi_resolve_explicit_1 (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
@@ -1719,6 +1904,19 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
            }
          eassert (bidi_it->bytepos == CHAR_TO_BYTE (bidi_it->charpos));
        }
+      /* 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 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.  */
+      if (bidi_it->first_elt && bidi_it->prev.type != UNKNOWN_BT)
+       {
+         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_wn;
+       }
     }
   /* Don't move at end of buffer/string.  */
   else if (bidi_it->charpos < (string_p ? bidi_it->string.schars : ZV))
@@ -1731,13 +1929,17 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
       if (bidi_it->ch_len == 0)
        emacs_abort ();
       bidi_it->bytepos += bidi_it->ch_len;
+      prev_type = bidi_it->orig_type;
+      if (prev_type == FSI)
+       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;
-  bidi_it->resolved_level = new_level;
 
   if (bidi_it->charpos >= (string_p ? bidi_it->string.schars : ZV))
     {
@@ -1749,6 +1951,52 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
     }
   else
     {
+      /* LRI, RLI, and FSI increment, and PDF decrements, the
+        embedding level of the _following_ characters, so we must
+        first look at the type of the previous character to support
+        that.  */
+      switch (prev_type)
+       {
+       case RLI:       /* X5a */
+         if (current_level < BIDI_MAXDEPTH
+             && bidi_it->invalid_levels == 0
+             && bidi_it->invalid_isolates == 0)
+           {
+             new_level = ((current_level + 1) & ~1) + 1;
+             bidi_it->isolate_level++;
+             bidi_push_embedding_level (bidi_it, new_level,
+                                        NEUTRAL_DIR, true);
+           }
+         else
+           bidi_it->invalid_isolates++;
+         break;
+       case LRI:       /* X5b */
+         if (current_level < BIDI_MAXDEPTH - 1
+             && bidi_it->invalid_levels == 0
+             && bidi_it->invalid_isolates == 0)
+           {
+             new_level = ((current_level + 2) & ~1);
+             bidi_it->isolate_level++;
+             bidi_push_embedding_level (bidi_it, new_level,
+                                        NEUTRAL_DIR, true);
+           }
+         else
+           bidi_it->invalid_isolates++;
+         break;
+       case PDF:       /* X7 */
+         if (!bidi_it->invalid_isolates)
+           {
+             if (bidi_it->invalid_levels)
+               bidi_it->invalid_levels--;
+             else if (!isolate_status && bidi_it->stack_idx >= 1)
+               new_level = bidi_pop_embedding_level (bidi_it);
+           }
+         break;
+       default:
+         eassert (prev_type != FSI);
+         /* Nothing.  */
+         break;
+       }
       /* Fetch the character at BYTEPOS.  If it is covered by a
         display string, treat the entire run of covered characters as
         a single character u+FFFC.  */
@@ -1759,6 +2007,7 @@ bidi_resolve_explicit_1 (struct bidi_it *bidi_it)
                                 &bidi_it->ch_len, &bidi_it->nchars);
     }
   bidi_it->ch = curchar;
+  bidi_it->resolved_level = new_level;
 
   /* Don't apply directional override here, as all the types we handle
      below will not be affected by the override anyway, and we need
@@ -1768,263 +2017,141 @@ bidi_resolve_explicit_1 (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);
-       type = WEAK_BN; /* X9/Retaining */
-       if (bidi_it->ignore_bn_limit <= -1)
-         {
-           if (current_level < BIDI_MAXDEPTH
-               && bidi_it->invalid_levels == 0
-               && bidi_it->invalid_isolates == 0)
-             {
-               /* Compute the least odd embedding level greater than
-                  the current level.  */
-               new_level = ((current_level + 1) & ~1) + 1;
-               if (bidi_it->type_after_w1 == RLE)
-                 override = NEUTRAL_DIR;
-               else
-                 override = R2L;
-               bidi_push_embedding_level (bidi_it, new_level, override, false);
-               bidi_it->resolved_level = new_level;
-             }
-           else
-             {
-               if (bidi_it->invalid_isolates == 0)
-                 bidi_it->invalid_levels++;
-             }
-         }
-       else if (bidi_it->prev.type_after_w1 == WEAK_EN /* W5/Retaining */
-                || (bidi_it->next_en_pos > bidi_it->charpos
-                    && bidi_it->next_en_type == WEAK_EN))
-         type = WEAK_EN;
-       break;
-      case LRE:        /* X3 */
-      case LRO:        /* X5 */
-       bidi_it->type_after_w1 = type;
-       bidi_check_type (bidi_it->type_after_w1);
-       type = WEAK_BN; /* X9/Retaining */
-       if (bidi_it->ignore_bn_limit <= -1)
-         {
-           if (current_level < BIDI_MAXDEPTH - 1
-               && bidi_it->invalid_levels == 0
-               && bidi_it->invalid_isolates == 0)
-             {
-               /* Compute the least even embedding level greater than
-                  the current level.  */
-               new_level = ((current_level + 2) & ~1);
-               if (bidi_it->type_after_w1 == LRE)
-                 override = NEUTRAL_DIR;
-               else
-                 override = L2R;
-               bidi_push_embedding_level (bidi_it, new_level, override, false);
-               bidi_it->resolved_level = new_level;
-             }
-           else
-             {
-               if (bidi_it->invalid_isolates == 0)
-                 bidi_it->invalid_levels++;
-             }
-         }
-       else if (bidi_it->prev.type_after_w1 == WEAK_EN /* W5/Retaining */
-                || (bidi_it->next_en_pos > bidi_it->charpos
-                    && bidi_it->next_en_type == WEAK_EN))
-         type = WEAK_EN;
-       break;
-      case FSI:        /* X5c */
-       end = string_p ? bidi_it->string.schars : ZV;
-       disp_pos = bidi_it->disp_pos;
-       disp_prop = bidi_it->disp_prop;
-       nchars = bidi_it->nchars;
-       ch_len = bidi_it->ch_len;
-       typ1 = find_first_strong_char (bidi_it->charpos, bidi_it->bytepos, end,
-                                      &disp_pos, &disp_prop, &bidi_it->string,
-                                      bidi_it->w, string_p, bidi_it->frame_window_p,
-                                      &ch_len, &nchars, true);
-       if (typ1 != STRONG_R && typ1 != STRONG_AL)
-         {
-           type = LRI;
-           goto fsi_as_lri;
-         }
-       else
-         type = RLI;
-       /* FALLTHROUGH */
-      case RLI:        /* X5a */
-       if (override == NEUTRAL_DIR)
-         bidi_it->type_after_w1 = 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);
-       if (current_level < BIDI_MAXDEPTH
-           && bidi_it->invalid_levels == 0
-           && bidi_it->invalid_isolates == 0)
-         {
-           new_level = ((current_level + 1) & ~1) + 1;
-           bidi_it->isolate_level++;
-           bidi_push_embedding_level (bidi_it, new_level, NEUTRAL_DIR, true);
-         }
-       else
-         bidi_it->invalid_isolates++;
-       break;
-      case LRI:        /* X5b */
-    fsi_as_lri:
-       if (override == NEUTRAL_DIR)
-         bidi_it->type_after_w1 = 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);
-       if (current_level < BIDI_MAXDEPTH - 1
-           && bidi_it->invalid_levels == 0
-           && bidi_it->invalid_isolates == 0)
-         {
-           new_level = ((current_level + 2) & ~1);
-           bidi_it->isolate_level++;
-           bidi_push_embedding_level (bidi_it, new_level, NEUTRAL_DIR, true);
-         }
-       else
-         bidi_it->invalid_isolates++;
-       break;
-      case PDI:        /* X6a */
-       if (bidi_it->invalid_isolates)
-         {
-           bidi_it->invalid_isolates--;
-           new_level = current_level;
-         }
-       else if (bidi_it->isolate_level > 0)
-         {
-           bidi_it->invalid_levels = 0;
-           while (!bidi_it->level_stack[bidi_it->stack_idx].isolate_status)
-             bidi_pop_embedding_level (bidi_it);
-           eassert (bidi_it->stack_idx > 0);
-           new_level = bidi_pop_embedding_level (bidi_it);
-           bidi_it->isolate_level--;
-         }
-       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;
-       break;
-      case PDF:        /* X7 */
-       bidi_it->type_after_w1 = type;
-       bidi_check_type (bidi_it->type_after_w1);
-       type = WEAK_BN; /* X9/Retaining */
-       if (bidi_it->ignore_bn_limit <= -1)
-         {
-           if (!bidi_it->invalid_isolates)
-             {
-               if (bidi_it->invalid_levels)
-                 bidi_it->invalid_levels--;
-               else if (!isolate_status && bidi_it->stack_idx > 1)
-                 bidi_pop_embedding_level (bidi_it);
-             }
-         }
-       else if (bidi_it->prev.type_after_w1 == WEAK_EN /* W5/Retaining */
-                || (bidi_it->next_en_pos > bidi_it->charpos
-                    && bidi_it->next_en_type == WEAK_EN))
-         type = WEAK_EN;
-       break;
-      default:
-       /* Nothing.  */
-       break;
-    }
-
-  bidi_it->type = type;
-  bidi_check_type (bidi_it->type);
-
-  eassert (bidi_it->resolved_level >= 0);
-  return bidi_it->resolved_level;
-}
-
-/* Given an iterator state in BIDI_IT, advance one character position
-   in the buffer/string to the next character (in the logical order),
-   resolve any explicit embeddings and directional overrides, and
-   return the embedding level of the character after resolving
-   explicit directives and ignoring empty embeddings.  */
-static int
-bidi_resolve_explicit (struct bidi_it *bidi_it)
-{
-  int prev_level = bidi_it->level_stack[bidi_it->stack_idx].level;
-  int new_level  = bidi_resolve_explicit_1 (bidi_it);
-  ptrdiff_t eob = bidi_it->string.s ? bidi_it->string.schars : ZV;
-  const unsigned char *s
-    = (STRINGP (bidi_it->string.lstring)
-       ? SDATA (bidi_it->string.lstring)
-       : bidi_it->string.s);
-
-  eassert (prev_level >= 0);
-  if (prev_level < new_level
-      && bidi_it->type == WEAK_BN
-      && bidi_it->ignore_bn_limit == -1 /* only if not already known */
-      && bidi_it->charpos < eob                /* not already at EOB */
-      && bidi_explicit_dir_char (bidi_char_at_pos (bidi_it->bytepos
-                                                  + bidi_it->ch_len, s,
-                                                  bidi_it->string.unibyte)))
-    {
-      /* Avoid pushing and popping embedding levels if the level run
-        is empty, as this breaks level runs where it shouldn't.
-        UAX#9 removes all the explicit embedding and override codes,
-        so empty embeddings disappear without a trace.  We need to
-        behave as if we did the same.  */
-      struct bidi_it saved_it;
-      int level = prev_level;
-
-      bidi_copy_it (&saved_it, bidi_it);
-
-      while (bidi_explicit_dir_char (bidi_char_at_pos (bidi_it->bytepos
-                                                      + bidi_it->ch_len, s,
-                                                      bidi_it->string.unibyte)))
+    case RLE:  /* X2 */
+    case RLO:  /* X4 */
+      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
+         && bidi_it->invalid_isolates == 0)
        {
-         /* This advances to the next character, skipping any
-            characters covered by display strings.  */
-         level = bidi_resolve_explicit_1 (bidi_it);
-         /* If string.lstring was relocated inside bidi_resolve_explicit_1,
-            a pointer to its data is no longer valid.  */
-         if (STRINGP (bidi_it->string.lstring))
-           s = SDATA (bidi_it->string.lstring);
+         /* Compute the least odd embedding level greater than
+            the current level.  */
+         new_level = ((new_level + 1) & ~1) + 1;
+         if (bidi_it->type_after_wn == RLE)
+           override = NEUTRAL_DIR;
+         else
+           override = R2L;
+         bidi_push_embedding_level (bidi_it, new_level, override, false);
+         bidi_it->resolved_level = new_level;
        }
-
-      if (bidi_it->nchars <= 0)
-       emacs_abort ();
-      if (level == prev_level) /* empty embedding */
-       saved_it.ignore_bn_limit = bidi_it->charpos + bidi_it->nchars;
-      else                     /* this embedding is non-empty */
-       saved_it.ignore_bn_limit = -2;
-
-      bidi_copy_it (bidi_it, &saved_it);
-      if (bidi_it->ignore_bn_limit > -1)
+      else
        {
-         /* We pushed a level, but we shouldn't have.  Undo that. */
-         if (!bidi_it->invalid_levels)
-           new_level = bidi_pop_embedding_level (bidi_it);
+         if (bidi_it->invalid_isolates == 0)
+           bidi_it->invalid_levels++;
+       }
+      break;
+    case LRE:  /* X3 */
+    case LRO:  /* X5 */
+      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
+         && bidi_it->invalid_isolates == 0)
+       {
+         /* Compute the least even embedding level greater than
+            the current level.  */
+         new_level = ((new_level + 2) & ~1);
+         if (bidi_it->type_after_wn == LRE)
+           override = NEUTRAL_DIR;
          else
-           bidi_it->invalid_levels--;
+           override = L2R;
+         bidi_push_embedding_level (bidi_it, new_level, override, false);
+         bidi_it->resolved_level = new_level;
+       }
+      else
+       {
+         if (bidi_it->invalid_isolates == 0)
+           bidi_it->invalid_levels++;
        }
+      break;
+    case FSI:  /* X5c */
+      end = string_p ? bidi_it->string.schars : ZV;
+      disp_pos = bidi_it->disp_pos;
+      disp_prop = bidi_it->disp_prop;
+      nchars = bidi_it->nchars;
+      ch_len = bidi_it->ch_len;
+      typ1 = find_first_strong_char (bidi_it->charpos,
+                                    bidi_it->bytepos, end,
+                                    &disp_pos, &disp_prop,
+                                    &bidi_it->string, bidi_it->w,
+                                    string_p, bidi_it->frame_window_p,
+                                    &ch_len, &nchars, true);
+      if (typ1 != STRONG_R && typ1 != STRONG_AL)
+       {
+         type = LRI;
+         goto fsi_as_lri;
+       }
+      else
+       type = RLI;
+      /* FALLTHROUGH */
+    case RLI:  /* X5a */
+      if (override == NEUTRAL_DIR)
+       bidi_it->type_after_wn = type;
+      else     /* Unicode 8.0 correction.  */
+       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_wn = type;
+      else     /* Unicode 8.0 correction.  */
+       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)
+       bidi_it->invalid_isolates--;
+      else if (bidi_it->isolate_level > 0)
+       {
+         bidi_it->invalid_levels = 0;
+         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);
+         bidi_it->isolate_level--;
+       }
+      bidi_it->resolved_level = new_level;
+      /* Unicode 8.0 correction.  */
+      {
+       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_wn = type;
+      bidi_check_type (bidi_it->type_after_wn);
+      type = WEAK_BN; /* X9/Retaining */
+      break;
+    default:
+      /* Nothing.  */
+      break;
     }
 
+  bidi_it->type = type;
+  bidi_check_type (bidi_it->type);
+
   if (bidi_it->type == NEUTRAL_B)      /* X8 */
     {
       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_check_type (bidi_it->type_after_w1);
+      bidi_it->type_after_wn = bidi_it->type;
     }
 
-  return new_level;
-}
-
-static bool
-bidi_isolate_fmt_char (bidi_type_t ch_type)
-{
-  return (ch_type == LRI || ch_type == RLI || ch_type == PDI);
+  eassert (bidi_it->resolved_level >= 0);
+  return bidi_it->resolved_level;
 }
 
 /* Advance in the buffer/string, resolve weak types and return the
@@ -2044,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
@@ -2054,24 +2181,17 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
             || type == PDF));
 
   eassert (prev_level >= 0);
-  if (new_level > prev_level
-      /* When the embedding level goes down, we only need to compute
-        the type of sos if this level is not an isolate, because the
-        sos type of the isolating sequence was already computed and
-        saved on the stack.  */
-      || (new_level < prev_level
-         && !bidi_it->level_stack[bidi_it->stack_idx].isolate_status)
-      || bidi_it->type == NEUTRAL_B)
+  if (bidi_it->type == NEUTRAL_B)
     {
       /* We've got a new isolating sequence, compute the directional
          type of sos and initialize per-run variables (UAX#9, clause
          X10).  */
       bidi_set_sos_type (bidi_it, prev_level, new_level);
     }
-  else 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);
+  if (type == NEUTRAL_S || type == NEUTRAL_WS
+      || type == WEAK_BN || type == STRONG_AL)
+    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.  */
@@ -2088,16 +2208,29 @@ 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.  */
-         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))
-               type = NEUTRAL_ON;
+             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
+                    type other than PDI must be an overflow isolate
+                    initiator."  */
+                 eassert (bidi_it->invalid_isolates > 0);
+                 type = NEUTRAL_ON;
+               }
              else
-               type = bidi_it->prev.type_after_w1;
+               {
+                 /* 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)
            type = STRONG_R;
@@ -2107,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)
@@ -2136,8 +2269,7 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
              bidi_copy_it (&saved_it, bidi_it);
              while (bidi_resolve_explicit (bidi_it) == new_level
                     && bidi_it->type == WEAK_BN)
-               ;
-             type_of_next = bidi_it->type;
+               type_of_next = bidi_it->type;
              bidi_copy_it (bidi_it, &saved_it);
            }
 
@@ -2147,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
@@ -2159,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)
@@ -2180,6 +2312,12 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
            }
          else if (bidi_it->next_en_pos >=0)
            {
+             /* We overstepped the last known position for ET
+                resolution but there could be other such characters
+                in this paragraph (when we are sure there are no more
+                such positions, we set next_en_pos to a negative
+                value).  Try to find the next position for ET
+                resolution.  */
              ptrdiff_t en_pos = bidi_it->charpos + bidi_it->nchars;
              const unsigned char *s = (STRINGP (bidi_it->string.lstring)
                                        ? SDATA (bidi_it->string.lstring)
@@ -2202,9 +2340,20 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
                  while (bidi_resolve_explicit (bidi_it) == new_level
                         && (bidi_it->type == WEAK_BN
                             || bidi_it->type == WEAK_ET))
-                   ;
-                 type_of_next = bidi_it->type;
-                 en_pos = bidi_it->charpos;
+                   type_of_next = bidi_it->type;
+                 if (type == WEAK_BN
+                     && bidi_it->charpos == saved_it.charpos + saved_it.nchars)
+                   {
+                     /* If we entered the above loop with a BN that
+                        changes the level, the type of next
+                        character, which is in a different level, is
+                        not relevant to resolving this series of ET
+                        and BN.  */
+                     en_pos = saved_it.charpos;
+                     type_of_next = type;
+                   }
+                 else
+                   en_pos = bidi_it->charpos;
                  bidi_copy_it (bidi_it, &saved_it);
                }
              /* Remember this position, to speed up processing of the
@@ -2214,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 */
@@ -2234,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;
     }
@@ -2264,7 +2413,8 @@ bidi_resolve_weak (struct bidi_it *bidi_it)
 static bidi_type_t
 bidi_resolve_neutral_1 (bidi_type_t prev_type, bidi_type_t next_type, int lev)
 {
-  /* N1: European and Arabic numbers are treated as though they were R.  */
+  /* N1: "European and Arabic numbers act as if they were R in terms
+     of their influence on NIs."  */
   if (next_type == WEAK_EN || next_type == WEAK_AN)
     next_type = STRONG_R;
   if (prev_type == WEAK_EN || prev_type == WEAK_AN)
@@ -2278,34 +2428,536 @@ bidi_resolve_neutral_1 (bidi_type_t prev_type, bidi_type_t next_type, int lev)
     return STRONG_R;
 }
 
+#define FLAG_EMBEDDING_INSIDE  1
+#define FLAG_OPPOSITE_INSIDE   2
+
+/* A data type used in the stack maintained by
+   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 : 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 ((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 \
+   bpa_stack[bpa_sp].open_bracket_pos = bidi_it->charpos
+#else
+# define STORE_BRACKET_CHARPOS /* nothing */
+#endif
+
+#define PUSH_BPA_STACK                                                 \
+  do {                                                                 \
+    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.  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.  */
+  if (bidi_it->scan_dir != 1)
+    emacs_abort ();
+
+  btype = bidi_paired_bracket_type (bidi_it->ch);
+  if (btype == BIDI_BRACKET_OPEN)
+    {
+      bpa_stack_entry bpa_stack[MAX_BPA_STACK];
+      int bpa_sp = -1;
+      struct bidi_it saved_it;
+      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);
+      /* 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;
+
+         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;
+         else if (btype == BIDI_BRACKET_CLOSE)
+           {
+             int sp = bpa_sp;
+             int curchar = CANONICAL_EQU (bidi_it->ch);
+
+             eassert (sp >= 0);
+             while (sp >= 0 && bpa_stack[sp].close_bracket_char != curchar)
+               sp--;
+             if (sp >= 0)
+               {
+                 /* Update and cache the corresponding opening bracket.  */
+                 bidi_cache_fetch_state (bpa_stack[sp].open_bracket_idx,
+                                         &tem_it);
+#ifdef ENABLE_CHECKING
+                 eassert (bpa_stack[sp].open_bracket_pos == tem_it.charpos);
+#endif
+                 /* 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)
+               {
+                 retval = true;
+                 break;
+               }
+           }
+         else if (bidi_get_category (bidi_it->type_after_wn) != NEUTRAL)
+           {
+             unsigned flag = 0;
+             int sp;
+
+             /* 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);
+                 l2r_seen = true;
+                 break;
+               case STRONG_R:
+               case WEAK_EN:
+               case WEAK_AN:
+                 flag = ((embedding_level & 1) == 1
+                         ? FLAG_EMBEDDING_INSIDE
+                         : FLAG_OPPOSITE_INSIDE);
+                 r2l_seen = true;
+                 break;
+               default:
+                 break;
+               }
+             if (flag)
+               {
+                 for (sp = bpa_sp; sp >= 0; sp--)
+                   bpa_stack[sp].flags |= flag;
+               }
+           }
+         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
+             && (ISOLATE_STATUS (bidi_it, new_sidx)
+                 || (new_sidx > old_sidx + 1
+                     && ISOLATE_STATUS (bidi_it, new_sidx - 1))))
+           {
+             while (bidi_it->level_stack[bidi_it->stack_idx].level
+                    > current_level)
+               {
+                 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);
+               }
+           }
+         if (type == NEUTRAL_B
+             || (bidi_it->level_stack[bidi_it->stack_idx].level
+                 != current_level))
+           {
+             /* 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.  Leave
+                their type unchanged.  */
+             pairing_pos = bidi_it->charpos;
+             break;
+           }
+         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;
+       }
+
+      /* 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_neutral (struct bidi_it *bidi_it)
+bidi_resolve_brackets (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;
+  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);
 
-  eassert ((type == STRONG_R
-           || type == STRONG_L
-           || type == WEAK_BN
-           || type == WEAK_EN
-           || type == WEAK_AN
-           || type == NEUTRAL_B
-           || type == NEUTRAL_S
-           || type == NEUTRAL_WS
-           || type == NEUTRAL_ON));
+  /* 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;
+       }
+    }
 
-  eassert (prev_level >= 0);
+  /* 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;
+}
+
+static bidi_type_t
+bidi_resolve_neutral (struct bidi_it *bidi_it)
+{
+  bidi_type_t type = bidi_resolve_brackets (bidi_it);
+  int current_level;
+  bool is_neutral;
+
+  eassert (type == STRONG_R
+          || type == STRONG_L
+          || type == WEAK_BN
+          || type == WEAK_EN
+          || type == WEAK_AN
+          || type == NEUTRAL_B
+          || type == NEUTRAL_S
+          || type == NEUTRAL_WS
+          || type == NEUTRAL_ON
+          || type == LRI
+          || type == RLI
+          || type == PDI);
+
+  current_level = bidi_it->level_stack[bidi_it->stack_idx].level;
   eassert (current_level >= 0);
+  is_neutral = bidi_get_category (type) == NEUTRAL;
+
   if ((type != NEUTRAL_B /* Don't risk entering the long loop below if
                            we are already at paragraph end.  */
-       && bidi_get_category (type) == NEUTRAL)
-      || (type == WEAK_BN && prev_level == current_level))
+       && (is_neutral || bidi_isolate_fmt_char (type)))
+      /* N1-N2/Retaining */
+      || (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
@@ -2321,7 +2973,8 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
         entering the expensive loop in the "else" clause.  */
       else if (current_level == 0
               && bidi_it->prev_for_neutral.type == STRONG_L
-              && !bidi_explicit_dir_char (bidi_it->ch))
+              && !bidi_explicit_dir_char (bidi_it->ch)
+              && !bidi_isolate_fmt_char (type))
        type = bidi_resolve_neutral_1 (bidi_it->prev_for_neutral.type,
                                       STRONG_L, current_level);
       else if (/* current level is 1 */
@@ -2333,7 +2986,8 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
               && (bidi_it->prev_for_neutral.type == STRONG_R
                   || bidi_it->prev_for_neutral.type == WEAK_EN
                   || bidi_it->prev_for_neutral.type == WEAK_AN)
-              && !bidi_explicit_dir_char (bidi_it->ch))
+              && !bidi_explicit_dir_char (bidi_it->ch)
+              && !bidi_isolate_fmt_char (type))
        type = bidi_resolve_neutral_1 (bidi_it->prev_for_neutral.type,
                                       STRONG_R, current_level);
       else
@@ -2348,85 +3002,107 @@ bidi_resolve_neutral (struct bidi_it *bidi_it)
             implementations!  */
          struct bidi_it saved_it;
          bidi_type_t next_type;
-
-         if (bidi_it->scan_dir == -1)
-           emacs_abort ();
+         bool adjacent_to_neutrals = is_neutral;
 
          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
             are dealing with now.  We also cache the scanned iterator
             states, to salvage some of the effort later.  */
-         bidi_cache_iterator_state (bidi_it, 0);
          do {
-           /* Record the info about the previous character, so that
-              it will be cached below 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);
-           type = bidi_resolve_weak (bidi_it);
+           int old_sidx, new_sidx;
+
            /* Paragraph separators have their levels fully resolved
               at this point, so cache them as resolved.  */
-           bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B);
-           /* FIXME: implement L1 here, by testing for a newline and
-              resetting the level for any sequence of whitespace
-              characters adjacent to it.  */
+           bidi_cache_iterator_state (bidi_it, type == NEUTRAL_B, 0);
+           old_sidx = bidi_it->stack_idx;
+           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
+               && (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
+                       && 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, 0);
+                   type = bidi_resolve_brackets (bidi_it);
+                 }
+             }
+           if (!adjacent_to_neutrals
+               && (bidi_get_category (type) == NEUTRAL
+                   || bidi_isolate_fmt_char (type)))
+             adjacent_to_neutrals = true;
          } while (!(type == NEUTRAL_B
                     || (type != WEAK_BN
-                        && bidi_get_category (type) != NEUTRAL)
+                        && bidi_get_category (type) != NEUTRAL
+                        && !bidi_isolate_fmt_char (type))
                     /* This is all per level run, so stop when we
                        reach the end of this level run.  */
                     || (bidi_it->level_stack[bidi_it->stack_idx].level
                         != current_level)));
 
-         bidi_remember_char (&saved_it.next_for_neutral, bidi_it);
+         /* Record the character we stopped at.  */
+         bidi_remember_char (&saved_it.next_for_neutral, bidi_it, 1);
 
-         switch (type)
+         if ((bidi_it->level_stack[bidi_it->stack_idx].level != current_level)
+             || type == NEUTRAL_B)
            {
-             case STRONG_L:
-             case STRONG_R:
-             case STRONG_AL:
-               /* Actually, STRONG_AL cannot happen here, because
-                  bidi_resolve_weak converts it to STRONG_R, per W3.  */
-               eassert (type != STRONG_AL);
-               next_type = type;
-               break;
-             case WEAK_EN:
-             case WEAK_AN:
-               /* N1: ``European and Arabic numbers are treated as
-                  though they were R.''  */
-               next_type = STRONG_R;
-               break;
-             case WEAK_BN:
-             case NEUTRAL_ON:  /* W6/Retaining */
-               if (!bidi_explicit_dir_char (bidi_it->ch))
-                 emacs_abort (); /* can't happen: BNs are skipped */
-               /* FALLTHROUGH */
-             case NEUTRAL_B:
-               /* Marched all the way to the end of this level run.
-                  We need to use the eos type, whose information is
-                  stored by bidi_set_sos_type in the prev_for_neutral
-                  member.  */
-               if (saved_it.type != WEAK_BN
-                   || bidi_get_category (bidi_it->prev.type_after_w1) == NEUTRAL)
-                 next_type = bidi_it->prev_for_neutral.type;
-               else
-                 {
-                   /* This is a BN which does not adjoin neutrals.
-                      Leave its type alone.  */
-                   bidi_copy_it (bidi_it, &saved_it);
-                   return bidi_it->type;
-                 }
-               break;
-             default:
-               emacs_abort ();
+             /* Marched all the way to the end of this level run.  We
+                need to use the eos type, whose information is stored
+                by bidi_set_sos_type in the prev_for_neutral
+                member.  */
+             if (adjacent_to_neutrals)
+               next_type = bidi_it->prev_for_neutral.type;
+             else
+               {
+                 /* This is a BN which does not adjoin neutrals.
+                    Leave its type alone.  */
+                 bidi_copy_it (bidi_it, &saved_it);
+                 return bidi_it->type;
+               }
+           }
+         else
+           {
+             switch (type)
+               {
+               case STRONG_L:
+               case STRONG_R:
+               case STRONG_AL:
+                 /* Actually, STRONG_AL cannot happen here, because
+                    bidi_resolve_weak converts it to STRONG_R, per W3.  */
+                 eassert (type != STRONG_AL);
+                 next_type = type;
+                 break;
+               case WEAK_EN:
+               case WEAK_AN:
+                 /* N1: "European and Arabic numbers act as if they
+                    were R in terms of their influence on NIs."  */
+                 next_type = STRONG_R;
+                 break;
+               default:
+                 emacs_abort ();
+                 break;
+               }
            }
+         /* Resolve the type of all the NIs found during the above loop.  */
          type = bidi_resolve_neutral_1 (saved_it.prev_for_neutral.type,
                                         next_type, current_level);
+         /* Update next_for_neutral with the resolved type, so we
+            could use it for all the other NIs up to the place where
+            we exited the loop.  */
          saved_it.next_for_neutral.type = next_type;
+         bidi_check_type (type);
+         /* Update the character which caused us to enter the above loop.  */
          saved_it.type = type;
          bidi_check_type (next_type);
-         bidi_check_type (type);
          bidi_copy_it (bidi_it, &saved_it);
        }
     }
@@ -2446,14 +3122,6 @@ bidi_type_of_next_char (struct bidi_it *bidi_it)
   if (bidi_it->scan_dir != 1)
     emacs_abort ();
 
-  /* Reset the limit until which to ignore BNs if we step out of the
-     area where we found only empty levels.  */
-  if ((bidi_it->ignore_bn_limit > -1
-       && bidi_it->ignore_bn_limit <= bidi_it->charpos)
-      || (bidi_it->ignore_bn_limit == -2
-         && !bidi_explicit_dir_char (bidi_it->ch)))
-    bidi_it->ignore_bn_limit = -1;
-
   type = bidi_resolve_neutral (bidi_it);
 
   return type;
@@ -2466,9 +3134,8 @@ 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;
 
   if (bidi_it->scan_dir == 1)
@@ -2477,58 +3144,23 @@ 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);
+
       if (bidi_it->scan_dir > 0)
        {
          if (bidi_it->nchars <= 0)
@@ -2542,32 +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, -1, bidi_it);
-      else
-       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;
        }
     }
+
   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.  */
@@ -2583,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 */)
-      || (type == WEAK_BN && prev_level == level))
-    {
-      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
@@ -2607,8 +3210,9 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
   /* For L1 below, we need to know, for each WS character, whether
      it belongs to a sequence of WS characters preceding a newline
      or a TAB or a paragraph separator.  */
-  if (bidi_it->orig_type == NEUTRAL_WS
-      && bidi_it->next_for_ws.type == UNKNOWN_BT)
+  if ((bidi_it->orig_type == NEUTRAL_WS
+       || bidi_isolate_fmt_char (bidi_it->orig_type))
+      && bidi_it->next_for_ws.charpos < bidi_it->charpos)
     {
       int ch;
       ptrdiff_t clen = bidi_it->ch_len;
@@ -2628,49 +3232,18 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
                              bidi_it->w, fwp, &clen, &nc);
        chtype = bidi_get_type (ch, NEUTRAL_DIR);
       } while (chtype == NEUTRAL_WS || chtype == WEAK_BN
+              || bidi_isolate_fmt_char (chtype)
               || bidi_explicit_dir_char (ch)); /* L1/Retaining */
       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;
     }
 
-  /* Resolve implicit levels, with a twist: PDFs get the embedding
-     level of the embedding they terminate.  See below for the
-     reason.  */
-  if (bidi_it->orig_type == PDF
-      /* Don't do this if this formatting code didn't change the
-        embedding level due to invalid or empty embeddings.  */
-      && prev_level != level)
-    {
-      /* Don't look in UAX#9 for the reason for this: it's our own
-        private quirk.  The reason is that we want the formatting
-        codes to be delivered so that they bracket the text of their
-        embedding.  For example, given the text
-
-            {RLO}teST{PDF}
+  /* Update the cache, but only if this state was already cached.  */
+  bidi_cache_iterator_state (bidi_it, 1, 1);
 
-        we want it to be displayed as
-
-            {PDF}STet{RLO}
-
-        not as
-
-            STet{RLO}{PDF}
-
-        which will result because we bump up the embedding level as
-        soon as we see the RLO and pop it as soon as we see the PDF,
-        so RLO itself has the same embedding level as "teST", and
-        thus would be normally delivered last, just before the PDF.
-        The switch below fiddles with the level of PDF so that this
-        ugly side effect does not happen.
-
-        (This is, of course, only important if the formatting codes
-        are actually displayed, but Emacs does need to display them
-        if the user wants to.)  */
-      level = prev_level;
-    }
-  else if (bidi_it->orig_type == NEUTRAL_B /* L1 */
+  /* Resolve implicit levels.  */
+  if (bidi_it->orig_type == NEUTRAL_B /* L1 */
           || bidi_it->orig_type == NEUTRAL_S
           || bidi_it->ch == '\n' || bidi_it->ch == BIDI_EOB
           || (bidi_it->orig_type == NEUTRAL_WS
@@ -2690,8 +3263,6 @@ bidi_level_of_next_char (struct bidi_it *bidi_it)
        level++;
     }
 
-  /* FIXME: Exempt explicit directional characters from the assignment
-     below, and remove the PDF hack above.  */
   bidi_it->resolved_level = level;
   return level;
 }
@@ -2734,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);
     }
 }
@@ -2781,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;
@@ -2891,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;