[clutter/wip/correct-opacity: 8/8] clutter-actor: Add a 'has_overlaps' virtual



commit 313bce436aca499477800289ea46b258186124bb
Author: Neil Roberts <neil linux intel com>
Date:   Mon Mar 14 16:30:53 2011 +0000

    clutter-actor: Add a 'has_overlaps' virtual
    
    This adds a virtual to ClutterActor so that an actor subclass can
    report whether it has overlapping primitives. ClutterActor uses this
    to determine whether it needs to use ClutterFlattenEffect to implement
    the opacity property. The default implementation of the virtual
    returns TRUE which means that most actors will end up being redirected
    offscreen when the opacity != 255. ClutterTexture and ClutterRectangle
    override this to return FALSE because they should never need to be
    redirected. ClutterClone overrides it to divert to the source.
    
    The values for the ClutterOffscreenRedirect enum have changed to:
    
    AUTOMATIC_FOR_OPACITY
    
     The actor will only be redirected if has_overlaps returns TRUE and
     the opacity is < 255
    
    ALWAYS_FOR_OPACITY
    
     The actor will always be redirected if the opacity < 255 regardless
     of the return value of has_overlaps
    
    ALWAYS
    
     The actor will always be redirected offscreen.
    
    This means that the property can't be used to prevent the actor from
    being redirected but only to increase the likelihood that it will be
    redirected.
    
    ClutterActor now adds and removes the flatten effect depending on
    whether flattening is needed directly in clutter_actor_paint(). There
    are new internal versions of add/remove_effect that don't queue a
    redraw. This means that ClutterFlattenEffect is now just a no-op
    subclass of ClutterOffscreen. It is only needed because
    ClutterOffscreen is abstract. Removing the effect also makes it so
    that the cached image will be freed as soon as an actor is repainted
    without being flattened.

 clutter/clutter-actor.c                    |  232 ++++++++++++++++++++--------
 clutter/clutter-actor.h                    |   28 +++-
 clutter/clutter-clone.c                    |   14 ++
 clutter/clutter-flatten-effect.c           |  101 +------------
 clutter/clutter-flatten-effect.h           |    2 -
 clutter/clutter-rectangle.c                |    9 +
 clutter/clutter-texture.c                  |    9 +
 doc/reference/clutter/clutter-sections.txt |    1 +
 tests/conform/test-offscreen-redirect.c    |   55 ++++++-
 9 files changed, 270 insertions(+), 181 deletions(-)
---
diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c
index 1828e3c..a4af23c 100644
--- a/clutter/clutter-actor.c
+++ b/clutter/clutter-actor.c
@@ -2656,6 +2656,101 @@ _clutter_actor_get_pick_id (ClutterActor *self)
   return self->priv->pick_id;
 }
 
+/* This is the same as clutter_actor_add_effect except that it doesn't
+   queue a redraw and it doesn't notify on the effect property */
+static void
+_clutter_actor_add_effect_internal (ClutterActor  *self,
+                                    ClutterEffect *effect)
+{
+  ClutterActorPrivate *priv = self->priv;
+
+  if (priv->effects == NULL)
+    {
+      priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
+      priv->effects->actor = self;
+    }
+
+  _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
+}
+
+/* This is the same as clutter_actor_remove_effect except that it doesn't
+   queue a redraw and it doesn't notify on the effect property */
+static void
+_clutter_actor_remove_effect_internal (ClutterActor  *self,
+                                       ClutterEffect *effect)
+{
+  ClutterActorPrivate *priv = self->priv;
+
+  if (priv->effects == NULL)
+    return;
+
+  _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
+}
+
+static gboolean
+needs_flatten_effect (ClutterActor *self)
+{
+  ClutterActorPrivate *priv = self->priv;
+
+  switch (priv->offscreen_redirect)
+    {
+    case CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY:
+      if (!clutter_actor_has_overlaps (self))
+        return FALSE;
+      /* flow through */
+    case CLUTTER_OFFSCREEN_REDIRECT_ALWAYS_FOR_OPACITY:
+      return clutter_actor_get_paint_opacity (self) < 255;
+
+    case CLUTTER_OFFSCREEN_REDIRECT_ALWAYS:
+      return TRUE;
+    }
+
+  g_assert_not_reached ();
+}
+
+static void
+add_or_remove_flatten_effect (ClutterActor *self)
+{
+  ClutterActorPrivate *priv = self->priv;
+
+  /* Add or remove the flatten effect depending on the
+     offscreen-redirect property. */
+  if (needs_flatten_effect (self))
+    {
+      if (priv->flatten_effect == NULL)
+        {
+          ClutterActorMeta *actor_meta;
+          gint priority;
+
+          priv->flatten_effect = _clutter_flatten_effect_new ();
+          /* Keep a reference to the effect so that we can queue
+             redraws from it */
+          g_object_ref_sink (priv->flatten_effect);
+
+          /* Set the priority of the effect to high so that it will
+             always be applied to the actor first. It uses an internal
+             priority so that it won't be visible to applications */
+          actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
+          priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
+          _clutter_actor_meta_set_priority (actor_meta, priority);
+
+          /* This will add the effect without queueing a redraw */
+          _clutter_actor_add_effect_internal (self, priv->flatten_effect);
+        }
+    }
+  else
+    {
+      if (priv->flatten_effect != NULL)
+        {
+          /* Destroy the effect so that it will lose its fbo cache of
+             the actor */
+          _clutter_actor_remove_effect_internal (self, priv->flatten_effect);
+          g_object_unref (priv->flatten_effect);
+          priv->flatten_effect = NULL;
+        }
+    }
+}
+
 /**
  * clutter_actor_paint:
  * @self: A #ClutterActor
@@ -2757,6 +2852,12 @@ clutter_actor_paint (ClutterActor *self)
     {
       CLUTTER_COUNTER_INC (_clutter_uprof_context, actor_paint_counter);
 
+      /* We check whether we need to add the flatten effect before
+         each paint so that we can avoid having a mechanism for
+         applications to notify when the value of the
+         has_overlaps virtual changes. */
+      add_or_remove_flatten_effect (self);
+
       /* We save the current paint volume so that the next time the
        * actor queues a redraw we can constrain the redraw to just
        * cover the union of the new bounding box and the old.
@@ -3648,6 +3749,17 @@ clutter_actor_real_get_paint_volume (ClutterActor       *self,
   return FALSE;
 }
 
+static gboolean
+clutter_actor_real_has_overlaps (ClutterActor *self)
+{
+  /* By default we'll assume that all actors need an offscreen
+     redirect to get the correct opacity. This effectively favours
+     accuracy over efficiency. Actors such as ClutterTexture that
+     would never need an offscreen redirect can override this to
+     return FALSE. */
+  return TRUE;
+}
+
 static void
 clutter_actor_class_init (ClutterActorClass *klass)
 {
@@ -4052,7 +4164,7 @@ clutter_actor_class_init (ClutterActorClass *klass)
                              P_("Whether to flatten the actor into a "
                                 "single image"),
                              CLUTTER_TYPE_OFFSCREEN_REDIRECT,
-                             CLUTTER_OFFSCREEN_REDIRECT_NEVER,
+                             CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY,
                              CLUTTER_PARAM_READWRITE);
   obj_props[PROP_OFFSCREEN_REDIRECT] = pspec;
   g_object_class_install_property (object_class,
@@ -5092,6 +5204,7 @@ clutter_actor_class_init (ClutterActorClass *klass)
   klass->apply_transform = clutter_actor_real_apply_transform;
   klass->get_accessible = clutter_actor_real_get_accessible;
   klass->get_paint_volume = clutter_actor_real_get_paint_volume;
+  klass->has_overlaps = clutter_actor_real_has_overlaps;
 }
 
 static void
@@ -5104,7 +5217,7 @@ clutter_actor_init (ClutterActor *self)
   priv->parent_actor = NULL;
   priv->has_clip = FALSE;
   priv->opacity = 0xff;
-  priv->offscreen_redirect = CLUTTER_OFFSCREEN_REDIRECT_NEVER;
+  priv->offscreen_redirect = CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY;
   priv->id = _clutter_context_acquire_id (self);
   priv->pick_id = -1;
   priv->scale_x = 1.0;
@@ -7447,7 +7560,7 @@ clutter_actor_get_opacity (ClutterActor *self)
  * some cases be a performance lose so it is important to determine
  * which value is right for an actor before modifying this value. For
  * example, there is never any reason to flatten an actor that is just
- * a single texture (such as a ClutterTexture) because it is
+ * a single texture (such as a #ClutterTexture) because it is
  * effectively already cached in an image so the offscreen would be
  * redundant. Also if the actor contains primitives that are far apart
  * with a large transparent area in the middle (such as a large
@@ -7460,28 +7573,35 @@ clutter_actor_get_opacity (ClutterActor *self)
  * forwards on the opacity to all of the children. If the children are
  * overlapping then it will appear as if they are two separate glassy
  * objects and there will be a break in the color where they
- * overlap. By setting the offscreen-redirect to
- * %CLUTTER_OFFSCREEN_REDIRECT_OPACITY_ONLY it will be as if the two
- * opaque objects are combined into one and then made transparent
+ * overlap. By redirecting to an offscreen buffer it will be as if the
+ * two opaque objects are combined into one and then made transparent
  * which is usually what is expected.
  *
- * The image below demonstrates the difference between the fast
- * default opacity and the correct but inefficient opacity achieved
- * through the offscreen redirect. The image shows two Clutter groups,
- * each containing a red and a green rectangle which overlap. The
- * opacity on the group is set to 128 (which is 50%). When the
- * offscreen redirect is not used, the red rectangle can be seen
- * through the blue rectangle as if the two rectangles were separately
- * transparent. When the redirect is used the group as a whole is
- * transparent instead so the red rectangle is not visible where they
- * overlap.
+ * The image below demonstrates the difference between redirecting and
+ * not. The image shows two Clutter groups, each containing a red and
+ * a green rectangle which overlap. The opacity on the group is set to
+ * 128 (which is 50%). When the offscreen redirect is not used, the
+ * red rectangle can be seen through the blue rectangle as if the two
+ * rectangles were separately transparent. When the redirect is used
+ * the group as a whole is transparent instead so the red rectangle is
+ * not visible where they overlap.
  *
  * <figure id="offscreen-redirect">
  *   <title>Sample of using an offscreen redirect for transparency</title>
  *   <graphic fileref="offscreen-redirect.png" format="PNG"/>
  * </figure>
  *
- * The default value is %CLUTTER_OFFSCREEN_REDIRECT_NEVER.
+ * The default behaviour is
+ * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY. This will end up
+ * redirecting actors whenever they are semi-transparent unless their
+ * has_overlaps() virtual returns %FALSE. This should mean that
+ * generally all actors will be rendered with the correct opacity and
+ * certain actors that don't need the offscreen redirect (such as
+ * #ClutterTexture) will paint directly for efficiency.
+ *
+ * Custom actors that don't contain any overlapping primitives are
+ * recommended to override the has_overlaps() virtual to return %FALSE
+ * for maximum efficiency.
  *
  * Since: 1.8
  */
@@ -7499,35 +7619,13 @@ clutter_actor_set_offscreen_redirect (ClutterActor *self,
     {
       priv->offscreen_redirect = redirect;
 
-      if (priv->flatten_effect == NULL)
-        {
-          ClutterActorMeta *actor_meta;
-          gint priority;
-
-          priv->flatten_effect = _clutter_flatten_effect_new ();
-          /* Keep a reference to the effect so that we can queue
-             redraws from it */
-          g_object_ref_sink (priv->flatten_effect);
-
-          /* Set the priority of the effect to high so that it will
-             always be applied to the actor first. It uses an internal
-             priority so that it won't be visible to applications */
-          actor_meta = CLUTTER_ACTOR_META (priv->flatten_effect);
-          priority = CLUTTER_ACTOR_META_PRIORITY_INTERNAL_HIGH;
-          _clutter_actor_meta_set_priority (actor_meta, priority);
-
-          /* This will also queue a full redraw of the actor */
-          clutter_actor_add_effect (self, priv->flatten_effect);
-        }
-      else
-        {
-          /* Queue a redraw from the effect so that it can use its
-             cached image if available instead of having to redraw the
-             actual actor. If it doesn't end up using the FBO then the
-             effect is still able to continue the paint anyway */
-          _clutter_actor_queue_redraw_with_effect (self,
-                                                   priv->flatten_effect);
-        }
+      /* Queue a redraw from the effect so that it can use its cached
+         image if available instead of having to redraw the actual
+         actor. If it doesn't end up using the FBO then the effect is
+         still able to continue the paint anyway. If there is no
+         effect then this is equivalent to queuing a full redraw */
+      _clutter_actor_queue_redraw_with_effect (self,
+                                               priv->flatten_effect);
 
       g_object_notify_by_pspec (G_OBJECT (self),
                                 obj_props[PROP_OFFSCREEN_REDIRECT]);
@@ -11769,20 +11867,10 @@ void
 clutter_actor_add_effect (ClutterActor  *self,
                           ClutterEffect *effect)
 {
-  ClutterActorPrivate *priv;
-
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
 
-  priv = self->priv;
-
-  if (priv->effects == NULL)
-    {
-      priv->effects = g_object_new (CLUTTER_TYPE_META_GROUP, NULL);
-      priv->effects->actor = self;
-    }
-
-  _clutter_meta_group_add_meta (priv->effects, CLUTTER_ACTOR_META (effect));
+  _clutter_actor_add_effect_internal (self, effect);
 
   clutter_actor_queue_redraw (self);
 
@@ -11835,17 +11923,10 @@ void
 clutter_actor_remove_effect (ClutterActor  *self,
                              ClutterEffect *effect)
 {
-  ClutterActorPrivate *priv;
-
   g_return_if_fail (CLUTTER_IS_ACTOR (self));
   g_return_if_fail (CLUTTER_IS_EFFECT (effect));
 
-  priv = self->priv;
-
-  if (priv->effects == NULL)
-    return;
-
-  _clutter_meta_group_remove_meta (priv->effects, CLUTTER_ACTOR_META (effect));
+  _clutter_actor_remove_effect_internal (self, effect);
 
   clutter_actor_queue_redraw (self);
 
@@ -12261,6 +12342,27 @@ clutter_actor_get_paint_box (ClutterActor    *self,
   return TRUE;
 }
 
+/**
+ * clutter_actor_has_overlaps:
+ * @self: A #ClutterActor
+ *
+ * Return value: whether the actor may contain overlapping
+ * primitives. Clutter uses this to determine whether the painting
+ * should be redirected to an offscreen buffer to correctly implement
+ * the opacity property. Custom actors can override this by
+ * implementing the has_overlaps virtual. See
+ * clutter_actor_set_offscreen_redirect() for more information.
+ *
+ * Since: 1.8
+ */
+gboolean
+clutter_actor_has_overlaps (ClutterActor *self)
+{
+  g_return_val_if_fail (CLUTTER_IS_ACTOR (self), TRUE);
+
+  return CLUTTER_ACTOR_GET_CLASS (self)->has_overlaps (self);
+}
+
 gint
 _clutter_actor_get_n_children (ClutterActor *self)
 {
diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h
index 06e1ae7..584cc2a 100644
--- a/clutter/clutter-actor.h
+++ b/clutter/clutter-actor.h
@@ -118,12 +118,14 @@ typedef enum
 
 /**
  * ClutterOffscreenRedirect:
- * @CLUTTER_OFFSCREEN_REDIRECT_NEVER: Never redirect the actor to an
- *   offscreen buffer.
+ * @CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY: Only redirect
+ *   the actor if it is semi-transparent and its has_overlaps()
+ *   virtual returns %TRUE. This is the default.
+ * @CLUTTER_OFFSCREEN_REDIRECT_ALWAYS_FOR_OPACITY: Always redirect the
+ *   actor if it is semi-transparent regardless of the return value of
+ *   its has_overlaps() virtual.
  * @CLUTTER_OFFSCREEN_REDIRECT_ALWAYS: Always redirect the actor to an
- *   offscreen buffer.
- * @CLUTTER_OFFSCREEN_REDIRECT_OPACITY_ONLY: Only redirect the actor if
- *   it is semi-transparent.
+ *   offscreen buffer even if it is fully opaque.
  *
  * Possible values to pass to clutter_actor_set_offscreen_redirect().
  *
@@ -131,9 +133,9 @@ typedef enum
  */
 typedef enum
 {
-  CLUTTER_OFFSCREEN_REDIRECT_NEVER,
-  CLUTTER_OFFSCREEN_REDIRECT_ALWAYS,
-  CLUTTER_OFFSCREEN_REDIRECT_OPACITY_ONLY
+  CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY,
+  CLUTTER_OFFSCREEN_REDIRECT_ALWAYS_FOR_OPACITY,
+  CLUTTER_OFFSCREEN_REDIRECT_ALWAYS
 } ClutterOffscreenRedirect;
 
 /**
@@ -235,6 +237,10 @@ struct _ClutterActor
  *   describes the actor to an assistive technology.
  * @get_paint_volume: virtual function, for sub-classes to define their
  *   #ClutterPaintVolume
+ * @has_overlaps: virtual function for
+ *   sub-classes to advertise whether they need an offscreen redirect
+ *   to get the correct opacity. See
+ *   clutter_actor_set_offscreen_redirect() for details.
  *
  * Base class for actors.
  */
@@ -312,9 +318,11 @@ struct _ClutterActorClass
   gboolean    (* get_paint_volume)  (ClutterActor         *actor,
                                      ClutterPaintVolume   *volume);
 
+  gboolean (* has_overlaps)         (ClutterActor *actor);
+
   /*< private >*/
   /* padding for future expansion */
-  gpointer _padding_dummy[29];
+  gpointer _padding_dummy[28];
 };
 
 GType                 clutter_actor_get_type                  (void) G_GNUC_CONST;
@@ -610,6 +618,8 @@ const ClutterPaintVolume  *clutter_actor_get_transformed_paint_volume (ClutterAc
 gboolean             clutter_actor_get_paint_box      (ClutterActor         *self,
                                                        ClutterActorBox      *box);
 
+gboolean             clutter_actor_has_overlaps       (ClutterActor         *self);
+
 G_END_DECLS
 
 #endif /* __CLUTTER_ACTOR_H__ */
diff --git a/clutter/clutter-clone.c b/clutter/clutter-clone.c
index c0c4ee3..d5ce9ef 100644
--- a/clutter/clutter-clone.c
+++ b/clutter/clutter-clone.c
@@ -221,6 +221,19 @@ clutter_clone_get_paint_volume (ClutterActor *self,
   return TRUE;
 }
 
+static gboolean
+clutter_clone_has_overlaps (ClutterActor *self)
+{
+  ClutterClonePrivate *priv = CLUTTER_CLONE (self)->priv;
+
+  /* The clone has overlaps iff the source has overlaps */
+
+  if (priv->clone_source == NULL)
+    return FALSE;
+
+  return clutter_actor_has_overlaps (priv->clone_source);
+}
+
 static void
 clutter_clone_allocate (ClutterActor           *self,
                         const ClutterActorBox  *box,
@@ -309,6 +322,7 @@ clutter_clone_class_init (ClutterCloneClass *klass)
   actor_class->get_preferred_width  = clutter_clone_get_preferred_width;
   actor_class->get_preferred_height = clutter_clone_get_preferred_height;
   actor_class->allocate             = clutter_clone_allocate;
+  actor_class->has_overlaps         = clutter_clone_has_overlaps;
 
   gobject_class->dispose      = clutter_clone_dispose;
   gobject_class->set_property = clutter_clone_set_property;
diff --git a/clutter/clutter-flatten-effect.c b/clutter/clutter-flatten-effect.c
index d844299..3342b04 100644
--- a/clutter/clutter-flatten-effect.c
+++ b/clutter/clutter-flatten-effect.c
@@ -23,7 +23,9 @@
  */
 
 /* This is an internal-only effect used to implement the
-   'flatness' property of ClutterActor */
+   'offscreen-redirect' property of ClutterActor. It doesn't actually
+   need to do anything on top of the ClutterOffscreenEffect class so
+   it only exists because that class is abstract */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -33,50 +35,18 @@
 #include "clutter-private.h"
 #include "clutter-actor-private.h"
 
-static void
-_clutter_flatten_effect_set_actor (ClutterActorMeta *meta,
-                                   ClutterActor *actor);
-
-static void
-_clutter_flatten_effect_run (ClutterEffect *effect,
-                             ClutterEffectRunFlags flags);
-
 G_DEFINE_TYPE (ClutterFlattenEffect,
                _clutter_flatten_effect,
                CLUTTER_TYPE_OFFSCREEN_EFFECT);
 
-#define CLUTTER_FLATTEN_EFFECT_GET_PRIVATE(obj) \
-  (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_FLATTEN_EFFECT, \
-                                ClutterFlattenEffectPrivate))
-
-struct _ClutterFlattenEffectPrivate
-{
-  ClutterActor *actor;
-
-  /* This records whether the last paint went through the FBO or if it
-     was painted directly. We need to know this so we can force the
-     offscreen effect to clear its image when we switch from rendering
-     directly to rendering through the FBO */
-  gboolean last_paint_used_fbo;
-};
-
 static void
 _clutter_flatten_effect_class_init (ClutterFlattenEffectClass *klass)
 {
-  ClutterActorMetaClass *actor_meta_class = (ClutterActorMetaClass *) klass;
-  ClutterEffectClass *effect_class = (ClutterEffectClass *) klass;
-
-  actor_meta_class->set_actor = _clutter_flatten_effect_set_actor;
-
-  effect_class->run = _clutter_flatten_effect_run;
-
-  g_type_class_add_private (klass, sizeof (ClutterFlattenEffectPrivate));
 }
 
 static void
 _clutter_flatten_effect_init (ClutterFlattenEffect *self)
 {
-  self->priv = CLUTTER_FLATTEN_EFFECT_GET_PRIVATE (self);
 }
 
 ClutterEffect *
@@ -84,68 +54,3 @@ _clutter_flatten_effect_new (void)
 {
   return g_object_new (CLUTTER_TYPE_FLATTEN_EFFECT, NULL);
 }
-
-static gboolean
-_clutter_flatten_effect_is_using_fbo (ClutterFlattenEffect *opacity_effect)
-{
-  ClutterFlattenEffectPrivate *priv = opacity_effect->priv;
-
-  switch (clutter_actor_get_offscreen_redirect (priv->actor))
-    {
-    case CLUTTER_OFFSCREEN_REDIRECT_NEVER:
-      return FALSE;
-
-    case CLUTTER_OFFSCREEN_REDIRECT_ALWAYS:
-      return TRUE;
-
-    case CLUTTER_OFFSCREEN_REDIRECT_OPACITY_ONLY:
-      return clutter_actor_get_paint_opacity (priv->actor) < 255;
-    }
-
-  g_assert_not_reached ();
-}
-
-
-static void
-_clutter_flatten_effect_set_actor (ClutterActorMeta *meta,
-                                   ClutterActor *actor)
-{
-  ClutterFlattenEffect *opacity_effect = CLUTTER_FLATTEN_EFFECT (meta);
-  ClutterFlattenEffectPrivate *priv = opacity_effect->priv;
-
-  CLUTTER_ACTOR_META_CLASS (_clutter_flatten_effect_parent_class)->
-    set_actor (meta, actor);
-
-  /* we keep a back pointer here, to avoid going through the ActorMeta */
-  priv->actor = clutter_actor_meta_get_actor (meta);
-}
-
-static void
-_clutter_flatten_effect_run (ClutterEffect *effect,
-                             ClutterEffectRunFlags flags)
-{
-  ClutterFlattenEffect *opacity_effect = CLUTTER_FLATTEN_EFFECT (effect);
-  ClutterFlattenEffectPrivate *priv = opacity_effect->priv;
-
-  if (_clutter_flatten_effect_is_using_fbo (opacity_effect))
-    {
-      /* If the last paint bypassed the FBO then we'll pretend the
-         actor is dirty so that the offscreen will clear its image */
-      if (!priv->last_paint_used_fbo)
-        {
-          flags |= CLUTTER_EFFECT_RUN_ACTOR_DIRTY;
-          priv->last_paint_used_fbo = TRUE;
-        }
-
-      /* Let the offscreen effect paint the actor through the FBO */
-      CLUTTER_EFFECT_CLASS (_clutter_flatten_effect_parent_class)->
-        run (effect, flags);
-    }
-  else
-    {
-      /* Just let the actor paint directly to the stage */
-      clutter_actor_continue_paint (priv->actor);
-
-      priv->last_paint_used_fbo = FALSE;
-    }
-}
diff --git a/clutter/clutter-flatten-effect.h b/clutter/clutter-flatten-effect.h
index 7508f8c..03b2df6 100644
--- a/clutter/clutter-flatten-effect.h
+++ b/clutter/clutter-flatten-effect.h
@@ -62,8 +62,6 @@ struct _ClutterFlattenEffectClass
 struct _ClutterFlattenEffect
 {
   ClutterOffscreenEffect parent;
-
-  ClutterFlattenEffectPrivate *priv;
 };
 
 GType _clutter_flatten_effect_get_type (void) G_GNUC_CONST;
diff --git a/clutter/clutter-rectangle.c b/clutter/clutter-rectangle.c
index e45e0c4..3a96e04 100644
--- a/clutter/clutter-rectangle.c
+++ b/clutter/clutter-rectangle.c
@@ -162,6 +162,14 @@ clutter_rectangle_get_paint_volume (ClutterActor       *self,
                                                   volume);
 }
 
+static gboolean
+clutter_rectangle_has_overlaps (ClutterActor *self)
+{
+  /* Rectangles never need an offscreen redirect because there are
+     never any overlapping primitives */
+  return FALSE;
+}
+
 static void
 clutter_rectangle_set_property (GObject      *object,
 				guint         prop_id,
@@ -243,6 +251,7 @@ clutter_rectangle_class_init (ClutterRectangleClass *klass)
 
   actor_class->paint            = clutter_rectangle_paint;
   actor_class->get_paint_volume = clutter_rectangle_get_paint_volume;
+  actor_class->has_overlaps     = clutter_rectangle_has_overlaps;
 
   gobject_class->finalize     = clutter_rectangle_finalize;
   gobject_class->dispose      = clutter_rectangle_dispose;
diff --git a/clutter/clutter-texture.c b/clutter/clutter-texture.c
index ae4aa13..b21fa06 100644
--- a/clutter/clutter-texture.c
+++ b/clutter/clutter-texture.c
@@ -409,6 +409,14 @@ clutter_texture_allocate (ClutterActor           *self,
     clutter_actor_allocate_preferred_size (priv->fbo_source, flags);
 }
 
+static gboolean
+clutter_texture_has_overlaps (ClutterActor *self)
+{
+  /* Textures never need an offscreen redirect because there are never
+     any overlapping primitives */
+  return FALSE;
+}
+
 static void
 set_viewport_with_buffer_under_fbo_source (ClutterActor *fbo_source,
                                            int viewport_width,
@@ -980,6 +988,7 @@ clutter_texture_class_init (ClutterTextureClass *klass)
   actor_class->get_paint_volume = clutter_texture_get_paint_volume;
   actor_class->realize          = clutter_texture_realize;
   actor_class->unrealize        = clutter_texture_unrealize;
+  actor_class->has_overlaps     = clutter_texture_has_overlaps;
 
   actor_class->get_preferred_width  = clutter_texture_get_preferred_width;
   actor_class->get_preferred_height = clutter_texture_get_preferred_height;
diff --git a/doc/reference/clutter/clutter-sections.txt b/doc/reference/clutter/clutter-sections.txt
index e6ea579..80a0bbf 100644
--- a/doc/reference/clutter/clutter-sections.txt
+++ b/doc/reference/clutter/clutter-sections.txt
@@ -299,6 +299,7 @@ clutter_actor_event
 clutter_actor_should_pick_paint
 clutter_actor_map
 clutter_actor_unmap
+clutter_actor_has_overlaps
 
 <SUBSECTION>
 ClutterAllocationFlags
diff --git a/tests/conform/test-offscreen-redirect.c b/tests/conform/test-offscreen-redirect.c
index 04da603..3e25c98 100644
--- a/tests/conform/test-offscreen-redirect.c
+++ b/tests/conform/test-offscreen-redirect.c
@@ -33,7 +33,7 @@ GType foo_actor_get_type (void) G_GNUC_CONST;
 G_DEFINE_TYPE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR);
 
 static void
-foo_actor_class_paint (ClutterActor *actor)
+foo_actor_paint (ClutterActor *actor)
 {
   FooActor *foo_actor = (FooActor *) actor;
   ClutterActorBox allocation;
@@ -55,19 +55,26 @@ foo_actor_class_paint (ClutterActor *actor)
 }
 
 static gboolean
-foo_actor_class_get_paint_volume (ClutterActor *actor,
-                                  ClutterPaintVolume *volume)
+foo_actor_get_paint_volume (ClutterActor *actor,
+                            ClutterPaintVolume *volume)
 {
   return clutter_paint_volume_set_from_allocation (volume, actor);
 }
 
+static gboolean
+foo_actor_has_overlaps (ClutterActor *actor)
+{
+  return FALSE;
+}
+
 static void
 foo_actor_class_init (FooActorClass *klass)
 {
   ClutterActorClass *actor_class = (ClutterActorClass *) klass;
 
-  actor_class->paint = foo_actor_class_paint;
-  actor_class->get_paint_volume = foo_actor_class_get_paint_volume;
+  actor_class->paint = foo_actor_paint;
+  actor_class->get_paint_volume = foo_actor_get_paint_volume;
+  actor_class->has_overlaps = foo_actor_has_overlaps;
 }
 
 static void
@@ -75,6 +82,40 @@ foo_actor_init (FooActor *self)
 {
 }
 
+typedef struct _FooGroup      FooGroup;
+typedef struct _FooGroupClass FooGroupClass;
+
+struct _FooGroupClass
+{
+  ClutterGroupClass parent_class;
+};
+
+struct _FooGroup
+{
+  ClutterGroup parent;
+};
+
+G_DEFINE_TYPE (FooGroup, foo_group, CLUTTER_TYPE_GROUP);
+
+static gboolean
+foo_group_has_overlaps (ClutterActor *actor)
+{
+  return FALSE;
+}
+
+static void
+foo_group_class_init (FooGroupClass *klass)
+{
+  ClutterActorClass *actor_class = (ClutterActorClass *) klass;
+
+  actor_class->has_overlaps = foo_group_has_overlaps;
+}
+
+static void
+foo_group_init (FooGroup *self)
+{
+}
+
 static void
 verify_results (Data *data,
                 guint8 expected_color_red,
@@ -155,7 +196,7 @@ timeout_cb (gpointer user_data)
      it needs to fill the cache first. It should be painted with full
      opacity */
   clutter_actor_set_offscreen_redirect
-    (data->container, CLUTTER_OFFSCREEN_REDIRECT_OPACITY_ONLY);
+    (data->container, CLUTTER_OFFSCREEN_REDIRECT_ALWAYS_FOR_OPACITY);
   verify_results (data,
                   255, 127, 127,
                   1,
@@ -242,7 +283,7 @@ test_offscreen_redirect (TestConformSimpleFixture *fixture,
 
       data.parent_container = clutter_group_new ();
 
-      data.container = clutter_group_new ();
+      data.container = g_object_new (foo_group_get_type (), NULL);
 
       data.foo_actor = g_object_new (foo_actor_get_type (), NULL);
       clutter_actor_set_size (CLUTTER_ACTOR (data.foo_actor), 100, 100);



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]