actor: Improve conditions for skipping implicit transitions

The "should this implicit transition be skipped" check should live into
its own function, where we can actually explain what it does and which
conditions should be respected.

Instead of just blindly skipping actors that are unmapped, or haven't
been painted yet, we should add a couple of escape hatches.

First of all, we don't want :allocation to be implicitly animated until
we have been painted (thus allocated) once; this avoids actors "flying
in" into their allocation.

We also want to allow implicit transitions on the opacity even if we
haven't been painted yet; the internal optimization that we employ in
clutter_actor_paint() and skips painting fully transparent actors is
exactly that: an internal optimization. Caller code should not be aware
of this change, and it should not influence code outside of ClutterActor
itself.

The rest of the conditions are the same: if the easing state's duration
is zero, or if the actor is both unmapped and not in a cloned branch of
the scene graph, then implicit transitions are pointless, as they won't
be painted.

https://bugzilla.gnome.org/show_bug.cgi?id=698766
This commit is contained in:
Emmanuele Bassi 2013-04-24 15:17:07 -04:00
parent f92b78781d
commit 9424e995fa

View File

@ -18706,6 +18706,52 @@ clutter_actor_add_transition_internal (ClutterActor *self,
clutter_timeline_start (timeline);
}
static gboolean
should_skip_transition (ClutterActor *self,
GParamSpec *pspec)
{
ClutterActorPrivate *priv = self->priv;
const ClutterAnimationInfo *info;
/* this function is called from _clutter_actor_create_transition() which
* calls _clutter_actor_get_animation_info() first, so we're guaranteed
* to have the correct ClutterAnimationInfo pointer
*/
info = _clutter_actor_get_animation_info_or_defaults (self);
/* if the easing state has a non-zero duration we always want an
* implicit transition to occur
*/
if (info->cur_state->easing_duration == 0)
return TRUE;
/* we do want :opacity transitions to work even if they start from an
* unpainted actor, because of the opacity optimization that lives in
* clutter_actor_paint()
*/
if (pspec == obj_props[PROP_OPACITY] && !priv->was_painted)
return FALSE;
/* on the other hand, if the actor hasn't been allocated yet, we want to
* skip all transitions on the :allocation, to avoid actors "flying in"
* into their new position and size
*/
if (pspec == obj_props[PROP_ALLOCATION] && priv->needs_allocation)
return TRUE;
/* if the actor is not mapped and is not part of a branch of the scene
* graph that is being cloned, then we always skip implicit transitions
* on the account of the fact that the actor is not going to be visible
* when those transitions happen
*/
if (!CLUTTER_ACTOR_IS_MAPPED (self) &&
priv->in_cloned_branch == 0 &&
!clutter_actor_has_mapped_clones (self))
return TRUE;
return FALSE;
}
/*< private >*
* _clutter_actor_create_transition:
* @actor: a #ClutterActor
@ -18783,17 +18829,9 @@ _clutter_actor_create_transition (ClutterActor *actor,
goto out;
}
if (info->cur_state->easing_duration == 0 ||
!actor->priv->was_painted ||
(!CLUTTER_ACTOR_IS_MAPPED (actor) &&
actor->priv->in_cloned_branch == 0 &&
!clutter_actor_has_mapped_clones (actor)))
if (should_skip_transition (actor, pspec))
{
/* don't bother creating the transition if one is not necessary
* because the actor doesn't want one, or if the actor is not
* visible: we just set the final value directly on the actor.
*
* we also don't go through the Animatable interface because we
/* we don't go through the Animatable interface because we
* already know we got here through an animatable property.
*/
CLUTTER_NOTE (ANIMATION, "Easing duration=0 was_painted=%s, immediate set for '%s::%s'",
@ -18808,6 +18846,7 @@ _clutter_actor_create_transition (ClutterActor *actor,
pspec->param_id,
&final,
pspec);
g_value_unset (&initial);
g_value_unset (&final);