Subject: bug#50660: 28.0.50; Text artifacting when the cursor moves over text under mouse face that originally displayed a box

From: Po Lu <[email-masked]>
Date: Mon, 20 Sep 2021 19:08:13 +0800

Eli Zaretskii <[email-masked]> writes:

> Specifically, I now think the adjustment should happen in this
> fragment from show_mouse_face, before we call display_and_set_cursor:

Thanks, but I already cooked something up.  The adjustment, in my case,
is done in draw_phys_cursor_glyph, conditional on
cursor_in_mouse_face_p.

Is there anything wrong with this approach?  Thanks.
diff --git a/src/xdisp.c b/src/xdisp.c
index 2e72f6b591..ca6b98155a 100644
--- a/src/xdisp.c
+++ b/src/xdisp.c
@@ -31696,7 +31696,69 @@ draw_phys_cursor_glyph (struct window *w, struct glyph_row *row,
       bool on_p = w->phys_cursor_on_p;
       int x1;
       int hpos = w->phys_cursor.hpos;
+      int mouse_off = 0;
+#ifdef HAVE_WINDOW_SYSTEM
+      if (cursor_in_mouse_face_p (w))
+	{
+	  struct frame *f = WINDOW_XFRAME (w);
+	  Mouse_HLInfo *hlinfo = MOUSE_HL_INFO (f);
+	  struct glyph *start, *end;
+	  struct face *mouse_face = FACE_FROM_ID (f, hlinfo->mouse_face_face_id);
+	  end = &row->glyphs[TEXT_AREA][hpos];
+
+	  if (MATRIX_ROW_VPOS (row, w->current_matrix) ==
+	      hlinfo->mouse_face_beg_row)
+	    start = &row->glyphs[TEXT_AREA][hlinfo->mouse_face_beg_col];
+	  else
+	    start = row->glyphs[TEXT_AREA];
+
+	  /* Calculate an offset to correct phys_cursor x if we are
+	     drawing the cursor in the mouse face. */
+
+	  for (; start <= end; ++start)
+	    {
+	      struct glyph *g = start;
+	      struct face *mouse = mouse_face;
+	      struct face *regular_face = FACE_FROM_ID (f, g->face_id);
+
+	      bool do_left_box_p = g->left_box_line_p;
+	      bool do_right_box_p = g->right_box_line_p;
 
+	      if (row->reversed_p && g->type == IMAGE_GLYPH)
+		{
+		  struct image *img = IMAGE_FROM_ID (WINDOW_XFRAME (w),
+						     g->u.img_id);
+		  do_left_box_p = g->right_box_line_p &&
+		    g->slice.img.x + g->slice.img.width == img->width;
+		  do_right_box_p = g->left_box_line_p &&
+		    g->slice.img.x == 0;
+		}
+	      else if (g->type == IMAGE_GLYPH)
+		{
+		  struct image *img = IMAGE_FROM_ID (WINDOW_XFRAME (w),
+						     g->u.img_id);
+		  do_left_box_p = g->left_box_line_p &&
+		    g->slice.img.x + g->slice.img.width == img->width;
+		  do_right_box_p = g->right_box_line_p &&
+		    g->slice.img.x == 0;
+		}
+
+	      /* If the glyph has a left box line, subtract it the
+		 offset. */
+	      if (do_left_box_p)
+		mouse_off -= max (0, regular_face->box_vertical_line_width);
+	      /* Likewise with the right box line, as there may be a
+		 box there as well. */
+	      if (do_right_box_p)
+		mouse_off -= max (0, regular_face->box_vertical_line_width);
+	      /* Now we add the line widths from the new face. */
+	      if (g->left_box_line_p)
+		mouse_off += max (0, mouse->box_vertical_line_width);
+	      if (g->right_box_line_p)
+	        mouse_off += max (0, mouse->box_vertical_line_width);
+	    }
+	}
+#endif
       /* When the window is hscrolled, cursor hpos can legitimately be
 	 out of bounds, but we draw the cursor at the corresponding
 	 window margin in that case.  */
@@ -31705,7 +31767,8 @@ draw_phys_cursor_glyph (struct window *w, struct glyph_row *row,
       if (row->reversed_p && hpos >= row->used[TEXT_AREA])
 	hpos = row->used[TEXT_AREA] - 1;
 
-      x1 = draw_glyphs (w, w->phys_cursor.x, row, TEXT_AREA, hpos, hpos + 1,
+      x1 = draw_glyphs (w, w->phys_cursor.x + mouse_off,
+			row, TEXT_AREA, hpos, hpos + 1,
 			hl, 0);
       w->phys_cursor_on_p = on_p;