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..657072a 100644 --- a/src/nsterm.m +++ b/src/nsterm.m @@ -2596,6 +2596,55 @@ ns_get_glyph_string_clip_rect (struct glyph_string *s, NativeRectangle *nr) return n; } +/* ------------------------------------------------------------- + Draw a wavy line. The wave fills wave_height pixels from y0. + + x0 wave_length = 2 + -- + y0 * * * * * + |* * * * * * * * * + wave_height = 3 | * * * * + -------------------------------------------------------------- */ + +static void +ns_draw_underwave (int x0, int y0, + int width, + int wave_height, int wave_length) +{ + int dx = wave_length, dy = wave_height-1; + int x1, y1, x2, y2; + double coef = dy/(double)dx; + NSPoint a, b; + + /* Set the phase */ + x1 = x0; + x2 = x0 + dx - (x0 % dx); + + while (x1 < x0+width) + { + int odd = (x1/dx) % 2; + + if (odd) + { + y1 = y0 + (dy - coef * (x1 % dx)); + y2 = y0 + coef * (x2 % dx); + } + else + { + y1 = y0 + coef * (x1 % dx); + y2 = y0 + (dy - coef * (x2 % dx)); + } + + a.x = x1, a.y = y1; + b.x = x2, b.y = y2; + [NSBezierPath strokeLineFromPoint:a toPoint: b]; + + x1 = x2; + x2 += dx; + } +} + + void ns_draw_text_decoration (struct glyph_string *s, struct face *face, NSColor *defaultCol, CGFloat width, CGFloat x) @@ -2609,63 +2658,77 @@ 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; + unsigned long height = 2, len = 3, y = s->ybase + 1; + + if (face->underline_defaulted_p) + [defaultCol set]; + else + [ns_lookup_indexed_color (face->underline_color, s->f) set]; + + ns_draw_underwave (s->x, y, s->width, height, len); } - 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; + NSRect r; + unsigned long thickness, position; - /* 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); + /* If the prev was underlined, match its appearance. */ + if (s->prev && s->prev->face->underline_p + && s->prev->underline_thickness > 0) + { + thickness = s->prev->underline_thickness; + position = s->prev->underline_position; + } else - position = underline_minimum_offset; + { + struct font *font; + unsigned long descent; - position = max (position, underline_minimum_offset); + font=s->font; + descent = s->y + s->height - s->ybase; - /* Ensure underlining is not cropped. */ - if (descent <= position) - { - position = descent - 1; - thickness = 1; + /* 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); + + /* Ensure underlining is not cropped. */ + if (descent <= position) + { + position = descent - 1; + thickness = 1; + } + else if (descent < position + thickness) + thickness = 1; } - else if (descent < position + thickness) - thickness = 1; - } - s->underline_thickness = thickness; - s->underline_position = position; + s->underline_thickness = thickness; + s->underline_position = position; - r = NSMakeRect (x, s->ybase + position, width, thickness); + 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); + 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..27aa415 100644 --- a/src/w32term.c +++ b/src/w32term.c @@ -309,6 +309,60 @@ w32_set_clip_rectangle (HDC hdc, RECT *rect) SelectClipRgn (hdc, NULL); } +/* + Draw a wavy line. The wave fills wave_height pixels from y0. + + x0 wave_length = 2 + -- + y0 * * * * * + |* * * * * * * * * + wave_height = 3 | * * * * + +*/ + +void +w32_draw_underwave (HDC hdc, COLORREF *color, + int x0, int y0, + int width, + int wave_height, int wave_length) +{ + HPEN hp, oldhp; + int dx = wave_length, dy = wave_height-1; + int x1, y1, x2, y2; + double coef = dy/(double)dx; + + hp = CreatePen (PS_SOLID, 0, color); + oldhb = SelectObject (hdc, hb); + oldhp = SelectObject (hdc, hp); + + /* Set the phase */ + x1 = x0; + x2 = x0 + dx - (x0 % dx); + MoveToEx (hdc, x1, y2, NULL); + + while (x1 < x0+width) + { + int odd = (x1/dx) % 2; + + if (odd) + { + y1 = y0 + (dy - coef * (x1 % dx)); + y2 = y0 + coef * (x2 % dx); + } + else + { + y1 = y0 + coef * (x1 % dx); + y2 = y0 + (dy - coef * (x2 % dx)); + } + + LineTo (hdc, x2, y2); + x1 = x2; + x2 += dx; + } + + SelectObject (hdc, oldhp); + DeleteObject (hp); +} /* Draw a hollow rectangle at the specified position. */ void @@ -2343,60 +2397,76 @@ 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; + unsigned long height = 2, len = 3, y = s->ybase + 1; + COLORREF color; + + if (s->face->underline_defaulted_p) + color = s->gc->foreground; + else + color = s->face->underline_color; + + w32_draw_underwave (s->hdc, color, + s->x, y, s->width, height, len); } - 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; - else - thickness = 1; - if (x_underline_at_descent_line) - position = (s->height - thickness) - (s->ybase - s->y); + 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 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 + /* 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) */ + 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; + 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 + { + 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..bd2597c 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -2653,6 +2653,52 @@ x_draw_stretch_glyph_string (struct glyph_string *s) s->background_filled_p = 1; } +/* + Draw a wavy line. The wave fills wave_height pixels from y0. + + x0 wave_length = 2 + -- + y0 * * * * * + |* * * * * * * * * + wave_height = 3 | * * * * + +*/ + +static void +x_draw_underwave (Display *dpy, Window win, GC gc, + unsigned long x0, unsigned long y0, + unsigned long width, + unsigned long wave_height, unsigned long wave_length) +{ + unsigned long dx = wave_length, dy = wave_height-1; + unsigned long x1, y1, x2, y2; + double coef = dy/(double)dx; + + /* Set the phase */ + x1 = x0; + x2 = x0 + dx - (x0 % dx); + + while (x1 < x0+width) + { + int odd = (x1/dx) % 2; + + if (odd) + { + y1 = y0 + (dy - coef * (x1 % dx)); + y2 = y0 + coef * (x2 % dx); + } + else + { + y1 = y0 + coef * (x1 % dx); + y2 = y0 + (dy - coef * (x2 % dx)); + } + + XDrawLine (dpy, win, gc, x1, y1, x2, y2); + x1 = x2; + x2 += dx; + } +} + /* Draw glyph string S. */ @@ -2756,67 +2802,86 @@ 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 + if (s->face->underline_type == FACE_UNDER_WAVE) + { + unsigned long height = 2, len = 3, y = s->ybase + 1; - ROUND ((maximum descent) / 2), with - ROUND(x) = floor (x + 0.5) */ + if (s->face->underline_defaulted_p) + x_draw_underwave (s->display, s->window, s->gc, + s->x, y, s->width, height, len); + else + { + XGCValues xgcv; + XGetGCValues (s->display, s->gc, GCForeground, &xgcv); + XSetForeground (s->display, s->gc, s->face->underline_color); + x_draw_underwave (s->display, s->window, s->gc, + s->x, y, s->width, height, len); + 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 - 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); - } - } + 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) {