aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlp Aker2012-06-16 20:32:36 -0400
committerAlp Aker2012-06-16 20:32:36 -0400
commit9b0e3ebaef5aed8097965b14c97a0579763be7fd (patch)
treeeeabc5495c58289454d9c53c9dd409377ec72cf3
parent40d8bcb854203237c6ad8327bc1fc0644f8734ec (diff)
downloademacs-9b0e3ebaef5aed8097965b14c97a0579763be7fd.tar.gz
emacs-9b0e3ebaef5aed8097965b14c97a0579763be7fd.zip
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.
-rw-r--r--ChangeLog5
-rw-r--r--doc/lispref/display.texi30
-rw-r--r--lisp/ChangeLog7
-rw-r--r--lisp/cus-face.el9
-rw-r--r--lisp/faces.el19
-rw-r--r--src/ChangeLog17
-rw-r--r--src/dispextern.h10
-rw-r--r--src/nsterm.m158
-rw-r--r--src/w32term.c196
-rw-r--r--src/xfaces.c125
-rw-r--r--src/xterm.c196
11 files changed, 591 insertions, 181 deletions
diff --git a/ChangeLog b/ChangeLog
index f089df625a9..a72d426416d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
12012-06-16 Aurelien Aptel <aurelien.aptel@gmail.com>
2
3 * doc/lispref/display.texi: Document wave-style underline
4 face attribute.
5
12012-06-13 Andreas Schwab <schwab@linux-m68k.org> 62012-06-13 Andreas Schwab <schwab@linux-m68k.org>
2 7
3 * configure.in: Rename --enable-use-lisp-union-type to 8 * 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
2130name, or a hexadecimal color specification. @xref{Color Names}. 2130name, or a hexadecimal color specification. @xref{Color Names}.
2131 2131
2132@item :underline 2132@item :underline
2133Whether or not characters should be underlined, and in what color. If 2133Whether or not characters should be underlined, and in what
2134the value is @code{t}, underlining uses the foreground color of the 2134color. Here are the possible values of the @code{:underline}
2135face. If the value is a string, underlining uses that color. The 2135attribute, and what they mean:
2136value @code{nil} means do not underline. 2136
2137@table @asis
2138@item @code{nil}
2139Don't underline.
2140
2141@item @code{t}
2142Underline with the foreground color of the face.
2143
2144@item @var{color}
2145Underline in color @var{color}.
2146
2147@item @code{(:color @var{color} :style @var{style})}
2148If @var{color} is a string, underline in it.
2149If @var{color} is @code{foreground-color}, underline with the
2150foreground color of the face.
2151
2152If @var{style} is @code{wave} underline with a wave.
2153If @var{style} is @code{line} underline with a line.
2154
2155If the attribute @code{:color} is omited, underline with the
2156foreground color of the face.
2157If the attribute @code{:style} is omited, underline with a line.
2158@end table
2137 2159
2138@item :overline 2160@item :overline
2139Whether or not characters should be overlined, and in what color. 2161Whether 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 @@
12012-06-16 Aurelien Aptel <aurelien.aptel@gmail.com>
2
3 * cus-face.el (custom-face-attributes): Add wave-style underline
4 attribute.
5 * faces.el (set-face-attribute): Update docstring to describe
6 wave-style underline attribute.
7
12012-06-16 Chong Yidong <cyd@gnu.org> 82012-06-16 Chong Yidong <cyd@gnu.org>
2 9
3 * term/xterm.el (terminal-init-xterm): Discard input before 10 * 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 @@
135 (choice :tag "Underline" 135 (choice :tag "Underline"
136 :help-echo "Control text underlining." 136 :help-echo "Control text underlining."
137 (const :tag "Off" nil) 137 (const :tag "Off" nil)
138 (const :tag "On" t) 138 (list :tag "On"
139 (color :tag "Colored"))) 139 (const :format "" :value :color)
140 (choice :tag "Color" (const :tag "Foreground Color" foreground-color) color)
141 (const :format "" :value :style)
142 (choice :tag "Style"
143 (const :tag "Line" line)
144 (const :tag "Wave" wave)))))
140 145
141 (:overline 146 (:overline
142 (choice :tag "Overline" 147 (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.
623 623
624`:underline' 624`:underline'
625 625
626VALUE specifies whether characters in FACE should be underlined. If 626VALUE specifies whether characters in FACE should be underlined.
627VALUE is t, underline with foreground color of the face. If VALUE is 627If VALUE is t, underline with foreground color of the face.
628a string, underline with that color. If VALUE is nil, explicitly 628If VALUE is a string, underline with that color.
629don't underline. 629If VALUE is nil, explicitly don't underline.
630
631Otherwise, VALUE must be a property list of the form:
632
633`(:color COLOR :style STYLE)'.
634
635COLOR can be a either a color name string or `foreground-color'.
636STYLE can be either `line' or `wave'.
637If a keyword/value pair is missing from the property list, a
638default value will be used for the value.
639The default value of COLOR is the foreground color of the face.
640The default value of STYLE is `line'.
630 641
631`:overline' 642`:overline'
632 643
diff --git a/src/ChangeLog b/src/ChangeLog
index 321c3b9c62f..d392dd522b3 100644
--- a/src/ChangeLog
+++ b/src/ChangeLog
@@ -1,3 +1,20 @@
12012-06-16 Aurelien Aptel <aurelien.aptel@gmail.com>
2
3 Implement wave-style variant of underlining.
4 * dispextern.h (face_underline_type): New enum.
5 (face): Add field for underline type.
6 * nsterm.m (ns_draw_underwave): New function.
7 (ns_draw_text_decoration): Use it.
8 * w32term.c (w32_restore_glyph_string_clip, w32_draw_underwave):
9 New functions.
10 (x_draw_glyph_string): Use them.
11 * xfaces.c (Qline, Qwave): New Lisp objects.
12 (check_lface_attrs, merge_face_ref)
13 (Finternal_set_lisp_face_attribute, realize_x_face): Handle
14 wave-style underline face attributes.
15 * xterm.c (x_draw_underwave): New function.
16 (x_draw_glyph_string): Use it.
17
12012-06-16 Juanma Barranquero <lekktu@gmail.com> 182012-06-16 Juanma Barranquero <lekktu@gmail.com>
2 19
3 * makefile.w32-in ($(BLD)/emacs.$(O), $(BLD)/fringe.$(O)) 20 * 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
1510 FACE_SUNKEN_BOX 1510 FACE_SUNKEN_BOX
1511}; 1511};
1512 1512
1513/* Underline type. */
1514
1515enum face_underline_type
1516{
1517 FACE_UNDER_LINE,
1518 FACE_UNDER_WAVE
1519};
1513 1520
1514/* Structure describing a realized face. 1521/* Structure describing a realized face.
1515 1522
@@ -1585,6 +1592,9 @@ struct face
1585 drawing shadows. */ 1592 drawing shadows. */
1586 unsigned use_box_color_for_shadows_p : 1; 1593 unsigned use_box_color_for_shadows_p : 1;
1587 1594
1595 /* Style of underlining. */
1596 enum face_underline_type underline_type;
1597
1588 /* Non-zero if text in this face should be underlined, overlined, 1598 /* Non-zero if text in this face should be underlined, overlined,
1589 strike-through or have a box drawn around it. */ 1599 strike-through or have a box drawn around it. */
1590 unsigned underline_p : 1; 1600 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)
2595 return n; 2595 return n;
2596} 2596}
2597 2597
2598/* --------------------------------------------------------------------
2599 Draw a wavy line under glyph string s. The wave fills wave_height
2600 pixels from y.
2601
2602 x wave_length = 3
2603 --
2604 y * * * * *
2605 |* * * * * * * * *
2606 wave_height = 3 | * * * *
2607 --------------------------------------------------------------------- */
2608
2609static void
2610ns_draw_underwave (struct glyph_string *s, CGFloat width, CGFloat x)
2611{
2612 int wave_height = 3, wave_length = 3;
2613 int y, dx, dy, odd, xmax;
2614 NSPoint a, b;
2615 NSRect waveClip;
2616
2617 dx = wave_length;
2618 dy = wave_height - 1;
2619 y = s->ybase + 1;
2620 xmax = x + width;
2621
2622 /* Find and set clipping rectangle */
2623 waveClip = NSMakeRect (x, y, width, wave_height);
2624 [[NSGraphicsContext currentContext] saveGraphicsState];
2625 NSRectClip (waveClip);
2626
2627 /* Draw the waves */
2628 a.x = x - ((int)(x) % dx);
2629 b.x = a.x + dx;
2630 odd = (int)(a.x/dx) % 2;
2631 a.y = b.y = y;
2632
2633 if (odd)
2634 a.y += dy;
2635 else
2636 b.y += dy;
2637
2638 while (a.x <= xmax)
2639 {
2640 [NSBezierPath strokeLineFromPoint:a toPoint:b];
2641 a.x = b.x, a.y = b.y;
2642 b.x += dx, b.y = y + odd*dy;
2643 odd = !odd;
2644 }
2645
2646 /* Restore previous clipping rectangle(s) */
2647 [[NSGraphicsContext currentContext] restoreGraphicsState];
2648}
2649
2650
2651
2598void 2652void
2599ns_draw_text_decoration (struct glyph_string *s, struct face *face, 2653ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2600 NSColor *defaultCol, CGFloat width, CGFloat x) 2654 NSColor *defaultCol, CGFloat width, CGFloat x)
@@ -2608,63 +2662,75 @@ ns_draw_text_decoration (struct glyph_string *s, struct face *face,
2608 /* Do underline. */ 2662 /* Do underline. */
2609 if (face->underline_p) 2663 if (face->underline_p)
2610 { 2664 {
2611 NSRect r; 2665 if (s->face->underline_type == FACE_UNDER_WAVE)
2612 unsigned long thickness, position;
2613
2614 /* If the prev was underlined, match its appearance. */
2615 if (s->prev && s->prev->face->underline_p
2616 && s->prev->underline_thickness > 0)
2617 { 2666 {
2618 thickness = s->prev->underline_thickness; 2667 if (face->underline_defaulted_p)
2619 position = s->prev->underline_position; 2668 [defaultCol set];
2669 else
2670 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2671
2672 ns_draw_underwave (s, width, x);
2620 } 2673 }
2621 else 2674 else if (s->face->underline_type == FACE_UNDER_LINE)
2622 { 2675 {
2623 struct font *font;
2624 unsigned long descent;
2625
2626 font=s->font;
2627 descent = s->y + s->height - s->ybase;
2628
2629 /* Use underline thickness of font, defaulting to 1. */
2630 thickness = (font && font->underline_thickness > 0)
2631 ? font->underline_thickness : 1;
2632
2633 /* Determine the offset of underlining from the baseline. */
2634 if (x_underline_at_descent_line)
2635 position = descent - thickness;
2636 else if (x_use_underline_position_properties
2637 && font && font->underline_position >= 0)
2638 position = font->underline_position;
2639 else if (font)
2640 position = lround (font->descent / 2);
2641 else
2642 position = underline_minimum_offset;
2643 2676
2644 position = max (position, underline_minimum_offset); 2677 NSRect r;
2678 unsigned long thickness, position;
2645 2679
2646 /* Ensure underlining is not cropped. */ 2680 /* If the prev was underlined, match its appearance. */
2647 if (descent <= position) 2681 if (s->prev && s->prev->face->underline_p
2682 && s->prev->underline_thickness > 0)
2648 { 2683 {
2649 position = descent - 1; 2684 thickness = s->prev->underline_thickness;
2650 thickness = 1; 2685 position = s->prev->underline_position;
2651 } 2686 }
2652 else if (descent < position + thickness) 2687 else
2653 thickness = 1; 2688 {
2654 } 2689 struct font *font;
2690 unsigned long descent;
2691
2692 font=s->font;
2693 descent = s->y + s->height - s->ybase;
2694
2695 /* Use underline thickness of font, defaulting to 1. */
2696 thickness = (font && font->underline_thickness > 0)
2697 ? font->underline_thickness : 1;
2698
2699 /* Determine the offset of underlining from the baseline. */
2700 if (x_underline_at_descent_line)
2701 position = descent - thickness;
2702 else if (x_use_underline_position_properties
2703 && font && font->underline_position >= 0)
2704 position = font->underline_position;
2705 else if (font)
2706 position = lround (font->descent / 2);
2707 else
2708 position = underline_minimum_offset;
2655 2709
2656 s->underline_thickness = thickness; 2710 position = max (position, underline_minimum_offset);
2657 s->underline_position = position;
2658 2711
2659 r = NSMakeRect (x, s->ybase + position, width, thickness); 2712 /* Ensure underlining is not cropped. */
2713 if (descent <= position)
2714 {
2715 position = descent - 1;
2716 thickness = 1;
2717 }
2718 else if (descent < position + thickness)
2719 thickness = 1;
2720 }
2660 2721
2661 if (face->underline_defaulted_p) 2722 s->underline_thickness = thickness;
2662 [defaultCol set]; 2723 s->underline_position = position;
2663 else 2724
2664 [ns_lookup_indexed_color (face->underline_color, s->f) set]; 2725 r = NSMakeRect (x, s->ybase + position, width, thickness);
2665 NSRectFill (r);
2666 }
2667 2726
2727 if (face->underline_defaulted_p)
2728 [defaultCol set];
2729 else
2730 [ns_lookup_indexed_color (face->underline_color, s->f) set];
2731 NSRectFill (r);
2732 }
2733 }
2668 /* Do overline. We follow other terms in using a thickness of 1 2734 /* Do overline. We follow other terms in using a thickness of 1
2669 and ignoring overline_margin. */ 2735 and ignoring overline_margin. */
2670 if (face->overline_p) 2736 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)
313 SelectClipRgn (hdc, NULL); 313 SelectClipRgn (hdc, NULL);
314} 314}
315 315
316/* Restore clipping rectangle in S */
317static void
318w32_restore_glyph_string_clip (struct glyph_string *s)
319{
320 RECT *r = s->clip;
321 int n = s->num_clips;
322
323 if (n == 1)
324 w32_set_clip_rectangle (s->hdc, r);
325 else if (n > 1)
326 {
327 HRGN clip1 = CreateRectRgnIndirect (r);
328 HRGN clip2 = CreateRectRgnIndirect (r + 1);
329 if (CombineRgn (clip1, clip1, clip2, RGN_OR) != ERROR)
330 SelectClipRgn (s->hdc, clip1);
331 DeleteObject (clip1);
332 DeleteObject (clip2);
333 }
334}
335
336/*
337 Draw a wavy line under S. The wave fills wave_height pixels from y0.
338
339 x0 wave_length = 2
340 --
341 y0 * * * * *
342 |* * * * * * * * *
343 wave_height = 3 | * * * *
344
345*/
346
347void
348w32_draw_underwave (struct glyph_string *s, COLORREF color)
349{
350 int wave_height = 2, wave_length = 3;
351 int dx, dy, x0, y0, width, x1, y1, x2, y2, odd, xmax;
352 XRectangle wave_clip, string_clip, final_clip;
353 RECT w32_final_clip, w32_string_clip;
354 HPEN hp, oldhp;
355
356 dx = wave_length;
357 dy = wave_height - 1;
358 x0 = s->x;
359 y0 = s->ybase + 1;
360 width = s->width;
361 xmax = x0 + width;
362
363 /* Find and set clipping rectangle */
364
365 wave_clip = (XRectangle){ x0, y0, width, wave_height };
366 get_glyph_string_clip_rect (s, &w32_string_clip);
367 CONVERT_TO_XRECT (string_clip, w32_string_clip);
368
369 if (!x_intersect_rectangles (&wave_clip, &string_clip, &final_clip))
370 return;
371
372 hp = CreatePen (PS_SOLID, 0, color);
373 oldhp = SelectObject (s->hdc, hp);
374 CONVERT_FROM_XRECT (final_clip, w32_final_clip);
375 w32_set_clip_rectangle (s->hdc, &w32_final_clip);
376
377 /* Draw the waves */
378
379 x1 = x0 - (x0 % dx);
380 x2 = x1 + dx;
381 odd = (x1/dx) % 2;
382 y1 = y2 = y0;
383
384 if (odd)
385 y1 += dy;
386 else
387 y2 += dy;
388
389 MoveToEx (s->hdc, x1, y1, NULL);
390
391 while (x1 <= xmax)
392 {
393 LineTo (s->hdc, x2, y2);
394 x1 = x2, y1 = y2;
395 x2 += dx, y2 = y0 + odd*dy;
396 odd = !odd;
397 }
398
399 /* Restore previous pen and clipping rectangle(s) */
400 w32_restore_glyph_string_clip (s);
401 SelectObject (s->hdc, oldhp);
402 DeleteObject (hp);
403}
316 404
317/* Draw a hollow rectangle at the specified position. */ 405/* Draw a hollow rectangle at the specified position. */
318void 406void
@@ -2347,60 +2435,74 @@ x_draw_glyph_string (struct glyph_string *s)
2347 /* Draw underline. */ 2435 /* Draw underline. */
2348 if (s->face->underline_p) 2436 if (s->face->underline_p)
2349 { 2437 {
2350 unsigned long thickness, position; 2438 if (s->face->underline_type == FACE_UNDER_WAVE)
2351 int y;
2352
2353 if (s->prev && s->prev->face->underline_p)
2354 { 2439 {
2355 /* We use the same underline style as the previous one. */ 2440 COLORREF color;
2356 thickness = s->prev->underline_thickness; 2441
2357 position = s->prev->underline_position; 2442 if (s->face->underline_defaulted_p)
2443 color = s->gc->foreground;
2444 else
2445 color = s->face->underline_color;
2446
2447 w32_draw_underwave (s, color);
2358 } 2448 }
2359 else 2449 else if (s->face->underline_type == FACE_UNDER_LINE)
2360 { 2450 {
2361 /* Get the underline thickness. Default is 1 pixel. */ 2451 unsigned long thickness, position;
2362 if (s->font && s->font->underline_thickness > 0) 2452 int y;
2363 thickness = s->font->underline_thickness; 2453
2454 if (s->prev && s->prev->face->underline_p)
2455 {
2456 /* We use the same underline style as the previous one. */
2457 thickness = s->prev->underline_thickness;
2458 position = s->prev->underline_position;
2459 }
2364 else 2460 else
2365 thickness = 1; 2461 {
2366 if (x_underline_at_descent_line) 2462 /* Get the underline thickness. Default is 1 pixel. */
2367 position = (s->height - thickness) - (s->ybase - s->y); 2463 if (s->font && s->font->underline_thickness > 0)
2464 thickness = s->font->underline_thickness;
2465 else
2466 thickness = 1;
2467 if (x_underline_at_descent_line)
2468 position = (s->height - thickness) - (s->ybase - s->y);
2469 else
2470 {
2471 /* Get the underline position. This is the recommended
2472 vertical offset in pixels from the baseline to the top of
2473 the underline. This is a signed value according to the
2474 specs, and its default is
2475
2476 ROUND ((maximum_descent) / 2), with
2477 ROUND (x) = floor (x + 0.5) */
2478
2479 if (x_use_underline_position_properties
2480 && s->font && s->font->underline_position >= 0)
2481 position = s->font->underline_position;
2482 else if (s->font)
2483 position = (s->font->descent + 1) / 2;
2484 }
2485 position = max (position, underline_minimum_offset);
2486 }
2487 /* Check the sanity of thickness and position. We should
2488 avoid drawing underline out of the current line area. */
2489 if (s->y + s->height <= s->ybase + position)
2490 position = (s->height - 1) - (s->ybase - s->y);
2491 if (s->y + s->height < s->ybase + position + thickness)
2492 thickness = (s->y + s->height) - (s->ybase + position);
2493 s->underline_thickness = thickness;
2494 s->underline_position =position;
2495 y = s->ybase + position;
2496 if (s->face->underline_defaulted_p)
2497 {
2498 w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
2499 y, s->width, 1);
2500 }
2368 else 2501 else
2369 { 2502 {
2370 /* Get the underline position. This is the recommended 2503 w32_fill_area (s->f, s->hdc, s->face->underline_color, s->x,
2371 vertical offset in pixels from the baseline to the top of 2504 y, s->width, 1);
2372 the underline. This is a signed value according to the
2373 specs, and its default is
2374
2375 ROUND ((maximum_descent) / 2), with
2376 ROUND (x) = floor (x + 0.5) */
2377
2378 if (x_use_underline_position_properties
2379 && s->font && s->font->underline_position >= 0)
2380 position = s->font->underline_position;
2381 else if (s->font)
2382 position = (s->font->descent + 1) / 2;
2383 } 2505 }
2384 position = max (position, underline_minimum_offset);
2385 }
2386 /* Check the sanity of thickness and position. We should
2387 avoid drawing underline out of the current line area. */
2388 if (s->y + s->height <= s->ybase + position)
2389 position = (s->height - 1) - (s->ybase - s->y);
2390 if (s->y + s->height < s->ybase + position + thickness)
2391 thickness = (s->y + s->height) - (s->ybase + position);
2392 s->underline_thickness = thickness;
2393 s->underline_position =position;
2394 y = s->ybase + position;
2395 if (s->face->underline_defaulted_p)
2396 {
2397 w32_fill_area (s->f, s->hdc, s->gc->foreground, s->x,
2398 y, s->width, 1);
2399 }
2400 else
2401 {
2402 w32_fill_area (s->f, s->hdc, s->face->underline_color, s->x,
2403 y, s->width, 1);
2404 } 2506 }
2405 } 2507 }
2406 /* Draw overline. */ 2508 /* 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;
320 320
321Lisp_Object Qnormal; 321Lisp_Object Qnormal;
322Lisp_Object Qbold; 322Lisp_Object Qbold;
323static Lisp_Object Qline, Qwave;
323static Lisp_Object Qultra_light, Qextra_light, Qlight; 324static Lisp_Object Qultra_light, Qextra_light, Qlight;
324static Lisp_Object Qsemi_light, Qsemi_bold, Qextra_bold, Qultra_bold; 325static Lisp_Object Qsemi_light, Qsemi_bold, Qextra_bold, Qultra_bold;
325static Lisp_Object Qoblique, Qreverse_oblique, Qreverse_italic; 326static Lisp_Object Qoblique, Qreverse_oblique, Qreverse_italic;
@@ -1894,7 +1895,8 @@ check_lface_attrs (Lisp_Object *attrs)
1894 xassert (UNSPECIFIEDP (attrs[LFACE_UNDERLINE_INDEX]) 1895 xassert (UNSPECIFIEDP (attrs[LFACE_UNDERLINE_INDEX])
1895 || IGNORE_DEFFACE_P (attrs[LFACE_UNDERLINE_INDEX]) 1896 || IGNORE_DEFFACE_P (attrs[LFACE_UNDERLINE_INDEX])
1896 || SYMBOLP (attrs[LFACE_UNDERLINE_INDEX]) 1897 || SYMBOLP (attrs[LFACE_UNDERLINE_INDEX])
1897 || STRINGP (attrs[LFACE_UNDERLINE_INDEX])); 1898 || STRINGP (attrs[LFACE_UNDERLINE_INDEX])
1899 || CONSP (attrs[LFACE_UNDERLINE_INDEX]));
1898 xassert (UNSPECIFIEDP (attrs[LFACE_OVERLINE_INDEX]) 1900 xassert (UNSPECIFIEDP (attrs[LFACE_OVERLINE_INDEX])
1899 || IGNORE_DEFFACE_P (attrs[LFACE_OVERLINE_INDEX]) 1901 || IGNORE_DEFFACE_P (attrs[LFACE_OVERLINE_INDEX])
1900 || SYMBOLP (attrs[LFACE_OVERLINE_INDEX]) 1902 || SYMBOLP (attrs[LFACE_OVERLINE_INDEX])
@@ -2525,7 +2527,8 @@ merge_face_ref (struct frame *f, Lisp_Object face_ref, Lisp_Object *to,
2525 { 2527 {
2526 if (EQ (value, Qt) 2528 if (EQ (value, Qt)
2527 || NILP (value) 2529 || NILP (value)
2528 || STRINGP (value)) 2530 || STRINGP (value)
2531 || CONSP (value))
2529 to[LFACE_UNDERLINE_INDEX] = value; 2532 to[LFACE_UNDERLINE_INDEX] = value;
2530 else 2533 else
2531 err = 1; 2534 err = 1;
@@ -2948,15 +2951,54 @@ FRAME 0 means change the face on all frames, and change the default
2948 } 2951 }
2949 else if (EQ (attr, QCunderline)) 2952 else if (EQ (attr, QCunderline))
2950 { 2953 {
2951 if (!UNSPECIFIEDP (value) && !IGNORE_DEFFACE_P (value)) 2954 int valid_p = 0;
2952 if ((SYMBOLP (value) 2955
2953 && !EQ (value, Qt) 2956 if (UNSPECIFIEDP (value) || IGNORE_DEFFACE_P (value))
2954 && !EQ (value, Qnil)) 2957 valid_p = 1;
2955 /* Underline color. */ 2958 else if (NILP (value) || EQ (value, Qt))
2956 || (STRINGP (value) 2959 valid_p = 1;
2957 && SCHARS (value) == 0)) 2960 else if (STRINGP (value) && SCHARS (value) > 0)
2958 signal_error ("Invalid face underline", value); 2961 valid_p = 1;
2959 2962 else if (CONSP (value))
2963 {
2964 Lisp_Object key, val, list;
2965
2966 list = value;
2967 valid_p = 1;
2968
2969 while (!NILP (CAR_SAFE(list)))
2970 {
2971 key = CAR_SAFE (list);
2972 list = CDR_SAFE (list);
2973 val = CAR_SAFE (list);
2974 list = CDR_SAFE (list);
2975
2976 if(NILP (key) || NILP (val))
2977 {
2978 valid_p = 0;
2979 break;
2980 }
2981
2982 else if (EQ (key, QCcolor)
2983 && !(EQ (val, Qforeground_color)
2984 || (STRINGP (val) && SCHARS (val) > 0)))
2985 {
2986 valid_p = 0;
2987 break;
2988 }
2989
2990 else if (EQ (key, QCstyle)
2991 && !(EQ (val, Qline) || EQ (val, Qwave)))
2992 {
2993 valid_p = 0;
2994 break;
2995 }
2996 }
2997 }
2998
2999 if (!valid_p)
3000 signal_error ("Invalid face underline", value);
3001
2960 old_value = LFACE_UNDERLINE (lface); 3002 old_value = LFACE_UNDERLINE (lface);
2961 LFACE_UNDERLINE (lface) = value; 3003 LFACE_UNDERLINE (lface) = value;
2962 } 3004 }
@@ -5576,7 +5618,7 @@ realize_x_face (struct face_cache *cache, Lisp_Object *attrs)
5576#ifdef HAVE_WINDOW_SYSTEM 5618#ifdef HAVE_WINDOW_SYSTEM
5577 struct face *default_face; 5619 struct face *default_face;
5578 struct frame *f; 5620 struct frame *f;
5579 Lisp_Object stipple, overline, strike_through, box; 5621 Lisp_Object stipple, underline, overline, strike_through, box;
5580 5622
5581 xassert (FRAME_WINDOW_P (cache->f)); 5623 xassert (FRAME_WINDOW_P (cache->f));
5582 5624
@@ -5709,29 +5751,76 @@ realize_x_face (struct face_cache *cache, Lisp_Object *attrs)
5709 5751
5710 /* Text underline, overline, strike-through. */ 5752 /* Text underline, overline, strike-through. */
5711 5753
5712 if (EQ (attrs[LFACE_UNDERLINE_INDEX], Qt)) 5754 underline = attrs[LFACE_UNDERLINE_INDEX];
5755 if (EQ (underline, Qt))
5713 { 5756 {
5714 /* Use default color (same as foreground color). */ 5757 /* Use default color (same as foreground color). */
5715 face->underline_p = 1; 5758 face->underline_p = 1;
5759 face->underline_type = FACE_UNDER_LINE;
5716 face->underline_defaulted_p = 1; 5760 face->underline_defaulted_p = 1;
5717 face->underline_color = 0; 5761 face->underline_color = 0;
5718 } 5762 }
5719 else if (STRINGP (attrs[LFACE_UNDERLINE_INDEX])) 5763 else if (STRINGP (underline))
5720 { 5764 {
5721 /* Use specified color. */ 5765 /* Use specified color. */
5722 face->underline_p = 1; 5766 face->underline_p = 1;
5767 face->underline_type = FACE_UNDER_LINE;
5723 face->underline_defaulted_p = 0; 5768 face->underline_defaulted_p = 0;
5724 face->underline_color 5769 face->underline_color
5725 = load_color (f, face, attrs[LFACE_UNDERLINE_INDEX], 5770 = load_color (f, face, underline,
5726 LFACE_UNDERLINE_INDEX); 5771 LFACE_UNDERLINE_INDEX);
5727 } 5772 }
5728 else if (NILP (attrs[LFACE_UNDERLINE_INDEX])) 5773 else if (NILP (underline))
5729 { 5774 {
5730 face->underline_p = 0; 5775 face->underline_p = 0;
5731 face->underline_defaulted_p = 0; 5776 face->underline_defaulted_p = 0;
5732 face->underline_color = 0; 5777 face->underline_color = 0;
5733 } 5778 }
5734 5779 else if (CONSP (underline))
5780 {
5781 /* `(:color COLOR :style STYLE)'.
5782 STYLE being one of `line' or `wave'. */
5783 face->underline_p = 1;
5784 face->underline_color = 0;
5785 face->underline_defaulted_p = 1;
5786 face->underline_type = FACE_UNDER_LINE;
5787
5788 while (CONSP (underline))
5789 {
5790 Lisp_Object keyword, value;
5791
5792 keyword = XCAR (underline);
5793 underline = XCDR (underline);
5794
5795 if (!CONSP (underline))
5796 break;
5797 value = XCAR (underline);
5798 underline = XCDR (underline);
5799
5800 if (EQ (keyword, QCcolor))
5801 {
5802 if (EQ (value, Qforeground_color))
5803 {
5804 face->underline_defaulted_p = 1;
5805 face->underline_color = 0;
5806 }
5807 else if (STRINGP (value))
5808 {
5809 face->underline_defaulted_p = 0;
5810 face->underline_color = load_color (f, face, value,
5811 LFACE_UNDERLINE_INDEX);
5812 }
5813 }
5814 else if (EQ (keyword, QCstyle))
5815 {
5816 if (EQ (value, Qline))
5817 face->underline_type = FACE_UNDER_LINE;
5818 else if (EQ (value, Qwave))
5819 face->underline_type = FACE_UNDER_WAVE;
5820 }
5821 }
5822 }
5823
5735 overline = attrs[LFACE_OVERLINE_INDEX]; 5824 overline = attrs[LFACE_OVERLINE_INDEX];
5736 if (STRINGP (overline)) 5825 if (STRINGP (overline))
5737 { 5826 {
@@ -6476,6 +6565,8 @@ syms_of_xfaces (void)
6476 DEFSYM (QCcolor, ":color"); 6565 DEFSYM (QCcolor, ":color");
6477 DEFSYM (QCline_width, ":line-width"); 6566 DEFSYM (QCline_width, ":line-width");
6478 DEFSYM (QCstyle, ":style"); 6567 DEFSYM (QCstyle, ":style");
6568 DEFSYM (Qline, "line");
6569 DEFSYM (Qwave, "wave");
6479 DEFSYM (Qreleased_button, "released-button"); 6570 DEFSYM (Qreleased_button, "released-button");
6480 DEFSYM (Qpressed_button, "pressed-button"); 6571 DEFSYM (Qpressed_button, "pressed-button");
6481 DEFSYM (Qnormal, "normal"); 6572 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)
2663 s->background_filled_p = 1; 2663 s->background_filled_p = 1;
2664} 2664}
2665 2665
2666/*
2667 Draw a wavy line under S. The wave fills wave_height pixels from y0.
2668
2669 x0 wave_length = 2
2670 --
2671 y0 * * * * *
2672 |* * * * * * * * *
2673 wave_height = 3 | * * * *
2674
2675*/
2676
2677static void
2678x_draw_underwave (struct glyph_string *s)
2679{
2680 int wave_height = 2, wave_length = 3;
2681 int dx, dy, x0, y0, width, x1, y1, x2, y2, odd, xmax;
2682 XRectangle wave_clip, string_clip, final_clip;
2683
2684 dx = wave_length;
2685 dy = wave_height - 1;
2686 x0 = s->x;
2687 y0 = s->ybase + 1;
2688 width = s->width;
2689 xmax = x0 + width;
2690
2691 /* Find and set clipping rectangle */
2692
2693 wave_clip = (XRectangle){ x0, y0, width, wave_height };
2694 get_glyph_string_clip_rect (s, &string_clip);
2695
2696 if (!x_intersect_rectangles (&wave_clip, &string_clip, &final_clip))
2697 return;
2698
2699 XSetClipRectangles (s->display, s->gc, 0, 0, &final_clip, 1, Unsorted);
2700
2701 /* Draw the waves */
2702
2703 x1 = x0 - (x0 % dx);
2704 x2 = x1 + dx;
2705 odd = (x1/dx) % 2;
2706 y1 = y2 = y0;
2707
2708 if (odd)
2709 y1 += dy;
2710 else
2711 y2 += dy;
2712
2713 while (x1 <= xmax)
2714 {
2715 XDrawLine (s->display, s->window, s->gc, x1, y1, x2, y2);
2716 x1 = x2, y1 = y2;
2717 x2 += dx, y2 = y0 + odd*dy;
2718 odd = !odd;
2719 }
2720
2721 /* Restore previous clipping rectangle(s) */
2722 XSetClipRectangles (s->display, s->gc, 0, 0, s->clip, s->num_clips, Unsorted);
2723}
2724
2666 2725
2667/* Draw glyph string S. */ 2726/* Draw glyph string S. */
2668 2727
@@ -2765,68 +2824,83 @@ x_draw_glyph_string (struct glyph_string *s)
2765 { 2824 {
2766 /* Draw underline. */ 2825 /* Draw underline. */
2767 if (s->face->underline_p) 2826 if (s->face->underline_p)
2768 { 2827 {
2769 unsigned long thickness, position; 2828 if (s->face->underline_type == FACE_UNDER_WAVE)
2770 int y; 2829 {
2771 2830 if (s->face->underline_defaulted_p)
2772 if (s->prev && s->prev->face->underline_p) 2831 x_draw_underwave (s);
2773 { 2832 else
2774 /* We use the same underline style as the previous one. */ 2833 {
2775 thickness = s->prev->underline_thickness; 2834 XGCValues xgcv;
2776 position = s->prev->underline_position; 2835 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
2777 } 2836 XSetForeground (s->display, s->gc, s->face->underline_color);
2778 else 2837 x_draw_underwave (s);
2779 { 2838 XSetForeground (s->display, s->gc, xgcv.foreground);
2780 /* Get the underline thickness. Default is 1 pixel. */ 2839 }
2781 if (s->font && s->font->underline_thickness > 0) 2840 }
2782 thickness = s->font->underline_thickness; 2841 else if (s->face->underline_type == FACE_UNDER_LINE)
2783 else 2842 {
2784 thickness = 1; 2843 unsigned long thickness, position;
2785 if (x_underline_at_descent_line) 2844 int y;
2786 position = (s->height - thickness) - (s->ybase - s->y);
2787 else
2788 {
2789 /* Get the underline position. This is the recommended
2790 vertical offset in pixels from the baseline to the top of
2791 the underline. This is a signed value according to the
2792 specs, and its default is
2793
2794 ROUND ((maximum descent) / 2), with
2795 ROUND(x) = floor (x + 0.5) */
2796
2797 if (x_use_underline_position_properties
2798 && s->font && s->font->underline_position >= 0)
2799 position = s->font->underline_position;
2800 else if (s->font)
2801 position = (s->font->descent + 1) / 2;
2802 else
2803 position = underline_minimum_offset;
2804 }
2805 position = max (position, underline_minimum_offset);
2806 }
2807 /* Check the sanity of thickness and position. We should
2808 avoid drawing underline out of the current line area. */
2809 if (s->y + s->height <= s->ybase + position)
2810 position = (s->height - 1) - (s->ybase - s->y);
2811 if (s->y + s->height < s->ybase + position + thickness)
2812 thickness = (s->y + s->height) - (s->ybase + position);
2813 s->underline_thickness = thickness;
2814 s->underline_position = position;
2815 y = s->ybase + position;
2816 if (s->face->underline_defaulted_p)
2817 XFillRectangle (s->display, s->window, s->gc,
2818 s->x, y, s->width, thickness);
2819 else
2820 {
2821 XGCValues xgcv;
2822 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
2823 XSetForeground (s->display, s->gc, s->face->underline_color);
2824 XFillRectangle (s->display, s->window, s->gc,
2825 s->x, y, s->width, thickness);
2826 XSetForeground (s->display, s->gc, xgcv.foreground);
2827 }
2828 }
2829 2845
2846 if (s->prev && s->prev->face->underline_p)
2847 {
2848 /* We use the same underline style as the previous one. */
2849 thickness = s->prev->underline_thickness;
2850 position = s->prev->underline_position;
2851 }
2852 else
2853 {
2854 /* Get the underline thickness. Default is 1 pixel. */
2855 if (s->font && s->font->underline_thickness > 0)
2856 thickness = s->font->underline_thickness;
2857 else
2858 thickness = 1;
2859 if (x_underline_at_descent_line)
2860 position = (s->height - thickness) - (s->ybase - s->y);
2861 else
2862 {
2863 /* Get the underline position. This is the recommended
2864 vertical offset in pixels from the baseline to the top of
2865 the underline. This is a signed value according to the
2866 specs, and its default is
2867
2868 ROUND ((maximum descent) / 2), with
2869 ROUND(x) = floor (x + 0.5) */
2870
2871 if (x_use_underline_position_properties
2872 && s->font && s->font->underline_position >= 0)
2873 position = s->font->underline_position;
2874 else if (s->font)
2875 position = (s->font->descent + 1) / 2;
2876 else
2877 position = underline_minimum_offset;
2878 }
2879 position = max (position, underline_minimum_offset);
2880 }
2881 /* Check the sanity of thickness and position. We should
2882 avoid drawing underline out of the current line area. */
2883 if (s->y + s->height <= s->ybase + position)
2884 position = (s->height - 1) - (s->ybase - s->y);
2885 if (s->y + s->height < s->ybase + position + thickness)
2886 thickness = (s->y + s->height) - (s->ybase + position);
2887 s->underline_thickness = thickness;
2888 s->underline_position = position;
2889 y = s->ybase + position;
2890 if (s->face->underline_defaulted_p)
2891 XFillRectangle (s->display, s->window, s->gc,
2892 s->x, y, s->width, thickness);
2893 else
2894 {
2895 XGCValues xgcv;
2896 XGetGCValues (s->display, s->gc, GCForeground, &xgcv);
2897 XSetForeground (s->display, s->gc, s->face->underline_color);
2898 XFillRectangle (s->display, s->window, s->gc,
2899 s->x, y, s->width, thickness);
2900 XSetForeground (s->display, s->gc, xgcv.foreground);
2901 }
2902 }
2903 }
2830 /* Draw overline. */ 2904 /* Draw overline. */
2831 if (s->face->overline_p) 2905 if (s->face->overline_p)
2832 { 2906 {