Use const, move declarations to header files.
[bpt/emacs.git] / src / composite.c
index a24abd0..dbd7e3d 100644 (file)
@@ -1,7 +1,7 @@
 /* Composite sequence support.
    Copyright (C) 2001, 2002, 2003, 2004, 2005,
-                 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
-   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
+                 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
      National Institute of Advanced Industrial Science and Technology (AIST)
      Registration Number H14PRO021
    Copyright (C) 2003, 2006
@@ -74,8 +74,8 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
        composition rules to tell how to compose (2N+2)th element with
        the previously composed 2N glyphs.
 
-   COMPONENTS-VEC -- Vector of integers.  In relative composition, the
-       elements are characters to be composed.  In rule-base
+   COMPONENTS-VEC -- Vector of integers.  In a relative composition,
+       the elements are the characters to be composed.  In a rule-base
        composition, the elements are characters or encoded
        composition rules.
 
@@ -95,13 +95,13 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
    get_composition_id checks the validity of `composition' property,
    and, if valid, assigns a new ID, registers the information in
    composition_hash_table and composition_table, and changes the form
-   of the property value.  If the property is invalid, return -1
-   without changing the property value.
+   of the property value.  If the property is invalid,
+   get_composition_id returns -1 without changing the property value.
 
-   We use two tables to keep information about composition;
+   We use two tables to keep the information about composition;
    composition_hash_table and composition_table.
 
-   The former is a hash table in which keys are COMPONENTS-VECs and
+   The former is a hash table whose keys are COMPONENTS-VECs and
    values are the corresponding COMPOSITION-IDs.  This hash table is
    weak, but as each key (COMPONENTS-VEC) is also kept as a value of the
    `composition' property, it won't be collected as garbage until all
@@ -157,12 +157,13 @@ Lisp_Object composition_hash_table;
 Lisp_Object Vcompose_chars_after_function;
 
 Lisp_Object Qauto_composed;
+Lisp_Object Vauto_composition_mode;
 Lisp_Object Vauto_composition_function;
 Lisp_Object Qauto_composition_function;
 Lisp_Object Vcomposition_function_table;
 
-/* Maxinum number of characters to lookback to check
-   auto-composition.  */
+/* Maximum number of characters to look back for
+   auto-compositions.  */
 #define MAX_AUTO_COMPOSITION_LOOKBACK 3
 
 EXFUN (Fremove_list_of_text_properties, 4);
@@ -179,9 +180,7 @@ Lisp_Object composition_temp;
    If the composition is invalid, return -1.  */
 
 int
-get_composition_id (charpos, bytepos, nchars, prop, string)
-     int charpos, bytepos, nchars;
-     Lisp_Object prop, string;
+get_composition_id (int charpos, int bytepos, int nchars, Lisp_Object prop, Lisp_Object string)
 {
   Lisp_Object id, length, components, key, *key_contents;
   int glyph_len;
@@ -428,10 +427,7 @@ get_composition_id (charpos, bytepos, nchars, prop, string)
    This doesn't check the validity of composition.  */
 
 int
-find_composition (pos, limit, start, end, prop, object)
-     int pos, limit;
-     EMACS_INT *start, *end;
-     Lisp_Object *prop, object;
+find_composition (int pos, int limit, EMACS_INT *start, EMACS_INT *end, Lisp_Object *prop, Lisp_Object object)
 {
   Lisp_Object val;
 
@@ -469,9 +465,7 @@ find_composition (pos, limit, start, end, prop, object)
    FROM and TO with property PROP.  */
 
 static void
-run_composition_function (from, to, prop)
-     int from, to;
-     Lisp_Object prop;
+run_composition_function (int from, int to, Lisp_Object prop)
 {
   Lisp_Object func;
   EMACS_INT start, end;
@@ -503,9 +497,7 @@ run_composition_function (from, to, prop)
    change is deletion, FROM == TO.  Otherwise, FROM < TO.  */
 
 void
-update_compositions (from, to, check_mask)
-     EMACS_INT from, to;
-     int check_mask;
+update_compositions (EMACS_INT from, EMACS_INT to, int check_mask)
 {
   Lisp_Object prop;
   EMACS_INT start, end;
@@ -611,8 +603,7 @@ update_compositions (from, to, check_mask)
    top-level copies of them so that none of them are `eq'.  */
 
 void
-make_composition_value_copy (list)
-     Lisp_Object list;
+make_composition_value_copy (Lisp_Object list)
 {
   Lisp_Object plist, val;
 
@@ -637,9 +628,7 @@ make_composition_value_copy (list)
    indices START and END in STRING.  */
 
 void
-compose_text (start, end, components, modification_func, string)
-     int start, end;
-     Lisp_Object components, modification_func, string;
+compose_text (int start, int end, Lisp_Object components, Lisp_Object modification_func, Lisp_Object string)
 {
   Lisp_Object prop;
 
@@ -650,9 +639,9 @@ compose_text (start, end, components, modification_func, string)
 }
 
 
-static Lisp_Object autocmp_chars P_ ((Lisp_Object, EMACS_INT, EMACS_INT,
-                                     EMACS_INT, struct window *,
-                                     struct face *, Lisp_Object));
+static Lisp_Object autocmp_chars (Lisp_Object, EMACS_INT, EMACS_INT,
+                                  EMACS_INT, struct window *,
+                                  struct face *, Lisp_Object);
 
 \f
 /* Lisp glyph-string handlers */
@@ -663,11 +652,10 @@ static Lisp_Object autocmp_chars P_ ((Lisp_Object, EMACS_INT, EMACS_INT,
 
 static Lisp_Object gstring_hash_table;
 
-static Lisp_Object gstring_lookup_cache P_ ((Lisp_Object));
+static Lisp_Object gstring_lookup_cache (Lisp_Object);
 
 static Lisp_Object
-gstring_lookup_cache (header)
-     Lisp_Object header;
+gstring_lookup_cache (Lisp_Object header)
 {
   struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
   int i = hash_lookup (h, header, NULL);
@@ -676,9 +664,7 @@ gstring_lookup_cache (header)
 }
 
 Lisp_Object
-composition_gstring_put_cache (gstring, len)
-     Lisp_Object gstring;
-     int len;
+composition_gstring_put_cache (Lisp_Object gstring, int len)
 {
   struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
   unsigned hash;
@@ -706,21 +692,19 @@ composition_gstring_put_cache (gstring, len)
 }
 
 Lisp_Object
-composition_gstring_from_id (id)
-     int id;
+composition_gstring_from_id (int id)
 {
   struct Lisp_Hash_Table *h = XHASH_TABLE (gstring_hash_table);
 
   return HASH_VALUE (h, id);
 }
 
-static Lisp_Object fill_gstring_header P_ ((Lisp_Object, Lisp_Object,
-                                           Lisp_Object, Lisp_Object,
-                                           Lisp_Object));
+static Lisp_Object fill_gstring_header (Lisp_Object, Lisp_Object,
+                                        Lisp_Object, Lisp_Object,
+                                        Lisp_Object);
 
 int
-composition_gstring_p (gstring)
-     Lisp_Object gstring;
+composition_gstring_p (Lisp_Object gstring)
 {
   Lisp_Object header;
   int i;
@@ -751,10 +735,7 @@ composition_gstring_p (gstring)
 }
 
 int
-composition_gstring_width (gstring, from, to, metrics)
-     Lisp_Object gstring;
-     int from, to;
-     struct font_metrics *metrics;
+composition_gstring_width (Lisp_Object gstring, int from, int to, struct font_metrics *metrics)
 {
   Lisp_Object *glyph;
   int width = 0;
@@ -810,8 +791,7 @@ static Lisp_Object gstring_work;
 static Lisp_Object gstring_work_headers;
 
 static Lisp_Object
-fill_gstring_header (header, start, end, font_object, string)
-     Lisp_Object header, start, end, font_object, string;
+fill_gstring_header (Lisp_Object header, Lisp_Object start, Lisp_Object end, Lisp_Object font_object, Lisp_Object string)
 {
   EMACS_INT from, to, from_byte;
   EMACS_INT len, i;
@@ -868,11 +848,10 @@ fill_gstring_header (header, start, end, font_object, string)
   return header;
 }
 
-extern void font_fill_lglyph_metrics P_ ((Lisp_Object, Lisp_Object));
+extern void font_fill_lglyph_metrics (Lisp_Object, Lisp_Object);
 
 static void
-fill_gstring_body (gstring)
-     Lisp_Object gstring;
+fill_gstring_body (Lisp_Object gstring)
 {
   Lisp_Object font_object = LGSTRING_FONT (gstring);
   Lisp_Object header = AREF (gstring, 0);
@@ -914,171 +893,318 @@ fill_gstring_body (gstring)
 }
 
 
-/* Try to compose the characters at CHARPOS according to CFT_ELEMENT
-   which is an element of composition-function-table (which see).
-   LIMIT limits the characters to compose.  STRING, if not nil, is a
-   target string.  WIN is a window where the characters are being
-   displayed.  */
+/* Try to compose the characters at CHARPOS according to composition
+   rule RULE ([PATTERN PREV-CHARS FUNC]).  LIMIT limits the characters
+   to compose.  STRING, if not nil, is a target string.  WIN is a
+   window where the characters are being displayed.  If characters are
+   successfully composed, return the composition as a glyph-string
+   object.  Otherwise return nil.  */
 
 static Lisp_Object
-autocmp_chars (cft_element, charpos, bytepos, limit, win, face, string)
-     Lisp_Object cft_element;
-     EMACS_INT charpos, bytepos, limit;
-     struct window *win;
-     struct face *face;
-     Lisp_Object string;
+autocmp_chars (Lisp_Object rule, EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT limit, struct window *win, struct face *face, Lisp_Object string)
 {
   int count = SPECPDL_INDEX ();
   FRAME_PTR f = XFRAME (win->frame);
   Lisp_Object pos = make_number (charpos);
+  EMACS_INT to;
   EMACS_INT pt = PT, pt_byte = PT_BYTE;
-  int lookback;
+  Lisp_Object re, font_object, lgstring;
+  int len;
 
   record_unwind_save_match_data ();
-  for (lookback = -1; CONSP (cft_element); cft_element = XCDR (cft_element))
+  re = AREF (rule, 0);
+  if (NILP (re))
+    len = 1;
+  else if (! STRINGP (re))
+    return unbind_to (count, Qnil);
+  else if ((len = fast_looking_at (re, charpos, bytepos, limit, -1, string))
+          > 0)
     {
-      Lisp_Object elt = XCAR (cft_element);
-      Lisp_Object re;
-      Lisp_Object font_object = Qnil, gstring;
-      EMACS_INT len, to;
-
-      if (! VECTORP (elt) || ASIZE (elt) != 3)
-       continue;
-      if (lookback < 0)
-       {
-         lookback = XFASTINT (AREF (elt, 1));
-         if (limit > charpos + MAX_COMPOSITION_COMPONENTS)
-           limit = charpos + MAX_COMPOSITION_COMPONENTS;
-       }
-      else if (lookback != XFASTINT (AREF (elt, 1)))
-       break;
-      re = AREF (elt, 0);
-      if (NILP (re))
-       len = 1;
-      else if ((len = fast_looking_at (re, charpos, bytepos, limit, -1, string))
-              > 0)
-       {
-         if (NILP (string))
-           len = BYTE_TO_CHAR (bytepos + len) - charpos;
-         else
-           len = string_byte_to_char (string, bytepos + len) - charpos;
-       }
-      if (len > 0)
-       {
-         limit = to = charpos + len;
+      if (NILP (string))
+       len = BYTE_TO_CHAR (bytepos + len) - charpos;
+      else
+       len = string_byte_to_char (string, bytepos + len) - charpos;
+    }
+  if (len <= 0)
+    return unbind_to (count, Qnil);
+  to = limit = charpos + len;
 #ifdef HAVE_WINDOW_SYSTEM
-         if (FRAME_WINDOW_P (f))
-           {
-             font_object = font_range (charpos, &to, win, face, string);
-             if (! FONT_OBJECT_P (font_object)
-                 || (! NILP (re)
-                     && to < limit
-                     && (fast_looking_at (re, charpos, bytepos, to, -1, string) <= 0)))
-               {
-                 if (NILP (string))
-                   TEMP_SET_PT_BOTH (pt, pt_byte);
-                 return unbind_to (count, Qnil);
-               }
-           }
-         else
+  if (FRAME_WINDOW_P (f))
+    {
+      font_object = font_range (charpos, &to, win, face, string);
+      if (! FONT_OBJECT_P (font_object)
+         || (! NILP (re)
+             && to < limit
+             && (fast_looking_at (re, charpos, bytepos, to, -1, string) <= 0)))
+       return unbind_to (count, Qnil);
+    }
+  else
 #endif /* not HAVE_WINDOW_SYSTEM */
-           font_object = win->frame;
-         gstring = Fcomposition_get_gstring (pos, make_number (to),
-                                             font_object, string);
-         if (NILP (LGSTRING_ID (gstring)))
-           {
-             Lisp_Object args[6];
-
-             args[0] = Vauto_composition_function;
-             args[1] = AREF (elt, 2);
-             args[2] = pos;
-             args[3] = make_number (to);
-             args[4] = font_object;
-             args[5] = string;
-             gstring = safe_call (6, args);
-           }
-         if (NILP (string))
-           TEMP_SET_PT_BOTH (pt, pt_byte);
-         return unbind_to (count, gstring);
+    font_object = win->frame;
+  lgstring = Fcomposition_get_gstring (pos, make_number (to), font_object,
+                                      string);
+  if (NILP (LGSTRING_ID (lgstring)))
+    {
+      Lisp_Object args[6];
+
+      /* Save point as marker before calling out to lisp.  */
+      if (NILP (string))
+       {
+         Lisp_Object m = Fmake_marker ();
+         set_marker_both (m, Qnil, pt, pt_byte);
+         record_unwind_protect (restore_point_unwind, m);
        }
+
+      args[0] = Vauto_composition_function;
+      args[1] = AREF (rule, 2);
+      args[2] = pos;
+      args[3] = make_number (to);
+      args[4] = font_object;
+      args[5] = string;
+      lgstring = safe_call (6, args);
+      if (NILP (string))
+       TEMP_SET_PT_BOTH (pt, pt_byte);
     }
-  if (NILP (string))
-    TEMP_SET_PT_BOTH (pt, pt_byte);
-  return unbind_to (count, Qnil);
+  return unbind_to (count, lgstring);
 }
 
+static Lisp_Object _work_val;
+static int _work_char;
+
+/* 1 iff the character C is composable.  */
+#define CHAR_COMPOSABLE_P(C)                                           \
+  ((C) == 0x200C || (C) == 0x200D                                      \
+   || (_work_val = CHAR_TABLE_REF (Vunicode_category_table, (C)),      \
+       (SYMBOLP (_work_val)                                            \
+       && (_work_char = SDATA (SYMBOL_NAME (_work_val))[0]) != 'C'     \
+       && _work_char != 'Z')))
 
 /* Update cmp_it->stop_pos to the next position after CHARPOS (and
    BYTEPOS) where character composition may happen.  If BYTEPOS is
-   negative, compoute it.  If it is a static composition, set
-   cmp_it->ch to -1.  Otherwise, set cmp_it->ch to the character that
-   triggers a automatic composition.  */
+   negative, compute it.  ENDPOS is a limit of searching.  If it is
+   less than CHARPOS, search backward to ENDPOS+1 assuming that
+   set_iterator_to_next works in reverse order.  In this case, if a
+   composition closest to CHARPOS is found, set cmp_it->stop_pos to
+   the last character of the composition.
+
+   If no composition is found, set cmp_it->ch to -2.  If a static
+   composition is found, set cmp_it->ch to -1.  Otherwise, set
+   cmp_it->ch to the character that triggers the automatic
+   composition.  */
 
 void
-composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string)
-     struct composition_it *cmp_it;
-     EMACS_INT charpos, bytepos, endpos;
-     Lisp_Object string;
+composition_compute_stop_pos (struct composition_it *cmp_it, EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT endpos, Lisp_Object string)
 {
   EMACS_INT start, end, c;
   Lisp_Object prop, val;
   /* This is from forward_to_next_line_start in xdisp.c.  */
   const int MAX_NEWLINE_DISTANCE = 500;
 
-  if (endpos > charpos + MAX_NEWLINE_DISTANCE)
-    endpos = charpos + MAX_NEWLINE_DISTANCE;
-  cmp_it->stop_pos = endpos;
+  if (charpos < endpos)
+    {
+      if (endpos > charpos + MAX_NEWLINE_DISTANCE)
+       endpos = charpos + MAX_NEWLINE_DISTANCE;
+    }
+  else if (endpos < charpos)
+    {
+      /* We search backward for a position to check composition.  */
+      if (endpos < 0)
+       {
+         /* But we don't know where to stop the searching.  */
+         endpos = NILP (string) ? BEGV - 1 : -1;
+         /* Usually we don't reach ENDPOS because we stop searching
+            at an uncomposable character (NL, LRE, etc).  */
+       }
+    }
   cmp_it->id = -1;
   cmp_it->ch = -2;
-  if (find_composition (charpos, endpos, &start, &end, &prop, string)
+  cmp_it->reversed_p = 0;
+  cmp_it->stop_pos = endpos;
+  if (charpos == endpos)
+    return;
+  /* FIXME: Bidi is not yet handled well in static composition.  */
+  if (charpos < endpos
+      && find_composition (charpos, endpos, &start, &end, &prop, string)
       && COMPOSITION_VALID_P (start, end, prop))
     {
       cmp_it->stop_pos = endpos = start;
       cmp_it->ch = -1;
     }
-  if (NILP (string) && PT > charpos && PT < endpos)
-    cmp_it->stop_pos = PT;
+  if (NILP (string))
+    {
+      /* A composition never strides over PT.  */
+      if (PT > charpos)
+       {
+         if (PT < endpos)
+           cmp_it->stop_pos = endpos = PT;
+       }
+      else if (PT < charpos && PT > endpos)
+       {
+         cmp_it->stop_pos = endpos = PT - 1;
+       }
+    }
   if (NILP (current_buffer->enable_multibyte_characters)
-      || ! FUNCTIONP (Vauto_composition_function))
+      || NILP (Vauto_composition_mode))
     return;
   if (bytepos < 0)
     {
-      if (STRINGP (string))
-       bytepos = string_char_to_byte (string, charpos);
-      else
+      if (NILP (string))
        bytepos = CHAR_TO_BYTE (charpos);
+      else
+       bytepos = string_char_to_byte (string, charpos);
     }
 
   start = charpos;
-  while (charpos < endpos)
+  if (charpos < endpos)
     {
-      if (STRINGP (string))
-       FETCH_STRING_CHAR_ADVANCE (c, string, charpos, bytepos);
-      else
-       FETCH_CHAR_ADVANCE (c, charpos, bytepos);
-      if (c == '\n')
+      /* Forward search.  */
+      while (charpos < endpos)
        {
-         cmp_it->ch = -2;
-         break;
+         if (STRINGP (string))
+           FETCH_STRING_CHAR_ADVANCE (c, string, charpos, bytepos);
+         else
+           FETCH_CHAR_ADVANCE (c, charpos, bytepos);
+         if (c == '\n')
+           {
+             cmp_it->ch = -2;
+             break;
+           }
+         val = CHAR_TABLE_REF (Vcomposition_function_table, c);
+         if (! NILP (val))
+           {
+             Lisp_Object elt;
+             int ridx;
+
+             for (ridx = 0; CONSP (val); val = XCDR (val), ridx++)
+               {
+                 elt = XCAR (val);
+                 if (VECTORP (elt) && ASIZE (elt) == 3
+                     && NATNUMP (AREF (elt, 1))
+                     && charpos - 1 - XFASTINT (AREF (elt, 1)) >= start)
+                   break;
+               }
+             if (CONSP (val))
+               {
+                 cmp_it->rule_idx = ridx;
+                 cmp_it->lookback = XFASTINT (AREF (elt, 1));
+                 cmp_it->stop_pos = charpos - 1 - cmp_it->lookback;
+                 cmp_it->ch = c;
+                 return;
+               }
+           }
        }
-      val = CHAR_TABLE_REF (Vcomposition_function_table, c);
-      if (! NILP (val))
+    }
+  else if (charpos > endpos)
+    {
+      /* Search backward for a pattern that may be composed and the
+        position of (possibly) the last character of the match is
+        closest to (but not after) START.  The reason for the last
+        character is that set_iterator_to_next works in reverse order,
+        and thus we must stop at the last character for composition
+        check.  */
+      unsigned char *p;
+      int len;
+      /* Limit byte position used in fast_looking_at.  This is the
+        byte position of the character after START. */
+      EMACS_INT limit;
+
+      if (NILP (string))
+       p = BYTE_POS_ADDR (bytepos);
+      else
+       p = SDATA (string) + bytepos;
+      c = STRING_CHAR_AND_LENGTH (p, len);
+      limit = bytepos + len;
+      while (CHAR_COMPOSABLE_P (c))
        {
-         Lisp_Object elt;
+         val = CHAR_TABLE_REF (Vcomposition_function_table, c);
+         if (! NILP (val))
+           {
+             Lisp_Object elt;
+             int ridx, back, len;
 
-         for (; CONSP (val); val = XCDR (val))
+             for (ridx = 0; CONSP (val); val = XCDR (val), ridx++)
+               {
+                 elt = XCAR (val);
+                 if (VECTORP (elt) && ASIZE (elt) == 3
+                     && NATNUMP (AREF (elt, 1))
+                     && charpos - (back = XFASTINT (AREF (elt, 1))) > endpos)
+                   {
+                     EMACS_INT cpos = charpos - back, bpos;
+
+                     if (back == 0)
+                       bpos = bytepos;
+                     else
+                       bpos = (NILP (string) ? CHAR_TO_BYTE (cpos)
+                               : string_char_to_byte (string, cpos));
+                     if (STRINGP (AREF (elt, 0)))
+                       len = fast_looking_at (AREF (elt, 0), cpos, bpos,
+                                              start + 1, limit, string);
+                     else
+                       len = 1;
+                     if (len > 0)
+                       {
+                         /* Make CPOS point to the last character of
+                            match.  Note that LEN is byte-length.  */
+                         if (len > 1)
+                           {
+                             bpos += len;
+                             if (NILP (string))
+                               cpos = BYTE_TO_CHAR (bpos) - 1;
+                             else
+                               cpos = string_byte_to_char (string, bpos) - 1;
+                           }
+                         back = cpos - (charpos - back);
+                         if (cmp_it->stop_pos < cpos
+                             || (cmp_it->stop_pos == cpos
+                                 && cmp_it->lookback < back))
+                           {
+                             cmp_it->rule_idx = ridx;
+                             cmp_it->stop_pos = cpos;
+                             cmp_it->ch = c;
+                             cmp_it->lookback = back;
+                             cmp_it->nchars = back + 1;
+                           }
+                       }
+                   }
+               }
+           }
+         if (charpos - 1 == endpos)
+           break;
+         if (STRINGP (string))
            {
-             elt = XCAR (val);
-             if (VECTORP (elt) && ASIZE (elt) == 3 && NATNUMP (AREF (elt, 1))
-                 && charpos - 1 - XFASTINT (AREF (elt, 1)) >= start)
-               break;
+             p--, bytepos--;
+             while (! CHAR_HEAD_P (*p))
+               p--, bytepos--;
+             charpos--;
+           }
+         else
+           {
+             DEC_BOTH (charpos, bytepos);
+             p = BYTE_POS_ADDR (bytepos);
+           }
+         c = STRING_CHAR (p);
+       }
+      if (cmp_it->ch >= 0)
+       /* We found a position to check.  */
+       return;
+      /* Skip all uncomposable characters.  */
+      if (NILP (string))
+       {
+         while (charpos - 1 > endpos && ! CHAR_COMPOSABLE_P (c))
+           {
+             DEC_BOTH (charpos, bytepos);
+             c = FETCH_MULTIBYTE_CHAR (bytepos);
            }
-         if (CONSP (val))
+       }
+      else
+       {
+         while (charpos - 1 > endpos && ! CHAR_COMPOSABLE_P (c))
            {
-             cmp_it->lookback = XFASTINT (AREF (elt, 1));
-             cmp_it->stop_pos = charpos - 1 - cmp_it->lookback;
-             cmp_it->ch = c;
-             return;
+             p--;
+             while (! CHAR_HEAD_P (*p))
+               p--;
+             charpos--;
+             c = STRING_CHAR (p);
            }
        }
     }
@@ -1093,24 +1219,35 @@ composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string)
    string.  In that case, FACE must not be NULL.
 
    If the character is composed, setup members of CMP_IT (id, nglyphs,
-   and from), and return 1.  Otherwise, update CMP_IT->stop_pos, and
-   return 0.  */
+   from, to, reversed_p), and return 1.  Otherwise, update
+   CMP_IT->stop_pos, and return 0.  */
 
 int
-composition_reseat_it (cmp_it, charpos, bytepos, endpos, w, face, string)
-     struct composition_it *cmp_it;
-     EMACS_INT charpos, bytepos, endpos;
-     struct window *w;
-     struct face *face;
-     Lisp_Object string;
+composition_reseat_it (struct composition_it *cmp_it, EMACS_INT charpos, EMACS_INT bytepos, EMACS_INT endpos, struct window *w, struct face *face, Lisp_Object string)
 {
-  if (charpos < PT && PT < endpos)
-    endpos = PT;
+  if (endpos <= charpos)
+    {
+      if (NILP (string))
+       {
+         if (endpos < 0)
+           endpos = BEGV;
+         if (endpos < PT && PT < charpos)
+           endpos = PT;
+       }
+      else if (endpos < 0)
+       endpos = 0;
+    }
+  else
+    {
+      if (NILP (string) && charpos < PT && PT < endpos)
+       endpos = PT;
+    }
 
   if (cmp_it->ch == -2)
     {
       composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string);
-      if (cmp_it->ch == -2)
+      if (cmp_it->ch == -2 || cmp_it->stop_pos != charpos)
+       /* The current position is not composed.  */
        return 0;
     }
 
@@ -1130,57 +1267,131 @@ composition_reseat_it (cmp_it, charpos, bytepos, endpos, w, face, string)
     }
   else if (w)
     {
-      Lisp_Object val, elt;
-      int i;
+      Lisp_Object lgstring = Qnil;
+      Lisp_Object val, elt, re;
+      int len, i;
 
       val = CHAR_TABLE_REF (Vcomposition_function_table, cmp_it->ch);
-      for (; CONSP (val); val = XCDR (val))
+      for (i = 0; i < cmp_it->rule_idx; i++, val = XCDR (val));
+      if (charpos < endpos)
        {
-         elt = XCAR (val);
-         if (cmp_it->lookback == XFASTINT (AREF (elt, 1)))
-           break;
+         for (; CONSP (val); val = XCDR (val))
+           {
+             elt = XCAR (val);
+             if (! VECTORP (elt) || ASIZE (elt) != 3
+                 || ! INTEGERP (AREF (elt, 1)))
+               continue;
+             if (XFASTINT (AREF (elt, 1)) != cmp_it->lookback)
+               goto no_composition;
+             lgstring = autocmp_chars (elt, charpos, bytepos, endpos,
+                                       w, face, string);
+             if (composition_gstring_p (lgstring))
+               break;
+             lgstring = Qnil;
+             /* Composition failed perhaps because the font doesn't
+                support sufficient range of characters.  Try the
+                other composition rules if any.  */
+           }
+         cmp_it->reversed_p = 0;
        }
-      if (NILP (val))
-       goto no_composition;
+      else
+       {
+         EMACS_INT cpos = charpos, bpos = bytepos;
 
-      val = autocmp_chars (val, charpos, bytepos, endpos, w, face, string);
-      if (! composition_gstring_p (val))
+         while (1)
+           {
+             elt = XCAR (val);
+             if (cmp_it->lookback > 0)
+               {
+                 cpos -= cmp_it->lookback;
+                 if (STRINGP (string))
+                   bpos = string_char_to_byte (string, cpos);
+                 else
+                   bpos = CHAR_TO_BYTE (cpos);
+               }
+             lgstring = autocmp_chars (elt, cpos, bpos, charpos + 1, w, face,
+                                       string);
+             if (composition_gstring_p (lgstring)
+                 && cpos + LGSTRING_CHAR_LEN (lgstring) - 1 == charpos)
+               break;
+             /* Composition failed or didn't cover the current
+                character.  */
+             if (cmp_it->lookback == 0)
+               goto no_composition;
+             lgstring = Qnil;
+             /* Try to find a shorter compostion that starts after CPOS.  */
+             composition_compute_stop_pos (cmp_it, charpos, bytepos, cpos,
+                                           string);
+             if (cmp_it->ch == -2 || cmp_it->stop_pos < charpos)
+               goto no_composition;
+             val = CHAR_TABLE_REF (Vcomposition_function_table, cmp_it->ch);
+             for (i = 0; i < cmp_it->rule_idx; i++, val = XCDR (val));
+           }
+         cmp_it->reversed_p = 1;
+       }
+      if (NILP (lgstring))
        goto no_composition;
-      if (NILP (LGSTRING_ID (val)))
-       val = composition_gstring_put_cache (val, -1);
-      cmp_it->id = XINT (LGSTRING_ID (val));
-      for (i = 0; i < LGSTRING_GLYPH_LEN (val); i++)
-       if (NILP (LGSTRING_GLYPH (val, i)))
+      if (NILP (LGSTRING_ID (lgstring)))
+       lgstring = composition_gstring_put_cache (lgstring, -1);
+      cmp_it->id = XINT (LGSTRING_ID (lgstring));
+      for (i = 0; i < LGSTRING_GLYPH_LEN (lgstring); i++)
+       if (NILP (LGSTRING_GLYPH (lgstring, i)))
          break;
       cmp_it->nglyphs = i;
+      cmp_it->from = 0;
+      cmp_it->to = i;
     }
   else
     goto no_composition;
-  cmp_it->from = 0;
   return 1;
 
  no_composition:
-  charpos++;
-  if (STRINGP (string))
-    bytepos += MULTIBYTE_LENGTH_NO_CHECK (SDATA (string) + bytepos);
+  if (charpos == endpos)
+    return 0;
+  if (charpos < endpos)
+    {
+      charpos++;
+      if (NILP (string))
+       INC_POS (bytepos);
+      else
+       bytepos += BYTES_BY_CHAR_HEAD (*(SDATA (string) + bytepos));
+    }
   else
-    INC_POS (bytepos);
+    {
+      charpos--;
+      /* BYTEPOS is calculated in composition_compute_stop_pos */
+      bytepos = -1;
+    }
   composition_compute_stop_pos (cmp_it, charpos, bytepos, endpos, string);
   return 0;
 }
 
+/* Update charpos, nchars, nbytes, and width of the current grapheme
+   cluster.
+
+   If the composition is static or automatic in L2R context, the
+   cluster is identified by CMP_IT->from, and CHARPOS is the position
+   of the first character of the cluster.  In this case, update
+   CMP_IT->to too.
+
+   If the composition is automatic in R2L context, the cluster is
+   identified by CMP_IT->to, and CHARPOS is the position of the last
+   character of the cluster.  In this case, update CMP_IT->from too.
+
+   The return value is the character code of the first character of
+   the cluster, or -1 if the composition is somehow broken.  */
+
 int
-composition_update_it (cmp_it, charpos, bytepos, string)
-     struct composition_it *cmp_it;
-     EMACS_INT charpos, bytepos;
-     Lisp_Object string;
+composition_update_it (struct composition_it *cmp_it, EMACS_INT charpos, EMACS_INT bytepos, Lisp_Object string)
 {
   int i, c;
 
   if (cmp_it->ch < 0)
     {
+      /* static composition */
       struct composition *cmp = composition_table[cmp_it->id];
 
+      cmp_it->charpos = charpos;
       cmp_it->to = cmp_it->nglyphs;
       if (cmp_it->nglyphs == 0)
        c = -1;
@@ -1193,43 +1404,64 @@ composition_update_it (cmp_it, charpos, bytepos, string)
            c = ' ';
        }
       cmp_it->width = cmp->width;
+      charpos += cmp_it->nchars;
+      if (STRINGP (string))
+       cmp_it->nbytes = string_char_to_byte (string, charpos) - bytepos;
+      else
+       cmp_it->nbytes = CHAR_TO_BYTE (charpos) - bytepos;
     }
   else
     {
+      /* automatic composition */
       Lisp_Object gstring = composition_gstring_from_id (cmp_it->id);
+      Lisp_Object glyph;
+      int from, to;
 
       if (cmp_it->nglyphs == 0)
        {
-         c = -1;
          cmp_it->nchars = LGSTRING_CHAR_LEN (gstring);
          cmp_it->width = 0;
+         cmp_it->from = cmp_it->to = 0;
+         return -1;
        }
-      else
+      if (! cmp_it->reversed_p)
        {
-         Lisp_Object glyph = LGSTRING_GLYPH (gstring, cmp_it->from);
-         int from = LGLYPH_FROM (glyph);
-
-         c = XINT (LGSTRING_CHAR (gstring, from));
-         cmp_it->nchars = LGLYPH_TO (glyph) - from + 1;
-         cmp_it->width = (LGLYPH_WIDTH (glyph) > 0
-                          ? CHAR_WIDTH (LGLYPH_CHAR (glyph)) : 0);
+         glyph = LGSTRING_GLYPH (gstring, cmp_it->from);
+         from = LGLYPH_FROM (glyph);
          for (cmp_it->to = cmp_it->from + 1; cmp_it->to < cmp_it->nglyphs;
               cmp_it->to++)
            {
              glyph = LGSTRING_GLYPH (gstring, cmp_it->to);
              if (LGLYPH_FROM (glyph) != from)
                break;
-             if (LGLYPH_WIDTH (glyph) > 0)
-               cmp_it->width += CHAR_WIDTH (LGLYPH_CHAR (glyph));
            }
+         cmp_it->charpos = charpos;
+       }
+      else
+       {
+         glyph = LGSTRING_GLYPH (gstring, cmp_it->to - 1);
+         from = LGLYPH_FROM (glyph);
+         cmp_it->charpos = charpos - (LGLYPH_TO (glyph) - from);
+         for (cmp_it->from = cmp_it->to - 1; cmp_it->from > 0;
+              cmp_it->from--)
+           {
+             glyph = LGSTRING_GLYPH (gstring, cmp_it->from - 1);
+             if (LGLYPH_FROM (glyph) != from)
+               break;
+           }
+       }
+      glyph = LGSTRING_GLYPH (gstring, cmp_it->from);
+      cmp_it->nchars = LGLYPH_TO (glyph) + 1 - from;
+      cmp_it->nbytes = 0;
+      cmp_it->width = 0;
+      for (i = cmp_it->nchars - 1; i >= 0; i--)
+       {
+         c = XINT (LGSTRING_CHAR (gstring, i));
+         cmp_it->nbytes += CHAR_BYTES (c);
+         cmp_it->width = (LGLYPH_WIDTH (glyph) > 0
+                          ? CHAR_WIDTH (LGLYPH_CHAR (glyph)) : 0);
        }
     }
-
-  charpos += cmp_it->nchars;
-  if (STRINGP (string))
-    cmp_it->nbytes = string_char_to_byte (string, charpos) - bytepos;
-  else
-    cmp_it->nbytes = CHAR_TO_BYTE (charpos) - bytepos;
   return c;
 }
 
@@ -1240,7 +1472,7 @@ struct position_record
   unsigned char *p;
 };
 
-/* Update the members of POSTION to the next character boundary.  */
+/* Update the members of POSITION to the next character boundary.  */
 #define FORWARD_CHAR(POSITION, STOP)                                   \
   do {                                                                 \
     (POSITION).pos++;                                                  \
@@ -1256,7 +1488,7 @@ struct position_record
       }                                                                        \
   } while (0)
 
-/* Update the members of POSTION to the previous character boundary.  */
+/* Update the members of POSITION to the previous character boundary.  */
 #define BACKWARD_CHAR(POSITION, STOP)          \
   do {                                         \
     if ((POSITION).pos == STOP)                        \
@@ -1268,25 +1500,12 @@ struct position_record
     (POSITION).pos--;                          \
   } while (0)
 
-static Lisp_Object _work_val;
-static int _work_char;
-
-/* 1 iff the character C is composable.  */
-#define CHAR_COMPOSABLE_P(C)                                           \
-  ((C) == 0x200C || (C) == 0x200D                                      \
-   || (_work_val = CHAR_TABLE_REF (Vunicode_category_table, (C)),      \
-       (SYMBOLP (_work_val)                                            \
-       && (_work_char = SDATA (SYMBOL_NAME (_work_val))[0]) != 'C'     \
-       && _work_char != 'Z')))
-
 /* This is like find_composition, but find an automatic composition
    instead.  If found, set *GSTRING to the glyph-string representing
    the composition, and return 1.  Otherwise, return 0.  */
 
 static int
-find_automatic_composition (pos, limit, start, end, gstring, string)
-     EMACS_INT pos, limit, *start, *end;
-     Lisp_Object *gstring, string;
+find_automatic_composition (EMACS_INT pos, EMACS_INT limit, EMACS_INT *start, EMACS_INT *end, Lisp_Object *gstring, Lisp_Object string)
 {
   EMACS_INT head, tail, stop;
   /* Limit to check a composition after POS.  */
@@ -1409,7 +1628,7 @@ find_automatic_composition (pos, limit, start, end, gstring, string)
                    check.pos_byte = cur.pos_byte;
                  else
                    check.pos_byte = CHAR_TO_BYTE (check.pos);
-                 val = autocmp_chars (check_val, check.pos, check.pos_byte,
+                 val = autocmp_chars (elt, check.pos, check.pos_byte,
                                       tail, w, NULL, string);
                  need_adjustment = 1;
                  if (! NILP (val))
@@ -1428,7 +1647,7 @@ find_automatic_composition (pos, limit, start, end, gstring, string)
            }
          if (need_adjustment)
            {
-             /* As we have called Lisp, there's a possibilily that
+             /* As we have called Lisp, there's a possibility that
                 buffer/string is relocated.  */
              if (NILP (string))
                cur.p  = BYTE_POS_ADDR (cur.pos_byte);
@@ -1457,8 +1676,7 @@ find_automatic_composition (pos, limit, start, end, gstring, string)
    to NEW_PT.  */
 
 int
-composition_adjust_point (last_pt, new_pt)
-     EMACS_INT last_pt, new_pt;
+composition_adjust_point (EMACS_INT last_pt, EMACS_INT new_pt)
 {
   EMACS_INT charpos, bytepos, startpos, beg, end, pos;
   Lisp_Object val;
@@ -1478,7 +1696,7 @@ composition_adjust_point (last_pt, new_pt)
     }
 
   if (NILP (current_buffer->enable_multibyte_characters)
-      || ! FUNCTIONP (Vauto_composition_function))
+      || NILP (Vauto_composition_mode))
     return new_pt;
 
   /* Next check the automatic composition.  */
@@ -1540,8 +1758,7 @@ where
 
 If GLYPH is nil, the remaining elements of the glyph-string vector
 should be ignored.  */)
-     (from, to, font_object, string)
-     Lisp_Object font_object, from, to, string;
+  (Lisp_Object from, Lisp_Object to, Lisp_Object font_object, Lisp_Object string)
 {
   Lisp_Object gstring, header;
   EMACS_INT frompos, topos;
@@ -1586,8 +1803,7 @@ DEFUN ("compose-region-internal", Fcompose_region_internal,
 Compose text in the region between START and END.
 Optional 3rd and 4th arguments are COMPONENTS and MODIFICATION-FUNC
 for the composition.  See `compose-region' for more details.  */)
-     (start, end, components, modification_func)
-     Lisp_Object start, end, components, modification_func;
+  (Lisp_Object start, Lisp_Object end, Lisp_Object components, Lisp_Object modification_func)
 {
   validate_region (&start, &end);
   if (!NILP (components)
@@ -1607,8 +1823,7 @@ DEFUN ("compose-string-internal", Fcompose_string_internal,
 Compose text between indices START and END of STRING.
 Optional 4th and 5th arguments are COMPONENTS and MODIFICATION-FUNC
 for the composition.  See `compose-string' for more details.  */)
-     (string, start, end, components, modification_func)
-     Lisp_Object string, start, end, components, modification_func;
+  (Lisp_Object string, Lisp_Object start, Lisp_Object end, Lisp_Object components, Lisp_Object modification_func)
 {
   CHECK_STRING (string);
   CHECK_NUMBER (start);
@@ -1629,8 +1844,7 @@ DEFUN ("find-composition-internal", Ffind_composition_internal,
 
 Return information about composition at or nearest to position POS.
 See `find-composition' for more details.  */)
-     (pos, limit, string, detail_p)
-     Lisp_Object pos, limit, string, detail_p;
+  (Lisp_Object pos, Lisp_Object limit, Lisp_Object string, Lisp_Object detail_p)
 {
   Lisp_Object prop, tail, gstring;
   EMACS_INT start, end, from, to;
@@ -1661,7 +1875,7 @@ See `find-composition' for more details.  */)
   if (!find_composition (from, to, &start, &end, &prop, string))
     {
       if (!NILP (current_buffer->enable_multibyte_characters)
-         && FUNCTIONP (Vauto_composition_function)
+         && ! NILP (Vauto_composition_mode)
          && find_automatic_composition (from, to, &start, &end, &gstring,
                                         string))
        return list3 (make_number (start), make_number (end), gstring);
@@ -1673,7 +1887,7 @@ See `find-composition' for more details.  */)
 
       if (find_automatic_composition (from, to, &s, &e, &gstring, string)
          && (e <= XINT (pos) ? e > end : s < start))
-       return list3 (make_number (start), make_number (end), gstring);
+       return list3 (make_number (s), make_number (e), gstring);
     }
   if (!COMPOSITION_VALID_P (start, end, prop))
     return Fcons (make_number (start), Fcons (make_number (end),
@@ -1715,7 +1929,7 @@ See `find-composition' for more details.  */)
 
 \f
 void
-syms_of_composite ()
+syms_of_composite (void)
 {
   int i;
 
@@ -1725,7 +1939,6 @@ syms_of_composite ()
   /* Make a hash table for static composition.  */
   {
     Lisp_Object args[6];
-    extern Lisp_Object QCsize;
 
     args[0] = QCtest;
     args[1] = Qequal;
@@ -1745,8 +1958,6 @@ syms_of_composite ()
   /* Make a hash table for glyph-string.  */
   {
     Lisp_Object args[6];
-    extern Lisp_Object QCsize;
-
     args[0] = QCtest;
     args[1] = Qequal;
     args[2] = QCweakness;
@@ -1788,6 +1999,11 @@ The default value is the function `compose-chars-after'.  */);
   Qauto_composition_function = intern_c_string ("auto-composition-function");
   staticpro (&Qauto_composition_function);
 
+  DEFVAR_LISP ("auto-composition-mode", &Vauto_composition_mode,
+              doc: /* Non-nil if Auto-Composition mode is enabled.
+Use the command `auto-composition-mode' to change this variable. */);
+  Vauto_composition_mode = Qt;
+
   DEFVAR_LISP ("auto-composition-function", &Vauto_composition_function,
               doc: /* Function to call to compose characters automatically.
 This function is called from the display routine with four arguments:
@@ -1808,7 +2024,7 @@ preceding and/or following characters, this char-table contains
 a function to call to compose that character.
 
 The element at index C in the table, if non-nil, is a list of
-this form: ([PATTERN PREV-CHARS FUNC] ...)
+composition rules of this form: ([PATTERN PREV-CHARS FUNC] ...)
 
 PATTERN is a regular expression which C and the surrounding
 characters must match.