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.
This commit is contained in:
Po Lu
-
parent 77a170a175
commit e844b81c56
3 changed files with 108 additions and 23 deletions

View File

@@ -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,

View File

@@ -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;
}

View File

@@ -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)