Subject: Re: bug#13011: 24.2; Text flickering moving cursor with box around text enabled

From: Eli Zaretskii <[email-masked]>
Date: Thu, 29 Nov 2012 18:42:47 +0200

> From: Stefan Monnier <[email-masked]>
> Cc: mario giovinazzo <[email-masked]>,  [email-masked]
> Date: Wed, 28 Nov 2012 23:39:04 -0500
> 
> When the box width is 1, indeed, there's no much Emacs could do, but
> when the width is -1 (i.e. drawn "inside" the normal text box),
> characters shouldn't move, whereas they do (they get shifted
> horizontally by a few pixels, and if you try it in the *Help* buffer
> you may see that the number of pixel shifts seems to increase at
> transition points between different fonts, such as italics for function
> arguments).

Looks like this was done on (some) purpose:

In xdisp.c:

	  /* If face has a box, add the box thickness to the character
	     height.  If character has a box line to the left and/or
	     right, add the box line width to the character's width.  */
	  if (face->box != FACE_NO_BOX)
	    {
	      int thick = face->box_line_width;

	      if (thick > 0)
		{
		  it->ascent += thick;
		  it->descent += thick;
		}
	      else
		thick = -thick;   <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

	      if (it->start_of_box_run_p)
		it->pixel_width += thick;  <<<<<<<<<<<<<<<<<<<<<<<<<
	      if (it->end_of_box_run_p)
		it->pixel_width += thick;
	    }

Note that the ascent and descent are only enlarged when the value is
positive, but pixel_width is also enlarged when the value is negative.

And then in xterm.c:

  /* If first glyph of S has a left box line, start drawing the text
     of S to the right of that box line.  */
  if (s->face->box != FACE_NO_BOX
      && s->first_glyph->left_box_line_p)
    x = s->x + eabs (s->face->box_line_width);  <<<<<<<<<<<<<<<<<<<<
  else         ^^^^
    x = s->x;

Moreover, the commentary in dispextern.h explicitly says that the
left/right borders are not affected by the sign of the box width (note
the last sentence):

  /* Non-zero means characters in this face have a box of that
     thickness around them.  If this value is negative, its absolute
     value indicates the thickness, and the horizontal (top and
     bottom) borders of box are drawn inside of the character glyphs'
     area.  The vertical (left and right) borders of the box are drawn
     in the same way as when this value is positive.  */
  int box_line_width;

and the doc string in faces.el only mentions the top and bottom borders
of the box as being affected by negative values:

  `:box'

  VALUE specifies whether characters in FACE should have a box drawn
  around them.  If VALUE is nil, explicitly don't draw boxes.  If
  VALUE is t, draw a box with lines of width 1 in the foreground color
  of the face.  If VALUE is a string, the string must be a color name,
  and the box is drawn in that color with a line width of 1.  Otherwise,
  VALUE must be a property list of the form `(:line-width WIDTH
  :color COLOR :style STYLE)'.  If a keyword/value pair is missing from
  the property list, a default value will be used for the value, as
  specified below.  WIDTH specifies the width of the lines to draw; it
  defaults to 1.  If WIDTH is negative, the absolute value is the width
  of the lines, and draw top/bottom lines inside the characters area,
  not around it.

Only the ELisp manual makes it sound like both horizontal and vertical
borders are drawn inside the character cell:

    `(:line-width WIDTH :color COLOR :style STYLE)'
          This way you can explicitly specify all aspects of the box.
          The value WIDTH specifies the width of the lines to draw; it
          defaults to 1.  A negative width -N means to draw a line of
          width N that occupies the space of the underlying text, thus
          avoiding any increase in the character height or width.

I made a provisional change that behaves with left and right borders
like it does with horizontal ones, and it seems to work, at least with
character display (didn't text with images, image slices, composite
characters, etc.).  But I'd like to ask Handa-san (CC'ed), who wrote
the code for this feature (almost 12 years ago!), whether he might
remember why the code deliberately makes the left and right borders
behave differently from top and bottom ones.

To see the original changeset that introduced this feature, type

   bzr diff -r 36005..36010