From 8da12ac0e0547dacb53b07f95173bc9534841275 Mon Sep 17 00:00:00 2001 From: "Jasper St. Pierre" Date: Fri, 27 Apr 2012 00:14:42 -0400 Subject: [PATCH] window-actor: Punt mask generation to MetaWindowActor This effectively makes MetaShapedTexture not a MetaShapedTexture, but a simple and dumb MetaMaskedTexture, with an optimization for clipped regions. We're doing this as the mask may need to be more complicated than made of a region plus a "cairo overlay" -- we eventually want GTK+ to draw the rounded corner background. Save rounded corners for a later commit, again. --- src/compositor/meta-shaped-texture.c | 143 +++------------------------ src/compositor/meta-window-actor.c | 91 +++++++++++++++-- src/meta/meta-shaped-texture.h | 5 +- 3 files changed, 97 insertions(+), 142 deletions(-) diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index f560ac90c..3d1254f50 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -30,13 +30,11 @@ #include #include "meta-texture-tower.h" -#include "meta-texture-rectangle.h" #include #include #include #include /* for gdk_rectangle_intersect() */ -#include static void meta_shaped_texture_dispose (GObject *object); @@ -54,8 +52,6 @@ static void meta_shaped_texture_get_preferred_height (ClutterActor *self, gfloat *min_height_p, gfloat *natural_height_p); -static void meta_shaped_texture_dirty_mask (MetaShapedTexture *stex); - static gboolean meta_shaped_texture_get_paint_volume (ClutterActor *self, ClutterPaintVolume *volume); G_DEFINE_TYPE (MetaShapedTexture, meta_shaped_texture, @@ -75,10 +71,8 @@ struct _MetaShapedTexturePrivate CoglHandle material_unshaped; cairo_region_t *clip_region; - cairo_region_t *shape_region; guint tex_width, tex_height; - guint mask_width, mask_height; guint create_mipmaps : 1; }; @@ -107,7 +101,6 @@ meta_shaped_texture_init (MetaShapedTexture *self) priv = self->priv = META_SHAPED_TEXTURE_GET_PRIVATE (self); - priv->shape_region = NULL; priv->paint_tower = meta_texture_tower_new (); priv->texture = COGL_INVALID_HANDLE; priv->mask_texture = COGL_INVALID_HANDLE; @@ -124,8 +117,6 @@ meta_shaped_texture_dispose (GObject *object) meta_texture_tower_free (priv->paint_tower); priv->paint_tower = NULL; - meta_shaped_texture_dirty_mask (self); - if (priv->material != COGL_INVALID_HANDLE) { cogl_handle_unref (priv->material); @@ -142,118 +133,11 @@ meta_shaped_texture_dispose (GObject *object) priv->texture = COGL_INVALID_HANDLE; } - meta_shaped_texture_set_shape_region (self, NULL); meta_shaped_texture_set_clip_region (self, NULL); G_OBJECT_CLASS (meta_shaped_texture_parent_class)->dispose (object); } -static void -meta_shaped_texture_dirty_mask (MetaShapedTexture *stex) -{ - MetaShapedTexturePrivate *priv = stex->priv; - - if (priv->mask_texture != COGL_INVALID_HANDLE) - { - cogl_handle_unref (priv->mask_texture); - priv->mask_texture = COGL_INVALID_HANDLE; - } - - if (priv->material != COGL_INVALID_HANDLE) - cogl_material_set_layer (priv->material, 1, COGL_INVALID_HANDLE); -} - -static void -meta_shaped_texture_ensure_mask (MetaShapedTexture *stex) -{ - MetaShapedTexturePrivate *priv = stex->priv; - CoglHandle paint_tex; - guint tex_width, tex_height; - - paint_tex = priv->texture; - - if (paint_tex == COGL_INVALID_HANDLE) - return; - - tex_width = cogl_texture_get_width (paint_tex); - tex_height = cogl_texture_get_height (paint_tex); - - /* If the mask texture we have was created for a different size then - recreate it */ - if (priv->mask_texture != COGL_INVALID_HANDLE - && (priv->mask_width != tex_width || priv->mask_height != tex_height)) - meta_shaped_texture_dirty_mask (stex); - - /* If we don't have a mask texture yet then create one */ - if (priv->mask_texture == COGL_INVALID_HANDLE) - { - guchar *mask_data; - int i; - int n_rects; - int stride; - - /* If we have no shape region, we don't need to create - * a full mask texture, so quit early. */ - if (priv->shape_region == NULL) - return; - - stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, tex_width); - - /* Create data for an empty image */ - mask_data = g_malloc0 (stride * tex_height); - - n_rects = cairo_region_num_rectangles (priv->shape_region); - - /* Fill in each rectangle. */ - for (i = 0; i < n_rects; i ++) - { - cairo_rectangle_int_t rect; - cairo_region_get_rectangle (priv->shape_region, i, &rect); - - gint x1 = rect.x, x2 = x1 + rect.width; - gint y1 = rect.y, y2 = y1 + rect.height; - guchar *p; - - /* Clip the rectangle to the size of the texture */ - x1 = CLAMP (x1, 0, (gint) tex_width - 1); - x2 = CLAMP (x2, x1, (gint) tex_width); - y1 = CLAMP (y1, 0, (gint) tex_height - 1); - y2 = CLAMP (y2, y1, (gint) tex_height); - - /* Fill the rectangle */ - for (p = mask_data + y1 * stride + x1; - y1 < y2; - y1++, p += stride) - memset (p, 255, x2 - x1); - } - - if (meta_texture_rectangle_check (paint_tex)) - priv->mask_texture = meta_texture_rectangle_new (tex_width, tex_height, - COGL_PIXEL_FORMAT_A_8, - COGL_PIXEL_FORMAT_A_8, - stride, - mask_data, - NULL /* error */); - else - { - /* Note: we don't allow slicing for this texture because we - * need to use it with multi-texturing which doesn't support - * sliced textures */ - priv->mask_texture = cogl_texture_new_from_data (tex_width, tex_height, - COGL_TEXTURE_NO_SLICING, - COGL_PIXEL_FORMAT_A_8, - COGL_PIXEL_FORMAT_ANY, - stride, - mask_data); - } - - g_free (mask_data); - - priv->mask_width = tex_width; - priv->mask_height = tex_height; - } -} - static void meta_shaped_texture_paint (ClutterActor *actor) { @@ -303,9 +187,9 @@ meta_shaped_texture_paint (ClutterActor *actor) if (tex_width == 0 || tex_height == 0) /* no contents yet */ return; - if (priv->shape_region == NULL) + if (priv->mask_texture == COGL_INVALID_HANDLE) { - /* No region means an unclipped shape. Use a single-layer texture. */ + /* Use a single-layer texture if we don't have a mask. */ if (priv->material_unshaped == COGL_INVALID_HANDLE) { @@ -318,8 +202,6 @@ meta_shaped_texture_paint (ClutterActor *actor) } else { - meta_shaped_texture_ensure_mask (stex); - if (priv->material == COGL_INVALID_HANDLE) { if (G_UNLIKELY (material_template == COGL_INVALID_HANDLE)) @@ -410,7 +292,7 @@ meta_shaped_texture_pick (ClutterActor *actor, MetaShapedTexturePrivate *priv = stex->priv; /* If there is no region then use the regular pick */ - if (priv->shape_region == NULL) + if (priv->mask_texture == COGL_INVALID_HANDLE) CLUTTER_ACTOR_CLASS (meta_shaped_texture_parent_class) ->pick (actor, color); else if (clutter_actor_should_pick_paint (actor)) @@ -430,8 +312,6 @@ meta_shaped_texture_pick (ClutterActor *actor, if (tex_width == 0 || tex_height == 0) /* no contents yet */ return; - meta_shaped_texture_ensure_mask (stex); - cogl_set_source_color4ub (color->red, color->green, color->blue, color->alpha); @@ -522,8 +402,8 @@ meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex, } void -meta_shaped_texture_set_shape_region (MetaShapedTexture *stex, - cairo_region_t *region) +meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex, + CoglHandle mask_texture) { MetaShapedTexturePrivate *priv; @@ -531,19 +411,18 @@ meta_shaped_texture_set_shape_region (MetaShapedTexture *stex, priv = stex->priv; - if (priv->shape_region != NULL) + if (priv->mask_texture != COGL_INVALID_HANDLE) { - cairo_region_destroy (priv->shape_region); - priv->shape_region = NULL; + cogl_handle_unref (priv->mask_texture); + priv->mask_texture = COGL_INVALID_HANDLE; } - if (region != NULL) + if (mask_texture != COGL_INVALID_HANDLE) { - cairo_region_reference (region); - priv->shape_region = region; + priv->mask_texture = mask_texture; + cogl_handle_ref (priv->mask_texture); } - meta_shaped_texture_dirty_mask (stex); clutter_actor_queue_redraw (CLUTTER_ACTOR (stex)); } diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index 686e3c310..3b617932b 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -13,6 +13,7 @@ #define COGL_ENABLE_EXPERIMENTAL_API #include #include /* for gdk_rectangle_union() */ +#include #include #include @@ -24,6 +25,7 @@ #include "compositor-private.h" #include "meta-shadow-factory-private.h" #include "meta-window-actor-private.h" +#include "meta-texture-rectangle.h" enum { POSITION_CHANGED, @@ -1635,7 +1637,6 @@ meta_window_actor_update_shape_region (MetaWindowActor *self, /* region must be non-null */ priv->shape_region = region; - cairo_region_reference (region); /* Our "shape_region" is called the "bounding region" in the X Shape * Extension Documentation. @@ -1989,6 +1990,86 @@ meta_window_actor_sync_visibility (MetaWindowActor *self) } } +static void +static void +generate_mask (MetaWindowActor *self, + MetaFrameBorders *borders, + cairo_region_t *shape_region) +{ + MetaWindowActorPrivate *priv = self->priv; + guchar *mask_data; + guint tex_width, tex_height; + CoglHandle paint_tex, mask_texture; + int i; + int n_rects; + int stride; + + paint_tex = meta_shaped_texture_get_texture (META_SHAPED_TEXTURE (priv->actor)); + if (paint_tex == COGL_INVALID_HANDLE) + return; + + tex_width = cogl_texture_get_width (paint_tex); + tex_height = cogl_texture_get_height (paint_tex); + + stride = cairo_format_stride_for_width (CAIRO_FORMAT_A8, tex_width); + + /* Create data for an empty image */ + mask_data = g_malloc0 (stride * tex_height); + + n_rects = cairo_region_num_rectangles (shape_region); + + /* Fill in each rectangle. */ + for (i = 0; i < n_rects; i ++) + { + cairo_rectangle_int_t rect; + cairo_region_get_rectangle (shape_region, i, &rect); + + gint x1 = rect.x, x2 = x1 + rect.width; + gint y1 = rect.y, y2 = y1 + rect.height; + guchar *p; + + /* Clip the rectangle to the size of the texture */ + x1 = CLAMP (x1, 0, (gint) tex_width - 1); + x2 = CLAMP (x2, x1, (gint) tex_width); + y1 = CLAMP (y1, 0, (gint) tex_height - 1); + y2 = CLAMP (y2, y1, (gint) tex_height); + + /* Fill the rectangle */ + for (p = mask_data + y1 * stride + x1; + y1 < y2; + y1++, p += stride) + memset (p, 255, x2 - x1); + } + + if (meta_texture_rectangle_check (paint_tex)) + { + mask_texture = meta_texture_rectangle_new (tex_width, tex_height, + COGL_PIXEL_FORMAT_A_8, + COGL_PIXEL_FORMAT_A_8, + stride, + mask_data, + NULL /* error */); + } + else + { + /* Note: we don't allow slicing for this texture because we + * need to use it with multi-texturing which doesn't support + * sliced textures */ + mask_texture = cogl_texture_new_from_data (tex_width, tex_height, + COGL_TEXTURE_NO_SLICING, + COGL_PIXEL_FORMAT_A_8, + COGL_PIXEL_FORMAT_ANY, + stride, + mask_data); + } + + meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), + mask_texture); + cogl_handle_unref (mask_texture); + + g_free (mask_data); +} + static void check_needs_reshape (MetaWindowActor *self) { @@ -2001,7 +2082,7 @@ check_needs_reshape (MetaWindowActor *self) if (!priv->needs_reshape) return; - meta_shaped_texture_set_shape_region (META_SHAPED_TEXTURE (priv->actor), NULL); + meta_shaped_texture_set_mask_texture (META_SHAPED_TEXTURE (priv->actor), COGL_INVALID_HANDLE); meta_window_actor_clear_shape_region (self); meta_frame_calc_borders (priv->window->frame, &borders); @@ -2060,12 +2141,8 @@ check_needs_reshape (MetaWindowActor *self) } #endif - meta_shaped_texture_set_shape_region (META_SHAPED_TEXTURE (priv->actor), - region); - meta_window_actor_update_shape_region (self, region); - - cairo_region_destroy (region); + generate_mask (self, &borders, region); priv->needs_reshape = FALSE; meta_window_actor_invalidate_shadow (self); diff --git a/src/meta/meta-shaped-texture.h b/src/meta/meta-shaped-texture.h index 7c8ce81ac..ace4396b9 100644 --- a/src/meta/meta-shaped-texture.h +++ b/src/meta/meta-shaped-texture.h @@ -72,9 +72,8 @@ void meta_shaped_texture_set_pixmap (MetaShapedTexture *stex, CoglHandle meta_shaped_texture_get_texture (MetaShapedTexture *stex); -void meta_shaped_texture_set_shape_region (MetaShapedTexture *stex, - cairo_region_t *region); - +void meta_shaped_texture_set_mask_texture (MetaShapedTexture *stex, + CoglHandle mask_texture); /* Assumes ownership of clip_region */ void meta_shaped_texture_set_clip_region (MetaShapedTexture *stex,