bug-gnu-emacs
[Top][All Lists]
Advanced

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

bug#38731: [PATCH] Calculate first glyph to be redrawn when exposing (bu


From: Alan Third
Subject: bug#38731: [PATCH] Calculate first glyph to be redrawn when exposing (bug#38731)
Date: Sat, 28 Dec 2019 11:20:13 +0000

On Sat, Dec 28, 2019 at 10:54:50AM +0200, Eli Zaretskii wrote:
> > Date: Fri, 27 Dec 2019 19:06:52 +0000
> > From: Alan Third <alan@idiocy.org>
> > Cc: netjune@outlook.com, 38731@debbugs.gnu.org
> > 
> > The actual problem is that if there is a face that’s to extend to the
> > end of the line (for example with global-hl-line-mode) then
> > expose_area asks draw_glyphs to draw glyph 0 at x coordinate 0, even
> > though in this case there is horizontal scrolling in effect that means
> > glyph 0 should be at a negative x coordinate.
> > 
> > In my case I could see that row->x in expose_area was set to -42 but
> > expose_area called draw_glyphs with an x parameter of 0. This offset
> > the glyphs on the screen by 42 pixels. I could see this both in
> > debugging printfs and by actually measuring the difference between the
> > cursor and the equivalent text as drawn on the screen.
> 
> You are saying that, when the window is hscrolled, the glyphs in the
> glyph row start with the glyph for the very first character of the
> physical line in this case?  IOW, if the line's text is "abcdef", then
> row->glyphs[TEXT_AREA] is the glyph for the character 'a', even though
> the line is hscrolled?
> 
> This shouldn't happen, because display_line, the function which
> produces glyphs in glyph rows, starts producing the glyphs at the
> first one that is actually visible, thus taking the hscroll into
> account.  See the code in display_line that follows this comment:
> 
>   /* Move over display elements that are not visible because we are
>      hscrolled.  This may stop at an x-position < first_visible_x
>      if the first glyph is partially visible or if we hit a line end.  */
>   if (it->current_x < it->first_visible_x + x_incr)

Ah! I have misunderstood what exactly expose_area is doing.

The first visible glyph is a tab character, width ~64 pixels, which is
only partially visible. It should start 42 pixels to the left of the
window. expose_area calls draw_glyphs with an x coordinate of 0, which
draws the entire tab instead of only the visible portion.

It’s pretty simple to manually step through the two sides of the big
if in expose_area and show that with the same input (except for
row->fill_line_p) they will start drawing the line at different x
coordinates.

A minimal, and possibly correct, fix is:

modified   src/xdisp.c
@@ -33491,7 +33491,7 @@ expose_area (struct window *w, struct glyph_row *row, 
const Emacs_Rectangle *r,
 
   if (area == TEXT_AREA && row->fill_line_p)
     /* If row extends face to end of line write the whole line.  */
-    draw_glyphs (w, 0, row, area,
+    draw_glyphs (w, row->x, row, area,
                 0, row->used[area],
                 DRAW_NORMAL_TEXT, 0);
   else

> So if in your case you get a glyph row with all the characters,
> including those which are scrolled out of the viewport, then something
> is wrong where the glyph row is prepared, not where it is displayed.
> Specifically, when the window is hscrolled, display_line is called
> again to produce the glyphs starting from the first visible glyph.
> Perhaps in this case the NS display machinery uses a stale glyph row,
> from before the hscrolling?

I’m 100% sure the NS code is being passed bad coordinates.

This isn’t just a problem when scrolling to the end of the line. If
the window is horizontally scrolled and you move the cursor onto
another line, the line that was previously wrong corrects itself and
the line with the pointer on it now draws wrong. So it’s possible to
move the pointer between two lines and have them jump left and right.

Also the incorrectly drawn line doesn’t necessarily match any
previously displayed line. If we had some cached glyph row I wouldn’t
expect that to happen.

-- 
Alan Third





reply via email to

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