aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAlp Aker2012-06-16 20:32:36 -0400
committerAlp Aker2012-06-16 20:32:36 -0400
commit9b0e3ebaef5aed8097965b14c97a0579763be7fd (patch)
treeeeabc5495c58289454d9c53c9dd409377ec72cf3 /src
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.
Diffstat (limited to 'src')
-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
6 files changed, 531 insertions, 171 deletions
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 {