From: Po Lu <luangruo@yahoo.com>
To: Eli Zaretskii <eliz@gnu.org>
Cc: emacs-devel@gnu.org
Subject: Re: Making `x-underline-at-descent-line' a face attribute
Date: Fri, 07 Jan 2022 19:04:50 +0800 [thread overview]
Message-ID: <877dbbyffx.fsf@yahoo.com> (raw)
In-Reply-To: <83mtk854rt.fsf@gnu.org> (Eli Zaretskii's message of "Fri, 07 Jan 2022 10:28:06 +0200")
[-- Attachment #1: Type: text/plain, Size: 1009 bytes --]
Eli Zaretskii <eliz@gnu.org> writes:
>> From: Po Lu <luangruo@yahoo.com>
>> Cc: emacs-devel@gnu.org
>> Date: Fri, 07 Jan 2022 15:14:45 +0800
>>
>> Thanks, one last question (before I start to implement this): what would
>> you recommend as a special value of `:underline'?
>>
>> Would it be okay to add a new property to the property list that is
>> already accepted as such a value?
>
> Yes, something like
>
> (:color COLOR :style STYLE :position POS)
>
> where POS can be t (with the same effect as non-nil value of
> x-underline-at-descent-line) or (if you want to get fancy) a number,
> to specify an explicit offset from the baseline.
Thanks, I implemented that, though I haven't written any documentation
yet. It would be nice if someone could test the attached diff on
MS-Windows.
BTW, there's a `hash' parameter in struct face, but I can't find where
it's calculated. I assume I have to the hashing take any new fields
into account, but I don't know how. Can you help with this? Thanks.
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: test.diff --]
[-- Type: text/x-patch, Size: 12195 bytes --]
diff --git a/src/dispextern.h b/src/dispextern.h
index 954992a0ec..368507732c 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1720,6 +1720,12 @@ #define FONT_TOO_HIGH(ft) \
int box_vertical_line_width;
int box_horizontal_line_width;
+
+ /* The amount of pixels above the descent line the underline should
+ be displayed. It does not take effect unless
+ `underline_at_descent_line_p` is t. */
+ int underline_pixels_above_descent_line;
+
/* Type of box drawn. A value of FACE_NO_BOX means no box is drawn
around text in this face. A value of FACE_SIMPLE_BOX means a box
of width box_line_width is drawn in color box_color. A value of
@@ -1753,6 +1759,9 @@ #define FONT_TOO_HIGH(ft) \
bool_bf strike_through_color_defaulted_p : 1;
bool_bf box_color_defaulted_p : 1;
+ /* True means the underline should be drawn at the descent line. */
+ bool_bf underline_at_descent_line_p : 1;
+
/* TTY appearances. Colors are found in `lface' with empty color
string meaning the default color of the TTY. */
bool_bf tty_bold_p : 1;
diff --git a/src/haikuterm.c b/src/haikuterm.c
index 2239770de9..560ce913ac 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -608,7 +608,12 @@ haiku_draw_text_decoration (struct glyph_string *s, struct face *face,
unsigned long thickness, position;
int y;
- if (s->prev && s->prev && s->prev->hl == DRAW_MOUSE_FACE)
+ if (s->prev
+ && s->prev->face->underline == FACE_UNDER_LINE
+ && (s->prev->face->underline_at_descent_line_p
+ == s->face->underline_at_descent_line_p)
+ && (s->prev->face->underline_pixels_above_descent_line
+ == s->face->underline_pixels_above_descent_line))
{
struct face *prev_face = s->prev->face;
@@ -639,7 +644,8 @@ haiku_draw_text_decoration (struct glyph_string *s, struct face *face,
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_underline_at_descent_line, s->w));
underline_at_descent_line
- = !(NILP (val) || EQ (val, Qunbound));
+ = (!(NILP (val) || EQ (val, Qunbound))
+ || s->face->underline_at_descent_line_p);
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_use_underline_position_properties, s->w));
@@ -652,7 +658,9 @@ haiku_draw_text_decoration (struct glyph_string *s, struct face *face,
else
thickness = 1;
if (underline_at_descent_line)
- position = (s->height - thickness) - (s->ybase - s->y);
+ position = ((s->height - thickness)
+ - (s->ybase - s->y)
+ - s->face->underline_pixels_above_descent_line);
else
{
/* Get the underline position. This is the
diff --git a/src/nsterm.m b/src/nsterm.m
index a15dc47a22..4f60cc737d 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -3265,7 +3265,11 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
/* If the prev was underlined, match its appearance. */
if (s->prev
&& s->prev->face->underline == FACE_UNDER_LINE
- && s->prev->underline_thickness > 0)
+ && s->prev->underline_thickness > 0
+ && (s->prev->face->underline_at_descent_line_p
+ == s->face->underline_at_descent_line_p)
+ && (s->prev->face->underline_pixels_above_descent_line
+ == s->face->underline_pixels_above_descent_line))
{
thickness = s->prev->underline_thickness;
position = s->prev->underline_position;
@@ -3286,7 +3290,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_underline_at_descent_line, s->w));
- underline_at_descent_line = !(NILP (val) || EQ (val, Qunbound));
+ underline_at_descent_line = (!(NILP (val) || EQ (val, Qunbound))
+ || s->face->underline_at_descent_line_p);
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_use_underline_position_properties, s->w));
@@ -3299,7 +3304,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
/* Determine the offset of underlining from the baseline. */
if (underline_at_descent_line)
- position = descent - thickness;
+ position = (descent - thickness
+ - s->face->underline_pixels_above_descent_line);
else if (use_underline_position_properties
&& font && font->underline_position >= 0)
position = font->underline_position;
@@ -3308,7 +3314,8 @@ Note that CURSOR_WIDTH is meaningful only for (h)bar cursors.
else
position = minimum_offset;
- position = max (position, minimum_offset);
+ if (!s->face->underline_pixels_above_descent_line)
+ position = max (position, minimum_offset);
/* Ensure underlining is not cropped. */
if (descent <= position)
diff --git a/src/w32term.c b/src/w32term.c
index 700c492cc3..78777f153c 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -2564,7 +2564,11 @@ w32_draw_glyph_string (struct glyph_string *s)
int y;
if (s->prev
- && s->prev->face->underline == FACE_UNDER_LINE)
+ && s->prev->face->underline == FACE_UNDER_LINE
+ && (s->prev->face->underline_at_descent_line_p
+ == s->face->underline_at_descent_line_p)
+ && (s->prev->face->underline_pixels_above_descent_line
+ == s->face->underline_pixels_above_descent_line))
{
/* We use the same underline style as the previous one. */
thickness = s->prev->underline_thickness;
@@ -2587,7 +2591,8 @@ w32_draw_glyph_string (struct glyph_string *s)
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_underline_at_descent_line, s->w));
underline_at_descent_line
- = !(NILP (val) || EQ (val, Qunbound));
+ = (!(NILP (val) || EQ (val, Qunbound))
+ || s->face->underline_at_descent_line_p);
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_use_underline_position_properties, s->w));
@@ -2601,7 +2606,9 @@ w32_draw_glyph_string (struct glyph_string *s)
thickness = 1;
if (underline_at_descent_line
|| !font)
- position = (s->height - thickness) - (s->ybase - s->y);
+ position = ((s->height - thickness)
+ - (s->ybase - s->y)
+ - s->face->underline_pixels_above_descent_line);
else
{
/* Get the underline position. This is the
@@ -2619,7 +2626,12 @@ w32_draw_glyph_string (struct glyph_string *s)
else
position = (font->descent + 1) / 2;
}
- position = max (position, minimum_offset);
+
+ if (!(s->face->underline_at_descent_line_p
+ /* Ignore minimum_offset if the amount of pixels
+ was explictly specified. */
+ && s->face->underline_pixels_above_descent_line))
+ position = max (position, minimum_offset);
}
/* Check the sanity of thickness and position. We should
avoid drawing underline out of the current line area. */
diff --git a/src/xfaces.c b/src/xfaces.c
index 3fd31b7f22..8064d47c94 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -6041,6 +6041,8 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE]
face->underline = FACE_UNDER_LINE;
face->underline_defaulted_p = true;
face->underline_color = 0;
+ face->underline_at_descent_line_p = false;
+ face->underline_pixels_above_descent_line = 0;
}
else if (STRINGP (underline))
{
@@ -6050,12 +6052,16 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE]
face->underline_color
= load_color (f, face, underline,
LFACE_UNDERLINE_INDEX);
+ face->underline_at_descent_line_p = false;
+ face->underline_pixels_above_descent_line = 0;
}
else if (NILP (underline))
{
face->underline = FACE_NO_UNDERLINE;
face->underline_defaulted_p = false;
face->underline_color = 0;
+ face->underline_at_descent_line_p = false;
+ face->underline_pixels_above_descent_line = 0;
}
else if (CONSP (underline))
{
@@ -6064,6 +6070,8 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE]
face->underline = FACE_UNDER_LINE;
face->underline_color = 0;
face->underline_defaulted_p = true;
+ face->underline_at_descent_line_p = false;
+ face->underline_pixels_above_descent_line = 0;
/* FIXME? This is also not robust about checking the precise form.
See comments in Finternal_set_lisp_face_attribute. */
@@ -6100,6 +6108,13 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE]
else if (EQ (value, Qwave))
face->underline = FACE_UNDER_WAVE;
}
+ else if (EQ (keyword, QCposition))
+ {
+ face->underline_at_descent_line_p = !NILP (value);
+
+ if (FIXNATP (value))
+ face->underline_pixels_above_descent_line = XFIXNAT (value);
+ }
}
}
@@ -6915,6 +6930,7 @@ syms_of_xfaces (void)
DEFSYM (QCcolor, ":color");
DEFSYM (QCline_width, ":line-width");
DEFSYM (QCstyle, ":style");
+ DEFSYM (QCposition, ":position");
DEFSYM (Qline, "line");
DEFSYM (Qwave, "wave");
DEFSYM (Qreleased_button, "released-button");
diff --git a/src/xterm.c b/src/xterm.c
index b284fdd312..717e946538 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -4131,8 +4131,12 @@ x_draw_glyph_string (struct glyph_string *s)
unsigned long thickness, position;
int y;
- if (s->prev &&
- s->prev->face->underline == FACE_UNDER_LINE)
+ if (s->prev
+ && s->prev->face->underline == FACE_UNDER_LINE
+ && (s->prev->face->underline_at_descent_line_p
+ == s->face->underline_at_descent_line_p)
+ && (s->prev->face->underline_pixels_above_descent_line
+ == s->face->underline_pixels_above_descent_line))
{
/* We use the same underline style as the previous one. */
thickness = s->prev->underline_thickness;
@@ -4155,7 +4159,8 @@ x_draw_glyph_string (struct glyph_string *s)
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_underline_at_descent_line, s->w));
underline_at_descent_line
- = !(NILP (val) || EQ (val, Qunbound));
+ = (!(NILP (val) || EQ (val, Qunbound))
+ || s->face->underline_at_descent_line_p);
val = (WINDOW_BUFFER_LOCAL_VALUE
(Qx_use_underline_position_properties, s->w));
@@ -4168,7 +4173,9 @@ x_draw_glyph_string (struct glyph_string *s)
else
thickness = 1;
if (underline_at_descent_line)
- position = (s->height - thickness) - (s->ybase - s->y);
+ position = ((s->height - thickness)
+ - (s->ybase - s->y)
+ - s->face->underline_pixels_above_descent_line);
else
{
/* Get the underline position. This is the
@@ -4188,12 +4195,16 @@ x_draw_glyph_string (struct glyph_string *s)
else
position = minimum_offset;
}
- position = max (position, minimum_offset);
+
+ /* Ignore minimum_offset if the amount of pixels was
+ explictly specified. */
+ if (!s->face->underline_pixels_above_descent_line)
+ position = max (position, minimum_offset);
}
/* Check the sanity of thickness and position. We should
avoid drawing underline out of the current line area. */
- if (s->y + s->height <= s->ybase + position)
- position = (s->height - 1) - (s->ybase - s->y);
+ if (s->y + s->height <= s->ybase + position)
+ position = (s->height - 1) - (s->ybase - s->y);
if (s->y + s->height < s->ybase + position + thickness)
thickness = (s->y + s->height) - (s->ybase + position);
s->underline_thickness = thickness;
next prev parent reply other threads:[~2022-01-07 11:04 UTC|newest]
Thread overview: 43+ messages / expand[flat|nested] mbox.gz Atom feed top
[not found] <87lezt5v7h.fsf.ref@yahoo.com>
2022-01-06 4:44 ` Making `x-underline-at-descent-line' a face attribute Po Lu
2022-01-06 5:08 ` Jim Porter
2022-01-06 5:35 ` Po Lu
2022-01-06 8:47 ` Eli Zaretskii
2022-01-06 8:43 ` Eli Zaretskii
2022-01-06 17:47 ` Jim Porter
2022-01-06 20:07 ` Eli Zaretskii
2022-01-06 20:18 ` Juri Linkov
2022-01-07 0:55 ` Po Lu
2022-01-07 7:17 ` Eli Zaretskii
2022-01-07 8:40 ` Juri Linkov
2022-01-07 9:40 ` Stefan Kangas
2022-01-08 18:20 ` Juri Linkov
2022-01-08 18:52 ` Eli Zaretskii
2022-01-08 19:09 ` Juri Linkov
2022-01-08 19:14 ` Eli Zaretskii
2022-01-07 13:14 ` Eli Zaretskii
2022-01-07 13:32 ` martin rudalics
2022-01-08 18:23 ` Juri Linkov
2022-01-08 18:39 ` Eli Zaretskii
2022-01-06 20:49 ` Jim Porter
2022-01-07 6:43 ` Eli Zaretskii
2022-01-06 8:44 ` Eli Zaretskii
2022-01-06 9:36 ` Po Lu
2022-01-06 12:02 ` Eli Zaretskii
2022-01-06 12:24 ` Po Lu
2022-01-06 13:51 ` Eli Zaretskii
2022-01-07 0:47 ` Po Lu
2022-01-07 7:12 ` Eli Zaretskii
2022-01-07 7:14 ` Po Lu
2022-01-07 8:28 ` Eli Zaretskii
2022-01-07 11:04 ` Po Lu [this message]
2022-01-07 12:21 ` Eli Zaretskii
2022-01-07 12:33 ` Po Lu
2022-01-07 12:41 ` Eli Zaretskii
2022-01-09 0:43 ` Po Lu
2022-01-10 10:54 ` Po Lu
2022-01-10 11:32 ` Po Lu
2022-01-10 17:41 ` Eli Zaretskii
2022-01-11 0:47 ` Po Lu
2022-01-11 16:46 ` Eli Zaretskii
2022-01-06 8:48 ` Lars Ingebrigtsen
2022-01-06 9:38 ` Po Lu
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=877dbbyffx.fsf@yahoo.com \
--to=luangruo@yahoo.com \
--cc=eliz@gnu.org \
--cc=emacs-devel@gnu.org \
/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).