diff --git a/src/compositor/meta-shaped-texture.c b/src/compositor/meta-shaped-texture.c index f560ac90c..a5fce0416 100644 --- a/src/compositor/meta-shaped-texture.c +++ b/src/compositor/meta-shaped-texture.c @@ -1,11 +1,13 @@ /* * shaped texture * - * An actor to draw a texture clipped to a list of rectangles + * An actor to draw a masked texture. * * Authored By Neil Roberts + * and Jasper St. Pierre * * Copyright (C) 2008 Intel Corporation + * Copyright (C) 2012 Red Hat, Inc. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -30,13 +32,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 +54,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 +73,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 +103,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 +119,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 +135,12 @@ meta_shaped_texture_dispose (GObject *object) priv->texture = COGL_INVALID_HANDLE; } - meta_shaped_texture_set_shape_region (self, NULL); + meta_shaped_texture_set_mask_texture (self, COGL_INVALID_HANDLE); 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 +190,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 +205,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 +295,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 +315,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 +405,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 +414,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..7f80064da 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, @@ -1989,6 +1991,85 @@ meta_window_actor_sync_visibility (MetaWindowActor *self) } } +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,9 +2141,7 @@ check_needs_reshape (MetaWindowActor *self) } #endif - meta_shaped_texture_set_shape_region (META_SHAPED_TEXTURE (priv->actor), - region); - + generate_mask (self, &borders, region); meta_window_actor_update_shape_region (self, region); cairo_region_destroy (region); 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,