Subject: Re: bug#72771: 31.0.50; shr html renderer throwing "Specified window is not displaying the current buffer"

From: Jim Porter <[email-masked]>
Date: Sat, 24 Aug 2024 12:42:04 -0700

On 8/24/2024 12:01 PM, Eli Zaretskii wrote:
>> Date: Sat, 24 Aug 2024 10:10:06 -0700
>> Cc: [email-masked], [email-masked], [email-masked]
>> From: Jim Porter <[email-masked]>
>>
>>>    . use the font obtained from (face-font 'default) (or the actual face
>>>      of the text, if you can get at it easily), like this:
>>>
>>>         (aref (font-info (face-font 'default)) 10)
>>
>> I think the problem is getting the actual face, which works for simple
>> cases via 'get-text-property', but not for more complex ones, e.g. when
>> the 'face' property is a list; 'face-font' raises an error in that case.
>> Effectively what I want would be a Lisp version of
>> 'face_at_buffer_position', but that requires a window object anyway, so
>> I'm back to the original problem...
> 
> What's wrong with face-at-point?

I don't know if that gets me quite what I want; it seems to be 
equivalent to 'get-text-property' for this case. The real problem is 
that I can't pass a list of faces to 'face-font'. In a case like that, 
any one of the faces in the list could be setting the font, so I can't 
just pass the first face in the list (or some other simplification).

I'm sure I could iterate over the faces, but that seems more complex 
than the 'font-at' trick.

>>>    . use buffer-text-pixel-size or string-pixel-width to measure the
>>>      width of a string of a single SPC character
>>
>> I think this wouldn't work since I want the average font width, not the
>> width of SPC.
> 
> Then use a few different characters and take their average width.

Well, I just want the "average-width" parameter as reported by the font 
object (falling back to "space-width"), since Emacs has already computed 
that. Trying to re-approximate that already-computed value doesn't seem 
like the right thing to do when I can jump over a small hurdle to get 
the existing value. Then I also don't have to worry about the 
performance impact of computing the approximation many times (or finding 
a place to cache it).

> And I think you place too much faith in the average-width parameter of
> a font.  It can fail you.  The display engine uses:
> 
> 	      char_width = (font->average_width
> 	                    ? font->average_width
> 	                    : font->space_width);

Thanks for prompting me to re-read the manual on this. I'd 
misinterpreted this passage in the documentation for 'query-font':

> average-width > The average width of the font characters. If this is zero, Emacs uses
> the value of space-width instead, when it calculates text layout on
> display.

Previously I thought it meant that this element of the vector would hold 
the average-width, or if that was zero, hold (a copy of) the 
space-width. But checking the code, I see that's not right, and I should 
be sure to mimic what the display engine does above.

Maybe this passage could be reworded to something like this: "This value 
may be zero.  In that case, for calculating text layout on display, 
Emacs will consult the space-width instead." (Or maybe this is just a 
"me" problem...)

>> In light of the above, I think what I have now might be the best way to
>> do it for the time being
> 
> Do you still think that?

Aside from the above issue with 'space-width', yes (fixed in the 
attached patch). The 'font-at' trick seems like it gets me the font 
object with the least amount of fuss, and then I can I can retrieve the 
pixel-size of the 'width' unit as used by the display engine when 
handling the pixel specification.

Maybe some higher-level function would be useful here but I don't know 
if this is a very common thing people need to do either...

From 0ef908e34e7a75e84dcadb4b09d583faacbd2bba Mon Sep 17 00:00:00 2001
From: Jim Porter <[email-masked]>
Date: Fri, 23 Aug 2024 15:11:24 -0700
Subject: [PATCH] Improve computation of indent depth in SHR and
 'visual-wrap-prefix-mode'

This method gets the font that would be used for the current window for
the text in question.  That way, there are no problems if the current
buffer isn't being displayed in a window.

* lisp/net/shr.el (shr-indent):
* lisp/visual-wrap.el (visual-wrap--content-prefix): Fix getting the
font when the buffer isn't displayed in a window.
(visual-wrap-fill-context-prefix): Fix indentation.
---
 lisp/net/shr.el     | 15 ++++++++++-----
 lisp/visual-wrap.el | 12 ++++++++----
 2 files changed, 18 insertions(+), 9 deletions(-)

diff --git a/lisp/net/shr.el b/lisp/net/shr.el
index b9ac9f0c8c0..1cbd9a0eaf5 100644
--- a/lisp/net/shr.el
+++ b/lisp/net/shr.el
@@ -1057,11 +1057,16 @@ shr-indent
          ;; of the current face, like (N . width).  That way, the
          ;; indentation is calculated correctly when using
          ;; `text-scale-adjust'.
-         `(space :width (,(if-let ((font (font-at (1- (point))))
-                                   (info (query-font font)))
-                              (/ (float shr-indentation) (aref info 7))
-                            shr-indentation)
-                         . width))))
+         `(space :width
+                 (,(if-let ((text (buffer-substring (1- (point)) (point)))
+                            (font (font-at 0 nil text))
+                            (info (query-font font))
+                            (avg-width (if (/= (aref info 7) 0)
+                                           (aref info 7)
+                                         (aref info 6))))
+                       (/ (float shr-indentation) avg-width)
+                     shr-indentation)
+                  . width))))
       (put-text-property start (+ (point) prefix)
                          'shr-prefix-length (+ prefix (- (point) start))))))
 
diff --git a/lisp/visual-wrap.el b/lisp/visual-wrap.el
index 902a9e41c5e..d0c87fd6e9e 100644
--- a/lisp/visual-wrap.el
+++ b/lisp/visual-wrap.el
@@ -164,11 +164,15 @@ visual-wrap--content-prefix
     ;; width of the first-line prefix in canonical-width characters.
     ;; This is useful if the first-line prefix uses some very-wide
     ;; characters.
-    (if-let ((font (font-at position))
-             (info (query-font font)))
+    (if-let ((text (buffer-substring position (1+ position)))
+             (font (font-at 0 nil text))
+             (info (query-font font))
+             (avg-width (if (/= (aref info 7) 0)
+                            (aref info 7)
+                          (aref info 6))))
         (max (string-width prefix)
              (ceiling (string-pixel-width prefix (current-buffer))
-                      (aref info 7)))
+                      avg-width))
       ;; We couldn't get the font, so we're in a terminal and
       ;; `string-pixel-width' is really returning the number of columns.
       ;; (This is different from `string-width', since that doesn't
@@ -189,7 +193,7 @@ visual-wrap-fill-context-prefix
           ;; make much sense (and is positively harmful in
           ;; taskpaper-mode where paragraph-start matches everything).
           (or (let ((paragraph-start regexp-unmatchable))
-                    (fill-context-prefix beg end))
+                (fill-context-prefix beg end))
                   ;; Note: fill-context-prefix may return nil; See:
                   ;; http://article.gmane.org/gmane.emacs.devel/156285
               ""))
-- 
2.25.1