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

From: Jim Porter <[email-masked]>
Date: Thu, 29 May 2025 09:38:15 -0700

On 5/28/2025 11:18 PM, Eli Zaretskii wrote:
> I don't follow this argument.  string-pixel-width uses the display
> code, so it should return the exact same value in pixels as what the
> actual display produces when the same characters are shown on the
> screen.  So whatever rounding happens (which I don't think it does,
> since font glyphs have integer advance width), it happens the same in
> both cases and should yield the same values.  Or what am I missing?

The short version is that we should pass the current buffer to 
'string-pixel-width' so that we can just use the display code to compute 
the string's width with all the remappings applied, rather than having 
the display code compute it without remappings and then trying to guess 
what the remapping would do to the width.

Here's a longer version if it helps:

The problem is that 'text-scale-increase' modifies the text size by a 
particular ratio; when zooming out by one step, that defaults to 1 / 
text-scale-mode-step, or 5/6.

My fixed-pitch font is 8 pixels wide at the default size, so zooming out 
one step means the pixel width per char is 8 * 5/6 = 6.666. Since the 
advance width is an integer, we round up to 7 pixels. The original code 
works for fixed-pitch fonts since '(default-font-width)' returns 7 in 
this case, so the original expression:

   (ceiling (* (string-pixel-width str)
               (/ (float (default-font-width)) (frame-char-width))))

is equivalent (only in this simple case) to:

   (* (string-width str) (default-font-width))

Hopefully that all makes sense.

For variable-pitch fonts, this is more complex. Our zoom ratio is still 
5/6, but we apply that ratio per-character, rounding each time. For the 
string "hi there", the pixel widths of each character are:

   Scale   h  i  _  t  h  e  r  e   Total
       0   8  4  4  5  8  8  5  8      50
      -1   7  3  4  4  7  7  5  7      44

Since the error introduced by rounding each character is a bit 
different, we get a different result between the width from the display 
engine compared to the approximation in the first expression above where 
we round only once at the very end.