diff options
| author | Po Lu | 1970-01-01 00:00:00 +0000 |
|---|---|---|
| committer | Po Lu | 2024-04-28 11:58:54 +0800 |
| commit | e844b81c56d74aa2b2efa0ce98ed3de71647e656 (patch) | |
| tree | 0dd2259e464b4c8bc0c80efbdad27dfa6abfd915 /src | |
| parent | 77a170a175dfeb17dab23e41668b8497b8b3b9d7 (diff) | |
| download | emacs-e844b81c56d74aa2b2efa0ce98ed3de71647e656.tar.gz emacs-e844b81c56d74aa2b2efa0ce98ed3de71647e656.zip | |
Implement dots and dashes on X
* src/dispextern.h (enum face_underline_type): Indent and expand
commentary as to the new dependency on the order of its
enumerals.
* src/xfaces.c (realize_gui_face): Enable dots and dashes on
window systems.
* src/xterm.c (x_draw_underwave): Don't define unused variable
on Cairo builds.
(x_draw_dash): New function; implement for X and Cairo.
(x_fill_underline): New function. Delegate to x_fill_rectangle
or x_draw_dash as appropriate.
(x_draw_glyph_string): Call x_fill_underline rather than
x_fill_rectangle.
Diffstat (limited to 'src')
| -rw-r--r-- | src/dispextern.h | 4 | ||||
| -rw-r--r-- | src/xfaces.c | 2 | ||||
| -rw-r--r-- | src/xterm.c | 125 |
3 files changed, 108 insertions, 23 deletions
diff --git a/src/dispextern.h b/src/dispextern.h index 1614a044cbf..93cbde6583d 100644 --- a/src/dispextern.h +++ b/src/dispextern.h | |||
| @@ -1697,7 +1697,9 @@ enum face_box_type | |||
| 1697 | 1697 | ||
| 1698 | enum face_underline_type | 1698 | enum face_underline_type |
| 1699 | { | 1699 | { |
| 1700 | /* Note: Order matches the order of the Smulx terminfo extension. */ | 1700 | /* Note: order matches the order of the Smulx terminfo extension, and |
| 1701 | is also relied on to remain in its present order by | ||
| 1702 | x_draw_glyph_string and company. */ | ||
| 1701 | FACE_NO_UNDERLINE = 0, | 1703 | FACE_NO_UNDERLINE = 0, |
| 1702 | FACE_UNDERLINE_SINGLE, | 1704 | FACE_UNDERLINE_SINGLE, |
| 1703 | FACE_UNDERLINE_DOUBLE_LINE, | 1705 | FACE_UNDERLINE_DOUBLE_LINE, |
diff --git a/src/xfaces.c b/src/xfaces.c index d9ee82c8e7f..56d067ade5b 100644 --- a/src/xfaces.c +++ b/src/xfaces.c | |||
| @@ -6404,12 +6404,10 @@ realize_gui_face (struct face_cache *cache, Lisp_Object attrs[LFACE_VECTOR_SIZE] | |||
| 6404 | face->underline = FACE_UNDERLINE_DOUBLE_LINE; | 6404 | face->underline = FACE_UNDERLINE_DOUBLE_LINE; |
| 6405 | else if (EQ (value, Qwave)) | 6405 | else if (EQ (value, Qwave)) |
| 6406 | face->underline = FACE_UNDERLINE_WAVE; | 6406 | face->underline = FACE_UNDERLINE_WAVE; |
| 6407 | #if 0 | ||
| 6408 | else if (EQ (value, Qdots)) | 6407 | else if (EQ (value, Qdots)) |
| 6409 | face->underline = FACE_UNDERLINE_DOTS; | 6408 | face->underline = FACE_UNDERLINE_DOTS; |
| 6410 | else if (EQ (value, Qdashes)) | 6409 | else if (EQ (value, Qdashes)) |
| 6411 | face->underline = FACE_UNDERLINE_DASHES; | 6410 | face->underline = FACE_UNDERLINE_DASHES; |
| 6412 | #endif /* 0 */ | ||
| 6413 | else | 6411 | else |
| 6414 | face->underline = FACE_UNDERLINE_SINGLE; | 6412 | face->underline = FACE_UNDERLINE_SINGLE; |
| 6415 | } | 6413 | } |
diff --git a/src/xterm.c b/src/xterm.c index 9b014a7d0e4..505a3d9360a 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -10764,13 +10764,11 @@ x_get_scale_factor (struct x_display_info *dpyinfo, | |||
| 10764 | static void | 10764 | static void |
| 10765 | x_draw_underwave (struct glyph_string *s, int decoration_width) | 10765 | x_draw_underwave (struct glyph_string *s, int decoration_width) |
| 10766 | { | 10766 | { |
| 10767 | Display *display; | ||
| 10768 | struct x_display_info *dpyinfo; | 10767 | struct x_display_info *dpyinfo; |
| 10769 | /* Adjust for scale/HiDPI. */ | 10768 | /* Adjust for scale/HiDPI. */ |
| 10770 | int scale_x, scale_y; | 10769 | int scale_x, scale_y; |
| 10771 | 10770 | ||
| 10772 | dpyinfo = FRAME_DISPLAY_INFO (s->f); | 10771 | dpyinfo = FRAME_DISPLAY_INFO (s->f); |
| 10773 | display = dpyinfo->display; | ||
| 10774 | x_get_scale_factor (dpyinfo, &scale_x, &scale_y); | 10772 | x_get_scale_factor (dpyinfo, &scale_x, &scale_y); |
| 10775 | 10773 | ||
| 10776 | int wave_height = 3 * scale_y, wave_length = 2 * scale_x; | 10774 | int wave_height = 3 * scale_y, wave_length = 2 * scale_x; |
| @@ -10779,6 +10777,7 @@ x_draw_underwave (struct glyph_string *s, int decoration_width) | |||
| 10779 | x_draw_horizontal_wave (s->f, s->gc, s->x, s->ybase - wave_height + 3, | 10777 | x_draw_horizontal_wave (s->f, s->gc, s->x, s->ybase - wave_height + 3, |
| 10780 | decoration_width, wave_height, wave_length); | 10778 | decoration_width, wave_height, wave_length); |
| 10781 | #else /* not USE_CAIRO */ | 10779 | #else /* not USE_CAIRO */ |
| 10780 | Display *display; | ||
| 10782 | int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax, thickness = scale_y;; | 10781 | int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax, thickness = scale_y;; |
| 10783 | bool odd; | 10782 | bool odd; |
| 10784 | XRectangle wave_clip, string_clip, final_clip; | 10783 | XRectangle wave_clip, string_clip, final_clip; |
| @@ -10801,6 +10800,7 @@ x_draw_underwave (struct glyph_string *s, int decoration_width) | |||
| 10801 | if (!gui_intersect_rectangles (&wave_clip, &string_clip, &final_clip)) | 10800 | if (!gui_intersect_rectangles (&wave_clip, &string_clip, &final_clip)) |
| 10802 | return; | 10801 | return; |
| 10803 | 10802 | ||
| 10803 | display = dpyinfo->display; | ||
| 10804 | XSetClipRectangles (display, s->gc, 0, 0, &final_clip, 1, Unsorted); | 10804 | XSetClipRectangles (display, s->gc, 0, 0, &final_clip, 1, Unsorted); |
| 10805 | 10805 | ||
| 10806 | /* Draw the waves */ | 10806 | /* Draw the waves */ |
| @@ -10833,6 +10833,98 @@ x_draw_underwave (struct glyph_string *s, int decoration_width) | |||
| 10833 | #endif /* not USE_CAIRO */ | 10833 | #endif /* not USE_CAIRO */ |
| 10834 | } | 10834 | } |
| 10835 | 10835 | ||
| 10836 | /* Draw a dashed underline of thickness THICKNESS and width WIDTH onto F | ||
| 10837 | at a vertical offset of OFFSET from the position of the glyph string | ||
| 10838 | S, with each segment SEGMENT pixels in length. */ | ||
| 10839 | |||
| 10840 | static void | ||
| 10841 | x_draw_dash (struct frame *f, struct glyph_string *s, int width, | ||
| 10842 | char segment, int offset, int thickness) | ||
| 10843 | { | ||
| 10844 | #ifndef USE_CAIRO | ||
| 10845 | GC gc; | ||
| 10846 | Display *display; | ||
| 10847 | XGCValues gcv; | ||
| 10848 | int y_center; | ||
| 10849 | |||
| 10850 | /* Configure the GC, the dash pattern and a suitable offset. */ | ||
| 10851 | gc = s->gc; | ||
| 10852 | display = FRAME_X_DISPLAY (f); | ||
| 10853 | |||
| 10854 | XGetGCValues (display, s->gc, GCLineStyle, &gcv); | ||
| 10855 | gcv.line_style = LineOnOffDash; | ||
| 10856 | gcv.line_width = thickness; | ||
| 10857 | XChangeGC (display, s->gc, GCLineStyle | GCLineWidth, &gcv); | ||
| 10858 | XSetDashes (display, s->gc, s->x, &segment, 1); | ||
| 10859 | |||
| 10860 | /* Offset the origin of the line by half the line width. */ | ||
| 10861 | y_center = s->ybase + offset + thickness / 2; | ||
| 10862 | XDrawLine (display, FRAME_X_DRAWABLE (f), gc, | ||
| 10863 | s->x, y_center, s->x + width, y_center); | ||
| 10864 | |||
| 10865 | /* Restore the initial line style. */ | ||
| 10866 | gcv.line_style = LineSolid; | ||
| 10867 | gcv.line_width = 1; | ||
| 10868 | XChangeGC (display, s->gc, GCLineStyle | GCLineWidth, &gcv); | ||
| 10869 | #else /* USE_CAIRO */ | ||
| 10870 | cairo_t *cr; | ||
| 10871 | double cr_segment, y_center; | ||
| 10872 | |||
| 10873 | cr = x_begin_cr_clip (f, s->gc); | ||
| 10874 | cr_segment = (double) segment; | ||
| 10875 | y_center = s->ybase + offset + (thickness / 2.0); | ||
| 10876 | |||
| 10877 | x_set_cr_source_with_gc_foreground (f, s->gc, false); | ||
| 10878 | cairo_set_dash (cr, &cr_segment, 1, s->x); | ||
| 10879 | cairo_set_line_width (cr, thickness); | ||
| 10880 | cairo_move_to (cr, s->x, y_center); | ||
| 10881 | cairo_line_to (cr, s->x + width, y_center); | ||
| 10882 | cairo_stroke (cr); | ||
| 10883 | x_end_cr_clip (f); | ||
| 10884 | #endif /* USE_CAIRO */ | ||
| 10885 | } | ||
| 10886 | |||
| 10887 | /* Draw an underline of STYLE onto F at an offset of POSITION from the | ||
| 10888 | baseline of the glyph string S, DECORATION_WIDTH in length, and | ||
| 10889 | THICKNESS in height. */ | ||
| 10890 | |||
| 10891 | static void | ||
| 10892 | x_fill_underline (struct frame *f, struct glyph_string *s, | ||
| 10893 | enum face_underline_type style, int position, | ||
| 10894 | int decoration_width, int thickness) | ||
| 10895 | { | ||
| 10896 | int segment; | ||
| 10897 | char x_segment; | ||
| 10898 | |||
| 10899 | segment = thickness * 3; | ||
| 10900 | |||
| 10901 | switch (style) | ||
| 10902 | { | ||
| 10903 | /* FACE_UNDERLINE_DOUBLE_LINE is treated identically to SINGLE, as | ||
| 10904 | the second line will be filled by another invocation of this | ||
| 10905 | function. */ | ||
| 10906 | case FACE_UNDERLINE_SINGLE: | ||
| 10907 | case FACE_UNDERLINE_DOUBLE_LINE: | ||
| 10908 | x_fill_rectangle (f, s->gc, s->x, s->ybase + position, | ||
| 10909 | decoration_width, thickness, false); | ||
| 10910 | break; | ||
| 10911 | |||
| 10912 | case FACE_UNDERLINE_DOTS: | ||
| 10913 | segment = thickness; | ||
| 10914 | FALLTHROUGH; | ||
| 10915 | |||
| 10916 | case FACE_UNDERLINE_DASHES: | ||
| 10917 | x_segment = min (segment, CHAR_MAX); | ||
| 10918 | x_draw_dash (f, s, decoration_width, x_segment, position, | ||
| 10919 | thickness); | ||
| 10920 | break; | ||
| 10921 | |||
| 10922 | case FACE_NO_UNDERLINE: | ||
| 10923 | case FACE_UNDERLINE_WAVE: | ||
| 10924 | default: | ||
| 10925 | emacs_abort (); | ||
| 10926 | } | ||
| 10927 | } | ||
| 10836 | 10928 | ||
| 10837 | /* Draw glyph string S. */ | 10929 | /* Draw glyph string S. */ |
| 10838 | 10930 | ||
| @@ -10973,16 +11065,13 @@ x_draw_glyph_string (struct glyph_string *s) | |||
| 10973 | XSetForeground (display, s->gc, xgcv.foreground); | 11065 | XSetForeground (display, s->gc, xgcv.foreground); |
| 10974 | } | 11066 | } |
| 10975 | } | 11067 | } |
| 10976 | else if (s->face->underline == FACE_UNDERLINE_SINGLE | 11068 | else if (s->face->underline >= FACE_UNDERLINE_SINGLE) |
| 10977 | || s->face->underline == FACE_UNDERLINE_DOUBLE_LINE) | ||
| 10978 | { | 11069 | { |
| 10979 | unsigned long thickness, position; | 11070 | unsigned long thickness, position; |
| 10980 | int y; | ||
| 10981 | 11071 | ||
| 10982 | if (s->prev | 11072 | if (s->prev |
| 10983 | && ((s->prev->face->underline == FACE_UNDERLINE_SINGLE) | 11073 | && (s->prev->face->underline != FACE_UNDERLINE_WAVE |
| 10984 | || (s->prev->face->underline | 11074 | && s->prev->face->underline >= FACE_UNDERLINE_SINGLE) |
| 10985 | == FACE_UNDERLINE_DOUBLE_LINE)) | ||
| 10986 | && (s->prev->face->underline_at_descent_line_p | 11075 | && (s->prev->face->underline_at_descent_line_p |
| 10987 | == s->face->underline_at_descent_line_p) | 11076 | == s->face->underline_at_descent_line_p) |
| 10988 | && (s->prev->face->underline_pixels_above_descent_line | 11077 | && (s->prev->face->underline_pixels_above_descent_line |
| @@ -11064,20 +11153,16 @@ x_draw_glyph_string (struct glyph_string *s) | |||
| 11064 | Display *display = FRAME_X_DISPLAY (s->f); | 11153 | Display *display = FRAME_X_DISPLAY (s->f); |
| 11065 | XGCValues xgcv; | 11154 | XGCValues xgcv; |
| 11066 | 11155 | ||
| 11067 | y = s->ybase + position; | 11156 | if (!s->face->underline_defaulted_p) |
| 11068 | if (s->face->underline_defaulted_p) | ||
| 11069 | x_fill_rectangle (s->f, s->gc, | ||
| 11070 | s->x, y, decoration_width, thickness, | ||
| 11071 | false); | ||
| 11072 | else | ||
| 11073 | { | 11157 | { |
| 11074 | XGetGCValues (display, s->gc, GCForeground, &xgcv); | 11158 | XGetGCValues (display, s->gc, GCForeground, &xgcv); |
| 11075 | XSetForeground (display, s->gc, s->face->underline_color); | 11159 | XSetForeground (display, s->gc, s->face->underline_color); |
| 11076 | x_fill_rectangle (s->f, s->gc, | ||
| 11077 | s->x, y, decoration_width, thickness, | ||
| 11078 | false); | ||
| 11079 | } | 11160 | } |
| 11080 | 11161 | ||
| 11162 | x_fill_underline (s->f, s, s->face->underline, | ||
| 11163 | position, decoration_width, | ||
| 11164 | thickness); | ||
| 11165 | |||
| 11081 | /* Place a second underline above the first if this was | 11166 | /* Place a second underline above the first if this was |
| 11082 | requested in the face specification. */ | 11167 | requested in the face specification. */ |
| 11083 | 11168 | ||
| @@ -11085,9 +11170,9 @@ x_draw_glyph_string (struct glyph_string *s) | |||
| 11085 | { | 11170 | { |
| 11086 | /* Compute the position of the second underline. */ | 11171 | /* Compute the position of the second underline. */ |
| 11087 | position = position - thickness - 1; | 11172 | position = position - thickness - 1; |
| 11088 | y = s->ybase + position; | 11173 | x_fill_underline (s->f, s, s->face->underline, |
| 11089 | x_fill_rectangle (s->f, s->gc, s->x, y, decoration_width, | 11174 | position, decoration_width, |
| 11090 | thickness, false); | 11175 | thickness); |
| 11091 | } | 11176 | } |
| 11092 | 11177 | ||
| 11093 | if (!s->face->underline_defaulted_p) | 11178 | if (!s->face->underline_defaulted_p) |