Subject: Re: bug#62637: 29.0.60; Issues when displaying images

From: Eli Zaretskii <[email-masked]>
Date: Mon, 03 Apr 2023 16:35:02 +0300

> Date: Sun, 02 Apr 2023 14:31:12 +0100
> From:  Abdul-Lateef Haji-Ali via "Bug reports for GNU Emacs,
>  the Swiss army knife of text editors" <[email-masked]>
> 
> 
> It seems that `mm-inline-image` switched to using `insert-image` instead of `put-image` which resulted in some regressions in notmuch that I noticed between emacs 29 and emacs 28.2. However, I tracked down the discrepancy to the following issues in displaying images in emacs-29. 

Maybe I'm missing something (you've lumped together several code
fragments without too many explanations), but I see no discrepancies
here, only unjustified expectations.

> First the following code (assuming some image in /tmp/tmp.png), executed in "emacs -Q" on either emacs 28.2 or emacs 29:
> 
> (let (content-begin
>       content-end)
>   (goto-char (point-max))
>   (insert "\n")
>   (setq content-begin (point))
>   (insert-image (create-image "/tmp/tmp.png"))
>   (setq content-end (point))
> 
>   ;; I expect the following line to indent the image (or not).
>   ;; instead the image is removed completely
>   ;;(indent-rigidly content-begin content-end 1)

indent-rigidly removes the existing whitespace and then inserts new
whitespace as needed.  And insert-image by default puts the 'display'
property on a space character.  Does this explain what you see?

>   ;; This line should hide the image, but it doesn't
>   ;;(overlay-put (make-overlay content-begin content-end) 'invisible t)
>   )

Due to the way the Emacs display engine is implemented, 'display'
properties (which is how images are implemented in Emacs) are
processed before invisible properties.  And a 'display' property that
specifies an image is a "replacing" property: the image is displayed
_instead_ of the buffer text which has this property, and the buffer
text itself is skipped.  What this means in this case is that the
overlay with the invisible property is completely ignored by the
display code, because the buffer text on which you put that overlay is
skipped when the 'display' property is processed.

> Similar code to this example is executed in notmuch when displaying message, but using `mm-inline-image` instead of insert-image:

I don't understand all the fine details of what mm-inline-image does,
but its current implementation again uses a space for the text on
which it puts the 'display' property that is displayed as the image.

> As a last test, in case it is helpful, I tried the following in emacs 29 using `put-image` instead of `insert-image` (`mm-inline-image` uses in Emacs 28.2 uses `put-image` while in Emacs 29 it uses 'insert-image'), and noticed an equally puzzling behaviour:
> 
> (let (content-begin
>       content-end)
>   (goto-char (point-max))
>   (insert "\n")
> 
>   (setq content-begin (point))
>   (put-image (create-image "/tmp/tmp.png") (point-marker))  
>   (setq content-end (point))
> 
>   ;; I expect the following line to indent the image (or not).
>   ;; instead the image is removed completely
>   ;;(indent-rigidly content-begin content-end 1)
> 
>   ;; This line should hide the image, but it doesn't
>   ;;(overlay-put (make-overlay content-begin content-end) 'invisible t)
> )
> 
> In this case, `indent-rigidly` does not remove the image, but hiding the overlay does not work.

For the overlays part, see the above: put-image cannot change that
basic fact.  If you are saying that notmuch was able to hide images by
using overlays, you will need to tell more and show some code which
did that in some prior version of Emacs.

As for indentation: put-image uses a different default for the text on
which it puts the image 'display' property.  That explains why
re-indentation didn't remove the image in Emacs 28.  Perhaps we should
modify mm-inline-image to use a non-whitespace text on which to put
the image?  Can you try that?  Lars, any reason you explicitly used
whitespace as the STRING argument of insert-image that replaced
put-image in mm-inline-image?