diff options
-rw-r--r-- | doc/emacs/mark.texi | 5 | ||||
-rw-r--r-- | doc/lispref/display.texi | 22 | ||||
-rw-r--r-- | etc/NEWS | 7 | ||||
-rw-r--r-- | lisp/cus-face.el | 6 | ||||
-rw-r--r-- | lisp/faces.el | 47 | ||||
-rw-r--r-- | lisp/help-fns.el | 1 | ||||
-rw-r--r-- | lisp/hl-line.el | 2 | ||||
-rw-r--r-- | src/dispextern.h | 27 | ||||
-rw-r--r-- | src/font.c | 10 | ||||
-rw-r--r-- | src/nsterm.m | 10 | ||||
-rw-r--r-- | src/w32term.c | 12 | ||||
-rw-r--r-- | src/xdisp.c | 567 | ||||
-rw-r--r-- | src/xfaces.c | 144 | ||||
-rw-r--r-- | src/xterm.c | 10 |
14 files changed, 492 insertions, 378 deletions
diff --git a/doc/emacs/mark.texi b/doc/emacs/mark.texi index bbeb4cb039e..f012d72fc2a 100644 --- a/doc/emacs/mark.texi +++ b/doc/emacs/mark.texi @@ -23,6 +23,11 @@ When the mark is active, we say also that the region is active; Emacs indicates its extent by highlighting the text within it, using the @code{region} face (@pxref{Face Customization}). +This is one of the few faces that has the @code{:extend t} attribute +by default, which implies that the same face is used to highlight the +text and space between end of line and the window border. To +highlight only the text you could set this attribute to @code{nil}. + @cindex deactivating the mark After certain non-motion commands, including any command that changes the text in the buffer, Emacs automatically @dfn{deactivates} diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 61bd4ce8830..1678d32db0a 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -2482,6 +2482,17 @@ faces (@pxref{Displaying Faces}). If the face to inherit from is never merges @code{:inherit} attributes. If a list of faces is used, attributes from faces earlier in the list override those from later faces. + +@item :extend +Whether or not this face will be extended until the end of the window. +The value should be @code{t} to extend until end of the window using +this face or @code{nil} fill the space between the end of the line and +the end of the window with the default face. When a face is conformed +by merging multiple other faces; only those with @code{:extend t} will +be merged to conform a new face to extend until end of window. By +default only @code{region} and @code{hl-line} have this attribute set +to @code{t}. + @end table @defun font-family-list &optional frame @@ -2842,6 +2853,11 @@ This sets the @code{:inverse-video} attribute of @var{face} to This swaps the foreground and background colors of face @var{face}. @end deffn +@deffn Command set-face-extend face extend &optional frame +This sets the @code{:extend} attribute of @var{face} to +@var{extend}. +@end deffn + The following functions examine the attributes of a face. They mostly provide compatibility with old versions of Emacs. If you don't specify @var{frame}, they refer to the selected frame; @code{t} refers @@ -2900,6 +2916,12 @@ This function returns non-@code{nil} if face @var{face} specifies a non-@code{nil} @code{:inverse-video} attribute. @end defun +@defun face-extend-p face &optional frame +This function returns non-@code{nil} if face @var{face} specifies +a non-@code{nil} @code{:extend} attribute. +@end defun + + @node Displaying Faces @subsection Displaying Faces @cindex displaying faces @@ -384,6 +384,13 @@ matches strings where the pattern appears as a subsequence. Put simply, makes "foo" complete to both "barfoo" and "frodo". Add 'flex' to 'completion-styles' or 'completion-category-overrides' to use it. ++++ +** New face attribute ':extend' to control face extension at EOL. +There is a new face attribute :extend to use the face attributes to +extend after the end of the line until the end of the window. Such +:extend is set to nil by default in all faces except for 'hl-line' and +'region' because those extend until the end of the window by default. + ** Connection-local variables +++ diff --git a/lisp/cus-face.el b/lisp/cus-face.el index d73bce42c3e..5a49a810434 100644 --- a/lisp/cus-face.el +++ b/lisp/cus-face.el @@ -233,7 +233,11 @@ (file :tag "File" :help-echo "Name of bitmap file." :must-match t))) - + (:extend + (choice :tag "Extend" + :help-echo "Control whether attributes should be extended after EOL." + (const :tag "Off" nil) + (const :tag "On" t))) (:inherit (repeat :tag "Inherit" :help-echo "List of faces to inherit attributes from." diff --git a/lisp/faces.el b/lisp/faces.el index c789d3729e0..36fc69895dd 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -342,6 +342,7 @@ is either `foreground-color', `background-color', or a keyword." (:box (".attributeBox" . "Face.AttributeBox")) (:underline (".attributeUnderline" . "Face.AttributeUnderline")) (:inverse-video (".attributeInverse" . "Face.AttributeInverse")) + (:extend (".attributeExtend" . "Face.AttributeExtend")) (:stipple (".attributeStipple" . "Face.AttributeStipple") (".attributeBackgroundPixmap" . "Face.AttributeBackgroundPixmap")) @@ -594,6 +595,13 @@ Use `face-attribute' for finer control." (let ((italic (face-attribute face :slant frame inherit))) (memq italic '(italic oblique)))) +(defun face-extend-p (face &optional frame inherit) + "Return non-nil if FACE specifies a non-nil extend. +If the optional argument FRAME is given, report on face FACE in that frame. +If FRAME is t, report on the defaults for face FACE (for new frames). +If FRAME is omitted or nil, use the selected frame. +Optional argument INHERIT is passed to `face-attribute'." + (eq (face-attribute face :extend frame inherit) t)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; @@ -760,6 +768,11 @@ For convenience, attributes `:family', `:foundry', `:width', `:height', `:weight', and `:slant' may also be set in one step from an X font name: +`:extend' + +VALUE specifies whether the FACE should be extended after EOL. +VALUE must be one of t or nil. + `:font' Set font-related face attributes from VALUE. @@ -979,6 +992,18 @@ Use `set-face-attribute' or `modify-face' for finer control." (define-obsolete-function-alias 'set-face-italic-p 'set-face-italic "24.4") +(defun set-face-extend (face extend-p &optional frame) + "Specify whether face FACE should be extended. +EXTEND-P nil means FACE explicitly doesn't extend after EOL. +EXTEND-P t means FACE extends after EOL. + +FRAME nil or not specified means change face on all frames. +Use `set-face-attribute' to \"unspecify\" underlining." + (interactive + (let ((list (read-face-and-attribute :extend))) + (list (car list) (if (cadr list) t)))) + (set-face-attribute face frame :extend extend-p)) + (defalias 'set-face-background-pixmap 'set-face-stipple) @@ -1102,7 +1127,7 @@ an integer value." (:slant (mapcar #'(lambda (x) (cons (symbol-name (aref x 1)) (aref x 1))) font-slant-table)) - (:inverse-video + ((or :inverse-video :extend) (mapcar #'(lambda (x) (cons (symbol-name x) x)) (internal-lisp-face-attribute-values attribute))) ((or :underline :overline :strike-through :box) @@ -1147,6 +1172,7 @@ an integer value." (:slant . "slant") (:underline . "underline") (:overline . "overline") + (:extend . "extend") (:strike-through . "strike-through") (:box . "box") (:inverse-video . "inverse-video display") @@ -1549,7 +1575,8 @@ is given, in which case return its value instead." ;; (see also realize_default_face in xfaces.c). (append '(:underline nil :overline nil :strike-through nil - :box nil :inverse-video nil :stipple nil :inherit nil) + :box nil :inverse-video nil :stipple nil :inherit nil + :extend nil) ;; `display-graphic-p' is unavailable when running ;; temacs, prior to loading frame.el. (when (fboundp 'display-graphic-p) @@ -2314,24 +2341,24 @@ If you set `term-file-prefix' to nil, this function does nothing." ;; if background is light. (defface region '((((class color) (min-colors 88) (background dark)) - :background "blue3") + :background "blue3" :extend t) (((class color) (min-colors 88) (background light) (type gtk)) :distant-foreground "gtk_selection_fg_color" - :background "gtk_selection_bg_color") + :background "gtk_selection_bg_color" :extend t) (((class color) (min-colors 88) (background light) (type ns)) :distant-foreground "ns_selection_fg_color" - :background "ns_selection_bg_color") + :background "ns_selection_bg_color" :extend t) (((class color) (min-colors 88) (background light)) - :background "lightgoldenrod2") + :background "lightgoldenrod2" :extend t) (((class color) (min-colors 16) (background dark)) - :background "blue3") + :background "blue3" :extend t) (((class color) (min-colors 16) (background light)) - :background "lightgoldenrod2") + :background "lightgoldenrod2" :extend t) (((class color) (min-colors 8)) - :background "blue" :foreground "white") + :background "blue" :foreground "white" :extend t) (((type tty) (class mono)) :inverse-video t) - (t :background "gray")) + (t :background "gray" :extend t)) "Basic face for highlighting the region." :version "21.1" :group 'basic-faces) diff --git a/lisp/help-fns.el b/lisp/help-fns.el index 5e55240daba..235aa9a6e19 100644 --- a/lisp/help-fns.el +++ b/lisp/help-fns.el @@ -1385,6 +1385,7 @@ If FRAME is omitted or nil, use the selected frame." (:stipple . "Stipple") (:font . "Font") (:fontset . "Fontset") + (:extend . "Extend") (:inherit . "Inherit"))) (max-width (apply #'max (mapcar #'(lambda (x) (length (cdr x))) attrs)))) diff --git a/lisp/hl-line.el b/lisp/hl-line.el index 8d929b8bb09..8d92e36214f 100644 --- a/lisp/hl-line.el +++ b/lisp/hl-line.el @@ -78,7 +78,7 @@ when `global-hl-line-sticky-flag' is non-nil.") :group 'convenience) (defface hl-line - '((t :inherit highlight)) + '((t :inherit highlight :extend t)) "Default face for highlighting the current line in Hl-Line mode." :version "22.1" :group 'hl-line) diff --git a/src/dispextern.h b/src/dispextern.h index 7a15e2745b5..0615b16d712 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1607,6 +1607,7 @@ enum lface_attribute_index LFACE_INHERIT_INDEX, LFACE_FONTSET_INDEX, LFACE_DISTANT_FOREGROUND_INDEX, + LFACE_EXTEND_INDEX, LFACE_VECTOR_SIZE }; @@ -1632,6 +1633,7 @@ enum face_box_type enum face_underline_type { + FACE_NO_UNDERLINE = 0, FACE_UNDER_LINE, FACE_UNDER_WAVE }; @@ -1675,11 +1677,9 @@ struct face /* Pixel value or color index of background color. */ unsigned long background; - /* Pixel value or color index of underline color. */ + /* Pixel value or color index of underline, overlined, + strike-through, or box color. */ unsigned long underline_color; - - /* Pixel value or color index of overlined, strike-through, or box - color. */ unsigned long overline_color; unsigned long strike_through_color; unsigned long box_color; @@ -1706,7 +1706,7 @@ struct face ENUM_BF (face_box_type) box : 2; /* Style of underlining. */ - ENUM_BF (face_underline_type) underline_type : 1; + ENUM_BF (face_underline_type) underline : 2; /* If `box' above specifies a 3D type, true means use box_color for drawing shadows. */ @@ -1714,7 +1714,6 @@ struct face /* Non-zero if text in this face should be underlined, overlined, strike-through or have a box drawn around it. */ - bool_bf underline_p : 1; bool_bf overline_p : 1; bool_bf strike_through_p : 1; @@ -1724,14 +1723,10 @@ struct face bool_bf foreground_defaulted_p : 1; bool_bf background_defaulted_p : 1; - /* True means that either no color is specified for underlining or that - the specified color couldn't be loaded. Use the foreground - color when drawing in that case. */ - bool_bf underline_defaulted_p : 1; - /* True means that either no color is specified for the corresponding attribute or that the specified color couldn't be loaded. Use the foreground color when drawing in that case. */ + bool_bf underline_defaulted_p : 1; bool_bf overline_color_defaulted_p : 1; bool_bf strike_through_color_defaulted_p : 1; bool_bf box_color_defaulted_p : 1; @@ -1867,6 +1862,9 @@ struct face_cache ? FRAME_FACE_CACHE (F)->faces_by_id[ID] \ : NULL) +#define FACE_EXTENSIBLE_P(F) \ + (!NILP (F->lface[LFACE_EXTEND_INDEX])) + /* True if FACE is suitable for displaying ASCII characters. */ INLINE bool FACE_SUITABLE_FOR_ASCII_CHAR_P (struct face *face) @@ -3553,12 +3551,13 @@ int lookup_derived_face (struct window *, struct frame *, void init_frame_faces (struct frame *); void free_frame_faces (struct frame *); void recompute_basic_faces (struct frame *); -int face_at_buffer_position (struct window *, ptrdiff_t, ptrdiff_t *, ptrdiff_t, - bool, int); +int face_at_buffer_position (struct window *, ptrdiff_t, ptrdiff_t *, + ptrdiff_t, bool, int, enum lface_attribute_index); int face_for_overlay_string (struct window *, ptrdiff_t, ptrdiff_t *, ptrdiff_t, bool, Lisp_Object); int face_at_string_position (struct window *, Lisp_Object, ptrdiff_t, ptrdiff_t, - ptrdiff_t *, enum face_id, bool); + ptrdiff_t *, enum face_id, bool, + enum lface_attribute_index); int merge_faces (struct window *, Lisp_Object, int, int); int compute_char_face (struct frame *, int, Lisp_Object); void free_all_realized_faces (Lisp_Object); diff --git a/src/font.c b/src/font.c index 6bc977fd68e..7fdadb17c14 100644 --- a/src/font.c +++ b/src/font.c @@ -3785,10 +3785,10 @@ font_at (int c, ptrdiff_t pos, struct face *face, struct window *w, if (STRINGP (string)) face_id = face_at_string_position (w, string, pos, 0, &endptr, - DEFAULT_FACE_ID, false); + DEFAULT_FACE_ID, false, 0); else face_id = face_at_buffer_position (w, pos, &endptr, - pos + 100, false, -1); + pos + 100, false, -1, 0); face = FACE_FROM_ID (f, face_id); } if (multibyte) @@ -3832,7 +3832,7 @@ font_range (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t *limit, if (NILP (string)) face_id = face_at_buffer_position (w, pos, &ignore, *limit, - false, -1); + false, -1, 0); else { face_id = @@ -3841,7 +3841,7 @@ font_range (ptrdiff_t pos, ptrdiff_t pos_byte, ptrdiff_t *limit, : lookup_basic_face (w, f, DEFAULT_FACE_ID); face_id = face_at_string_position (w, string, pos, 0, &ignore, - face_id, false); + face_id, false, 0); } face = FACE_FROM_ID (f, face_id); } @@ -4618,7 +4618,7 @@ DEFUN ("internal-char-font", Finternal_char_font, Sinternal_char_font, 1, 2, 0, w = XWINDOW (window); f = XFRAME (w->frame); face_id = face_at_buffer_position (w, pos, &dummy, - pos + 100, false, -1); + pos + 100, false, -1, 0); } if (! CHAR_VALID_P (c)) return Qnil; diff --git a/src/nsterm.m b/src/nsterm.m index c8094d0ee37..5583c6105cb 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -3404,9 +3404,9 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face, return; /* Do underline. */ - if (face->underline_p) + if (face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { if (face->underline_defaulted_p) [defaultCol set]; @@ -3415,15 +3415,15 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face, ns_draw_underwave (s, width, x); } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { NSRect r; unsigned long thickness, position; /* If the prev was underlined, match its appearance. */ - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE + if (s->prev + && s->prev->face->underline == FACE_UNDER_LINE && s->prev->underline_thickness > 0) { thickness = s->prev->underline_thickness; diff --git a/src/w32term.c b/src/w32term.c index 82256db1721..9da0845836a 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -2481,9 +2481,9 @@ w32_draw_glyph_string (struct glyph_string *s) if (!s->for_overlaps) { /* Draw underline. */ - if (s->face->underline_p) + if (s->face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { COLORREF color; @@ -2494,13 +2494,13 @@ w32_draw_glyph_string (struct glyph_string *s) w32_draw_underwave (s, color); } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { unsigned long thickness, position; int y; - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE) + if (s->prev + && s->prev->face->underline == FACE_UNDER_LINE) { /* We use the same underline style as the previous one. */ thickness = s->prev->underline_thickness; @@ -2514,7 +2514,7 @@ w32_draw_glyph_string (struct glyph_string *s) BOOL use_underline_position_properties; Lisp_Object val = buffer_local_value (Qunderline_minimum_offset, - s->w->contents); + s->w->contents); if (FIXNUMP (val)) minimum_offset = max (0, XFIXNUM (val)); else diff --git a/src/xdisp.c b/src/xdisp.c index 1cfd7ef7601..30be492d9b4 100644 --- a/src/xdisp.c +++ b/src/xdisp.c @@ -431,17 +431,26 @@ static Lisp_Object list_of_error; met, return the (nonnegative) column number, else return a negative value. */ static int -fill_column_indicator_column (struct it *it) +fill_column_indicator_column (struct it *it, int char_width) { if (Vdisplay_fill_column_indicator + && !it->w->pseudo_window_p && it->continuation_lines_width == 0 && CHARACTERP (Vdisplay_fill_column_indicator_character)) { Lisp_Object col = (EQ (Vdisplay_fill_column_indicator_column, Qt) ? BVAR (current_buffer, fill_column) : Vdisplay_fill_column_indicator_column); + + /* The stretch width needs to consider the latter + added glyph in append_space_for_newline. */ if (RANGED_FIXNUMP (0, col, INT_MAX)) - return XFIXNUM (col); + { + int icol = XFIXNUM (col); + if (!INT_MULTIPLY_WRAPV (char_width, icol, &icol) + && !INT_ADD_WRAPV (it->lnum_pixel_width, icol, &icol)) + return icol; + } } return -1; } @@ -984,7 +993,7 @@ static int handle_display_spec (struct it *, Lisp_Object, Lisp_Object, static int handle_single_display_spec (struct it *, Lisp_Object, Lisp_Object, Lisp_Object, struct text_pos *, ptrdiff_t, int, bool, bool); -static int underlying_face_id (struct it *); +static int underlying_face_id (const struct it *); #define face_before_it_pos(IT) face_before_or_after_it_pos (IT, true) #define face_after_it_pos(IT) face_before_or_after_it_pos (IT, false) @@ -4148,56 +4157,20 @@ handle_fontified_prop (struct it *it) Faces ***********************************************************************/ -/* Set up iterator IT from face properties at its current position. - Called from handle_stop. */ - -static enum prop_handled -handle_face_prop (struct it *it) +static int +face_at_pos (const struct it *it, enum lface_attribute_index attr_filter) { - int new_face_id; ptrdiff_t next_stop; if (!STRINGP (it->string)) { - new_face_id - = face_at_buffer_position (it->w, - IT_CHARPOS (*it), - &next_stop, - (IT_CHARPOS (*it) - + TEXT_PROP_DISTANCE_LIMIT), - false, it->base_face_id); - - /* Is this a start of a run of characters with box face? - Caveat: this can be called for a freshly initialized - iterator; face_id is -1 in this case. We know that the new - face will not change until limit, i.e. if the new face has a - box, all characters up to limit will have one. But, as - usual, we don't know whether limit is really the end. */ - if (new_face_id != it->face_id) - { - struct face *new_face = FACE_FROM_ID (it->f, new_face_id); - /* If it->face_id is -1, old_face below will be NULL, see - the definition of FACE_FROM_ID_OR_NULL. This will happen - if this is the initial call that gets the face. */ - struct face *old_face = FACE_FROM_ID_OR_NULL (it->f, it->face_id); - - /* If the value of face_id of the iterator is -1, we have to - look in front of IT's position and see whether there is a - face there that's different from new_face_id. */ - if (!old_face && IT_CHARPOS (*it) > BEG) - { - int prev_face_id = face_before_it_pos (it); - - old_face = FACE_FROM_ID_OR_NULL (it->f, prev_face_id); - } - - /* If the new face has a box, but the old face does not, - this is the start of a run of characters with box face, - i.e. this character has a shadow on the left side. */ - it->start_of_box_run_p = (new_face->box != FACE_NO_BOX - && (old_face == NULL || !old_face->box)); - it->face_box_p = new_face->box != FACE_NO_BOX; - } + return face_at_buffer_position (it->w, + IT_CHARPOS (*it), + &next_stop, + (IT_CHARPOS (*it) + + TEXT_PROP_DISTANCE_LIMIT), + false, it->base_face_id, + attr_filter); } else { @@ -4207,7 +4180,7 @@ handle_face_prop (struct it *it) Lisp_Object from_overlay = (it->current.overlay_string_index >= 0 ? it->string_overlays[it->current.overlay_string_index - % OVERLAY_STRING_CHUNK_SIZE] + % OVERLAY_STRING_CHUNK_SIZE] : Qnil); /* See if we got to this string directly or indirectly from @@ -4222,7 +4195,7 @@ handle_face_prop (struct it *it) if (it->stack[i].current.overlay_string_index >= 0) from_overlay = it->string_overlays[it->stack[i].current.overlay_string_index - % OVERLAY_STRING_CHUNK_SIZE]; + % OVERLAY_STRING_CHUNK_SIZE]; else if (! NILP (it->stack[i].from_overlay)) from_overlay = it->stack[i].from_overlay; @@ -4237,12 +4210,12 @@ handle_face_prop (struct it *it) only on text properties and ignores overlays. */ base_face_id = face_for_overlay_string (it->w, - IT_CHARPOS (*it), - &next_stop, - (IT_CHARPOS (*it) - + TEXT_PROP_DISTANCE_LIMIT), - false, - from_overlay); + IT_CHARPOS (*it), + &next_stop, + (IT_CHARPOS (*it) + + TEXT_PROP_DISTANCE_LIMIT), + false, + from_overlay); } else { @@ -4271,35 +4244,60 @@ handle_face_prop (struct it *it) : underlying_face_id (it); } - new_face_id = face_at_string_position (it->w, - it->string, - IT_STRING_CHARPOS (*it), - bufpos, - &next_stop, - base_face_id, false); + return face_at_string_position (it->w, + it->string, + IT_STRING_CHARPOS (*it), + bufpos, + &next_stop, + base_face_id, false, + attr_filter); + } // !STRINGP (it->string)) +} + - /* Is this a start of a run of characters with box? Caveat: - this can be called for a freshly allocated iterator; face_id - is -1 is this case. We know that the new face will not - change until the next check pos, i.e. if the new face has a - box, all characters up to that position will have a - box. But, as usual, we don't know whether that position - is really the end. */ - if (new_face_id != it->face_id) +/* Set up iterator IT from face properties at its current position. + Called from handle_stop. */ +static enum prop_handled +handle_face_prop (struct it *it) +{ + const int new_face_id = face_at_pos (it, 0); + + + /* Is this a start of a run of characters with box face? + Caveat: this can be called for a freshly initialized + iterator; face_id is -1 in this case. We know that the new + face will not change until limit, i.e. if the new face has a + box, all characters up to limit will have one. But, as + usual, we don't know whether limit is really the end. */ + if (new_face_id != it->face_id) + { + struct face *new_face = FACE_FROM_ID (it->f, new_face_id); + /* If it->face_id is -1, old_face below will be NULL, see + the definition of FACE_FROM_ID_OR_NULL. This will happen + if this is the initial call that gets the face. */ + struct face *old_face = FACE_FROM_ID_OR_NULL (it->f, it->face_id); + + /* If the value of face_id of the iterator is -1, we have to + look in front of IT's position and see whether there is a + face there that's different from new_face_id. */ + if (!STRINGP (it->string) + && !old_face + && IT_CHARPOS (*it) > BEG) { - struct face *new_face = FACE_FROM_ID (it->f, new_face_id); - struct face *old_face = FACE_FROM_ID_OR_NULL (it->f, it->face_id); + const int prev_face_id = face_before_it_pos (it); - /* If new face has a box but old face hasn't, this is the - start of a run of characters with box, i.e. it has a - shadow on the left side. */ - it->start_of_box_run_p - = new_face->box && (old_face == NULL || !old_face->box); - it->face_box_p = new_face->box != FACE_NO_BOX; + old_face = FACE_FROM_ID_OR_NULL (it->f, prev_face_id); } + + /* If the new face has a box, but the old face does not, + this is the start of a run of characters with box face, + i.e. this character has a shadow on the left side. */ + it->face_id = new_face_id; + it->start_of_box_run_p = (new_face->box != FACE_NO_BOX + && (old_face == NULL || !old_face->box)); + it->face_box_p = new_face->box != FACE_NO_BOX; } - it->face_id = new_face_id; return HANDLED_NORMALLY; } @@ -4310,7 +4308,7 @@ handle_face_prop (struct it *it) Otherwise, use the iterator's base_face_id. */ static int -underlying_face_id (struct it *it) +underlying_face_id (const struct it *it) { int face_id = it->base_face_id, i; @@ -4423,12 +4421,9 @@ face_before_or_after_it_pos (struct it *it, bool before_p) base_face_id = underlying_face_id (it); /* Get the face for ASCII, or unibyte. */ - face_id = face_at_string_position (it->w, - it->string, - charpos, - bufpos, - &next_check_charpos, - base_face_id, false); + face_id = face_at_string_position (it->w, it->string, charpos, + bufpos, &next_check_charpos, + base_face_id, false, 0); /* Correct the face for charsets different from ASCII. Do it for the multibyte case only. The face returned above is @@ -4527,7 +4522,7 @@ face_before_or_after_it_pos (struct it *it, bool before_p) face_id = face_at_buffer_position (it->w, CHARPOS (pos), &next_check_charpos, - limit, false, -1); + limit, false, -1, 0); /* Correct the face for charsets different from ASCII. Do it for the multibyte case only. The face returned above is @@ -7638,7 +7633,8 @@ get_next_display_element (struct it *it) next_face_id = face_at_string_position (it->w, base_string, CHARPOS (pos), 0, - &ignore, face_id, false); + &ignore, face_id, + false, 0); it->end_of_box_run_p = (FACE_FROM_ID (it->f, next_face_id)->box == FACE_NO_BOX); @@ -7649,10 +7645,11 @@ get_next_display_element (struct it *it) else { next_face_id = - face_at_buffer_position (it->w, CHARPOS (pos), &ignore, + face_at_buffer_position (it->w, CHARPOS (pos), + &ignore, CHARPOS (pos) + TEXT_PROP_DISTANCE_LIMIT, - false, -1); + false, -1, 0); it->end_of_box_run_p = (FACE_FROM_ID (it->f, next_face_id)->box == FACE_NO_BOX); @@ -21366,80 +21363,78 @@ compute_line_metrics (struct it *it) static bool append_space_for_newline (struct it *it, bool default_face_p) { -#ifdef HAVE_WINDOW_SYSTEM - if (FRAME_WINDOW_P (it->f)) + int n = it->glyph_row->used[TEXT_AREA]; + + if (it->glyph_row->glyphs[TEXT_AREA] + n + < it->glyph_row->glyphs[1 + TEXT_AREA]) { - int n = it->glyph_row->used[TEXT_AREA]; - - if (it->glyph_row->glyphs[TEXT_AREA] + n - < it->glyph_row->glyphs[1 + TEXT_AREA]) - { - /* Save some values that must not be changed. - Must save IT->c and IT->len because otherwise - ITERATOR_AT_END_P wouldn't work anymore after - append_space_for_newline has been called. */ - enum display_element_type saved_what = it->what; - int saved_c = it->c, saved_len = it->len; - int saved_char_to_display = it->char_to_display; - int saved_x = it->current_x; - int saved_face_id = it->face_id; - bool saved_box_end = it->end_of_box_run_p; - struct text_pos saved_pos; - Lisp_Object saved_object; - struct face *face; + /* Save some values that must not be changed. + Must save IT->c and IT->len because otherwise + ITERATOR_AT_END_P wouldn't work anymore after + append_space_for_newline has been called. */ + enum display_element_type saved_what = it->what; + int saved_c = it->c, saved_len = it->len; + int saved_char_to_display = it->char_to_display; + int saved_x = it->current_x; + const int saved_face_id = it->face_id; + bool saved_box_end = it->end_of_box_run_p; + struct text_pos saved_pos = it->position; + Lisp_Object saved_object = it->object; + struct face *face; - saved_object = it->object; - saved_pos = it->position; + it->what = IT_CHARACTER; + memset (&it->position, 0, sizeof it->position); + it->object = Qnil; + it->len = 1; - it->what = IT_CHARACTER; - memset (&it->position, 0, sizeof it->position); - it->object = Qnil; - it->len = 1; + int char_width = 1; - int local_default_face_id = + if (default_face_p +#ifdef HAVE_WINDOW_SYSTEM + || FRAME_WINDOW_P (it->f) +#endif + ) + { + const int local_default_face_id = lookup_basic_face (it->w, it->f, DEFAULT_FACE_ID); struct face* default_face = FACE_FROM_ID_OR_NULL (it->f, local_default_face_id); - /* Corner case for when display-fill-column-indicator-mode - is active and the extra character should be added in the - same place than the line. */ - int indicator_column = (it->w->pseudo_window_p == 0 - ? fill_column_indicator_column (it) - : -1); - if (indicator_column >= 0) - { - struct font *font = (default_face->font - ? default_face->font - : FRAME_FONT (it->f)); - const int char_width = (font->average_width - ? font->average_width - : font->space_width); - int column_x; - - if (!INT_MULTIPLY_WRAPV (indicator_column, char_width, - &column_x) - && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, - &column_x) - && it->current_x == column_x) - { - it->c = it->char_to_display - = XFIXNAT (Vdisplay_fill_column_indicator_character); - it->face_id - = merge_faces (it->w, Qfill_column_indicator, - 0, saved_face_id); - face = FACE_FROM_ID (it->f, it->face_id); - goto produce_glyphs; - } +#ifdef HAVE_WINDOW_SYSTEM + if (FRAME_WINDOW_P (it->f)) + { + struct font *font = (default_face->font + ? default_face->font + : FRAME_FONT (it->f)); + char_width = (font->average_width + ? font->average_width + : font->space_width); } +#endif + if (default_face_p) + it->face_id = local_default_face_id; + } + /* Corner case for when display-fill-column-indicator-mode + is active and the extra character should be added in the + same place than the line. */ + + const int indicator_column = + fill_column_indicator_column (it, char_width); + if (it->current_x == indicator_column) + { + it->c = it->char_to_display + = XFIXNAT (Vdisplay_fill_column_indicator_character); + it->face_id + = merge_faces (it->w, Qfill_column_indicator, + 0, saved_face_id); + face = FACE_FROM_ID (it->f, it->face_id); + } + else + { it->c = it->char_to_display = ' '; /* If the default face was remapped, be sure to use the remapped face for the appended newline. */ - if (default_face_p) - it->face_id = local_default_face_id; - else if (it->face_before_selective_p) - it->face_id = it->saved_face_id; face = FACE_FROM_ID (it->f, it->face_id); it->face_id = FACE_FOR_CHAR (it->f, face, 0, -1, Qnil); @@ -21453,10 +21448,11 @@ append_space_for_newline (struct it *it, bool default_face_p) so leave the box flag set. */ && saved_x + FRAME_COLUMN_WIDTH (it->f) < it->last_visible_x) it->end_of_box_run_p = false; - - produce_glyphs: - PRODUCE_GLYPHS (it); - + } + PRODUCE_GLYPHS (it); +#ifdef HAVE_WINDOW_SYSTEM + if (FRAME_WINDOW_P (it->f)) + { /* Make sure this space glyph has the right ascent and descent values, or else cursor at end of line will look funny, and height of empty lines will be incorrect. */ @@ -21477,8 +21473,8 @@ append_space_for_newline (struct it *it, bool default_face_p) gui_produce_glyph for newline characters. */ height = get_it_property (it, Qline_height); if (CONSP (height) - && CONSP (XCDR (height)) - && NILP (XCDR (XCDR (height)))) + && CONSP (XCDR (height)) + && NILP (XCDR (XCDR (height)))) { total_height = XCAR (XCDR (height)); height = XCAR (height); @@ -21507,12 +21503,12 @@ append_space_for_newline (struct it *it, bool default_face_p) if (!NILP (total_height)) spacing = calc_line_height_property (it, total_height, font, - boff, false); + boff, false); else { spacing = get_it_property (it, Qline_spacing); spacing = calc_line_height_property (it, spacing, font, - boff, false); + boff, false); } if (FIXNUMP (spacing)) { @@ -21535,22 +21531,21 @@ append_space_for_newline (struct it *it, bool default_face_p) g->ascent = it->max_ascent; g->descent = it->max_descent; - - it->override_ascent = -1; - it->constrain_row_ascent_descent_p = false; - it->current_x = saved_x; - it->object = saved_object; - it->position = saved_pos; - it->what = saved_what; - it->face_id = saved_face_id; - it->len = saved_len; - it->c = saved_c; - it->char_to_display = saved_char_to_display; - it->end_of_box_run_p = saved_box_end; - return true; } +#endif /* HAVE_WINDOW_SYSTEM */ + it->override_ascent = -1; + it->constrain_row_ascent_descent_p = false; + it->current_x = saved_x; + it->object = saved_object; + it->position = saved_pos; + it->what = saved_what; + it->face_id = saved_face_id; + it->len = saved_len; + it->c = saved_c; + it->char_to_display = saved_char_to_display; + it->end_of_box_run_p = saved_box_end; + return true; } -#endif return false; } @@ -21566,7 +21561,6 @@ append_space_for_newline (struct it *it, bool default_face_p) static void extend_face_to_end_of_line (struct it *it) { - struct face *face; struct frame *f = it->f; /* If line is already filled, do nothing. Non window-system frames @@ -21584,12 +21578,17 @@ extend_face_to_end_of_line (struct it *it) || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)) return; - /* Face extension extends the background and box of IT->face_id + const int extend_face_id = (it->face_id == DEFAULT_FACE_ID + || it->s != NULL) + ? DEFAULT_FACE_ID + : face_at_pos (it, LFACE_EXTEND_INDEX); + + /* Face extension extends the background and box of IT->extend_face_id to the end of the line. If the background equals the background of the frame, we don't have to do anything. */ - face = FACE_FROM_ID (f, (it->face_before_selective_p - ? it->saved_face_id - : it->face_id)); + struct face *face = FACE_FROM_ID (f, (it->face_before_selective_p + ? it->saved_face_id + : extend_face_id)); if (FRAME_WINDOW_P (f) && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row) @@ -21612,9 +21611,7 @@ extend_face_to_end_of_line (struct it *it) that the character will always be single byte in unibyte text. */ if (!ASCII_CHAR_P (it->c)) - { it->face_id = FACE_FOR_CHAR (f, face, 0, -1, Qnil); - } /* The default face, possibly remapped. */ struct face *default_face = @@ -21665,79 +21662,81 @@ extend_face_to_end_of_line (struct it *it) /* Display fill column indicator if not in modeline or toolbar and display fill column indicator mode is active. */ - int indicator_column = (it->w->pseudo_window_p == 0 - ? fill_column_indicator_column (it) - : -1); - if (indicator_column >= 0) + + struct font *font = (default_face->font + ? default_face->font + : FRAME_FONT (f)); + + const int char_width = (font->average_width + ? font->average_width + : font->space_width); + + const int indicator_column = + fill_column_indicator_column (it, char_width); + + const char saved_char = it->char_to_display; + const struct text_pos saved_pos = it->position; + const bool saved_avoid_cursor = it->avoid_cursor_p; + const bool saved_box_start = it->start_of_box_run_p; + Lisp_Object save_object = it->object; + const int saved_face_id = it->face_id; + + it->face_id = extend_face_id; + it->avoid_cursor_p = true; + it->object = Qnil; + + if (indicator_column >= 0 + && indicator_column > it->current_x + && indicator_column < it->last_visible_x) { - struct font *font = (default_face->font - ? default_face->font - : FRAME_FONT (f)); - const int char_width = (font->average_width - ? font->average_width - : font->space_width); - int column_x; - - if (!INT_MULTIPLY_WRAPV (indicator_column, char_width, &column_x) - && !INT_ADD_WRAPV (it->lnum_pixel_width, column_x, &column_x) - && column_x >= it->current_x - && column_x <= it->last_visible_x) - { - const char saved_char = it->char_to_display; - const struct text_pos saved_pos = it->position; - const bool saved_avoid_cursor = it->avoid_cursor_p; - const int saved_face_id = it->face_id; - const bool saved_box_start = it->start_of_box_run_p; - Lisp_Object save_object = it->object; - - /* The stretch width needs to considet the latter - added glyph. */ - const int stretch_width - = column_x - it->current_x - char_width; - - memset (&it->position, 0, sizeof it->position); - it->avoid_cursor_p = true; - it->object = Qnil; - - /* Only generate a stretch glyph if there is distance - between current_x and and the indicator position. */ - if (stretch_width > 0) - { - int stretch_ascent = (((it->ascent + it->descent) - * FONT_BASE (font)) / FONT_HEIGHT (font)); - append_stretch_glyph (it, Qnil, stretch_width, - it->ascent + it->descent, - stretch_ascent); - } - /* Generate the glyph indicator only if - append_space_for_newline didn't already. */ - if (it->current_x < column_x) - { - it->char_to_display - = XFIXNAT (Vdisplay_fill_column_indicator_character); - it->face_id - = merge_faces (it->w, Qfill_column_indicator, - 0, saved_face_id); - PRODUCE_GLYPHS (it); - } - - /* Restore the face after the indicator was generated. */ - it->face_id = saved_face_id; - - /* If there is space after the indicator generate an - extra empty glyph to restore the face. Issue was - observed in X systems. */ - it->char_to_display = ' '; - PRODUCE_GLYPHS (it); - - it->char_to_display = saved_char; - it->position = saved_pos; - it->avoid_cursor_p = saved_avoid_cursor; - it->start_of_box_run_p = saved_box_start; - it->object = save_object; - } + /* Here we substract char_width because we want the + column indicator in the column INDICATOR_COLUMN, not + after it. */ + const int stretch_width = + indicator_column - it->current_x - char_width; + + memset (&it->position, 0, sizeof it->position); + + /* Only generate a stretch glyph if there is distance + between current_x and and the indicator position. */ + if (stretch_width > 0) + { + int stretch_ascent = (((it->ascent + it->descent) + * FONT_BASE (font)) / FONT_HEIGHT (font)); + append_stretch_glyph (it, Qnil, stretch_width, + it->ascent + it->descent, + stretch_ascent); + } + + /* Generate the glyph indicator only if + append_space_for_newline didn't already. */ + if (it->current_x < indicator_column) + { + const int save_face_id = it->face_id; + it->char_to_display + = XFIXNAT (Vdisplay_fill_column_indicator_character); + it->face_id + = merge_faces (it->w, Qfill_column_indicator, + 0, extend_face_id); + PRODUCE_GLYPHS (it); + it->face_id = save_face_id; + } } + + /* If there is space after the indicator generate an + extra empty glyph to restore the face. Issue was + observed in X systems. */ + it->char_to_display = ' '; + PRODUCE_GLYPHS (it); + + it->char_to_display = saved_char; + it->position = saved_pos; + it->avoid_cursor_p = saved_avoid_cursor; + it->start_of_box_run_p = saved_box_start; + it->object = save_object; + it->face_id = saved_face_id; + } if (it->glyph_row->reversed_p) { @@ -21783,10 +21782,9 @@ extend_face_to_end_of_line (struct it *it) /* The last row's stretch glyph should get the default face, to avoid painting the rest of the window with the region face, if the region ends at ZV. */ - if (it->glyph_row->ends_at_zv_p) - it->face_id = default_face->id; - else - it->face_id = face->id; + it->face_id = (it->glyph_row->ends_at_zv_p ? + default_face->id : face->id); + it->start_of_box_run_p = false; append_stretch_glyph (it, Qnil, stretch_width, it->ascent + it->descent, stretch_ascent); @@ -21808,14 +21806,11 @@ extend_face_to_end_of_line (struct it *it) { /* Save some values that must not be changed. */ int saved_x = it->current_x; - struct text_pos saved_pos; - Lisp_Object saved_object; + struct text_pos saved_pos = it->position; + Lisp_Object saved_object = it->object;; enum display_element_type saved_what = it->what; int saved_face_id = it->face_id; - saved_object = it->object; - saved_pos = it->position; - it->what = IT_CHARACTER; memset (&it->position, 0, sizeof it->position); it->object = Qnil; @@ -21854,34 +21849,31 @@ extend_face_to_end_of_line (struct it *it) /* The last row's blank glyphs should get the default face, to avoid painting the rest of the window with the region face, if the region ends at ZV. */ - if (it->glyph_row->ends_at_zv_p) - it->face_id = default_face->id; - else - it->face_id = face->id; + it->face_id = (it->glyph_row->ends_at_zv_p ? + default_face->id : face->id); /* Display fill-column indicator if needed. */ - int indicator_column = fill_column_indicator_column (it); - if (indicator_column >= 0 - && INT_ADD_WRAPV (it->lnum_pixel_width, indicator_column, - &indicator_column)) - indicator_column = -1; + /* We need to subtract 1 to the indicator_column here because we + will add the indicator IN the column indicator number, not + after it. We compare the variable it->current_x before + producing the glyph. When FRAME_WINDOW_P we substract + CHAR_WIDTH calculating STRETCH_WIDTH for the same reason. */ + const int indicator_column = + fill_column_indicator_column (it, 1) - 1; do { - int saved_face_id; - bool indicate = it->current_x == indicator_column; - if (indicate) + if (it->current_x != indicator_column) + PRODUCE_GLYPHS (it); + else { - saved_face_id = it->face_id; + int saved_face_id = it->face_id; it->face_id - = merge_faces (it->w, Qfill_column_indicator, 0, saved_face_id); + = merge_faces (it->w, Qfill_column_indicator, 0, extend_face_id); it->c = it->char_to_display = XFIXNAT (Vdisplay_fill_column_indicator_character); - } - PRODUCE_GLYPHS (it); + PRODUCE_GLYPHS (it); - if (indicate) - { it->face_id = saved_face_id; it->c = it->char_to_display = ' '; } @@ -26581,8 +26573,8 @@ display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_st /* Initialize the iterator IT for iteration over STRING beginning with index START. */ - reseat_to_string (it, NILP (lisp_string) ? string : NULL, lisp_string, start, - precision, field_width, multibyte); + reseat_to_string (it, NILP (lisp_string) ? string : NULL, lisp_string, + start, precision, field_width, multibyte); if (string && STRINGP (lisp_string)) /* LISP_STRING is the one returned by decode_mode_spec. We should ignore its text properties. */ @@ -26597,7 +26589,7 @@ display_string (const char *string, Lisp_Object lisp_string, Lisp_Object face_st it->face_id = face_at_string_position (it->w, face_string, face_string_pos, - 0, &endptr, it->base_face_id, false); + 0, &endptr, it->base_face_id, false, 0); face = FACE_FROM_ID (it->f, it->face_id); it->face_box_p = face->box != FACE_NO_BOX; } @@ -28502,7 +28494,7 @@ font_for_underline_metrics (struct glyph_string *s) for (g = s->first_glyph - 1; g >= g0; g--) { struct face *prev_face = FACE_FROM_ID (s->f, g->face_id); - if (!(prev_face && prev_face->underline_p)) + if (!(prev_face && prev_face->underline != FACE_NO_UNDERLINE)) break; } @@ -32068,7 +32060,7 @@ mouse_face_from_buffer_pos (Lisp_Object window, hlinfo->mouse_face_face_id = face_at_buffer_position (w, mouse_charpos, &ignore, mouse_charpos + 1, - !hlinfo->mouse_face_hidden, -1); + !hlinfo->mouse_face_hidden, -1, 0); show_mouse_face (hlinfo, DRAW_MOUSE_FACE); } @@ -32757,11 +32749,10 @@ note_mode_line_or_margin_highlight (Lisp_Object window, int x, int y, hlinfo->mouse_face_past_end = false; hlinfo->mouse_face_window = window; - hlinfo->mouse_face_face_id = face_at_string_position (w, string, - charpos, - 0, &ignore, - glyph->face_id, - true); + hlinfo->mouse_face_face_id = + face_at_string_position (w, string, charpos, 0, &ignore, + glyph->face_id, true, 0); + show_mouse_face (hlinfo, DRAW_MOUSE_FACE); mouse_face_shown = true; @@ -33187,7 +33178,7 @@ note_mouse_highlight (struct frame *f, int x, int y) hlinfo->mouse_face_window = window; hlinfo->mouse_face_face_id = face_at_string_position (w, object, pos, 0, &ignore, - glyph->face_id, true); + glyph->face_id, true, 0); show_mouse_face (hlinfo, DRAW_MOUSE_FACE); cursor = No_Cursor; } diff --git a/src/xfaces.c b/src/xfaces.c index 0c99eea1567..5a741ae8cc6 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -347,7 +347,8 @@ static struct face_cache *make_face_cache (struct frame *); static void free_face_cache (struct face_cache *); static bool merge_face_ref (struct window *w, struct frame *, Lisp_Object, Lisp_Object *, - bool, struct named_merge_point *); + bool, struct named_merge_point *, + enum lface_attribute_index); static int color_distance (Emacs_Color *x, Emacs_Color *y); #ifdef HAVE_WINDOW_SYSTEM @@ -1209,7 +1210,7 @@ free_face_colors (struct frame *f, struct face *face) IF_DEBUG (--ncolors_allocated); } - if (face->underline_p + if (face->underline && !face->underline_defaulted_p) { x_free_colors (f, &face->underline_color, 1); @@ -1590,6 +1591,7 @@ the WIDTH times as wide as FACE on FRAME. */) #define LFACE_FONT(LFACE) AREF ((LFACE), LFACE_FONT_INDEX) #define LFACE_INHERIT(LFACE) AREF ((LFACE), LFACE_INHERIT_INDEX) #define LFACE_FONTSET(LFACE) AREF ((LFACE), LFACE_FONTSET_INDEX) +#define LFACE_EXTEND(LFACE) AREF ((LFACE), LFACE_EXTEND_INDEX) #define LFACE_DISTANT_FOREGROUND(LFACE) \ AREF ((LFACE), LFACE_DISTANT_FOREGROUND_INDEX) @@ -1633,6 +1635,10 @@ check_lface_attrs (Lisp_Object attrs[LFACE_VECTOR_SIZE]) || SYMBOLP (attrs[LFACE_UNDERLINE_INDEX]) || STRINGP (attrs[LFACE_UNDERLINE_INDEX]) || CONSP (attrs[LFACE_UNDERLINE_INDEX])); + eassert (UNSPECIFIEDP (attrs[LFACE_EXTEND_INDEX]) + || IGNORE_DEFFACE_P (attrs[LFACE_EXTEND_INDEX]) + || SYMBOLP (attrs[LFACE_EXTEND_INDEX]) + || STRINGP (attrs[LFACE_EXTEND_INDEX])); eassert (UNSPECIFIEDP (attrs[LFACE_OVERLINE_INDEX]) || IGNORE_DEFFACE_P (attrs[LFACE_OVERLINE_INDEX]) || SYMBOLP (attrs[LFACE_OVERLINE_INDEX]) @@ -1905,7 +1911,8 @@ get_lface_attributes (struct window *w, attrs[i] = Qunspecified; return merge_face_ref (w, f, XCDR (face_remapping), attrs, - signal_p, named_merge_points); + signal_p, named_merge_points, + 0); } } @@ -2060,7 +2067,8 @@ merge_face_vectors (struct window *w, if (!UNSPECIFIEDP (from[LFACE_INHERIT_INDEX]) && !NILP (from[LFACE_INHERIT_INDEX])) merge_face_ref (w, f, from[LFACE_INHERIT_INDEX], - to, false, named_merge_points); + to, false, named_merge_points, + 0); if (FONT_SPEC_P (from[LFACE_FONT_INDEX])) { @@ -2126,7 +2134,8 @@ merge_face_vectors (struct window *w, static bool merge_named_face (struct window *w, struct frame *f, Lisp_Object face_name, Lisp_Object *to, - struct named_merge_point *named_merge_points) + struct named_merge_point *named_merge_points, + enum lface_attribute_index attr_filter) { struct named_merge_point named_merge_point; @@ -2136,9 +2145,13 @@ merge_named_face (struct window *w, { Lisp_Object from[LFACE_VECTOR_SIZE]; bool ok = get_lface_attributes (w, f, face_name, from, false, - named_merge_points); + named_merge_points); - if (ok) + eassert (attr_filter < LFACE_VECTOR_SIZE); + + if (ok && (attr_filter == 0 + || (!NILP (from[attr_filter]) + && !UNSPECIFIEDP (from[attr_filter])))) merge_face_vectors (w, f, from, to, named_merge_points); return ok; @@ -2269,6 +2282,11 @@ filter_face_ref (Lisp_Object face_ref, of ERR_MSGS). Use NAMED_MERGE_POINTS to detect loops in face inheritance or list structure; it may be 0 for most callers. + ATTR_FILTER is the index of a parameter that conditions the merging + for named faces (case 1) to only the face_ref where + lface[merge_face_ref] is non-nil. To merge unconditionally set this + value to 0. + FACE_REF may be a single face specification or a list of such specifications. Each face specification can be: @@ -2297,7 +2315,8 @@ filter_face_ref (Lisp_Object face_ref, static bool merge_face_ref (struct window *w, struct frame *f, Lisp_Object face_ref, Lisp_Object *to, - bool err_msgs, struct named_merge_point *named_merge_points) + bool err_msgs, struct named_merge_point *named_merge_points, + enum lface_attribute_index attr_filter) { bool ok = true; /* Succeed without an error? */ Lisp_Object filtered_face_ref; @@ -2509,7 +2528,15 @@ merge_face_ref (struct window *w, /* This is not really very useful; it's just like a normal face reference. */ if (! merge_face_ref (w, f, value, to, - err_msgs, named_merge_points)) + err_msgs, named_merge_points, + attr_filter)) + err = true; + } + else if (EQ (keyword, QCextend)) + { + if (EQ (value, Qt) || NILP (value)) + to[LFACE_EXTEND_INDEX] = value; + else err = true; } else @@ -2532,16 +2559,19 @@ merge_face_ref (struct window *w, Lisp_Object next = XCDR (face_ref); if (! NILP (next)) - ok = merge_face_ref (w, f, next, to, err_msgs, named_merge_points); + ok = merge_face_ref (w, f, next, to, err_msgs, + named_merge_points, attr_filter); - if (! merge_face_ref (w, f, first, to, err_msgs, named_merge_points)) + if (! merge_face_ref (w, f, first, to, err_msgs, + named_merge_points, attr_filter)) ok = false; } } else { /* FACE_REF ought to be a face name. */ - ok = merge_named_face (w, f, face_ref, to, named_merge_points); + ok = merge_named_face (w, f, face_ref, to, named_merge_points, + attr_filter); if (!ok && err_msgs) add_to_log ("Invalid face reference: %s", face_ref); } @@ -3030,6 +3060,17 @@ FRAME 0 means change the face on all frames, and change the default old_value = LFACE_INVERSE (lface); ASET (lface, LFACE_INVERSE_INDEX, value); } + else if (EQ (attr, QCextend)) + { + if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value)) + { + CHECK_SYMBOL (value); + if (!EQ (value, Qt) && !NILP (value)) + signal_error ("Invalid extend face attribute value", value); + } + old_value = LFACE_EXTEND (lface); + ASET (lface, LFACE_EXTEND_INDEX, value); + } else if (EQ (attr, QCforeground)) { /* Compatibility with 20.x. */ @@ -3503,7 +3544,9 @@ DEFUN ("internal-set-lisp-face-attribute-from-resource", value = face_boolean_x_resource_value (value, true); else if (EQ (attr, QCweight) || EQ (attr, QCslant) || EQ (attr, QCwidth)) value = intern (SSDATA (value)); - else if (EQ (attr, QCreverse_video) || EQ (attr, QCinverse_video)) + else if (EQ (attr, QCreverse_video) + || EQ (attr, QCinverse_video) + || EQ (attr, QCextend)) value = face_boolean_x_resource_value (value, true); else if (EQ (attr, QCunderline) || EQ (attr, QCoverline) @@ -3727,6 +3770,8 @@ frames). If FRAME is omitted or nil, use the selected frame. */) value = LFACE_SWIDTH (lface); else if (EQ (keyword, QCinherit)) value = LFACE_INHERIT (lface); + else if (EQ (keyword, QCextend)) + value = LFACE_EXTEND (lface); else if (EQ (keyword, QCfont)) value = LFACE_FONT (lface); else if (EQ (keyword, QCfontset)) @@ -3754,7 +3799,9 @@ Value is nil if ATTR doesn't have a discrete set of valid values. */) if (EQ (attr, QCunderline) || EQ (attr, QCoverline) || EQ (attr, QCstrike_through) - || EQ (attr, QCinverse_video) || EQ (attr, QCreverse_video)) + || EQ (attr, QCinverse_video) + || EQ (attr, QCreverse_video) + || EQ (attr, QCextend)) result = list2 (Qt, Qnil); return result; @@ -4505,7 +4552,8 @@ lookup_face (struct frame *f, Lisp_Object *attr) suitable face is found, realize a new one. */ int -face_for_font (struct frame *f, Lisp_Object font_object, struct face *base_face) +face_for_font (struct frame *f, Lisp_Object font_object, + struct face *base_face) { struct face_cache *cache = FRAME_FACE_CACHE (f); unsigned hash; @@ -4740,7 +4788,7 @@ DEFUN ("face-attributes-as-vector", Fface_attributes_as_vector, Lisp_Object lface = make_vector (LFACE_VECTOR_SIZE, Qunspecified); merge_face_ref (NULL, XFRAME (selected_frame), plist, XVECTOR (lface)->contents, - true, 0); + true, NULL, 0); return lface; } @@ -4784,6 +4832,9 @@ gui_supports_face_attributes_p (struct frame *f, || (!UNSPECIFIEDP (attrs[LFACE_INVERSE_INDEX]) && face_attr_equal_p (attrs[LFACE_INVERSE_INDEX], def_attrs[LFACE_INVERSE_INDEX])) + || (!UNSPECIFIEDP (attrs[LFACE_EXTEND_INDEX]) + && face_attr_equal_p (attrs[LFACE_EXTEND_INDEX], + def_attrs[LFACE_EXTEND_INDEX])) || (!UNSPECIFIEDP (attrs[LFACE_FOREGROUND_INDEX]) && face_attr_equal_p (attrs[LFACE_FOREGROUND_INDEX], def_attrs[LFACE_FOREGROUND_INDEX])) @@ -5094,7 +5145,7 @@ face for italic. */) for (i = 0; i < LFACE_VECTOR_SIZE; i++) attrs[i] = Qunspecified; - merge_face_ref (NULL, f, attributes, attrs, true, 0); + merge_face_ref (NULL, f, attributes, attrs, true, NULL, 0); def_face = FACE_FROM_ID_OR_NULL (f, DEFAULT_FACE_ID); if (def_face == NULL) @@ -5362,6 +5413,9 @@ realize_default_face (struct frame *f) ASET (lface, LFACE_FONTSET_INDEX, Qnil); } + if (UNSPECIFIEDP (LFACE_EXTEND (lface))) + ASET (lface, LFACE_EXTEND_INDEX, Qnil); + if (UNSPECIFIEDP (LFACE_UNDERLINE (lface))) ASET (lface, LFACE_UNDERLINE_INDEX, Qnil); @@ -5698,16 +5752,14 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] if (EQ (underline, Qt)) { /* Use default color (same as foreground color). */ - face->underline_p = true; - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; face->underline_defaulted_p = true; face->underline_color = 0; } else if (STRINGP (underline)) { /* Use specified color. */ - face->underline_p = true; - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; face->underline_defaulted_p = false; face->underline_color = load_color (f, face, underline, @@ -5715,7 +5767,7 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] } else if (NILP (underline)) { - face->underline_p = false; + face->underline = FACE_NO_UNDERLINE; face->underline_defaulted_p = false; face->underline_color = 0; } @@ -5723,10 +5775,9 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] { /* `(:color COLOR :style STYLE)'. STYLE being one of `line' or `wave'. */ - face->underline_p = true; + face->underline = FACE_UNDER_LINE; face->underline_color = 0; face->underline_defaulted_p = true; - face->underline_type = FACE_UNDER_LINE; /* FIXME? This is also not robust about checking the precise form. See comments in Finternal_set_lisp_face_attribute. */ @@ -5759,9 +5810,9 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] else if (EQ (keyword, QCstyle)) { if (EQ (value, Qline)) - face->underline_type = FACE_UNDER_LINE; + face->underline = FACE_UNDER_LINE; else if (EQ (value, Qwave)) - face->underline_type = FACE_UNDER_WAVE; + face->underline = FACE_UNDER_WAVE; } } } @@ -5980,7 +6031,7 @@ compute_char_face (struct frame *f, int ch, Lisp_Object prop) Lisp_Object attrs[LFACE_VECTOR_SIZE]; struct face *default_face = FACE_FROM_ID (f, DEFAULT_FACE_ID); memcpy (attrs, default_face->lface, sizeof attrs); - merge_face_ref (NULL, f, prop, attrs, true, 0); + merge_face_ref (NULL, f, prop, attrs, true, NULL, 0); face_id = lookup_face (f, attrs); } @@ -5992,6 +6043,8 @@ compute_char_face (struct frame *f, int ch, Lisp_Object prop) which a different face is needed, as far as text properties and overlays are concerned. W is a window displaying current_buffer. + ATTR_FILTER is passed merge_face_ref. + REGION_BEG, REGION_END delimit the region, so it can be highlighted. @@ -6011,7 +6064,8 @@ compute_char_face (struct frame *f, int ch, Lisp_Object prop) int face_at_buffer_position (struct window *w, ptrdiff_t pos, ptrdiff_t *endptr, ptrdiff_t limit, - bool mouse, int base_face_id) + bool mouse, int base_face_id, + enum lface_attribute_index attr_filter) { struct frame *f = XFRAME (w->frame); Lisp_Object attrs[LFACE_VECTOR_SIZE]; @@ -6080,11 +6134,11 @@ face_at_buffer_position (struct window *w, ptrdiff_t pos, } /* Begin with attributes from the default face. */ - memcpy (attrs, default_face->lface, sizeof attrs); + memcpy (attrs, default_face->lface, sizeof(attrs)); /* Merge in attributes specified via text properties. */ if (!NILP (prop)) - merge_face_ref (w, f, prop, attrs, true, 0); + merge_face_ref (w, f, prop, attrs, true, NULL, attr_filter); /* Now merge the overlay data. */ noverlays = sort_overlays (overlay_vec, noverlays, w); @@ -6104,7 +6158,7 @@ face_at_buffer_position (struct window *w, ptrdiff_t pos, so discard the mouse-face text property, if any, and use the overlay property instead. */ memcpy (attrs, default_face->lface, sizeof attrs); - merge_face_ref (w, f, prop, attrs, true, 0); + merge_face_ref (w, f, prop, attrs, true, NULL, attr_filter); } oend = OVERLAY_END (overlay_vec[i]); @@ -6121,8 +6175,9 @@ face_at_buffer_position (struct window *w, ptrdiff_t pos, ptrdiff_t oendpos; prop = Foverlay_get (overlay_vec[i], propname); + if (!NILP (prop)) - merge_face_ref (w, f, prop, attrs, true, 0); + merge_face_ref (w, f, prop, attrs, true, NULL, attr_filter); oend = OVERLAY_END (overlay_vec[i]); oendpos = OVERLAY_POSITION (oend); @@ -6188,7 +6243,7 @@ face_for_overlay_string (struct window *w, ptrdiff_t pos, /* Merge in attributes specified via text properties. */ if (!NILP (prop)) - merge_face_ref (w, f, prop, attrs, true, 0); + merge_face_ref (w, f, prop, attrs, true, NULL, 0); *endptr = endpos; @@ -6221,9 +6276,10 @@ face_for_overlay_string (struct window *w, ptrdiff_t pos, int face_at_string_position (struct window *w, Lisp_Object string, - ptrdiff_t pos, ptrdiff_t bufpos, - ptrdiff_t *endptr, enum face_id base_face_id, - bool mouse_p) + ptrdiff_t pos, ptrdiff_t bufpos, + ptrdiff_t *endptr, enum face_id base_face_id, + bool mouse_p, + enum lface_attribute_index attr_filter) { Lisp_Object prop, position, end, limit; struct frame *f = XFRAME (WINDOW_FRAME (w)); @@ -6267,7 +6323,7 @@ face_at_string_position (struct window *w, Lisp_Object string, /* Merge in attributes specified via text properties. */ if (!NILP (prop)) - merge_face_ref (w, f, prop, attrs, true, 0); + merge_face_ref (w, f, prop, attrs, true, NULL, attr_filter); /* Look up a realized face with the given face attributes, or realize a new one for ASCII characters. */ @@ -6296,9 +6352,8 @@ merge_faces (struct window *w, Lisp_Object face_name, int face_id, { struct frame *f = WINDOW_XFRAME (w); Lisp_Object attrs[LFACE_VECTOR_SIZE]; - struct face *base_face; + struct face *base_face = FACE_FROM_ID_OR_NULL (f, base_face_id); - base_face = FACE_FROM_ID_OR_NULL (f, base_face_id); if (!base_face) return base_face_id; @@ -6318,17 +6373,19 @@ merge_faces (struct window *w, Lisp_Object face_name, int face_id, if (!NILP (face_name)) { - if (!merge_named_face (w, f, face_name, attrs, 0)) + if (!merge_named_face (w, f, face_name, attrs, NULL, 0)) return base_face_id; } else { - struct face *face; if (face_id < 0) return base_face_id; - face = FACE_FROM_ID_OR_NULL (f, face_id); + + struct face *face = FACE_FROM_ID_OR_NULL (f, face_id); + if (!face) return base_face_id; + merge_face_vectors (w, f, face->lface, attrs, 0); } @@ -6416,7 +6473,7 @@ dump_realized_face (struct face *face) #endif fprintf (stderr, "fontset: %d\n", face->fontset); fprintf (stderr, "underline: %d (%s)\n", - face->underline_p, + face->underline, SDATA (Fsymbol_name (face->lface[LFACE_UNDERLINE_INDEX]))); fprintf (stderr, "hash: %" PRIuPTR "\n", face->hash); } @@ -6541,6 +6598,7 @@ syms_of_xfaces (void) DEFSYM (QCstrike_through, ":strike-through"); DEFSYM (QCbox, ":box"); DEFSYM (QCinherit, ":inherit"); + DEFSYM (QCextend, ":extend"); /* Symbols used for Lisp face attribute values. */ DEFSYM (QCcolor, ":color"); diff --git a/src/xterm.c b/src/xterm.c index b49c9d6893a..5d8b1482a6d 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -3813,9 +3813,9 @@ x_draw_glyph_string (struct glyph_string *s) if (!s->for_overlaps) { /* Draw underline. */ - if (s->face->underline_p) + if (s->face->underline) { - if (s->face->underline_type == FACE_UNDER_WAVE) + if (s->face->underline == FACE_UNDER_WAVE) { if (s->face->underline_defaulted_p) x_draw_underwave (s); @@ -3829,13 +3829,13 @@ x_draw_glyph_string (struct glyph_string *s) XSetForeground (display, s->gc, xgcv.foreground); } } - else if (s->face->underline_type == FACE_UNDER_LINE) + else if (s->face->underline == FACE_UNDER_LINE) { unsigned long thickness, position; int y; - if (s->prev && s->prev->face->underline_p - && s->prev->face->underline_type == FACE_UNDER_LINE) + if (s->prev && + s->prev->face->underline == FACE_UNDER_LINE) { /* We use the same underline style as the previous one. */ thickness = s->prev->underline_thickness; |