From: Ergus via "Emacs development discussions." <emacs-devel@gnu.org>
To: Eli Zaretskii <eliz@gnu.org>
Cc: rudalics@gmx.at, emacs-devel@gnu.org
Subject: Re: Question about display engine
Date: Tue, 3 Sep 2019 07:35:53 +0200 [thread overview]
Message-ID: <20190903053553.hqk4uoktyhjprzcq@Ergus> (raw)
In-Reply-To: <83zhjm7juc.fsf@gnu.org>
[-- Attachment #1: Type: text/plain, Size: 2920 bytes --]
PATCH: (relative to dd162a3f2264940e3e329d0bf)
On Mon, Sep 02, 2019 at 07:18:19PM +0300, Eli Zaretskii wrote:
>> Date: Mon, 2 Sep 2019 13:05:04 +0200
>> From: Ergus <spacibba@aol.com>
>> Cc: Eli Zaretskii <eliz@gnu.org>, emacs-devel@gnu.org
>>
>> >If so then we might consider the following optimization: The extra
>> >face pointer in each face is no more needed after the display engine
>> >has processed the face. So we could build a "shadow" face for b+d,
>> >keep it in a separate, static face structure and realize a face from
>> >that structure whenever we want to (eagerly or lazily). The display
>> >engine, when it finds a pointer to such an extra face at EOL, uses it
>> >(maybe realizing it on the fly).
>> >
>> >Also, the merger could nullify the extra face if it's the same as the
>> >normal one, that is no single merge step had an :extend false value
>> >override a former :extend true value. So the display engine would
>> >know beforehand that it does not have to change the current face.
>> >
>> Yes; in my initial proposed approach the local pointer will be null in
>> that case.
>
>I don't think I understand why you are talking about face pointers.
>The iterator doesn't keep any face pointers, it keeps face IDs (which
>allow to obtain the face pointer, when needed, by using FACE_FROM_ID).
>
>So all you need is to have another face ID member in the iterator, to
>be used for extending past EOL; depending on how the :extend bits are
>set, that face ID may or may not be identical to the "normal" face ID,
>the one we have now and use for buffer text.
>
>> >Last but not least, the display engine has to, after processing the
>> >spaces at the EOL from b+d, restore the a+b+c+d+e face as its current
>> >face. So we have two static pointers to keep around: One for the b+d
>> >face structure (or its already realized face) while the display engine
>> >processes normal text and one for the a+b+c+d+e realized face while
>> >the display engine processes the spaces at EOL. Can you still agree?
>>
>> In the display engine we do this very
>> frequently. As extend_face_to_end_of_line is very localized we just need
>> to save a pointer to a+b+c+d on the beginning of the function and
>> restore it at the end.
>
>Again, not a pointer: a face ID. And yes, we have saved_face_id
>member of the iterator for this purpose.
>
>> And that in X there is some extra code (somewhere) to extend the
>> background color using the color in the last inserted glyph (it is
>> something happening by default without calling even
>> extend_face_to_end_of_line). That code should be removed after this
>> change; but I don't know where is it. But for sure Eli will tell.
>
>It's just that we clear to EOL with the last background color, and
>avoid doing that if the background color is identical to the frame's
>background. I don't think anything will have to be changed there, but
>we will see (I hope).
>
[-- Attachment #2: extend.patch --]
[-- Type: text/plain, Size: 31218 bytes --]
diff --git a/lisp/cus-face.el b/lisp/cus-face.el
index d73bce42c3..5a49a81043 100644
--- a/lisp/cus-face.el
+++ b/lisp/cus-face.el
@@ -233,7 +233,11 @@ custom-face-attributes
(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 5193c216d0..11e42c5380 100644
--- a/lisp/faces.el
+++ b/lisp/faces.el
@@ -342,6 +342,7 @@ face-x-resources
(: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 @@ face-italic-p
(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))
\f
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -760,6 +768,11 @@ set-face-attribute
`: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 @@ set-face-italic
(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 @@ face-valid-attribute-values
(: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,12 +1172,13 @@ face-attribute-name-alist
(:slant . "slant")
(:underline . "underline")
(:overline . "overline")
+ (:extend . "extend")
(:strike-through . "strike-through")
(:box . "box")
(:inverse-video . "inverse-video display")
(:foreground . "foreground color")
(:background . "background color")
- (:stipple . "background stipple")
+ (:background . "background color")
(:inherit . "inheritance"))
"An alist of descriptive names for face attributes.
Each element has the form (ATTRIBUTE-NAME . DESCRIPTION) where
@@ -2432,24 +2458,24 @@ highlight
;; 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/src/dispextern.h b/src/dispextern.h
index 05f199ff35..e09d36944a 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1564,6 +1564,7 @@ #define FONT_TOO_HIGH(ft) \
LFACE_INHERIT_INDEX,
LFACE_FONTSET_INDEX,
LFACE_DISTANT_FOREGROUND_INDEX,
+ LFACE_EXTEND_INDEX,
LFACE_VECTOR_SIZE
};
@@ -1589,6 +1590,7 @@ #define FONT_TOO_HIGH(ft) \
enum face_underline_type
{
+ FACE_NO_UNDERLINE = 0,
FACE_UNDER_LINE,
FACE_UNDER_WAVE
};
@@ -1632,11 +1634,9 @@ #define FONT_TOO_HIGH(ft) \
/* 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;
@@ -1663,7 +1663,7 @@ #define FONT_TOO_HIGH(ft) \
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. */
@@ -1671,7 +1671,6 @@ #define FONT_TOO_HIGH(ft) \
/* 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;
@@ -1681,14 +1680,10 @@ #define FONT_TOO_HIGH(ft) \
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;
@@ -2448,6 +2443,9 @@ #define OVERLAY_STRING_CHUNK_SIZE 16
/* Face to use. */
int face_id;
+ /* Face to extend at EOL/ */
+ int extend_face_id;
+
/* Setting of buffer-local variable selective-display-ellipses. */
bool_bf selective_display_ellipsis_p : 1;
diff --git a/src/xdisp.c b/src/xdisp.c
index 75bc536cb9..015a80af42 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -7141,18 +7141,50 @@ lookup_glyphless_char_display (int c, struct it *it)
}
/* Merge escape glyph face and cache the result. */
+static struct frame *last_extend_glyph_frame = NULL;
+static int last_extend_glyph_face_id = (1 << FACE_ID_BITS);
+static int last_extend_glyph_merged_face_id = 0;
+static int
+merge_extend_glyph_face (struct it *it)
+{
+ int extend_face_id = it->extend_face_id;
+
+ struct face *face = FACE_FROM_ID (it->f, it->extend_face_id);
+ fprintf(stderr, "extending1!!!\n");
+
+ if (!NILP (face->lface[LFACE_EXTEND_INDEX]))
+ {
+ fprintf(stderr,"extending2!!!\n");
+
+ if (it->f == last_extend_glyph_frame
+ && it->extend_face_id == last_extend_glyph_face_id)
+ return last_extend_glyph_merged_face_id;
+
+ /* Merge the `glyphless-char' face into the current face. */
+ extend_face_id = merge_faces (it->w, Qt, it->face_id, extend_face_id);
+ last_extend_glyph_frame = it->f;
+ last_extend_glyph_face_id = it->extend_face_id;
+ last_extend_glyph_merged_face_id = extend_face_id;
+ }
+ return extend_face_id;
+}
+
+
+/* Merge escape glyph face and cache the result. */
static struct frame *last_escape_glyph_frame = NULL;
static int last_escape_glyph_face_id = (1 << FACE_ID_BITS);
static int last_escape_glyph_merged_face_id = 0;
static int
-merge_escape_glyph_face (struct it *it)
+merge_escape_glyph_face (struct it *it, int lface_id)
{
int face_id;
- if (it->f == last_escape_glyph_frame
- && it->face_id == last_escape_glyph_face_id)
+ if (lface_id)
+ face_id = merge_faces (it->w, Qt, lface_id, it->face_id);
+ else if (it->f == last_escape_glyph_frame
+ && it->face_id == last_escape_glyph_face_id)
face_id = last_escape_glyph_merged_face_id;
else
{
@@ -7162,6 +7194,8 @@ merge_escape_glyph_face (struct it *it)
last_escape_glyph_face_id = it->face_id;
last_escape_glyph_merged_face_id = face_id;
}
+
+ merge_extend_glyph_face (it);
return face_id;
}
@@ -7187,9 +7221,12 @@ merge_glyphless_glyph_face (struct it *it)
last_glyphless_glyph_face_id = it->face_id;
last_glyphless_glyph_merged_face_id = face_id;
}
+
+ merge_extend_glyph_face (it);
return face_id;
}
+
/* Forget the `escape-glyph' and `glyphless-char' faces. This should
be called before redisplaying windows, and when the frame's face
cache is freed. */
@@ -7355,9 +7392,7 @@ get_next_display_element (struct it *it)
lface_id = GLYPH_CODE_FACE (gc);
}
- face_id = (lface_id
- ? merge_faces (it->w, Qt, lface_id, it->face_id)
- : merge_escape_glyph_face (it));
+ face_id = merge_escape_glyph_face (it, lface_id);
XSETINT (it->ctl_chars[0], g);
XSETINT (it->ctl_chars[1], c ^ 0100);
@@ -7373,6 +7408,8 @@ get_next_display_element (struct it *it)
/* Merge `nobreak-space' into the current face. */
face_id = merge_faces (it->w, Qnobreak_space, 0,
it->face_id);
+
+ merge_extend_glyph_face (it);
XSETINT (it->ctl_chars[0], ' ');
ctl_len = 1;
goto display_control;
@@ -7385,7 +7422,10 @@ get_next_display_element (struct it *it)
{
/* Merge `nobreak-space' into the current face. */
face_id = merge_faces (it->w, Qnobreak_hyphen, 0,
- it->face_id);
+ it->face_id);
+
+ merge_extend_glyph_face (it);
+
XSETINT (it->ctl_chars[0], '-');
ctl_len = 1;
goto display_control;
@@ -7403,12 +7443,10 @@ get_next_display_element (struct it *it)
lface_id = GLYPH_CODE_FACE (gc);
}
- face_id = (lface_id
- ? merge_faces (it->w, Qt, lface_id, it->face_id)
- : merge_escape_glyph_face (it));
+ face_id = merge_escape_glyph_face (it, lface_id);
+
/* Draw non-ASCII space/hyphen with escape glyph: */
-
if (nonascii_space_p || nonascii_hyphen_p)
{
XSETINT (it->ctl_chars[0], escape_glyph);
@@ -8032,8 +8070,11 @@ next_element_from_display_vector (struct it *it)
{
int lface_id = GLYPH_CODE_FACE (gc);
if (lface_id > 0)
- it->face_id = merge_faces (it->w, Qt, lface_id,
- it->saved_face_id);
+ {
+ it->face_id = merge_faces (it->w, Qt, lface_id,
+ it->saved_face_id);
+ merge_extend_glyph_face (it);
+ }
}
/* Glyphs in the display vector could have the box face, so we
@@ -8061,8 +8102,11 @@ next_element_from_display_vector (struct it *it)
GLYPH_CODE_FACE (it->dpvec[it->current.dpvec_index + 1]);
if (lface_id > 0)
- next_face_id = merge_faces (it->w, Qt, lface_id,
- it->saved_face_id);
+ {
+ next_face_id = merge_faces (it->w, Qt, lface_id,
+ it->saved_face_id);
+ merge_extend_glyph_face (it);
+ }
}
}
next_face = FACE_FROM_ID_OR_NULL (it->f, next_face_id);
@@ -20324,7 +20368,7 @@ append_space_for_newline (struct it *it, bool default_face_p)
= XFIXNAT (Vdisplay_fill_column_indicator_character);
it->face_id
= merge_faces (it->w, Qfill_column_indicator,
- 0, saved_face_id);
+ 0, it->extend_face_id);
face = FACE_FROM_ID (it->f, it->face_id);
goto produce_glyphs;
}
@@ -20471,33 +20515,33 @@ extend_face_to_end_of_line (struct it *it)
1-``pixel'' wide, so they hit the equality too early. This grace
is needed only for R2L rows that are not continued, to produce
one extra blank where we could display the cursor. */
- if ((it->current_x >= it->last_visible_x
- + (!FRAME_WINDOW_P (f)
- && it->glyph_row->reversed_p
- && !it->glyph_row->continued_p))
- /* If the window has display margins, we will need to extend
- their face even if the text area is filled. */
- && !(WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
- || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0))
- return;
-
- /* Face extension extends the background and box of IT->face_id
- to the end of the line. If the background equals the background
- of the frame, we don't have to do anything. */
+/* if ((it->current_x >= it->last_visible_x */
+/* + (!FRAME_WINDOW_P (f) */
+/* && it->glyph_row->reversed_p */
+/* && !it->glyph_row->continued_p)) */
+/* /\* If the window has display margins, we will need to extend */
+/* their face even if the text area is filled. *\/ */
+/* && !(WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0 */
+/* || WINDOW_RIGHT_MARGIN_WIDTH (it->w) > 0)) */
+/* return; */
+
+/* /\* Face extension extends the background and box of IT->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));
-
- if (FRAME_WINDOW_P (f)
- && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row)
- && face->box == FACE_NO_BOX
- && FACE_COLOR_TO_PIXEL (face->background, f) == FRAME_BACKGROUND_PIXEL (f)
-#ifdef HAVE_WINDOW_SYSTEM
- && !face->stipple
-#endif
- && !it->glyph_row->reversed_p
- && !Vdisplay_fill_column_indicator)
- return;
+ : it->extend_face_id));
+
+/* if (FRAME_WINDOW_P (f) */
+/* && MATRIX_ROW_DISPLAYS_TEXT_P (it->glyph_row) */
+/* && face->box == FACE_NO_BOX */
+/* && FACE_COLOR_TO_PIXEL (face->background, f) == FRAME_BACKGROUND_PIXEL (f) */
+/* #ifdef HAVE_WINDOW_SYSTEM */
+/* && !face->stipple */
+/* #endif */
+/* && !it->glyph_row->reversed_p */
+/* && !Vdisplay_fill_column_indicator) */
+/* return; */
/* Set the glyph row flag indicating that the face of the last glyph
in the text area has to be drawn to the end of the text area. */
@@ -20560,79 +20604,88 @@ 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. */
+ 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;
+
+ it->avoid_cursor_p = true;
+ it->object = Qnil;
+ memset (&it->position, 0, sizeof it->position);
+
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
+
+ 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);
- }
+ const int char_width = (font->average_width
+ ? font->average_width
+ : font->space_width);
+ int column_x;
+
+ if (indicator_column >= 0
+ && !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)
+ {
+
+ /* The stretch width needs to considet the latter
+ added glyph. */
+ const int stretch_width
+ = column_x - it->current_x - char_width;
+
+ /* Only generate a stretch glyph if there is distance
+ between current_x and and the indicator position. */
+ if (stretch_width > 0)
+ {
+ it->face_id = it->extend_face_id;
- /* 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;
- }
- }
+ 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, it->extend_face_id);
+ PRODUCE_GLYPHS (it);
+ it->char_to_display = saved_char;
+ }
+
+ }
+
+ const int stretch_width = it->last_visible_x - it->current_x;
+
+ if (stretch_width > 0)
+ {
+ it->face_id = it->extend_face_id;
+
+ 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);
+ }
+
+ it->char_to_display = saved_char;
+ it->position = saved_pos;
+ it->avoid_cursor_p = saved_avoid_cursor;
+ it->face_id = saved_face_id;
+ it->start_of_box_run_p = saved_box_start;
+ it->object = save_object;
}
if (it->glyph_row->reversed_p)
{
@@ -20718,7 +20771,7 @@ extend_face_to_end_of_line (struct it *it)
it->len = 1;
if (WINDOW_LEFT_MARGIN_WIDTH (it->w) > 0
- && (it->glyph_row->used[LEFT_MARGIN_AREA]
+ && (it->glyph_row->used[LEFT_MARGIN_AREA]
< WINDOW_LEFT_MARGIN_WIDTH (it->w))
&& !it->glyph_row->mode_line_p
&& FACE_COLOR_TO_PIXEL (face->background, f) != FRAME_BACKGROUND_PIXEL (f))
@@ -20762,24 +20815,25 @@ extend_face_to_end_of_line (struct it *it)
indicator_column = -1;
do
{
- int saved_face_id;
- bool indicate = it->current_x == indicator_column;
- if (indicate)
+ if (it->current_x == indicator_column)
{
- 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,
+ it->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 = ' ';
}
+ else
+ {
+ PRODUCE_GLYPHS (it);
+ }
}
while (it->current_x <= it->last_visible_x);
@@ -21760,6 +21814,7 @@ display_line (struct it *it, int cursor_vpos)
it->starts_in_middle_of_char_p = false;
it->tab_offset = 0;
it->line_number_produced_p = false;
+ it->extend_face_id = DEFAULT_FACE_ID;
/* Arrange the overlays nicely for our purposes. Usually, we call
display_line on only one line at a time, in which case this
@@ -27354,7 +27409,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;
}
diff --git a/src/xfaces.c b/src/xfaces.c
index c3cae7e2a6..092e110de5 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -1209,7 +1209,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 +1590,7 @@ #define LFACE_BOX(LFACE) AREF ((LFACE), LFACE_BOX_INDEX)
#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)
@@ -2512,6 +2513,13 @@ merge_face_ref (struct window *w,
err_msgs, named_merge_points))
err = true;
}
+ else if (EQ (keyword, QCextend))
+ {
+ if (EQ (value, Qt) || NILP (value))
+ to[LFACE_EXTEND_INDEX] = value;
+ else
+ err = true;
+ }
else
err = true;
@@ -3030,6 +3038,17 @@ DEFUN ("internal-set-lisp-face-attribute", Finternal_set_lisp_face_attribute,
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 inverse-video face attribute value", value);
+ }
+ old_value = LFACE_EXTEND (lface);
+ ASET (lface, LFACE_EXTEND_INDEX, value);
+ }
else if (EQ (attr, QCforeground))
{
/* Compatibility with 20.x. */
@@ -3203,6 +3222,14 @@ DEFUN ("internal-set-lisp-face-attribute", Finternal_set_lisp_face_attribute,
ASET (lface, LFACE_SLANT_INDEX, NILP (value) ? Qnormal : Qitalic);
prop_index = FONT_SLANT_INDEX;
}
+ else if (EQ (attr, QCitalic))
+ {
+ attr = QCslant;
+ old_value = LFACE_SLANT (lface);
+ ASET (lface, LFACE_SLANT_INDEX, NILP (value) ? Qnormal : Qitalic);
+ prop_index = FONT_SLANT_INDEX;
+ }
+
else
signal_error ("Invalid face attribute name", attr);
@@ -3503,7 +3530,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 +3756,8 @@ DEFUN ("internal-get-lisp-face-attribute", Finternal_get_lisp_face_attribute,
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))
@@ -5694,16 +5725,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,
@@ -5711,7 +5740,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;
}
@@ -5719,10 +5748,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. */
@@ -5755,9 +5783,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;
}
}
}
@@ -6292,9 +6320,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;
@@ -6319,12 +6346,14 @@ merge_faces (struct window *w, Lisp_Object face_name, int 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);
}
@@ -6412,7 +6441,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);
}
@@ -6537,6 +6566,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 b761eaf4d1..b8f8db56a7 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -3798,9 +3798,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);
@@ -3814,13 +3814,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;
next prev parent reply other threads:[~2019-09-03 5:35 UTC|newest]
Thread overview: 183+ messages / expand[flat|nested] mbox.gz Atom feed top
2019-08-07 0:54 Question about display engine Ergus
2019-08-07 15:01 ` Eli Zaretskii
2019-08-07 15:32 ` Ergus
2019-08-07 15:45 ` Eli Zaretskii
2019-08-07 15:57 ` Ergus
2019-08-07 16:12 ` Eli Zaretskii
2019-08-07 16:25 ` martin rudalics
2019-08-07 16:41 ` Eli Zaretskii
2019-08-08 7:25 ` martin rudalics
2019-08-08 8:38 ` Ergus
2019-08-08 8:45 ` martin rudalics
2019-08-08 9:29 ` Ergus
2019-08-08 13:05 ` martin rudalics
2019-08-08 13:59 ` Eli Zaretskii
2019-08-08 16:43 ` Ergus
2019-08-08 17:50 ` Eli Zaretskii
2019-08-08 22:37 ` Ergus
2019-08-09 6:28 ` Eli Zaretskii
2019-08-09 9:08 ` Ergus
2019-08-09 9:40 ` Eli Zaretskii
2019-08-09 11:31 ` Ergus
2019-08-09 14:04 ` Eli Zaretskii
2019-08-09 15:09 ` Ergus
2019-08-09 8:59 ` martin rudalics
2019-08-09 9:31 ` Ergus
2019-08-09 9:38 ` Ergus
2019-08-10 11:42 ` Eli Zaretskii
2019-08-11 8:14 ` martin rudalics
2019-08-09 8:59 ` martin rudalics
2019-08-08 14:50 ` Ergus
2019-08-09 8:59 ` martin rudalics
2019-08-10 11:30 ` Eli Zaretskii
2019-08-11 8:14 ` martin rudalics
2019-08-11 14:13 ` Eli Zaretskii
2019-08-12 8:59 ` martin rudalics
2019-08-12 15:29 ` Eli Zaretskii
2019-08-12 22:18 ` Stefan Monnier
2019-08-13 8:17 ` martin rudalics
2019-08-13 15:32 ` Eli Zaretskii
2019-08-13 22:33 ` Stefan Monnier
2019-08-14 8:58 ` martin rudalics
2019-08-13 8:17 ` martin rudalics
2019-08-13 15:31 ` Eli Zaretskii
2019-08-14 8:58 ` martin rudalics
2019-08-14 15:14 ` Eli Zaretskii
2019-08-15 8:13 ` martin rudalics
2019-08-15 15:18 ` Eli Zaretskii
2019-08-16 7:29 ` martin rudalics
2019-08-16 8:34 ` Eli Zaretskii
2019-08-17 8:25 ` martin rudalics
2019-08-19 16:13 ` Ergus
2019-08-19 16:50 ` Eli Zaretskii
2019-08-19 21:30 ` Ergus
2019-08-20 14:09 ` Eli Zaretskii
2019-08-25 10:22 ` Ergus
2019-08-25 10:44 ` Eli Zaretskii
2019-08-26 4:31 ` Ergus
2019-08-26 7:45 ` Eli Zaretskii
2019-08-26 8:18 ` Ergus
2019-08-26 9:49 ` Eli Zaretskii
2019-08-27 22:20 ` Ergus
2019-08-28 8:35 ` martin rudalics
2019-08-28 9:07 ` Eli Zaretskii
2019-08-28 12:19 ` martin rudalics
2019-08-28 16:31 ` Ergus
2019-08-28 17:24 ` Eli Zaretskii
2019-08-28 18:19 ` Ergus
2019-08-29 18:28 ` Eli Zaretskii
2019-08-30 7:02 ` martin rudalics
2019-08-30 7:26 ` Eli Zaretskii
2019-08-30 9:34 ` Ergus
2019-08-29 7:45 ` martin rudalics
2019-08-28 17:21 ` Eli Zaretskii
2019-08-29 7:45 ` martin rudalics
2019-08-29 18:36 ` Eli Zaretskii
2019-08-30 7:03 ` martin rudalics
2019-08-30 8:48 ` Eli Zaretskii
2019-08-31 7:29 ` martin rudalics
2019-08-31 7:57 ` Eli Zaretskii
2019-09-01 8:14 ` martin rudalics
2019-09-01 12:26 ` Ergus
2019-09-02 8:36 ` martin rudalics
2019-09-02 11:05 ` Ergus
2019-09-02 16:18 ` Eli Zaretskii
2019-09-03 5:33 ` Ergus
2019-09-03 8:45 ` martin rudalics
2019-09-03 11:23 ` Ergus
2019-09-03 12:17 ` martin rudalics
2019-09-03 14:56 ` Eli Zaretskii
2019-09-03 5:35 ` Ergus via Emacs development discussions. [this message]
2019-09-03 8:45 ` martin rudalics
2019-09-03 14:53 ` Eli Zaretskii
2019-09-03 16:41 ` martin rudalics
2019-09-03 17:31 ` Eli Zaretskii
2019-09-03 18:59 ` martin rudalics
2019-09-04 18:33 ` Ergus
2019-09-04 20:04 ` martin rudalics
2019-09-04 20:19 ` Ergus via Emacs development discussions.
2019-09-05 7:32 ` martin rudalics
2019-09-05 13:54 ` Ergus
2019-09-05 19:31 ` Ergus
[not found] ` <1826922767.1725310.1567682307734@mail.yahoo.com>
2019-09-05 11:18 ` Ergus
2019-08-21 7:37 ` martin rudalics
2019-08-08 17:37 ` Eli Zaretskii
2019-08-09 12:46 ` martin rudalics
2019-08-10 11:25 ` Eli Zaretskii
2019-08-10 23:04 ` Stefan Monnier
2019-08-11 2:43 ` Eli Zaretskii
2019-08-11 8:17 ` martin rudalics
2019-08-11 8:11 ` martin rudalics
2019-08-08 17:38 ` Eli Zaretskii
2019-08-08 8:15 ` Ergus
2019-08-08 8:45 ` martin rudalics
2019-08-08 9:17 ` Ergus
2019-08-08 17:35 ` Eli Zaretskii
2019-08-08 20:37 ` Juri Linkov
2019-08-08 22:24 ` Ergus
2019-08-09 6:42 ` Eli Zaretskii
2019-08-09 17:54 ` Juri Linkov
-- strict thread matches above, loose matches on Subject: below --
2019-08-27 16:01 Keith David Bershatsky
[not found] <318675867.1913640.1567711569517.ref@mail.yahoo.com>
2019-09-05 19:26 ` Ergus
2019-09-06 8:22 ` martin rudalics
2019-09-06 9:31 ` Ergus
2019-09-07 6:52 ` martin rudalics
2019-09-07 7:37 ` Eli Zaretskii
2019-09-07 7:55 ` Eli Zaretskii
2019-09-08 0:51 ` Ergus via Emacs development discussions.
2019-09-08 8:40 ` martin rudalics
2019-09-08 12:53 ` Ergus
2019-09-09 7:39 ` martin rudalics
2019-09-09 13:56 ` Ergus
2019-09-09 16:00 ` Eli Zaretskii
2019-09-09 17:08 ` Ergus
2019-09-09 18:08 ` Eli Zaretskii
2019-09-09 19:29 ` Ergus
2019-09-10 2:27 ` Eli Zaretskii
2019-09-12 3:37 ` Ergus
2019-09-13 8:50 ` Eli Zaretskii
2019-09-08 17:51 ` Eli Zaretskii
2019-09-08 18:23 ` Ergus
2019-09-14 20:42 ` Ergus
2019-09-15 8:25 ` martin rudalics
2019-09-15 11:26 ` Ergus
2019-09-15 12:22 ` martin rudalics
2019-09-15 14:28 ` Stefan Monnier
2019-09-16 9:05 ` martin rudalics
2019-09-15 15:32 ` Eli Zaretskii
2019-09-15 21:42 ` Ergus
2019-09-17 2:17 ` Ergus
2019-09-17 9:48 ` Eli Zaretskii
2019-09-21 8:20 ` Eli Zaretskii
2019-09-21 13:57 ` Ergus
2019-09-21 21:55 ` Ergus
2019-09-26 16:32 ` Ergus
2019-09-28 10:35 ` Eli Zaretskii
2019-09-29 10:30 ` Ergus
2019-09-29 10:57 ` Eli Zaretskii
2019-10-07 15:40 ` Ergus
2019-10-09 9:02 ` Eli Zaretskii
2019-10-12 18:16 ` Ergus
2019-10-12 18:29 ` Eli Zaretskii
2019-09-06 8:55 ` Eli Zaretskii
2019-09-06 10:30 ` Ergus
2019-09-06 13:28 ` Eli Zaretskii
2019-09-06 16:34 ` Ergus
2019-09-06 18:12 ` Eli Zaretskii
2019-09-07 2:35 ` Ergus
2019-09-07 6:41 ` Eli Zaretskii
[not found] <20191012222305.jpjinkd5y2lz6xiv@Ergus>
[not found] ` <83mue5kmfx.fsf@gnu.org>
2019-10-13 15:40 ` Ergus
2019-10-13 16:06 ` Eli Zaretskii
2019-10-13 16:44 ` Ergus
2019-10-13 17:04 ` Eli Zaretskii
2019-10-13 18:11 ` Ergus
2019-10-13 18:25 ` Ergus
2019-10-13 18:53 ` Eli Zaretskii
2019-10-13 19:38 ` Ergus
2019-10-13 21:01 ` Eli Zaretskii
2019-10-13 22:27 ` Ergus
2019-10-14 8:26 ` Eli Zaretskii
2019-10-20 22:20 ` Ergus
2019-10-21 6:38 ` Eli Zaretskii
2019-10-13 19:41 ` Ergus
2019-10-13 16:11 ` Eli Zaretskii
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20190903053553.hqk4uoktyhjprzcq@Ergus \
--to=emacs-devel@gnu.org \
--cc=eliz@gnu.org \
--cc=rudalics@gmx.at \
--cc=spacibba@aol.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).