Subject: Re: bug#67604: Motion problems with inline images

From: Eli Zaretskii <[email-masked]>
Date: Thu, 29 May 2025 17:18:12 +0300

> From: JD Smith <[email-masked]>
> Date: Thu, 29 May 2025 09:56:55 -0400
> Cc: [email-masked]
> 
> Question: if you are simply "moving back to the current position", as start_display does (so as to correctly calculate the x pixel position), why does it matter whether the image covers 1 or more buffer positions?  E.g., my green box covers pos=89-125 in my test setup.  If I'm moving "back" to pos=89 from BOL, should reaching the position at the precise start of the image span not constitute BUFFER_POS_REACHED_P?  

Because that position's character is not shown.  It's concealed by the
image.

> In other words, it seems we don't need to know where an image or stretch _ends_ to know that we've reached its _beginning_.  I.e. could that portion of the test be crafted as (see alt2 patch, attached):
> 
>    && (it->method == GET_FROM_BUFFER                            \
>        || ((it->method == GET_FROM_IMAGE			\
> 	    || it->method == GET_FROM_STRETCH)			\
> 	   && IT_CHARPOS (*it) == to_charpos)                   \
> 
> ??

No, that's against the contract of the move_it_* functions.  They
return after they reached (or passed) the specified position and
processed the display element at that position, i.e. computed its
metrics.  And you cannot do that if you stop before the image.

> > So in this case, to return MOVE_POS_MATCH_OR_ZV, you need to move past
> > the image to the newline.  If that's what you did, and it->method was
> > still GET_FROM_IMAGE, please see why we don't update it->method,
> > because that is unexpected, I think.
> 
> In the case of a newline inserted right after a "just fitting on the line" green image (testing newline overflow into the fringe), this is indeed the current default scenario: we move past the image to the newline.  But, with my first patch, since it avoids the "just fits" branch, the one whose body starts:
> 
> 		      ++it->hpos;
> 		      it->current_x = new_x;
> 
> 		      /* The character's last glyph just barely fits
> 			 in this row.  */
> 		      if (i == it->nglyphs - 1)
> 
> we do not get a chance to notice ITERATOR_AT_END_OF_LINE_P and return early with MOVE_POS_MATCH_OR_ZV, instead returning MOVE_LINE_CONTINUED a bit further down, here:
> 
> 		  move_trace ("move_it_in: continued at %td\n",
> 			      IT_CHARPOS (*it));
> 		  result = MOVE_LINE_CONTINUED;
> 		  break;
> 
> This would also be true for a normal (non-WS) just-fitting character followed by a newline.  Again, this could be a distinction without a difference, but I don't know what depends on the precise return value of move_it_in_display_line_to.

Sorry, you lost me here.  I asked a question: if the iterator moves to
the newline immediately after the image, does it->method become
GET_FROM_BUFFER?  If yes, why don't we return MOVE_POS_MATCH_OR_ZV?
If it->method is not GET_FROM_BUFFER, why not?

As for the return value of move_it_in_display_line_to, it _is_
important to some of its callers.  So it's important to get it right.