diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi index 381eaf6..464dfaa 100644 --- a/doc/lispref/display.texi +++ b/doc/lispref/display.texi @@ -2080,10 +2080,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: + address@hidden @asis address@hidden @code{nil} +Don't underline. + address@hidden @code{t} +Underline with the foreground color of the face. + address@hidden @var{color} +Underline in color @var{color}. + address@hidden @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. address@hidden table @item :overline Whether or not characters should be overlined, and in what color. diff --git a/lisp/cus-face.el b/lisp/cus-face.el index d725111..3680a26 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 5d406ad..e68abb1 100644 --- a/lisp/faces.el +++ b/lisp/faces.el @@ -616,10 +616,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/dispextern.h b/src/dispextern.h index 2c59f4f..cdbbc16 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 70d3cc0..0378330 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -2596,6 +2596,68 @@ 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 = 2 + -- + 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, stringClip, finalClip; + + 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); + ns_get_glyph_string_clip_rect (s, &stringClip); + finalClip = NSIntersectionRect (waveClip, stringClip); + + if (NSIsEmptyRect (finalClip)) + return; + + [[NSGraphicsContext currentContext] saveGraphicsState]; + NSRectClip (finalClip); + + /* 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) @@ -2609,63 +2671,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; + + position = max (position, underline_minimum_offset); - s->underline_thickness = thickness; - s->underline_position = position; + /* Ensure underlining is not cropped. */ + if (descent <= position) + { + position = descent - 1; + thickness = 1; + } + else if (descent < position + thickness) + thickness = 1; + } - r = NSMakeRect (x, s->ybase + position, width, thickness); + s->underline_thickness = thickness; + s->underline_position = position; - if (face->underline_defaulted_p) - [defaultCol set]; - else - [ns_lookup_indexed_color (face->underline_color, s->f) set]; - NSRectFill (r); - } + 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 f764ad9..d53f0ab 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -309,6 +309,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 @@ -2343,60 +2431,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 617097d..8bee2d6 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; @@ -1889,7 +1890,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]) @@ -2520,7 +2522,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; @@ -2944,15 +2947,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; } @@ -3762,6 +3804,7 @@ Value is nil if ATTR doesn't have a discrete set of valid values. */) CHECK_SYMBOL (attr); + /* XXX: no check for QCbox? */ if (EQ (attr, QCunderline)) result = Fcons (Qt, Fcons (Qnil, Qnil)); else if (EQ (attr, QCoverline)) @@ -5563,7 +5606,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)); @@ -5696,29 +5739,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)) { @@ -6465,6 +6555,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 4b34d63..a58e366 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -2653,6 +2653,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. */ @@ -2755,68 +2814,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) {