Subject: bug#78621: Pixelwise display specified spaces less precise than min-width

From: Ship Mints <[email-masked]>
Date: Thu, 29 May 2025 12:41:11 -0400

On Thu, May 29, 2025 at 2:07 AM Eli Zaretskii <[email-masked]> wrote:

> > Cc: [email-masked]
> > From: Ship Mints <[email-masked]>
> > Date: Wed, 28 May 2025 16:40:26 -0400
> >
> > On Wed, May 28, 2025 at 4:14 PM Jim Porter <[email-masked]>
> wrote:
> >
> >  On 5/28/2025 12:44 PM, Ship Mints wrote:
> >  > You can see this in text-scaled buffers when attempting to pad a
> string
> >  > to a specific pixel boundary.  If a pixelwise specified-width space
> is
> >  > inserted after a string with variable-pitch glyphs, it doesn't honor
> the
> >  > net pixel width.  That same string padded using min-width with the
> same
> >  > number of pixels works fine.
> >
> >  Are you sure that your implementation of 'string-pixel-width-scaled' is
> >  correct? From a brief look, I'd expect that you get some jitter when
> >  dividing '(default-font-width)' by '(frame-char-width)', since both are
> >  rounded to the nearest whole number.
> >
> >  If I instead replace that call with:
> >
> >     (string-pixel-width str (current-buffer))
> >
> >  then everything looks ok to me. As of Emacs 31, passing a buffer does
> this:
> >
> >     If BUFFER is non-nil, use the face remappings, alternative and
> default
> >     properties from that buffer when determining the width.
> >
> >  That should handle all the necessary work to get the string width after
> >  applying text-scale remappings. I added that argument so I could use it
> >  in 'visual-wrap-prefix-mode' for a very similar issue you're seeing.
> See
> >  commit f70a6ea0ea86ef461e40d20664a75a92d02679ea.
> >
> > Thanks for that.  I think I'm using that in other places.
> >
> > But... Did you run the repro in question and it worked for you, or are
> you saying that this worked for your
> > case?
> >
> > AFAICT, the repro demonstrates a different issue.  With the identical
> string-pixel-width, padding using
> > specified-width spaces vs. min-width behave differently, so this isn't
> due to jitter as the widths used are the
> > same for both cases.
>
> I tried your recipe in Emacs 31.  The variable-pitch text indeed
> doesn't align, but the reason seems to be that the WIDTH value of
> '(space :width WIDTH)' display property is miscalculated.  In my case
> the :min-width spec has the value (150), i.e. 150 pixels, as expected,
> whereas in the '(space :width WIDTH)' spec WIDTH is (66) while the
> width of the text "f:0123456789" on display is 72 pixels (measured
> with posn-at-point).  So the sum is 72 + 66 = 138 pixels, not 150.
>
> The question is why is the value miscalculated.  Perhaps
> string-pixel-width-scaled doesn't do its job reliably with
> variable-pitch fonts?  I didn't have time to explore deeper, since you
> guys seem to be looking into that already.  Let me know if you find
> something unexpected or need my further help.
>

Indeed the two methods used in core Emacs to adjust widths in text-scaled
buffers do not work reliably with variable-pitch fonts.

  (/ (float (default-font-width)) (frame-char-width))
  (expt text-scale-mode-step text-scale-mode-amount)

I will now rely solely on 'string-pixel-width' specifying the reference
buffer from which the display engine can derive the text scale.

In the end, this was an experiment gone wonky, a nonbug, and now solved.

Thanks, all,

-Stephane