Bug 1228229 part 8 - Add EffectCompositor::(Maybe)UpdateCascadeResults; r=dbaron

--HG--
extra : rebase_source : 7f87c5a33e153e0815d39b7eb21917f3c034c0d3
This commit is contained in:
Brian Birtles 2016-01-06 11:04:05 +09:00
Родитель 144a09f431
Коммит f14f3a2be8
4 изменённых файлов: 207 добавлений и 4 удалений

Просмотреть файл

@ -12,10 +12,15 @@
#include "mozilla/AnimationUtils.h"
#include "mozilla/EffectSet.h"
#include "mozilla/LayerAnimationInfo.h"
#include "AnimationCommon.h" // For AnimationCollection
#include "nsAnimationManager.h"
#include "nsComputedDOMStyle.h" // nsComputedDOMStyle::GetPresShellForContent
#include "nsCSSPropertySet.h"
#include "nsIPresShell.h"
#include "nsLayoutUtils.h"
#include "nsRuleNode.h" // For nsRuleNode::ComputePropertiesOverridingAnimation
#include "nsTArray.h"
#include "nsTransitionManager.h"
using mozilla::dom::Animation;
using mozilla::dom::Element;
@ -110,6 +115,57 @@ EffectCompositor::GetAnimationsForCompositor(const nsIFrame* aFrame,
return result;
}
/* static */ void
EffectCompositor::MaybeUpdateCascadeResults(Element* aElement,
nsCSSPseudoElements::Type
aPseudoType,
nsStyleContext* aStyleContext)
{
EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
if (!effects || !effects->CascadeNeedsUpdate()) {
return;
}
UpdateCascadeResults(*effects, aElement, aPseudoType, aStyleContext);
MOZ_ASSERT(!effects->CascadeNeedsUpdate(), "Failed to update cascade state");
}
namespace {
class EffectCompositeOrderComparator {
public:
bool Equals(const KeyframeEffectReadOnly* a,
const KeyframeEffectReadOnly* b) const
{
return a == b;
}
bool LessThan(const KeyframeEffectReadOnly* a,
const KeyframeEffectReadOnly* b) const
{
MOZ_ASSERT(a->GetAnimation() && b->GetAnimation());
MOZ_ASSERT(
Equals(a, b) ||
a->GetAnimation()->HasLowerCompositeOrderThan(*b->GetAnimation()) !=
b->GetAnimation()->HasLowerCompositeOrderThan(*a->GetAnimation()));
return a->GetAnimation()->HasLowerCompositeOrderThan(*b->GetAnimation());
}
};
}
/* static */ void
EffectCompositor::UpdateCascadeResults(Element* aElement,
nsCSSPseudoElements::Type aPseudoType,
nsStyleContext* aStyleContext)
{
EffectSet* effects = EffectSet::GetEffectSet(aElement, aPseudoType);
if (!effects) {
return;
}
UpdateCascadeResults(*effects, aElement, aPseudoType, aStyleContext);
}
/* static */ Maybe<Pair<Element*, nsCSSPseudoElements::Type>>
EffectCompositor::GetAnimationElementAndPseudoForFrame(const nsIFrame* aFrame)
{
@ -167,4 +223,116 @@ EffectCompositor::GetOverriddenProperties(nsStyleContext* aStyleContext,
aPropertiesOverridden);
}
/* static */ void
EffectCompositor::UpdateCascadeResults(EffectSet& aEffectSet,
Element* aElement,
nsCSSPseudoElements::Type aPseudoType,
nsStyleContext* aStyleContext)
{
MOZ_ASSERT(EffectSet::GetEffectSet(aElement, aPseudoType) == &aEffectSet,
"Effect set should correspond to the specified (pseudo-)element");
if (aEffectSet.IsEmpty()) {
aEffectSet.MarkCascadeUpdated();
return;
}
// Get a list of effects sorted by composite order.
nsTArray<KeyframeEffectReadOnly*> sortedEffectList;
for (KeyframeEffectReadOnly* effect : aEffectSet) {
sortedEffectList.AppendElement(effect);
}
sortedEffectList.Sort(EffectCompositeOrderComparator());
// Get properties that override the *animations* level of the cascade.
//
// We only do this for properties that we can animate on the compositor
// since we will apply other properties on the main thread where the usual
// cascade applies.
nsCSSPropertySet overriddenProperties;
if (aStyleContext) {
GetOverriddenProperties(aStyleContext, overriddenProperties);
}
bool changed = false;
nsCSSPropertySet animatedProperties;
// Iterate from highest to lowest composite order.
for (KeyframeEffectReadOnly* effect : Reversed(sortedEffectList)) {
MOZ_ASSERT(effect->GetAnimation(),
"Effects on a target element should have an Animation");
bool inEffect = effect->IsInEffect();
for (AnimationProperty& prop : effect->Properties()) {
bool winsInCascade = !animatedProperties.HasProperty(prop.mProperty) &&
inEffect;
// If this property wins in the cascade, add it to the set of animated
// properties. We need to do this even if the property is overridden
// (in which case we set winsInCascade to false below) since we don't
// want to fire transitions on these properties.
if (winsInCascade) {
animatedProperties.AddProperty(prop.mProperty);
}
// For effects that will be applied to the animations level of the
// cascade, we need to check that the property isn't being set by
// something with higher priority in the cascade.
//
// We only do this, however, for properties that can be animated on
// the compositor. For properties animated on the main thread the usual
// cascade ensures these animations will be correctly overridden.
if (winsInCascade &&
!effect->GetAnimation()->AppliesToTransitionsLevel() &&
overriddenProperties.HasProperty(prop.mProperty)) {
winsInCascade = false;
}
if (winsInCascade != prop.mWinsInCascade) {
changed = true;
}
prop.mWinsInCascade = winsInCascade;
}
}
aEffectSet.MarkCascadeUpdated();
// If there is any change in the cascade result, update animations on
// layers with the winning animations.
nsPresContext* presContext = GetPresContext(aElement);
if (changed && presContext) {
// We currently unconditionally update both animations and transitions
// even if we could, for example, get away with only updating animations.
// This is a temporary measure until we unify all animation style updating
// under EffectCompositor.
AnimationCollection* animations =
presContext->AnimationManager()->GetAnimationCollection(aElement,
aPseudoType,
false);
/* don't create */
if (animations) {
animations->RequestRestyle(AnimationCollection::RestyleType::Layer);
}
AnimationCollection* transitions =
presContext->TransitionManager()->GetAnimationCollection(aElement,
aPseudoType,
false);
/* don't create */
if (transitions) {
transitions->RequestRestyle(AnimationCollection::RestyleType::Layer);
}
}
}
/* static */ nsPresContext*
EffectCompositor::GetPresContext(Element* aElement)
{
MOZ_ASSERT(aElement);
nsIPresShell* shell = nsComputedDOMStyle::GetPresShellForContent(aElement);
if (!shell) {
return nullptr;
}
return shell->GetPresContext();
}
} // namespace mozilla

Просмотреть файл

@ -14,9 +14,13 @@
#include "nsTArray.h"
class nsCSSPropertySet;
class nsPresContext;
class nsStyleContext;
namespace mozilla {
class EffectSet;
namespace dom {
class Animation;
class Element;
@ -32,6 +36,30 @@ public:
GetAnimationsForCompositor(const nsIFrame* aFrame,
nsCSSProperty aProperty);
// Update animation cascade results for the specified (pseudo-)element
// but only if we have marked the cascade as needing an update due a
// the change in the set of effects or a change in one of the effects'
// "in effect" state.
//
// This method does NOT detect if other styles that apply above the
// animation level of the cascade have changed.
static void
MaybeUpdateCascadeResults(dom::Element* aElement,
nsCSSPseudoElements::Type aPseudoType,
nsStyleContext* aStyleContext);
// Update the mWinsInCascade member for each property in effects targetting
// the specified (pseudo-)element.
//
// This can be expensive so we should only call it if styles that apply
// above the animation level of the cascade might have changed. For all
// other cases we should call MaybeUpdateCascadeResults.
static void
UpdateCascadeResults(dom::Element* aElement,
nsCSSPseudoElements::Type aPseudoType,
nsStyleContext* aStyleContext);
// Helper to fetch the corresponding element and pseudo-type from a frame.
//
// For frames corresponding to pseudo-elements, the returned element is the
@ -50,6 +78,15 @@ public:
static void
GetOverriddenProperties(nsStyleContext* aStyleContext,
nsCSSPropertySet& aPropertiesOverridden);
private:
static void
UpdateCascadeResults(EffectSet& aEffectSet,
dom::Element* aElement,
nsCSSPseudoElements::Type aPseudoType,
nsStyleContext* aStyleContext);
static nsPresContext* GetPresContext(dom::Element* aElement);
};
} // namespace mozilla

Просмотреть файл

@ -131,10 +131,7 @@ struct AnimationProperty
// For CSS Animations, which are overridden by !important rules in the
// cascade, we actually determine this from the CSS cascade
// computations, and then use it for OMTA.
// **NOTE**: For CSS animations, we only bother setting mWinsInCascade
// accurately for properties that we can animate on the compositor.
// For other properties, we make it always be true.
// **NOTE 2**: This member is not included when comparing AnimationProperty
// **NOTE**: This member is not included when comparing AnimationProperty
// objects for equality.
bool mWinsInCascade = true;

Просмотреть файл

@ -39,6 +39,7 @@ UNIFIED_SOURCES += [
LOCAL_INCLUDES += [
'/dom/base',
'/layout/style',
]
FINAL_LIBRARY = 'xul'