From: Alp Aker Date: Sun, 17 Jun 2012 00:32:36 +0000 (-0400) Subject: Implement wave-style variant of underlining. X-Git-Tag: emacs-24.2.90~1199^2~455 X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=9b0e3ebaef5aed8097965b14c97a0579763be7fd;p=emacs.git Implement wave-style variant of underlining. * doc/lispref/display.texi: Document new face attribute. * lisp/cus-face.el (custom-face-attributes): Add wave-style underline attribute. * lisp/faces.el (set-face-attribute): Update docstring. * src/dispextern.h (face_underline_type): New enum. (face): Add field for underline type. * src/nsterm.m (ns_draw_underwave): New function. (ns_draw_text_decoration): Use it. * src/w32term.c (w32_restore_glyph_string_clip, w32_draw_underwave): New functions. (x_draw_glyph_string): Use them. * src/xfaces.c (Qline, Qwave): New Lisp objects. (check_lface_attrs, merge_face_ref) (Finternal_set_lisp_face_attribute, realize_x_face): Handle wave-style underline face attributes. * src/xterm.c (x_draw_underwave): New function. (x_draw_glyph_string): Use it. --- diff --git a/ChangeLog b/ChangeLog index f089df625a9..a72d426416d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2012-06-16 Aurelien Aptel + + * doc/lispref/display.texi: Document wave-style underline + face attribute. + 2012-06-13 Andreas Schwab * configure.in: Rename --enable-use-lisp-union-type to diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 5face4138e0..60e14b6b85b 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -2130,10 +2130,32 @@ Background color, a string. The value can be a system-defined color name, or a hexadecimal color specification. @xref{Color Names}. @item :underline -Whether or not characters should be underlined, and in what color. If -the value is @code{t}, underlining uses the foreground color of the -face. If the value is a string, underlining uses that color. The -value @code{nil} means do not underline. +Whether or not characters should be underlined, and in what +color. Here are the possible values of the @code{:underline} +attribute, and what they mean: + +@table @asis +@item @code{nil} +Don't underline. + +@item @code{t} +Underline with the foreground color of the face. + +@item @var{color} +Underline in color @var{color}. + +@item @code{(:color @var{color} :style @var{style})} +If @var{color} is a string, underline in it. +If @var{color} is @code{foreground-color}, underline with the +foreground color of the face. + +If @var{style} is @code{wave} underline with a wave. +If @var{style} is @code{line} underline with a line. + +If the attribute @code{:color} is omited, underline with the +foreground color of the face. +If the attribute @code{:style} is omited, underline with a line. +@end table @item :overline Whether or not characters should be overlined, and in what color. diff --git a/lisp/ChangeLog b/lisp/ChangeLog index ee7f2562185..ddc8f9b5a7e 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -1,3 +1,10 @@ +2012-06-16 Aurelien Aptel + + * cus-face.el (custom-face-attributes): Add wave-style underline + attribute. + * faces.el (set-face-attribute): Update docstring to describe + wave-style underline attribute. + 2012-06-16 Chong Yidong * term/xterm.el (terminal-init-xterm): Discard input before diff --git a/lisp/cus-face.el b/lisp/cus-face.el index d725111b6fd..3680a2648ce 100644 --- a/lisp/cus-face.el +++ b/lisp/cus-face.el @@ -135,8 +135,13 @@ (choice :tag "Underline" :help-echo "Control text underlining." (const :tag "Off" nil) - (const :tag "On" t) - (color :tag "Colored"))) + (list :tag "On" + (const :format "" :value :color) + (choice :tag "Color" (const :tag "Foreground Color" foreground-color) color) + (const :format "" :value :style) + (choice :tag "Style" + (const :tag "Line" line) + (const :tag "Wave" wave))))) (:overline (choice :tag "Overline" diff --git a/lisp/faces.el b/lisp/faces.el index 0c1eab474c3..40b45187f6c 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -623,10 +623,21 @@ VALUE must be a color name, a string. `:underline' -VALUE specifies whether characters in FACE should be underlined. If -VALUE is t, underline with foreground color of the face. If VALUE is -a string, underline with that color. If VALUE is nil, explicitly -don't underline. +VALUE specifies whether characters in FACE should be underlined. +If VALUE is t, underline with foreground color of the face. +If VALUE is a string, underline with that color. +If VALUE is nil, explicitly don't underline. + +Otherwise, VALUE must be a property list of the form: + +`(:color COLOR :style STYLE)'. + +COLOR can be a either a color name string or `foreground-color'. +STYLE can be either `line' or `wave'. +If a keyword/value pair is missing from the property list, a +default value will be used for the value. +The default value of COLOR is the foreground color of the face. +The default value of STYLE is `line'. `:overline' diff --git a/src/ChangeLog b/src/ChangeLog index 321c3b9c62f..d392dd522b3 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,20 @@ +2012-06-16 Aurelien Aptel + + Implement wave-style variant of underlining. + * dispextern.h (face_underline_type): New enum. + (face): Add field for underline type. + * nsterm.m (ns_draw_underwave): New function. + (ns_draw_text_decoration): Use it. + * w32term.c (w32_restore_glyph_string_clip, w32_draw_underwave): + New functions. + (x_draw_glyph_string): Use them. + * xfaces.c (Qline, Qwave): New Lisp objects. + (check_lface_attrs, merge_face_ref) + (Finternal_set_lisp_face_attribute, realize_x_face): Handle + wave-style underline face attributes. + * xterm.c (x_draw_underwave): New function. + (x_draw_glyph_string): Use it. + 2012-06-16 Juanma Barranquero * makefile.w32-in ($(BLD)/emacs.$(O), $(BLD)/fringe.$(O)) diff --git a/src/dispextern.h b/src/dispextern.h index 6e070f3dbef..fc7bec97f7a 100644 --- a/src/dispextern.h +++ b/src/dispextern.h @@ -1510,6 +1510,13 @@ enum face_box_type FACE_SUNKEN_BOX }; +/* Underline type. */ + +enum face_underline_type +{ + FACE_UNDER_LINE, + FACE_UNDER_WAVE +}; /* Structure describing a realized face. @@ -1585,6 +1592,9 @@ struct face drawing shadows. */ unsigned use_box_color_for_shadows_p : 1; + /* Style of underlining. */ + enum face_underline_type underline_type; + /* Non-zero if text in this face should be underlined, overlined, strike-through or have a box drawn around it. */ unsigned underline_p : 1; diff --git a/src/nsterm.m b/src/nsterm.m index 8bd2bb283b2..48057302090 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -2595,6 +2595,60 @@ ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr) return n; } +/* -------------------------------------------------------------------- + Draw a wavy line under glyph string s. The wave fills wave_height + pixels from y. + + x wave_length = 3 + -- + y * * * * * + |* * * * * * * * * + wave_height = 3 | * * * * + --------------------------------------------------------------------- */ + +static void +ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x) +{ + int wave_height = 3, wave_length = 3; + int y, dx, dy, odd, xmax; + NSPoint a, b; + NSRect waveClip; + + dx = wave_length; + dy = wave_height - 1; + y = s->ybase + 1; + xmax = x + width; + + /* Find and set clipping rectangle */ + waveClip = NSMakeRect (x, y, width, wave_height); + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (waveClip); + + /* Draw the waves */ + a.x = x - ((int)(x) % dx); + b.x = a.x + dx; + odd = (int)(a.x/dx) % 2; + a.y = b.y = y; + + if (odd) + a.y += dy; + else + b.y += dy; + + while (a.x <= xmax) + { + [NSBezierPath strokeLineFromPoint:a toPoint:b]; + a.x = b.x, a.y = b.y; + b.x += dx, b.y = y + odd*dy; + odd = !odd; + } + + /* Restore previous clipping rectangle(s) */ + [[NSGraphicsContext currentContext] restoreGraphicsState]; +} + + + void ns_draw_text_decoration (struct glyph_string *s, struct face *face, NSColor *defaultCol, CGFloat width, CGFloat x) @@ -2608,63 +2662,75 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face, /* Do underline. */ if (face->underline_p) { - NSRect r; - unsigned long thickness, position; - - /* If the prev was underlined, match its appearance. */ - if (s->prev && s->prev->face->underline_p - && s->prev->underline_thickness > 0) + if (s->face->underline_type == FACE_UNDER_WAVE) { - thickness = s->prev->underline_thickness; - position = s->prev->underline_position; + if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + + ns_draw_underwave (s, width, x); } - else + else if (s->face->underline_type == FACE_UNDER_LINE) { - struct font *font; - unsigned long descent; - - font=s->font; - descent = s->y + s->height - s->ybase; - - /* Use underline thickness of font, defaulting to 1. */ - thickness = (font && font->underline_thickness > 0) - ? font->underline_thickness : 1; - - /* Determine the offset of underlining from the baseline. */ - if (x_underline_at_descent_line) - position = descent - thickness; - else if (x_use_underline_position_properties - && font && font->underline_position >= 0) - position = font->underline_position; - else if (font) - position = lround (font->descent / 2); - else - position = underline_minimum_offset; - position = max (position, underline_minimum_offset); + NSRect r; + unsigned long thickness, position; - /* Ensure underlining is not cropped. */ - if (descent <= position) + /* If the prev was underlined, match its appearance. */ + if (s->prev && s->prev->face->underline_p + && s->prev->underline_thickness > 0) { - position = descent - 1; - thickness = 1; + thickness = s->prev->underline_thickness; + position = s->prev->underline_position; } - else if (descent < position + thickness) - thickness = 1; - } + else + { + struct font *font; + unsigned long descent; + + font=s->font; + descent = s->y + s->height - s->ybase; + + /* Use underline thickness of font, defaulting to 1. */ + thickness = (font && font->underline_thickness > 0) + ? font->underline_thickness : 1; + + /* Determine the offset of underlining from the baseline. */ + if (x_underline_at_descent_line) + position = descent - thickness; + else if (x_use_underline_position_properties + && font && font->underline_position >= 0) + position = font->underline_position; + else if (font) + position = lround (font->descent / 2); + else + position = underline_minimum_offset; - s->underline_thickness = thickness; - s->underline_position = position; + position = max (position, underline_minimum_offset); - r = NSMakeRect (x, s->ybase + position, width, thickness); + /* Ensure underlining is not cropped. */ + if (descent <= position) + { + position = descent - 1; + thickness = 1; + } + else if (descent < position + thickness) + thickness = 1; + } - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; - NSRectFill (r); - } + s->underline_thickness = thickness; + s->underline_position = position; + + r = NSMakeRect (x, s->ybase + position, width, thickness); + if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + NSRectFill (r); + } + } /* Do overline. We follow other terms in using a thickness of 1 and ignoring overline_margin. */ if (face->overline_p) diff --git a/src/w32term.c b/src/w32term.c index 38120b77ac9..6a4b3ca4afb 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -313,6 +313,94 @@ w32_set_clip_rectangle (HDC hdc, RECT *rect) SelectClipRgn (hdc, NULL); } +/* Restore clipping rectangle in S */ +static void +w32_restore_glyph_string_clip (struct glyph_string *s) +{ + RECT *r = s->clip; + int n = s->num_clips; + + if (n == 1) + w32_set_clip_rectangle (s->hdc, r); + else if (n > 1) + { + HRGN clip1 = CreateRectRgnIndirect (r); + HRGN clip2 = CreateRectRgnIndirect (r + 1); + if (CombineRgn (clip1, clip1, clip2, RGN_OR) != ERROR) + SelectClipRgn (s->hdc, clip1); + DeleteObject (clip1); + DeleteObject (clip2); + } +} + +/* + Draw a wavy line under S. The wave fills wave_height pixels from y0. + + x0 wave_length = 2 + -- + y0 * * * * * + |* * * * * * * * * + wave_height = 3 | * * * * + +*/ + +void +w32_draw_underwave (struct glyph_string *s, COLORREF color) +{ + int wave_height = 2, wave_length = 3; + int dx, dy, x0, y0, width, x1, y1, x2, y2, odd, xmax; + XRectangle wave_clip, string_clip, final_clip; + RECT w32_final_clip, w32_string_clip; + HPEN hp, oldhp; + + dx = wave_length; + dy = wave_height - 1; + x0 = s->x; + y0 = s->ybase + 1; + width = s->width; + xmax = x0 + width; + + /* Find and set clipping rectangle */ + + wave_clip = (XRectangle){ x0, y0, width, wave_height }; + get_glyph_string_clip_rect (s, &w32_string_clip); + CONVERT_TO_XRECT (string_clip, w32_string_clip); + + if (!x_intersect_rectangles (&wave_clip, &string_clip, &final_clip)) + return; + + hp = CreatePen (PS_SOLID, 0, color); + oldhp = SelectObject (s->hdc, hp); + CONVERT_FROM_XRECT (final_clip, w32_final_clip); + w32_set_clip_rectangle (s->hdc, &w32_final_clip); + + /* Draw the waves */ + + x1 = x0 - (x0 % dx); + x2 = x1 + dx; + odd = (x1/dx) % 2; + y1 = y2 = y0; + + if (odd) + y1 += dy; + else + y2 += dy; + + MoveToEx (s->hdc, x1, y1, NULL); + + while (x1 <= xmax) + { + LineTo (s->hdc, x2, y2); + x1 = x2, y1 = y2; + x2 += dx, y2 = y0 + odd*dy; + odd = !odd; + } + + /* Restore previous pen and clipping rectangle(s) */ + w32_restore_glyph_string_clip (s); + SelectObject (s->hdc, oldhp); + DeleteObject (hp); +} /* Draw a hollow rectangle at the specified position. */ void @@ -2347,60 +2435,74 @@ x_draw_glyph_string (struct glyph_string *s) /* Draw underline. */ if (s->face->underline_p) { - unsigned long thickness, position; - int y; - - if (s->prev && s->prev->face->underline_p) + if (s->face->underline_type == FACE_UNDER_WAVE) { - /* We use the same underline style as the previous one. */ - thickness = s->prev->underline_thickness; - position = s->prev->underline_position; + COLORREF color; + + if (s->face->underline_defaulted_p) + color = s->gc->foreground; + else + color = s->face->underline_color; + + w32_draw_underwave (s, color); } - else + else if (s->face->underline_type == FACE_UNDER_LINE) { - /* Get the underline thickness. Default is 1 pixel. */ - if (s->font && s->font->underline_thickness > 0) - thickness = s->font->underline_thickness; + unsigned long thickness, position; + int y; + + if (s->prev && s->prev->face->underline_p) + { + /* We use the same underline style as the previous one. */ + thickness = s->prev->underline_thickness; + position = s->prev->underline_position; + } else - thickness = 1; - if (x_underline_at_descent_line) - position = (s->height - thickness) - (s->ybase - s->y); + { + /* Get the underline thickness. Default is 1 pixel. */ + if (s->font && s->font->underline_thickness > 0) + thickness = s->font->underline_thickness; + else + thickness = 1; + if (x_underline_at_descent_line) + position = (s->height - thickness) - (s->ybase - s->y); + else + { + /* Get the underline position. This is the recommended + vertical offset in pixels from the baseline to the top of + the underline. This is a signed value according to the + specs, and its default is + + ROUND ((maximum_descent) / 2), with + ROUND (x) = floor (x + 0.5) */ + + if (x_use_underline_position_properties + && s->font && s->font->underline_position >= 0) + position = s->font->underline_position; + else if (s->font) + position = (s->font->descent + 1) / 2; + } + position = max (position, underline_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 + thickness) + thickness = (s->y + s->height) - (s->ybase + position); + s->underline_thickness = thickness; + s->underline_position =position; + y = s->ybase + position; + if (s->face->underline_defaulted_p) + { + w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x, + y, s->width, 1); + } else { - /* Get the underline position. This is the recommended - vertical offset in pixels from the baseline to the top of - the underline. This is a signed value according to the - specs, and its default is - - ROUND ((maximum_descent) / 2), with - ROUND (x) = floor (x + 0.5) */ - - if (x_use_underline_position_properties - && s->font && s->font->underline_position >= 0) - position = s->font->underline_position; - else if (s->font) - position = (s->font->descent + 1) / 2; + w32_fill_area (s->f, s->hdc, s->face->underline_color, s->x, + y, s->width, 1); } - position = max (position, underline_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 + thickness) - thickness = (s->y + s->height) - (s->ybase + position); - s->underline_thickness = thickness; - s->underline_position =position; - y = s->ybase + position; - if (s->face->underline_defaulted_p) - { - w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x, - y, s->width, 1); - } - else - { - w32_fill_area (s->f, s->hdc, s->face->underline_color, s->x, - y, s->width, 1); } } /* Draw overline. */ diff --git a/src/xfaces.c b/src/xfaces.c index 772d2646291..32d1499b85a 100644 --- a/src/xfaces.c +++ b/src/xfaces.c @@ -320,6 +320,7 @@ static Lisp_Object QCfontset; Lisp_Object Qnormal; Lisp_Object Qbold; +static Lisp_Object Qline, Qwave; static Lisp_Object Qultra_light, Qextra_light, Qlight; static Lisp_Object Qsemi_light, Qsemi_bold, Qextra_bold, Qultra_bold; static Lisp_Object Qoblique, Qreverse_oblique, Qreverse_italic; @@ -1894,7 +1895,8 @@ check_lface_attrs (Lisp_Object *attrs) xassert (UNSPECIFIEDP (attrs[LFACE_UNDERLINE_INDEX]) || IGNORE_DEFFACE_P (attrs[LFACE_UNDERLINE_INDEX]) || SYMBOLP (attrs[LFACE_UNDERLINE_INDEX]) - || STRINGP (attrs[LFACE_UNDERLINE_INDEX])); + || STRINGP (attrs[LFACE_UNDERLINE_INDEX]) + || CONSP (attrs[LFACE_UNDERLINE_INDEX])); xassert (UNSPECIFIEDP (attrs[LFACE_OVERLINE_INDEX]) || IGNORE_DEFFACE_P (attrs[LFACE_OVERLINE_INDEX]) || SYMBOLP (attrs[LFACE_OVERLINE_INDEX]) @@ -2525,7 +2527,8 @@ merge_face_ref (struct frame *f, Lisp_Object face_ref, Lisp_Object *to, { if (EQ (value, Qt) || NILP (value) - || STRINGP (value)) + || STRINGP (value) + || CONSP (value)) to[LFACE_UNDERLINE_INDEX] = value; else err = 1; @@ -2948,15 +2951,54 @@ FRAME 0 means change the face on all frames, and change the default } else if (EQ (attr, QCunderline)) { - if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value)) - if ((SYMBOLP (value) - && !EQ (value, Qt) - && !EQ (value, Qnil)) - /* Underline color. */ - || (STRINGP (value) - && SCHARS (value) == 0)) - signal_error ("Invalid face underline", value); - + int valid_p = 0; + + if (UNSPECIFIEDP (value) || IGNORE_DEFFACE_P (value)) + valid_p = 1; + else if (NILP (value) || EQ (value, Qt)) + valid_p = 1; + else if (STRINGP (value) && SCHARS (value) > 0) + valid_p = 1; + else if (CONSP (value)) + { + Lisp_Object key, val, list; + + list = value; + valid_p = 1; + + while (!NILP (CAR_SAFE(list))) + { + key = CAR_SAFE (list); + list = CDR_SAFE (list); + val = CAR_SAFE (list); + list = CDR_SAFE (list); + + if(NILP (key) || NILP (val)) + { + valid_p = 0; + break; + } + + else if (EQ (key, QCcolor) + && !(EQ (val, Qforeground_color) + || (STRINGP (val) && SCHARS (val) > 0))) + { + valid_p = 0; + break; + } + + else if (EQ (key, QCstyle) + && !(EQ (val, Qline) || EQ (val, Qwave))) + { + valid_p = 0; + break; + } + } + } + + if (!valid_p) + signal_error ("Invalid face underline", value); + old_value = LFACE_UNDERLINE (lface); LFACE_UNDERLINE (lface) = value; } @@ -5576,7 +5618,7 @@ realize_x_face (struct face_cache *cache, Lisp_Object *attrs) #ifdef HAVE_WINDOW_SYSTEM struct face *default_face; struct frame *f; - Lisp_Object stipple, overline, strike_through, box; + Lisp_Object stipple, underline, overline, strike_through, box; xassert (FRAME_WINDOW_P (cache->f)); @@ -5709,29 +5751,76 @@ realize_x_face (struct face_cache *cache, Lisp_Object *attrs) /* Text underline, overline, strike-through. */ - if (EQ (attrs[LFACE_UNDERLINE_INDEX], Qt)) + underline = attrs[LFACE_UNDERLINE_INDEX]; + if (EQ (underline, Qt)) { /* Use default color (same as foreground color). */ face->underline_p = 1; + face->underline_type = FACE_UNDER_LINE; face->underline_defaulted_p = 1; face->underline_color = 0; } - else if (STRINGP (attrs[LFACE_UNDERLINE_INDEX])) + else if (STRINGP (underline)) { /* Use specified color. */ face->underline_p = 1; + face->underline_type = FACE_UNDER_LINE; face->underline_defaulted_p = 0; face->underline_color - = load_color (f, face, attrs[LFACE_UNDERLINE_INDEX], + = load_color (f, face, underline, LFACE_UNDERLINE_INDEX); } - else if (NILP (attrs[LFACE_UNDERLINE_INDEX])) + else if (NILP (underline)) { face->underline_p = 0; face->underline_defaulted_p = 0; face->underline_color = 0; } - + else if (CONSP (underline)) + { + /* `(:color COLOR :style STYLE)'. + STYLE being one of `line' or `wave'. */ + face->underline_p = 1; + face->underline_color = 0; + face->underline_defaulted_p = 1; + face->underline_type = FACE_UNDER_LINE; + + while (CONSP (underline)) + { + Lisp_Object keyword, value; + + keyword = XCAR (underline); + underline = XCDR (underline); + + if (!CONSP (underline)) + break; + value = XCAR (underline); + underline = XCDR (underline); + + if (EQ (keyword, QCcolor)) + { + if (EQ (value, Qforeground_color)) + { + face->underline_defaulted_p = 1; + face->underline_color = 0; + } + else if (STRINGP (value)) + { + face->underline_defaulted_p = 0; + face->underline_color = load_color (f, face, value, + LFACE_UNDERLINE_INDEX); + } + } + else if (EQ (keyword, QCstyle)) + { + if (EQ (value, Qline)) + face->underline_type = FACE_UNDER_LINE; + else if (EQ (value, Qwave)) + face->underline_type = FACE_UNDER_WAVE; + } + } + } + overline = attrs[LFACE_OVERLINE_INDEX]; if (STRINGP (overline)) { @@ -6476,6 +6565,8 @@ syms_of_xfaces (void) DEFSYM (QCcolor, ":color"); DEFSYM (QCline_width, ":line-width"); DEFSYM (QCstyle, ":style"); + DEFSYM (Qline, "line"); + DEFSYM (Qwave, "wave"); DEFSYM (Qreleased_button, "released-button"); DEFSYM (Qpressed_button, "pressed-button"); DEFSYM (Qnormal, "normal"); diff --git a/src/xterm.c b/src/xterm.c index 3c7a7efdd71..914d195778f 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -2663,6 +2663,65 @@ x_draw_stretch_glyph_string (struct glyph_string *s) s->background_filled_p = 1; } +/* + Draw a wavy line under S. The wave fills wave_height pixels from y0. + + x0 wave_length = 2 + -- + y0 * * * * * + |* * * * * * * * * + wave_height = 3 | * * * * + +*/ + +static void +x_draw_underwave (struct glyph_string *s) +{ + int wave_height = 2, wave_length = 3; + int dx, dy, x0, y0, width, x1, y1, x2, y2, odd, xmax; + XRectangle wave_clip, string_clip, final_clip; + + dx = wave_length; + dy = wave_height - 1; + x0 = s->x; + y0 = s->ybase + 1; + width = s->width; + xmax = x0 + width; + + /* Find and set clipping rectangle */ + + wave_clip = (XRectangle){ x0, y0, width, wave_height }; + get_glyph_string_clip_rect (s, &string_clip); + + if (!x_intersect_rectangles (&wave_clip, &string_clip, &final_clip)) + return; + + XSetClipRectangles (s->display, s->gc, 0, 0, &final_clip, 1, Unsorted); + + /* Draw the waves */ + + x1 = x0 - (x0 % dx); + x2 = x1 + dx; + odd = (x1/dx) % 2; + y1 = y2 = y0; + + if (odd) + y1 += dy; + else + y2 += dy; + + while (x1 <= xmax) + { + XDrawLine (s->display, s->window, s->gc, x1, y1, x2, y2); + x1 = x2, y1 = y2; + x2 += dx, y2 = y0 + odd*dy; + odd = !odd; + } + + /* Restore previous clipping rectangle(s) */ + XSetClipRectangles (s->display, s->gc, 0, 0, s->clip, s->num_clips, Unsorted); +} + /* Draw glyph string S. */ @@ -2765,68 +2824,83 @@ x_draw_glyph_string (struct glyph_string *s) { /* Draw underline. */ if (s->face->underline_p) - { - unsigned long thickness, position; - int y; - - if (s->prev && s->prev->face->underline_p) - { - /* We use the same underline style as the previous one. */ - thickness = s->prev->underline_thickness; - position = s->prev->underline_position; - } - else - { - /* Get the underline thickness. Default is 1 pixel. */ - if (s->font && s->font->underline_thickness > 0) - thickness = s->font->underline_thickness; - else - thickness = 1; - if (x_underline_at_descent_line) - position = (s->height - thickness) - (s->ybase - s->y); - else - { - /* Get the underline position. This is the recommended - vertical offset in pixels from the baseline to the top of - the underline. This is a signed value according to the - specs, and its default is - - ROUND ((maximum descent) / 2), with - ROUND(x) = floor (x + 0.5) */ - - if (x_use_underline_position_properties - && s->font && s->font->underline_position >= 0) - position = s->font->underline_position; - else if (s->font) - position = (s->font->descent + 1) / 2; - else - position = underline_minimum_offset; - } - position = max (position, underline_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 + thickness) - thickness = (s->y + s->height) - (s->ybase + position); - s->underline_thickness = thickness; - s->underline_position = position; - y = s->ybase + position; - if (s->face->underline_defaulted_p) - XFillRectangle (s->display, s->window, s->gc, - s->x, y, s->width, thickness); - else - { - XGCValues xgcv; - XGetGCValues (s->display, s->gc, GCForeground, &xgcv); - XSetForeground (s->display, s->gc, s->face->underline_color); - XFillRectangle (s->display, s->window, s->gc, - s->x, y, s->width, thickness); - XSetForeground (s->display, s->gc, xgcv.foreground); - } - } + { + if (s->face->underline_type == FACE_UNDER_WAVE) + { + if (s->face->underline_defaulted_p) + x_draw_underwave (s); + else + { + XGCValues xgcv; + XGetGCValues (s->display, s->gc, GCForeground, &xgcv); + XSetForeground (s->display, s->gc, s->face->underline_color); + x_draw_underwave (s); + XSetForeground (s->display, s->gc, xgcv.foreground); + } + } + else if (s->face->underline_type == FACE_UNDER_LINE) + { + unsigned long thickness, position; + int y; + if (s->prev && s->prev->face->underline_p) + { + /* We use the same underline style as the previous one. */ + thickness = s->prev->underline_thickness; + position = s->prev->underline_position; + } + else + { + /* Get the underline thickness. Default is 1 pixel. */ + if (s->font && s->font->underline_thickness > 0) + thickness = s->font->underline_thickness; + else + thickness = 1; + if (x_underline_at_descent_line) + position = (s->height - thickness) - (s->ybase - s->y); + else + { + /* Get the underline position. This is the recommended + vertical offset in pixels from the baseline to the top of + the underline. This is a signed value according to the + specs, and its default is + + ROUND ((maximum descent) / 2), with + ROUND(x) = floor (x + 0.5) */ + + if (x_use_underline_position_properties + && s->font && s->font->underline_position >= 0) + position = s->font->underline_position; + else if (s->font) + position = (s->font->descent + 1) / 2; + else + position = underline_minimum_offset; + } + position = max (position, underline_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 + thickness) + thickness = (s->y + s->height) - (s->ybase + position); + s->underline_thickness = thickness; + s->underline_position = position; + y = s->ybase + position; + if (s->face->underline_defaulted_p) + XFillRectangle (s->display, s->window, s->gc, + s->x, y, s->width, thickness); + else + { + XGCValues xgcv; + XGetGCValues (s->display, s->gc, GCForeground, &xgcv); + XSetForeground (s->display, s->gc, s->face->underline_color); + XFillRectangle (s->display, s->window, s->gc, + s->x, y, s->width, thickness); + XSetForeground (s->display, s->gc, xgcv.foreground); + } + } + } /* Draw overline. */ if (s->face->overline_p) {