mirror of
				https://github.com/yshui/picom.git
				synced 2025-10-30 23:46:46 -04:00 
			
		
		
		
	renderer/command_builder: fix masking of rounded window body for shadows
If `full_shadow = false`, we mask out window body when rendering shadows. For rounded windows, we remove a corner_radius sized rectangles from the four corners of the window body. But we forgot to take into account the scaling factor of the window when removing these corners. Related: #1389 (partial fix) Changelog: BugFix: Fix shadow not being correctly masked when scaled. Signed-off-by: Yuxuan Shui <yshuiv7@gmail.com>
This commit is contained in:
		
							parent
							
								
									1b78521bac
								
							
						
					
					
						commit
						4715498b20
					
				
					 3 changed files with 25 additions and 55 deletions
				
			
		| 
						 | 
				
			
			@ -51,7 +51,10 @@ commands_for_window_body(struct layer *layer, struct backend_command *cmd_base,
 | 
			
		|||
		}
 | 
			
		||||
	}
 | 
			
		||||
	if (layer->options.corner_radius > 0) {
 | 
			
		||||
		win_region_remove_corners(w, layer->window.origin, &cmd->opaque_region);
 | 
			
		||||
		// Scale is applied below, by region_scale.
 | 
			
		||||
		win_remove_region_corners(layer->window.size, SCALE_IDENTITY,
 | 
			
		||||
		                          (int)layer->options.corner_radius,
 | 
			
		||||
		                          layer->window.origin, &cmd->opaque_region);
 | 
			
		||||
	}
 | 
			
		||||
	struct shader_info *shader = NULL;
 | 
			
		||||
	if (layer->options.shader != NULL) {
 | 
			
		||||
| 
						 | 
				
			
			@ -188,8 +191,9 @@ command_for_shadow(struct layer *layer, struct backend_command *cmd,
 | 
			
		|||
				region_t mask_without_corners;
 | 
			
		||||
				pixman_region32_init(&mask_without_corners);
 | 
			
		||||
				pixman_region32_copy(&mask_without_corners, &j->target_mask);
 | 
			
		||||
				win_region_remove_corners(layer->win, j->origin,
 | 
			
		||||
				                          &mask_without_corners);
 | 
			
		||||
				win_remove_region_corners(layer->window.size, layer->scale,
 | 
			
		||||
				                          (int)layer->options.corner_radius,
 | 
			
		||||
				                          j->origin, &mask_without_corners);
 | 
			
		||||
				pixman_region32_subtract(&cmd->target_mask, &cmd->target_mask,
 | 
			
		||||
				                         &mask_without_corners);
 | 
			
		||||
				pixman_region32_fini(&mask_without_corners);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										21
									
								
								src/wm/win.c
									
										
									
									
									
								
							
							
						
						
									
										21
									
								
								src/wm/win.c
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -130,27 +130,6 @@ static void win_get_region_local(const struct win *w, region_t *res) {
 | 
			
		|||
	pixman_region32_init_rect(res, 0, 0, (uint)w->widthb, (uint)w->heightb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Get a rectangular region a window occupies, excluding frame and shadow.
 | 
			
		||||
 */
 | 
			
		||||
void win_get_region_noframe_local(const struct win *w, region_t *res) {
 | 
			
		||||
	const margin_t extents = win_calc_frame_extents(w);
 | 
			
		||||
 | 
			
		||||
	int x = extents.left;
 | 
			
		||||
	int y = extents.top;
 | 
			
		||||
	int width = max2(w->widthb - (extents.left + extents.right), 0);
 | 
			
		||||
	int height = max2(w->heightb - (extents.top + extents.bottom), 0);
 | 
			
		||||
 | 
			
		||||
	pixman_region32_fini(res);
 | 
			
		||||
	if (width > 0 && height > 0) {
 | 
			
		||||
		pixman_region32_init_rect(res, x, y, (uint)width, (uint)height);
 | 
			
		||||
	} else {
 | 
			
		||||
		pixman_region32_init(res);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
gen_without_corners(win_get_region_noframe_local);
 | 
			
		||||
 | 
			
		||||
void win_get_region_frame_local(const struct win *w, region_t *res) {
 | 
			
		||||
	const margin_t extents = win_calc_frame_extents(w);
 | 
			
		||||
	auto outer_width = w->widthb;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										49
									
								
								src/wm/win.h
									
										
									
									
									
								
							
							
						
						
									
										49
									
								
								src/wm/win.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -436,13 +436,6 @@ bool win_is_bypassing_compositor(const session_t *ps, const struct win *w);
 | 
			
		|||
 */
 | 
			
		||||
void win_extents(const struct win *w, region_t *res);
 | 
			
		||||
region_t win_extents_by_val(const struct win *w);
 | 
			
		||||
/**
 | 
			
		||||
 * Get a rectangular region a window occupies, excluding frame and shadow.
 | 
			
		||||
 *
 | 
			
		||||
 * Return region in global coordinates.
 | 
			
		||||
 */
 | 
			
		||||
void win_get_region_noframe_local(const struct win *w, region_t *);
 | 
			
		||||
void win_get_region_noframe_local_without_corners(const struct win *w, region_t *);
 | 
			
		||||
 | 
			
		||||
/// Get the region for the frame of the window
 | 
			
		||||
void win_get_region_frame_local(const struct win *w, region_t *res);
 | 
			
		||||
| 
						 | 
				
			
			@ -552,25 +545,33 @@ static inline attr_unused void win_set_property_stale(struct win *w, xcb_atom_t
 | 
			
		|||
/// Free all resources in a struct win
 | 
			
		||||
void free_win_res(session_t *ps, struct win *w);
 | 
			
		||||
 | 
			
		||||
/// Remove the corners of window `w` from region `res`. `origin` is the top-left corner of
 | 
			
		||||
/// `w` in `res`'s coordinate system.
 | 
			
		||||
static inline void
 | 
			
		||||
win_region_remove_corners(const struct win *w, ivec2 origin, region_t *res) {
 | 
			
		||||
	static const int corner_index[][2] = {
 | 
			
		||||
/// Remove the corners of a scaled, rounded rectangle from region `res`. `origin` is the
 | 
			
		||||
/// top-left corner of the rectangle in `res`'s coordinate system. `size` is the size of
 | 
			
		||||
/// the rectangle, `scale` is the scaling factor. `corner_radius` is the _unscaled_ radius
 | 
			
		||||
/// of the rounded corners. The top-left corner of the rectangle is the scaling origin.
 | 
			
		||||
static inline void win_remove_region_corners(ivec2 size, vec2 scale, int corner_radius,
 | 
			
		||||
                                             ivec2 origin, region_t *res) {
 | 
			
		||||
	static const struct {
 | 
			
		||||
		int x, y;
 | 
			
		||||
	} corner_index[] = {
 | 
			
		||||
	    {0, 0},
 | 
			
		||||
	    {0, 1},
 | 
			
		||||
	    {1, 0},
 | 
			
		||||
	    {1, 1},
 | 
			
		||||
	};
 | 
			
		||||
	int corner_radius = (int)win_options(w).corner_radius;
 | 
			
		||||
	rect_t rectangles[4];
 | 
			
		||||
	for (size_t i = 0; i < ARR_SIZE(corner_index); i++) {
 | 
			
		||||
		double x1 = origin.x +
 | 
			
		||||
		            corner_index[i].x * (size.width - corner_radius) * scale.x,
 | 
			
		||||
		       y1 = origin.y +
 | 
			
		||||
		            corner_index[i].y * (size.height - corner_radius) * scale.y,
 | 
			
		||||
		       x2 = x1 + corner_radius * scale.x, y2 = y1 + corner_radius * scale.y;
 | 
			
		||||
		rectangles[i] = (rect_t){
 | 
			
		||||
		    .x1 = origin.x + corner_index[i][0] * (w->widthb - corner_radius),
 | 
			
		||||
		    .y1 = origin.y + corner_index[i][1] * (w->heightb - corner_radius),
 | 
			
		||||
		    .x1 = (int32_t)floor(x1),
 | 
			
		||||
		    .y1 = (int32_t)floor(y1),
 | 
			
		||||
		    .x2 = (int32_t)ceil(x2),
 | 
			
		||||
		    .y2 = (int32_t)ceil(y2),
 | 
			
		||||
		};
 | 
			
		||||
		rectangles[i].x2 = rectangles[i].x1 + corner_radius;
 | 
			
		||||
		rectangles[i].y2 = rectangles[i].y1 + corner_radius;
 | 
			
		||||
	}
 | 
			
		||||
	region_t corners;
 | 
			
		||||
	pixman_region32_init_rects(&corners, rectangles, 4);
 | 
			
		||||
| 
						 | 
				
			
			@ -578,11 +579,6 @@ win_region_remove_corners(const struct win *w, ivec2 origin, region_t *res) {
 | 
			
		|||
	pixman_region32_fini(&corners);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Like `win_region_remove_corners`, but `origin` is (0, 0).
 | 
			
		||||
static inline void win_region_remove_corners_local(const struct win *w, region_t *res) {
 | 
			
		||||
	win_region_remove_corners(w, (ivec2){0, 0}, res);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline region_t attr_unused win_get_bounding_shape_global_by_val(struct win *w) {
 | 
			
		||||
	region_t ret;
 | 
			
		||||
	pixman_region32_init(&ret);
 | 
			
		||||
| 
						 | 
				
			
			@ -591,15 +587,6 @@ static inline region_t attr_unused win_get_bounding_shape_global_by_val(struct w
 | 
			
		|||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline region_t win_get_bounding_shape_global_without_corners_by_val(struct win *w) {
 | 
			
		||||
	region_t ret;
 | 
			
		||||
	pixman_region32_init(&ret);
 | 
			
		||||
	pixman_region32_copy(&ret, &w->bounding_shape);
 | 
			
		||||
	win_region_remove_corners_local(w, &ret);
 | 
			
		||||
	pixman_region32_translate(&ret, w->g.x, w->g.y);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Calculate the extents of the frame of the given window based on EWMH
 | 
			
		||||
 * _NET_FRAME_EXTENTS and the X window border width.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue