From: Po Lu Date: Tue, 26 Sep 2023 01:30:04 +0000 (+0800) Subject: Properly clip overlaid fringe bitmaps X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=50281b4007062533ca18f98deeac6b7d923d1922;p=emacs.git Properly clip overlaid fringe bitmaps * src/xterm.c (x_draw_fringe_bitmap): Save clip rectangle from x_clip_to_row, and draw only the intersection between it and the fringe bitmap, for if the bitmap is overlaid, the clip mask will override the clip rectangle. (x_clip_to_row): New argument *RECT_RETURN. All callers changed. --- diff --git a/src/xterm.c b/src/xterm.c index bd779cb21bf..33e12d48912 100644 --- a/src/xterm.c +++ b/src/xterm.c @@ -1167,7 +1167,7 @@ static struct terminal *x_create_terminal (struct x_display_info *); static void x_frame_rehighlight (struct x_display_info *); static void x_clip_to_row (struct window *, struct glyph_row *, - enum glyph_row_area, GC); + enum glyph_row_area, GC, XRectangle *); static struct scroll_bar *x_window_to_scroll_bar (Display *, Window, int); static struct frame *x_window_to_frame (struct x_display_info *, int); static void x_scroll_bar_report_motion (struct frame **, Lisp_Object *, @@ -7842,9 +7842,10 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, Display *display = FRAME_X_DISPLAY (f); GC gc = f->output_data.x->normal_gc; struct face *face = p->face; + XRectangle clip_rect; /* Must clip because of partially visible lines. */ - x_clip_to_row (w, row, ANY_AREA, gc); + x_clip_to_row (w, row, ANY_AREA, gc, &clip_rect); if (p->bx >= 0 && !p->overlay_p) { @@ -7914,6 +7915,30 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, memset (&attrs, 0, sizeof attrs); #endif + XRectangle image_rect, dest; + int window_x, window_y, window_width; + int px, py, pwidth, pheight; + + /* Intersect the destination rectangle with that of the row. + Setting a clip mask overrides the clip rectangles provided by + x_clip_to_row, so clipping must be performed by hand. */ + + image_rect.x = p->x; + image_rect.y = p->y; + image_rect.width = p->wd; + image_rect.height = p->h; + + if (!gui_intersect_rectangles (&clip_rect, &image_rect, &dest)) + /* The entire destination rectangle falls outside the row. */ + goto undo_clip; + + /* Extrapolate the source rectangle from the difference between + the destination and image rectangles. */ + + px = dest.x - image_rect.x; + py = dest.y - image_rect.y; + pwidth = dest.width; + pheight = dest.height; if (p->wd > 8) bits = (char *) (p->bits + p->dh); @@ -7985,15 +8010,16 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, x_xr_apply_ext_clip (f, gc); XRenderComposite (display, PictOpSrc, picture, None, FRAME_X_PICTURE (f), - 0, 0, 0, 0, p->x, p->y, p->wd, p->h); + px, py, px, py, dest.x, dest.y, + pwidth, pheight); x_xr_reset_ext_clip (f); XRenderFreePicture (display, picture); } else #endif - XCopyArea (display, pixmap, drawable, gc, 0, 0, - p->wd, p->h, p->x, p->y); + XCopyArea (display, pixmap, drawable, gc, px, py, + pwidth, pheight, dest.x, dest.y); XFreePixmap (display, pixmap); if (p->overlay_p) @@ -8003,6 +8029,8 @@ x_draw_fringe_bitmap (struct window *w, struct glyph_row *row, XFreePixmap (display, clipmask); } } + + undo_clip: #endif /* not USE_CAIRO */ x_reset_clip_rectangles (f, gc); @@ -25646,13 +25674,17 @@ XTread_socket (struct terminal *terminal, struct input_event *hold_quit) /* Set clipping for output in glyph row ROW. W is the window in which we operate. GC is the graphics context to set clipping in. + If RECT_RETURN is non-NULL, return the clip rectangle within + *RECT_RETURN. + ROW may be a text row or, e.g., a mode line. Text rows must be clipped to the interior of the window dedicated to text display, mode lines must be clipped to the whole window. */ static void x_clip_to_row (struct window *w, struct glyph_row *row, - enum glyph_row_area area, GC gc) + enum glyph_row_area area, GC gc, + XRectangle *rect_return) { struct frame *f = XFRAME (WINDOW_FRAME (w)); XRectangle clip_rect; @@ -25667,6 +25699,9 @@ x_clip_to_row (struct window *w, struct glyph_row *row, clip_rect.height = row->visible_height; x_set_clip_rectangles (f, gc, &clip_rect, 1); + + if (rect_return) + *rect_return = clip_rect; } @@ -25715,7 +25750,7 @@ x_draw_hollow_cursor (struct window *w, struct glyph_row *row) wd -= 1; } /* Set clipping, draw the rectangle, and reset clipping again. */ - x_clip_to_row (w, row, TEXT_AREA, gc); + x_clip_to_row (w, row, TEXT_AREA, gc, NULL); x_draw_rectangle (f, gc, x, y, wd, h - 1); x_reset_clip_rectangles (f, gc); } @@ -25785,7 +25820,7 @@ x_draw_bar_cursor (struct window *w, struct glyph_row *row, int width, enum text FRAME_DISPLAY_INFO (f)->scratch_cursor_gc = gc; } - x_clip_to_row (w, row, TEXT_AREA, gc); + x_clip_to_row (w, row, TEXT_AREA, gc, NULL); if (kind == BAR_CURSOR) {