emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master e844b81c56d 3/3: Implement dots and dashes on X


From: Po Lu
Subject: master e844b81c56d 3/3: Implement dots and dashes on X
Date: Sat, 27 Apr 2024 23:59:50 -0400 (EDT)

branch: master
commit e844b81c56d74aa2b2efa0ce98ed3de71647e656
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    Implement dots and dashes on X
    
    * src/dispextern.h (enum face_underline_type): Indent and expand
    commentary as to the new dependency on the order of its
    enumerals.
    
    * src/xfaces.c (realize_gui_face): Enable dots and dashes on
    window systems.
    
    * src/xterm.c (x_draw_underwave): Don't define unused variable
    on Cairo builds.
    (x_draw_dash): New function; implement for X and Cairo.
    (x_fill_underline): New function.  Delegate to x_fill_rectangle
    or x_draw_dash as appropriate.
    (x_draw_glyph_string): Call x_fill_underline rather than
    x_fill_rectangle.
---
 src/dispextern.h |   4 +-
 src/xfaces.c     |   2 -
 src/xterm.c      | 125 ++++++++++++++++++++++++++++++++++++++++++++++---------
 3 files changed, 108 insertions(+), 23 deletions(-)

diff --git a/src/dispextern.h b/src/dispextern.h
index 1614a044cbf..93cbde6583d 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1697,7 +1697,9 @@ enum face_box_type
 
 enum face_underline_type
 {
-       /* Note: Order matches the order of the Smulx terminfo extension. */
+  /* Note: order matches the order of the Smulx terminfo extension, and
+     is also relied on to remain in its present order by
+     x_draw_glyph_string and company.  */
   FACE_NO_UNDERLINE = 0,
   FACE_UNDERLINE_SINGLE,
   FACE_UNDERLINE_DOUBLE_LINE,
diff --git a/src/xfaces.c b/src/xfaces.c
index d9ee82c8e7f..56d067ade5b 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -6404,12 +6404,10 @@ realize_gui_face (struct face_cache *cache, Lisp_Object 
attrs[LFACE_VECTOR_SIZE]
                face->underline = FACE_UNDERLINE_DOUBLE_LINE;
              else if (EQ (value, Qwave))
                face->underline = FACE_UNDERLINE_WAVE;
-#if 0
              else if (EQ (value, Qdots))
                face->underline = FACE_UNDERLINE_DOTS;
              else if (EQ (value, Qdashes))
                face->underline = FACE_UNDERLINE_DASHES;
-#endif /* 0 */
              else
                face->underline = FACE_UNDERLINE_SINGLE;
            }
diff --git a/src/xterm.c b/src/xterm.c
index 9b014a7d0e4..505a3d9360a 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -10764,13 +10764,11 @@ x_get_scale_factor (struct x_display_info *dpyinfo,
 static void
 x_draw_underwave (struct glyph_string *s, int decoration_width)
 {
-  Display *display;
   struct x_display_info *dpyinfo;
   /* Adjust for scale/HiDPI.  */
   int scale_x, scale_y;
 
   dpyinfo = FRAME_DISPLAY_INFO (s->f);
-  display = dpyinfo->display;
   x_get_scale_factor (dpyinfo, &scale_x, &scale_y);
 
   int wave_height = 3 * scale_y, wave_length = 2 * scale_x;
@@ -10779,6 +10777,7 @@ x_draw_underwave (struct glyph_string *s, int 
decoration_width)
   x_draw_horizontal_wave (s->f, s->gc, s->x, s->ybase - wave_height + 3,
                          decoration_width, wave_height, wave_length);
 #else  /* not USE_CAIRO */
+  Display *display;
   int dx, dy, x0, y0, width, x1, y1, x2, y2, xmax, thickness = scale_y;;
   bool odd;
   XRectangle wave_clip, string_clip, final_clip;
@@ -10801,6 +10800,7 @@ x_draw_underwave (struct glyph_string *s, int 
decoration_width)
   if (!gui_intersect_rectangles (&wave_clip, &string_clip, &final_clip))
     return;
 
+  display = dpyinfo->display;
   XSetClipRectangles (display, s->gc, 0, 0, &final_clip, 1, Unsorted);
 
   /* Draw the waves */
@@ -10833,6 +10833,98 @@ x_draw_underwave (struct glyph_string *s, int 
decoration_width)
 #endif /* not USE_CAIRO */
 }
 
+/* Draw a dashed underline of thickness THICKNESS and width WIDTH onto F
+   at a vertical offset of OFFSET from the position of the glyph string
+   S, with each segment SEGMENT pixels in length.  */
+
+static void
+x_draw_dash (struct frame *f, struct glyph_string *s, int width,
+            char segment, int offset, int thickness)
+{
+#ifndef USE_CAIRO
+  GC gc;
+  Display *display;
+  XGCValues gcv;
+  int y_center;
+
+  /* Configure the GC, the dash pattern and a suitable offset.  */
+  gc = s->gc;
+  display = FRAME_X_DISPLAY (f);
+
+  XGetGCValues (display, s->gc, GCLineStyle, &gcv);
+  gcv.line_style = LineOnOffDash;
+  gcv.line_width = thickness;
+  XChangeGC (display, s->gc, GCLineStyle | GCLineWidth, &gcv);
+  XSetDashes (display, s->gc, s->x, &segment, 1);
+
+  /* Offset the origin of the line by half the line width. */
+  y_center = s->ybase + offset + thickness / 2;
+  XDrawLine (display, FRAME_X_DRAWABLE (f), gc,
+            s->x, y_center, s->x + width, y_center);
+
+  /* Restore the initial line style.  */
+  gcv.line_style = LineSolid;
+  gcv.line_width = 1;
+  XChangeGC (display, s->gc, GCLineStyle | GCLineWidth, &gcv);
+#else /* USE_CAIRO */
+  cairo_t *cr;
+  double cr_segment, y_center;
+
+  cr = x_begin_cr_clip (f, s->gc);
+  cr_segment = (double) segment;
+  y_center = s->ybase + offset + (thickness / 2.0);
+
+  x_set_cr_source_with_gc_foreground (f, s->gc, false);
+  cairo_set_dash (cr, &cr_segment, 1, s->x);
+  cairo_set_line_width (cr, thickness);
+  cairo_move_to (cr, s->x, y_center);
+  cairo_line_to (cr, s->x + width, y_center);
+  cairo_stroke (cr);
+  x_end_cr_clip (f);
+#endif /* USE_CAIRO */
+}
+
+/* Draw an underline of STYLE onto F at an offset of POSITION from the
+   baseline of the glyph string S, DECORATION_WIDTH in length, and
+   THICKNESS in height.  */
+
+static void
+x_fill_underline (struct frame *f, struct glyph_string *s,
+                 enum face_underline_type style, int position,
+                 int decoration_width, int thickness)
+{
+  int segment;
+  char x_segment;
+
+  segment = thickness * 3;
+
+  switch (style)
+    {
+      /* FACE_UNDERLINE_DOUBLE_LINE is treated identically to SINGLE, as
+        the second line will be filled by another invocation of this
+        function.  */
+    case FACE_UNDERLINE_SINGLE:
+    case FACE_UNDERLINE_DOUBLE_LINE:
+      x_fill_rectangle (f, s->gc, s->x, s->ybase + position,
+                       decoration_width, thickness, false);
+      break;
+
+    case FACE_UNDERLINE_DOTS:
+      segment = thickness;
+      FALLTHROUGH;
+
+    case FACE_UNDERLINE_DASHES:
+      x_segment = min (segment, CHAR_MAX);
+      x_draw_dash (f, s, decoration_width, x_segment, position,
+                  thickness);
+      break;
+
+    case FACE_NO_UNDERLINE:
+    case FACE_UNDERLINE_WAVE:
+    default:
+      emacs_abort ();
+    }
+}
 
 /* Draw glyph string S.  */
 
@@ -10973,16 +11065,13 @@ x_draw_glyph_string (struct glyph_string *s)
                   XSetForeground (display, s->gc, xgcv.foreground);
                 }
             }
-          else if (s->face->underline == FACE_UNDERLINE_SINGLE
-                  || s->face->underline == FACE_UNDERLINE_DOUBLE_LINE)
+          else if (s->face->underline >= FACE_UNDERLINE_SINGLE)
             {
               unsigned long thickness, position;
-              int y;
 
               if (s->prev
-                 && ((s->prev->face->underline == FACE_UNDERLINE_SINGLE)
-                     || (s->prev->face->underline
-                         == FACE_UNDERLINE_DOUBLE_LINE))
+                 && (s->prev->face->underline != FACE_UNDERLINE_WAVE
+                     && s->prev->face->underline >= FACE_UNDERLINE_SINGLE)
                  && (s->prev->face->underline_at_descent_line_p
                      == s->face->underline_at_descent_line_p)
                  && (s->prev->face->underline_pixels_above_descent_line
@@ -11064,20 +11153,16 @@ x_draw_glyph_string (struct glyph_string *s)
                Display *display = FRAME_X_DISPLAY (s->f);
                XGCValues xgcv;
 
-               y = s->ybase + position;
-               if (s->face->underline_defaulted_p)
-                 x_fill_rectangle (s->f, s->gc,
-                                   s->x, y, decoration_width, thickness,
-                                   false);
-               else
+               if (!s->face->underline_defaulted_p)
                  {
                    XGetGCValues (display, s->gc, GCForeground, &xgcv);
                    XSetForeground (display, s->gc, s->face->underline_color);
-                   x_fill_rectangle (s->f, s->gc,
-                                     s->x, y, decoration_width, thickness,
-                                     false);
                  }
 
+               x_fill_underline (s->f, s, s->face->underline,
+                                 position, decoration_width,
+                                 thickness);
+
                /* Place a second underline above the first if this was
                   requested in the face specification.  */
 
@@ -11085,9 +11170,9 @@ x_draw_glyph_string (struct glyph_string *s)
                  {
                    /* Compute the position of the second underline.  */
                    position = position - thickness - 1;
-                   y        = s->ybase + position;
-                   x_fill_rectangle (s->f, s->gc, s->x, y, decoration_width,
-                                     thickness, false);
+                   x_fill_underline (s->f, s, s->face->underline,
+                                     position, decoration_width,
+                                     thickness);
                  }
 
                if (!s->face->underline_defaulted_p)



reply via email to

[Prev in Thread] Current Thread [Next in Thread]