diff options
| author | Po Lu | 2022-01-10 19:26:46 +0800 |
|---|---|---|
| committer | Po Lu | 2022-01-10 19:26:46 +0800 |
| commit | 4f50d964e51bbe5219f40df4353f4314c7ade985 (patch) | |
| tree | 8c68be6ee5b0b9999bb61ed7dd3553b456828b7b /src | |
| parent | e36f076eb7681e32b3b0cc61c4fd33e448e3bc74 (diff) | |
| download | emacs-4f50d964e51bbe5219f40df4353f4314c7ade985.tar.gz emacs-4f50d964e51bbe5219f40df4353f4314c7ade985.zip | |
Allow controlling the underline position of faces
* doc/lispref/display.texi (Face Attributes): Document new
`:position' property of the `:underline' attribute.
* etc/NEWS: Announce new property.
* lisp/cus-face.el (custom-face-attributes): Implement
customization for new face attribute.
* src/dispextern.h (struct face): New fields
`underline_pixels_above_descent_line' and
`underline_at_descent_line_p'.
* src/haikuterm.c (haiku_draw_text_decoration):
* src/nsterm.m (ns_draw_text_decoration):
* src/w32term.c (w32_draw_glyph_string):
* src/xterm.c (x_draw_glyph_string): Respect new face fields.
* src/xfaces.c (realize_gui_face): Handle new `:position'
keyword.
(syms_of_xfaces): New symbol `:position'.
Diffstat (limited to 'src')
| -rw-r--r-- | src/dispextern.h | 9 | ||||
| -rw-r--r-- | src/haikuterm.c | 14 | ||||
| -rw-r--r-- | src/nsterm.m | 15 | ||||
| -rw-r--r-- | src/w32term.c | 20 | ||||
| -rw-r--r-- | src/xfaces.c | 16 | ||||
| -rw-r--r-- | src/xterm.c | 25 |
6 files changed, 81 insertions, 18 deletions
diff --git a/src/dispextern.h b/src/dispextern.h index 954992a0ec2..368507732ce 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -1720,6 +1720,12 @@ struct face | |||
| 1720 | int box_vertical_line_width; | 1720 | int box_vertical_line_width; |
| 1721 | int box_horizontal_line_width; | 1721 | int box_horizontal_line_width; |
| 1722 | 1722 | ||
| 1723 | |||
| 1724 | /* The amount of pixels above the descent line the underline should | ||
| 1725 | be displayed. It does not take effect unless | ||
| 1726 | `underline_at_descent_line_p` is t. */ | ||
| 1727 | int underline_pixels_above_descent_line; | ||
| 1728 | |||
| 1723 | /* Type of box drawn. A value of FACE_NO_BOX means no box is drawn | 1729 | /* Type of box drawn. A value of FACE_NO_BOX means no box is drawn |
| 1724 | around text in this face. A value of FACE_SIMPLE_BOX means a box | 1730 | around text in this face. A value of FACE_SIMPLE_BOX means a box |
| 1725 | of width box_line_width is drawn in color box_color. A value of | 1731 | of width box_line_width is drawn in color box_color. A value of |
| @@ -1753,6 +1759,9 @@ struct face | |||
| 1753 | bool_bf strike_through_color_defaulted_p : 1; | 1759 | bool_bf strike_through_color_defaulted_p : 1; |
| 1754 | bool_bf box_color_defaulted_p : 1; | 1760 | bool_bf box_color_defaulted_p : 1; |
| 1755 | 1761 | ||
| 1762 | /* True means the underline should be drawn at the descent line. */ | ||
| 1763 | bool_bf underline_at_descent_line_p : 1; | ||
| 1764 | |||
| 1756 | /* TTY appearances. Colors are found in `lface' with empty color | 1765 | /* TTY appearances. Colors are found in `lface' with empty color |
| 1757 | string meaning the default color of the TTY. */ | 1766 | string meaning the default color of the TTY. */ |
| 1758 | bool_bf tty_bold_p : 1; | 1767 | bool_bf tty_bold_p : 1; |
diff --git a/src/haikuterm.c b/src/haikuterm.c index b6d105bf2b6..2304f718c31 100644 --- a/src/haikuterm.c +++ b/src/haikuterm.c | |||
| @@ -613,7 +613,12 @@ haiku_draw_text_decoration (struct glyph_string *s, struct face *face, | |||
| 613 | unsigned long thickness, position; | 613 | unsigned long thickness, position; |
| 614 | int y; | 614 | int y; |
| 615 | 615 | ||
| 616 | if (s->prev && s->prev && s->prev->hl == DRAW_MOUSE_FACE) | 616 | if (s->prev |
| 617 | && s->prev->face->underline == FACE_UNDER_LINE | ||
| 618 | && (s->prev->face->underline_at_descent_line_p | ||
| 619 | == s->face->underline_at_descent_line_p) | ||
| 620 | && (s->prev->face->underline_pixels_above_descent_line | ||
| 621 | == s->face->underline_pixels_above_descent_line)) | ||
| 617 | { | 622 | { |
| 618 | struct face *prev_face = s->prev->face; | 623 | struct face *prev_face = s->prev->face; |
| 619 | 624 | ||
| @@ -644,7 +649,8 @@ haiku_draw_text_decoration (struct glyph_string *s, struct face *face, | |||
| 644 | val = (WINDOW_BUFFER_LOCAL_VALUE | 649 | val = (WINDOW_BUFFER_LOCAL_VALUE |
| 645 | (Qx_underline_at_descent_line, s->w)); | 650 | (Qx_underline_at_descent_line, s->w)); |
| 646 | underline_at_descent_line | 651 | underline_at_descent_line |
| 647 | = !(NILP (val) || EQ (val, Qunbound)); | 652 | = (!(NILP (val) || EQ (val, Qunbound)) |
| 653 | || s->face->underline_at_descent_line_p); | ||
| 648 | 654 | ||
| 649 | val = (WINDOW_BUFFER_LOCAL_VALUE | 655 | val = (WINDOW_BUFFER_LOCAL_VALUE |
| 650 | (Qx_use_underline_position_properties, s->w)); | 656 | (Qx_use_underline_position_properties, s->w)); |
| @@ -657,7 +663,9 @@ haiku_draw_text_decoration (struct glyph_string *s, struct face *face, | |||
| 657 | else | 663 | else |
| 658 | thickness = 1; | 664 | thickness = 1; |
| 659 | if (underline_at_descent_line) | 665 | if (underline_at_descent_line) |
| 660 | position = (s->height - thickness) - (s->ybase - s->y); | 666 | position = ((s->height - thickness) |
| 667 | - (s->ybase - s->y) | ||
| 668 | - s->face->underline_pixels_above_descent_line); | ||
| 661 | else | 669 | else |
| 662 | { | 670 | { |
| 663 | /* Get the underline position. This is the | 671 | /* Get the underline position. This is the |
diff --git a/src/nsterm.m b/src/nsterm.m index a15dc47a226..4f60cc737da 100644 --- a/src/nsterm.m +++ b/src/nsterm.m | |||
| @@ -3265,7 +3265,11 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face, | |||
| 3265 | /* If the prev was underlined, match its appearance. */ | 3265 | /* If the prev was underlined, match its appearance. */ |
| 3266 | if (s->prev | 3266 | if (s->prev |
| 3267 | && s->prev->face->underline == FACE_UNDER_LINE | 3267 | && s->prev->face->underline == FACE_UNDER_LINE |
| 3268 | && s->prev->underline_thickness > 0) | 3268 | && s->prev->underline_thickness > 0 |
| 3269 | && (s->prev->face->underline_at_descent_line_p | ||
| 3270 | == s->face->underline_at_descent_line_p) | ||
| 3271 | && (s->prev->face->underline_pixels_above_descent_line | ||
| 3272 | == s->face->underline_pixels_above_descent_line)) | ||
| 3269 | { | 3273 | { |
| 3270 | thickness = s->prev->underline_thickness; | 3274 | thickness = s->prev->underline_thickness; |
| 3271 | position = s->prev->underline_position; | 3275 | position = s->prev->underline_position; |
| @@ -3286,7 +3290,8 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face, | |||
| 3286 | 3290 | ||
| 3287 | val = (WINDOW_BUFFER_LOCAL_VALUE | 3291 | val = (WINDOW_BUFFER_LOCAL_VALUE |
| 3288 | (Qx_underline_at_descent_line, s->w)); | 3292 | (Qx_underline_at_descent_line, s->w)); |
| 3289 | underline_at_descent_line = !(NILP (val) || EQ (val, Qunbound)); | 3293 | underline_at_descent_line = (!(NILP (val) || EQ (val, Qunbound)) |
| 3294 | || s->face->underline_at_descent_line_p); | ||
| 3290 | 3295 | ||
| 3291 | val = (WINDOW_BUFFER_LOCAL_VALUE | 3296 | val = (WINDOW_BUFFER_LOCAL_VALUE |
| 3292 | (Qx_use_underline_position_properties, s->w)); | 3297 | (Qx_use_underline_position_properties, s->w)); |
| @@ -3299,7 +3304,8 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face, | |||
| 3299 | 3304 | ||
| 3300 | /* Determine the offset of underlining from the baseline. */ | 3305 | /* Determine the offset of underlining from the baseline. */ |
| 3301 | if (underline_at_descent_line) | 3306 | if (underline_at_descent_line) |
| 3302 | position = descent - thickness; | 3307 | position = (descent - thickness |
| 3308 | - s->face->underline_pixels_above_descent_line); | ||
| 3303 | else if (use_underline_position_properties | 3309 | else if (use_underline_position_properties |
| 3304 | && font && font->underline_position >= 0) | 3310 | && font && font->underline_position >= 0) |
| 3305 | position = font->underline_position; | 3311 | position = font->underline_position; |
| @@ -3308,7 +3314,8 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face, | |||
| 3308 | else | 3314 | else |
| 3309 | position = minimum_offset; | 3315 | position = minimum_offset; |
| 3310 | 3316 | ||
| 3311 | position = max (position, minimum_offset); | 3317 | if (!s->face->underline_pixels_above_descent_line) |
| 3318 | position = max (position, minimum_offset); | ||
| 3312 | 3319 | ||
| 3313 | /* Ensure underlining is not cropped. */ | 3320 | /* Ensure underlining is not cropped. */ |
| 3314 | if (descent <= position) | 3321 | if (descent <= position) |
diff --git a/src/w32term.c b/src/w32term.c index 700c492cc37..78777f153c0 100644 --- a/src/w32term.c +++ b/src/w32term.c | |||
| @@ -2564,7 +2564,11 @@ w32_draw_glyph_string (struct glyph_string *s) | |||
| 2564 | int y; | 2564 | int y; |
| 2565 | 2565 | ||
| 2566 | if (s->prev | 2566 | if (s->prev |
| 2567 | && s->prev->face->underline == FACE_UNDER_LINE) | 2567 | && s->prev->face->underline == FACE_UNDER_LINE |
| 2568 | && (s->prev->face->underline_at_descent_line_p | ||
| 2569 | == s->face->underline_at_descent_line_p) | ||
| 2570 | && (s->prev->face->underline_pixels_above_descent_line | ||
| 2571 | == s->face->underline_pixels_above_descent_line)) | ||
| 2568 | { | 2572 | { |
| 2569 | /* We use the same underline style as the previous one. */ | 2573 | /* We use the same underline style as the previous one. */ |
| 2570 | thickness = s->prev->underline_thickness; | 2574 | thickness = s->prev->underline_thickness; |
| @@ -2587,7 +2591,8 @@ w32_draw_glyph_string (struct glyph_string *s) | |||
| 2587 | val = (WINDOW_BUFFER_LOCAL_VALUE | 2591 | val = (WINDOW_BUFFER_LOCAL_VALUE |
| 2588 | (Qx_underline_at_descent_line, s->w)); | 2592 | (Qx_underline_at_descent_line, s->w)); |
| 2589 | underline_at_descent_line | 2593 | underline_at_descent_line |
| 2590 | = !(NILP (val) || EQ (val, Qunbound)); | 2594 | = (!(NILP (val) || EQ (val, Qunbound)) |
| 2595 | || s->face->underline_at_descent_line_p); | ||
| 2591 | 2596 | ||
| 2592 | val = (WINDOW_BUFFER_LOCAL_VALUE | 2597 | val = (WINDOW_BUFFER_LOCAL_VALUE |
| 2593 | (Qx_use_underline_position_properties, s->w)); | 2598 | (Qx_use_underline_position_properties, s->w)); |
| @@ -2601,7 +2606,9 @@ w32_draw_glyph_string (struct glyph_string *s) | |||
| 2601 | thickness = 1; | 2606 | thickness = 1; |
| 2602 | if (underline_at_descent_line | 2607 | if (underline_at_descent_line |
| 2603 | || !font) | 2608 | || !font) |
| 2604 | position = (s->height - thickness) - (s->ybase - s->y); | 2609 | position = ((s->height - thickness) |
| 2610 | - (s->ybase - s->y) | ||
| 2611 | - s->face->underline_pixels_above_descent_line); | ||
| 2605 | else | 2612 | else |
| 2606 | { | 2613 | { |
| 2607 | /* Get the underline position. This is the | 2614 | /* Get the underline position. This is the |
| @@ -2619,7 +2626,12 @@ w32_draw_glyph_string (struct glyph_string *s) | |||
| 2619 | else | 2626 | else |
| 2620 | position = (font->descent + 1) / 2; | 2627 | position = (font->descent + 1) / 2; |
| 2621 | } | 2628 | } |
| 2622 | position = max (position, minimum_offset); | 2629 | |
| 2630 | if (!(s->face->underline_at_descent_line_p | ||
| 2631 | /* Ignore minimum_offset if the amount of pixels | ||
| 2632 | was explictly specified. */ | ||
| 2633 | && s->face->underline_pixels_above_descent_line)) | ||
| 2634 | position = max (position, minimum_offset); | ||
| 2623 | } | 2635 | } |
| 2624 | /* Check the sanity of thickness and position. We should | 2636 | /* Check the sanity of thickness and position. We should |
| 2625 | avoid drawing underline out of the current line area. */ | 2637 | avoid drawing underline out of the current line area. */ |
diff --git a/src/xfaces.c b/src/xfaces.c index 3fd31b7f225..8064d47c947 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] | |||
| 6041 | face->underline = FACE_UNDER_LINE; | 6041 | face->underline = FACE_UNDER_LINE; |
| 6042 | face->underline_defaulted_p = true; | 6042 | face->underline_defaulted_p = true; |
| 6043 | face->underline_color = 0; | 6043 | face->underline_color = 0; |
| 6044 | face->underline_at_descent_line_p = false; | ||
| 6045 | face->underline_pixels_above_descent_line = 0; | ||
| 6044 | } | 6046 | } |
| 6045 | else if (STRINGP (underline)) | 6047 | else if (STRINGP (underline)) |
| 6046 | { | 6048 | { |
| @@ -6050,12 +6052,16 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] | |||
| 6050 | face->underline_color | 6052 | face->underline_color |
| 6051 | = load_color (f, face, underline, | 6053 | = load_color (f, face, underline, |
| 6052 | LFACE_UNDERLINE_INDEX); | 6054 | LFACE_UNDERLINE_INDEX); |
| 6055 | face->underline_at_descent_line_p = false; | ||
| 6056 | face->underline_pixels_above_descent_line = 0; | ||
| 6053 | } | 6057 | } |
| 6054 | else if (NILP (underline)) | 6058 | else if (NILP (underline)) |
| 6055 | { | 6059 | { |
| 6056 | face->underline = FACE_NO_UNDERLINE; | 6060 | face->underline = FACE_NO_UNDERLINE; |
| 6057 | face->underline_defaulted_p = false; | 6061 | face->underline_defaulted_p = false; |
| 6058 | face->underline_color = 0; | 6062 | face->underline_color = 0; |
| 6063 | face->underline_at_descent_line_p = false; | ||
| 6064 | face->underline_pixels_above_descent_line = 0; | ||
| 6059 | } | 6065 | } |
| 6060 | else if (CONSP (underline)) | 6066 | else if (CONSP (underline)) |
| 6061 | { | 6067 | { |
| @@ -6064,6 +6070,8 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] | |||
| 6064 | face->underline = FACE_UNDER_LINE; | 6070 | face->underline = FACE_UNDER_LINE; |
| 6065 | face->underline_color = 0; | 6071 | face->underline_color = 0; |
| 6066 | face->underline_defaulted_p = true; | 6072 | face->underline_defaulted_p = true; |
| 6073 | face->underline_at_descent_line_p = false; | ||
| 6074 | face->underline_pixels_above_descent_line = 0; | ||
| 6067 | 6075 | ||
| 6068 | /* FIXME? This is also not robust about checking the precise form. | 6076 | /* FIXME? This is also not robust about checking the precise form. |
| 6069 | See comments in Finternal_set_lisp_face_attribute. */ | 6077 | 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] | |||
| 6100 | else if (EQ (value, Qwave)) | 6108 | else if (EQ (value, Qwave)) |
| 6101 | face->underline = FACE_UNDER_WAVE; | 6109 | face->underline = FACE_UNDER_WAVE; |
| 6102 | } | 6110 | } |
| 6111 | else if (EQ (keyword, QCposition)) | ||
| 6112 | { | ||
| 6113 | face->underline_at_descent_line_p = !NILP (value); | ||
| 6114 | |||
| 6115 | if (FIXNATP (value)) | ||
| 6116 | face->underline_pixels_above_descent_line = XFIXNAT (value); | ||
| 6117 | } | ||
| 6103 | } | 6118 | } |
| 6104 | } | 6119 | } |
| 6105 | 6120 | ||
| @@ -6915,6 +6930,7 @@ syms_of_xfaces (void) | |||
| 6915 | DEFSYM (QCcolor, ":color"); | 6930 | DEFSYM (QCcolor, ":color"); |
| 6916 | DEFSYM (QCline_width, ":line-width"); | 6931 | DEFSYM (QCline_width, ":line-width"); |
| 6917 | DEFSYM (QCstyle, ":style"); | 6932 | DEFSYM (QCstyle, ":style"); |
| 6933 | DEFSYM (QCposition, ":position"); | ||
| 6918 | DEFSYM (Qline, "line"); | 6934 | DEFSYM (Qline, "line"); |
| 6919 | DEFSYM (Qwave, "wave"); | 6935 | DEFSYM (Qwave, "wave"); |
| 6920 | DEFSYM (Qreleased_button, "released-button"); | 6936 | DEFSYM (Qreleased_button, "released-button"); |
diff --git a/src/xterm.c b/src/xterm.c index 321b4c5ab66..e2b09938a27 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -4144,8 +4144,12 @@ x_draw_glyph_string (struct glyph_string *s) | |||
| 4144 | unsigned long thickness, position; | 4144 | unsigned long thickness, position; |
| 4145 | int y; | 4145 | int y; |
| 4146 | 4146 | ||
| 4147 | if (s->prev && | 4147 | if (s->prev |
| 4148 | s->prev->face->underline == FACE_UNDER_LINE) | 4148 | && s->prev->face->underline == FACE_UNDER_LINE |
| 4149 | && (s->prev->face->underline_at_descent_line_p | ||
| 4150 | == s->face->underline_at_descent_line_p) | ||
| 4151 | && (s->prev->face->underline_pixels_above_descent_line | ||
| 4152 | == s->face->underline_pixels_above_descent_line)) | ||
| 4149 | { | 4153 | { |
| 4150 | /* We use the same underline style as the previous one. */ | 4154 | /* We use the same underline style as the previous one. */ |
| 4151 | thickness = s->prev->underline_thickness; | 4155 | thickness = s->prev->underline_thickness; |
| @@ -4168,7 +4172,8 @@ x_draw_glyph_string (struct glyph_string *s) | |||
| 4168 | val = (WINDOW_BUFFER_LOCAL_VALUE | 4172 | val = (WINDOW_BUFFER_LOCAL_VALUE |
| 4169 | (Qx_underline_at_descent_line, s->w)); | 4173 | (Qx_underline_at_descent_line, s->w)); |
| 4170 | underline_at_descent_line | 4174 | underline_at_descent_line |
| 4171 | = !(NILP (val) || EQ (val, Qunbound)); | 4175 | = (!(NILP (val) || EQ (val, Qunbound)) |
| 4176 | || s->face->underline_at_descent_line_p); | ||
| 4172 | 4177 | ||
| 4173 | val = (WINDOW_BUFFER_LOCAL_VALUE | 4178 | val = (WINDOW_BUFFER_LOCAL_VALUE |
| 4174 | (Qx_use_underline_position_properties, s->w)); | 4179 | (Qx_use_underline_position_properties, s->w)); |
| @@ -4181,7 +4186,9 @@ x_draw_glyph_string (struct glyph_string *s) | |||
| 4181 | else | 4186 | else |
| 4182 | thickness = 1; | 4187 | thickness = 1; |
| 4183 | if (underline_at_descent_line) | 4188 | if (underline_at_descent_line) |
| 4184 | position = (s->height - thickness) - (s->ybase - s->y); | 4189 | position = ((s->height - thickness) |
| 4190 | - (s->ybase - s->y) | ||
| 4191 | - s->face->underline_pixels_above_descent_line); | ||
| 4185 | else | 4192 | else |
| 4186 | { | 4193 | { |
| 4187 | /* Get the underline position. This is the | 4194 | /* Get the underline position. This is the |
| @@ -4201,12 +4208,16 @@ x_draw_glyph_string (struct glyph_string *s) | |||
| 4201 | else | 4208 | else |
| 4202 | position = minimum_offset; | 4209 | position = minimum_offset; |
| 4203 | } | 4210 | } |
| 4204 | position = max (position, minimum_offset); | 4211 | |
| 4212 | /* Ignore minimum_offset if the amount of pixels was | ||
| 4213 | explictly specified. */ | ||
| 4214 | if (!s->face->underline_pixels_above_descent_line) | ||
| 4215 | position = max (position, minimum_offset); | ||
| 4205 | } | 4216 | } |
| 4206 | /* Check the sanity of thickness and position. We should | 4217 | /* Check the sanity of thickness and position. We should |
| 4207 | avoid drawing underline out of the current line area. */ | 4218 | avoid drawing underline out of the current line area. */ |
| 4208 | if (s->y + s->height <= s->ybase + position) | 4219 | if (s->y + s->height <= s->ybase + position) |
| 4209 | position = (s->height - 1) - (s->ybase - s->y); | 4220 | position = (s->height - 1) - (s->ybase - s->y); |
| 4210 | if (s->y + s->height < s->ybase + position + thickness) | 4221 | if (s->y + s->height < s->ybase + position + thickness) |
| 4211 | thickness = (s->y + s->height) - (s->ybase + position); | 4222 | thickness = (s->y + s->height) - (s->ybase + position); |
| 4212 | s->underline_thickness = thickness; | 4223 | s->underline_thickness = thickness; |