GNU bug report logs - #71039
:box :line-width and :underline :position should accept fractional sizes

Previous Next

Package: emacs;

Reported by: JD Smith <jdtsmith <at> gmail.com>

Date: Sat, 18 May 2024 14:53:02 UTC

Severity: normal

To reply to this bug, email your comments to 71039 AT debbugs.gnu.org.

Toggle the display of automated, internal messages from the tracker.

View this report as an mbox folder, status mbox, maintainer mbox


Report forwarded to bug-gnu-emacs <at> gnu.org:
bug#71039; Package emacs. (Sat, 18 May 2024 14:53:02 GMT) Full text and rfc822 format available.

Acknowledgement sent to JD Smith <jdtsmith <at> gmail.com>:
New bug report received and forwarded. Copy sent to bug-gnu-emacs <at> gnu.org. (Sat, 18 May 2024 14:53:02 GMT) Full text and rfc822 format available.

Message #5 received at submit <at> debbugs.gnu.org (full text, mbox):

From: JD Smith <jdtsmith <at> gmail.com>
To: bug-gnu-emacs <at> gnu.org
Subject: :box :line-width and :underline :position should accept fractional
 sizes
Date: Sat, 18 May 2024 10:52:03 -0400
[Message part 1 (text/plain, inline)]
For modes which layout mostly on fixed character-width grids, it is convenient to preserve that layout even as the text-scale changes.  Most of the size related attributes associated with display and face properties accommodate this style well, since they accept floating point values which adapt to the underlying char size.  These include face height, display height and raise, specified space dimensions, etc.   

There are, however, two face size attributes which are hard-coded in pixels: :box :linewidth and :underline :position.  It would be very convenient if these also accepted fractional floating point values.  E.g. a face attribute of:

:box (:line-width (0.5 . -0.25)) 

would indicate a box with half a char width outside padding left & right, and one-quarter char height padding above and below.

In addition, :box would be even more powerful, and obviate the use of SVG styling in many situations, if :box :line-width optionally accepted a list of four parameters for box dimensions, one for each side:

:line-width (left right top bottom)

naturally as either pixel or floating point fractions.

[Message part 2 (text/html, inline)]

Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#71039; Package emacs. (Sat, 18 May 2024 16:07:02 GMT) Full text and rfc822 format available.

Message #8 received at 71039 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: JD Smith <jdtsmith <at> gmail.com>
Cc: 71039 <at> debbugs.gnu.org
Subject: Re: bug#71039: :box :line-width and :underline :position should accept
 fractional sizes
Date: Sat, 18 May 2024 19:06:29 +0300
> From: JD Smith <jdtsmith <at> gmail.com>
> Date: Sat, 18 May 2024 10:52:03 -0400
> 
> There are, however, two face size attributes which are hard-coded in pixels: :box :linewidth and :underline :
> position.  It would be very convenient if these also accepted fractional floating point values.  E.g. a face
> attribute of:
> 
>  :box (:line-width (0.5 . -0.25)) 
> 
> would indicate a box with half a char width outside padding left & right, and one-quarter char height padding
> above and below.

Are you sure this is a good idea?  What would you like this to do when
two adjacent runs of text are shown using different-size fonts (which
AFAIU is the main use case for this feature)?  We currently force the
thickness and position of the underline to be identical for all the
characters of a stretch of underlined text, even if they are displayed
using different fonts, and we take those values from the first part of
the underlined text's stretch.  This is because having the underline
break or show differently in the middle of an underlined text has ugly
appearance.

OTOH, calculating the thickness and position in pixels from the face
font's dimensions is easy enough if your code needs that.

Given these two facts, I'm not sure supporting float values here will
be worth the effort.

> In addition, :box would be even more powerful, and obviate the use of SVG styling in many situations, if :box :
> line-width optionally accepted a list of four parameters for box dimensions, one for each side:
> 
>  :line-width (left right top bottom)
> 
> naturally as either pixel or floating point fractions.

How is this different from specifying the thickness and the position,
as we have today?




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#71039; Package emacs. (Sun, 19 May 2024 01:34:01 GMT) Full text and rfc822 format available.

Message #11 received at 71039 <at> debbugs.gnu.org (full text, mbox):

From: JD Smith <jdtsmith <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 71039 <at> debbugs.gnu.org
Subject: Re: bug#71039: :box :line-width and :underline :position should
 accept fractional sizes
Date: Sat, 18 May 2024 21:32:23 -0400

> On May 18, 2024, at 12:06 PM, Eli Zaretskii <eliz <at> gnu.org> wrote:
> 
>> From: JD Smith <jdtsmith <at> gmail.com>
>> Date: Sat, 18 May 2024 10:52:03 -0400
>> 
>> There are, however, two face size attributes which are hard-coded in pixels: :box :linewidth and :underline :
>> position.  It would be very convenient if these also accepted fractional floating point values.  E.g. a face
>> attribute of:
>> 
>> :box (:line-width (0.5 . -0.25)) 
>> 
>> would indicate a box with half a char width outside padding left & right, and one-quarter char height padding
>> above and below.
> 
> Are you sure this is a good idea?  

Definitely!  I've spent a good bit of time working around the absence of this feature (and, while I found solutions, they were too convoluted to be practical).

> What would you like this to do when
> two adjacent runs of text are shown using different-size fonts (which
> AFAIU is the main use case for this feature)?  

They'd have different height boxes, and that would be the desired effect.  Sort of the same idea as something like:

(insert "\n"
        (propertize " Short " 'face '(:box (:line-width (0 . -4)) :inverse-video t))
        (propertize " BOX " 'face '(:box (:line-width (0 . -2)) :inverse-video t))
        (propertize " tall box " 'face '(:box (:line-width (1 . 1))))
        "\n")

except also adaptive to the text height.  Normally of course you would not do this for random text.  Instead you'd apply targeted floating :box widths to short stretches of text, like labels.

> We currently force the
> thickness and position of the underline to be identical for all the
> characters of a stretch of underlined text, even if they are displayed
> using different fonts, and we take those values from the first part of
> the underlined text's stretch.  This is because having the underline
> break or show differently in the middle of an underlined text has ugly
> appearance.

I wan't aware of this behavior, but I do see the value in that special rule for underlines.  It's possible that pixel position indeed makes the most sense for underline, given the face-merging behavior you describe.  I included it mostly for completeness.

More important is :box.  For various effects which cover short stretches of text like label boxes, etc., the ability to have the box thickness scale with char size would be very useful.  Often these use inverse-video, so that the "box" is in the background color.  Many packages reach for SVG images in this context, but with a little help, many of those uses could be avoided.

> OTOH, calculating the thickness and position in pixels from the face
> font's dimensions is easy enough if your code needs that.

Sure, but upon text-scaling, this calculation needs to be performed again (probably in a temporary buffer, and across many faces).  Then, per-buffer face remaps must be applied and managed, etc.   I've done that, but it's a lot to juggle for a simple box.

> Given these two facts, I'm not sure supporting float values here will
> be worth the effort.

I'm confident they'd be used quite a lot.  Do you have a sense of how difficult these improvements would be?  Since you can already now apply fractional specified space like (space :width (0.25 . width)), I was hopeful the calculations would be close at hand.

>> In addition, :box would be even more powerful, and obviate the use of SVG styling in many situations, if :box :
>> line-width optionally accepted a list of four parameters for box dimensions, one for each side:
>> 
>> :line-width (left right top bottom)
>> 
>> naturally as either pixel or floating point fractions.
> 
> How is this different from specifying the thickness and the position,
> as we have today?

AFAIU there is no :position offset for :box?  Right now, :box can specify thickness as a fixed number of pixels outside (or inside, if negative) the character(s), and in recent versions these widths can differ vertically and horizontally.  But boxes are always centered horizontally on the boxed text and vertically on the line (including any line-spacing).

What the above proposal would do is allow you to specify the box width separately on all 4 sides of the affected text: left, right, top, and bottom.  So for example:

	:line-width (4 0 -0.25 -0.1)

would push the box 4 pixel to the left, and pull the box down from the top more than up from the bottom. As a related idea, following your suggestion, you could keep :line-width as-is and add a :box :position attribute that shifts the box vertically (which would be the same except symmetric left/right).  

The floating point width is probably more important, but this would enable some useful effects like simple text-based progress bars, etc. 



Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#71039; Package emacs. (Sun, 19 May 2024 06:38:02 GMT) Full text and rfc822 format available.

Message #14 received at 71039 <at> debbugs.gnu.org (full text, mbox):

From: Eli Zaretskii <eliz <at> gnu.org>
To: JD Smith <jdtsmith <at> gmail.com>
Cc: 71039 <at> debbugs.gnu.org
Subject: Re: bug#71039: :box :line-width and :underline :position should
 accept fractional sizes
Date: Sun, 19 May 2024 09:37:19 +0300
> From: JD Smith <jdtsmith <at> gmail.com>
> Date: Sat, 18 May 2024 21:32:23 -0400
> Cc: 71039 <at> debbugs.gnu.org
> 
> > Are you sure this is a good idea?  
> 
> Definitely!  I've spent a good bit of time working around the absence of this feature (and, while I found solutions, they were too convoluted to be practical).
> 
> > What would you like this to do when
> > two adjacent runs of text are shown using different-size fonts (which
> > AFAIU is the main use case for this feature)?  
> 
> They'd have different height boxes, and that would be the desired effect.  Sort of the same idea as something like:
> 
> (insert "\n"
>         (propertize " Short " 'face '(:box (:line-width (0 . -4)) :inverse-video t))
>         (propertize " BOX " 'face '(:box (:line-width (0 . -2)) :inverse-video t))
>         (propertize " tall box " 'face '(:box (:line-width (1 . 1))))
>         "\n")
> 
> except also adaptive to the text height.  Normally of course you would not do this for random text.  Instead you'd apply targeted floating :box widths to short stretches of text, like labels.

I think it will look ugly, but I guess to each their own.

Anyway, the line width is stored in the face structure when the face
is realized, and kept there for when the box face needs to be drawn.
If the values are relative, the drawing back-end will need to compute
the corresponding absolute width values by accessing the font metrics
(or is it the height of the screen line?) at draw time.  And we will
need to do that for all the back-ends we have.  Patches welcome.

> I'm confident they'd be used quite a lot.  Do you have a sense of how difficult these improvements would be?  Since you can already now apply fractional specified space like (space :width (0.25 . width)), I was hopeful the calculations would be close at hand.

The space width is calculated in the back-end-independent part of the
display code (xdisp.c), because it yields a stretch glyph of a certain
width (which is later drawn on screen as a stretch of background
color).  By contrast, the box face is implemented in back-end code
(*term.c), since it needs to draw lines using the display-specific
APIs.  So we cannot use the same code in these two cases.

> What the above proposal would do is allow you to specify the box width separately on all 4 sides of the affected text: left, right, top, and bottom.  So for example:
> 
> 	:line-width (4 0 -0.25 -0.1)
> 
> would push the box 4 pixel to the left, and pull the box down from the top more than up from the bottom. As a related idea, following your suggestion, you could keep :line-width as-is and add a :box :position attribute that shifts the box vertically (which would be the same except symmetric left/right).  
> 
> The floating point width is probably more important, but this would enable some useful effects like simple text-based progress bars, etc. 

This will need to extend the face structure to store 4 line thickness
values, not 2 as we do today.




Information forwarded to bug-gnu-emacs <at> gnu.org:
bug#71039; Package emacs. (Sun, 19 May 2024 13:48:02 GMT) Full text and rfc822 format available.

Message #17 received at 71039 <at> debbugs.gnu.org (full text, mbox):

From: JD Smith <jdtsmith <at> gmail.com>
To: Eli Zaretskii <eliz <at> gnu.org>
Cc: 71039 <at> debbugs.gnu.org
Subject: Re: bug#71039: :box :line-width and :underline :position should
 accept fractional sizes
Date: Sun, 19 May 2024 09:45:52 -0400

> On May 19, 2024, at 2:37 AM, Eli Zaretskii <eliz <at> gnu.org> wrote:
> 
>>  Normally of course you would not do this for random text.  Instead you'd apply targeted floating :box widths to short stretches of text, like labels.
> 
> I think it will look ugly, but I guess to each their own.

That's just a random example, not meant for appearance evaluation ;).  It's already the idea used for popular packages like org-modern (with some difficulty resulting from the limitations of :box).  The basic idea is to give more flexibility for box placement, which will open up many uses.

> Anyway, the line width is stored in the face structure when the face
> is realized, and kept there for when the box face needs to be drawn.
> If the values are relative, the drawing back-end will need to compute
> the corresponding absolute width values by accessing the font metrics

I guess this is how face must already handle :height, selecting a font based on that (after inheritance, and multiplying all the :height's together).  Perhaps turning fractional box size into pixel values could make use of that work?  Surely that is not back-end dependent.

> (or is it the height of the screen line?) at draw time.  

Ideally the fractional box widths would be relative to the font size itself, but I think line height would also be fine, if that were simpler and more performant.

>> I'm confident they'd be used quite a lot.  Do you have a sense of how difficult these improvements would be?  Since you can already now apply fractional specified space like (space :width (0.25 . width)), I was hopeful the calculations would be close at hand.
> 
> The space width is calculated in the back-end-independent part of the
> display code (xdisp.c), because it yields a stretch glyph of a certain
> width (which is later drawn on screen as a stretch of background
> color).  By contrast, the box face is implemented in back-end code
> (*term.c), since it needs to draw lines using the display-specific
> APIs.  So we cannot use the same code in these two cases.

I see, thanks.  Given that, it would probably be worthwhile to get broader input on what types of back-end dependent screen drawing improvements would be valuable for faces.

>> What the above proposal would do is allow you to specify the box width separately on all 4 sides of the affected text: left, right, top, and bottom.  So for example:
>> 
>> 	:line-width (4 0 -0.25 -0.1)
>> 
>> would push the box 4 pixel to the left, and pull the box down from the top more than up from the bottom. As a related idea, following your suggestion, you could keep :line-width as-is and add a :box :position attribute that shifts the box vertically (which would be the same except symmetric left/right).  
>> 
>> The floating point width is probably more important, but this would enable some useful effects like simple text-based progress bars, etc.
> 
> This will need to extend the face structure to store 4 line thickness
> values, not 2 as we do today.

Or 3, if the :position flavor were deemed superior.  

Thanks for the information.





This bug report was last modified 13 days ago.

Previous Next


GNU bug tracking system
Copyright (C) 1999 Darren O. Benham, 1997,2003 nCipher Corporation Ltd, 1994-97 Ian Jackson.