From: Po Lu Date: Thu, 1 Jan 1970 00:00:00 +0000 (+0000) Subject: Implement dots and dashes on X X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=63a3ebdd3106a3c789659b94927f441cdafb9db3;p=emacs.git 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. (cherry picked from commit e844b81c56d74aa2b2efa0ce98ed3de71647e656) --- 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 enum face_underline_type { - /* Note: Order matches the order of the Smulx terminfo extension. */ + /* Note: order matches the order of the Smulx terminfo extension, and + is also relied on to remain in its present order by + x_draw_glyph_string and company. */ FACE_NO_UNDERLINE = 0, FACE_UNDERLINE_SINGLE, 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] face->underline = FACE_UNDERLINE_DOUBLE_LINE; else if (EQ (value, Qwave)) face->underline = FACE_UNDERLINE_WAVE; -#if 0 else if (EQ (value, Qdots)) face->underline = FACE_UNDERLINE_DOTS; else if (EQ (value, Qdashes)) face->underline = FACE_UNDERLINE_DASHES; -#endif /* 0 */ else face->underline = FACE_UNDERLINE_SINGLE; } 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, static void x_draw_underwave (struct glyph_string *s, int decoration_width) { - Display *display; struct x_display_info *dpyinfo; /* Adjust for scale/HiDPI. */ int scale_x, scale_y; dpyinfo = FRAME_DISPLAY_INFO (s->f); - display = dpyinfo->display; x_get_scale_factor (dpyinfo, &scale_x, &scale_y); 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) x_draw_horizontal_wave (s->f, s->gc, s->x, s->ybase - wave_height + 3, decoration_width, wave_height, wave_length); #else /* not USE_CAIRO */ + Display *display; int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax, thickness = scale_y;; bool odd; XRectangle wave_clip, string_clip, final_clip; @@ -10801,6 +10800,7 @@ x_draw_underwave (struct glyph_string *s, int decoration_width) if (!gui_intersect_rectangles (&wave_clip, &string_clip, &final_clip)) return; + display = dpyinfo->display; XSetClipRectangles (display, s->gc, 0, 0, &final_clip, 1, Unsorted); /* Draw the waves */ @@ -10833,6 +10833,98 @@ x_draw_underwave (struct glyph_string *s, int decoration_width) #endif /* not USE_CAIRO */ } +/* Draw a dashed underline of thickness THICKNESS and width WIDTH onto F + at a vertical offset of OFFSET from the position of the glyph string + S, with each segment SEGMENT pixels in length. */ + +static void +x_draw_dash (struct frame *f, struct glyph_string *s, int width, + char segment, int offset, int thickness) +{ +#ifndef USE_CAIRO + GC gc; + Display *display; + XGCValues gcv; + int y_center; + + /* Configure the GC, the dash pattern and a suitable offset. */ + gc = s->gc; + display = FRAME_X_DISPLAY (f); + + XGetGCValues (display, s->gc, GCLineStyle, &gcv); + gcv.line_style = LineOnOffDash; + gcv.line_width = thickness; + XChangeGC (display, s->gc, GCLineStyle | GCLineWidth, &gcv); + XSetDashes (display, s->gc, s->x, &segment, 1); + + /* Offset the origin of the line by half the line width. */ + y_center = s->ybase + offset + thickness / 2; + XDrawLine (display, FRAME_X_DRAWABLE (f), gc, + s->x, y_center, s->x + width, y_center); + + /* Restore the initial line style. */ + gcv.line_style = LineSolid; + gcv.line_width = 1; + XChangeGC (display, s->gc, GCLineStyle | GCLineWidth, &gcv); +#else /* USE_CAIRO */ + cairo_t *cr; + double cr_segment, y_center; + + cr = x_begin_cr_clip (f, s->gc); + cr_segment = (double) segment; + y_center = s->ybase + offset + (thickness / 2.0); + + x_set_cr_source_with_gc_foreground (f, s->gc, false); + cairo_set_dash (cr, &cr_segment, 1, s->x); + cairo_set_line_width (cr, thickness); + cairo_move_to (cr, s->x, y_center); + cairo_line_to (cr, s->x + width, y_center); + cairo_stroke (cr); + x_end_cr_clip (f); +#endif /* USE_CAIRO */ +} + +/* Draw an underline of STYLE onto F at an offset of POSITION from the + baseline of the glyph string S, DECORATION_WIDTH in length, and + THICKNESS in height. */ + +static void +x_fill_underline (struct frame *f, struct glyph_string *s, + enum face_underline_type style, int position, + int decoration_width, int thickness) +{ + int segment; + char x_segment; + + segment = thickness * 3; + + switch (style) + { + /* FACE_UNDERLINE_DOUBLE_LINE is treated identically to SINGLE, as + the second line will be filled by another invocation of this + function. */ + case FACE_UNDERLINE_SINGLE: + case FACE_UNDERLINE_DOUBLE_LINE: + x_fill_rectangle (f, s->gc, s->x, s->ybase + position, + decoration_width, thickness, false); + break; + + case FACE_UNDERLINE_DOTS: + segment = thickness; + FALLTHROUGH; + + case FACE_UNDERLINE_DASHES: + x_segment = min (segment, CHAR_MAX); + x_draw_dash (f, s, decoration_width, x_segment, position, + thickness); + break; + + case FACE_NO_UNDERLINE: + case FACE_UNDERLINE_WAVE: + default: + emacs_abort (); + } +} /* Draw glyph string S. */ @@ -10973,16 +11065,13 @@ x_draw_glyph_string (struct glyph_string *s) XSetForeground (display, s->gc, xgcv.foreground); } } - else if (s->face->underline == FACE_UNDERLINE_SINGLE - || s->face->underline == FACE_UNDERLINE_DOUBLE_LINE) + else if (s->face->underline >= FACE_UNDERLINE_SINGLE) { unsigned long thickness, position; - int y; if (s->prev - && ((s->prev->face->underline == FACE_UNDERLINE_SINGLE) - || (s->prev->face->underline - == FACE_UNDERLINE_DOUBLE_LINE)) + && (s->prev->face->underline != FACE_UNDERLINE_WAVE + && s->prev->face->underline >= FACE_UNDERLINE_SINGLE) && (s->prev->face->underline_at_descent_line_p == s->face->underline_at_descent_line_p) && (s->prev->face->underline_pixels_above_descent_line @@ -11064,20 +11153,16 @@ x_draw_glyph_string (struct glyph_string *s) Display *display = FRAME_X_DISPLAY (s->f); XGCValues xgcv; - y = s->ybase + position; - if (s->face->underline_defaulted_p) - x_fill_rectangle (s->f, s->gc, - s->x, y, decoration_width, thickness, - false); - else + if (!s->face->underline_defaulted_p) { XGetGCValues (display, s->gc, GCForeground, &xgcv); XSetForeground (display, s->gc, s->face->underline_color); - x_fill_rectangle (s->f, s->gc, - s->x, y, decoration_width, thickness, - false); } + x_fill_underline (s->f, s, s->face->underline, + position, decoration_width, + thickness); + /* Place a second underline above the first if this was requested in the face specification. */ @@ -11085,9 +11170,9 @@ x_draw_glyph_string (struct glyph_string *s) { /* Compute the position of the second underline. */ position = position - thickness - 1; - y = s->ybase + position; - x_fill_rectangle (s->f, s->gc, s->x, y, decoration_width, - thickness, false); + x_fill_underline (s->f, s, s->face->underline, + position, decoration_width, + thickness); } if (!s->face->underline_defaulted_p)