diff options
| author | Miles Bader | 2008-06-01 05:04:24 +0000 |
|---|---|---|
| committer | Miles Bader | 2008-06-01 05:04:24 +0000 |
| commit | f2cec7a9907796d97bbe4f99ce00d1866b773dfb (patch) | |
| tree | 24b0e99f39a2da47cc60d4f8c3848c01f7f0bf99 /src | |
| parent | 70583cb56977d91d94bff77cb2fb93922c44876c (diff) | |
| download | emacs-f2cec7a9907796d97bbe4f99ce00d1866b773dfb.tar.gz emacs-f2cec7a9907796d97bbe4f99ce00d1866b773dfb.zip | |
Implement face-remapping-alist feature
Revision: emacs@sv.gnu.org/emacs--devo--0--patch-1195
Diffstat (limited to 'src')
| -rw-r--r-- | src/ChangeLog | 34 | ||||
| -rw-r--r-- | src/dispextern.h | 3 | ||||
| -rw-r--r-- | src/fontset.c | 2 | ||||
| -rw-r--r-- | src/xdisp.c | 16 | ||||
| -rw-r--r-- | src/xfaces.c | 253 |
5 files changed, 268 insertions, 40 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index c8cbaf174dd..526d0c07bb0 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,37 @@ | |||
| 1 | 2008-06-01 Miles Bader <miles@gnu.org> | ||
| 2 | |||
| 3 | * xfaces.c (Vface_remapping_alist): New variable. | ||
| 4 | (syms_of_xfaces): Initialize it. | ||
| 5 | (enum named_merge_point_kind): New type. | ||
| 6 | (struct named_merge_point): Add `named_merge_point_kind' field. | ||
| 7 | (push_named_merge_point): Make cycle detection respect different | ||
| 8 | named-merge-point kinds. | ||
| 9 | (lface_from_face_name_no_resolve): Renamed from `lface_from_face_name'. | ||
| 10 | Remove face-name alias resolution. | ||
| 11 | (lface_from_face_name): New definition using | ||
| 12 | `lface_from_face_name_no_resolve'. | ||
| 13 | (get_lface_attributes_no_remap): Renamed from `get_lface_attributes'. | ||
| 14 | Call lface_from_face_name_no_resolve instead of lface_from_face_name. | ||
| 15 | (get_lface_attributes): New definition that layers face-remapping on | ||
| 16 | top of get_lface_attributes_no_remap. New arg `named_merge_points'. | ||
| 17 | (lookup_basic_face): New function. | ||
| 18 | (lookup_derived_face): Pass new last arg to `get_lface_attributes'. | ||
| 19 | (realize_named_face): Call `get_lface_attributes_no_remap' instead of | ||
| 20 | `get_lface_attributes'. | ||
| 21 | (face_at_buffer_position): Use `lookup_basic_face' to lookup | ||
| 22 | DEFAULT_FACE_ID if necessary. When optimizing the default-face case, | ||
| 23 | return default_face's face-id instead of the constant DEFAULT_FACE_ID. | ||
| 24 | |||
| 25 | * xdisp.c (init_iterator): Pass base_face_id through | ||
| 26 | `lookup_basic_face' when we actually use it as a face-id. | ||
| 27 | (handle_single_display_prop): Use `lookup_basic_face' to lookup | ||
| 28 | DEFAULT_FACE_ID. | ||
| 29 | |||
| 30 | * fontset.c (Finternal_char_font): Use `lookup_basic_face' to | ||
| 31 | lookup the initial face-id. | ||
| 32 | |||
| 33 | * dispextern.h (lookup_basic_face, Vface_remapping_alist): New decls. | ||
| 34 | |||
| 1 | 2008-06-01 Juanma Barranquero <lekktu@gmail.com> | 35 | 2008-06-01 Juanma Barranquero <lekktu@gmail.com> |
| 2 | 36 | ||
| 3 | * textprop.c (syms_of_textprop) <text-property-default-nonsticky>: | 37 | * textprop.c (syms_of_textprop) <text-property-default-nonsticky>: |
diff --git a/src/dispextern.h b/src/dispextern.h index 2101d70478f..4a4c731748b 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -2852,6 +2852,7 @@ int xstrcasecmp P_ ((const unsigned char *, const unsigned char *)); | |||
| 2852 | int lookup_face P_ ((struct frame *, Lisp_Object *)); | 2852 | int lookup_face P_ ((struct frame *, Lisp_Object *)); |
| 2853 | int lookup_non_ascii_face P_ ((struct frame *, int, struct face *)); | 2853 | int lookup_non_ascii_face P_ ((struct frame *, int, struct face *)); |
| 2854 | int lookup_named_face P_ ((struct frame *, Lisp_Object, int)); | 2854 | int lookup_named_face P_ ((struct frame *, Lisp_Object, int)); |
| 2855 | int lookup_basic_face P_ ((struct frame *, int)); | ||
| 2855 | int smaller_face P_ ((struct frame *, int, int)); | 2856 | int smaller_face P_ ((struct frame *, int, int)); |
| 2856 | int face_with_height P_ ((struct frame *, int, int)); | 2857 | int face_with_height P_ ((struct frame *, int, int)); |
| 2857 | int lookup_derived_face P_ ((struct frame *, Lisp_Object, int, int)); | 2858 | int lookup_derived_face P_ ((struct frame *, Lisp_Object, int, int)); |
| @@ -2880,6 +2881,8 @@ extern char unspecified_fg[], unspecified_bg[]; | |||
| 2880 | extern Lisp_Object split_font_name_into_vector P_ ((Lisp_Object)); | 2881 | extern Lisp_Object split_font_name_into_vector P_ ((Lisp_Object)); |
| 2881 | extern Lisp_Object build_font_name_from_vector P_ ((Lisp_Object)); | 2882 | extern Lisp_Object build_font_name_from_vector P_ ((Lisp_Object)); |
| 2882 | 2883 | ||
| 2884 | extern Lisp_Object Vface_remapping_alist; | ||
| 2885 | |||
| 2883 | /* Defined in xfns.c */ | 2886 | /* Defined in xfns.c */ |
| 2884 | 2887 | ||
| 2885 | #ifdef HAVE_X_WINDOWS | 2888 | #ifdef HAVE_X_WINDOWS |
diff --git a/src/fontset.c b/src/fontset.c index d384dd41345..fbc6b866f31 100644 --- a/src/fontset.c +++ b/src/fontset.c | |||
| @@ -1677,7 +1677,7 @@ DEFUN ("internal-char-font", Finternal_char_font, Sinternal_char_font, 1, 2, 0, | |||
| 1677 | CHECK_CHARACTER (ch); | 1677 | CHECK_CHARACTER (ch); |
| 1678 | c = XINT (ch); | 1678 | c = XINT (ch); |
| 1679 | f = XFRAME (selected_frame); | 1679 | f = XFRAME (selected_frame); |
| 1680 | face_id = DEFAULT_FACE_ID; | 1680 | face_id = lookup_basic_face (f, DEFAULT_FACE_ID); |
| 1681 | pos = -1; | 1681 | pos = -1; |
| 1682 | cs_id = -1; | 1682 | cs_id = -1; |
| 1683 | } | 1683 | } |
diff --git a/src/xdisp.c b/src/xdisp.c index 9b934c8803d..8d87123934b 100644 --- a/src/xdisp.c +++ b/src/xdisp.c | |||
| @@ -2491,6 +2491,7 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) | |||
| 2491 | enum face_id base_face_id; | 2491 | enum face_id base_face_id; |
| 2492 | { | 2492 | { |
| 2493 | int highlight_region_p; | 2493 | int highlight_region_p; |
| 2494 | enum face_id remapped_base_face_id = base_face_id; | ||
| 2494 | 2495 | ||
| 2495 | /* Some precondition checks. */ | 2496 | /* Some precondition checks. */ |
| 2496 | xassert (w != NULL && it != NULL); | 2497 | xassert (w != NULL && it != NULL); |
| @@ -2507,6 +2508,10 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) | |||
| 2507 | free_all_realized_faces (Qnil); | 2508 | free_all_realized_faces (Qnil); |
| 2508 | } | 2509 | } |
| 2509 | 2510 | ||
| 2511 | /* Perhaps remap BASE_FACE_ID to a user-specified alternative. */ | ||
| 2512 | if (! NILP (Vface_remapping_alist)) | ||
| 2513 | remapped_base_face_id = lookup_basic_face (XFRAME (w->frame), base_face_id); | ||
| 2514 | |||
| 2510 | /* Use one of the mode line rows of W's desired matrix if | 2515 | /* Use one of the mode line rows of W's desired matrix if |
| 2511 | appropriate. */ | 2516 | appropriate. */ |
| 2512 | if (row == NULL) | 2517 | if (row == NULL) |
| @@ -2522,7 +2527,7 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) | |||
| 2522 | bzero (it, sizeof *it); | 2527 | bzero (it, sizeof *it); |
| 2523 | it->current.overlay_string_index = -1; | 2528 | it->current.overlay_string_index = -1; |
| 2524 | it->current.dpvec_index = -1; | 2529 | it->current.dpvec_index = -1; |
| 2525 | it->base_face_id = base_face_id; | 2530 | it->base_face_id = remapped_base_face_id; |
| 2526 | it->string = Qnil; | 2531 | it->string = Qnil; |
| 2527 | IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1; | 2532 | IT_STRING_CHARPOS (*it) = IT_STRING_BYTEPOS (*it) = -1; |
| 2528 | 2533 | ||
| @@ -2707,11 +2712,11 @@ init_iterator (it, w, charpos, bytepos, row, base_face_id) | |||
| 2707 | { | 2712 | { |
| 2708 | struct face *face; | 2713 | struct face *face; |
| 2709 | 2714 | ||
| 2710 | it->face_id = base_face_id; | 2715 | it->face_id = remapped_base_face_id; |
| 2711 | 2716 | ||
| 2712 | /* If we have a boxed mode line, make the first character appear | 2717 | /* If we have a boxed mode line, make the first character appear |
| 2713 | with a left box line. */ | 2718 | with a left box line. */ |
| 2714 | face = FACE_FROM_ID (it->f, base_face_id); | 2719 | face = FACE_FROM_ID (it->f, remapped_base_face_id); |
| 2715 | if (face->box != FACE_NO_BOX) | 2720 | if (face->box != FACE_NO_BOX) |
| 2716 | it->start_of_box_run_p = 1; | 2721 | it->start_of_box_run_p = 1; |
| 2717 | } | 2722 | } |
| @@ -4077,7 +4082,8 @@ handle_single_display_spec (it, spec, object, overlay, position, | |||
| 4077 | /* Value is a multiple of the canonical char height. */ | 4082 | /* Value is a multiple of the canonical char height. */ |
| 4078 | struct face *face; | 4083 | struct face *face; |
| 4079 | 4084 | ||
| 4080 | face = FACE_FROM_ID (it->f, DEFAULT_FACE_ID); | 4085 | face = FACE_FROM_ID (it->f, |
| 4086 | lookup_basic_face (it->f, DEFAULT_FACE_ID)); | ||
| 4081 | new_height = (XFLOATINT (it->font_height) | 4087 | new_height = (XFLOATINT (it->font_height) |
| 4082 | * XINT (face->lface[LFACE_HEIGHT_INDEX])); | 4088 | * XINT (face->lface[LFACE_HEIGHT_INDEX])); |
| 4083 | } | 4089 | } |
| @@ -4187,7 +4193,7 @@ handle_single_display_spec (it, spec, object, overlay, position, | |||
| 4187 | || EQ (XCAR (spec), Qright_fringe)) | 4193 | || EQ (XCAR (spec), Qright_fringe)) |
| 4188 | && CONSP (XCDR (spec))) | 4194 | && CONSP (XCDR (spec))) |
| 4189 | { | 4195 | { |
| 4190 | int face_id = DEFAULT_FACE_ID; | 4196 | int face_id = lookup_basic_face (it->f, DEFAULT_FACE_ID); |
| 4191 | int fringe_bitmap; | 4197 | int fringe_bitmap; |
| 4192 | 4198 | ||
| 4193 | if (!FRAME_WINDOW_P (it->f)) | 4199 | if (!FRAME_WINDOW_P (it->f)) |
diff --git a/src/xfaces.c b/src/xfaces.c index b5704ab6174..074b71b13c1 100644 --- a/src/xfaces.c +++ b/src/xfaces.c | |||
| @@ -422,6 +422,23 @@ Lisp_Object Qbitmap_spec_p; | |||
| 422 | 422 | ||
| 423 | Lisp_Object Vface_new_frame_defaults; | 423 | Lisp_Object Vface_new_frame_defaults; |
| 424 | 424 | ||
| 425 | /* Alist of face remappings. Each element is of the form: | ||
| 426 | (FACE REPLACEMENT...) which causes display of the face FACE to use | ||
| 427 | REPLACEMENT... instead. REPLACEMENT... is interpreted the same way | ||
| 428 | the value of a `face' text property is: it may be (1) A face name, | ||
| 429 | (2) A list of face names, (3) A property-list of face attribute/value | ||
| 430 | pairs, or (4) A list of face names intermixed with lists containing | ||
| 431 | face attribute/value pairs. | ||
| 432 | |||
| 433 | Multiple entries in REPLACEMENT... are merged together to form the final | ||
| 434 | result, with faces or attributes earlier in the list taking precedence | ||
| 435 | over those that are later. | ||
| 436 | |||
| 437 | Face-name remapping cycles are suppressed; recursive references use | ||
| 438 | the underlying face instead of the remapped face. */ | ||
| 439 | |||
| 440 | Lisp_Object Vface_remapping_alist; | ||
| 441 | |||
| 425 | /* The next ID to assign to Lisp faces. */ | 442 | /* The next ID to assign to Lisp faces. */ |
| 426 | 443 | ||
| 427 | static int next_lface_id; | 444 | static int next_lface_id; |
| @@ -493,7 +510,8 @@ static void map_tty_color P_ ((struct frame *, struct face *, | |||
| 493 | static Lisp_Object resolve_face_name P_ ((Lisp_Object, int)); | 510 | static Lisp_Object resolve_face_name P_ ((Lisp_Object, int)); |
| 494 | static int may_use_scalable_font_p P_ ((const char *)); | 511 | static int may_use_scalable_font_p P_ ((const char *)); |
| 495 | static void set_font_frame_param P_ ((Lisp_Object, Lisp_Object)); | 512 | static void set_font_frame_param P_ ((Lisp_Object, Lisp_Object)); |
| 496 | static int get_lface_attributes P_ ((struct frame *, Lisp_Object, Lisp_Object *, int)); | 513 | static int get_lface_attributes P_ ((struct frame *, Lisp_Object, Lisp_Object *, |
| 514 | int, struct named_merge_point *)); | ||
| 497 | static int load_pixmap P_ ((struct frame *, Lisp_Object, unsigned *, unsigned *)); | 515 | static int load_pixmap P_ ((struct frame *, Lisp_Object, unsigned *, unsigned *)); |
| 498 | static unsigned char *xstrlwr P_ ((unsigned char *)); | 516 | static unsigned char *xstrlwr P_ ((unsigned char *)); |
| 499 | static struct frame *frame_or_selected_frame P_ ((Lisp_Object, int)); | 517 | static struct frame *frame_or_selected_frame P_ ((Lisp_Object, int)); |
| @@ -2063,6 +2081,12 @@ check_lface (lface) | |||
| 2063 | 2081 | ||
| 2064 | /* Face-merge cycle checking. */ | 2082 | /* Face-merge cycle checking. */ |
| 2065 | 2083 | ||
| 2084 | enum named_merge_point_kind | ||
| 2085 | { | ||
| 2086 | NAMED_MERGE_POINT_NORMAL, | ||
| 2087 | NAMED_MERGE_POINT_REMAP | ||
| 2088 | }; | ||
| 2089 | |||
| 2066 | /* A `named merge point' is simply a point during face-merging where we | 2090 | /* A `named merge point' is simply a point during face-merging where we |
| 2067 | look up a face by name. We keep a stack of which named lookups we're | 2091 | look up a face by name. We keep a stack of which named lookups we're |
| 2068 | currently processing so that we can easily detect cycles, using a | 2092 | currently processing so that we can easily detect cycles, using a |
| @@ -2072,27 +2096,40 @@ check_lface (lface) | |||
| 2072 | struct named_merge_point | 2096 | struct named_merge_point |
| 2073 | { | 2097 | { |
| 2074 | Lisp_Object face_name; | 2098 | Lisp_Object face_name; |
| 2099 | enum named_merge_point_kind named_merge_point_kind; | ||
| 2075 | struct named_merge_point *prev; | 2100 | struct named_merge_point *prev; |
| 2076 | }; | 2101 | }; |
| 2077 | 2102 | ||
| 2078 | 2103 | ||
| 2079 | /* If a face merging cycle is detected for FACE_NAME, return 0, | 2104 | /* If a face merging cycle is detected for FACE_NAME, return 0, |
| 2080 | otherwise add NEW_NAMED_MERGE_POINT, which is initialized using | 2105 | otherwise add NEW_NAMED_MERGE_POINT, which is initialized using |
| 2081 | FACE_NAME, as the head of the linked list pointed to by | 2106 | FACE_NAME and NAMED_MERGE_POINT_KIND, as the head of the linked list |
| 2082 | NAMED_MERGE_POINTS, and return 1. */ | 2107 | pointed to by NAMED_MERGE_POINTS, and return 1. */ |
| 2083 | 2108 | ||
| 2084 | static INLINE int | 2109 | static INLINE int |
| 2085 | push_named_merge_point (struct named_merge_point *new_named_merge_point, | 2110 | push_named_merge_point (struct named_merge_point *new_named_merge_point, |
| 2086 | Lisp_Object face_name, | 2111 | Lisp_Object face_name, |
| 2112 | enum named_merge_point_kind named_merge_point_kind, | ||
| 2087 | struct named_merge_point **named_merge_points) | 2113 | struct named_merge_point **named_merge_points) |
| 2088 | { | 2114 | { |
| 2089 | struct named_merge_point *prev; | 2115 | struct named_merge_point *prev; |
| 2090 | 2116 | ||
| 2091 | for (prev = *named_merge_points; prev; prev = prev->prev) | 2117 | for (prev = *named_merge_points; prev; prev = prev->prev) |
| 2092 | if (EQ (face_name, prev->face_name)) | 2118 | if (EQ (face_name, prev->face_name)) |
| 2093 | return 0; | 2119 | { |
| 2120 | if (prev->named_merge_point_kind == named_merge_point_kind) | ||
| 2121 | /* A cycle, so fail. */ | ||
| 2122 | return 0; | ||
| 2123 | else if (prev->named_merge_point_kind == NAMED_MERGE_POINT_REMAP) | ||
| 2124 | /* A remap `hides ' any previous normal merge points | ||
| 2125 | (because the remap means that it's actually different face), | ||
| 2126 | so as we know the current merge point must be normal, we | ||
| 2127 | can just assume it's OK. */ | ||
| 2128 | break; | ||
| 2129 | } | ||
| 2094 | 2130 | ||
| 2095 | new_named_merge_point->face_name = face_name; | 2131 | new_named_merge_point->face_name = face_name; |
| 2132 | new_named_merge_point->named_merge_point_kind = named_merge_point_kind; | ||
| 2096 | new_named_merge_point->prev = *named_merge_points; | 2133 | new_named_merge_point->prev = *named_merge_points; |
| 2097 | 2134 | ||
| 2098 | *named_merge_points = new_named_merge_point; | 2135 | *named_merge_points = new_named_merge_point; |
| @@ -2170,22 +2207,17 @@ resolve_face_name (face_name, signal_p) | |||
| 2170 | /* Return the face definition of FACE_NAME on frame F. F null means | 2207 | /* Return the face definition of FACE_NAME on frame F. F null means |
| 2171 | return the definition for new frames. FACE_NAME may be a string or | 2208 | return the definition for new frames. FACE_NAME may be a string or |
| 2172 | a symbol (apparently Emacs 20.2 allowed strings as face names in | 2209 | a symbol (apparently Emacs 20.2 allowed strings as face names in |
| 2173 | face text properties; Ediff uses that). If FACE_NAME is an alias | 2210 | face text properties; Ediff uses that). If SIGNAL_P is non-zero, |
| 2174 | for another face, return that face's definition. If SIGNAL_P is | 2211 | signal an error if FACE_NAME is not a valid face name. If SIGNAL_P |
| 2175 | non-zero, signal an error if FACE_NAME is not a valid face name. | 2212 | is zero, value is nil if FACE_NAME is not a valid face name. */ |
| 2176 | If SIGNAL_P is zero, value is nil if FACE_NAME is not a valid face | ||
| 2177 | name. */ | ||
| 2178 | |||
| 2179 | static INLINE Lisp_Object | 2213 | static INLINE Lisp_Object |
| 2180 | lface_from_face_name (f, face_name, signal_p) | 2214 | lface_from_face_name_no_resolve (f, face_name, signal_p) |
| 2181 | struct frame *f; | 2215 | struct frame *f; |
| 2182 | Lisp_Object face_name; | 2216 | Lisp_Object face_name; |
| 2183 | int signal_p; | 2217 | int signal_p; |
| 2184 | { | 2218 | { |
| 2185 | Lisp_Object lface; | 2219 | Lisp_Object lface; |
| 2186 | 2220 | ||
| 2187 | face_name = resolve_face_name (face_name, signal_p); | ||
| 2188 | |||
| 2189 | if (f) | 2221 | if (f) |
| 2190 | lface = assq_no_quit (face_name, f->face_alist); | 2222 | lface = assq_no_quit (face_name, f->face_alist); |
| 2191 | else | 2223 | else |
| @@ -2197,9 +2229,28 @@ lface_from_face_name (f, face_name, signal_p) | |||
| 2197 | signal_error ("Invalid face", face_name); | 2229 | signal_error ("Invalid face", face_name); |
| 2198 | 2230 | ||
| 2199 | check_lface (lface); | 2231 | check_lface (lface); |
| 2232 | |||
| 2200 | return lface; | 2233 | return lface; |
| 2201 | } | 2234 | } |
| 2202 | 2235 | ||
| 2236 | /* Return the face definition of FACE_NAME on frame F. F null means | ||
| 2237 | return the definition for new frames. FACE_NAME may be a string or | ||
| 2238 | a symbol (apparently Emacs 20.2 allowed strings as face names in | ||
| 2239 | face text properties; Ediff uses that). If FACE_NAME is an alias | ||
| 2240 | for another face, return that face's definition. If SIGNAL_P is | ||
| 2241 | non-zero, signal an error if FACE_NAME is not a valid face name. | ||
| 2242 | If SIGNAL_P is zero, value is nil if FACE_NAME is not a valid face | ||
| 2243 | name. */ | ||
| 2244 | static INLINE Lisp_Object | ||
| 2245 | lface_from_face_name (f, face_name, signal_p) | ||
| 2246 | struct frame *f; | ||
| 2247 | Lisp_Object face_name; | ||
| 2248 | int signal_p; | ||
| 2249 | { | ||
| 2250 | face_name = resolve_face_name (face_name, signal_p); | ||
| 2251 | return lface_from_face_name_no_resolve (f, face_name, signal_p); | ||
| 2252 | } | ||
| 2253 | |||
| 2203 | 2254 | ||
| 2204 | /* Get face attributes of face FACE_NAME from frame-local faces on | 2255 | /* Get face attributes of face FACE_NAME from frame-local faces on |
| 2205 | frame F. Store the resulting attributes in ATTRS which must point | 2256 | frame F. Store the resulting attributes in ATTRS which must point |
| @@ -2208,26 +2259,65 @@ lface_from_face_name (f, face_name, signal_p) | |||
| 2208 | Otherwise, value is zero if FACE_NAME is not a face. */ | 2259 | Otherwise, value is zero if FACE_NAME is not a face. */ |
| 2209 | 2260 | ||
| 2210 | static INLINE int | 2261 | static INLINE int |
| 2211 | get_lface_attributes (f, face_name, attrs, signal_p) | 2262 | get_lface_attributes_no_remap (f, face_name, attrs, signal_p) |
| 2212 | struct frame *f; | 2263 | struct frame *f; |
| 2213 | Lisp_Object face_name; | 2264 | Lisp_Object face_name; |
| 2214 | Lisp_Object *attrs; | 2265 | Lisp_Object *attrs; |
| 2215 | int signal_p; | 2266 | int signal_p; |
| 2216 | { | 2267 | { |
| 2217 | Lisp_Object lface; | 2268 | Lisp_Object lface; |
| 2218 | int success_p; | ||
| 2219 | 2269 | ||
| 2220 | lface = lface_from_face_name (f, face_name, signal_p); | 2270 | lface = lface_from_face_name_no_resolve (f, face_name, signal_p); |
| 2221 | if (!NILP (lface)) | 2271 | |
| 2272 | if (! NILP (lface)) | ||
| 2273 | bcopy (XVECTOR (lface)->contents, attrs, | ||
| 2274 | LFACE_VECTOR_SIZE * sizeof *attrs); | ||
| 2275 | |||
| 2276 | return !NILP (lface); | ||
| 2277 | } | ||
| 2278 | |||
| 2279 | /* Get face attributes of face FACE_NAME from frame-local faces on frame | ||
| 2280 | F. Store the resulting attributes in ATTRS which must point to a | ||
| 2281 | vector of Lisp_Objects of size LFACE_VECTOR_SIZE. If FACE_NAME is an | ||
| 2282 | alias for another face, use that face's definition. If SIGNAL_P is | ||
| 2283 | non-zero, signal an error if FACE_NAME does not name a face. | ||
| 2284 | Otherwise, value is zero if FACE_NAME is not a face. */ | ||
| 2285 | |||
| 2286 | static INLINE int | ||
| 2287 | get_lface_attributes (f, face_name, attrs, signal_p, named_merge_points) | ||
| 2288 | struct frame *f; | ||
| 2289 | Lisp_Object face_name; | ||
| 2290 | Lisp_Object *attrs; | ||
| 2291 | int signal_p; | ||
| 2292 | struct named_merge_point *named_merge_points; | ||
| 2293 | { | ||
| 2294 | Lisp_Object face_remapping; | ||
| 2295 | |||
| 2296 | face_name = resolve_face_name (face_name, signal_p); | ||
| 2297 | |||
| 2298 | /* See if SYMBOL has been remapped to some other face (usually this | ||
| 2299 | is done buffer-locally). */ | ||
| 2300 | face_remapping = assq_no_quit (face_name, Vface_remapping_alist); | ||
| 2301 | if (CONSP (face_remapping)) | ||
| 2222 | { | 2302 | { |
| 2223 | bcopy (XVECTOR (lface)->contents, attrs, | 2303 | struct named_merge_point named_merge_point; |
| 2224 | LFACE_VECTOR_SIZE * sizeof *attrs); | 2304 | |
| 2225 | success_p = 1; | 2305 | if (push_named_merge_point (&named_merge_point, |
| 2306 | face_name, NAMED_MERGE_POINT_REMAP, | ||
| 2307 | &named_merge_points)) | ||
| 2308 | { | ||
| 2309 | int i; | ||
| 2310 | |||
| 2311 | for (i = 1; i < LFACE_VECTOR_SIZE; ++i) | ||
| 2312 | attrs[i] = Qunspecified; | ||
| 2313 | |||
| 2314 | return merge_face_ref (f, XCDR (face_remapping), attrs, | ||
| 2315 | signal_p, named_merge_points); | ||
| 2316 | } | ||
| 2226 | } | 2317 | } |
| 2227 | else | ||
| 2228 | success_p = 0; | ||
| 2229 | 2318 | ||
| 2230 | return success_p; | 2319 | /* Default case, no remapping. */ |
| 2320 | return get_lface_attributes_no_remap (f, face_name, attrs, signal_p); | ||
| 2231 | } | 2321 | } |
| 2232 | 2322 | ||
| 2233 | 2323 | ||
| @@ -2383,8 +2473,8 @@ merge_face_heights (from, to, invalid) | |||
| 2383 | specified attribute of FROM overrides the corresponding attribute of | 2473 | specified attribute of FROM overrides the corresponding attribute of |
| 2384 | TO; relative attributes in FROM are merged with the absolute value in | 2474 | TO; relative attributes in FROM are merged with the absolute value in |
| 2385 | TO and replace it. NAMED_MERGE_POINTS is used internally to detect | 2475 | TO and replace it. NAMED_MERGE_POINTS is used internally to detect |
| 2386 | loops in face inheritance; it should be 0 when called from other | 2476 | loops in face inheritance/remapping; it should be 0 when called from |
| 2387 | places. */ | 2477 | other places. */ |
| 2388 | 2478 | ||
| 2389 | static INLINE void | 2479 | static INLINE void |
| 2390 | merge_face_vectors (f, from, to, named_merge_points) | 2480 | merge_face_vectors (f, from, to, named_merge_points) |
| @@ -2459,11 +2549,12 @@ merge_named_face (f, face_name, to, named_merge_points) | |||
| 2459 | struct named_merge_point named_merge_point; | 2549 | struct named_merge_point named_merge_point; |
| 2460 | 2550 | ||
| 2461 | if (push_named_merge_point (&named_merge_point, | 2551 | if (push_named_merge_point (&named_merge_point, |
| 2462 | face_name, &named_merge_points)) | 2552 | face_name, NAMED_MERGE_POINT_NORMAL, |
| 2553 | &named_merge_points)) | ||
| 2463 | { | 2554 | { |
| 2464 | struct gcpro gcpro1; | 2555 | struct gcpro gcpro1; |
| 2465 | Lisp_Object from[LFACE_VECTOR_SIZE]; | 2556 | Lisp_Object from[LFACE_VECTOR_SIZE]; |
| 2466 | int ok = get_lface_attributes (f, face_name, from, 0); | 2557 | int ok = get_lface_attributes (f, face_name, from, 0, named_merge_points); |
| 2467 | 2558 | ||
| 2468 | if (ok) | 2559 | if (ok) |
| 2469 | { | 2560 | { |
| @@ -3441,7 +3532,7 @@ update_face_from_frame_parameter (f, param, new_value) | |||
| 3441 | 3532 | ||
| 3442 | /* Changing the background color might change the background | 3533 | /* Changing the background color might change the background |
| 3443 | mode, so that we have to load new defface specs. | 3534 | mode, so that we have to load new defface specs. |
| 3444 | Call frame-set-background-mode to do that. */ | 3535 | Call frame-update-face-colors to do that. */ |
| 3445 | XSETFRAME (frame, f); | 3536 | XSETFRAME (frame, f); |
| 3446 | call1 (Qframe_set_background_mode, frame); | 3537 | call1 (Qframe_set_background_mode, frame); |
| 3447 | 3538 | ||
| @@ -4647,7 +4738,7 @@ lookup_named_face (f, symbol, signal_p) | |||
| 4647 | abort (); /* realize_basic_faces must have set it up */ | 4738 | abort (); /* realize_basic_faces must have set it up */ |
| 4648 | } | 4739 | } |
| 4649 | 4740 | ||
| 4650 | if (!get_lface_attributes (f, symbol, symbol_attrs, signal_p)) | 4741 | if (! get_lface_attributes (f, symbol, symbol_attrs, signal_p, 0)) |
| 4651 | return -1; | 4742 | return -1; |
| 4652 | 4743 | ||
| 4653 | bcopy (default_face->lface, attrs, sizeof attrs); | 4744 | bcopy (default_face->lface, attrs, sizeof attrs); |
| @@ -4657,6 +4748,58 @@ lookup_named_face (f, symbol, signal_p) | |||
| 4657 | } | 4748 | } |
| 4658 | 4749 | ||
| 4659 | 4750 | ||
| 4751 | /* Return the display face-id of the basic face who's canonical face-id | ||
| 4752 | is FACE_ID. The return value will usually simply be FACE_ID, unless that | ||
| 4753 | basic face has bee remapped via Vface_remapping_alist. This function is | ||
| 4754 | conservative: if something goes wrong, it will simply return FACE_ID | ||
| 4755 | rather than signal an error. */ | ||
| 4756 | |||
| 4757 | int | ||
| 4758 | lookup_basic_face (f, face_id) | ||
| 4759 | struct frame *f; | ||
| 4760 | int face_id; | ||
| 4761 | { | ||
| 4762 | Lisp_Object name, mapping; | ||
| 4763 | int remapped_face_id; | ||
| 4764 | |||
| 4765 | if (NILP (Vface_remapping_alist)) | ||
| 4766 | return face_id; /* Nothing to do. */ | ||
| 4767 | |||
| 4768 | switch (face_id) | ||
| 4769 | { | ||
| 4770 | case DEFAULT_FACE_ID: name = Qdefault; break; | ||
| 4771 | case MODE_LINE_FACE_ID: name = Qmode_line; break; | ||
| 4772 | case MODE_LINE_INACTIVE_FACE_ID: name = Qmode_line_inactive; break; | ||
| 4773 | case HEADER_LINE_FACE_ID: name = Qheader_line; break; | ||
| 4774 | case TOOL_BAR_FACE_ID: name = Qtool_bar; break; | ||
| 4775 | case FRINGE_FACE_ID: name = Qfringe; break; | ||
| 4776 | case SCROLL_BAR_FACE_ID: name = Qscroll_bar; break; | ||
| 4777 | case BORDER_FACE_ID: name = Qborder; break; | ||
| 4778 | case CURSOR_FACE_ID: name = Qcursor; break; | ||
| 4779 | case MOUSE_FACE_ID: name = Qmouse; break; | ||
| 4780 | case MENU_FACE_ID: name = Qmenu; break; | ||
| 4781 | |||
| 4782 | default: | ||
| 4783 | abort (); /* the caller is supposed to pass us a basic face id */ | ||
| 4784 | } | ||
| 4785 | |||
| 4786 | /* Do a quick scan through Vface_remapping_alist, and return immediately | ||
| 4787 | if there is no remapping for face NAME. This is just an optimization | ||
| 4788 | for the very common no-remapping case. */ | ||
| 4789 | mapping = assq_no_quit (name, Vface_remapping_alist); | ||
| 4790 | if (NILP (mapping)) | ||
| 4791 | return face_id; /* Give up. */ | ||
| 4792 | |||
| 4793 | /* If there is a remapping entry, lookup the face using NAME, which will | ||
| 4794 | handle the remapping too. */ | ||
| 4795 | remapped_face_id = lookup_named_face (f, name, 0); | ||
| 4796 | if (remapped_face_id < 0) | ||
| 4797 | return face_id; /* Give up. */ | ||
| 4798 | |||
| 4799 | return remapped_face_id; | ||
| 4800 | } | ||
| 4801 | |||
| 4802 | |||
| 4660 | /* Return the ID of the realized ASCII face of Lisp face with ID | 4803 | /* Return the ID of the realized ASCII face of Lisp face with ID |
| 4661 | LFACE_ID on frame F. Value is -1 if LFACE_ID isn't valid. */ | 4804 | LFACE_ID on frame F. Value is -1 if LFACE_ID isn't valid. */ |
| 4662 | 4805 | ||
| @@ -4789,7 +4932,7 @@ lookup_derived_face (f, symbol, face_id, signal_p) | |||
| 4789 | if (!default_face) | 4932 | if (!default_face) |
| 4790 | abort (); | 4933 | abort (); |
| 4791 | 4934 | ||
| 4792 | get_lface_attributes (f, symbol, symbol_attrs, signal_p); | 4935 | get_lface_attributes (f, symbol, symbol_attrs, signal_p, 0); |
| 4793 | bcopy (default_face->lface, attrs, sizeof attrs); | 4936 | bcopy (default_face->lface, attrs, sizeof attrs); |
| 4794 | merge_face_vectors (f, symbol_attrs, attrs, 0); | 4937 | merge_face_vectors (f, symbol_attrs, attrs, 0); |
| 4795 | return lookup_face (f, attrs); | 4938 | return lookup_face (f, attrs); |
| @@ -5498,7 +5641,7 @@ realize_named_face (f, symbol, id) | |||
| 5498 | struct face *new_face; | 5641 | struct face *new_face; |
| 5499 | 5642 | ||
| 5500 | /* The default face must exist and be fully specified. */ | 5643 | /* The default face must exist and be fully specified. */ |
| 5501 | get_lface_attributes (f, Qdefault, attrs, 1); | 5644 | get_lface_attributes_no_remap (f, Qdefault, attrs, 1); |
| 5502 | check_lface_attrs (attrs); | 5645 | check_lface_attrs (attrs); |
| 5503 | xassert (lface_fully_specified_p (attrs)); | 5646 | xassert (lface_fully_specified_p (attrs)); |
| 5504 | 5647 | ||
| @@ -5511,7 +5654,7 @@ realize_named_face (f, symbol, id) | |||
| 5511 | } | 5654 | } |
| 5512 | 5655 | ||
| 5513 | /* Merge SYMBOL's face with the default face. */ | 5656 | /* Merge SYMBOL's face with the default face. */ |
| 5514 | get_lface_attributes (f, symbol, symbol_attrs, 1); | 5657 | get_lface_attributes_no_remap (f, symbol, symbol_attrs, 1); |
| 5515 | merge_face_vectors (f, symbol_attrs, attrs, 0); | 5658 | merge_face_vectors (f, symbol_attrs, attrs, 0); |
| 5516 | 5659 | ||
| 5517 | /* Realize the face. */ | 5660 | /* Realize the face. */ |
| @@ -6068,13 +6211,18 @@ face_at_buffer_position (w, pos, region_beg, region_end, | |||
| 6068 | 6211 | ||
| 6069 | *endptr = endpos; | 6212 | *endptr = endpos; |
| 6070 | 6213 | ||
| 6071 | default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID); | 6214 | |
| 6215 | /* Perhaps remap BASE_FACE_ID to a user-specified alternative. */ | ||
| 6216 | if (NILP (Vface_remapping_alist)) | ||
| 6217 | default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID); | ||
| 6218 | else | ||
| 6219 | default_face = FACE_FROM_ID (f, lookup_basic_face (f, DEFAULT_FACE_ID)); | ||
| 6072 | 6220 | ||
| 6073 | /* Optimize common cases where we can use the default face. */ | 6221 | /* Optimize common cases where we can use the default face. */ |
| 6074 | if (noverlays == 0 | 6222 | if (noverlays == 0 |
| 6075 | && NILP (prop) | 6223 | && NILP (prop) |
| 6076 | && !(pos >= region_beg && pos < region_end)) | 6224 | && !(pos >= region_beg && pos < region_end)) |
| 6077 | return DEFAULT_FACE_ID; | 6225 | return default_face->id; |
| 6078 | 6226 | ||
| 6079 | /* Begin with attributes from the default face. */ | 6227 | /* Begin with attributes from the default face. */ |
| 6080 | bcopy (default_face->lface, attrs, sizeof attrs); | 6228 | bcopy (default_face->lface, attrs, sizeof attrs); |
| @@ -6673,6 +6821,43 @@ Each element is a regular expression that matches names of fonts to | |||
| 6673 | ignore. */); | 6821 | ignore. */); |
| 6674 | Vface_ignored_fonts = Qnil; | 6822 | Vface_ignored_fonts = Qnil; |
| 6675 | 6823 | ||
| 6824 | DEFVAR_LISP ("face-remapping-alist", &Vface_remapping_alist, | ||
| 6825 | doc: /* Alist of face remappings. | ||
| 6826 | Each element is of the form: | ||
| 6827 | |||
| 6828 | (FACE REPLACEMENT...), | ||
| 6829 | |||
| 6830 | which causes display of the face FACE to use REPLACEMENT... instead. | ||
| 6831 | REPLACEMENT... is interpreted the same way the value of a `face' text | ||
| 6832 | property is: it may be (1) A face name, (2) A list of face names, (3) A | ||
| 6833 | property-list of face attribute/value pairs, or (4) A list of face names | ||
| 6834 | intermixed with lists containing face attribute/value pairs. | ||
| 6835 | |||
| 6836 | Multiple entries in REPLACEMENT... are merged together to form the final | ||
| 6837 | result, with faces or attributes earlier in the list taking precedence | ||
| 6838 | over those that are later. | ||
| 6839 | |||
| 6840 | Face-name remapping cycles are suppressed; recursive references use the | ||
| 6841 | underlying face instead of the remapped face. So a remapping of the form: | ||
| 6842 | |||
| 6843 | (FACE EXTRA-FACE... FACE) | ||
| 6844 | |||
| 6845 | or: | ||
| 6846 | |||
| 6847 | (FACE (FACE-ATTR VAL ...) FACE) | ||
| 6848 | |||
| 6849 | will cause EXTRA-FACE... or (FACE-ATTR VAL ...) to be _merged_ with the | ||
| 6850 | existing definition of FACE. Note that for the default face, this isn't | ||
| 6851 | necessary, as every face inherits from the default face. | ||
| 6852 | |||
| 6853 | Making this variable buffer-local is a good way to allow buffer-specific | ||
| 6854 | face definitions. For instance, the mode my-mode could define a face | ||
| 6855 | `my-mode-default', and then in the mode setup function, do: | ||
| 6856 | |||
| 6857 | (set (make-local-variable 'face-remapping-alist) | ||
| 6858 | '((default my-mode-default)))). */); | ||
| 6859 | Vface_remapping_alist = Qnil; | ||
| 6860 | |||
| 6676 | DEFVAR_LISP ("face-font-rescale-alist", &Vface_font_rescale_alist, | 6861 | DEFVAR_LISP ("face-font-rescale-alist", &Vface_font_rescale_alist, |
| 6677 | doc: /* Alist of fonts vs the rescaling factors. | 6862 | doc: /* Alist of fonts vs the rescaling factors. |
| 6678 | Each element is a cons (FONT-NAME-PATTERN . RESCALE-RATIO), where | 6863 | Each element is a cons (FONT-NAME-PATTERN . RESCALE-RATIO), where |