Antialiased corners

Use a specially constructed cairo overlay to give us fully anti-aliased
corners on the mask texture.

https://bugzilla.gnome.org/show_bug.cgi?id=628195
This commit is contained in:
Jasper St. Pierre 2011-08-10 10:32:47 -04:00
parent 49a3fd53b0
commit dcfa6986c6

View File

@ -2,7 +2,6 @@
#include <config.h> #include <config.h>
#define _ISOC99_SOURCE /* for roundf */
#include <math.h> #include <math.h>
#include <X11/extensions/shape.h> #include <X11/extensions/shape.h>
@ -1697,13 +1696,8 @@ meta_window_actor_set_visible_region (MetaWindowActor *self,
/* Get the area of the window texture that would be drawn if /* Get the area of the window texture that would be drawn if
* we weren't obscured at all * we weren't obscured at all
*/ */
if (priv->shape_region) texture_clip_region = meta_shaped_texture_get_visible_pixels_region (META_SHAPED_TEXTURE (priv->actor));
texture_clip_region = cairo_region_copy (priv->shape_region); texture_clip_region = cairo_region_copy (texture_clip_region);
else if (priv->bounding_region)
texture_clip_region = cairo_region_copy (priv->bounding_region);
if (!texture_clip_region)
texture_clip_region = cairo_region_create ();
/* Then intersect that with the visible region to get the region /* Then intersect that with the visible region to get the region
* that we actually need to redraw. * that we actually need to redraw.
@ -1993,12 +1987,120 @@ meta_window_actor_sync_visibility (MetaWindowActor *self)
} }
} }
static inline void
set_integral_bounding_rect (cairo_rectangle_int_t *rect,
double x, double y,
double width, double height)
{
rect->x = floor(x);
rect->y = floor(y);
rect->width = ceil(x + width) - rect->x;
rect->height = ceil(y + height) - rect->y;
}
static void
update_corners (MetaWindowActor *self,
MetaFrameBorders *borders)
{
MetaWindowActorPrivate *priv = self->priv;
MetaRectangle outer;
cairo_rectangle_int_t corner_rects[4];
cairo_region_t *corner_region;
cairo_path_t *corner_path;
float top_left, top_right, bottom_left, bottom_right;
/* need these to build a path */
cairo_t *cr;
cairo_surface_t *surface;
if (!priv->window->frame)
return;
meta_window_get_outer_rect (priv->window, &outer);
meta_frame_get_corner_radiuses (priv->window->frame,
&top_left,
&top_right,
&bottom_left,
&bottom_right);
/* Unfortunately, cairo does not allow us to create a context
* without a surface. Create a 0x0 image surface to "paint to"
* so we can get the path. */
surface = cairo_image_surface_create (CAIRO_FORMAT_A8,
0, 0);
cr = cairo_create (surface);
/* top left */
set_integral_bounding_rect (&corner_rects[0],
borders->invisible.left,
borders->invisible.top,
top_left, top_left);
cairo_arc (cr,
corner_rects[0].x + top_left,
corner_rects[0].y + top_left,
top_left,
0, M_PI*2);
/* top right */
set_integral_bounding_rect (&corner_rects[1],
borders->invisible.left + outer.width - top_right,
borders->invisible.top,
top_right, top_right);
cairo_arc (cr,
corner_rects[1].x,
corner_rects[1].y + top_right,
top_right,
0, M_PI*2);
/* bottom left */
set_integral_bounding_rect (&corner_rects[2],
borders->invisible.left,
borders->invisible.top + outer.height - bottom_left,
bottom_left, bottom_left);
cairo_arc (cr,
corner_rects[2].x + bottom_left,
corner_rects[2].y,
bottom_left,
0, M_PI*2);
/* bottom right */
set_integral_bounding_rect (&corner_rects[3],
borders->invisible.left + outer.width - bottom_right,
borders->invisible.top + outer.height - bottom_right,
bottom_right, bottom_right);
cairo_arc (cr,
corner_rects[3].x,
corner_rects[3].y,
bottom_right,
0, M_PI*2);
corner_path = cairo_copy_path (cr);
cairo_surface_destroy (surface);
cairo_destroy (cr);
corner_region = cairo_region_create_rectangles (corner_rects, 4);
meta_shaped_texture_set_overlay_path (META_SHAPED_TEXTURE (priv->actor),
corner_region, corner_path);
cairo_region_destroy (corner_region);
}
static void static void
check_needs_reshape (MetaWindowActor *self) check_needs_reshape (MetaWindowActor *self)
{ {
MetaWindowActorPrivate *priv = self->priv; MetaWindowActorPrivate *priv = self->priv;
MetaScreen *screen = priv->screen; MetaScreen *screen = priv->screen;
MetaDisplay *display = meta_screen_get_display (screen); MetaDisplay *display = meta_screen_get_display (screen);
MetaFrameBorders borders;
cairo_region_t *region; cairo_region_t *region;
if (!priv->needs_reshape) if (!priv->needs_reshape)
@ -2007,6 +2109,9 @@ check_needs_reshape (MetaWindowActor *self)
meta_shaped_texture_set_shape_region (META_SHAPED_TEXTURE (priv->actor), NULL); meta_shaped_texture_set_shape_region (META_SHAPED_TEXTURE (priv->actor), NULL);
meta_window_actor_clear_shape_region (self); meta_window_actor_clear_shape_region (self);
if (priv->window->frame)
meta_frame_calc_borders (priv->window->frame, &borders);
region = meta_window_get_frame_bounds (priv->window); region = meta_window_get_frame_bounds (priv->window);
if (region != NULL) if (region != NULL)
{ {
@ -2034,9 +2139,6 @@ check_needs_reshape (MetaWindowActor *self)
if (priv->window->frame) if (priv->window->frame)
{ {
MetaFrameBorders borders;
meta_frame_calc_borders (priv->window->frame, &borders);
client_area.x = borders.total.left; client_area.x = borders.total.left;
client_area.y = borders.total.top; client_area.y = borders.total.top;
} }
@ -2080,6 +2182,8 @@ check_needs_reshape (MetaWindowActor *self)
cairo_region_destroy (region); cairo_region_destroy (region);
update_corners (self, &borders);
priv->needs_reshape = FALSE; priv->needs_reshape = FALSE;
meta_window_actor_invalidate_shadow (self); meta_window_actor_invalidate_shadow (self);
} }