emacs-devel
[Top][All Lists]
Advanced

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

Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functi


From: Eli Zaretskii
Subject: Re: Need `truncate-string-to-pixel-width` and `glyph-pixel-width` functions in C
Date: Fri, 25 Oct 2024 18:11:02 +0300

> From: Jimmy Yuen Ho Wong <wyuenho@gmail.com>
> Date: Fri, 25 Oct 2024 14:35:16 +0100
> Cc: emacs-devel@gnu.org
> 
> Here are more gaps to fill in for you. The margin and the scroll bar widths 
> are both calculated relative to the
> `default-font-width`, the reason for that is, assuming most of the text is in 
> the default font, if it is 20px wide, it's
> undesirable to have a fixed scroll bar size of 3px. The scroll bar and the 
> margin need to scale with the default
> font size to fight for just enough of the user's attention when viewed. This 
> can be known with some refactoring
> by the time `string-pixel-width` is called on all the formatted completion 
> strings, but the whole issue is the
> "right" in :align-to (- right <whatever>) would be referring to the window 
> from which you calculate
> `string-pixel-width` from, not the window in the child frame, because we are 
> trying calculate the child frame
> width from the content width at this point. What you are suggesting has a 
> logical circular dependency here,
> which is why I explained to you that :align-to can only be calculated from 
> `(+ prefix-column-width
> candidate--column-width (- suffix-column-width suffix-width)`. The suffix 
> width means the annotation's pixel
> width, the part you keep calling type, which is not necessarily the case. I.e:

So the problem is that you perform all the calculations _before_ the
child frame is created and shown?  If so, the :align-to will indeed be
incorrect, but the difference between the alignment you calculate and
the one you need is fixed: it's the difference in pixels between the
width of the selected window when you calculate the alignment and the
actual width of the window in the child frame where you will show the
completion candidates.  How hard is it to walk over all the candidates
you prepared for display and adjust the :align-to values once the
child frame is created?

And if the problem is that the dimensions of the child frame depend on
the width of the candidates+suffix to begin with, then you could
perhaps break this circular dependency by estimating the expected
width of the candidates by some coarse method that ignores the
subtleties and adds some slack to be on the safe side.

>  IOW, your proposed idea will work for the simple cases, but falls
>  apart for a general-purpose API which will rightfully be expected to
>  work in any situation and use case supported by Emacs.
> 
> Ok, makes sense. Thanks for filling in the missing parts for me. Here's some 
> further questions.
> 
> WRT case 1, translating tab sizes is a simple multiplication, it sounds to me 
> it can still be fast by bypassing
> windows. Is this correct? Anything else that can slow this case down?

The problem is that the actual width of a TAB on display depends on
the column where the TAB starts.  IOW, a TAB is not shown as 8
columns, it is shown as the number of columns till the next tab stop.
So its width cannot be reliably known for an arbitrary string until
you know at which column that string will start on display.
string-pixel-width assumes the string starts at column zero, but that
might not be true.

> WRT case 2, boldly extrapolating from my simple benchmarks, resolving the 
> font from faces takes ~10% of the
> time in `string-pixel-width`, besides saving and restoring window states and 
> scanning window positions, what
> else does "string-pixel-width" spend on the other 90% of the time?

In what version of Emacs did you benchmark it?  In Emacs 30, my
profiling indicates a large portion of the time is taken by
with-current-buffer.  Emacs 31 cuts the time in half by using a fixed
work buffer, but still, the actual pixel-width calculation takes only
about 30% of the running time.

(You can profile it yourself using profiler-start, but I suggest to
load subr-x.el first as the .el file, so that the profile will be more
detailed in terms of Lisp code.)

Bottom line: string-pixel-width is hardly efficient enough when
invoked in a tight loop, so if you need to call it many times for many
strings, perhaps a better idea would be to insert all the strings into
a work buffer, then measure their width one by one using
window-text-pixel-size, each time calling it with different FROM and
TO values?  That involves switching a window's buffer and then
switching it back, but maybe it will be faster?

Alternatively, if you only need the width of the widest string in a
collection, you could concatenate them separated by newlines, then
call string-pixel-width on the result.



reply via email to

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