actor: make default get_paint_volume more conservative

There are too many examples where the default assumption that an actor
paints inside its allocation isn't true, so we now return FALSE in the
base implementation instead. This means that by default we are saying
"we don't know the paint volume of the actor", so developers need to
implement the get_paint_volume virtual to take advantage of culling and
clipped redraws with their actors.

This patch provides very conservative get_paint_volume implementations
for ClutterTexture, ClutterCairoTexture, ClutterRectangle and
ClutterText which all explicitly check the actor's object type to avoid
making any assumptions about subclasses.
This commit is contained in:
Robert Bragg 2010-09-08 19:47:11 +01:00
parent d9a7f1b03b
commit 72eeb8e809
5 changed files with 112 additions and 18 deletions

View File

@ -3457,19 +3457,7 @@ static gboolean
clutter_actor_real_get_paint_volume (ClutterActor *self,
ClutterPaintVolume *volume)
{
ClutterActorPrivate *priv = self->priv;
gfloat width, height;
if (G_UNLIKELY (priv->needs_allocation))
return FALSE;
/* the default origin is set to { 0, 0, 0 } */
clutter_actor_box_get_size (&priv->allocation, &width, &height);
clutter_paint_volume_set_width (volume, width);
clutter_paint_volume_set_height (volume, height);
/* the default depth will be 0 since most actors are 2D */
return TRUE;
return FALSE;
}
static void

View File

@ -366,6 +366,31 @@ clutter_cairo_texture_get_preferred_height (ClutterActor *actor,
*natural_height = (gfloat) priv->height;
}
static gboolean
clutter_cairo_texture_get_paint_volume (ClutterActor *self,
ClutterPaintVolume *volume)
{
ClutterGeometry allocation;
/* XXX: we are being conservative here and not making assumptions
* that sub-classes won't paint outside their allocation. */
if (G_OBJECT_TYPE (self) != CLUTTER_TYPE_CAIRO_TEXTURE)
return FALSE;
/* XXX: clutter_actor_get_allocation can potentially be very
* expensive to call if called while the actor doesn't have a valid
* allocation since it will trigger a synchronous relayout of the
* scenegraph. We explicitly check we have a valid allocation
* to avoid hitting that codepath. */
if (!clutter_actor_has_allocation (self))
return FALSE;
clutter_actor_get_allocation_geometry (self, &allocation);
clutter_paint_volume_set_width (volume, allocation.width);
clutter_paint_volume_set_height (volume, allocation.height);
return TRUE;
}
static void
clutter_cairo_texture_class_init (ClutterCairoTextureClass *klass)
{
@ -378,6 +403,9 @@ clutter_cairo_texture_class_init (ClutterCairoTextureClass *klass)
gobject_class->get_property = clutter_cairo_texture_get_property;
gobject_class->notify = clutter_cairo_texture_notify;
actor_class->get_paint_volume =
clutter_cairo_texture_get_paint_volume;
actor_class->get_preferred_width =
clutter_cairo_texture_get_preferred_width;
actor_class->get_preferred_height =

View File

@ -152,6 +152,31 @@ clutter_rectangle_paint (ClutterActor *self)
}
}
static gboolean
clutter_rectangle_get_paint_volume (ClutterActor *self,
ClutterPaintVolume *volume)
{
ClutterGeometry allocation;
/* XXX: we are being conservative here and not making assumptions
* that sub-classes won't paint outside their allocation. */
if (G_OBJECT_TYPE (self) != CLUTTER_TYPE_RECTANGLE)
return FALSE;
/* XXX: clutter_actor_get_allocation can potentially be very
* expensive to call if called while the actor doesn't have a valid
* allocation since it will trigger a synchronous relayout of the
* scenegraph. We explicitly check we have a valid allocation
* to avoid hitting that codepath. */
if (!clutter_actor_has_allocation (self))
return FALSE;
clutter_actor_get_allocation_geometry (self, &allocation);
clutter_paint_volume_set_width (volume, allocation.width);
clutter_paint_volume_set_height (volume, allocation.height);
return TRUE;
}
static void
clutter_rectangle_set_property (GObject *object,
guint prop_id,
@ -231,7 +256,8 @@ clutter_rectangle_class_init (ClutterRectangleClass *klass)
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
GParamSpec *pspec;
actor_class->paint = clutter_rectangle_paint;
actor_class->paint = clutter_rectangle_paint;
actor_class->get_paint_volume = clutter_rectangle_get_paint_volume;
gobject_class->finalize = clutter_rectangle_finalize;
gobject_class->dispose = clutter_rectangle_dispose;

View File

@ -1920,6 +1920,31 @@ clutter_text_paint (ClutterActor *self)
}
static gboolean
clutter_text_get_paint_volume (ClutterActor *self,
ClutterPaintVolume *volume)
{
ClutterGeometry allocation;
/* XXX: we are being conservative here and not making assumptions
* that sub-classes won't paint outside their allocation. */
if (G_OBJECT_TYPE (self) != CLUTTER_TYPE_TEXT)
return FALSE;
/* XXX: clutter_actor_get_allocation can potentially be very
* expensive to call if called while the actor doesn't have a valid
* allocation since it will trigger a synchronous relayout of the
* scenegraph. We explicitly check we have a valid allocation
* to avoid hitting that codepath. */
if (!clutter_actor_has_allocation (self))
return FALSE;
clutter_actor_get_allocation_geometry (self, &allocation);
clutter_paint_volume_set_width (volume, allocation.width);
clutter_paint_volume_set_height (volume, allocation.height);
return TRUE;
}
static void
clutter_text_get_preferred_width (ClutterActor *self,
gfloat for_height,
@ -2492,6 +2517,7 @@ clutter_text_class_init (ClutterTextClass *klass)
gobject_class->finalize = clutter_text_finalize;
actor_class->paint = clutter_text_paint;
actor_class->get_paint_volume = clutter_text_get_paint_volume;
actor_class->get_preferred_width = clutter_text_get_preferred_width;
actor_class->get_preferred_height = clutter_text_get_preferred_height;
actor_class->allocate = clutter_text_allocate;

View File

@ -685,6 +685,31 @@ clutter_texture_paint (ClutterActor *self)
gen_texcoords_and_draw_cogl_rectangle (self);
}
static gboolean
clutter_texture_get_paint_volume (ClutterActor *self,
ClutterPaintVolume *volume)
{
ClutterGeometry allocation;
/* XXX: we are being conservative here and not making assumptions
* that sub-classes won't paint outside their allocation. */
if (G_OBJECT_TYPE (self) != CLUTTER_TYPE_TEXTURE)
return FALSE;
/* XXX: clutter_actor_get_allocation can potentially be very
* expensive to call if called while the actor doesn't have a valid
* allocation since it will trigger a synchronous relayout of the
* scenegraph. We explicitly check we have a valid allocation
* to avoid hitting that codepath. */
if (!clutter_actor_has_allocation (self))
return FALSE;
clutter_actor_get_allocation_geometry (self, &allocation);
clutter_paint_volume_set_width (volume, allocation.width);
clutter_paint_volume_set_height (volume, allocation.height);
return TRUE;
}
static void
clutter_texture_async_data_free (ClutterTextureAsyncData *data)
{
@ -956,10 +981,11 @@ clutter_texture_class_init (ClutterTextureClass *klass)
g_type_class_add_private (klass, sizeof (ClutterTexturePrivate));
actor_class->paint = clutter_texture_paint;
actor_class->pick = clutter_texture_pick;
actor_class->realize = clutter_texture_realize;
actor_class->unrealize = clutter_texture_unrealize;
actor_class->paint = clutter_texture_paint;
actor_class->pick = clutter_texture_pick;
actor_class->get_paint_volume = clutter_texture_get_paint_volume;
actor_class->realize = clutter_texture_realize;
actor_class->unrealize = clutter_texture_unrealize;
actor_class->get_preferred_width = clutter_texture_get_preferred_width;
actor_class->get_preferred_height = clutter_texture_get_preferred_height;