Subject: bug#30226: Fixing it->pixel_width / it->current_x when tabs and line numbers.

From: Keith David Bershatsky <[email-masked]>
Date: Sun, 28 Jan 2018 11:52:48 -0800

> Bottom line: to get accurate values of pixel width, you need to
> subtract it->current_x value at some position from current_x at the
> next glyph position.  This is the only reliable way to obtain accurate
> pixel width values when using the move_it_* functions.

Thank you, Eli, for the detailed explanation regarding what is happening underneath the Emacs hood.  The "bottom line" method does not seem to be working in this example to calculate the tab STRETCH because it.current_x of the character that _follows_ the tab STRETCH is wrong when w->hscroll >= 2.  In the revised bug-30226 function below:  When w->hscroll >= 2, we take the it.current_x of the letter "H" in "Hello-world" (which is ostensibly 84); and, we subtract (it.first_visible_x + it.lnum_pixel_width).  This gives us a purported tab STRETCH of 42; however, it should really be 35.

A.  This is the first (1st) time we call the revised bug-30226 [w->hscroll == 1]:

1.  NOTHING
    it.c (0)
    w->hscroll (1)
    it.current_x (0)
    it.pixel_width (0)

2.  TAB CHARACTER
    it.c (187)
    w->hscroll (1)
    it.current_x (0)
    it.pixel_width (7)

3.  TAB STRETCH
    it.c (9)
    w->hscroll (1)
    it.current_x (7)
    it.pixel_width (49)

"Bottom Line" method -- pixel-width of tab STRETCH:  0

4.  TAB STRETCH
    it.c (9)
    w->hscroll (1)
    it.current_x (35)
    it.pixel_width (42)

"Bottom Line" method -- pixel-width of tab STRETCH:  42

5.  TEXT
    it.c (72)
    w->hscroll (1)
    it.current_x (77)
    it.pixel_width (7)

* * *

Row     Start       End Used oE><\CTZFesm     X    Y    W    H    V    A    P
==============================================================================
 12       455       467   17 111000110000     0  192  154   16   16   12   12
           -1        -1	    0
           -1        -1
           -1        -1
 Glyph#  Type       Pos   O   W     Code      C Face LR
      0     C        -1   0   7 0x000020          29 00
      1     C        -1   0   7 0x000031      1   29 00
      2     C        -1   0   7 0x000033      3   29 00
      3     C        -1   0   7 0x000020          29 00
      4     S       455   B  42 0x000000          31 00
      5     C       456   B   7 0x000048      H    0 00
      6     C       457   B   7 0x000065      e    0 00
      7     C       458   B   7 0x00006c      l    0 00
      8     C       459   B   7 0x00006c      l    0 00
      9     C       460   B   7 0x00006f      o    0 00
     10     C       461   B   7 0x00002d      -    0 00
     11     C       462   B   7 0x000077      w    0 00
     12     C       463   B   7 0x00006f      o    0 00
     13     C       464   B   7 0x000072      r    0 00
     14     C       465   B   7 0x00006c      l    0 00
     15     C       466   B   7 0x000064      d    0 00
     16     C         0   0   7 0x000020           0 00

B.  This is the second (2nd) time we call the revised bug-30226 [w->hscroll == 2]:

1.  NOTHING
    it.c (0)
    w->hscroll (2)
    it.current_x (0)
    it.pixel_width (0)

2.  TAB CHARACTER
    it.c (187)
    w->hscroll (2)
    it.current_x (0)
    it.pixel_width (7)

3.  TAB STRETCH
    it.c (9)
    w->hscroll (2)
    it.current_x (7)
    it.pixel_width (49)

"Bottom Line" method -- pixel-width of tab STRETCH:  42

4.  TEXT
    it.c (72)
    w->hscroll (2)
    it.current_x (84)
    it.pixel_width (7)

* * * 

Row     Start       End Used oE><\CTZFesm     X    Y    W    H    V    A    P
==============================================================================
 12       455       467   17 111000110000     0  192  147   16   16   12   12
           -1        -1	    0
           -1        -1
           -1        -1
 Glyph#  Type       Pos   O   W     Code      C Face LR
      0     C        -1   0   7 0x000020          29 00
      1     C        -1   0   7 0x000031      1   29 00
      2     C        -1   0   7 0x000033      3   29 00
      3     C        -1   0   7 0x000020          29 00
      4     S       455   B  35 0x000000          31 00
      5     C       456   B   7 0x000048      H    0 00
      6     C       457   B   7 0x000065      e    0 00
      7     C       458   B   7 0x00006c      l    0 00
      8     C       459   B   7 0x00006c      l    0 00
      9     C       460   B   7 0x00006f      o    0 00
     10     C       461   B   7 0x00002d      -    0 00
     11     C       462   B   7 0x000077      w    0 00
     12     C       463   B   7 0x00006f      o    0 00
     13     C       464   B   7 0x000072      r    0 00
     14     C       465   B   7 0x00006c      l    0 00
     15     C       466   B   7 0x000064      d    0 00
     16     C         0   0   7 0x000020           0 00

DEFUN ("bug-30226", Fbug_30226, Sbug_30226, 0, 0, 0,
       doc: /* Debug the pixel-width of a stretch tab. */)
  (void)
{
  Fscroll_left (make_number (1), Qnil);
  struct window *w = decode_live_window (selected_window);
  struct frame *f = XFRAME (w->frame);
  struct it it;
  void *itdata = bidi_shelve_cache ();
  enum move_it_result rc = MOVE_X_REACHED;
  struct text_pos start_text_position;
  int count = 1;
  int previous_character = 0;
/* ******************************************************************************
                      START DISPLAY -- w->start
****************************************************************************** */
  /* Begin the journey at w->start. */
  SET_TEXT_POS_FROM_MARKER (start_text_position, w->start);
  start_display (&it, w, start_text_position);
  struct face *face = FACE_FROM_ID (it.f, it.face_id);
  struct font *font = face->font;
/* ******************************************************************************
                GO TO THE BEGINNING OF THE CURRENT LINE.
****************************************************************************** */
  /* Place the IT on the current line containing PT. */
  int voffset = (WINDOW_HEADER_LINE_HEIGHT (w) > 0
                 && w->output_cursor.vpos > 0)
                  ? w->output_cursor.vpos - 1
                  : w->output_cursor.vpos;
  if (voffset > 0)
    move_it_by_lines (&it, voffset);
/* ******************************************************************************
             MOVE IT OVER EACH CHARACTER ON THE CURRENT LINE.
****************************************************************************** */
  while (true)
    {
      if (ITERATOR_AT_END_OF_LINE_P (&it)
          || FETCH_BYTE (IT_BYTEPOS (it)) == '\n'
          || rc == MOVE_POS_MATCH_OR_ZV)
        break;
/* ******************************************************************************
                     HYPOTHETICAL CALCULATION OF PIXEL-WIDTH
****************************************************************************** */
      if (w->hscroll > 0
          && previous_character == '\t')
       fprintf (stderr, "\n\"Bottom Line\" method -- pixel-width of tab STRETCH:  %d\n",
                it.current_x - (it.first_visible_x + it.lnum_pixel_width));
/* ******************************************************************************
                       DUMP RELEVANT GLYPH INFORMATION
****************************************************************************** */
      if (w->hscroll > 0)
        {
          int w_hscroll = w->hscroll;
          fprintf (stderr, "\n%d.  %s\n\
    it.c (%d)\n\
    w->hscroll (%d)\n\
    it.current_x (%d)\n\
    it.pixel_width (%d)\n",
                 count,
                 (it.c == 0
                   ? "NOTHING"
                   : it.c == 187
                     ? "TAB CHARACTER"
                   : it.c == '\t'
                     ? "TAB STRETCH"
                   : "TEXT"),
                 it.c,
                 w_hscroll,
                 it.current_x,
                 it.pixel_width);
        }
/* ******************************************************************************
                       MOVE IT -- INCREMENT == IT.PIXEL_WIDTH 
****************************************************************************** */
      previous_character = it.c;
      rc = move_it_in_display_line_to (&it, ZV, it.current_x + it.pixel_width,
                                       MOVE_TO_POS | MOVE_TO_X);
      count = count + 1;
      if (rc == MOVE_LINE_CONTINUED)
        break;
      if (it.current_x - it.first_visible_x + font->space_width >=
          window_box_width (w, TEXT_AREA))
        break;
    }
/* ******************************************************************************
                         REDISPLAY AND DUMP_GLPYH_ROW
****************************************************************************** */
  redisplay_internal ();
  fprintf (stderr, "\n");
  struct glyph_row *glyph_row = MATRIX_ROW (w->current_matrix, it.vpos);
  dump_glyph_row (glyph_row, it.vpos, 2);
  bidi_unshelve_cache (itdata, false);
  return Qnil;
}