*** empty log message ***
[bpt/emacs.git] / src / xfaces.c
index 76e546b..51cb455 100644 (file)
@@ -1,5 +1,6 @@
 /* xfaces.c -- "Face" primitives.
-   Copyright (C) 1993, 1994, 1998, 1999, 2000 Free Software Foundation.
+   Copyright (C) 1993, 1994, 1998, 1999, 2000, 2001
+   Free Software Foundation.
 
 This file is part of GNU Emacs.
 
@@ -65,6 +66,8 @@ Boston, MA 02111-1307, USA.  */
    font determined by the other attributes (those may be inherited
    from the `default' face).
 
+   15. A face name or list of face names from which to inherit attributes.
+
    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
@@ -154,10 +157,17 @@ Boston, MA 02111-1307, USA.  */
    width---tries to find a best match for the specified font height,
    etc.
 
-   2. Setting face-alternative-font-family-alist allows the user to
+   2. Setting face-font-family-alternatives allows the user to
    specify alternative font families to try if a family specified by a
    face doesn't exist.
 
+   3. Setting face-font-registry-alternatives allows the user to
+   specify all alternative font registries to try for a face
+   specifying a registry.
+
+   4. Setting face-ignored-fonts allows the user to ignore specific
+   fonts.
+
 
    Character compositition.
 
@@ -177,15 +187,6 @@ Boston, MA 02111-1307, USA.  */
    basic faces are realized for CHARSET_ASCII.  Frame parameters are
    used to fill in unspecified attributes of the default face.  */
 
-/* Define SCALABLE_FONTS to a non-zero value to enable scalable
-   font use. Define it to zero to disable scalable font use.
-
-   Use of too many or too large scalable fonts can crash XFree86
-   servers.  That's why I've put the code dealing with scalable fonts
-   in #if's.  */
-
-#define SCALABLE_FONTS 1
-
 #include <config.h>
 #include <sys/types.h>
 #include <sys/stat.h>
@@ -195,14 +196,15 @@ Boston, MA 02111-1307, USA.  */
 
 #ifdef HAVE_WINDOW_SYSTEM
 #include "fontset.h"
-#endif
+#endif /* HAVE_WINDOW_SYSTEM */
+
 #ifdef HAVE_X_WINDOWS
 #include "xterm.h"
 #ifdef USE_MOTIF
 #include <Xm/Xm.h>
 #include <Xm/XmStrDefs.h>
 #endif /* USE_MOTIF */
-#endif
+#endif /* HAVE_X_WINDOWS */
 
 #ifdef MSDOS
 #include "dosfns.h"
@@ -222,6 +224,33 @@ Boston, MA 02111-1307, USA.  */
 /* For historic reasons, FONT_WIDTH refers to average width on W32,
    not maximum as on X. Redefine here. */
 #define FONT_WIDTH FONT_MAX_WIDTH
+#endif /* WINDOWSNT */
+
+#ifdef macintosh
+#include "macterm.h"
+#define x_display_info mac_display_info
+#define check_x check_mac
+
+extern XGCValues *XCreateGC (void *, WindowPtr, unsigned long, XGCValues *);
+
+static INLINE GC
+x_create_gc (f, mask, xgcv)
+     struct frame *f;
+     unsigned long mask;
+     XGCValues *xgcv;
+{
+  GC gc;
+  gc = XCreateGC (FRAME_MAC_DISPLAY (f), FRAME_MAC_WINDOW (f), mask, xgcv);
+  return gc;
+}
+
+static INLINE void
+x_free_gc (f, gc)
+     struct frame *f;
+     GC gc;
+{
+  XFreeGC (FRAME_MAC_DISPLAY (f), gc);
+}
 #endif
 
 #include "buffer.h"
@@ -259,6 +288,10 @@ Boston, MA 02111-1307, USA.  */
 #define abs(X)         ((X) < 0 ? -(X) : (X))
 #endif
 
+/* Number of pt per inch (from the TeXbook).  */
+
+#define PT_PER_INCH 72.27
+
 /* Non-zero if face attribute ATTR is unspecified.  */
 
 #define UNSPECIFIEDP(ATTR) EQ ((ATTR), Qunspecified)
@@ -303,7 +336,7 @@ Lisp_Object QCfamily, QCheight, QCweight, QCslant, QCunderline;
 Lisp_Object QCinverse_video, QCforeground, QCbackground, QCstipple;
 Lisp_Object QCwidth, QCfont, QCbold, QCitalic;
 Lisp_Object QCreverse_video;
-Lisp_Object QCoverline, QCstrike_through, QCbox;
+Lisp_Object QCoverline, QCstrike_through, QCbox, QCinherit;
 
 /* Symbols used for attribute values.  */
 
@@ -354,15 +387,23 @@ Lisp_Object Vface_default_stipple;
 
 Lisp_Object Vface_alternative_font_family_alist;
 
+/* Alist of alternative font registries.  Each element is of the form
+   (REGISTRY REGISTRY1 REGISTRY2...).  If fonts of REGISTRY can't be
+   loaded, try REGISTRY1, then REGISTRY2, ...  */
+
+Lisp_Object Vface_alternative_font_registry_alist;
+
 /* Allowed scalable fonts.  A value of nil means don't allow any
    scalable fonts.  A value of t means allow the use of any scalable
    font.  Otherwise, value must be a list of regular expressions.  A
    font may be scaled if its name matches a regular expression in the
    list.  */
 
-#if SCALABLE_FONTS
 Lisp_Object Vscalable_fonts_allowed;
-#endif
+
+/* List of regular expressions that matches names of fonts to ignore. */
+
+Lisp_Object Vface_ignored_fonts;
 
 /* Maximum number of fonts to consider in font_list.  If not an
    integer > 0, DEFAULT_FONT_LIST_LIMIT is used instead.  */
@@ -426,6 +467,10 @@ static int clear_font_table_count;
 
 int face_change_count;
 
+/* Incremented for every change in the `menu' face.  */
+
+int menu_face_change_count;
+
 /* Non-zero means don't display bold text if a face's foreground
    and background colors are the inverse of the default colors of the
    display.   This is a kluge to suppress `bold black' foreground text
@@ -433,6 +478,11 @@ int face_change_count;
 
 int tty_suppress_bold_inverse_default_colors_p;
 
+/* A list of the form `((x . y))' used to avoid consing in
+   Finternal_set_lisp_face_attribute.  */
+
+static Lisp_Object Vparam_value_alist;
+
 /* The total number of colors currently allocated.  */
 
 #if GLYPH_DEBUG
@@ -474,6 +524,8 @@ static void free_font_names P_ ((struct font_name *, int));
 static int sorted_font_list P_ ((struct frame *, char *,
                                 int (*cmpfn) P_ ((const void *, const void *)),
                                 struct font_name **));
+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,
@@ -502,7 +554,9 @@ 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));
-static void merge_face_vectors P_ ((Lisp_Object *from, Lisp_Object *));
+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 int set_lface_from_font_name P_ ((struct frame *, Lisp_Object,
@@ -629,9 +683,9 @@ DEFUN ("dump-colors", Fdump_colors, Sdump_colors, 0, 0, 0,
   return Qnil;
 }
 
-
 #endif /* DEBUG_X_COLORS */
 
+
 /* Free colors used on frame F.  PIXELS is an array of NPIXELS pixel
    color values.  Interrupt input must be blocked when this function
    is called.  */
@@ -648,11 +702,11 @@ x_free_colors (f, pixels, npixels)
      necessary and some servers don't allow it.  So don't do it.  */
   if (class != StaticColor && class != StaticGray && class != TrueColor)
     {
-      XFreeColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
-                  pixels, npixels, 0);
 #ifdef DEBUG_X_COLORS
       unregister_colors (pixels, npixels);
 #endif
+      XFreeColors (FRAME_X_DISPLAY (f), FRAME_X_COLORMAP (f),
+                  pixels, npixels, 0);
     }
 }
 
@@ -676,10 +730,10 @@ x_free_dpy_colors (dpy, screen, cmap, pixels, npixels)
      necessary and some servers don't allow it.  So don't do it.  */
   if (class != StaticColor && class != StaticGray && class != TrueColor)
     {
-      XFreeColors (dpy, cmap, pixels, npixels, 0);
 #ifdef DEBUG_X_COLORS
       unregister_colors (pixels, npixels);
 #endif
+      XFreeColors (dpy, cmap, pixels, npixels, 0);
     }
 }
 
@@ -1305,7 +1359,6 @@ defined_color (f, color_name, color_def, alloc)
 #endif
 #ifdef macintosh
   else if (FRAME_MAC_P (f))
-    /* FIXME: mac_defined_color doesn't exist!  */
     return mac_defined_color (f, color_name, color_def, alloc);
 #endif
   else
@@ -1736,6 +1789,7 @@ static struct table_entry weight_table[] =
   {"black",            XLFD_WEIGHT_ULTRA_BOLD,         &Qultra_bold},
   {"bold",             XLFD_WEIGHT_BOLD,               &Qbold},
   {"book",             XLFD_WEIGHT_SEMI_LIGHT,         &Qsemi_light},
+  {"demi",             XLFD_WEIGHT_SEMI_BOLD,          &Qsemi_bold},
   {"demibold",         XLFD_WEIGHT_SEMI_BOLD,          &Qsemi_bold},
   {"extralight",       XLFD_WEIGHT_EXTRA_LIGHT,        &Qextra_light},
   {"extrabold",                XLFD_WEIGHT_EXTRA_BOLD,         &Qextra_bold},
@@ -1789,6 +1843,9 @@ struct font_name
   /* Numeric values for those fields that interest us.  See
      split_font_name for which these are.  */
   int numeric[XLFD_LAST];
+
+  /* Lower value mean higher priority.  */
+  int registry_priority;
 };
 
 /* The frame in effect when sorting font names.  Set temporarily in
@@ -1801,8 +1858,11 @@ static struct frame *font_frame;
    font height, then for weight, then for slant.'  This variable can be
    set via set-face-font-sort-order.  */
 
+#ifdef macintosh
+static int font_sort_order[4] = { XLFD_SWIDTH, XLFD_POINT_SIZE, XLFD_WEIGHT, XLFD_SLANT };
+#else
 static int font_sort_order[4];
-
+#endif
 
 /* Look up FONT.fields[FIELD_INDEX] in TABLE which has DIM entries.
    TABLE must be sorted by TABLE[i]->name in ascending order.  Value
@@ -2050,14 +2110,13 @@ xlfd_point_size (f, font)
      struct font_name *font;
 {
   double resy = FRAME_X_DISPLAY_INFO (f)->resy;
-  double font_resy = atoi (font->fields[XLFD_RESY]);
-  double font_pt = atoi (font->fields[XLFD_POINT_SIZE]);
+  double font_pixel = atoi (font->fields[XLFD_PIXEL_SIZE]);
   int real_pt;
 
-  if (font_resy == 0 || font_pt == 0)
+  if (font_pixel == 0)
     real_pt = 0;
   else
-    real_pt = (font_resy / resy) * font_pt + 0.5;
+    real_pt = PT_PER_INCH * 10.0 * font_pixel / resy + 0.5;
 
   return real_pt;
 }
@@ -2076,8 +2135,9 @@ pixel_point_size (f, pixel)
   double real_pt;
   int int_pt;
 
-  /* As one inch is 72 points, 72/RESY gives the point size of one dot.  */
-  real_pt = pixel * 72 / resy;
+  /* As one inch is PT_PER_INCH points, PT_PER_INCH/RESY gives the
+     point size of one dot.  */
+  real_pt = pixel * PT_PER_INCH / resy;
   int_pt = real_pt + 0.5;
 
   return int_pt;
@@ -2135,6 +2195,10 @@ split_font_name (f, font, numeric_p)
       font->numeric[XLFD_SWIDTH] = xlfd_numeric_swidth (font);
     }
 
+  /* Initialize it to zero.  It will be overridden by font_list while
+     trying alternate registries.  */
+  font->registry_priority = 0;
+
   return success_p;
 }
 
@@ -2217,12 +2281,7 @@ sort_fonts (f, fonts, nfonts, cmpfn)
 
    For all fonts found, set FONTS[i].name to the name of the font,
    allocated via xmalloc, and split font names into fields.  Ignore
-   fonts that we can't parse.  Value is the number of fonts found.
-
-   This is similar to x_list_fonts.  The differences are:
-
-   1. It avoids consing.
-   2. It never calls XLoadQueryFont.  */
+   fonts that we can't parse.  Value is the number of fonts found.  */
 
 static int
 x_face_list_fonts (f, pattern, fonts, nfonts, try_alternatives_p,
@@ -2233,89 +2292,60 @@ x_face_list_fonts (f, pattern, fonts, nfonts, try_alternatives_p,
      int nfonts, try_alternatives_p;
      int scalable_fonts_p;
 {
-  int n, i, j;
-  char **names;
-#ifdef HAVE_X_WINDOWS
-  Display *dpy = f ? FRAME_X_DISPLAY (f) : x_display_list->display;
+  int n;
 
-  /* Get the list of fonts matching PATTERN from the X server.  */
-  BLOCK_INPUT;
-  names = XListFonts (dpy, pattern, nfonts, &n);
-  UNBLOCK_INPUT;
-#endif
-#ifdef WINDOWSNT
   /* NTEMACS_TODO : currently this uses w32_list_fonts, but it may be
      better to do it the other way around. */
   Lisp_Object lfonts;
   Lisp_Object lpattern, tem;
 
-  n = 0;
-  names = NULL;
-
   lpattern = build_string (pattern);
 
   /* Get the list of fonts matching PATTERN.  */
+#ifdef WINDOWSNT
   BLOCK_INPUT;
   lfonts = w32_list_fonts (f, lpattern, 0, nfonts);
   UNBLOCK_INPUT;
+#else
+  lfonts = x_list_fonts (f, lpattern, scalable_fonts_p ? -1 : 0, nfonts);
+#endif
 
-  /* Count fonts returned */
+  /* Make a copy of the font names we got from X, and
+     split them into fields.  */
+  n = 0;
   for (tem = lfonts; CONSP (tem); tem = XCDR (tem))
-    n++;
-
-  /* Allocate array.  */
-  if (n)
-    names = (char **) xmalloc (n * sizeof (char *));
-
-  /* Extract font names into char * array.  */
-  tem = lfonts;
-  for (i = 0; i < n; i++)
     {
-      names[i] = XSTRING (XCAR (tem))->data;
-      tem = XCDR (tem);
-    }
-#endif
+      Lisp_Object elt, tail;
+      char *name = XSTRING (XCAR (tem))->data;
 
-  if (names)
-    {
-      /* Make a copy of the font names we got from X, and
-        split them into fields.  */
-      for (i = j = 0; i < n; ++i)
+      for (tail = Vface_ignored_fonts; CONSP (tail); tail = XCDR (tail))
        {
-         /* Make a copy of the font name.  */
-         fonts[j].name = xstrdup (names[i]);
-
-         /* Ignore fonts having a name that we can't parse.  */
-         if (!split_font_name (f, fonts + j, 1))
-           xfree (fonts[j].name);
-         else if (font_scalable_p (fonts + j))
-           {
-#if SCALABLE_FONTS
-             if (!scalable_fonts_p
-                 || !may_use_scalable_font_p (fonts + j, names[i]))
-               xfree (fonts[j].name);
-             else
-               ++j;
-#else /* !SCALABLE_FONTS */
-             /* Always ignore scalable fonts.  */
-             xfree (fonts[j].name);
-#endif /* !SCALABLE_FONTS */
-           }
-         else
-           ++j;
+         elt = XCAR (tail);
+         if (STRINGP (elt)
+             && fast_c_string_match_ignore_case (elt, name) >= 0)
+           break;
        }
+      if (!NILP (tail))
+       continue;
 
-      n = j;
+      /* Make a copy of the font name.  */
+      fonts[n].name = xstrdup (name);
 
-#ifdef HAVE_X_WINDOWS
-      /* Free font names.  */
-      BLOCK_INPUT;
-      XFreeFontNames (names);
-      UNBLOCK_INPUT;
-#endif
+      /* Ignore fonts having a name that we can't parse.  */
+      if (!split_font_name (f, fonts + n, 1))
+       xfree (fonts[n].name);
+      else if (font_scalable_p (fonts + n))
+       {
+         if (!scalable_fonts_p
+             || !may_use_scalable_font_p (fonts + n, name))
+           xfree (fonts[n].name);
+         else
+           ++n;
+       }
+      else
+       ++n;
     }
 
-
   /* If no fonts found, try patterns from Valternate_fontname_alist.  */
   if (n == 0 && try_alternatives_p)
     {
@@ -2406,11 +2436,7 @@ sorted_font_list (f, pattern, cmpfn, fonts)
     nfonts = XFASTINT (Vfont_list_limit);
 
   *fonts = (struct font_name *) xmalloc (nfonts * sizeof **fonts);
-#if SCALABLE_FONTS
   nfonts = x_face_list_fonts (f, pattern, *fonts, nfonts, 1, 1);
-#else
-  nfonts = x_face_list_fonts (f, pattern, *fonts, nfonts, 1, 0);
-#endif
 
   /* Sort the resulting array and return it in *FONTS.  If no
      fonts were found, make sure to set *FONTS to null.  */
@@ -2477,7 +2503,7 @@ cmp_font_names (a, b)
    Value is the number of fonts found.  */
 
 static int
-font_list (f, pattern, family, registry, fonts)
+font_list_1 (f, pattern, family, registry, fonts)
      struct frame *f;
      Lisp_Object pattern, family, registry;
      struct font_name **fonts;
@@ -2511,6 +2537,83 @@ font_list (f, pattern, family, registry, fonts)
 }
 
 
+/* Concatenate font list FONTS1 and FONTS2.  FONTS1 and FONTS2
+   contains NFONTS1 fonts and NFONTS2 fonts respectively.  Return a
+   pointer to a newly allocated font list.  FONTS1 and FONTS2 are
+   freed.  */
+
+static struct font_name *
+concat_font_list (fonts1, nfonts1, fonts2, nfonts2)
+     struct font_name *fonts1, *fonts2;
+     int nfonts1, nfonts2;
+{
+  int new_nfonts = nfonts1 + nfonts2;
+  struct font_name *new_fonts;
+
+  new_fonts = (struct font_name *) xmalloc (sizeof *new_fonts * new_nfonts);
+  bcopy (fonts1, new_fonts, sizeof *new_fonts * nfonts1);
+  bcopy (fonts2, new_fonts + nfonts1, sizeof *new_fonts * nfonts2);
+  xfree (fonts1);
+  xfree (fonts2);
+  return new_fonts;
+}
+
+
+/* Get a sorted list of fonts of family FAMILY on frame F.
+
+   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 nil 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.  */
+
+static int
+font_list (f, pattern, family, registry, fonts)
+     struct frame *f;
+     Lisp_Object pattern, family, registry;
+     struct font_name **fonts;
+{
+  int nfonts = font_list_1 (f, pattern, family, registry, fonts);
+  
+  if (!NILP (registry)
+      && CONSP (Vface_alternative_font_registry_alist))
+    {
+      Lisp_Object alter;
+
+      alter = Fassoc (registry, Vface_alternative_font_registry_alist);
+      if (CONSP (alter))
+       {
+         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);
+               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;
+             }
+       }
+    }
+
+  return nfonts;
+}
+
+
 /* Remove elements from LIST whose cars are `equal'.  Called from
    x-family-fonts and x-font-family-list to remove duplicate font
    entries.  */
@@ -2699,9 +2802,11 @@ 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);
-      struct face *face = FACE_FROM_ID (f, face_id);
+      struct face *face = (face_id < 0
+                          ? NULL
+                          : FACE_FROM_ID (f, face_id));
 
-      if (face->font)
+      if (face && face->font)
        size = FONT_WIDTH (face->font);
       else
        size = FONT_WIDTH (FRAME_FONT (f));
@@ -2760,6 +2865,8 @@ the WIDTH times as wide as FACE on FRAME.")
      XVECTOR (LFACE)->contents[LFACE_BOX_INDEX]
 #define LFACE_FONT(LFACE) \
      XVECTOR (LFACE)->contents[LFACE_FONT_INDEX]
+#define LFACE_INHERIT(LFACE) \
+     XVECTOR (LFACE)->contents[LFACE_INHERIT_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.  */
@@ -2783,7 +2890,9 @@ check_lface_attrs (attrs)
   xassert (UNSPECIFIEDP (attrs[LFACE_SWIDTH_INDEX])
           || SYMBOLP (attrs[LFACE_SWIDTH_INDEX]));
   xassert (UNSPECIFIEDP (attrs[LFACE_HEIGHT_INDEX])
-          || INTEGERP (attrs[LFACE_HEIGHT_INDEX]));
+          || INTEGERP (attrs[LFACE_HEIGHT_INDEX])
+          || FLOATP (attrs[LFACE_HEIGHT_INDEX])
+          || FUNCTIONP (attrs[LFACE_HEIGHT_INDEX]));
   xassert (UNSPECIFIEDP (attrs[LFACE_WEIGHT_INDEX])
           || SYMBOLP (attrs[LFACE_WEIGHT_INDEX]));
   xassert (UNSPECIFIEDP (attrs[LFACE_SLANT_INDEX])
@@ -2808,6 +2917,10 @@ check_lface_attrs (attrs)
           || STRINGP (attrs[LFACE_FOREGROUND_INDEX]));
   xassert (UNSPECIFIEDP (attrs[LFACE_BACKGROUND_INDEX])
           || STRINGP (attrs[LFACE_BACKGROUND_INDEX]));
+  xassert (UNSPECIFIEDP (attrs[LFACE_INHERIT_INDEX])
+          || NILP (attrs[LFACE_INHERIT_INDEX])
+          || SYMBOLP (attrs[LFACE_INHERIT_INDEX])
+          || CONSP (attrs[LFACE_INHERIT_INDEX]));
 #ifdef HAVE_WINDOW_SYSTEM
   xassert (UNSPECIFIEDP (attrs[LFACE_STIPPLE_INDEX])
           || SYMBOLP (attrs[LFACE_STIPPLE_INDEX])
@@ -2853,7 +2966,7 @@ resolve_face_name (face_name)
   if (STRINGP (face_name))
     face_name = intern (XSTRING (face_name)->data);
 
-  for (;;)
+  while (SYMBOLP (face_name))
     {
       aliased = Fget (face_name, Qface_alias);
       if (NILP (aliased))
@@ -2867,10 +2980,10 @@ resolve_face_name (face_name)
 
 
 /* Return the face definition of FACE_NAME on frame F.  F null means
-   return the global definition.  FACE_NAME may be a string or a
-   symbol (apparently Emacs 20.2 allows strings as face names in face
-   text properties; ediff uses that).  If FACE_NAME is an alias for
-   another face, return that face's definition.  If SIGNAL_P is
+   return the definition for new frames.  FACE_NAME may be a string or
+   a symbol (apparently Emacs 20.2 allowed strings as face names in
+   face text properties; Ediff uses that).  If FACE_NAME is an alias
+   for another face, return that face's definition.  If SIGNAL_P is
    non-zero, signal an error if FACE_NAME is not a valid face name.
    If SIGNAL_P is zero, value is nil if FACE_NAME is not a valid face
    name.  */
@@ -2940,8 +3053,9 @@ lface_fully_specified_p (attrs)
   int i;
 
   for (i = 1; i < LFACE_VECTOR_SIZE; ++i)
-    if (UNSPECIFIEDP (attrs[i]) && i != LFACE_FONT_INDEX)
-      break;
+    if (i != LFACE_FONT_INDEX && i != LFACE_INHERIT_INDEX)
+      if (UNSPECIFIEDP (attrs[i])) 
+        break;
 
   return i == LFACE_VECTOR_SIZE;
 }
@@ -3046,21 +3160,197 @@ set_lface_from_font_name (f, lface, fontname, force_p, may_fail_p)
 
   return 1;
 }
+
 #endif /* HAVE_WINDOW_SYSTEM */
 
 
-/* Merge two Lisp face attribute vectors FROM and TO and store the
-   resulting attributes in TO.  Every non-nil attribute of FROM
-   overrides the corresponding attribute of TO.  */
+/* Merges the face height FROM with the face height TO, and returns the
+   merged height.  If FROM is an invalid height, then INVALID is
+   returned instead.  FROM may be a either an absolute face height or a
+   `relative' height, and TO must be an absolute height.  The returned
+   value is always an absolute height.  GCPRO is a lisp value that will
+   be protected from garbage-collection if this function makes a call
+   into lisp.  */
+
+Lisp_Object
+merge_face_heights (from, to, invalid, gcpro)
+     Lisp_Object from, to, invalid, gcpro;
+{
+  int result = 0;
+
+  if (INTEGERP (from))
+    result = XINT (from);
+  else if (NUMBERP (from))
+    result = XFLOATINT (from) * XINT (to);
+#if 0 /* Probably not so useful.  */
+  else if (CONSP (from) && CONSP (XCDR (from)))
+    {
+      if (EQ (XCAR(from), Qplus) || EQ (XCAR(from), Qminus))
+       {
+         if (INTEGERP (XCAR (XCDR (from))))
+           {
+             int inc = XINT (XCAR (XCDR (from)));
+             if (EQ (XCAR (from), Qminus))
+               inc = -inc;
+
+             result = XFASTINT (to);
+             if (result + inc > 0)
+               /* Note that `underflows' don't mean FROM is invalid, so
+                  we just pin the result at TO if it would otherwise be
+                  negative or 0.  */
+               result += inc;
+           }
+       }
+    }
+#endif
+  else if (FUNCTIONP (from))
+    {
+      /* Call function with current height as argument.
+        From is the new height.  */
+      Lisp_Object args[2], height;
+      struct gcpro gcpro1;
+
+      GCPRO1 (gcpro);
+
+      args[0] = from;
+      args[1] = to;
+      height = safe_call (2, args);
+
+      UNGCPRO;
+
+      if (NUMBERP (height))
+       result = XFLOATINT (height);
+    }
+
+  if (result > 0)
+    return make_number (result);
+  else
+    return invalid;
+}
+
+
+/* Merge two Lisp face attribute vectors on frame F, FROM and TO, and
+   store the resulting attributes in TO, which must be already be
+   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.  */
 
 static INLINE void
-merge_face_vectors (from, to)
+merge_face_vectors (f, from, to, cycle_check)
+     struct frame *f;
      Lisp_Object *from, *to;
+     Lisp_Object cycle_check;
 {
   int i;
+
+  /* If FROM inherits from some other faces, merge their attributes into
+     TO before merging FROM's direct attributes.  Note that an :inherit
+     attribute of `unspecified' is the same as one of nil; we never
+     merge :inherit attributes, so nil is more correct, but lots of
+     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);
+
+  /* If TO specifies a :font attribute, and FROM specifies some
+     font-related attribute, we need to clear TO's :font attribute
+     (because it will be inconsistent with whatever FROM specifies, and
+     FROM takes precedence).  */
+  if (!NILP (to[LFACE_FONT_INDEX])
+      && (!UNSPECIFIEDP (from[LFACE_FAMILY_INDEX])
+         || !UNSPECIFIEDP (from[LFACE_HEIGHT_INDEX])
+         || !UNSPECIFIEDP (from[LFACE_WEIGHT_INDEX])
+         || !UNSPECIFIEDP (from[LFACE_SLANT_INDEX])
+         || !UNSPECIFIEDP (from[LFACE_SWIDTH_INDEX])))
+    to[LFACE_FONT_INDEX] = Qnil;
+
   for (i = 1; i < LFACE_VECTOR_SIZE; ++i)
     if (!UNSPECIFIEDP (from[i]))
-      to[i] = from[i];
+      if (i == LFACE_HEIGHT_INDEX && !INTEGERP (from[i]))
+       to[i] = merge_face_heights (from[i], to[i], to[i], cycle_check);
+      else
+       to[i] = from[i];
+
+  /* TO is always an absolute face, which should inherit from nothing.
+     We blindly copy the :inherit attribute above and fix it up here.  */
+  to[LFACE_INHERIT_INDEX] = Qnil;
+}
+
+
+/* Checks the `cycle check' variable CHECK to see if it indicates that
+   EL is part of a cycle; CHECK must be either Qnil or a value returned
+   by an earlier use of CYCLE_CHECK.  SUSPICIOUS is the number of
+   elements after which a cycle might be suspected; after that many
+   elements, this macro begins consing in order to keep more precise
+   track of elements.
+
+   Returns NIL if a cycle was detected, otherwise a new value for CHECK
+   that includes EL.
+
+   CHECK is evaluated multiple times, EL and SUSPICIOUS 0 or 1 times, so
+   the caller should make sure that's ok.  */
+
+#define CYCLE_CHECK(check, el, suspicious)     \
+  (NILP (check)                                        \
+   ? make_number (0)                           \
+   : (INTEGERP (check)                         \
+      ? (XFASTINT (check) < (suspicious)       \
+        ? make_number (XFASTINT (check) + 1)   \
+        : Fcons (el, Qnil))                    \
+      : (!NILP (Fmemq ((el), (check)))         \
+        ? Qnil                                 \
+        : Fcons ((el), (check)))))
+
+
+/* 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'.  */
+
+static void
+merge_face_inheritance (f, inherit, to, cycle_check)
+     struct frame *f;
+     Lisp_Object inherit;
+     Lisp_Object *to;
+     Lisp_Object cycle_check;
+{
+  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;
+
+      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.  */
+    {
+      while (CONSP (inherit))
+       {
+         if (SYMBOLP (XCAR (inherit)))
+           merge_face_inheritance (f, XCAR (inherit), to, cycle_check);
+
+         /* Check for a circular inheritance list.  */
+         cycle_check = CYCLE_CHECK (cycle_check, inherit, 15);
+         if (NILP (cycle_check))
+           /* Cycle detected.  */
+           break;
+
+         inherit = XCDR (inherit);
+       }
+    }
 }
 
 
@@ -3129,10 +3419,14 @@ merge_face_vector_with_property (f, to, prop)
                }
              else if (EQ (keyword, QCheight))
                {
-                 if (INTEGERP (value))
-                   to[LFACE_HEIGHT_INDEX] = value;
-                 else
+                 Lisp_Object new_height =
+                   merge_face_heights (value, to[LFACE_HEIGHT_INDEX],
+                                       Qnil, Qnil);
+
+                 if (NILP (new_height))
                    add_to_log ("Invalid face font height", value, Qnil);
+                 else
+                   to[LFACE_HEIGHT_INDEX] = new_height;
                }
              else if (EQ (keyword, QCweight))
                {
@@ -3229,6 +3523,22 @@ merge_face_vector_with_property (f, to, prop)
                  else
                    add_to_log ("Invalid face width", value, Qnil);
                }
+             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);
+                   }
+               }
              else
                add_to_log ("Invalid attribute %s in face property",
                            keyword, Qnil);
@@ -3255,7 +3565,7 @@ merge_face_vector_with_property (f, to, prop)
       if (NILP (lface))
        add_to_log ("Invalid face text property value: %s", prop, Qnil);
       else
-       merge_face_vectors (XVECTOR (lface)->contents, to);
+       merge_face_vectors (f, XVECTOR (lface)->contents, to, Qnil);
     }
 }
 
@@ -3406,10 +3716,11 @@ Value is TO.")
 DEFUN ("internal-set-lisp-face-attribute", Finternal_set_lisp_face_attribute,
        Sinternal_set_lisp_face_attribute, 3, 4, 0,
   "Set attribute ATTR of FACE to VALUE.\n\
-If optional argument FRAME is given, set the face attribute of face FACE\n\
-on that frame.  If FRAME is t, set the attribute of the default for face\n\
-FACE (for new frames).  If FRAME is omitted or nil, use the selected\n\
-frame.")
+FRAME being a frame means change the face on that frame.\n\
+FRAME nil means change change the face of the selected frame.\n\
+FRAME t means change the default for new frames.\n\
+FRAME 0 means change the face on all frames, and change the default\n\
+  for new frames.")
   (face, attr, value, frame)
      Lisp_Object face, attr, value, frame;
 {
@@ -3425,6 +3736,17 @@ frame.")
 
   face = resolve_face_name (face);
 
+  /* If FRAME is 0, change face on all frames, and change the
+     default for new frames.  */
+  if (INTEGERP (frame) && XINT (frame) == 0)
+    {
+      Lisp_Object tail;
+      Finternal_set_lisp_face_attribute (face, attr, value, Qt);
+      FOR_EACH_FRAME (tail, frame)
+       Finternal_set_lisp_face_attribute (face, attr, value, frame);
+      return face;
+    }
+
   /* Set lface to the Lisp attribute vector of FACE.  */
   if (EQ (frame, Qt))
     lface = lface_from_face_name (NULL, face, 1);
@@ -3457,10 +3779,16 @@ frame.")
     {
       if (!UNSPECIFIEDP (value))
        {
-         CHECK_NUMBER (value, 3);
-         if (XINT (value) <= 0)
+         Lisp_Object test =
+           (EQ (face, Qdefault) ? value :
+            /* The default face must have an absolute size, otherwise, we do
+               a test merge with a random height to see if VALUE's ok. */
+            merge_face_heights (value, make_number(10), Qnil, Qnil));
+
+         if (!INTEGERP(test) || XINT(test) <= 0)
            signal_error ("Invalid face height", value);
        }
+
       old_value = LFACE_HEIGHT (lface);
       LFACE_HEIGHT (lface) = value;
       font_related_attr_p = 1;
@@ -3683,6 +4011,20 @@ frame.")
       font_attr_p = 1;
 #endif /* HAVE_WINDOW_SYSTEM */
     }
+  else if (EQ (attr, QCinherit))
+    {
+      Lisp_Object tail;
+      if (SYMBOLP (value))
+       tail = Qnil;
+      else
+       for (tail = value; CONSP (tail); tail = XCDR (tail))
+         if (!SYMBOLP (XCAR (tail)))
+           break;
+      if (NILP (tail))
+       LFACE_INHERIT (lface) = value;
+      else
+       signal_error ("Invalid face inheritance", value);
+    }
   else if (EQ (attr, QCbold))
     {
       old_value = LFACE_WEIGHT (lface);
@@ -3721,8 +4063,7 @@ frame.")
 
 #ifdef HAVE_WINDOW_SYSTEM
 
-  if (!EQ (frame, Qt)
-      && !UNSPECIFIEDP (value)
+  if (!UNSPECIFIEDP (value)
       && NILP (Fequal (old_value, value)))
     {
       Lisp_Object param;
@@ -3751,7 +4092,7 @@ frame.")
          else if (EQ (attr, QCbackground))
            param = Qscroll_bar_background;
        }
-#endif
+#endif /* not WINDOWSNT */
       else if (EQ (face, Qborder))
        {
          /* Changing background color of `border' sets frame parameter
@@ -3773,9 +4114,24 @@ frame.")
          if (EQ (attr, QCbackground))
            param = Qmouse_color;
        }
+      else if (EQ (face, Qmenu))
+       ++menu_face_change_count;
 
       if (!NILP (param))
-       Fmodify_frame_parameters (frame, Fcons (Fcons (param, value), Qnil));
+       if (EQ (frame, Qt))
+         /* Update `default-frame-alist', which is used for new frames.  */
+         {
+           store_in_alist (&Vdefault_frame_alist, param, value);
+         }
+       else
+         /* Update the current frame's parameters.  */
+         {
+           Lisp_Object cons;
+           cons = XCAR (Vparam_value_alist);
+           XCAR (cons) = param;
+           XCDR (cons) = value;
+           Fmodify_frame_parameters (frame, Vparam_value_alist);
+         }
     }
 
 #endif /* HAVE_WINDOW_SYSTEM */
@@ -3797,23 +4153,28 @@ set_font_frame_param (frame, lface)
      Lisp_Object frame, lface;
 {
   struct frame *f = XFRAME (frame);
-  Lisp_Object font_name;
-  char *font;
 
-  if (STRINGP (LFACE_FONT (lface)))
-    font_name = LFACE_FONT (lface);
-  else
+  if (FRAME_WINDOW_P (f))
     {
-      /* 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);
-      if (!font)
-       error ("No font matches the specified attribute");
-      font_name = build_string (font);
-      xfree (font);
+      Lisp_Object font_name;
+      char *font;
+      
+      if (STRINGP (LFACE_FONT (lface)))
+       font_name = LFACE_FONT (lface);
+      else
+       {
+         /* 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);
+         if (!font)
+           error ("No font matches the specified attribute");
+         font_name = build_string (font);
+         xfree (font);
+       }
+  
+      Fmodify_frame_parameters (frame, Fcons (Fcons (Qfont, font_name), Qnil));
     }
-  store_frame_param (f, Qfont, font_name);
 }
 
 
@@ -3887,6 +4248,7 @@ DEFUN ("internal-face-x-get-resource", Finternal_face_x_get_resource,
 {
   Lisp_Object value = Qnil;
 #ifndef WINDOWSNT
+#ifndef macintosh
   CHECK_STRING (resource, 0);
   CHECK_STRING (class, 1);
   CHECK_LIVE_FRAME (frame, 2);
@@ -3894,7 +4256,8 @@ DEFUN ("internal-face-x-get-resource", Finternal_face_x_get_resource,
   value = display_x_get_resource (FRAME_X_DISPLAY_INFO (XFRAME (frame)),
                                  resource, class, Qnil, Qnil);
   UNBLOCK_INPUT;
-#endif
+#endif /* not macintosh */
+#endif /* not WINDOWSNT */
   return value;
 }
 
@@ -4085,7 +4448,6 @@ xm_set_menu_resources_from_menu_face (f, widget)
     }
 }
 
-
 #endif /* USE_MOTIF */
 
 #ifdef USE_LUCID
@@ -4176,12 +4538,14 @@ x_set_menu_resources_from_menu_face (f, widget)
   if (f->face_cache->used == 0)
     recompute_basic_faces (f);
 
+  BLOCK_INPUT;
 #ifdef USE_LUCID
   xl_set_menu_resources_from_menu_face (f, widget);
 #endif
 #ifdef USE_MOTIF
   xm_set_menu_resources_from_menu_face (f, widget);
 #endif
+  UNBLOCK_INPUT;
 }
 
 #endif /* USE_X_TOOLKIT */
@@ -4244,6 +4608,8 @@ frames).  If FRAME is omitted or nil, use the selected frame.")
     value = LFACE_STIPPLE (lface);
   else if (EQ (keyword, QCwidth))
     value = LFACE_SWIDTH (lface);
+  else if (EQ (keyword, QCinherit))
+    value = LFACE_INHERIT (lface);
   else if (EQ (keyword, QCfont))
     value = LFACE_FONT (lface);
   else
@@ -4308,19 +4674,32 @@ Value is nil if ATTR doesn't have a discrete set of valid values.")
 
 DEFUN ("internal-merge-in-global-face", Finternal_merge_in_global_face,
        Sinternal_merge_in_global_face, 2, 2, 0,
-  "Add attributes from frame-default definition of FACE to FACE on FRAME.")
+  "Add attributes from frame-default definition of FACE to FACE on FRAME.\n\
+Default face attributes override any local face attributes.")
   (face, frame)
      Lisp_Object face, frame;
 {
-  Lisp_Object global_lface, local_lface;
+  int i;
+  Lisp_Object global_lface, local_lface, *gvec, *lvec;
+
   CHECK_LIVE_FRAME (frame, 1);
   global_lface = lface_from_face_name (NULL, face, 1);
   local_lface = lface_from_face_name (XFRAME (frame), face, 0);
   if (NILP (local_lface))
     local_lface = Finternal_make_lisp_face (face, frame);
-  merge_face_vectors (XVECTOR (global_lface)->contents,
-                     XVECTOR (local_lface)->contents);
-  return face;
+
+  /* Make every specified global attribute override the local one.
+     BEWARE!! This is only used from `face-set-after-frame-default' where
+     the local frame is defined from default specs in `face-defface-spec'
+     and those should be overridden by global settings.  Hence the strange
+     "global before local" priority.  */
+  lvec = XVECTOR (local_lface)->contents;
+  gvec = XVECTOR (global_lface)->contents;
+  for (i = 1; i < LFACE_VECTOR_SIZE; ++i)
+    if (! UNSPECIFIEDP (gvec[i]))
+      lvec[i] = gvec[i];
+
+  return Qnil;
 }
 
 
@@ -4359,7 +4738,7 @@ If FRAME is omitted or nil, use the selected frame.")
       struct frame *f = frame_or_selected_frame (frame, 1);
       int face_id = lookup_named_face (f, face, 0);
       struct face *face = FACE_FROM_ID (f, face_id);
-      return build_string (face->font_name);
+      return face ? build_string (face->font_name) : Qnil;
     }
 }
 
@@ -4530,8 +4909,7 @@ lface_same_font_attributes_p (lface1, lface2)
           && lface_fully_specified_p (lface2));
   return (xstricmp (XSTRING (lface1[LFACE_FAMILY_INDEX])->data,
                    XSTRING (lface2[LFACE_FAMILY_INDEX])->data) == 0
-         && (XFASTINT (lface1[LFACE_HEIGHT_INDEX])
-             == XFASTINT (lface2[LFACE_HEIGHT_INDEX]))
+         && EQ (lface1[LFACE_HEIGHT_INDEX], lface2[LFACE_HEIGHT_INDEX])
          && EQ (lface1[LFACE_SWIDTH_INDEX], lface2[LFACE_SWIDTH_INDEX])
          && EQ (lface1[LFACE_WEIGHT_INDEX], lface2[LFACE_WEIGHT_INDEX])
          && EQ (lface1[LFACE_SLANT_INDEX], lface2[LFACE_SLANT_INDEX])
@@ -4625,6 +5003,9 @@ prepare_face_for_display (f, face)
 #endif
 #ifdef WINDOWSNT
          xgcv.font = face->font;
+#endif
+#ifdef macintosh
+         xgcv.font = face->font;
 #endif
          mask |= GCFont;
        }
@@ -4975,7 +5356,9 @@ lookup_face (f, attr, c, base_face)
 
 
 /* Return the face id of the realized face for named face SYMBOL on
-   frame F suitable for displaying character C.  */
+   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.  */
 
 int
 lookup_named_face (f, symbol, c)
@@ -4987,9 +5370,16 @@ lookup_named_face (f, symbol, c)
   Lisp_Object symbol_attrs[LFACE_VECTOR_SIZE];
   struct face *default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
 
+  if (default_face == NULL)
+    {
+      if (!realize_basic_faces (f))
+       return -1;
+      default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
+    }
+
   get_lface_attributes (f, symbol, symbol_attrs, 1);
   bcopy (default_face->lface, attrs, sizeof attrs);
-  merge_face_vectors (symbol_attrs, attrs);
+  merge_face_vectors (f, symbol_attrs, attrs, Qnil);
   return lookup_face (f, attrs, c, NULL);
 }
 
@@ -5059,7 +5449,8 @@ smaller_face (f, face_id, steps)
       new_face = FACE_FROM_ID (f, new_face_id);
 
       /* If height changes, count that as one step.  */
-      if (FONT_HEIGHT (new_face->font) != last_height)
+      if ((delta < 0 && FONT_HEIGHT (new_face->font) < last_height)
+         || (delta > 0 && FONT_HEIGHT (new_face->font) > last_height))
        {
          --steps;
          last_height = FONT_HEIGHT (new_face->font);
@@ -5103,6 +5494,7 @@ face_with_height (f, face_id, height)
   return face_id;
 }
 
+
 /* 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
@@ -5126,7 +5518,7 @@ 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 (symbol_attrs, attrs);
+  merge_face_vectors (f, symbol_attrs, attrs, Qnil);
   return lookup_face (f, attrs, c, default_face);
 }
 
@@ -5215,6 +5607,23 @@ be found.  Value is ALIST.")
 }
 
 
+DEFUN ("internal-set-alternative-font-registry-alist",
+       Finternal_set_alternative_font_registry_alist,
+       Sinternal_set_alternative_font_registry_alist, 1, 1, 0,
+  "Define alternative font registries to try in face font selection.\n\
+ALIST is an alist of (REGISTRY ALTERNATIVE1 ALTERNATIVE2 ...) entries.\n\
+Each ALTERNATIVE is tried in order if no fonts of font registry REGISTRY can\n\
+be found.  Value is ALIST.")
+  (alist)
+     Lisp_Object alist;
+{
+  CHECK_LIST (alist, 0);
+  Vface_alternative_font_registry_alist = alist;
+  free_all_realized_faces (Qnil);
+  return alist;
+}
+
+
 #ifdef HAVE_WINDOW_SYSTEM
 
 /* Value is non-zero if FONT is the name of a scalable font.  The
@@ -5239,6 +5648,10 @@ font_scalable_p (font)
 }
 
 
+/* Ignore the difference of font point size less than this value.  */
+
+#define FONT_POINT_SIZE_QUANTUM 5
+
 /* Value is non-zero if FONT1 is a better match for font attributes
    VALUES than FONT2.  VALUES is an array of face attribute values in
    font sort order.  COMPARE_PT_P zero means don't compare point
@@ -5261,6 +5674,9 @@ better_font_p (values, font1, font2, compare_pt_p)
          int delta1 = abs (values[i] - font1->numeric[xlfd_idx]);
          int delta2 = abs (values[i] - font2->numeric[xlfd_idx]);
 
+         if (xlfd_idx == XLFD_POINT_SIZE
+             && abs (delta1 - delta2) < FONT_POINT_SIZE_QUANTUM)
+           continue;
          if (delta1 > delta2)
            return 0;
          else if (delta1 < delta2)
@@ -5278,12 +5694,10 @@ better_font_p (values, font1, font2, compare_pt_p)
        }
     }
 
-  return 0;
+  return (font1->registry_priority < font2->registry_priority);
 }
 
 
-#if SCALABLE_FONTS
-
 /* Value is non-zero if FONT is an exact match for face attributes in
    SPECIFIED.  SPECIFIED is an array of face attribute values in font
    sort order.  */
@@ -5324,12 +5738,12 @@ build_scalable_font_name (f, font, specified_pt)
   if (font->numeric[XLFD_RESY] != 0)
     {
       pt = resy / font->numeric[XLFD_RESY] * specified_pt + 0.5;
-      pixel_value = font->numeric[XLFD_RESY] / 720.0 * pt;
+      pixel_value = font->numeric[XLFD_RESY] / (PT_PER_INCH * 10.0) * pt;
     }
   else
     {
       pt = specified_pt;
-      pixel_value = resy / 720.0 * pt;
+      pixel_value = resy / (PT_PER_INCH * 10.0) * pt;
     }
 
   /* Set point size of the font.  */
@@ -5392,7 +5806,6 @@ may_use_scalable_font_p (font, name)
   return 0;
 }
 
-#endif /* SCALABLE_FONTS != 0 */
 
 
 /* Return the name of the best matching font for face attributes
@@ -5409,7 +5822,7 @@ best_matching_font (f, attrs, fonts, nfonts)
 {
   char *font_name;
   struct font_name *best;
-  int i, pt;
+  int i, pt = 0;
   int specified[4];
   int exact_p;
 
@@ -5434,9 +5847,6 @@ best_matching_font (f, attrs, fonts, nfonts)
        abort ();
     }
 
-#if SCALABLE_FONTS
-
-  /* Set to 1 */
   exact_p = 0;
 
   /* Start with the first non-scalable font in the list.  */
@@ -5499,22 +5909,6 @@ best_matching_font (f, attrs, fonts, nfonts)
   else
     font_name = build_font_name (best);
 
-#else /* !SCALABLE_FONTS */
-
-  /* Find the best non-scalable font.  */
-  best = fonts;
-
-  for (i = 1; i < nfonts; ++i)
-    {
-      xassert (!font_scalable_p (fonts + i));
-      if (better_font_p (specified, fonts + i, best, 1))
-       best = fonts + i;
-    }
-
-  font_name = build_font_name (best);
-
-#endif /* !SCALABLE_FONTS */
-
   /* Free font_name structures.  */
   free_font_names (fonts, nfonts);
 
@@ -5540,13 +5934,11 @@ try_font_list (f, attrs, pattern, family, registry, fonts)
     family = attrs[LFACE_FAMILY_INDEX];
 
   nfonts = font_list (f, pattern, family, registry, fonts);
-
   if (nfonts == 0 && !NILP (family))
     {
       Lisp_Object alter;
 
-      /* Try alternative font families from
-        Vface_alternative_font_family_alist.  */
+      /* Try alternative font families.  */
       alter = Fassoc (family, Vface_alternative_font_family_alist);
       if (CONSP (alter))
        for (alter = XCDR (alter);
@@ -5586,7 +5978,6 @@ face_fontset (attrs)
      Lisp_Object *attrs;
 {
   Lisp_Object name;
-  int fontset;
 
   name = attrs[LFACE_FONT_INDEX];
   if (!STRINGP (name))
@@ -5675,6 +6066,22 @@ realize_basic_faces (f)
       realize_named_face (f, Qcursor, CURSOR_FACE_ID);
       realize_named_face (f, Qmouse, MOUSE_FACE_ID);
       realize_named_face (f, Qmenu, MENU_FACE_ID);
+
+      /* Reflect changes in the `menu' face in menu bars.  */
+      if (menu_face_change_count)
+       {
+         menu_face_change_count = 0;
+         
+#ifdef USE_X_TOOLKIT
+         if (FRAME_X_P (f))
+           {
+             Widget menu = f->output_data.x->menubar_widget;
+             if (menu)
+               x_set_menu_resources_from_menu_face (f, menu);
+           }
+#endif /* USE_X_TOOLKIT */
+       }
+      
       success_p = 1;
     }
 
@@ -5696,7 +6103,6 @@ realize_default_face (f)
   Lisp_Object attrs[LFACE_VECTOR_SIZE];
   Lisp_Object frame_font;
   struct face *face;
-  int fontset;
 
   /* If the `default' face is not yet known, create it.  */
   lface = lface_from_face_name (f, Qdefault, 0);
@@ -5714,7 +6120,7 @@ realize_default_face (f)
       frame_font = Fassq (Qfont, f->param_alist);
       xassert (CONSP (frame_font) && STRINGP (XCDR (frame_font)));
       frame_font = XCDR (frame_font);
-      set_lface_from_font_name (f, lface, frame_font, 0, 1);
+      set_lface_from_font_name (f, lface, frame_font, 1, 1);
     }
 #endif /* HAVE_WINDOW_SYSTEM */
 
@@ -5752,7 +6158,9 @@ realize_default_face (f)
        LFACE_FOREGROUND (lface) = XCDR (color);
       else if (FRAME_WINDOW_P (f))
        return 0;
-      else if (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f))
+      else if (FRAME_TERMCAP_P (f)
+              || FRAME_MSDOS_P (f)
+              || FRAME_W32_CONSOLE_P (f))
        LFACE_FOREGROUND (lface) = build_string (unspecified_fg);
       else
        abort ();
@@ -5767,7 +6175,9 @@ realize_default_face (f)
        LFACE_BACKGROUND (lface) = XCDR (color);
       else if (FRAME_WINDOW_P (f))
        return 0;
-      else if (FRAME_TERMCAP_P (f) || FRAME_MSDOS_P (f))
+      else if (FRAME_TERMCAP_P (f)
+              || FRAME_MSDOS_P (f)
+              || FRAME_W32_CONSOLE_P (f))
        LFACE_BACKGROUND (lface) = build_string (unspecified_bg);
       else
        abort ();
@@ -5816,7 +6226,7 @@ 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 (symbol_attrs, attrs);
+  merge_face_vectors (f, symbol_attrs, attrs, Qnil);
 
   /* Realize the face.  */
   new_face = realize_face (c, attrs, 0, NULL, id);
@@ -5854,7 +6264,9 @@ 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);
-  else if (FRAME_TERMCAP_P (cache->f) || FRAME_MSDOS_P (cache->f))
+  else if (FRAME_TERMCAP_P (cache->f)
+          || FRAME_MSDOS_P (cache->f)
+          || FRAME_W32_CONSOLE_P (cache->f))
     face = realize_tty_face (cache, attrs, c);
   else
     abort ();
@@ -5955,6 +6367,18 @@ realize_x_face (cache, attrs, c, base_face)
        fontset = default_face->fontset;
       face->fontset = make_fontset_for_ascii_face (f, fontset);
       face->font = NULL;       /* to force realize_face to load font */
+
+#ifdef macintosh
+      /* Load the font if it is specified in ATTRS.  This fixes
+         changing frame font on the Mac.  */
+      if (STRINGP (attrs[LFACE_FONT_INDEX]))
+        {
+          struct font_info *font_info =
+            FS_LOAD_FONT (f, 0, XSTRING (attrs[LFACE_FONT_INDEX])->data, -1);
+          if (font_info)
+            face->font = font_info->font;
+        }
+#endif
     }
 
   /* Load colors, and set remaining attributes.  */
@@ -6194,11 +6618,14 @@ realize_tty_face (cache, attrs, c)
   struct frame *f = cache->f;
 
   /* Frame must be a termcap frame.  */
-  xassert (FRAME_TERMCAP_P (cache->f) || FRAME_MSDOS_P (cache->f));
+  xassert (FRAME_TERMCAP_P (cache->f)
+          || FRAME_MSDOS_P (cache->f)
+          || FRAME_W32_CONSOLE_P (cache->f));
 
   /* Allocate a new realized face.  */
   face = make_realized_face (attrs);
-  face->font_name = FRAME_MSDOS_P (cache->f) ? "ms-dos" : "tty";
+  face->font_name = FRAME_MSDOS_P (cache->f) ? "ms-dos" 
+    : FRAME_W32_CONSOLE_P (cache->f) ? "w32console" : "tty";
 
   /* Map face attributes to TTY appearances.  We map slant to
      dimmed text because we want italic text to appear differently
@@ -6329,7 +6756,6 @@ face_at_buffer_position (w, pos, region_beg, region_end,
   Lisp_Object propname = mouse ? Qmouse_face : Qface;
   Lisp_Object limit1, end;
   struct face *default_face;
-  int multibyte_p = !NILP (current_buffer->enable_multibyte_characters);
 
   /* W must display the current buffer.  We could write this function
      to use the frame and buffer of W, but right now it doesn't.  */
@@ -6413,7 +6839,7 @@ face_at_buffer_position (w, pos, region_beg, region_end,
   if (pos >= region_beg && pos < region_end)
     {
       Lisp_Object region_face = lface_from_face_name (f, Qregion, 0);
-      merge_face_vectors (XVECTOR (region_face)->contents, attrs);
+      merge_face_vectors (f, XVECTOR (region_face)->contents, attrs, Qnil);
 
       if (region_end < endpos)
        endpos = region_end;
@@ -6434,10 +6860,10 @@ face_at_buffer_position (w, pos, region_beg, region_end,
    current_buffer, otherwise BUFPOS is zero to indicate that STRING is
    not an overlay string.  W must display the current buffer.
    REGION_BEG and REGION_END give the start and end positions of the
-   region; both are -1 if no region is visible.  BASE_FACE_ID is the
-   id of the basic face to merge with.  It is usually equal to
-   DEFAULT_FACE_ID but can be MODE_LINE_FACE_ID or HEADER_LINE_FACE_ID
-   for strings displayed in the mode or top line.
+   region; both are -1 if no region is visible.
+
+   BASE_FACE_ID is the id of a face to merge with.  For strings coming
+   from overlays or the `display' property it is the face at BUFPOS.
 
    Set *ENDPTR to the next position where to check for faces in
    STRING; -1 if the face is constant from POS to the end of the
@@ -6513,7 +6939,7 @@ face_at_string_position (w, string, pos, bufpos, region_beg,
       && bufpos < region_end)
     {
       Lisp_Object region_face = lface_from_face_name (f, Qregion, 0);
-      merge_face_vectors (XVECTOR (region_face)->contents, attrs);
+      merge_face_vectors (f, XVECTOR (region_face)->contents, attrs, Qnil);
     }
 
   /* Look up a realized face with the given face attributes,
@@ -6658,6 +7084,8 @@ syms_of_xfaces ()
   staticpro (&QCstrike_through);
   QCbox = intern (":box");
   staticpro (&QCbox);
+  QCinherit = intern (":inherit");
+  staticpro (&QCinherit);
 
   /* Symbols used for Lisp face attribute values.  */
   QCcolor = intern (":color");
@@ -6748,8 +7176,12 @@ syms_of_xfaces ()
   Qtty_color_alist = intern ("tty-color-alist");
   staticpro (&Qtty_color_alist);
 
+  Vparam_value_alist = Fcons (Fcons (Qnil, Qnil), Qnil);
+  staticpro (&Vparam_value_alist);
   Vface_alternative_font_family_alist = Qnil;
   staticpro (&Vface_alternative_font_family_alist);
+  Vface_alternative_font_registry_alist = Qnil;
+  staticpro (&Vface_alternative_font_registry_alist);
 
   defsubr (&Sinternal_make_lisp_face);
   defsubr (&Sinternal_lisp_face_p);
@@ -6769,6 +7201,7 @@ syms_of_xfaces ()
   defsubr (&Sframe_face_alist);
   defsubr (&Sinternal_set_font_selection_order);
   defsubr (&Sinternal_set_alternative_font_family_alist);
+  defsubr (&Sinternal_set_alternative_font_registry_alist);
 #if GLYPH_DEBUG
   defsubr (&Sdump_face);
   defsubr (&Sshow_face_resources);
@@ -6801,22 +7234,24 @@ See `set-face-stipple' for possible values for this variable.");
    "An alist of defined terminal colors and their RGB values.");
   Vtty_defined_color_alist = Qnil;
 
-#if SCALABLE_FONTS
-
   DEFVAR_LISP ("scalable-fonts-allowed", &Vscalable_fonts_allowed,
     "Allowed scalable fonts.\n\
 A value of nil means don't allow any scalable fonts.\n\
 A value of t means allow any scalable font.\n\
 Otherwise, value must be a list of regular expressions.  A font may be\n\
 scaled if its name matches a regular expression in the list.");
-#ifdef WINDOWSNT
+#if defined (WINDOWSNT) || defined (macintosh)
   /* Windows uses mainly truetype fonts, so disallowing scalable fonts
      by default limits the fonts available severely. */
   Vscalable_fonts_allowed = Qt;
 #else
   Vscalable_fonts_allowed = Qnil;
 #endif
-#endif /* SCALABLE_FONTS */
+
+  DEFVAR_LISP ("face-ignored-fonts", &Vface_ignored_fonts,
+    "List of ignored fonts.\n\
+Each element is a regular expression that matches names of fonts to ignore.");
+  Vface_ignored_fonts = Qnil;
 
 #ifdef HAVE_WINDOW_SYSTEM
   defsubr (&Sbitmap_spec_p);