Merge from emacs--devo--0
[bpt/emacs.git] / src / xdisp.c
index c0caaf4..0ee3b19 100644 (file)
@@ -177,6 +177,7 @@ Boston, MA 02110-1301, USA.  */
 #include "termchar.h"
 #include "dispextern.h"
 #include "buffer.h"
+#include "character.h"
 #include "charset.h"
 #include "indent.h"
 #include "commands.h"
@@ -742,11 +743,13 @@ static enum prop_handled handle_display_prop P_ ((struct it *));
 static enum prop_handled handle_composition_prop P_ ((struct it *));
 static enum prop_handled handle_overlay_change P_ ((struct it *));
 static enum prop_handled handle_fontified_prop P_ ((struct it *));
+static enum prop_handled handle_auto_composed_prop P_ ((struct it *));
 
 /* Properties handled by iterators.  */
 
 static struct props it_props[] =
 {
+  {&Qauto_composed,    AUTO_COMPOSED_PROP_IDX, handle_auto_composed_prop},
   {&Qfontified,                FONTIFIED_PROP_IDX,     handle_fontified_prop},
   /* Handle `face' before `display' because some sub-properties of
      `display' need to know the face.  */
@@ -3453,7 +3456,7 @@ face_before_or_after_it_pos (it, before_p)
          struct face *face = FACE_FROM_ID (it->f, face_id);
 
          c = string_char_and_length (p, rest, &len);
-         face_id = FACE_FOR_CHAR (it->f, face, c);
+         face_id = FACE_FOR_CHAR (it->f, face, c, CHARPOS (pos), it->string);
        }
     }
   else
@@ -3492,7 +3495,7 @@ face_before_or_after_it_pos (it, before_p)
        {
          int c = FETCH_MULTIBYTE_CHAR (BYTEPOS (pos));
          struct face *face = FACE_FROM_ID (it->f, face_id);
-         face_id = FACE_FOR_CHAR (it->f, face, c);
+         face_id = FACE_FOR_CHAR (it->f, face, c, CHARPOS (pos), Qnil);
        }
     }
 
@@ -4067,7 +4070,7 @@ handle_single_display_spec (it, spec, object, position,
        {
          Lisp_Object face_name = XCAR (XCDR (XCDR (spec)));
          int face_id2 = lookup_derived_face (it->f, face_name,
-                                             'A', FRINGE_FACE_ID, 0);
+                                             FRINGE_FACE_ID, 0);
          if (face_id2 >= 0)
            face_id = face_id2;
        }
@@ -4412,6 +4415,90 @@ string_buffer_position (w, string, around_charpos)
                        `composition' property
  ***********************************************************************/
 
+static enum prop_handled
+handle_auto_composed_prop (it)
+     struct it *it;
+{
+  enum prop_handled handled = HANDLED_NORMALLY;
+
+  if (FUNCTIONP (Vauto_composition_function))
+    {
+      Lisp_Object val;
+      EMACS_INT pos, this_pos;
+
+      if (STRINGP (it->string))
+       pos = IT_STRING_CHARPOS (*it);
+      else
+       pos = IT_CHARPOS (*it);
+      this_pos = pos;
+
+      val =Fget_char_property (make_number (pos), Qauto_composed, it->string);
+      if (! NILP (val))
+       {
+         Lisp_Object limit = Qnil, next;
+         
+         /* As Fnext_single_char_property_change is very slow, we
+            limit the search to the current line.  */
+         if (STRINGP (it->string))
+           limit = make_number (SCHARS (it->string));
+         else
+           limit = make_number (find_next_newline_no_quit (pos, 1));
+
+         next = (Fnext_single_property_change
+                    (make_number (pos), Qauto_composed, it->string, limit));
+         if (XINT (next) < XINT (limit))
+           {
+             /* The current point is auto-composed, but there exist
+                characters not yet composed beyond the auto-composed
+                region.  There's a possiblity that the last
+                characters in the region may be newly composed.  */
+             int charpos = XINT (next) - 1, bytepos, c;
+
+             if (STRINGP (it->string))
+               {
+                 bytepos = string_char_to_byte (it->string, charpos);
+                 c = SDATA (it->string)[bytepos];
+               }
+             else
+               {
+                 bytepos = CHAR_TO_BYTE (charpos);
+                 c = FETCH_BYTE (bytepos);
+               }
+             if (c != '\n')
+               /* If the last character is not newline, it may be
+                  composed with the following characters.  */
+               val = Qnil, pos = charpos + 1;
+           }
+       }
+      if (NILP (val))
+       {
+         int count = SPECPDL_INDEX ();
+         Lisp_Object args[3];
+
+         args[0] = Vauto_composition_function;
+         specbind (Qauto_composition_function, Qnil);
+         args[1] = make_number (pos);
+         args[2] = it->string;
+         safe_call (3, args);
+         unbind_to (count, Qnil);
+
+         if (this_pos == pos)
+           {
+             val = Fget_char_property (args[1], Qauto_composed, it->string);
+             /* Return HANDLED_RECOMPUTE_PROPS only if function composed
+                something.  This avoids an endless loop if they failed to
+                fontify the text for which reason ever.  */
+             if (! NILP (val))
+               handled = HANDLED_RECOMPUTE_PROPS;
+           }
+         else
+           handled = HANDLED_RECOMPUTE_PROPS;
+       }
+    }
+
+  return handled;
+}
+
 /* Set up iterator IT from `composition' property at its current
    position.  Called from handle_stop.  */
 
@@ -4420,7 +4507,7 @@ handle_composition_prop (it)
      struct it *it;
 {
   Lisp_Object prop, string;
-  int pos, pos_byte, end;
+  EMACS_INT pos, pos_byte, start, end;
   enum prop_handled handled = HANDLED_NORMALLY;
 
   if (STRINGP (it->string))
@@ -4439,11 +4526,20 @@ handle_composition_prop (it)
   /* If there's a valid composition and point is not inside of the
      composition (in the case that the composition is from the current
      buffer), draw a glyph composed from the composition components.  */
-  if (find_composition (pos, -1, &pos, &end, &prop, string)
-      && COMPOSITION_VALID_P (pos, end, prop)
-      && (STRINGP (it->string) || (PT <= pos || PT >= end)))
+  if (find_composition (pos, -1, &start, &end, &prop, string)
+      && COMPOSITION_VALID_P (start, end, prop)
+      && (STRINGP (it->string) || (PT <= start || PT >= end)))
     {
-      int id = get_composition_id (pos, pos_byte, end - pos, prop, string);
+      int id;
+
+      if (start != pos)
+       {
+         if (STRINGP (it->string))
+           pos_byte = string_char_to_byte (it->string, start);
+         else
+           pos_byte = CHAR_TO_BYTE (start);
+       }
+      id = get_composition_id (start, pos_byte, end - start, prop, string);
 
       if (id >= 0)
        {
@@ -5425,31 +5521,26 @@ get_next_display_element (it)
             the translation.  This could easily be changed but I
             don't believe that it is worth doing.
 
-            If it->multibyte_p is nonzero, eight-bit characters and
-            non-printable multibyte characters are also translated to
-            octal form.
+            If it->multibyte_p is nonzero, non-printable non-ASCII
+            characters are also translated to octal form.
 
             If it->multibyte_p is zero, eight-bit characters that
             don't have corresponding multibyte char code are also
             translated to octal form.  */
          else if ((it->c < ' '
-                   && (it->area != TEXT_AREA
-                       /* In mode line, treat \n like other crl chars.  */
-                       || (it->c != '\t'
-                           && it->glyph_row && it->glyph_row->mode_line_p)
-                       || (it->c != '\n' && it->c != '\t')))
-                  || (it->multibyte_p
-                      ? ((it->c >= 127
-                          && it->len == 1)
-                         || !CHAR_PRINTABLE_P (it->c)
+                   ? (it->area != TEXT_AREA
+                      /* In mode line, treat \n, \t like other crl chars.  */
+                      || (it->c != '\t'
+                          && it->glyph_row && it->glyph_row->mode_line_p)
+                      || (it->c != '\n' && it->c != '\t'))
+                   : (it->multibyte_p
+                      ? (!CHAR_PRINTABLE_P (it->c)
                          || (!NILP (Vnobreak_char_display)
-                             && (it->c == 0x8a0 || it->c == 0x8ad
-                                 || it->c == 0x920 || it->c == 0x92d
-                                 || it->c == 0xe20 || it->c == 0xe2d
-                                 || it->c == 0xf20 || it->c == 0xf2d)))
+                             && (it->c == 0xA0 /* NO-BREAK SPACE */
+                                 || it->c == 0xAD /* SOFT HYPHEN */)))
                       : (it->c >= 127
-                         && (!unibyte_display_via_language_environment
-                             || it->c == unibyte_char_to_multibyte (it->c)))))
+                         && (! unibyte_display_via_language_environment
+                             || (UNIBYTE_CHAR_HAS_MULTIBYTE_P (it->c)))))))
            {
              /* IT->c is a control character which must be displayed
                 either as '\003' or as `^C' where the '\\' and '^'
@@ -5506,8 +5597,7 @@ get_next_display_element (it)
                 highlighting.  */
 
              if (EQ (Vnobreak_char_display, Qt)
-                 && (it->c == 0x8a0 || it->c == 0x920
-                     || it->c == 0xe20 || it->c == 0xf20))
+                 && it->c == 0xA0)
                {
                  /* Merge the no-break-space face into the current face.  */
                  face_id = merge_faces (it->f, Qnobreak_space, 0,
@@ -5558,8 +5648,7 @@ get_next_display_element (it)
                 highlighting.  */
 
              if (EQ (Vnobreak_char_display, Qt)
-                 && (it->c == 0x8ad || it->c == 0x92d
-                     || it->c == 0xe2d || it->c == 0xf2d))
+                 && it->c == 0xAD)
                {
                  g = it->c = '-';
                  XSETINT (it->ctl_chars[0], g);
@@ -5570,13 +5659,10 @@ get_next_display_element (it)
              /* Handle non-break space and soft hyphen
                 with the escape glyph.  */
 
-             if (it->c == 0x8a0 || it->c == 0x8ad
-                 || it->c == 0x920 || it->c == 0x92d
-                 || it->c == 0xe20 || it->c == 0xe2d
-                 || it->c == 0xf20 || it->c == 0xf2d)
+             if (it->c == 0xA0 || it->c == 0xAD)
                {
                  XSETINT (it->ctl_chars[0], escape_glyph);
-                 g = it->c = ((it->c & 0xf) == 0 ? ' ' : '-');
+                 g = it->c = (it->c == 0xA0 ? ' ' : '-');
                  XSETINT (it->ctl_chars[1], g);
                  ctl_len = 2;
                  goto display_control;
@@ -5588,23 +5674,27 @@ get_next_display_element (it)
                int i;
 
                /* Set IT->ctl_chars[0] to the glyph for `\\'.  */
-               if (SINGLE_BYTE_CHAR_P (it->c))
-                 str[0] = it->c, len = 1;
+               if (CHAR_BYTE8_P (it->c))
+                 {
+                   str[0] = CHAR_TO_BYTE8 (it->c);
+                   len = 1;
+                 }
+               else if (it->c < 256)
+                 {
+                   str[0] = it->c;
+                   len = 1;
+                 }
                else
                  {
-                   len = CHAR_STRING_NO_SIGNAL (it->c, str);
-                   if (len < 0)
-                     {
-                       /* It's an invalid character, which shouldn't
-                          happen actually, but due to bugs it may
-                          happen.  Let's print the char as is, there's
-                          not much meaningful we can do with it.  */
-                         str[0] = it->c;
-                         str[1] = it->c >> 8;
-                         str[2] = it->c >> 16;
-                         str[3] = it->c >> 24;
-                         len = 4;
-                       }
+                   /* It's an invalid character, which shouldn't
+                      happen actually, but due to bugs it may
+                      happen.  Let's print the char as is, there's
+                      not much meaningful we can do with it.  */
+                     str[0] = it->c;
+                     str[1] = it->c >> 8;
+                     str[2] = it->c >> 16;
+                     str[3] = it->c >> 24;
+                     len = 4;
                    }
 
                for (i = 0; i < len; i++)
@@ -5643,7 +5733,11 @@ get_next_display_element (it)
          && FRAME_WINDOW_P (it->f))
        {
          struct face *face = FACE_FROM_ID (it->f, it->face_id);
-         it->face_id = FACE_FOR_CHAR (it->f, face, it->c);
+         int pos = (it->s ? -1
+                    : STRINGP (it->string) ? IT_STRING_CHARPOS (*it)
+                    : IT_CHARPOS (*it));
+         
+         it->face_id = FACE_FOR_CHAR (it->f, face, it->c, pos, it->string);
        }
     }
 
@@ -6646,6 +6740,16 @@ move_it_to (it, to_charpos, to_x, to_y, to_vpos, op)
             the line.  */
          if (skip == MOVE_X_REACHED)
            {
+             /* Wait!  We can conclude that TO_Y is in the line if
+                the already scanned glyphs make the line tall enough
+                because further scanning doesn't make it shorter.  */
+             line_height = it->max_ascent + it->max_descent;
+             if (to_y >= it->current_y
+                 && to_y < it->current_y + line_height)
+               {
+                 reached = 6;
+                 break;
+               }
              it_backup = *it;
              TRACE_MOVE ((stderr, "move_it: from %d\n", IT_CHARPOS (*it)));
              skip2 = move_it_in_display_line_to (it, to_charpos, -1,
@@ -7169,7 +7273,7 @@ message_dolog (m, nbytes, nlflag, multibyte)
          for (i = 0; i < nbytes; i += char_bytes)
            {
              c = string_char_and_length (m + i, nbytes - i, &char_bytes);
-             work[0] = (SINGLE_BYTE_CHAR_P (c)
+             work[0] = (ASCII_CHAR_P (c)
                         ? c
                         : multibyte_char_to_unibyte (c, Qnil));
              insert_1_both (work, 1, 1, 1, 0, 0);
@@ -7185,7 +7289,8 @@ message_dolog (m, nbytes, nlflag, multibyte)
             for the *Message* buffer.  */
          for (i = 0; i < nbytes; i++)
            {
-             c = unibyte_char_to_multibyte (msg[i]);
+             c = msg[i];
+             c = unibyte_char_to_multibyte (c);
              char_bytes = CHAR_STRING (c, str);
              insert_1_both (str, 1, char_bytes, 1, 0, 0);
            }
@@ -8456,7 +8561,7 @@ set_message_1 (a1, a2, nbytes, multibyte_p)
          for (i = 0; i < nbytes; i += n)
            {
              c = string_char_and_length (s + i, nbytes - i, &n);
-             work[0] = (SINGLE_BYTE_CHAR_P (c)
+             work[0] = (ASCII_CHAR_P (c)
                         ? c
                         : multibyte_char_to_unibyte (c, Qnil));
              insert_1_both (work, 1, 1, 1, 0, 0);
@@ -8473,7 +8578,8 @@ set_message_1 (a1, a2, nbytes, multibyte_p)
          /* Convert a single-byte string to multibyte.  */
          for (i = 0; i < nbytes; i++)
            {
-             c = unibyte_char_to_multibyte (msg[i]);
+             c = msg[i];
+             c = unibyte_char_to_multibyte (c);
              n = CHAR_STRING (c, str);
              insert_1_both (str, 1, n, 1, 0, 0);
            }
@@ -10508,7 +10614,7 @@ check_point_in_composition (prev_buf, prev_pt, buf, pt)
      struct buffer *prev_buf, *buf;
      int prev_pt, pt;
 {
-  int start, end;
+  EMACS_INT start, end;
   Lisp_Object prop;
   Lisp_Object buffer;
 
@@ -11502,35 +11608,24 @@ disp_char_vector (dp, c)
      struct Lisp_Char_Table *dp;
      int c;
 {
-  int code[4], i;
   Lisp_Object val;
 
-  if (SINGLE_BYTE_CHAR_P (c))
-    return (dp->contents[c]);
-
-  SPLIT_CHAR (c, code[0], code[1], code[2]);
-  if (code[1] < 32)
-    code[1] = -1;
-  else if (code[2] < 32)
-    code[2] = -1;
-
-  /* Here, the possible range of code[0] (== charset ID) is
-     128..max_charset.  Since the top level char table contains data
-     for multibyte characters after 256th element, we must increment
-     code[0] by 128 to get a correct index.  */
-  code[0] += 128;
-  code[3] = -1;                /* anchor */
-
-  for (i = 0; code[i] >= 0; i++, dp = XCHAR_TABLE (val))
+  if (ASCII_CHAR_P (c))
     {
-      val = dp->contents[code[i]];
-      if (!SUB_CHAR_TABLE_P (val))
-       return (NILP (val) ? dp->defalt : val);
+      val = dp->ascii;
+      if (SUB_CHAR_TABLE_P (val))
+       val = XSUB_CHAR_TABLE (val)->contents[c];
     }
+  else
+    {
+      Lisp_Object table;
 
-  /* Here, val is a sub char table.  We return the default value of
-     it.  */
-  return (dp->defalt);
+      XSETCHAR_TABLE (table, dp);
+      val = char_table_ref (table, c);
+    }
+  if (NILP (val))
+    val = dp->defalt;
+  return val;
 }
 
 
@@ -15402,7 +15497,7 @@ append_space_for_newline (it, default_face_p)
          else if (it->face_before_selective_p)
            it->face_id = it->saved_face_id;
          face = FACE_FROM_ID (it->f, it->face_id);
-         it->face_id = FACE_FOR_CHAR (it->f, face, 0);
+         it->face_id = FACE_FOR_CHAR (it->f, face, 0, -1, Qnil);
 
          PRODUCE_GLYPHS (it);
 
@@ -15462,9 +15557,9 @@ extend_face_to_end_of_line (it)
          ASCII face.  This will be automatically undone the next time
          get_next_display_element returns a multibyte character.  Note
          that the character will always be single byte in unibyte text.  */
-  if (!SINGLE_BYTE_CHAR_P (it->c))
+  if (!ASCII_CHAR_P (it->c))
     {
-      it->face_id = FACE_FOR_CHAR (f, face, 0);
+      it->face_id = FACE_FOR_CHAR (f, face, 0, -1, Qnil);
     }
 
   if (FRAME_WINDOW_P (f))
@@ -15570,7 +15665,7 @@ highlight_trailing_whitespace (f, row)
                  && glyph->u.ch == ' '))
          && trailing_whitespace_p (glyph->charpos))
        {
-         int face_id = lookup_named_face (f, Qtrailing_whitespace, 0, 0);
+         int face_id = lookup_named_face (f, Qtrailing_whitespace, 0);
          if (face_id < 0)
            return;
 
@@ -17069,7 +17164,7 @@ are the selected window and the window's buffer).  */)
     {
       if (EQ (face, Qt))
        face = (EQ (window, selected_window) ? Qmode_line : Qmode_line_inactive);
-      face_id = lookup_named_face (XFRAME (WINDOW_FRAME (w)), face, 0, 0);
+      face_id = lookup_named_face (XFRAME (WINDOW_FRAME (w)), face, 0);
     }
 
   if (face_id < 0)
@@ -17292,7 +17387,7 @@ decode_mode_spec_coding (coding_system, buf, eol_flag)
   /* The EOL conversion we are using.  */
   Lisp_Object eoltype;
 
-  val = Fget (coding_system, Qcoding_system);
+  val = CODING_SYSTEM_SPEC (coding_system);
   eoltype = Qnil;
 
   if (!VECTORP (val))          /* Not yet decided.  */
@@ -17305,12 +17400,14 @@ decode_mode_spec_coding (coding_system, buf, eol_flag)
     }
   else
     {
+      Lisp_Object attrs;
       Lisp_Object eolvalue;
 
-      eolvalue = Fget (coding_system, Qeol_type);
+      attrs = AREF (val, 0);
+      eolvalue = AREF (val, 2);
 
       if (multibyte)
-       *buf++ = XFASTINT (AREF (val, 1));
+       *buf++ = XFASTINT (CODING_ATTR_MNEMONIC (attrs));
 
       if (eol_flag)
        {
@@ -17320,10 +17417,10 @@ decode_mode_spec_coding (coding_system, buf, eol_flag)
            eoltype = eol_mnemonic_undecided;
          else if (VECTORP (eolvalue)) /* Not yet decided.  */
            eoltype = eol_mnemonic_undecided;
-         else                  /* INTEGERP (eolvalue) -- 0:LF, 1:CRLF, 2:CR */
-           eoltype = (XFASTINT (eolvalue) == 0
+         else                  /* eolvalue is Qunix, Qdos, or Qmac.  */
+           eoltype = (EQ (eolvalue, Qunix)
                       ? eol_mnemonic_unix
-                      : (XFASTINT (eolvalue) == 1
+                      : (EQ (eolvalue, Qdos) == 1
                          ? eol_mnemonic_dos : eol_mnemonic_mac));
        }
     }
@@ -17336,8 +17433,7 @@ decode_mode_spec_coding (coding_system, buf, eol_flag)
          eol_str = SDATA (eoltype);
          eol_str_len = SBYTES (eoltype);
        }
-      else if (INTEGERP (eoltype)
-              && CHAR_VALID_P (XINT (eoltype), 0))
+      else if (CHARACTERP (eoltype))
        {
          unsigned char *tmp = (unsigned char *) alloca (MAX_MULTIBYTE_LENGTH);
          eol_str_len = CHAR_STRING (XINT (eoltype), tmp);
@@ -17718,8 +17814,10 @@ decode_mode_spec (w, c, field_width, precision, multibyte)
          {
            /* No need to mention EOL here--the terminal never needs
               to do EOL conversion.  */
-           p = decode_mode_spec_coding (keyboard_coding.symbol, p, 0);
-           p = decode_mode_spec_coding (terminal_coding.symbol, p, 0);
+           p = decode_mode_spec_coding (CODING_ID_NAME (keyboard_coding.id),
+                                        p, 0);
+           p = decode_mode_spec_coding (CODING_ID_NAME (terminal_coding.id),
+                                        p, 0);
          }
        p = decode_mode_spec_coding (b->buffer_file_coding_system,
                                     p, eol_flag);
@@ -17991,7 +18089,7 @@ display_string (string, lisp_string, face_string, face_string_pos,
                }
              break;
            }
-         else if (x + glyph->pixel_width > it->first_visible_x)
+         else if (x + glyph->pixel_width >= it->first_visible_x)
            {
              /* Glyph is at least partially visible.  */
              ++it->hpos;
@@ -18551,24 +18649,25 @@ get_glyph_face_and_encoding (f, glyph, char2b, two_byte_p)
     }
   else
     {
-      int c1, c2, charset;
+      struct font_info *font_info
+       = FONT_INFO_FROM_ID (f, face->font_info_id);
+      if (font_info)
+       {
+         struct charset *charset = CHARSET_FROM_ID (font_info->charset);
+         unsigned code = ENCODE_CHAR (charset, glyph->u.ch);
 
-      /* Split characters into bytes.  If c2 is -1 afterwards, C is
-        really a one-byte character so that byte1 is zero.  */
-      SPLIT_CHAR (glyph->u.ch, charset, c1, c2);
-      if (c2 > 0)
-       STORE_XCHAR2B (char2b, c1, c2);
-      else
-       STORE_XCHAR2B (char2b, 0, c1);
+         if (CHARSET_DIMENSION (charset) == 1)
+           STORE_XCHAR2B (char2b, 0, code);
+         else
+           STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
 
-      /* Maybe encode the character in *CHAR2B.  */
-      if (charset != CHARSET_ASCII)
-       {
-         struct font_info *font_info
-           = FONT_INFO_FROM_ID (f, face->font_info_id);
-         if (font_info)
-           glyph->font_type
-             = rif->encode_char (glyph->u.ch, char2b, font_info, two_byte_p);
+         /* Maybe encode the character in *CHAR2B.  */
+         if (CHARSET_ID (charset) != charset_ascii)
+           {
+             glyph->font_type
+               = rif->encode_char (glyph->u.ch, char2b, font_info, charset,
+                                   two_byte_p);
+           }
        }
     }
 
@@ -18602,14 +18701,24 @@ fill_composite_glyph_string (s, faces, overlaps)
   s->for_overlaps = overlaps;
 
   s->face = faces[s->gidx];
-  s->font = s->face->font;
-  s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+  if (s->face == NULL)
+    {
+      s->font = NULL;
+      s->font_info = NULL;
+    }
+  else
+    {
+      s->font = s->face->font;
+      s->font_info = FONT_INFO_FROM_ID (s->f, s->face->font_info_id);
+    }
 
   /* For all glyphs of this composition, starting at the offset
      S->gidx, until we reach the end of the definition or encounter a
      glyph that requires the different face, add it to S.  */
   ++s->nchars;
-  for (i = s->gidx + 1; i < s->cmp->glyph_len && faces[i] == s->face; ++i)
+  for (i = s->gidx + 1;
+       i < s->cmp->glyph_len && (faces[i] == s->face || ! faces[i] || ! s->face);
+       ++i)
     ++s->nchars;
 
   /* All glyph strings for the same composition has the same width,
@@ -18630,8 +18739,6 @@ fill_composite_glyph_string (s, faces, overlaps)
   /* Adjust base line for subscript/superscript text.  */
   s->ybase += s->first_glyph->voffset;
 
-  xassert (s->face && s->face->gc);
-
   /* This glyph string must always be drawn with 16-bit functions.  */
   s->two_byte_p = 1;
 
@@ -18809,6 +18916,13 @@ x_get_glyph_overhangs (glyph, f, left, right)
            *left = -pcm->lbearing;
        }
     }
+  else if (glyph->type == COMPOSITE_GLYPH)
+    {
+      struct composition *cmp = composition_table[glyph->u.cmp_id];
+
+      *right = cmp->rbearing - cmp->pixel_width;
+      *left = - cmp->lbearing;
+    }
 }
 
 
@@ -18943,7 +19057,7 @@ get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p)
       /* Unibyte case.  We don't have to encode, but we have to make
         sure to use a face suitable for unibyte.  */
       STORE_XCHAR2B (char2b, 0, c);
-      face_id = FACE_FOR_CHAR (f, face, c);
+      face_id = FACE_FOR_CHAR (f, face, c, -1, Qnil);
       face = FACE_FROM_ID (f, face_id);
     }
   else if (c < 128)
@@ -18951,26 +19065,19 @@ get_char_face_and_encoding (f, c, face_id, char2b, multibyte_p, display_p)
       /* Case of ASCII in a face known to fit ASCII.  */
       STORE_XCHAR2B (char2b, 0, c);
     }
-  else
+  else if (face->font != NULL)
     {
-      int c1, c2, charset;
+      struct font_info *font_info
+       = FONT_INFO_FROM_ID (f, face->font_info_id);
+      struct charset *charset = CHARSET_FROM_ID (font_info->charset);
+      unsigned code = ENCODE_CHAR (charset, c);
 
-      /* Split characters into bytes.  If c2 is -1 afterwards, C is
-        really a one-byte character so that byte1 is zero.  */
-      SPLIT_CHAR (c, charset, c1, c2);
-      if (c2 > 0)
-       STORE_XCHAR2B (char2b, c1, c2);
+      if (CHARSET_DIMENSION (charset) == 1)
+       STORE_XCHAR2B (char2b, 0, code);
       else
-       STORE_XCHAR2B (char2b, 0, c1);
-
-      /* Maybe encode the character in *CHAR2B.  */
-      if (face->font != NULL)
-       {
-         struct font_info *font_info
-           = FONT_INFO_FROM_ID (f, face->font_info_id);
-         if (font_info)
-           rif->encode_char (c, char2b, font_info, 0);
-       }
+       STORE_XCHAR2B (char2b, (code >> 8), (code & 0xFF));
+       /* Maybe encode the character in *CHAR2B.  */
+      rif->encode_char (c, char2b, font_info, charset, NULL);
     }
 
   /* Make sure X resources of the face are allocated.  */
@@ -19125,10 +19232,9 @@ compute_overhangs_and_x (s, x, backward_p)
 #define BUILD_CHAR_GLYPH_STRINGS(START, END, HEAD, TAIL, HL, X, LAST_X)           \
      do                                                                           \
        {                                                                  \
-        int c, face_id;                                                   \
+        int face_id;                                                      \
         XChar2b *char2b;                                                  \
                                                                           \
-        c = (row)->glyphs[area][START].u.ch;                              \
         face_id = (row)->glyphs[area][START].face_id;                     \
                                                                           \
         s = (struct glyph_string *) alloca (sizeof *s);                   \
@@ -19169,10 +19275,16 @@ compute_overhangs_and_x (s, x, backward_p)
     for (n = 0; n < glyph_len; n++)                                      \
       {                                                                          \
        int c = COMPOSITION_GLYPH (cmp, n);                               \
-       int this_face_id = FACE_FOR_CHAR (f, base_face, c);               \
-       faces[n] = FACE_FROM_ID (f, this_face_id);                        \
-       get_char_face_and_encoding (f, c, this_face_id,                   \
+                                                                         \
+       if (c == '\t')                                                    \
+         faces[n] = NULL;                                                \
+       else                                                              \
+         {                                                               \
+           int this_face_id = FACE_FOR_CHAR (f, base_face, c, -1, Qnil); \
+           faces[n] = FACE_FROM_ID (f, this_face_id);                    \
+           get_char_face_and_encoding (f, c, this_face_id,               \
                                    char2b + n, 1, 1);                    \
+         }                                                               \
       }                                                                          \
                                                                          \
     /* Make glyph_strings for each glyph sequence that is drawable by    \
@@ -19240,8 +19352,11 @@ compute_overhangs_and_x (s, x, backward_p)
                 abort ();                                                 \
               }                                                           \
                                                                           \
-             set_glyph_string_background_width (s, START, LAST_X);        \
-            (X) += s->width;                                              \
+            if (s)                                                        \
+              {                                                           \
+                set_glyph_string_background_width (s, START, LAST_X);     \
+                (X) += s->width;                                          \
+              }                                                           \
             }                                                             \
        }                                                                  \
      while (0)
@@ -19275,7 +19390,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps)
      int x;
      struct glyph_row *row;
      enum glyph_row_area area;
-     int start, end;
+     EMACS_INT start, end;
      enum draw_glyphs_face hl;
      int overlaps;
 {
@@ -19395,6 +19510,7 @@ draw_glyphs (w, x, row, area, start, end, hl, overlaps)
       if (i >= 0)
        {
          clip_tail = tail;
+         i++;                  /* We must include the Ith glyph.  */
          BUILD_GLYPH_STRINGS (end, i, h, t,
                               DRAW_NORMAL_TEXT, x, last_x);
          for (s = h; s; s = s->next)
@@ -19975,7 +20091,7 @@ calc_line_height_property (it, val, font, boff, override)
       struct face *face;
       struct font_info *font_info;
 
-      face_id = lookup_named_face (it->f, face_name, ' ', 0);
+      face_id = lookup_named_face (it->f, face_name, 0);
       if (face_id < 0)
        return make_number (-1);
 
@@ -20048,23 +20164,17 @@ x_produce_glyphs (it)
       /* Maybe translate single-byte characters to multibyte, or the
         other way.  */
       it->char_to_display = it->c;
-      if (!ASCII_BYTE_P (it->c))
+      if (!ASCII_BYTE_P (it->c)
+         && ! it->multibyte_p)
        {
-         if (unibyte_display_via_language_environment
-             && SINGLE_BYTE_CHAR_P (it->c)
-             && (it->c >= 0240
-                 || !NILP (Vnonascii_translation_table)))
+         if (SINGLE_BYTE_CHAR_P (it->c)
+             && unibyte_display_via_language_environment)
+           it->char_to_display = unibyte_char_to_multibyte (it->c);
+         if (! SINGLE_BYTE_CHAR_P (it->c))
            {
-             it->char_to_display = unibyte_char_to_multibyte (it->c);
              it->multibyte_p = 1;
-             it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
-             face = FACE_FROM_ID (it->f, it->face_id);
-           }
-         else if (!SINGLE_BYTE_CHAR_P (it->c)
-                  && !it->multibyte_p)
-           {
-             it->multibyte_p = 1;
-             it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
+             it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display,
+                                          -1, Qnil);
              face = FACE_FROM_ID (it->f, it->face_id);
            }
        }
@@ -20325,20 +20435,18 @@ x_produce_glyphs (it)
 
          /* If we found a font, this font should give us the right
             metrics.  If we didn't find a font, use the frame's
-            default font and calculate the width of the character
-            from the charset width; this is what old redisplay code
-            did.  */
+            default font and calculate the width of the character by
+            multiplying the width of font by the width of the
+            character.  */
 
          pcm = rif->per_char_metric (font, &char2b,
                                      FONT_TYPE_FOR_MULTIBYTE (font, it->c));
 
          if (font_not_found_p || !pcm)
            {
-             int charset = CHAR_CHARSET (it->char_to_display);
-
              it->glyph_not_available_p = 1;
              it->pixel_width = (FRAME_COLUMN_WIDTH (it->f)
-                                * CHARSET_WIDTH (charset));
+                                * CHAR_WIDTH (it->char_to_display));
              it->phys_ascent = FONT_BASE (font) + boff;
              it->phys_descent = FONT_DESCENT (font) - boff;
            }
@@ -20397,20 +20505,20 @@ x_produce_glyphs (it)
       struct font_info *font_info;
       int boff;                        /* baseline offset */
       struct composition *cmp = composition_table[it->cmp_id];
+      int pos;
 
       /* Maybe translate single-byte characters to multibyte.  */
       it->char_to_display = it->c;
       if (unibyte_display_via_language_environment
-         && SINGLE_BYTE_CHAR_P (it->c)
-         && (it->c >= 0240
-             || (it->c >= 0200
-                 && !NILP (Vnonascii_translation_table))))
+         && it->c >= 0200)
        {
          it->char_to_display = unibyte_char_to_multibyte (it->c);
        }
 
       /* Get face and font to use.  Encode IT->char_to_display.  */
-      it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display);
+      pos = STRINGP (it->string) ? IT_STRING_CHARPOS (*it) : IT_CHARPOS (*it);
+      it->face_id = FACE_FOR_CHAR (it->f, face, it->char_to_display,
+                                  pos, it->string);
       face = FACE_FROM_ID (it->f, it->face_id);
       get_char_face_and_encoding (it->f, it->char_to_display, it->face_id,
                                  &char2b, it->multibyte_p, 0);
@@ -20443,9 +20551,14 @@ x_produce_glyphs (it)
         now.  Theoretically, we have to check all fonts for the
         glyphs, but that requires much time and memory space.  So,
         here we check only the font of the first glyph.  This leads
-        to incorrect display very rarely, and C-l (recenter) can
-        correct the display anyway.  */
-      if (cmp->font != (void *) font)
+        to incorrect display, but it's very rare, and C-l (recenter)
+        can correct the display anyway.  */
+      if (cmp->glyph_len == 0)
+       {
+         cmp->lbearing = cmp->rbearing = 0;
+         cmp->pixel_width = cmp->ascent = cmp->descent = 0;
+       }
+      else if (cmp->font != (void *) font)
        {
          /* Ascent and descent of the font of the first character of
             this composition (adjusted by baseline offset).  Ascent
@@ -20453,9 +20566,12 @@ x_produce_glyphs (it)
             them respectively.  */
          int font_ascent = FONT_BASE (font) + boff;
          int font_descent = FONT_DESCENT (font) - boff;
+         int font_height = FONT_HEIGHT (font);
          /* Bounding box of the overall glyphs.  */
          int leftmost, rightmost, lowest, highest;
+         int lbearing, rbearing;
          int i, width, ascent, descent;
+         int fully_padded = 0;
 
          cmp->font = (void *) font;
 
@@ -20467,12 +20583,20 @@ x_produce_glyphs (it)
              width = pcm->width;
              ascent = pcm->ascent;
              descent = pcm->descent;
+             lbearing = pcm->lbearing;
+             if (lbearing > 0)
+               lbearing = 0;
+             rbearing = pcm->rbearing;
+             if (rbearing < width)
+               rbearing = width;
            }
          else
            {
              width = FONT_WIDTH (font);
              ascent = FONT_BASE (font);
              descent = FONT_DESCENT (font);
+             lbearing = 0;
+             rbearing = width;
            }
 
          rightmost = width;
@@ -20492,14 +20616,25 @@ x_produce_glyphs (it)
             the left.  */
          cmp->offsets[0] = 0;
          cmp->offsets[1] = boff;
+         cmp->lbearing = lbearing;
+         cmp->rbearing = rbearing;
 
          /* Set cmp->offsets for the remaining glyphs.  */
          for (i = 1; i < cmp->glyph_len; i++)
            {
              int left, right, btm, top;
              int ch = COMPOSITION_GLYPH (cmp, i);
-             int face_id = FACE_FOR_CHAR (it->f, face, ch);
+             int face_id;
+
+             if (ch == '\t')
+               {
+                 fully_padded = 1;
+                 cmp->offsets[i * 2] = 0;
+                 cmp->offsets[i * 2 + 1] = boff;
+                 continue;
+               }
 
+             face_id = FACE_FOR_CHAR (it->f, face, ch, pos, it->string);
              face = FACE_FROM_ID (it->f, face_id);
              get_char_face_and_encoding (it->f, ch, face->id,
                                          &char2b, it->multibyte_p, 0);
@@ -20526,12 +20661,20 @@ x_produce_glyphs (it)
                  width = pcm->width;
                  ascent = pcm->ascent;
                  descent = pcm->descent;
+                 lbearing = pcm->lbearing;
+                 if (lbearing > 0)
+                   lbearing = 0;
+                 rbearing = pcm->rbearing;
+                 if (rbearing < width)
+                   rbearing = width;
                }
              else
                {
                  width = FONT_WIDTH (font);
                  ascent = 1;
                  descent = 0;
+                 lbearing = 0;
+                 rbearing = width;
                }
 
              if (cmp->method != COMPOSITION_WITH_RULE_ALTCHARS)
@@ -20572,15 +20715,21 @@ x_produce_glyphs (it)
                        6---7---8 -- descent
                  */
                  int rule = COMPOSITION_RULE (cmp, i);
-                 int gref, nref, grefx, grefy, nrefx, nrefy;
+                 int gref, nref, grefx, grefy, nrefx, nrefy, xoff, yoff;
 
-                 COMPOSITION_DECODE_RULE (rule, gref, nref);
+                 COMPOSITION_DECODE_RULE (rule, gref, nref, xoff, yoff);
                  grefx = gref % 3, nrefx = nref % 3;
                  grefy = gref / 3, nrefy = nref / 3;
+                 if (xoff)
+                   xoff = font_height * (xoff - 128) / 256;
+                 if (yoff)
+                   yoff = font_height * (yoff - 128) / 256;
 
                  left = (leftmost
                          + grefx * (rightmost - leftmost) / 2
-                         - nrefx * width / 2);
+                         - nrefx * width / 2
+                         + xoff);
+                 
                  btm = ((grefy == 0 ? highest
                          : grefy == 1 ? 0
                          : grefy == 2 ? lowest
@@ -20588,23 +20737,32 @@ x_produce_glyphs (it)
                         - (nrefy == 0 ? ascent + descent
                            : nrefy == 1 ? descent - boff
                            : nrefy == 2 ? 0
-                           : (ascent + descent) / 2));
+                           : (ascent + descent) / 2)
+                        + yoff);
                }
 
              cmp->offsets[i * 2] = left;
              cmp->offsets[i * 2 + 1] = btm + descent;
 
              /* Update the bounding box of the overall glyphs. */
-             right = left + width;
+             if (width > 0)
+               {
+                 right = left + width;
+                 if (left < leftmost)
+                   leftmost = left;
+                 if (right > rightmost)
+                   rightmost = right;
+               }
              top = btm + descent + ascent;
-             if (left < leftmost)
-               leftmost = left;
-             if (right > rightmost)
-               rightmost = right;
              if (top > highest)
                highest = top;
              if (btm < lowest)
                lowest = btm;
+
+             if (cmp->lbearing > left + lbearing)
+               cmp->lbearing = left + lbearing;
+             if (cmp->rbearing < left + rbearing)
+               cmp->rbearing = left + rbearing;
            }
 
          /* If there are glyphs whose x-offsets are negative,
@@ -20615,6 +20773,17 @@ x_produce_glyphs (it)
              for (i = 0; i < cmp->glyph_len; i++)
                cmp->offsets[i * 2] -= leftmost;
              rightmost -= leftmost;
+             cmp->lbearing -= leftmost;
+             cmp->rbearing -= leftmost;
+           }
+
+         if (fully_padded)
+           {
+             for (i = 0; i < cmp->glyph_len; i++)
+               cmp->offsets[i * 2] -= cmp->lbearing;
+             rightmost = cmp->rbearing - cmp->lbearing;
+             cmp->lbearing = 0;
+             cmp->rbearing = rightmost; 
            }
 
          cmp->pixel_width = rightmost;
@@ -20626,6 +20795,11 @@ x_produce_glyphs (it)
            cmp->descent = font_descent;
        }
 
+      if (it->glyph_row
+         && (cmp->lbearing < 0
+             || cmp->rbearing > cmp->pixel_width))
+       it->glyph_row->contains_overlapping_glyphs_p = 1;
+
       it->pixel_width = cmp->pixel_width;
       it->ascent = it->phys_ascent = cmp->ascent;
       it->descent = it->phys_descent = cmp->descent;
@@ -20736,7 +20910,8 @@ x_insert_glyphs (start, len)
   int line_height, shift_by_width, shifted_region_width;
   struct glyph_row *row;
   struct glyph *glyph;
-  int frame_x, frame_y, hpos;
+  int frame_x, frame_y;
+  EMACS_INT hpos;
 
   xassert (updated_window && updated_row);
   BLOCK_INPUT;
@@ -21656,7 +21831,7 @@ cursor_in_mouse_face_p (w)
 static int
 fast_find_position (w, charpos, hpos, vpos, x, y, stop)
      struct window *w;
-     int charpos;
+     EMACS_INT charpos;
      int *hpos, *vpos, *x, *y;
      Lisp_Object stop;
 {
@@ -21744,7 +21919,7 @@ fast_find_position (w, charpos, hpos, vpos, x, y, stop)
 static int
 fast_find_position (w, pos, hpos, vpos, x, y, stop)
      struct window *w;
-     int pos;
+     EMACS_INT pos;
      int *hpos, *vpos, *x, *y;
      Lisp_Object stop;
 {
@@ -21858,7 +22033,7 @@ fast_find_position (w, pos, hpos, vpos, x, y, stop)
 static int
 fast_find_string_pos (w, pos, object, hpos, vpos, x, y, right_p)
      struct window *w;
-     int pos;
+     EMACS_INT pos;
      Lisp_Object object;
      int *hpos, *vpos, *x, *y;
      int right_p;