]> code.delx.au - gnu-emacs/blobdiff - src/xfaces.c
Revision: miles@gnu.org--gnu-2004/emacs--unicode--0--patch-24
[gnu-emacs] / src / xfaces.c
index fc665ce3bd5fc11eb44441a5f795375f7dbcdecf..6ee06ba5f7691c16c7af3e206a8cf31bdd41f5c2 100644 (file)
@@ -56,7 +56,7 @@ Boston, MA 02111-1307, USA.  */
    13. Whether or not a box should be drawn around characters, the box
    type, and, for simple boxes, in what color.
 
-   14. Font or fontset pattern, or nil.  This is a special attribute.
+   14. Font pattern, or nil.  This is a special attribute.
    When this attribute is specified, the face uses a font opened by
    that pattern as is.  In addition, all the other font-related
    attributes (1st thru 5th) are generated from the opened font name.
@@ -72,6 +72,8 @@ Boston, MA 02111-1307, USA.  */
    and is used to ensure that a font specified on the command line,
    for example, can be matched exactly.
 
+   17. A fontset name.
+
    Faces are frame-local by nature because Emacs allows to define the
    same named face (face names are symbols) differently for different
    frames.  Each frame has an alist of face definitions for all named
@@ -123,7 +125,7 @@ Boston, MA 02111-1307, USA.  */
    is realized, it inherits (thus shares) a fontset of an ASCII face
    that has the same attributes other than font-related ones.
 
-   Thus, all realized face have a realized fontset.
+   Thus, all realized faces have a realized fontset.
 
 
    Unibyte text.
@@ -197,6 +199,7 @@ Boston, MA 02111-1307, USA.  */
 #include <sys/stat.h>
 
 #include "lisp.h"
+#include "character.h"
 #include "charset.h"
 #include "keyboard.h"
 #include "frame.h"
@@ -300,6 +303,7 @@ Lisp_Object QCinverse_video, QCforeground, QCbackground, QCstipple;
 Lisp_Object QCwidth, QCfont, QCbold, QCitalic;
 Lisp_Object QCreverse_video;
 Lisp_Object QCoverline, QCstrike_through, QCbox, QCinherit;
+Lisp_Object QCfontset;
 
 /* Symbols used for attribute values.  */
 
@@ -460,6 +464,7 @@ int menu_face_changed_default;
 
 struct font_name;
 struct table_entry;
+struct named_merge_point;
 
 static void map_tty_color P_ ((struct frame *, struct face *,
                               enum lface_attribute_index, int *));
@@ -476,7 +481,7 @@ static int load_pixmap P_ ((struct frame *, Lisp_Object, unsigned *, unsigned *)
 static unsigned char *xstrlwr P_ ((unsigned char *));
 static void signal_error P_ ((char *, Lisp_Object));
 static struct frame *frame_or_selected_frame P_ ((Lisp_Object, int));
-static void load_face_font P_ ((struct frame *, struct face *, int));
+static void load_face_font P_ ((struct frame *, struct face *));
 static void load_face_colors P_ ((struct frame *, struct face *, Lisp_Object *));
 static void free_face_colors P_ ((struct frame *, struct face *));
 static int face_color_gray_p P_ ((struct frame *, char *));
@@ -489,18 +494,17 @@ static int font_list_1 P_ ((struct frame *, Lisp_Object, Lisp_Object,
                            Lisp_Object, struct font_name **));
 static int font_list P_ ((struct frame *, Lisp_Object, Lisp_Object,
                          Lisp_Object, struct font_name **));
-static int try_font_list P_ ((struct frame *, Lisp_Object *,
-                             Lisp_Object, Lisp_Object, struct font_name **,
-                             int));
+static int try_font_list P_ ((struct frame *, Lisp_Object,
+                             Lisp_Object, Lisp_Object, struct font_name **));
 static int try_alternative_families P_ ((struct frame *f, Lisp_Object,
                                         Lisp_Object, struct font_name **));
 static int cmp_font_names P_ ((const void *, const void *));
-static struct face *realize_face P_ ((struct face_cache *, Lisp_Object *, int,
-                                     struct face *, int));
-static struct face *realize_x_face P_ ((struct face_cache *,
-                                       Lisp_Object *, int, struct face *));
-static struct face *realize_tty_face P_ ((struct face_cache *,
-                                         Lisp_Object *, int));
+static struct face *realize_face P_ ((struct face_cache *, Lisp_Object *,
+                                     int));
+static struct face *realize_non_ascii_face P_ ((struct frame *, int,
+                                               struct face *));
+static struct face *realize_x_face P_ ((struct face_cache *, Lisp_Object *));
+static struct face *realize_tty_face P_ ((struct face_cache *, Lisp_Object *));
 static int realize_basic_faces P_ ((struct frame *));
 static int realize_default_face P_ ((struct frame *));
 static void realize_named_face P_ ((struct frame *, Lisp_Object, int));
@@ -510,24 +514,20 @@ static unsigned hash_string_case_insensitive P_ ((Lisp_Object));
 static unsigned lface_hash P_ ((Lisp_Object *));
 static int lface_same_font_attributes_p P_ ((Lisp_Object *, Lisp_Object *));
 static struct face_cache *make_face_cache P_ ((struct frame *));
-static void free_realized_face P_ ((struct frame *, struct face *));
 static void clear_face_gcs P_ ((struct face_cache *));
 static void free_face_cache P_ ((struct face_cache *));
 static int face_numeric_weight P_ ((Lisp_Object));
 static int face_numeric_slant P_ ((Lisp_Object));
 static int face_numeric_swidth P_ ((Lisp_Object));
 static int face_fontset P_ ((Lisp_Object *));
-static char *choose_face_font P_ ((struct frame *, Lisp_Object *, int, int, int*));
-static void merge_face_vectors P_ ((struct frame *, Lisp_Object *, Lisp_Object*, Lisp_Object));
-static void merge_face_inheritance P_ ((struct frame *f, Lisp_Object,
-                                       Lisp_Object *, Lisp_Object));
-static void merge_face_vector_with_property P_ ((struct frame *, Lisp_Object *,
-                                                Lisp_Object));
+static void merge_face_vectors P_ ((struct frame *, Lisp_Object *, Lisp_Object*,
+                                   struct named_merge_point *));
+static int merge_face_ref P_ ((struct frame *, Lisp_Object, Lisp_Object *,
+                              int, struct named_merge_point *));
 static int set_lface_from_font_name P_ ((struct frame *, Lisp_Object,
                                         Lisp_Object, int, int));
 static Lisp_Object lface_from_face_name P_ ((struct frame *, Lisp_Object, int));
 static struct face *make_realized_face P_ ((Lisp_Object *));
-static void free_realized_faces P_ ((struct face_cache *));
 static char *best_matching_font P_ ((struct frame *, Lisp_Object *,
                                     struct font_name *, int, int, int *));
 static void cache_face P_ ((struct face_cache *, struct face *, unsigned));
@@ -1216,15 +1216,13 @@ load_pixmap (f, name, w_ptr, h_ptr)
 
 #ifdef HAVE_WINDOW_SYSTEM
 
-/* Load font of face FACE which is used on frame F to display
-   character C.  The name of the font to load is determined by lface
-   and fontset of FACE.  */
+/* Load font of face FACE which is used on frame F to display ASCII
+   characters.  The name of the font to load is determined by lface.  */
 
 static void
-load_face_font (f, face, c)
+load_face_font (f, face)
      struct frame *f;
      struct face *face;
-     int c;
 {
   struct font_info *font_info = NULL;
   char *font_name;
@@ -1232,14 +1230,14 @@ load_face_font (f, face, c)
 
   face->font_info_id = -1;
   face->font = NULL;
+  face->font_name = NULL;
 
-  font_name = choose_face_font (f, face->lface, face->fontset, c,
-                               &needs_overstrike);
+  font_name = choose_face_font (f, face->lface, Qnil, &needs_overstrike);
   if (!font_name)
     return;
 
   BLOCK_INPUT;
-  font_info = FS_LOAD_FACE_FONT (f, c, font_name, face);
+  font_info = FS_LOAD_FONT (f, font_name);
   UNBLOCK_INPUT;
 
   if (font_info)
@@ -1378,7 +1376,7 @@ tty_defined_color (f, color_name, color_def, alloc)
   color_def->green = 0;
 
   if (*color_name)
-    status = tty_lookup_color (f, build_string (color_name), color_def, 0);
+    status = tty_lookup_color (f, build_string (color_name), color_def, NULL);
 
   if (color_def->pixel == FACE_TTY_DEFAULT_COLOR && *color_name)
     {
@@ -2120,7 +2118,7 @@ face_value (table, dim, symbol)
 static INLINE int
 face_numeric_value (table, dim, symbol)
      struct table_entry *table;
-     int dim;
+     size_t dim;
      Lisp_Object symbol;
 {
   struct table_entry *p = face_value (table, dim, symbol);
@@ -2161,9 +2159,65 @@ face_numeric_swidth (width)
   return face_numeric_value (swidth_table, DIM (swidth_table), width);
 }
 
-
 #ifdef HAVE_WINDOW_SYSTEM
 
+Lisp_Object
+split_font_name_into_vector (fontname)
+     Lisp_Object fontname;
+{
+  struct font_name font;
+  Lisp_Object vec;
+  int i;
+
+  font.name = LSTRDUPA (fontname);
+  if (! split_font_name (NULL, &font, 0))
+    return Qnil;
+  vec = Fmake_vector (make_number (XLFD_LAST), Qnil);
+  for (i = 0; i < XLFD_LAST; i++)
+    if (font.fields[i][0] != '*')
+      ASET (vec, i, build_string (font.fields[i]));
+  return vec;
+}
+
+Lisp_Object
+build_font_name_from_vector (vec)
+     Lisp_Object vec;
+{
+  struct font_name font;
+  Lisp_Object fontname;
+  char *p;
+  int i;
+
+  for (i = 0; i < XLFD_LAST; i++)
+    {
+      font.fields[i] = (NILP (AREF (vec, i))
+                       ? "*" : (char *) SDATA (AREF (vec, i)));
+      if ((i == XLFD_FAMILY || i == XLFD_REGISTRY)
+         && (p = strchr (font.fields[i], '-')))
+       {
+         char *p1 = STRDUPA (font.fields[i]);
+
+         p1[p - font.fields[i]] = '\0';
+         if (i == XLFD_FAMILY)
+           {
+             font.fields[XLFD_FOUNDRY] = p1;
+             font.fields[XLFD_FAMILY] = p + 1;
+           }
+         else
+           {
+             font.fields[XLFD_REGISTRY] = p1;
+             font.fields[XLFD_ENCODING] = p + 1;
+             break;
+           }
+       }
+    }
+
+  p = build_font_name (&font);
+  fontname = build_string (p);
+  xfree (p);
+  return fontname;
+}
+
 /* Return non-zero if FONT is the name of a fixed-pitch font.  */
 
 static INLINE int
@@ -2186,7 +2240,9 @@ xlfd_fixed_p (font)
    72dpi versions, only.)
 
    Value is the real point size of FONT on frame F, or 0 if it cannot
-   be determined.  */
+   be determined.
+
+   By side effect, set FONT->numeric[XLFD_PIXEL_SIZE].  */
 
 static INLINE int
 xlfd_point_size (f, font)
@@ -2225,6 +2281,7 @@ xlfd_point_size (f, font)
   else
     pixel = atoi (pixel_field);
 
+  font->numeric[XLFD_PIXEL_SIZE] = pixel;
   if (pixel == 0)
     real_pt = 0;
   else
@@ -2711,12 +2768,12 @@ cmp_font_names (a, b)
 }
 
 
-/* Get a sorted list of fonts of family FAMILY on frame F.  If PATTERN
-   is non-nil list fonts matching that pattern.  Otherwise, if
-   REGISTRY is non-nil return only fonts with that registry, otherwise
-   return fonts of any registry.  Set *FONTS to a vector of font_name
-   structures allocated from the heap containing the fonts found.
-   Value is the number of fonts found.  */
+/* Get a sorted list of fonts matching PATTERN on frame F.  If PATTERN
+   is nil, list fonts matching FAMILY and REGISTRY.  FAMILY is a
+   family name string or nil.  REGISTRY is a registry name string.
+   Set *FONTS to a vector of font_name structures allocated from the
+   heap containing the fonts found.  Value is the number of fonts
+   found.  */
 
 static int
 font_list_1 (f, pattern, family, registry, fonts)
@@ -2777,10 +2834,11 @@ concat_font_list (fonts1, nfonts1, fonts2, nfonts2)
 
 /* Get a sorted list of fonts of family FAMILY on frame F.
 
-   If PATTERN is non-nil list fonts matching that pattern.
+   If PATTERN is non-nil, list fonts matching that pattern.
 
-   If REGISTRY is non-nil, return fonts with that registry and the
-   alternative registries from Vface_alternative_font_registry_alist.
+   If REGISTRY is non-nil, it is a list of registry (and encoding)
+   names.  Return fonts with those registries and the alternative
+   registries from Vface_alternative_font_registry_alist.
 
    If REGISTRY is nil return fonts of any registry.
 
@@ -2794,35 +2852,37 @@ font_list (f, pattern, family, registry, fonts)
      Lisp_Object pattern, family, registry;
      struct font_name **fonts;
 {
-  int nfonts = font_list_1 (f, pattern, family, registry, fonts);
+  int nfonts;
+  int reg_prio;
+  int i;
 
-  if (!NILP (registry)
-      && CONSP (Vface_alternative_font_registry_alist))
+  if (NILP (registry))
+    return font_list_1 (f, pattern, family, registry, fonts);
+
+  for (reg_prio = 0, nfonts = 0; CONSP (registry); registry = XCDR (registry))
     {
-      Lisp_Object alter;
+      Lisp_Object elt, alter;
+      int nfonts2;
+      struct font_name *fonts2;
 
-      alter = Fassoc (registry, Vface_alternative_font_registry_alist);
-      if (CONSP (alter))
+      elt = XCAR (registry);
+      alter = Fassoc (elt, Vface_alternative_font_registry_alist);
+      if (NILP (alter))
+       alter = Fcons (elt, Qnil);
+      for (; CONSP (alter); alter = XCDR (alter), reg_prio++)
        {
-         int reg_prio, i;
-
-         for (alter = XCDR (alter), reg_prio = 1;
-              CONSP (alter);
-              alter = XCDR (alter), reg_prio++)
-           if (STRINGP (XCAR (alter)))
-             {
-               int nfonts2;
-               struct font_name *fonts2;
-
-               nfonts2 = font_list_1 (f, pattern, family, XCAR (alter),
-                                      &fonts2);
+         nfonts2 = font_list_1 (f, pattern, family, XCAR (alter), &fonts2);
+         if (nfonts2 > 0)
+           {
+             if (reg_prio > 0)
                for (i = 0; i < nfonts2; i++)
                  fonts2[i].registry_priority = reg_prio;
-               *fonts = (nfonts > 0
-                         ? concat_font_list (*fonts, nfonts, fonts2, nfonts2)
-                         : fonts2);
-               nfonts += nfonts2;
-             }
+             if (nfonts > 0)
+               *fonts = concat_font_list (*fonts, nfonts, fonts2, nfonts2);
+             else
+               *fonts = fonts2;
+             nfonts += nfonts2;
+           }
        }
     }
 
@@ -3004,7 +3064,7 @@ the WIDTH times as wide as FACE on FRAME.  */)
     {
       /* This is of limited utility since it works with character
         widths.  Keep it for compatibility.  --gerd.  */
-      int face_id = lookup_named_face (f, face, 0);
+      int face_id = lookup_named_face (f, face);
       struct face *face = (face_id < 0
                           ? NULL
                           : FACE_FROM_ID (f, face_id));
@@ -3063,6 +3123,7 @@ the WIDTH times as wide as FACE on FRAME.  */)
 #define LFACE_FONT(LFACE)          AREF ((LFACE), LFACE_FONT_INDEX)
 #define LFACE_INHERIT(LFACE)       AREF ((LFACE), LFACE_INHERIT_INDEX)
 #define LFACE_AVGWIDTH(LFACE)      AREF ((LFACE), LFACE_AVGWIDTH_INDEX)
+#define LFACE_FONTSET(LFACE)       AREF ((LFACE), LFACE_FONTSET_INDEX)
 
 /* Non-zero if LFACE is a Lisp face.  A Lisp face is a vector of size
    LFACE_VECTOR_SIZE which has the symbol `face' in slot 0.  */
@@ -3126,6 +3187,8 @@ check_lface_attrs (attrs)
   xassert (UNSPECIFIEDP (attrs[LFACE_FONT_INDEX])
           || NILP (attrs[LFACE_FONT_INDEX])
           || STRINGP (attrs[LFACE_FONT_INDEX]));
+  xassert (UNSPECIFIEDP (attrs[LFACE_FONTSET_INDEX])
+          || STRINGP (attrs[LFACE_FONTSET_INDEX]));
 #endif
 }
 
@@ -3151,6 +3214,49 @@ check_lface (lface)
 #endif /* GLYPH_DEBUG == 0 */
 
 
+\f
+/* Face-merge cycle checking.  */
+
+/* A `named merge point' is simply a point during face-merging where we
+   look up a face by name.  We keep a stack of which named lookups we're
+   currently processing so that we can easily detect cycles, using a
+   linked- list of struct named_merge_point structures, typically
+   allocated on the stack frame of the named lookup functions which are
+   active (so no consing is required).  */
+struct named_merge_point
+{
+  Lisp_Object face_name;
+  struct named_merge_point *prev;
+};
+
+
+/* If a face merging cycle is detected for FACE_NAME, return 0,
+   otherwise add NEW_NAMED_MERGE_POINT, which is initialized using
+   FACE_NAME, as the head of the linked list pointed to by
+   NAMED_MERGE_POINTS, and return 1.  */
+
+static INLINE int
+push_named_merge_point (struct named_merge_point *new_named_merge_point,
+                       Lisp_Object face_name,
+                       struct named_merge_point **named_merge_points)
+{
+  struct named_merge_point *prev;
+
+  for (prev = *named_merge_points; prev; prev = prev->prev)
+    if (EQ (face_name, prev->face_name))
+      return 0;
+
+  new_named_merge_point->face_name = face_name;
+  new_named_merge_point->prev = *named_merge_points;
+
+  *named_merge_points = new_named_merge_point;
+
+  return 1;
+}
+
+\f
+
+
 /* Resolve face name FACE_NAME.  If FACE_NAME is a string, intern it
    to make it a symvol.  If FACE_NAME is an alias for another face,
    return that face's name.  */
@@ -3252,7 +3358,7 @@ lface_fully_specified_p (attrs)
 
   for (i = 1; i < LFACE_VECTOR_SIZE; ++i)
     if (i != LFACE_FONT_INDEX && i != LFACE_INHERIT_INDEX
-       && i != LFACE_AVGWIDTH_INDEX)
+       && i != LFACE_AVGWIDTH_INDEX && i != LFACE_FONTSET_INDEX)
       if (UNSPECIFIEDP (attrs[i])
 #ifdef MAC_OS
         /* MAC_TODO: No stipple support on Mac OS yet, this index is
@@ -3296,8 +3402,14 @@ set_lface_from_font_name (f, lface, fontname, force_p, may_fail_p)
 
   /* If FONTNAME is actually a fontset name, get ASCII font name of it.  */
   fontset = fs_query_fontset (fontname, 0);
-  if (fontset >= 0)
+  if (fontset > 0)
     font_name = SDATA (fontset_ascii (fontset));
+  else if (fontset == 0)
+    {
+      if (may_fail_p)
+       return 0;
+      abort ();
+    }
 
   /* Check if FONT_NAME is surely available on the system.  Usually
      FONT_NAME is already cached for the frame F and FS_LOAD_FONT
@@ -3305,7 +3417,7 @@ set_lface_from_font_name (f, lface, fontname, force_p, may_fail_p)
      caching it now is not futail because we anyway load the font
      later.  */
   BLOCK_INPUT;
-  font_info = FS_LOAD_FONT (f, 0, font_name, -1);
+  font_info = FS_LOAD_FONT (f, font_name);
   UNBLOCK_INPUT;
 
   if (!font_info)
@@ -3367,8 +3479,18 @@ set_lface_from_font_name (f, lface, fontname, force_p, may_fail_p)
     LFACE_SLANT (lface)
       = have_xlfd_p ? xlfd_symbolic_slant (&font) : Qnormal;
 
-  LFACE_FONT (lface) = fontname;
-
+  if (fontset > 0)
+    {
+      LFACE_FONT (lface) = build_string (font_info->full_name);
+      LFACE_FONTSET (lface) = fontset_name (fontset);
+    }
+  else
+    {
+      LFACE_FONT (lface) = fontname;
+      fontset
+       = new_fontset_from_font_name (build_string (font_info->full_name));
+      LFACE_FONTSET (lface) = fontset_name (fontset);
+    }
   return 1;
 }
 
@@ -3401,6 +3523,8 @@ merge_face_heights (from, to, invalid, gcpro)
       else if (FLOATP (to))
        /* relative X relative => relative */
        result = make_float (XFLOAT_DATA (from) * XFLOAT_DATA (to));
+      else if (UNSPECIFIEDP (to))
+       result = from;
     }
   else if (FUNCTIONP (from))
     /* FROM is a function, which use to adjust TO.  */
@@ -3432,14 +3556,15 @@ merge_face_heights (from, to, invalid, gcpro)
    completely specified and contain only absolute attributes.  Every
    specified attribute of FROM overrides the corresponding attribute of
    TO; relative attributes in FROM are merged with the absolute value in
-   TO and replace it.  CYCLE_CHECK is used internally to detect loops in
-   face inheritance; it should be Qnil when called from other places.  */
+   TO and replace it.  NAMED_MERGE_POINTS is used internally to detect
+   loops in face inheritance; it should be 0 when called from other
+   places.  */
 
 static INLINE void
-merge_face_vectors (f, from, to, cycle_check)
+merge_face_vectors (f, from, to, named_merge_points)
      struct frame *f;
      Lisp_Object *from, *to;
-     Lisp_Object cycle_check;
+     struct named_merge_point *named_merge_points;
 {
   int i;
 
@@ -3450,7 +3575,7 @@ merge_face_vectors (f, from, to, cycle_check)
      other code uses `unspecified' as a generic value for face attributes. */
   if (!UNSPECIFIEDP (from[LFACE_INHERIT_INDEX])
       && !NILP (from[LFACE_INHERIT_INDEX]))
-    merge_face_inheritance (f, from[LFACE_INHERIT_INDEX], to, cycle_check);
+    merge_face_ref (f, from[LFACE_INHERIT_INDEX], to, 0, named_merge_points);
 
   /* If TO specifies a :font attribute, and FROM specifies some
      font-related attribute, we need to clear TO's :font attribute
@@ -3469,7 +3594,8 @@ merge_face_vectors (f, from, to, cycle_check)
     if (!UNSPECIFIEDP (from[i]))
       {
        if (i == LFACE_HEIGHT_INDEX && !INTEGERP (from[i]))
-         to[i] = merge_face_heights (from[i], to[i], to[i], cycle_check);
+         to[i] = merge_face_heights (from[i], to[i], to[i],
+                                     named_merge_points);
        else
          to[i] = from[i];
       }
@@ -3479,61 +3605,45 @@ merge_face_vectors (f, from, to, cycle_check)
   to[LFACE_INHERIT_INDEX] = Qnil;
 }
 
-/* Merge face attributes from the face on frame F whose name is
-   INHERITS, into the vector of face attributes TO; INHERITS may also be
-   a list of face names, in which case they are applied in order.
-   CYCLE_CHECK is used to detect loops in face inheritance.
-   Returns true if any of the inherited attributes are `font-related'.  */
+/* Merge the named face FACE_NAME on frame F, into the vector of face
+   attributes TO.  NAMED_MERGE_POINTS is used to detect loops in face
+   inheritance.  Returns true if FACE_NAME is a valid face name and
+   merging succeeded.  */
 
-static void
-merge_face_inheritance (f, inherit, to, cycle_check)
+static int
+merge_named_face (f, face_name, to, named_merge_points)
      struct frame *f;
-     Lisp_Object inherit;
+     Lisp_Object face_name;
      Lisp_Object *to;
-     Lisp_Object cycle_check;
+     struct named_merge_point *named_merge_points;
 {
-  if (SYMBOLP (inherit) && !EQ (inherit, Qunspecified))
-    /* Inherit from the named face INHERIT.  */
-    {
-      Lisp_Object lface;
-
-      /* Make sure we're not in an inheritance loop.  */
-      cycle_check = CYCLE_CHECK (cycle_check, inherit, 15);
-      if (NILP (cycle_check))
-       /* Cycle detected, ignore any further inheritance.  */
-       return;
+  struct named_merge_point named_merge_point;
 
-      lface = lface_from_face_name (f, inherit, 0);
-      if (!NILP (lface))
-       merge_face_vectors (f, XVECTOR (lface)->contents, to, cycle_check);
-    }
-  else if (CONSP (inherit))
-    /* Handle a list of inherited faces by calling ourselves recursively
-       on each element.  Note that we only do so for symbol elements, so
-       it's not possible to infinitely recurse.  */
+  if (push_named_merge_point (&named_merge_point,
+                             face_name, &named_merge_points))
     {
-      while (CONSP (inherit))
-       {
-         if (SYMBOLP (XCAR (inherit)))
-           merge_face_inheritance (f, XCAR (inherit), to, cycle_check);
+      Lisp_Object from[LFACE_VECTOR_SIZE];
+      int ok = get_lface_attributes (f, face_name, from, 0);
 
-         /* Check for a circular inheritance list.  */
-         cycle_check = CYCLE_CHECK (cycle_check, inherit, 15);
-         if (NILP (cycle_check))
-           /* Cycle detected.  */
-           break;
+      if (ok)
+       merge_face_vectors (f, from, to, named_merge_points);
 
-         inherit = XCDR (inherit);
-       }
+      return ok;
     }
+  else
+    return 0;
 }
 
 
-/* Given a Lisp face attribute vector TO and a Lisp object PROP that
-   is a face property, determine the resulting face attributes on
-   frame F, and store them in TO.  PROP may be a single face
-   specification or a list of such specifications.  Each face
-   specification can be
+/* Merge face attributes from the lisp `face reference' FACE_REF on
+   frame F into the face attribute vector TO.  If ERR_MSGS is non-zero,
+   problems with FACE_REF cause an error message to be shown.  Return
+   non-zero if no errors occurred (regardless of the value of ERR_MSGS).
+   NAMED_MERGE_POINTS is used to detect loops in face inheritance or
+   list structure; it may be 0 for most callers.
+
+   FACE_REF may be a single face specification or a list of such
+   specifications.  Each face specification can be:
 
    1. A symbol or string naming a Lisp face.
 
@@ -3548,22 +3658,26 @@ merge_face_inheritance (f, inherit, to, cycle_check)
    Face specifications earlier in lists take precedence over later
    specifications.  */
 
-static void
-merge_face_vector_with_property (f, to, prop)
+static int
+merge_face_ref (f, face_ref, to, err_msgs, named_merge_points)
      struct frame *f;
+     Lisp_Object face_ref;
      Lisp_Object *to;
-     Lisp_Object prop;
+     int err_msgs;
+     struct named_merge_point *named_merge_points;
 {
-  if (CONSP (prop))
+  int ok = 1;                  /* Succeed without an error? */
+
+  if (CONSP (face_ref))
     {
-      Lisp_Object first = XCAR (prop);
+      Lisp_Object first = XCAR (face_ref);
 
       if (EQ (first, Qforeground_color)
          || EQ (first, Qbackground_color))
        {
          /* One of (FOREGROUND-COLOR . COLOR) or (BACKGROUND-COLOR
             . COLOR).  COLOR must be a string.  */
-         Lisp_Object color_name = XCDR (prop);
+         Lisp_Object color_name = XCDR (face_ref);
          Lisp_Object color = first;
 
          if (STRINGP (color_name))
@@ -3574,23 +3688,28 @@ merge_face_vector_with_property (f, to, prop)
                to[LFACE_BACKGROUND_INDEX] = color_name;
            }
          else
-           add_to_log ("Invalid face color", color_name, Qnil);
+           {
+             if (err_msgs)
+               add_to_log ("Invalid face color", color_name, Qnil);
+             ok = 0;
+           }
        }
       else if (SYMBOLP (first)
               && *SDATA (SYMBOL_NAME (first)) == ':')
        {
          /* Assume this is the property list form.  */
-         while (CONSP (prop) && CONSP (XCDR (prop)))
+         while (CONSP (face_ref) && CONSP (XCDR (face_ref)))
            {
-             Lisp_Object keyword = XCAR (prop);
-             Lisp_Object value = XCAR (XCDR (prop));
+             Lisp_Object keyword = XCAR (face_ref);
+             Lisp_Object value = XCAR (XCDR (face_ref));
+             int err = 0;
 
              if (EQ (keyword, QCfamily))
                {
                  if (STRINGP (value))
                    to[LFACE_FAMILY_INDEX] = value;
                  else
-                   add_to_log ("Invalid face font family", value, Qnil);
+                   err = 1;
                }
              else if (EQ (keyword, QCheight))
                {
@@ -3598,10 +3717,10 @@ merge_face_vector_with_property (f, to, prop)
                    merge_face_heights (value, to[LFACE_HEIGHT_INDEX],
                                        Qnil, Qnil);
 
-                 if (NILP (new_height))
-                   add_to_log ("Invalid face font height", value, Qnil);
-                 else
+                 if (! NILP (new_height))
                    to[LFACE_HEIGHT_INDEX] = new_height;
+                 else
+                   err = 1;
                }
              else if (EQ (keyword, QCweight))
                {
@@ -3609,7 +3728,7 @@ merge_face_vector_with_property (f, to, prop)
                      && face_numeric_weight (value) >= 0)
                    to[LFACE_WEIGHT_INDEX] = value;
                  else
-                   add_to_log ("Invalid face weight", value, Qnil);
+                   err = 1;
                }
              else if (EQ (keyword, QCslant))
                {
@@ -3617,7 +3736,7 @@ merge_face_vector_with_property (f, to, prop)
                      && face_numeric_slant (value) >= 0)
                    to[LFACE_SLANT_INDEX] = value;
                  else
-                   add_to_log ("Invalid face slant", value, Qnil);
+                   err = 1;
                }
              else if (EQ (keyword, QCunderline))
                {
@@ -3626,7 +3745,7 @@ merge_face_vector_with_property (f, to, prop)
                      || STRINGP (value))
                    to[LFACE_UNDERLINE_INDEX] = value;
                  else
-                   add_to_log ("Invalid face underline", value, Qnil);
+                   err = 1;
                }
              else if (EQ (keyword, QCoverline))
                {
@@ -3635,7 +3754,7 @@ merge_face_vector_with_property (f, to, prop)
                      || STRINGP (value))
                    to[LFACE_OVERLINE_INDEX] = value;
                  else
-                   add_to_log ("Invalid face overline", value, Qnil);
+                   err = 1;
                }
              else if (EQ (keyword, QCstrike_through))
                {
@@ -3644,7 +3763,7 @@ merge_face_vector_with_property (f, to, prop)
                      || STRINGP (value))
                    to[LFACE_STRIKE_THROUGH_INDEX] = value;
                  else
-                   add_to_log ("Invalid face strike-through", value, Qnil);
+                   err = 1;
                }
              else if (EQ (keyword, QCbox))
                {
@@ -3656,7 +3775,7 @@ merge_face_vector_with_property (f, to, prop)
                      || NILP (value))
                    to[LFACE_BOX_INDEX] = value;
                  else
-                   add_to_log ("Invalid face box", value, Qnil);
+                   err = 1;
                }
              else if (EQ (keyword, QCinverse_video)
                       || EQ (keyword, QCreverse_video))
@@ -3664,21 +3783,21 @@ merge_face_vector_with_property (f, to, prop)
                  if (EQ (value, Qt) || NILP (value))
                    to[LFACE_INVERSE_INDEX] = value;
                  else
-                   add_to_log ("Invalid face inverse-video", value, Qnil);
+                   err = 1;
                }
              else if (EQ (keyword, QCforeground))
                {
                  if (STRINGP (value))
                    to[LFACE_FOREGROUND_INDEX] = value;
                  else
-                   add_to_log ("Invalid face foreground", value, Qnil);
+                   err = 1;
                }
              else if (EQ (keyword, QCbackground))
                {
                  if (STRINGP (value))
                    to[LFACE_BACKGROUND_INDEX] = value;
                  else
-                   add_to_log ("Invalid face background", value, Qnil);
+                   err = 1;
                }
              else if (EQ (keyword, QCstipple))
                {
@@ -3687,7 +3806,7 @@ merge_face_vector_with_property (f, to, prop)
                  if (!NILP (pixmap_p))
                    to[LFACE_STIPPLE_INDEX] = value;
                  else
-                   add_to_log ("Invalid face stipple", value, Qnil);
+                   err = 1;
 #endif
                }
              else if (EQ (keyword, QCwidth))
@@ -3696,52 +3815,51 @@ merge_face_vector_with_property (f, to, prop)
                      && face_numeric_swidth (value) >= 0)
                    to[LFACE_SWIDTH_INDEX] = value;
                  else
-                   add_to_log ("Invalid face width", value, Qnil);
+                   err = 1;
                }
              else if (EQ (keyword, QCinherit))
                {
-                 if (SYMBOLP (value))
-                   to[LFACE_INHERIT_INDEX] = value;
-                 else
-                   {
-                     Lisp_Object tail;
-                     for (tail = value; CONSP (tail); tail = XCDR (tail))
-                       if (!SYMBOLP (XCAR (tail)))
-                         break;
-                     if (NILP (tail))
-                       to[LFACE_INHERIT_INDEX] = value;
-                     else
-                       add_to_log ("Invalid face inherit", value, Qnil);
-                   }
+                 /* This is not really very useful; it's just like a
+                    normal face reference.  */
+                 if (! merge_face_ref (f, value, to,
+                                       err_msgs, named_merge_points))
+                   err = 1;
                }
              else
-               add_to_log ("Invalid attribute %s in face property",
-                           keyword, Qnil);
+               err = 1;
+
+             if (err)
+               {
+                 add_to_log ("Invalid face attribute %S %S", keyword, value);
+                 ok = 0;
+               }
 
-             prop = XCDR (XCDR (prop));
+             face_ref = XCDR (XCDR (face_ref));
            }
        }
       else
        {
-         /* This is a list of face specs.  Specifications at the
-            beginning of the list take precedence over later
-            specifications, so we have to merge starting with the
-            last specification.  */
-         Lisp_Object next = XCDR (prop);
-         if (!NILP (next))
-           merge_face_vector_with_property (f, to, next);
-         merge_face_vector_with_property (f, to, first);
+         /* This is a list of face refs.  Those at the beginning of the
+            list take precedence over what follows, so we have to merge
+            from the end backwards.  */
+         Lisp_Object next = XCDR (face_ref);
+
+         if (! NILP (next))
+           ok = merge_face_ref (f, next, to, err_msgs, named_merge_points);
+
+         if (! merge_face_ref (f, first, to, err_msgs, named_merge_points))
+           ok = 0;
        }
     }
   else
     {
-      /* PROP ought to be a face name.  */
-      Lisp_Object lface = lface_from_face_name (f, prop, 0);
-      if (NILP (lface))
-       add_to_log ("Invalid face text property value: %s", prop, Qnil);
-      else
-       merge_face_vectors (f, XVECTOR (lface)->contents, to, Qnil);
+      /* FACE_REF ought to be a face name.  */
+      ok = merge_named_face (f, face_ref, to, named_merge_points);
+      if (!ok && err_msgs)
+       add_to_log ("Invalid face reference: %s", face_ref, Qnil);
     }
+
+  return ok;
 }
 
 
@@ -3857,12 +3975,13 @@ Otherwise check for the existence of a global face.  */)
 DEFUN ("internal-copy-lisp-face", Finternal_copy_lisp_face,
        Sinternal_copy_lisp_face, 4, 4, 0,
        doc: /* Copy face FROM to TO.
-If FRAME is t, copy the global face definition of FROM to the
-global face definition of TO.  Otherwise, copy the frame-local
-definition of FROM on FRAME to the frame-local definition of TO
-on NEW-FRAME, or FRAME if NEW-FRAME is nil.
+If FRAME is t, copy the global face definition of FROM.
+Otherwise, copy the frame-local definition of FROM on FRAME.
+If NEW-FRAME is a frame, copy that data into the frame-local
+definition of TO on NEW-FRAME.  If NEW-FRAME is nil.
+FRAME controls where the data is copied to.
 
-Value is TO.  */)
+The value is TO.  */)
      (from, to, frame, new_frame)
      Lisp_Object from, to, frame, new_frame;
 {
@@ -3870,8 +3989,6 @@ Value is TO.  */)
 
   CHECK_SYMBOL (from);
   CHECK_SYMBOL (to);
-  if (NILP (new_frame))
-    new_frame = frame;
 
   if (EQ (frame, Qt))
     {
@@ -3883,6 +4000,8 @@ Value is TO.  */)
   else
     {
       /* Copy frame-local definition of FROM.  */
+      if (NILP (new_frame))
+       new_frame = frame;
       CHECK_LIVE_FRAME (frame);
       CHECK_LIVE_FRAME (new_frame);
       lface = lface_from_face_name (XFRAME (frame), from, 1);
@@ -4179,7 +4298,7 @@ FRAME 0 means change the face on all frames, and change the default
       LFACE_SWIDTH (lface) = value;
       font_related_attr_p = 1;
     }
-  else if (EQ (attr, QCfont))
+  else if (EQ (attr, QCfont) || EQ (attr, QCfontset))
     {
 #ifdef HAVE_WINDOW_SYSTEM
       if (EQ (frame, Qt) || FRAME_WINDOW_P (XFRAME (frame)))
@@ -4203,9 +4322,16 @@ FRAME 0 means change the face on all frames, and change the default
              tmp = Fquery_fontset (value, Qnil);
              if (!NILP (tmp))
                value = tmp;
+             else if (EQ (attr, QCfontset))
+               signal_error ("Invalid fontset name", value);
 
-             if (!set_lface_from_font_name (f, lface, value, 1, 1))
-               signal_error ("Invalid font or fontset name", value);
+             if (EQ (attr, QCfont))
+               {
+                 if (!set_lface_from_font_name (f, lface, value, 1, 1))
+                   signal_error ("Invalid font or fontset name", value);
+               }
+             else
+               LFACE_FONTSET (lface) = value;
            }
 
          font_attr_p = 1;
@@ -4256,6 +4382,7 @@ FRAME 0 means change the face on all frames, and change the default
      init_iterator will then free realized faces.  */
   if (!EQ (frame, Qt)
       && (EQ (attr, QCfont)
+         || EQ (attr, QCfontset)
          || NILP (Fequal (old_value, value))))
     {
       ++face_change_count;
@@ -4363,7 +4490,7 @@ FRAME 0 means change the face on all frames, and change the default
 #ifdef HAVE_WINDOW_SYSTEM
 
 /* Set the `font' frame parameter of FRAME determined from `default'
-   face attributes LFACE.  If a face or fontset name is explicitely
+   face attributes LFACE.  If a font name is explicitely
    specfied in LFACE, use it as is.  Otherwise, determine a font name
    from the other font-related atrributes of LFACE.  In that case, if
    there's no matching font, signals an error.  */
@@ -4386,7 +4513,7 @@ set_font_frame_param (frame, lface)
          /* Choose a font name that reflects LFACE's attributes and has
             the registry and encoding pattern specified in the default
             fontset (3rd arg: -1) for ASCII characters (4th arg: 0).  */
-         font = choose_face_font (f, XVECTOR (lface)->contents, -1, 0, 0);
+         font = choose_face_font (f, XVECTOR (lface)->contents, Qnil, NULL);
          if (!font)
            error ("No font matches the specified attribute");
          font_name = build_string (font);
@@ -4736,6 +4863,8 @@ frames).  If FRAME is omitted or nil, use the selected frame.  */)
     value = LFACE_INHERIT (lface);
   else if (EQ (keyword, QCfont))
     value = LFACE_FONT (lface);
+  else if (EQ (keyword, QCfontset))
+    value = LFACE_FONTSET (lface);
   else
     signal_error ("Invalid face attribute name", keyword);
 
@@ -4832,15 +4961,18 @@ Default face attributes override any local face attributes.  */)
    return fonts with the same size as the font of a face.  This is
    done in fontset.el.  */
 
-DEFUN ("face-font", Fface_font, Sface_font, 1, 2, 0,
+DEFUN ("face-font", Fface_font, Sface_font, 1, 3, 0,
        doc: /* Return the font name of face FACE, or nil if it is unspecified.
+The font name is, by default, for ASCII characters.
 If the optional argument FRAME is given, report on face FACE in that frame.
 If FRAME is t, report on the defaults for face FACE (for new frames).
   The font default for a face is either nil, or a list
   of the form (bold), (italic) or (bold italic).
-If FRAME is omitted or nil, use the selected frame.  */)
-     (face, frame)
-     Lisp_Object face, frame;
+If FRAME is omitted or nil, use the selected frame.  And, in this case,
+if the optional third argument CHARACTER is given,
+return the font name used for CHARACTER.  */)
+     (face, frame, character)
+     Lisp_Object face, frame, character;
 {
   if (EQ (frame, Qt))
     {
@@ -4860,9 +4992,23 @@ If FRAME is omitted or nil, use the selected frame.  */)
   else
     {
       struct frame *f = frame_or_selected_frame (frame, 1);
-      int face_id = lookup_named_face (f, face, 0);
+      int face_id = lookup_named_face (f, face);
       struct face *face = FACE_FROM_ID (f, face_id);
-      return face ? build_string (face->font_name) : Qnil;
+
+      if (! face)
+       return Qnil;
+#ifdef HAVE_WINDOW_SYSTEM
+      if (FRAME_WINDOW_P (f) && !NILP (character))
+       {
+         CHECK_CHARACTER (character);
+         face_id = FACE_FOR_CHAR (f, face, XINT (character), -1, Qnil);
+         face = FACE_FROM_ID (f, face_id);
+         return (face->font && face->font_name
+                 ? build_string (face->font_name)
+                 : Qnil);
+       }
+#endif
+      return build_string (face->font_name);
     }
 }
 
@@ -4873,6 +5019,7 @@ If FRAME is omitted or nil, use the selected frame.  */)
 
 static INLINE int
 face_attr_equal_p (v1, v2)
+     Lisp_Object v1, v2;
 {
   /* Type can differ, e.g. when one attribute is unspecified, i.e. nil,
      and the other is specified.  */
@@ -4927,18 +5074,8 @@ If FRAME is omitted or nil, use the selected frame.  */)
      Lisp_Object face1, face2, frame;
 {
   int equal_p;
-  struct frame *f;
   Lisp_Object lface1, lface2;
 
-  if (EQ (frame, Qt))
-    f = NULL;
-  else
-    /* Don't use check_x_frame here because this function is called
-       before X frames exist.  At that time, if FRAME is nil,
-       selected_frame will be used which is the frame dumped with
-       Emacs.  That frame is not an X frame.  */
-    f = frame_or_selected_frame (frame, 2);
-
   lface1 = lface_from_face_name (NULL, face1, 1);
   lface2 = lface_from_face_name (NULL, face2, 1);
   equal_p = lface_equal_p (XVECTOR (lface1)->contents,
@@ -5024,8 +5161,8 @@ lface_hash (v)
 
 /* Return non-zero if LFACE1 and LFACE2 specify the same font (without
    considering charsets/registries).  They do if they specify the same
-   family, point size, weight, width, slant, and fontset.  Both LFACE1
-   and LFACE2 must be fully-specified.  */
+   family, point size, weight, width, slant, font, and fontset.  Both
+   LFACE1 and LFACE2 must be fully-specified.  */
 
 static INLINE int
 lface_same_font_attributes_p (lface1, lface2)
@@ -5043,8 +5180,14 @@ lface_same_font_attributes_p (lface1, lface2)
          && (EQ (lface1[LFACE_FONT_INDEX], lface2[LFACE_FONT_INDEX])
              || (STRINGP (lface1[LFACE_FONT_INDEX])
                  && STRINGP (lface2[LFACE_FONT_INDEX])
-                 && xstricmp (SDATA (lface1[LFACE_FONT_INDEX]),
-                              SDATA (lface2[LFACE_FONT_INDEX])))));
+                 && ! xstricmp (SDATA (lface1[LFACE_FONT_INDEX]),
+                                SDATA (lface2[LFACE_FONT_INDEX]))))
+         && (EQ (lface1[LFACE_FONTSET_INDEX], lface2[LFACE_FONTSET_INDEX])
+             || (STRINGP (lface1[LFACE_FONTSET_INDEX])
+                 && STRINGP (lface2[LFACE_FONTSET_INDEX])
+                 && ! xstricmp (SDATA (lface1[LFACE_FONTSET_INDEX]),
+                                SDATA (lface2[LFACE_FONTSET_INDEX]))))
+         );
 }
 
 
@@ -5071,7 +5214,7 @@ make_realized_face (attr)
 /* Free realized face FACE, including its X resources.  FACE may
    be null.  */
 
-static void
+void
 free_realized_face (f, face)
      struct frame *f;
      struct face *face;
@@ -5306,11 +5449,10 @@ free_realized_faces (c)
 }
 
 
-/* Free all faces realized for multibyte characters on frame F that
-   has FONTSET.  */
+/* Free all realized faces that are using FONTSET on frame F.  */
 
 void
-free_realized_multibyte_face (f, fontset)
+free_realized_faces_for_fontset (f, fontset)
      struct frame *f;
      int fontset;
 {
@@ -5327,7 +5469,6 @@ free_realized_multibyte_face (f, fontset)
     {
       face = cache->faces_by_id[i];
       if (face
-         && face != face->ascii_face
          && face->fontset == fontset)
        {
          uncache_face (cache, face);
@@ -5385,10 +5526,11 @@ free_face_cache (c)
 
 
 /* Cache realized face FACE in face cache C.  HASH is the hash value
-   of FACE.  If FACE->fontset >= 0, add the new face to the end of the
-   collision list of the face hash table of C.  This is done because
-   otherwise lookup_face would find FACE for every character, even if
-   faces with the same attributes but for specific characters exist.  */
+   of FACE.  If FACE is for ASCII characters (i.e. FACE->ascii_face ==
+   FACE), insert the new face to the beginning of the collision list
+   of the face hash table of C.  Otherwise, add the new face to the
+   end of the collision list.  This way, lookup_face can quickly find
+   that a requested face is not cached.  */
 
 static void
 cache_face (c, face, hash)
@@ -5400,7 +5542,7 @@ cache_face (c, face, hash)
 
   face->hash = hash;
 
-  if (face->fontset >= 0)
+  if (face->ascii_face != face)
     {
       struct face *last = c->buckets[i];
       if (last)
@@ -5492,17 +5634,14 @@ uncache_face (c, face)
 
 
 /* Look up a realized face with face attributes ATTR in the face cache
-   of frame F.  The face will be used to display character C.  Value
-   is the ID of the face found.  If no suitable face is found, realize
-   a new one.  In that case, if C is a multibyte character, BASE_FACE
-   is a face that has the same attributes.  */
+   of frame F.  The face will be used to display ASCII characters.
+   Value is the ID of the face found.  If no suitable face is found,
+   realize a new one.  */
 
 INLINE int
-lookup_face (f, attr, c, base_face)
+lookup_face (f, attr)
      struct frame *f;
      Lisp_Object *attr;
-     int c;
-     struct face *base_face;
 {
   struct face_cache *cache = FRAME_FACE_CACHE (f);
   unsigned hash;
@@ -5517,44 +5656,83 @@ lookup_face (f, attr, c, base_face)
   i = hash % FACE_CACHE_BUCKETS_SIZE;
 
   for (face = cache->buckets[i]; face; face = face->next)
-    if (face->hash == hash
-       && (!FRAME_WINDOW_P (f)
-           || FACE_SUITABLE_FOR_CHAR_P (face, c))
-       && lface_equal_p (face->lface, attr))
-      break;
+    {
+      if (face->ascii_face != face)
+       {
+         /* There's no more ASCII face.  */
+         face = NULL;
+         break;
+       }
+      if (face->hash == hash
+         && lface_equal_p (face->lface, attr))
+       break;
+    }
 
   /* If not found, realize a new face.  */
   if (face == NULL)
-    face = realize_face (cache, attr, c, base_face, -1);
+    face = realize_face (cache, attr, -1);
 
 #if GLYPH_DEBUG
   xassert (face == FACE_FROM_ID (f, face->id));
-
-/* When this function is called from face_for_char (in this case, C is
-   a multibyte character), a fontset of a face returned by
-   realize_face is not yet set, i.e. FACE_SUITABLE_FOR_CHAR_P (FACE,
-   C) is not sutisfied.  The fontset is set for this face by
-   face_for_char later.  */
-#if 0
-  if (FRAME_WINDOW_P (f))
-    xassert (FACE_SUITABLE_FOR_CHAR_P (face, c));
-#endif
 #endif /* GLYPH_DEBUG */
 
   return face->id;
 }
 
+#ifdef HAVE_WINDOW_SYSTEM
+/* Look up a realized face that has the same attributes as BASE_FACE
+   except for the font in the face cache of frame F.  If FONT_ID is
+   not negative, it is an ID number of an already opened font that is
+   used by the face.  If FONT_ID is negative, the face has no font.
+   Value is the ID of the face found.  If no suitable face is found,
+   realize a new one.  */
+
+int
+lookup_non_ascii_face (f, font_id, base_face)
+     struct frame *f;
+     int font_id;
+     struct face *base_face;
+{
+  struct face_cache *cache = FRAME_FACE_CACHE (f);
+  unsigned hash;
+  int i;
+  struct face *face;
+
+  xassert (cache != NULL);
+  base_face = base_face->ascii_face;
+  hash = lface_hash (base_face->lface);
+  i = hash % FACE_CACHE_BUCKETS_SIZE;
+
+  for (face = cache->buckets[i]; face; face = face->next)
+    {
+      if (face->ascii_face == face)
+       continue;
+      if (face->ascii_face == base_face
+         && face->font_info_id == font_id)
+       break;
+    }
+
+  /* If not found, realize a new face.  */
+  if (face == NULL)
+    face = realize_non_ascii_face (f, font_id, base_face);
+
+#if GLYPH_DEBUG
+  xassert (face == FACE_FROM_ID (f, face->id));
+#endif /* GLYPH_DEBUG */
+
+  return face->id;
+}
+#endif /* HAVE_WINDOW_SYSTEM */
 
 /* Return the face id of the realized face for named face SYMBOL on
-   frame F suitable for displaying character C.  Value is -1 if the
-   face couldn't be determined, which might happen if the default face
-   isn't realized and cannot be realized.  */
+   frame F suitable for displaying ASCII characters.  Value is -1 if
+   the face couldn't be determined, which might happen if the default
+   face isn't realized and cannot be realized.  */
 
 int
-lookup_named_face (f, symbol, c)
+lookup_named_face (f, symbol)
      struct frame *f;
      Lisp_Object symbol;
-     int c;
 {
   Lisp_Object attrs[LFACE_VECTOR_SIZE];
   Lisp_Object symbol_attrs[LFACE_VECTOR_SIZE];
@@ -5569,8 +5747,9 @@ lookup_named_face (f, symbol, c)
 
   get_lface_attributes (f, symbol, symbol_attrs, 1);
   bcopy (default_face->lface, attrs, sizeof attrs);
-  merge_face_vectors (f, symbol_attrs, attrs, Qnil);
-  return lookup_face (f, attrs, c, NULL);
+  merge_face_vectors (f, symbol_attrs, attrs, 0);
+
+  return lookup_face (f, attrs);
 }
 
 
@@ -5587,7 +5766,7 @@ ascii_face_of_lisp_face (f, lface_id)
   if (lface_id >= 0 && lface_id < lface_id_to_name_size)
     {
       Lisp_Object face_name = lface_id_to_name[lface_id];
-      face_id = lookup_named_face (f, face_name, 0);
+      face_id = lookup_named_face (f, face_name);
     }
   else
     face_id = -1;
@@ -5635,7 +5814,7 @@ smaller_face (f, face_id, steps)
       /* Look up a face for a slightly smaller/larger font.  */
       pt += delta;
       attrs[LFACE_HEIGHT_INDEX] = make_number (pt);
-      new_face_id = lookup_face (f, attrs, 0, NULL);
+      new_face_id = lookup_face (f, attrs);
       new_face = FACE_FROM_ID (f, new_face_id);
 
       /* If height changes, count that as one step.  */
@@ -5678,7 +5857,7 @@ face_with_height (f, face_id, height)
   face = FACE_FROM_ID (f, face_id);
   bcopy (face->lface, attrs, sizeof attrs);
   attrs[LFACE_HEIGHT_INDEX] = make_number (height);
-  face_id = lookup_face (f, attrs, 0, NULL);
+  face_id = lookup_face (f, attrs);
 #endif /* HAVE_WINDOW_SYSTEM */
 
   return face_id;
@@ -5686,17 +5865,16 @@ face_with_height (f, face_id, height)
 
 
 /* Return the face id of the realized face for named face SYMBOL on
-   frame F suitable for displaying character C, and use attributes of
-   the face FACE_ID for attributes that aren't completely specified by
-   SYMBOL.  This is like lookup_named_face, except that the default
-   attributes come from FACE_ID, not from the default face.  FACE_ID
-   is assumed to be already realized.  */
+   frame F suitable for displaying ASCII characters, and use
+   attributes of the face FACE_ID for attributes that aren't
+   completely specified by SYMBOL.  This is like lookup_named_face,
+   except that the default attributes come from FACE_ID, not from the
+   default face.  FACE_ID is assumed to be already realized.  */
 
 int
-lookup_derived_face (f, symbol, c, face_id)
+lookup_derived_face (f, symbol, face_id)
      struct frame *f;
      Lisp_Object symbol;
-     int c;
      int face_id;
 {
   Lisp_Object attrs[LFACE_VECTOR_SIZE];
@@ -5708,8 +5886,8 @@ lookup_derived_face (f, symbol, c, face_id)
 
   get_lface_attributes (f, symbol, symbol_attrs, 1);
   bcopy (default_face->lface, attrs, sizeof attrs);
-  merge_face_vectors (f, symbol_attrs, attrs, Qnil);
-  return lookup_face (f, attrs, c, default_face);
+  merge_face_vectors (f, symbol_attrs, attrs, 0);
+  return lookup_face (f, attrs);
 }
 
 DEFUN ("face-attributes-as-vector", Fface_attributes_as_vector,
@@ -5721,9 +5899,8 @@ DEFUN ("face-attributes-as-vector", Fface_attributes_as_vector,
   Lisp_Object lface;
   lface = Fmake_vector (make_number (LFACE_VECTOR_SIZE),
                        Qunspecified);
-  merge_face_vector_with_property (XFRAME (selected_frame),
-                                  XVECTOR (lface)->contents,
-                                  plist);
+  merge_face_ref (XFRAME (selected_frame), plist, XVECTOR (lface)->contents,
+                 1, 0);
   return lface;
 }
 
@@ -5797,17 +5974,19 @@ x_supports_face_attributes_p (f, attrs, def_face)
       || !UNSPECIFIEDP (attrs[LFACE_SWIDTH_INDEX])
       || !UNSPECIFIEDP (attrs[LFACE_AVGWIDTH_INDEX]))
     {
+      int face_id;
       struct face *face;
       Lisp_Object merged_attrs[LFACE_VECTOR_SIZE];
 
       bcopy (def_attrs, merged_attrs, sizeof merged_attrs);
 
-      merge_face_vectors (f, attrs, merged_attrs, Qnil);
+      merge_face_vectors (f, attrs, merged_attrs, 0);
 
-      face = FACE_FROM_ID (f, lookup_face (f, merged_attrs, 0, 0));
+      face_id = lookup_face (f, merged_attrs);
+      face = FACE_FROM_ID (f, face_id);
 
       if (! face)
-       signal_error ("cannot make face", 0);
+       error ("cannot make face");
 
       /* If the font is the same, then not supported.  */
       if (face->font == def_face->font)
@@ -5842,7 +6021,7 @@ tty_supports_face_attributes_p (f, attrs, def_face)
      Lisp_Object *attrs;
      struct face *def_face;
 {
-  int weight, i;
+  int weight;
   Lisp_Object val, fg, bg;
   XColor fg_tty_color, fg_std_color;
   XColor bg_tty_color, bg_std_color;
@@ -6027,6 +6206,12 @@ face for italic. */)
   struct face *def_face;
   Lisp_Object attrs[LFACE_VECTOR_SIZE];
 
+  if (noninteractive || !initialized)
+    /* We may not be able to access low-level face information in batch
+       mode, or before being dumped, and this function is not going to
+       be very useful in those cases anyway, so just give up.  */
+    return Qnil;
+
   if (NILP (display))
     frame = selected_frame;
   else if (FRAMEP (display))
@@ -6052,13 +6237,13 @@ face for italic. */)
 
   for (i = 0; i < LFACE_VECTOR_SIZE; i++)
     attrs[i] = Qunspecified;
-  merge_face_vector_with_property (f, attrs, attributes);
+  merge_face_ref (f, attributes, attrs, 1, 0);
 
   def_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
   if (def_face == NULL)
     {
       if (! realize_basic_faces (f))
-       signal_error ("Cannot realize default face", 0);
+       error ("Cannot realize default face");
       def_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
     }
 
@@ -6078,7 +6263,7 @@ face for italic. */)
                            Font selection
  ***********************************************************************/
 
-DEFUN ("internal-set-font-selection-order",
+ DEFUN ("internal-set-font-selection-order",
        Finternal_set_font_selection_order,
        Sinternal_set_font_selection_order, 1, 1, 0,
        doc: /* Set font selection order for face font selection to ORDER.
@@ -6318,6 +6503,12 @@ build_scalable_font_name (f, font, specified_pt)
   double resy = FRAME_X_DISPLAY_INFO (f)->resy;
   double pt;
 
+  if (font->numeric[XLFD_PIXEL_SIZE] != 0
+      || font->numeric[XLFD_POINT_SIZE] != 0)
+    /* This is a scalable font but is requested for a specific size.
+       We should not change that size.  */
+    return build_font_name (font);
+
   /* If scalable font is for a specific resolution, compute
      the point size we must specify from the resolution of
      the display and the specified resolution of the font.  */
@@ -6597,69 +6788,62 @@ try_alternative_families (f, family, registry, fonts)
 
 /* Get a list of matching fonts on frame F.
 
-   FAMILY, if a string, specifies a font family derived from the fontset.
-   It is only used if the face does not specify any family in ATTRS or
-   if we cannot find any font of the face's family.
+   PATTERN, if a string, specifies a font name pattern to match while
+   ignoring FAMILY and REGISTRY.
 
-   REGISTRY, if a string, specifies a font registry and encoding to
-   match.  A value of nil means include fonts of any registry and
-   encoding.
+   FAMILY, if a list, specifies a list of font families to try.
 
-   If PREFER_FACE_FAMILY is nonzero, perfer face's family to FAMILY.
-   Otherwise, prefer FAMILY.
+   REGISTRY, if a list, specifies a list of font registries and
+   encodinging to try.
 
    Return in *FONTS a pointer to a vector of font_name structures for
    the fonts matched.  Value is the number of fonts found.  */
 
 static int
-try_font_list (f, attrs, family, registry, fonts, prefer_face_family)
+try_font_list (f, pattern, family, registry, fonts)
      struct frame *f;
-     Lisp_Object *attrs;
-     Lisp_Object family, registry;
+     Lisp_Object pattern, family, registry;
      struct font_name **fonts;
-     int prefer_face_family;
 {
   int nfonts = 0;
-  Lisp_Object face_family = attrs[LFACE_FAMILY_INDEX];
-  Lisp_Object try_family;
-
-  try_family = (prefer_face_family || NILP (family)) ? face_family : family;
 
-  if (STRINGP (try_family))
-    nfonts = try_alternative_families (f, try_family, registry, fonts);
-
-#ifdef MAC_OS
-  /* When realizing the default face and a font spec does not matched
-     exactly, Emacs looks for ones with the same registry as the
-     default font.  On the Mac, this is mac-roman, which does not work
-     if the family is -etl-fixed, e.g.  The following widens the
-     choices and fixes that problem.  */
-  if (nfonts == 0 && STRINGP (try_family) && STRINGP (registry)
-      && xstricmp (SDATA (registry), "mac-roman") == 0)
-    nfonts = try_alternative_families (f, try_family, Qnil, fonts);
-#endif
+  if (STRINGP (pattern))
+    {
+      nfonts = font_list (f, pattern, Qnil, Qnil, fonts);
+      if (nfonts == 0 && ! EQ (Vscalable_fonts_allowed, Qt))
+       {
+         int count = SPECPDL_INDEX ();
+         specbind (Qscalable_fonts_allowed, Qt);
+         nfonts = font_list (f, pattern, Qnil, Qnil, fonts);
+         unbind_to (count, Qnil);
+       }
+    }
+  else
+    {
+      Lisp_Object tail;
 
-  if (EQ (try_family, family))
-    family = face_family;
+      if (NILP (family))
+       nfonts = font_list (f, Qnil, Qnil, registry, fonts);
+      else
+       for (tail = family; ! nfonts && CONSP (tail); tail = XCDR (tail))
+         nfonts = try_alternative_families (f, XCAR (tail), registry, fonts);
 
-  if (nfonts == 0 && STRINGP (family))
-    nfonts = try_alternative_families (f, family, registry, fonts);
+      /* Try font family of the default face or "fixed".  */
+      if (nfonts == 0 && !NILP (family))
+       {
+         struct face *default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
+         if (default_face)
+           family = default_face->lface[LFACE_FAMILY_INDEX];
+         else
+           family = build_string ("fixed");
+         nfonts = try_alternative_families (f, family, registry, fonts);
+       }
 
-  /* Try font family of the default face or "fixed".  */
-  if (nfonts == 0)
-    {
-      struct face *default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
-      if (default_face)
-       family = default_face->lface[LFACE_FAMILY_INDEX];
-      else
-       family = build_string ("fixed");
-      nfonts = font_list (f, Qnil, family, registry, fonts);
+      /* Try any family with the given registry.  */
+      if (nfonts == 0 && !NILP (family))
+       nfonts = try_alternative_families (f, Qnil, registry, fonts);
     }
 
-  /* Try any family with the given registry.  */
-  if (nfonts == 0)
-    nfonts = try_alternative_families (f, Qnil, registry, fonts);
-
   return nfonts;
 }
 
@@ -6674,63 +6858,108 @@ face_fontset (attrs)
 {
   Lisp_Object name;
 
-  name = attrs[LFACE_FONT_INDEX];
+  name = attrs[LFACE_FONTSET_INDEX];
   if (!STRINGP (name))
     return -1;
   return fs_query_fontset (name, 0);
 }
 
 
-/* Choose a name of font to use on frame F to display character C with
+/* Choose a name of font to use on frame F to display characters with
    Lisp face attributes specified by ATTRS.  The font name is
-   determined by the font-related attributes in ATTRS and the name
-   pattern for C in FONTSET.  Value is the font name which is
-   allocated from the heap and must be freed by the caller, or NULL if
-   we can get no information about the font name of C.  It is assured
-   that we always get some information for a single byte
-   character.
+   determined by the font-related attributes in ATTRS and FONT-SPEC
+   (if specified).
 
-   If NEEDS_OVERSTRIKE is non-zero, a boolean is returned in it to
-   indicate whether the resulting font should be drawn using overstrike
-   to simulate bold-face.  */
+   When we are choosing a font for ASCII characters, FONT-SPEC is
+   always nil.  Otherwise FONT-SPEC is a list
+       [ FAMILY WEIGHT SLANT SWIDTH ADSTYLE REGISTRY ]
+   or a string specifying a font name pattern.
 
-static char *
-choose_face_font (f, attrs, fontset, c, needs_overstrike)
+   If NEEDS_OVERSTRIKE is not NULL, a boolean is returned in it to
+   indicate whether the resulting font should be drawn using
+   overstrike to simulate bold-face.
+
+   Value is the font name which is allocated from the heap and must be
+   freed by the caller.  */
+
+char *
+choose_face_font (f, attrs, font_spec, needs_overstrike)
      struct frame *f;
      Lisp_Object *attrs;
-     int fontset, c;
+     Lisp_Object font_spec;
      int *needs_overstrike;
 {
-  Lisp_Object pattern;
+  Lisp_Object pattern, family, adstyle, registry;
   char *font_name = NULL;
   struct font_name *fonts;
-  int nfonts, width_ratio;
+  int nfonts;
 
   if (needs_overstrike)
     *needs_overstrike = 0;
 
-  /* Get (foundry and) family name and registry (and encoding) name of
-     a font for C.  */
-  pattern = fontset_font_pattern (f, fontset, c);
-  if (NILP (pattern))
+  /* If we are choosing an ASCII font and a font name is explicitly
+     specified in ATTRS, return it.  */
+  if (NILP (font_spec) && STRINGP (attrs[LFACE_FONT_INDEX]))
+    return xstrdup (SDATA (attrs[LFACE_FONT_INDEX]));
+
+  if (NILP (attrs[LFACE_FAMILY_INDEX]))
+    family = Qnil;
+  else
+    family = Fcons (attrs[LFACE_FAMILY_INDEX], Qnil);
+
+  /* Decide FAMILY, ADSTYLE, and REGISTRY from FONT_SPEC.  But,
+     ADSTYLE is not used in the font selector for the moment.  */
+  if (VECTORP (font_spec))
     {
-      xassert (!SINGLE_BYTE_CHAR_P (c));
-      return NULL;
+      pattern = Qnil;
+      if (STRINGP (AREF (font_spec, FONT_SPEC_FAMILY_INDEX)))
+       family = Fcons (AREF (font_spec, FONT_SPEC_FAMILY_INDEX), family);
+      adstyle = AREF (font_spec, FONT_SPEC_ADSTYLE_INDEX);
+      registry = Fcons (AREF (font_spec, FONT_SPEC_REGISTRY_INDEX), Qnil);
+    }
+  else if (STRINGP (font_spec))
+    {
+      pattern = font_spec;
+      family = Qnil;
+      adstyle = Qnil;
+      registry = Qnil;
+    }
+  else
+    {
+      /* We are choosing an ASCII font.  By default, use the registry
+        name "iso8859-1".  But, if the registry name of the ASCII
+        font specified in the fontset of ATTRS is not "iso8859-1"
+        (e.g "iso10646-1"), use also that name with higher
+        priority.  */
+      int fontset = face_fontset (attrs);
+      Lisp_Object ascii;
+      int len;
+      struct font_name font;
+
+      pattern = Qnil;
+      adstyle = Qnil;
+      registry = Fcons (build_string ("iso8859-1"), Qnil);
+
+      ascii = fontset_ascii (fontset);
+      len = SBYTES (ascii);
+      if (len < 9
+         || strcmp (SDATA (ascii) + len - 9, "iso8859-1"))
+       {
+         font.name = LSTRDUPA (ascii);
+         /* Check if the name is in XLFD.  */
+         if (split_font_name (f, &font, 0))
+           {
+             font.fields[XLFD_ENCODING][-1] = '-';
+             registry = Fcons (build_string (font.fields[XLFD_REGISTRY]),
+                               registry);
+           }
+       }
     }
-
-  /* If what we got is a name pattern, return it.  */
-  if (STRINGP (pattern))
-    return xstrdup (SDATA (pattern));
 
   /* Get a list of fonts matching that pattern and choose the
      best match for the specified face attributes from it.  */
-  nfonts = try_font_list (f, attrs, XCAR (pattern), XCDR (pattern), &fonts,
-                         (SINGLE_BYTE_CHAR_P (c)
-                          || CHAR_CHARSET (c) == charset_latin_iso8859_1));
-  width_ratio = (SINGLE_BYTE_CHAR_P (c)
-                ? 1
-                : CHARSET_WIDTH (CHAR_CHARSET (c)));
-  font_name = best_matching_font (f, attrs, fonts, nfonts, width_ratio,
+  nfonts = try_font_list (f, pattern, family, registry, &fonts);
+  font_name = best_matching_font (f, attrs, fonts, nfonts, NILP (font_spec),
                                  needs_overstrike);
   return font_name;
 }
@@ -6892,7 +7121,7 @@ realize_default_face (f)
   xassert (lface_fully_specified_p (XVECTOR (lface)->contents));
   check_lface (lface);
   bcopy (XVECTOR (lface)->contents, attrs, sizeof attrs);
-  face = realize_face (c, attrs, 0, NULL, DEFAULT_FACE_ID);
+  face = realize_face (c, attrs, DEFAULT_FACE_ID);
   return 1;
 }
 
@@ -6928,26 +7157,22 @@ realize_named_face (f, symbol, id)
 
   /* Merge SYMBOL's face with the default face.  */
   get_lface_attributes (f, symbol, symbol_attrs, 1);
-  merge_face_vectors (f, symbol_attrs, attrs, Qnil);
+  merge_face_vectors (f, symbol_attrs, attrs, 0);
 
   /* Realize the face.  */
-  new_face = realize_face (c, attrs, 0, NULL, id);
+  new_face = realize_face (c, attrs, id);
 }
 
 
 /* Realize the fully-specified face with attributes ATTRS in face
-   cache CACHE for character C.  If C is a multibyte character,
-   BASE_FACE is a face that has the same attributes.  Otherwise,
-   BASE_FACE is ignored.  If FORMER_FACE_ID is non-negative, it is an
-   ID of face to remove before caching the new face.  Value is a
-   pointer to the newly created realized face.  */
+   cache CACHE for ASCII characters.  If FORMER_FACE_ID is
+   non-negative, it is an ID of face to remove before caching the new
+   face.  Value is a pointer to the newly created realized face.  */
 
 static struct face *
-realize_face (cache, attrs, c, base_face, former_face_id)
+realize_face (cache, attrs, former_face_id)
      struct face_cache *cache;
      Lisp_Object *attrs;
-     int c;
-     struct face *base_face;
      int former_face_id;
 {
   struct face *face;
@@ -6965,37 +7190,75 @@ realize_face (cache, attrs, c, base_face, former_face_id)
     }
 
   if (FRAME_WINDOW_P (cache->f))
-    face = realize_x_face (cache, attrs, c, base_face);
+    face = realize_x_face (cache, attrs);
   else if (FRAME_TERMCAP_P (cache->f) || FRAME_MSDOS_P (cache->f))
-    face = realize_tty_face (cache, attrs, c);
+    face = realize_tty_face (cache, attrs);
   else
     abort ();
 
   /* Insert the new face.  */
   cache_face (cache, face, lface_hash (attrs));
+  return face;
+}
+
+
 #ifdef HAVE_WINDOW_SYSTEM
-  if (FRAME_WINDOW_P (cache->f) && face->font == NULL)
-    load_face_font (cache->f, face, c);
-#endif  /* HAVE_WINDOW_SYSTEM */
+/* Realize the fully-specified face that has the same attributes as
+   BASE_FACE except for the font on frame F.  If FONT_ID is not
+   negative, it is an ID number of an already opened font that should
+   be used by the face.  If FONT_ID is negative, the face has no font,
+   i.e., characters are displayed by empty boxes.  */
+
+static struct face *
+realize_non_ascii_face (f, font_id, base_face)
+     struct frame *f;
+     int font_id;
+     struct face *base_face;
+{
+  struct face_cache *cache = FRAME_FACE_CACHE (f);
+  struct face *face;
+  struct font_info *font_info;
+
+  face = (struct face *) xmalloc (sizeof *face);
+  *face = *base_face;
+  face->gc = 0;
+
+  /* Don't try to free the colors copied bitwise from BASE_FACE.  */
+  face->colors_copied_bitwise_p = 1;
+
+  face->font_info_id = font_id;
+  if (font_id >= 0)
+    {
+      font_info = FONT_INFO_FROM_ID (f, font_id);
+      face->font = font_info->font;
+      face->font_name = font_info->full_name;
+    }
+  else
+    {
+      face->font = NULL;
+      face->font_name = NULL;
+    }
+
+  face->gc = 0;
+
+  cache_face (cache, face, face->hash);
+
   return face;
 }
+#endif /* HAVE_WINDOW_SYSTEM */
 
 
 /* Realize the fully-specified face with attributes ATTRS in face
-   cache CACHE for character C.  Do it for X frame CACHE->f.  If C is
-   a multibyte character, BASE_FACE is a face that has the same
-   attributes.  Otherwise, BASE_FACE is ignored.  If the new face
-   doesn't share font with the default face, a fontname is allocated
-   from the heap and set in `font_name' of the new face, but it is not
-   yet loaded here.  Value is a pointer to the newly created realized
-   face.  */
+   cache CACHE for ASCII characters.  Do it for X frame CACHE->f.  If
+   the new face doesn't share font with the default face, a fontname
+   is allocated from the heap and set in `font_name' of the new face,
+   but it is not yet loaded here.  Value is a pointer to the newly
+   created realized face.  */
 
 static struct face *
-realize_x_face (cache, attrs, c, base_face)
+realize_x_face (cache, attrs)
      struct face_cache *cache;
      Lisp_Object *attrs;
-     int c;
-     struct face *base_face;
 {
 #ifdef HAVE_WINDOW_SYSTEM
   struct face *face, *default_face;
@@ -7003,50 +7266,24 @@ realize_x_face (cache, attrs, c, base_face)
   Lisp_Object stipple, overline, strike_through, box;
 
   xassert (FRAME_WINDOW_P (cache->f));
-  xassert (SINGLE_BYTE_CHAR_P (c)
-          || base_face);
 
   /* Allocate a new realized face.  */
   face = make_realized_face (attrs);
+  face->ascii_face = face;
 
   f = cache->f;
 
-  /* If C is a multibyte character, we share all face attirbutes with
-     BASE_FACE including the realized fontset.  But, we must load a
-     different font.  */
-  if (!SINGLE_BYTE_CHAR_P (c))
-    {
-      bcopy (base_face, face, sizeof *face);
-      face->gc = 0;
-
-      /* Don't try to free the colors copied bitwise from BASE_FACE.  */
-      face->colors_copied_bitwise_p = 1;
-
-      /* to force realize_face to load font */
-      face->font = NULL;
-      return face;
-    }
-
-  /* Now we are realizing a face for ASCII (and unibyte) characters.  */
-
   /* Determine the font to use.  Most of the time, the font will be
      the same as the font of the default face, so try that first.  */
   default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
   if (default_face
-      && FACE_SUITABLE_FOR_CHAR_P (default_face, c)
       && lface_same_font_attributes_p (default_face->lface, attrs))
     {
       face->font = default_face->font;
-      face->fontset = default_face->fontset;
       face->font_info_id = default_face->font_info_id;
       face->font_name = default_face->font_name;
-      face->ascii_face = face;
-
-      /* But, as we can't share the fontset, make a new realized
-        fontset that has the same base fontset as of the default
-        face.  */
       face->fontset
-       = make_fontset_for_ascii_face (f, default_face->fontset);
+       = make_fontset_for_ascii_face (f, default_face->fontset, face);
     }
   else
     {
@@ -7058,10 +7295,16 @@ realize_x_face (cache, attrs, c, base_face)
         are constructed from ATTRS.  */
       int fontset = face_fontset (attrs);
 
-      if ((fontset == -1) && default_face)
+      /* If we are realizing the default face, ATTRS should specify a
+        fontset.  In other words, if FONTSET is -1, we are not
+        realizing the default face, thus the default face should have
+        already been realized.  */
+      if (fontset == -1)
        fontset = default_face->fontset;
-      face->fontset = make_fontset_for_ascii_face (f, fontset);
-      face->font = NULL;       /* to force realize_face to load font */
+      if (fontset == -1)
+       abort ();
+      load_face_font (f, face);
+      face->fontset = make_fontset_for_ascii_face (f, fontset, face);
     }
 
   /* Load colors, and set remaining attributes.  */
@@ -7193,7 +7436,6 @@ realize_x_face (cache, attrs, c, base_face)
   if (!NILP (stipple))
     face->stipple = load_pixmap (f, stipple, &face->pixmap_w, &face->pixmap_h);
 
-  xassert (FACE_SUITABLE_FOR_CHAR_P (face, c));
   return face;
 #endif /* HAVE_WINDOW_SYSTEM */
 }
@@ -7286,14 +7528,13 @@ map_tty_color (f, face, idx, defaulted)
 
 
 /* Realize the fully-specified face with attributes ATTRS in face
-   cache CACHE for character C.  Do it for TTY frame CACHE->f.  Value is a
-   pointer to the newly created realized face.  */
+   cache CACHE for ASCII characters.  Do it for TTY frame CACHE->f.
+   Value is a pointer to the newly created realized face.  */
 
 static struct face *
-realize_tty_face (cache, attrs, c)
+realize_tty_face (cache, attrs)
      struct face_cache *cache;
      Lisp_Object *attrs;
-     int c;
 {
   struct face *face;
   int weight, slant;
@@ -7386,15 +7627,15 @@ compute_char_face (f, ch, prop)
   if (NILP (prop))
     {
       struct face *face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
-      face_id = FACE_FOR_CHAR (f, face, ch);
+      face_id = FACE_FOR_CHAR (f, face, ch, -1, Qnil);
     }
   else
     {
       Lisp_Object attrs[LFACE_VECTOR_SIZE];
       struct face *default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
       bcopy (default_face->lface, attrs, sizeof attrs);
-      merge_face_vector_with_property (f, attrs, prop);
-      face_id = lookup_face (f, attrs, ch, NULL);
+      merge_face_ref (f, prop, attrs, 1, 0);
+      face_id = lookup_face (f, attrs);
     }
 
   return face_id;
@@ -7479,7 +7720,7 @@ face_at_buffer_position (w, pos, region_beg, region_end,
 
   /* Merge in attributes specified via text properties.  */
   if (!NILP (prop))
-    merge_face_vector_with_property (f, attrs, prop);
+    merge_face_ref (f, prop, attrs, 1, 0);
 
   /* Now merge the overlay data.  */
   noverlays = sort_overlays (overlay_vec, noverlays, w);
@@ -7490,7 +7731,7 @@ face_at_buffer_position (w, pos, region_beg, region_end,
 
       prop = Foverlay_get (overlay_vec[i], propname);
       if (!NILP (prop))
-       merge_face_vector_with_property (f, attrs, prop);
+       merge_face_ref (f, prop, attrs, 1, 0);
 
       oend = OVERLAY_END (overlay_vec[i]);
       oendpos = OVERLAY_POSITION (oend);
@@ -7501,8 +7742,7 @@ face_at_buffer_position (w, pos, region_beg, region_end,
   /* If in the region, merge in the region face.  */
   if (pos >= region_beg && pos < region_end)
     {
-      Lisp_Object region_face = lface_from_face_name (f, Qregion, 0);
-      merge_face_vectors (f, XVECTOR (region_face)->contents, attrs, Qnil);
+      merge_named_face (f, Qregion, attrs, 0);
 
       if (region_end < endpos)
        endpos = region_end;
@@ -7512,7 +7752,7 @@ face_at_buffer_position (w, pos, region_beg, region_end,
 
   /* Look up a realized face with the given face attributes,
      or realize a new one for ASCII characters.  */
-  return lookup_face (f, attrs, 0, NULL);
+  return lookup_face (f, attrs);
 }
 
 
@@ -7598,20 +7838,17 @@ face_at_string_position (w, string, pos, bufpos, region_beg,
 
   /* Merge in attributes specified via text properties.  */
   if (!NILP (prop))
-    merge_face_vector_with_property (f, attrs, prop);
+    merge_face_ref (f, prop, attrs, 1, 0);
 
   /* If in the region, merge in the region face.  */
   if (bufpos
       && bufpos >= region_beg
       && bufpos < region_end)
-    {
-      Lisp_Object region_face = lface_from_face_name (f, Qregion, 0);
-      merge_face_vectors (f, XVECTOR (region_face)->contents, attrs, Qnil);
-    }
+    merge_named_face (f, Qregion, attrs, 0);
 
   /* Look up a realized face with the given face attributes,
      or realize a new one for ASCII characters.  */
-  return lookup_face (f, attrs, 0, NULL);
+  return lookup_face (f, attrs);
 }
 
 
@@ -7650,7 +7887,6 @@ dump_realized_face (face)
           face->underline_p,
           SDATA (Fsymbol_name (face->lface[LFACE_UNDERLINE_INDEX])));
   fprintf (stderr, "hash: %d\n", face->hash);
-  fprintf (stderr, "charset: %d\n", face->charset);
 }
 
 
@@ -7741,6 +7977,8 @@ syms_of_xfaces ()
   staticpro (&QCwidth);
   QCfont = intern (":font");
   staticpro (&QCfont);
+  QCfontset = intern (":fontset");
+  staticpro (&QCfontset);
   QCbold = intern (":bold");
   staticpro (&QCbold);
   QCitalic = intern (":italic");