emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

+face-remapping-20040525-2-c.patch


From: Miles Bader
Subject: +face-remapping-20040525-2-c.patch
Date: Tue, 25 May 2004 23:39:29 +0900

Changes:

  (1) Face-inheritance and remapping now use the same mechanism face
      properties use, so that the merging order and other semantics are
      identical

  (2) Remapping/inheritance cycle detection is now precise -- cycles are
      detected as soon as they occurs, which could avoid problems with
      non-absolute attributes

  (3) NEWS / lispref entries

  (4) Some minor bugs fixed


Patch:


2004-05-25  Miles Bader  <address@hidden>

        * xfaces.c (Vface_remapping_alist): New variable.
        (syms_of_xfaces): Initialize it.
        (enum named_merge_point_kind, struct named_merge_point): New types.
        (push_named_merge_point): New function.
        (lface_from_face_name_no_resolve): Renamed from
        `lface_from_face_name'.  Don't resolve FACE_NAME.
        (lface_from_face_name): New function that does the resolve too.
        (get_lface_attributes_no_remap): Renamed from `get_lface_attributes'.
        Call lface_from_face_name_no_resolve instead of lface_from_face_name.
        (get_lface_attributes): New version of this function.
        (merge_face_heights): Handle `unspecified' in both directions.
        (merge_face_vectors): Take `named_merge_points' arg instead of
        `cycle_check'.  Call merge_face_ref instead merge_face_inheritance.
        (merge_face_inheritance): Function removed.
        (merge_named_face): New function.
        (merge_face_ref): Renamed from `merge_face_vector_with_property'.
        Add new `err_msgs' and `named_merge_points' args.  Return error
        status.  Only print error messages if ERR_MSGS is true.  Don't try to
        do :inherit attribute validation.
        (Ftty_supports_face_attributes_p, Fface_attributes_as_vector)
        (compute_char_face, face_at_buffer_position)
        (face_at_string_position): Call merge_face_ref instead of
        merge_face_vector_with_property.
        (lookup_named_face_1): Renamed from `lookup_named_face'.  Add new
        `signal_p' argument.
        (lookup_named_face): New version of this function.
        (lookup_basic_face): New function.
        (realize_named_face): Call get_lface_attributes_no_remap instead of
        get_lface_attributes.
        (face_at_buffer_position): Use lookup_basic_face to lookup basic
        face-ids.  Use merge_named_face instead of doing it manually.
        (face_at_string_position): Likewise.

        * xdisp.c (init_iterator): Use lookup_basic_face to lookup basic
        face-ids.
        * fontset.c (Finternal_char_font): Likewise.

        * dispextern.h (lookup_basic_face, Vface_remapping_alist): Declare.



M  etc/NEWS
M  src/ChangeLog
M  src/xfaces.c
M  src/dispextern.h
M  src/fontset.c
M  src/xdisp.c
M  lispref/display.texi

* modified files

*** orig/etc/NEWS
--- mod/etc/NEWS
***************
*** 2101,2107 ****
  total height of the line, i.e. a varying number of pixels are inserted
  after each line to make each line exactly that many pixels high.
  
- 
  ** The buffer local line-spacing variable may now have a float value,
  which is used as a height relative to the default frame line height.
  
--- 2101,2106 ----
***************
*** 2214,2219 ****
--- 2213,2221 ----
  If either property is not set, the default `overlay-arrow-string' or
  'overlay-arrow-fringe-bitmap' will be used.
  
+ ** New variable `face-remapping-alist' allows buffer-local face redefinitions
+ by remapping faces to other faces.
+ 
  +++
  ** New function `line-number-at-pos' returns line number of current
  line in current buffer, or if optional buffer position is given, line


*** orig/lispref/display.texi
--- mod/lispref/display.texi
***************
*** 2117,2122 ****
--- 2117,2156 ----
  @code{default} face specifies all attributes---in fact, the frame's own
  font and colors are synonymous with those of the default face.
  
+ @defvar face-remapping-alist
+ @tindex face-remapping-alist
+   This variable may be be used to locally change the meaning of face-names,
+ for instance making the @code{default} face a variable-pitch face in a
+ particular buffer.  It should be an alist, whose elements have the form
+ @code{(@var{face} @address@hidden)}; when the face @var{face} is
+ used at display time, then @address@hidden is used instead.
+ @address@hidden may be any face specification suitable for a
+ @code{face} text property, usually a face name, but also perhaps a property
+ list of face attribute/value pairs; @xref{Special Properties}.
+ 
+   Alternate face definitions provided by @code{face-remapping-alist}
+ @emph{replace} the remapped faces, they aren't merged with it.
+ 
+   Recursive face-remapping does not result in an error.  Instead, if a
+ remapped face is used recursively, the remapping is ignored for the
+ recursive used, and the ``true'' face used instead.
+ 
+   Because of the previous two properties, an easy way to @emph{add} to a
+ face's definition using @code{face-remapping-alist}, is simply to
+ recursively include the remapped face it the remapped definition (this is
+ not necessary when remapping the @code{default} face, the result will be
+ eventually merged with the true @code{default} by the display mechanism).
+ 
+   For example, here's how you could make the default face be the
+ @code{variable-pitch} face in a single buffer, with the height doubled:
+ 
+ @example
+ (set (make-local-variable 'face-remapping-alist)
+      '((default variable-pitch :height 2.0)))
+ @end example
+ 
+ @end defvar
+ 
  @node Font Selection
  @subsection Font Selection
  


*** orig/src/dispextern.h
--- mod/src/dispextern.h
***************
*** 2715,2720 ****
--- 2715,2721 ----
  int xstricmp P_ ((const unsigned char *, const unsigned char *));
  int lookup_face P_ ((struct frame *, Lisp_Object *, int, struct face *));
  int lookup_named_face P_ ((struct frame *, Lisp_Object, int));
+ int lookup_basic_face P_ ((struct frame *, int));
  int smaller_face P_ ((struct frame *, int, int));
  int face_with_height P_ ((struct frame *, int, int));
  int lookup_derived_face P_ ((struct frame *, Lisp_Object, int, int));
***************
*** 2731,2736 ****
--- 2732,2739 ----
  extern char unspecified_fg[], unspecified_bg[];
  void free_realized_multibyte_face P_ ((struct frame *, int));
  
+ extern Lisp_Object Vface_remapping_alist;
+ 
  /* Defined in xfns.c  */
  
  #ifdef HAVE_X_WINDOWS


*** orig/src/fontset.c
--- mod/src/fontset.c
***************
*** 1252,1258 ****
        CHECK_NATNUM (ch);
        c = XINT (ch);
        f = XFRAME (selected_frame);
!       face_id = DEFAULT_FACE_ID;
      }
    else
      {
--- 1252,1258 ----
        CHECK_NATNUM (ch);
        c = XINT (ch);
        f = XFRAME (selected_frame);
!       face_id = lookup_basic_face (f, DEFAULT_FACE_ID);
      }
    else
      {


*** orig/src/xdisp.c
--- mod/src/xdisp.c
***************
*** 2027,2032 ****
--- 2027,2033 ----
       enum face_id base_face_id;
  {
    int highlight_region_p;
+   enum face_id remapped_base_face_id = base_face_id;
  
    /* Some precondition checks.  */
    xassert (w != NULL && it != NULL);
***************
*** 2043,2048 ****
--- 2044,2053 ----
        free_all_realized_faces (Qnil);
      }
  
+   /* Perhaps remap BASE_FACE_ID to a user-specified alternative.  */
+   if (! NILP (Vface_remapping_alist))
+     remapped_base_face_id = lookup_basic_face (XFRAME (w->frame), 
base_face_id);
+ 
    /* Use one of the mode line rows of W's desired matrix if
       appropriate.  */
    if (row == NULL)
***************
*** 2058,2064 ****
    bzero (it, sizeof *it);
    it->current.overlay_string_index = -1;
    it->current.dpvec_index = -1;
!   it->base_face_id = base_face_id;
    it->string = Qnil;
    IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
  
--- 2063,2069 ----
    bzero (it, sizeof *it);
    it->current.overlay_string_index = -1;
    it->current.dpvec_index = -1;
!   it->base_face_id = remapped_base_face_id;
    it->string = Qnil;
    IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1;
  
***************
*** 2242,2252 ****
      {
        struct face *face;
  
!       it->face_id = base_face_id;
  
        /* If we have a boxed mode line, make the first character appear
         with a left box line.  */
!       face = FACE_FROM_ID (it->f, base_face_id);
        if (face->box != FACE_NO_BOX)
        it->start_of_box_run_p = 1;
      }
--- 2247,2257 ----
      {
        struct face *face;
  
!       it->face_id = remapped_base_face_id;
  
        /* If we have a boxed mode line, make the first character appear
         with a left box line.  */
!       face = FACE_FROM_ID (it->f, remapped_base_face_id);
        if (face->box != FACE_NO_BOX)
        it->start_of_box_run_p = 1;
      }
***************
*** 3472,3478 ****
              /* Value is a multiple of the canonical char height.  */
              struct face *face;
  
!             face = FACE_FROM_ID (it->f, DEFAULT_FACE_ID);
              new_height = (XFLOATINT (it->font_height)
                            * XINT (face->lface[LFACE_HEIGHT_INDEX]));
            }
--- 3477,3484 ----
              /* Value is a multiple of the canonical char height.  */
              struct face *face;
  
!             face = FACE_FROM_ID (it->f,
!                                  lookup_basic_face (it->f, DEFAULT_FACE_ID));
              new_height = (XFLOATINT (it->font_height)
                            * XINT (face->lface[LFACE_HEIGHT_INDEX]));
            }
***************
*** 3572,3578 ****
              || EQ (XCAR (prop), Qright_fringe))
          && CONSP (XCDR (prop)))
        {
!         unsigned face_id = DEFAULT_FACE_ID;
  
          /* Save current settings of IT so that we can restore them
             when we are finished with the glyph property value.  */
--- 3578,3584 ----
              || EQ (XCAR (prop), Qright_fringe))
          && CONSP (XCDR (prop)))
        {
!         unsigned face_id = lookup_basic_face (it->f, DEFAULT_FACE_ID);
  
          /* Save current settings of IT so that we can restore them
             when we are finished with the glyph property value.  */


*** orig/src/xfaces.c
--- mod/src/xfaces.c
***************
*** 396,401 ****
--- 396,408 ----
  
  Lisp_Object Vface_new_frame_defaults;
  
+ /* Alist of face mappings.  Each element is either of the form
+    (FACE . NEW-FACE), or (FACE NEW-FACE MERGE-FACE...),
+    where FACE is the named used for lookups, and NEW-FACE is the name
+    that actually gets looked up.  If present, MERGE-FACE... are merged
+    during display of FACE, with NEW-FACE.  */
+ Lisp_Object Vface_remapping_alist;
+ 
  /* The next ID to assign to Lisp faces.  */
  
  static int next_lface_id;
***************
*** 460,465 ****
--- 467,473 ----
  
  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 *));
***************
*** 471,477 ****
  static int x_face_list_fonts P_ ((struct frame *, char *,
                                  struct font_name **, int, int));
  static int font_scalable_p P_ ((struct font_name *));
! static int get_lface_attributes P_ ((struct frame *, Lisp_Object, Lisp_Object 
*, int));
  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));
--- 479,486 ----
  static int x_face_list_fonts P_ ((struct frame *, char *,
                                  struct font_name **, int, int));
  static int font_scalable_p P_ ((struct font_name *));
! static int get_lface_attributes P_ ((struct frame *, Lisp_Object, Lisp_Object 
*,
!                                    int, struct named_merge_point *));
  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));
***************
*** 518,528 ****
  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 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));
--- 527,536 ----
  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*,
!                                   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));
***************
*** 3151,3156 ****
--- 3159,3226 ----
  #endif /* GLYPH_DEBUG == 0 */
  
  
+ 
+ /* Face-merge cycle checking.  */
+ 
+ enum named_merge_point_kind
+ {
+   NAMED_MERGE_POINT_NORMAL,
+   NAMED_MERGE_POINT_REMAP
+ };
+ 
+ /* 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;
+   enum named_merge_point_kind named_merge_point_kind;
+   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 and NAMED_MERGE_POINT_KIND, 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,
+                       enum named_merge_point_kind named_merge_point_kind,
+                       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))
+       {
+       if (prev->named_merge_point_kind == named_merge_point_kind)
+         /* A cycle, so fail.  */
+         return 0;
+       else if (prev->named_merge_point_kind == NAMED_MERGE_POINT_REMAP)
+         /* A remap `hides ' any previous normal merge points
+            (because the remap means that it's actually different face),
+            so as we know the current merge point must be normal, we
+            can just assume it's OK.  */
+         break;
+       }
+ 
+   new_named_merge_point->face_name = face_name;
+   new_named_merge_point->named_merge_point_kind = named_merge_point_kind;
+   new_named_merge_point->prev = *named_merge_points;
+ 
+   *named_merge_points = new_named_merge_point;
+ 
+   return 1;
+ }
+ 
+ 
+ 
+ 
  /* 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.  */
***************
*** 3178,3201 ****
  
  
  /* Return the face definition of FACE_NAME on frame F.  F null means
!    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.  */
! 
  static INLINE Lisp_Object
! lface_from_face_name (f, face_name, signal_p)
       struct frame *f;
       Lisp_Object face_name;
       int signal_p;
  {
    Lisp_Object lface;
  
-   face_name = resolve_face_name (face_name);
- 
    if (f)
      lface = assq_no_quit (face_name, f->face_alist);
    else
--- 3248,3266 ----
  
  
  /* Return the face definition of FACE_NAME on frame F.  F null means
!    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 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.  */
  static INLINE Lisp_Object
! lface_from_face_name_no_resolve (f, face_name, signal_p)
       struct frame *f;
       Lisp_Object face_name;
       int signal_p;
  {
    Lisp_Object lface;
  
    if (f)
      lface = assq_no_quit (face_name, f->face_alist);
    else
***************
*** 3207,3215 ****
--- 3272,3298 ----
      signal_error ("Invalid face", face_name);
  
    check_lface (lface);
+ 
    return lface;
  }
  
+ /* Return the face definition of FACE_NAME on frame F.  F null means
+    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.  */
+ static INLINE Lisp_Object
+ lface_from_face_name (f, face_name, signal_p)
+      struct frame *f;
+      Lisp_Object face_name;
+      int signal_p;
+ {
+   return lface_from_face_name_no_resolve (f, face_name, signal_p);
+ }
+ 
  
  /* Get face attributes of face FACE_NAME from frame-local faces on
     frame F.  Store the resulting attributes in ATTRS which must point
***************
*** 3218,3243 ****
     Otherwise, value is zero if FACE_NAME is not a face.  */
  
  static INLINE int
! get_lface_attributes (f, face_name, attrs, signal_p)
       struct frame *f;
       Lisp_Object face_name;
       Lisp_Object *attrs;
       int signal_p;
  {
    Lisp_Object lface;
-   int success_p;
  
!   lface = lface_from_face_name (f, face_name, signal_p);
!   if (!NILP (lface))
      {
!       bcopy (XVECTOR (lface)->contents, attrs,
!            LFACE_VECTOR_SIZE * sizeof *attrs);
!       success_p = 1;
      }
-   else
-     success_p = 0;
  
!   return success_p;
  }
  
  
--- 3301,3365 ----
     Otherwise, value is zero if FACE_NAME is not a face.  */
  
  static INLINE int
! get_lface_attributes_no_remap (f, face_name, attrs, signal_p)
       struct frame *f;
       Lisp_Object face_name;
       Lisp_Object *attrs;
       int signal_p;
  {
    Lisp_Object lface;
  
!   lface = lface_from_face_name_no_resolve (f, face_name, signal_p);
! 
!   if (! NILP (lface))
!     bcopy (XVECTOR (lface)->contents, attrs,
!          LFACE_VECTOR_SIZE * sizeof *attrs);
! 
!   return !NILP (lface);
! }
! 
! /* Get face attributes of face FACE_NAME from frame-local faces on frame
!    F.  Store the resulting attributes in ATTRS which must point to a
!    vector of Lisp_Objects of size LFACE_VECTOR_SIZE.  If FACE_NAME is an
!    alias for another face, use that face's definition.  If SIGNAL_P is
!    non-zero, signal an error if FACE_NAME does not name a face.
!    Otherwise, value is zero if FACE_NAME is not a face.  */
! 
! static INLINE int
! get_lface_attributes (f, face_name, attrs, signal_p, named_merge_points)
!      struct frame *f;
!      Lisp_Object face_name;
!      Lisp_Object *attrs;
!      int signal_p;
!      struct named_merge_point *named_merge_points;
! {
!   Lisp_Object face_remapping;
! 
!   face_name = resolve_face_name (face_name);
! 
!   /* See if SYMBOL has been remapped to some other face (usually this
!      is done buffer-locally).  */
!   face_remapping = assq_no_quit (face_name, Vface_remapping_alist);
!   if (CONSP (face_remapping))
      {
!       struct named_merge_point named_merge_point;
! 
!       if (push_named_merge_point (&named_merge_point,
!                                 face_name, NAMED_MERGE_POINT_REMAP,
!                                 &named_merge_points))
!       {
!         int i;
! 
!         for (i = 1; i < LFACE_VECTOR_SIZE; ++i)
!           attrs[i] = Qunspecified;
! 
!         return merge_face_ref (f, XCDR (face_remapping), attrs,
!                                signal_p, named_merge_points);
!       }
      }
  
!   /* Default case, no remapping.  */
!   return get_lface_attributes_no_remap (f, face_name, attrs, signal_p);
  }
  
  
***************
*** 3401,3406 ****
--- 3523,3530 ----
        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,3445 ****
     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 (f, from, to, cycle_check)
       struct frame *f;
       Lisp_Object *from, *to;
!      Lisp_Object cycle_check;
  {
    int i;
  
--- 3556,3570 ----
     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.  NAMED_MERGE_POINTS is used internally to detect
!    loops in face inheritance/remapping; it should be 0 when called from
!    other places.  */
  
  static INLINE void
! merge_face_vectors (f, from, to, named_merge_points)
       struct frame *f;
       Lisp_Object *from, *to;
!      struct named_merge_point *named_merge_points;
  {
    int i;
  
***************
*** 3450,3456 ****
       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
--- 3575,3581 ----
       other code uses `unspecified' as a generic value for face attributes. */
    if (!UNSPECIFIEDP (from[LFACE_INHERIT_INDEX])
        && !NILP (from[LFACE_INHERIT_INDEX]))
!     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,3475 ****
      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);
        else
          to[i] = from[i];
        }
--- 3594,3601 ----
      if (!UNSPECIFIEDP (from[i]))
        {
        if (i == LFACE_HEIGHT_INDEX && !INTEGERP (from[i]))
!         to[i] = merge_face_heights (from[i], to[i], to[i],
!                                     named_merge_points);
        else
          to[i] = from[i];
        }
***************
*** 3479,3539 ****
    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'.  */
  
! 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);
!       }
      }
  }
  
  
! /* 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
  
     1. A symbol or string naming a Lisp face.
  
--- 3605,3650 ----
    to[LFACE_INHERIT_INDEX] = Qnil;
  }
  
! /* 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 int
! merge_named_face (f, face_name, to, named_merge_points)
       struct frame *f;
!      Lisp_Object face_name;
       Lisp_Object *to;
!      struct named_merge_point *named_merge_points;
  {
!   struct named_merge_point named_merge_point;
  
!   if (push_named_merge_point (&named_merge_point,
!                             face_name, NAMED_MERGE_POINT_NORMAL,
!                             &named_merge_points))
      {
!       Lisp_Object from[LFACE_VECTOR_SIZE];
!       int ok = get_lface_attributes (f, face_name, from, 0, 
named_merge_points);
  
!       if (ok)
!       merge_face_vectors (f, from, to, named_merge_points);
  
!       return ok;
      }
+   else
+     return 0;
  }
  
  
! /* 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,3569 ****
     Face specifications earlier in lists take precedence over later
     specifications.  */
  
! static void
! merge_face_vector_with_property (f, to, prop)
       struct frame *f;
       Lisp_Object *to;
!      Lisp_Object prop;
  {
!   if (CONSP (prop))
      {
!       Lisp_Object first = XCAR (prop);
  
        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 = first;
  
          if (STRINGP (color_name))
--- 3659,3684 ----
     Face specifications earlier in lists take precedence over later
     specifications.  */
  
! static int
! merge_face_ref (f, face_ref, to, err_msgs, named_merge_points)
       struct frame *f;
+      Lisp_Object face_ref;
       Lisp_Object *to;
!      int err_msgs;
!      struct named_merge_point *named_merge_points;
  {
!   int ok = 1;                 /* Succeed without an error? */
! 
!   if (CONSP (face_ref))
      {
!       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 (face_ref);
          Lisp_Object color = first;
  
          if (STRINGP (color_name))
***************
*** 3574,3596 ****
                to[LFACE_BACKGROUND_INDEX] = color_name;
            }
          else
!           add_to_log ("Invalid face color", color_name, Qnil);
        }
        else if (SYMBOLP (first)
               && *SDATA (SYMBOL_NAME (first)) == ':')
        {
          /* Assume this is the property list form.  */
!         while (CONSP (prop) && CONSP (XCDR (prop)))
            {
!             Lisp_Object keyword = XCAR (prop);
!             Lisp_Object value = XCAR (XCDR (prop));
  
              if (EQ (keyword, QCfamily))
                {
                  if (STRINGP (value))
                    to[LFACE_FAMILY_INDEX] = value;
                  else
!                   add_to_log ("Invalid face font family", value, Qnil);
                }
              else if (EQ (keyword, QCheight))
                {
--- 3689,3716 ----
                to[LFACE_BACKGROUND_INDEX] = color_name;
            }
          else
!           {
!             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 (face_ref) && CONSP (XCDR (face_ref)))
            {
!             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
!                   err = 1;
                }
              else if (EQ (keyword, QCheight))
                {
***************
*** 3598,3607 ****
                    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))
                {
--- 3718,3727 ----
                    merge_face_heights (value, to[LFACE_HEIGHT_INDEX],
                                        Qnil, Qnil);
  
!                 if (! NILP (new_height))
                    to[LFACE_HEIGHT_INDEX] = new_height;
+                 else
+                   err = 1;
                }
              else if (EQ (keyword, QCweight))
                {
***************
*** 3609,3615 ****
                      && face_numeric_weight (value) >= 0)
                    to[LFACE_WEIGHT_INDEX] = value;
                  else
!                   add_to_log ("Invalid face weight", value, Qnil);
                }
              else if (EQ (keyword, QCslant))
                {
--- 3729,3735 ----
                      && face_numeric_weight (value) >= 0)
                    to[LFACE_WEIGHT_INDEX] = value;
                  else
!                   err = 1;
                }
              else if (EQ (keyword, QCslant))
                {
***************
*** 3617,3623 ****
                      && face_numeric_slant (value) >= 0)
                    to[LFACE_SLANT_INDEX] = value;
                  else
!                   add_to_log ("Invalid face slant", value, Qnil);
                }
              else if (EQ (keyword, QCunderline))
                {
--- 3737,3743 ----
                      && face_numeric_slant (value) >= 0)
                    to[LFACE_SLANT_INDEX] = value;
                  else
!                   err = 1;
                }
              else if (EQ (keyword, QCunderline))
                {
***************
*** 3626,3632 ****
                      || STRINGP (value))
                    to[LFACE_UNDERLINE_INDEX] = value;
                  else
!                   add_to_log ("Invalid face underline", value, Qnil);
                }
              else if (EQ (keyword, QCoverline))
                {
--- 3746,3752 ----
                      || STRINGP (value))
                    to[LFACE_UNDERLINE_INDEX] = value;
                  else
!                   err = 1;
                }
              else if (EQ (keyword, QCoverline))
                {
***************
*** 3635,3641 ****
                      || STRINGP (value))
                    to[LFACE_OVERLINE_INDEX] = value;
                  else
!                   add_to_log ("Invalid face overline", value, Qnil);
                }
              else if (EQ (keyword, QCstrike_through))
                {
--- 3755,3761 ----
                      || STRINGP (value))
                    to[LFACE_OVERLINE_INDEX] = value;
                  else
!                   err = 1;
                }
              else if (EQ (keyword, QCstrike_through))
                {
***************
*** 3644,3650 ****
                      || STRINGP (value))
                    to[LFACE_STRIKE_THROUGH_INDEX] = value;
                  else
!                   add_to_log ("Invalid face strike-through", value, Qnil);
                }
              else if (EQ (keyword, QCbox))
                {
--- 3764,3770 ----
                      || STRINGP (value))
                    to[LFACE_STRIKE_THROUGH_INDEX] = value;
                  else
!                   err = 1;
                }
              else if (EQ (keyword, QCbox))
                {
***************
*** 3656,3662 ****
                      || NILP (value))
                    to[LFACE_BOX_INDEX] = value;
                  else
!                   add_to_log ("Invalid face box", value, Qnil);
                }
              else if (EQ (keyword, QCinverse_video)
                       || EQ (keyword, QCreverse_video))
--- 3776,3782 ----
                      || NILP (value))
                    to[LFACE_BOX_INDEX] = value;
                  else
!                   err = 1;
                }
              else if (EQ (keyword, QCinverse_video)
                       || EQ (keyword, QCreverse_video))
***************
*** 3664,3684 ****
                  if (EQ (value, Qt) || NILP (value))
                    to[LFACE_INVERSE_INDEX] = value;
                  else
!                   add_to_log ("Invalid face inverse-video", value, Qnil);
                }
              else if (EQ (keyword, QCforeground))
                {
                  if (STRINGP (value))
                    to[LFACE_FOREGROUND_INDEX] = value;
                  else
!                   add_to_log ("Invalid face foreground", value, Qnil);
                }
              else if (EQ (keyword, QCbackground))
                {
                  if (STRINGP (value))
                    to[LFACE_BACKGROUND_INDEX] = value;
                  else
!                   add_to_log ("Invalid face background", value, Qnil);
                }
              else if (EQ (keyword, QCstipple))
                {
--- 3784,3804 ----
                  if (EQ (value, Qt) || NILP (value))
                    to[LFACE_INVERSE_INDEX] = value;
                  else
!                   err = 1;
                }
              else if (EQ (keyword, QCforeground))
                {
                  if (STRINGP (value))
                    to[LFACE_FOREGROUND_INDEX] = value;
                  else
!                   err = 1;
                }
              else if (EQ (keyword, QCbackground))
                {
                  if (STRINGP (value))
                    to[LFACE_BACKGROUND_INDEX] = value;
                  else
!                   err = 1;
                }
              else if (EQ (keyword, QCstipple))
                {
***************
*** 3687,3693 ****
                  if (!NILP (pixmap_p))
                    to[LFACE_STIPPLE_INDEX] = value;
                  else
!                   add_to_log ("Invalid face stipple", value, Qnil);
  #endif
                }
              else if (EQ (keyword, QCwidth))
--- 3807,3813 ----
                  if (!NILP (pixmap_p))
                    to[LFACE_STIPPLE_INDEX] = value;
                  else
!                   err = 1;
  #endif
                }
              else if (EQ (keyword, QCwidth))
***************
*** 3696,3747 ****
                      && face_numeric_swidth (value) >= 0)
                    to[LFACE_SWIDTH_INDEX] = value;
                  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);
  
!             prop = XCDR (XCDR (prop));
            }
        }
        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);
        }
      }
    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);
      }
  }
  
  
--- 3816,3866 ----
                      && face_numeric_swidth (value) >= 0)
                    to[LFACE_SWIDTH_INDEX] = value;
                  else
!                   err = 1;
                }
              else if (EQ (keyword, QCinherit))
                {
!                 /* 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
!               err = 1;
  
!             if (err)
!               {
!                 add_to_log ("Invalid face attribute %S %S", keyword, value);
!                 ok = 0;
!               }
! 
!             face_ref = XCDR (XCDR (face_ref));
            }
        }
        else
        {
!         /* 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
      {
!       /* 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;
  }
  
  
***************
*** 5258,5264 ****
  
    for (i = 0; i < LFACE_VECTOR_SIZE; i++)
      attrs[i] = Qunspecified;
!   merge_face_vector_with_property (f, attrs, attributes);
  
    /* This function only works on ttys.  */
    if (!FRAME_TERMCAP_P (f) && !FRAME_MSDOS_P (f))
--- 5377,5383 ----
  
    for (i = 0; i < LFACE_VECTOR_SIZE; i++)
      attrs[i] = Qunspecified;
!   merge_face_ref (f, attributes, attrs, 1, 0);
  
    /* This function only works on ttys.  */
    if (!FRAME_TERMCAP_P (f) && !FRAME_MSDOS_P (f))
***************
*** 5734,5744 ****
     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)
       struct frame *f;
       Lisp_Object symbol;
       int c;
  {
    Lisp_Object attrs[LFACE_VECTOR_SIZE];
    Lisp_Object symbol_attrs[LFACE_VECTOR_SIZE];
--- 5853,5864 ----
     face couldn't be determined, which might happen if the default face
     isn't realized and cannot be realized.  */
  
! static int
! lookup_named_face_1 (f, symbol, c, signal_p)
       struct frame *f;
       Lisp_Object symbol;
       int c;
+      int signal_p;
  {
    Lisp_Object attrs[LFACE_VECTOR_SIZE];
    Lisp_Object symbol_attrs[LFACE_VECTOR_SIZE];
***************
*** 5751,5762 ****
        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 (f, symbol_attrs, attrs, Qnil);
    return lookup_face (f, attrs, c, NULL);
  }
  
  
  /* Return the ID of the realized ASCII face of Lisp face with ID
     LFACE_ID on frame F.  Value is -1 if LFACE_ID isn't valid.  */
--- 5871,5946 ----
        default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
      }
  
!   if (! get_lface_attributes (f, symbol, symbol_attrs, signal_p, 0))
!     return -1;
! 
    bcopy (default_face->lface, attrs, sizeof attrs);
!   merge_face_vectors (f, symbol_attrs, attrs, 0);
! 
    return lookup_face (f, attrs, c, NULL);
  }
  
+ /* 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.  */
+ 
+ int
+ lookup_named_face (f, symbol, c)
+      struct frame *f;
+      Lisp_Object symbol;
+      int c;
+ {
+   return lookup_named_face_1 (f, symbol, c, 0);
+ }
+ 
+ 
+ /* Return the display face-id of the basic face who's canonical face-id
+    is FACE_ID.  The return value will usually simply be FACE_ID, unless that
+    basic face has bee remapped via Vface_remapping_alist.  This function is
+    conservative: if something goes wrong, it will simply return FACE_ID
+    rather than signal an error.   */
+ 
+ int
+ lookup_basic_face (f, face_id)
+      struct frame *f;
+      int face_id;
+ {
+   Lisp_Object name, mapping;
+   int remapped_face_id;
+ 
+   if (NILP (Vface_remapping_alist))
+     return face_id;           /* Nothing to do.  */
+ 
+   switch (face_id)
+     {
+     case DEFAULT_FACE_ID:             name = Qdefault;                break;
+     case MODE_LINE_FACE_ID:           name = Qmode_line;              break;
+     case MODE_LINE_INACTIVE_FACE_ID:  name = Qmode_line_inactive;     break;
+     case HEADER_LINE_FACE_ID:         name = Qheader_line;            break;
+     case TOOL_BAR_FACE_ID:            name = Qtool_bar;               break;
+     case FRINGE_FACE_ID:              name = Qfringe;                 break;
+     case SCROLL_BAR_FACE_ID:          name = Qscroll_bar;             break;
+     case BORDER_FACE_ID:              name = Qborder;                 break;
+     case CURSOR_FACE_ID:              name = Qcursor;                 break;
+     case MOUSE_FACE_ID:                       name = Qmouse;                  
break;
+     case MENU_FACE_ID:                        name = Qmenu;                   
break;
+ 
+     default:
+       return face_id;         /* Give up.  */
+     }
+ 
+   mapping = assq_no_quit (name, Vface_remapping_alist);
+   if (NILP (mapping))
+     return face_id;           /* Give up.  */
+ 
+   remapped_face_id = lookup_named_face_1 (f, name, 0, 0);
+   if (remapped_face_id < 0)
+     return face_id;           /* Give up. */
+ 
+   return remapped_face_id;
+ }
+ 
  
  /* Return the ID of the realized ASCII face of Lisp face with ID
     LFACE_ID on frame F.  Value is -1 if LFACE_ID isn't valid.  */
***************
*** 5890,5898 ****
    if (!default_face)
      abort ();
  
!   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);
  }
  
--- 6074,6082 ----
    if (!default_face)
      abort ();
  
!   get_lface_attributes (f, symbol, symbol_attrs, 1, 0);
    bcopy (default_face->lface, attrs, sizeof attrs);
!   merge_face_vectors (f, symbol_attrs, attrs, 0);
    return lookup_face (f, attrs, c, default_face);
  }
  
***************
*** 5905,5913 ****
    Lisp_Object lface;
    lface = Fmake_vector (make_number (LFACE_VECTOR_SIZE),
                        Qunspecified);
!   merge_face_vector_with_property (XFRAME (selected_frame),
!                                  XVECTOR (lface)->contents,
!                                  plist);
    return lface;
  }
  
--- 6089,6096 ----
    Lisp_Object lface;
    lface = Fmake_vector (make_number (LFACE_VECTOR_SIZE),
                        Qunspecified);
!   merge_face_ref (XFRAME (selected_frame), plist, XVECTOR (lface)->contents,
!                 1, 0);
    return lface;
  }
  
***************
*** 6753,6759 ****
    struct face *new_face;
  
    /* The default face must exist and be fully specified.  */
!   get_lface_attributes (f, Qdefault, attrs, 1);
    check_lface_attrs (attrs);
    xassert (lface_fully_specified_p (attrs));
  
--- 6936,6942 ----
    struct face *new_face;
  
    /* The default face must exist and be fully specified.  */
!   get_lface_attributes_no_remap (f, Qdefault, attrs, 1);
    check_lface_attrs (attrs);
    xassert (lface_fully_specified_p (attrs));
  
***************
*** 6766,6773 ****
      }
  
    /* Merge SYMBOL's face with the default face.  */
!   get_lface_attributes (f, symbol, symbol_attrs, 1);
!   merge_face_vectors (f, symbol_attrs, attrs, Qnil);
  
    /* Realize the face.  */
    new_face = realize_face (c, attrs, 0, NULL, id);
--- 6949,6956 ----
      }
  
    /* Merge SYMBOL's face with the default face.  */
!   get_lface_attributes_no_remap (f, symbol, symbol_attrs, 1);
!   merge_face_vectors (f, symbol_attrs, attrs, 0);
  
    /* Realize the face.  */
    new_face = realize_face (c, attrs, 0, NULL, id);
***************
*** 7232,7238 ****
        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);
      }
  
--- 7415,7421 ----
        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_ref (f, prop, attrs, 1, 0);
        face_id = lookup_face (f, attrs, ch, NULL);
      }
  
***************
*** 7305,7324 ****
  
    *endptr = endpos;
  
!   default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
  
    /* Optimize common cases where we can use the default face.  */
    if (noverlays == 0
        && NILP (prop)
        && !(pos >= region_beg && pos < region_end))
!     return DEFAULT_FACE_ID;
  
    /* Begin with attributes from the default face.  */
    bcopy (default_face->lface, attrs, sizeof attrs);
  
    /* Merge in attributes specified via text properties.  */
    if (!NILP (prop))
!     merge_face_vector_with_property (f, attrs, prop);
  
    /* Now merge the overlay data.  */
    noverlays = sort_overlays (overlay_vec, noverlays, w);
--- 7488,7512 ----
  
    *endptr = endpos;
  
! 
!   /* Perhaps remap BASE_FACE_ID to a user-specified alternative.  */
!   if (NILP (Vface_remapping_alist))
!     default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID);
!   else
!     default_face = FACE_FROM_ID (f, lookup_basic_face (f, DEFAULT_FACE_ID));
  
    /* Optimize common cases where we can use the default face.  */
    if (noverlays == 0
        && NILP (prop)
        && !(pos >= region_beg && pos < region_end))
!     return default_face->id;
  
    /* Begin with attributes from the default face.  */
    bcopy (default_face->lface, attrs, sizeof attrs);
  
    /* Merge in attributes specified via text properties.  */
    if (!NILP (prop))
!     merge_face_ref (f, prop, attrs, 1, 0);
  
    /* Now merge the overlay data.  */
    noverlays = sort_overlays (overlay_vec, noverlays, w);
***************
*** 7329,7335 ****
  
        prop = Foverlay_get (overlay_vec[i], propname);
        if (!NILP (prop))
!       merge_face_vector_with_property (f, attrs, prop);
  
        oend = OVERLAY_END (overlay_vec[i]);
        oendpos = OVERLAY_POSITION (oend);
--- 7517,7523 ----
  
        prop = Foverlay_get (overlay_vec[i], propname);
        if (!NILP (prop))
!       merge_face_ref (f, prop, attrs, 1, 0);
  
        oend = OVERLAY_END (overlay_vec[i]);
        oendpos = OVERLAY_POSITION (oend);
***************
*** 7340,7347 ****
    /* 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);
  
        if (region_end < endpos)
        endpos = region_end;
--- 7528,7534 ----
    /* If in the region, merge in the region face.  */
    if (pos >= region_beg && pos < region_end)
      {
!       merge_named_face (f, Qregion, attrs, 0);
  
        if (region_end < endpos)
        endpos = region_end;
***************
*** 7437,7452 ****
  
    /* Merge in attributes specified via text properties.  */
    if (!NILP (prop))
!     merge_face_vector_with_property (f, attrs, prop);
  
    /* 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);
!     }
  
    /* Look up a realized face with the given face attributes,
       or realize a new one for ASCII characters.  */
--- 7624,7636 ----
  
    /* Merge in attributes specified via text properties.  */
    if (!NILP (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)
!     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.  */
***************
*** 7767,7772 ****
--- 7951,7993 ----
  ignore.  */);
    Vface_ignored_fonts = Qnil;
  
+   DEFVAR_LISP ("face-remapping-alist", &Vface_remapping_alist,
+              doc: /* Alist of face remappings.
+ Each element is of the form:
+ 
+    (OLD-FACE REPLACEMENT...),
+ 
+ which causes uses of the face OLD-FACE to use REPLACEMENT... instead.
+ REPLACEMENT... is interpreted the same way the value of a `face' text
+ property is; it may be (1) A face name, (2) A list of face names,
+ (3) A property-list of face attribute/value pairs, or (4) A list of face
+ names intermixed with lists containing face attribute/value pairs.
+ 
+ Multiple entries in REPLACEMENT... are merged together to form the final
+ result, with faces or attributes earlier in the list taking precedence
+ over those that are later.
+ 
+ Face-name remapping cycles are suppressed, causing the underlying face
+ to be used instead, so a remapping of the form:
+ 
+    (OLD-FACE EXTRA-FACE... OLD-FACE)
+ 
+ or:
+ 
+    (OLD-FACE (FACE-ATTR VAL ...) OLD-FACE)
+ 
+ will cause EXTRA-FACE... or (FACE-ATTR VAL ...) to be _merged_ with the
+ existing definition of OLD-FACE.  Note that for the default face, this
+ isn't necessary, as every face inherits from the default face.
+ 
+ Making this variable buffer-local is a good way to allow buffer-specific
+ face definitions.  For instance, the mode my-mode could define a face
+ `my-mode-default', and then in the mode setup function, do:
+ 
+    (set (make-local-variable 'face-remapping-alist)
+         '((default my-mode-default)))).  */);
+   Vface_remapping_alist = Qnil;
+ 
    DEFVAR_LISP ("face-font-rescale-alist", &Vface_font_rescale_alist,
               doc: /* Alist of fonts vs the rescaling factors.
  Each element is a cons (FONT-NAME-PATTERN . RESCALE-RATIO), where





-Miles
-- 
Would you like fries with that?

reply via email to

[Prev in Thread] Current Thread [Next in Thread]