unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* +face-remapping-20040525-2-c.patch
@ 2004-05-25 14:39 Miles Bader
  2004-05-25 23:22 ` +face-remapping-20040525-2-c.patch Miles Bader
  2004-05-27 12:46 ` +face-remapping-20040525-2-c.patch Richard Stallman
  0 siblings, 2 replies; 3+ messages in thread
From: Miles Bader @ 2004-05-25 14:39 UTC (permalink / raw)


[-- Attachment #1: Type: text/plain, Size: 412 bytes --]

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:



[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: +face-remapping-20040525-2-c.patch --]
[-- Type: text/x-patch, Size: 49399 bytes --]

2004-05-25  Miles Bader  <miles@gnu.org>

	* 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} @var{remapping@dots{}})}; when the face @var{face} is
+ used at display time, then @var{remapping@dots{}} is used instead.
+ @var{remapping@dots{}} 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 */
  
  
+ \f
+ /* 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;
+ }
+ 
+ \f
+ 
+ 
  /* Resolve face name FACE_NAME.  If FACE_NAME is a string, intern it
     to make it a symvol.  If FACE_NAME is an alias for another face,
     return that face's name.  */
***************
*** 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




[-- Attachment #3: Type: text/plain, Size: 46 bytes --]




-Miles
-- 
Would you like fries with that?

[-- Attachment #4: Type: text/plain, Size: 141 bytes --]

_______________________________________________
Emacs-devel mailing list
Emacs-devel@gnu.org
http://mail.gnu.org/mailman/listinfo/emacs-devel

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: +face-remapping-20040525-2-c.patch
  2004-05-25 14:39 +face-remapping-20040525-2-c.patch Miles Bader
@ 2004-05-25 23:22 ` Miles Bader
  2004-05-27 12:46 ` +face-remapping-20040525-2-c.patch Richard Stallman
  1 sibling, 0 replies; 3+ messages in thread
From: Miles Bader @ 2004-05-25 23:22 UTC (permalink / raw)


Whoops, in that patch I forgot to update the comment for the C variable
Vface_remapping_alist (tho the docstring is correct).

Rather than reposting the patch, here's just the updated comment:


/* Alist of face remappings.  Each element is of the form:
   (OLD-FACE REPLACEMENT...) which causes display 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; recursive references use
   the underlying face instead of the remapped face.  */

Lisp_Object Vface_remapping_alist;


-Miles
-- 
Love is a snowmobile racing across the tundra.  Suddenly it flips over,
pinning you underneath.  At night the ice weasels come.  --Nietzsche

^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: +face-remapping-20040525-2-c.patch
  2004-05-25 14:39 +face-remapping-20040525-2-c.patch Miles Bader
  2004-05-25 23:22 ` +face-remapping-20040525-2-c.patch Miles Bader
@ 2004-05-27 12:46 ` Richard Stallman
  1 sibling, 0 replies; 3+ messages in thread
From: Richard Stallman @ 2004-05-27 12:46 UTC (permalink / raw)
  Cc: emacs-devel

    +   This variable may be be used to locally change the meaning of face-names,

This variable is used for buffer-local changes in the appearance of
a face.

    + for instance making the @code{default} face a variable-pitch face in a
    + particular buffer.  It should be

Its value should be

				       an alist, whose elements have the form
    + @code{(@var{face} @var{remapping@dots{}})};

The @dots should be outside of @var.  Only the variable name itself
should be inside @var.

    +   Alternate face definitions provided by @code{face-remapping-alist}
    + @emph{replace} the remapped faces, they aren't merged with it.

This is not quite grammatical, and isn't entirely clear.

    +   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.

I think I understand what that means, but it isn't easy to translate
into concrete terms.  Could you write it more concretely?  And give an
example?

    +   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).

Could you give an example?

^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2004-05-27 12:46 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-05-25 14:39 +face-remapping-20040525-2-c.patch Miles Bader
2004-05-25 23:22 ` +face-remapping-20040525-2-c.patch Miles Bader
2004-05-27 12:46 ` +face-remapping-20040525-2-c.patch Richard Stallman

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).