emacs-diffs
[Top][All Lists]
Advanced

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

master 4f50d964e5: Allow controlling the underline position of faces


From: Po Lu
Subject: master 4f50d964e5: Allow controlling the underline position of faces
Date: Mon, 10 Jan 2022 06:32:31 -0500 (EST)

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

    Allow controlling the underline position of faces
    
    * doc/lispref/display.texi (Face Attributes): Document new
    `:position' property of the `:underline' attribute.
    * etc/NEWS: Announce new property.
    * lisp/cus-face.el (custom-face-attributes): Implement
    customization for new face attribute.
    * src/dispextern.h (struct face): New fields
    `underline_pixels_above_descent_line' and
    `underline_at_descent_line_p'.
    * src/haikuterm.c (haiku_draw_text_decoration):
    * src/nsterm.m (ns_draw_text_decoration):
    * src/w32term.c (w32_draw_glyph_string):
    * src/xterm.c (x_draw_glyph_string): Respect new face fields.
    
    * src/xfaces.c (realize_gui_face): Handle new `:position'
    keyword.
    (syms_of_xfaces): New symbol `:position'.
---
 doc/lispref/display.texi |  7 +++++--
 etc/NEWS                 |  6 ++++++
 lisp/cus-face.el         | 20 ++++++++++++++------
 src/dispextern.h         |  9 +++++++++
 src/haikuterm.c          | 14 +++++++++++---
 src/nsterm.m             | 15 +++++++++++----
 src/w32term.c            | 20 ++++++++++++++++----
 src/xfaces.c             | 16 ++++++++++++++++
 src/xterm.c              | 25 ++++++++++++++++++-------
 9 files changed, 106 insertions(+), 26 deletions(-)

diff --git a/doc/lispref/display.texi b/doc/lispref/display.texi
index f191c400ab..2183d35e7e 100644
--- a/doc/lispref/display.texi
+++ b/doc/lispref/display.texi
@@ -2555,13 +2555,16 @@ Underline with the foreground color of the face.
 @item @var{color}
 Underline in color @var{color}, a string specifying a color.
 
-@item @code{(:color @var{color} :style @var{style})}
+@item @code{(:color @var{color} :style @var{style} :position @var{position}}
 @var{color} is either a string, or the symbol @code{foreground-color},
 meaning the foreground color of the face.  Omitting the attribute
 @code{:color} means to use the foreground color of the face.
 @var{style} should be a symbol @code{line} or @code{wave}, meaning to
 use a straight or wavy line.  Omitting the attribute @code{:style}
-means to use a straight line.
+means to use a straight line.  @var{position}, if non-nil, means to
+display the underline at the descent of the text, instead of at the
+baseline level.  If it is a number, then it specifies the amount of
+pixels above the descent to display the underline.
 @end table
 
 @cindex overlined text
diff --git a/etc/NEWS b/etc/NEWS
index 4ff2325ff0..d256342f43 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -1278,6 +1278,12 @@ This is a subcategory of 'file-error', and is signaled 
when some file
 operation fails because the OS doesn't allow Emacs to access a file or
 a directory.
 
++++
+** The ':underline' face attribute now accepts a new property.
+The property ':position' now specifies the position of the underline
+when used as part of a property list specification for the
+':underline' attribute.
+
 
 * Changes in Emacs 29.1 on Non-Free Operating Systems
 
diff --git a/lisp/cus-face.el b/lisp/cus-face.el
index fa6d940d7c..e905a45557 100644
--- a/lisp/cus-face.el
+++ b/lisp/cus-face.el
@@ -141,7 +141,12 @@
                   (const :format "" :value :style)
                   (choice :tag "Style"
                           (const :tag "Line" line)
-                          (const :tag "Wave" wave))))
+                          (const :tag "Wave" wave))
+                   (const :format "" :value :position)
+                   (choice :tag "Position"
+                           (const :tag "At Default Position" nil)
+                           (const :tag "At Bottom Of Text" t)
+                           (integer :tag "Pixels Above Bottom Of Text"))))
      ;; filter to make value suitable for customize
      (lambda (real-value)
        (and real-value
@@ -151,18 +156,21 @@
                       'foreground-color))
                  (style
                   (or (and (consp real-value) (plist-get real-value :style))
-                      'line)))
-             (list :color color :style style))))
+                      'line))
+                  (position (and (consp real-value)
+                                 (plist-get real-value :style))))
+             (list :color color :style style :position position))))
      ;; filter to make customized-value suitable for storing
      (lambda (cus-value)
        (and cus-value
            (let ((color (plist-get cus-value :color))
-                 (style (plist-get cus-value :style)))
-             (cond ((eq style 'line)
+                 (style (plist-get cus-value :style))
+                  (position (plist-get cus-value :position)))
+             (cond ((and (eq style 'line) (not position))
                     ;; Use simple value for default style
                     (if (eq color 'foreground-color) t color))
                    (t
-                    `(:color ,color :style ,style)))))))
+                    `(:color ,color :style ,style :position ,position)))))))
 
     (:overline
      (choice :tag "Overline"
diff --git a/src/dispextern.h b/src/dispextern.h
index 954992a0ec..368507732c 100644
--- a/src/dispextern.h
+++ b/src/dispextern.h
@@ -1720,6 +1720,12 @@ struct face
   int box_vertical_line_width;
   int box_horizontal_line_width;
 
+
+  /* The amount of pixels above the descent line the underline should
+     be displayed.  It does not take effect unless
+     `underline_at_descent_line_p` is t.  */
+  int underline_pixels_above_descent_line;
+
   /* Type of box drawn.  A value of FACE_NO_BOX means no box is drawn
      around text in this face.  A value of FACE_SIMPLE_BOX means a box
      of width box_line_width is drawn in color box_color.  A value of
@@ -1753,6 +1759,9 @@ struct face
   bool_bf strike_through_color_defaulted_p : 1;
   bool_bf box_color_defaulted_p : 1;
 
+  /* True means the underline should be drawn at the descent line.  */
+  bool_bf underline_at_descent_line_p : 1;
+
   /* TTY appearances.  Colors are found in `lface' with empty color
      string meaning the default color of the TTY.  */
   bool_bf tty_bold_p : 1;
diff --git a/src/haikuterm.c b/src/haikuterm.c
index b6d105bf2b..2304f718c3 100644
--- a/src/haikuterm.c
+++ b/src/haikuterm.c
@@ -613,7 +613,12 @@ haiku_draw_text_decoration (struct glyph_string *s, struct 
face *face,
          unsigned long thickness, position;
          int y;
 
-         if (s->prev && s->prev && s->prev->hl == DRAW_MOUSE_FACE)
+         if (s->prev
+             && s->prev->face->underline == FACE_UNDER_LINE
+             && (s->prev->face->underline_at_descent_line_p
+                 == s->face->underline_at_descent_line_p)
+             && (s->prev->face->underline_pixels_above_descent_line
+                 == s->face->underline_pixels_above_descent_line))
            {
              struct face *prev_face = s->prev->face;
 
@@ -644,7 +649,8 @@ haiku_draw_text_decoration (struct glyph_string *s, struct 
face *face,
              val = (WINDOW_BUFFER_LOCAL_VALUE
                     (Qx_underline_at_descent_line, s->w));
              underline_at_descent_line
-               = !(NILP (val) || EQ (val, Qunbound));
+               = (!(NILP (val) || EQ (val, Qunbound))
+                  || s->face->underline_at_descent_line_p);
 
              val = (WINDOW_BUFFER_LOCAL_VALUE
                     (Qx_use_underline_position_properties, s->w));
@@ -657,7 +663,9 @@ haiku_draw_text_decoration (struct glyph_string *s, struct 
face *face,
              else
                thickness = 1;
              if (underline_at_descent_line)
-               position = (s->height - thickness) - (s->ybase - s->y);
+               position = ((s->height - thickness)
+                           - (s->ybase - s->y)
+                           - s->face->underline_pixels_above_descent_line);
              else
                {
                  /* Get the underline position.  This is the
diff --git a/src/nsterm.m b/src/nsterm.m
index a15dc47a22..4f60cc737d 100644
--- a/src/nsterm.m
+++ b/src/nsterm.m
@@ -3265,7 +3265,11 @@ ns_draw_text_decoration (struct glyph_string *s, struct 
face *face,
           /* If the prev was underlined, match its appearance.  */
           if (s->prev
              && s->prev->face->underline == FACE_UNDER_LINE
-              && s->prev->underline_thickness > 0)
+              && s->prev->underline_thickness > 0
+             && (s->prev->face->underline_at_descent_line_p
+                 == s->face->underline_at_descent_line_p)
+             && (s->prev->face->underline_pixels_above_descent_line
+                 == s->face->underline_pixels_above_descent_line))
             {
               thickness = s->prev->underline_thickness;
               position = s->prev->underline_position;
@@ -3286,7 +3290,8 @@ ns_draw_text_decoration (struct glyph_string *s, struct 
face *face,
 
              val = (WINDOW_BUFFER_LOCAL_VALUE
                     (Qx_underline_at_descent_line, s->w));
-             underline_at_descent_line = !(NILP (val) || EQ (val, Qunbound));
+             underline_at_descent_line = (!(NILP (val) || EQ (val, Qunbound))
+                                          || 
s->face->underline_at_descent_line_p);
 
              val = (WINDOW_BUFFER_LOCAL_VALUE
                     (Qx_use_underline_position_properties, s->w));
@@ -3299,7 +3304,8 @@ ns_draw_text_decoration (struct glyph_string *s, struct 
face *face,
 
               /* Determine the offset of underlining from the baseline.  */
               if (underline_at_descent_line)
-                position = descent - thickness;
+                position = (descent - thickness
+                           - s->face->underline_pixels_above_descent_line);
               else if (use_underline_position_properties
                        && font && font->underline_position >= 0)
                 position = font->underline_position;
@@ -3308,7 +3314,8 @@ ns_draw_text_decoration (struct glyph_string *s, struct 
face *face,
               else
                 position = minimum_offset;
 
-              position = max (position, minimum_offset);
+             if (!s->face->underline_pixels_above_descent_line)
+               position = max (position, minimum_offset);
 
               /* Ensure underlining is not cropped.  */
               if (descent <= position)
diff --git a/src/w32term.c b/src/w32term.c
index 700c492cc3..78777f153c 100644
--- a/src/w32term.c
+++ b/src/w32term.c
@@ -2564,7 +2564,11 @@ w32_draw_glyph_string (struct glyph_string *s)
               int y;
 
               if (s->prev
-                 && s->prev->face->underline == FACE_UNDER_LINE)
+                 && s->prev->face->underline == FACE_UNDER_LINE
+                 && (s->prev->face->underline_at_descent_line_p
+                     == s->face->underline_at_descent_line_p)
+                 && (s->prev->face->underline_pixels_above_descent_line
+                     == s->face->underline_pixels_above_descent_line))
                 {
                   /* We use the same underline style as the previous one.  */
                   thickness = s->prev->underline_thickness;
@@ -2587,7 +2591,8 @@ w32_draw_glyph_string (struct glyph_string *s)
                  val = (WINDOW_BUFFER_LOCAL_VALUE
                         (Qx_underline_at_descent_line, s->w));
                  underline_at_descent_line
-                   = !(NILP (val) || EQ (val, Qunbound));
+                   = (!(NILP (val) || EQ (val, Qunbound))
+                      || s->face->underline_at_descent_line_p);
 
                  val = (WINDOW_BUFFER_LOCAL_VALUE
                         (Qx_use_underline_position_properties, s->w));
@@ -2601,7 +2606,9 @@ w32_draw_glyph_string (struct glyph_string *s)
                     thickness = 1;
                   if (underline_at_descent_line
                       || !font)
-                    position = (s->height - thickness) - (s->ybase - s->y);
+                   position = ((s->height - thickness)
+                               - (s->ybase - s->y)
+                               - s->face->underline_pixels_above_descent_line);
                   else
                     {
                       /* Get the underline position.  This is the
@@ -2619,7 +2626,12 @@ w32_draw_glyph_string (struct glyph_string *s)
                       else
                         position = (font->descent + 1) / 2;
                     }
-                  position = max (position, minimum_offset);
+
+                 if (!(s->face->underline_at_descent_line_p
+                       /* Ignore minimum_offset if the amount of pixels
+                          was explictly specified.  */
+                       && s->face->underline_pixels_above_descent_line))
+                   position = max (position, minimum_offset);
                 }
               /* Check the sanity of thickness and position.  We should
                  avoid drawing underline out of the current line area.  */
diff --git a/src/xfaces.c b/src/xfaces.c
index 3fd31b7f22..8064d47c94 100644
--- a/src/xfaces.c
+++ b/src/xfaces.c
@@ -6041,6 +6041,8 @@ realize_gui_face (struct face_cache *cache, Lisp_Object 
attrs[LFACE_VECTOR_SIZE]
       face->underline = FACE_UNDER_LINE;
       face->underline_defaulted_p = true;
       face->underline_color = 0;
+      face->underline_at_descent_line_p = false;
+      face->underline_pixels_above_descent_line = 0;
     }
   else if (STRINGP (underline))
     {
@@ -6050,12 +6052,16 @@ realize_gui_face (struct face_cache *cache, Lisp_Object 
attrs[LFACE_VECTOR_SIZE]
       face->underline_color
        = load_color (f, face, underline,
                      LFACE_UNDERLINE_INDEX);
+      face->underline_at_descent_line_p = false;
+      face->underline_pixels_above_descent_line = 0;
     }
   else if (NILP (underline))
     {
       face->underline = FACE_NO_UNDERLINE;
       face->underline_defaulted_p = false;
       face->underline_color = 0;
+      face->underline_at_descent_line_p = false;
+      face->underline_pixels_above_descent_line = 0;
     }
   else if (CONSP (underline))
     {
@@ -6064,6 +6070,8 @@ realize_gui_face (struct face_cache *cache, Lisp_Object 
attrs[LFACE_VECTOR_SIZE]
       face->underline = FACE_UNDER_LINE;
       face->underline_color = 0;
       face->underline_defaulted_p = true;
+      face->underline_at_descent_line_p = false;
+      face->underline_pixels_above_descent_line = 0;
 
       /* FIXME?  This is also not robust about checking the precise form.
          See comments in Finternal_set_lisp_face_attribute.  */
@@ -6100,6 +6108,13 @@ realize_gui_face (struct face_cache *cache, Lisp_Object 
attrs[LFACE_VECTOR_SIZE]
               else if (EQ (value, Qwave))
                 face->underline = FACE_UNDER_WAVE;
             }
+         else if (EQ (keyword, QCposition))
+           {
+             face->underline_at_descent_line_p = !NILP (value);
+
+             if (FIXNATP (value))
+               face->underline_pixels_above_descent_line = XFIXNAT (value);
+           }
         }
     }
 
@@ -6915,6 +6930,7 @@ syms_of_xfaces (void)
   DEFSYM (QCcolor, ":color");
   DEFSYM (QCline_width, ":line-width");
   DEFSYM (QCstyle, ":style");
+  DEFSYM (QCposition, ":position");
   DEFSYM (Qline, "line");
   DEFSYM (Qwave, "wave");
   DEFSYM (Qreleased_button, "released-button");
diff --git a/src/xterm.c b/src/xterm.c
index 321b4c5ab6..e2b09938a2 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -4144,8 +4144,12 @@ x_draw_glyph_string (struct glyph_string *s)
               unsigned long thickness, position;
               int y;
 
-              if (s->prev &&
-                 s->prev->face->underline == FACE_UNDER_LINE)
+              if (s->prev
+                 && s->prev->face->underline == FACE_UNDER_LINE
+                 && (s->prev->face->underline_at_descent_line_p
+                     == s->face->underline_at_descent_line_p)
+                 && (s->prev->face->underline_pixels_above_descent_line
+                     == s->face->underline_pixels_above_descent_line))
                 {
                   /* We use the same underline style as the previous one.  */
                   thickness = s->prev->underline_thickness;
@@ -4168,7 +4172,8 @@ x_draw_glyph_string (struct glyph_string *s)
                  val = (WINDOW_BUFFER_LOCAL_VALUE
                         (Qx_underline_at_descent_line, s->w));
                  underline_at_descent_line
-                   = !(NILP (val) || EQ (val, Qunbound));
+                   = (!(NILP (val) || EQ (val, Qunbound))
+                      || s->face->underline_at_descent_line_p);
 
                  val = (WINDOW_BUFFER_LOCAL_VALUE
                         (Qx_use_underline_position_properties, s->w));
@@ -4181,7 +4186,9 @@ x_draw_glyph_string (struct glyph_string *s)
                   else
                     thickness = 1;
                   if (underline_at_descent_line)
-                    position = (s->height - thickness) - (s->ybase - s->y);
+                   position = ((s->height - thickness)
+                               - (s->ybase - s->y)
+                               - s->face->underline_pixels_above_descent_line);
                   else
                     {
                       /* Get the underline position.  This is the
@@ -4201,12 +4208,16 @@ x_draw_glyph_string (struct glyph_string *s)
                       else
                         position = minimum_offset;
                     }
-                  position = max (position, minimum_offset);
+
+                 /* Ignore minimum_offset if the amount of pixels was
+                    explictly specified.  */
+                 if (!s->face->underline_pixels_above_descent_line)
+                   position = max (position, 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)
+               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;



reply via email to

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