Commit d77f9555 authored by rune@opera.com's avatar rune@opera.com

Skip rule matching during animations.

If a style change is due to animations updating their interpolated values
only, store a clone of the RenderStyle before the animated properties are
applied to use as a base for updating RenderStyle for the next frames.

The base RenderStyle is stored on the ActiveAnimations object and cleared
when a recalc is triggered by changes that require rule matching.

The machinery for detecting if a LocalStyleChange is caused by an animation
update only was already in place, so this CL is making use of that.

Running blink_perf.animation shows a frame rate increase of 18-40% with
the exception of three tests which are unchanged.

In general this seems to shave off nearly 50% of the time used in
recalcStyle for each animation frame if no inherited properties are
animated. For instance, in "The expansion of the dictionary definition card"
from issue 377939.

R=dstockwell@chromium.org,esprehn@chromium.org
BUG=377939,421822

Review URL: https://codereview.chromium.org/635203003

git-svn-id: svn://svn.chromium.org/blink/trunk@183662 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 35fc4925
...@@ -35,6 +35,11 @@ ...@@ -35,6 +35,11 @@
namespace blink { namespace blink {
ActiveAnimations::ActiveAnimations()
: m_animationStyleChange(false)
{
}
ActiveAnimations::~ActiveAnimations() ActiveAnimations::~ActiveAnimations()
{ {
#if !ENABLE(OILPAN) #if !ENABLE(OILPAN)
...@@ -85,4 +90,26 @@ void ActiveAnimations::trace(Visitor* visitor) ...@@ -85,4 +90,26 @@ void ActiveAnimations::trace(Visitor* visitor)
#endif #endif
} }
const RenderStyle* ActiveAnimations::baseRenderStyle() const
{
#if !ENABLE(ASSERT)
if (isAnimationStyleChange())
return m_baseRenderStyle.get();
#endif
return nullptr;
}
void ActiveAnimations::updateBaseRenderStyle(const RenderStyle* renderStyle)
{
if (!isAnimationStyleChange()) {
m_baseRenderStyle = nullptr;
return;
}
#if ENABLE(ASSERT)
if (m_baseRenderStyle && renderStyle)
ASSERT(*m_baseRenderStyle == *renderStyle);
#endif
m_baseRenderStyle = RenderStyle::clone(renderStyle);
}
} // namespace blink } // namespace blink
...@@ -49,11 +49,7 @@ typedef WillBeHeapHashCountedSet<RawPtrWillBeWeakMember<AnimationPlayer> > Anima ...@@ -49,11 +49,7 @@ typedef WillBeHeapHashCountedSet<RawPtrWillBeWeakMember<AnimationPlayer> > Anima
class ActiveAnimations : public NoBaseWillBeGarbageCollectedFinalized<ActiveAnimations> { class ActiveAnimations : public NoBaseWillBeGarbageCollectedFinalized<ActiveAnimations> {
WTF_MAKE_NONCOPYABLE(ActiveAnimations); WTF_MAKE_NONCOPYABLE(ActiveAnimations);
public: public:
ActiveAnimations() ActiveAnimations();
: m_animationStyleChange(false)
{
}
~ActiveAnimations(); ~ActiveAnimations();
// Animations that are currently active for this element, their effects will be applied // Animations that are currently active for this element, their effects will be applied
...@@ -76,6 +72,9 @@ public: ...@@ -76,6 +72,9 @@ public:
void updateAnimationFlags(RenderStyle&); void updateAnimationFlags(RenderStyle&);
void setAnimationStyleChange(bool animationStyleChange) { m_animationStyleChange = animationStyleChange; } void setAnimationStyleChange(bool animationStyleChange) { m_animationStyleChange = animationStyleChange; }
const RenderStyle* baseRenderStyle() const;
void updateBaseRenderStyle(const RenderStyle*);
#if !ENABLE(OILPAN) #if !ENABLE(OILPAN)
void addAnimation(Animation* animation) { m_animations.append(animation); } void addAnimation(Animation* animation) { m_animations.append(animation); }
void notifyAnimationDestroyed(Animation* animation) { m_animations.remove(m_animations.find(animation)); } void notifyAnimationDestroyed(Animation* animation) { m_animations.remove(m_animations.find(animation)); }
...@@ -90,6 +89,7 @@ private: ...@@ -90,6 +89,7 @@ private:
CSSAnimations m_cssAnimations; CSSAnimations m_cssAnimations;
AnimationPlayerCountedSet m_players; AnimationPlayerCountedSet m_players;
bool m_animationStyleChange; bool m_animationStyleChange;
RefPtr<RenderStyle> m_baseRenderStyle;
#if !ENABLE(OILPAN) #if !ENABLE(OILPAN)
// FIXME: Oilpan: This is to avoid a reference cycle that keeps Elements alive // FIXME: Oilpan: This is to avoid a reference cycle that keeps Elements alive
......
...@@ -589,7 +589,12 @@ PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderS ...@@ -589,7 +589,12 @@ PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderS
return sharedStyle.release(); return sharedStyle.release();
} }
if (state.parentStyle()) { ActiveAnimations* activeAnimations = element->activeAnimations();
const RenderStyle* baseRenderStyle = activeAnimations ? activeAnimations->baseRenderStyle() : nullptr;
if (baseRenderStyle) {
state.setStyle(RenderStyle::clone(baseRenderStyle));
} else if (state.parentStyle()) {
state.setStyle(RenderStyle::create()); state.setStyle(RenderStyle::create());
state.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary); state.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary);
} else { } else {
...@@ -618,12 +623,13 @@ PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderS ...@@ -618,12 +623,13 @@ PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderS
state.style()->setInsideLink(linkState); state.style()->setInsideLink(linkState);
} }
bool needsCollection = false; if (!baseRenderStyle) {
CSSDefaultStyleSheets::instance().ensureDefaultStyleSheetsForElement(element, needsCollection);
if (needsCollection) bool needsCollection = false;
collectFeatures(); CSSDefaultStyleSheets::instance().ensureDefaultStyleSheetsForElement(element, needsCollection);
if (needsCollection)
collectFeatures();
{
ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style()); ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
matchAllRules(state, collector, matchingBehavior != MatchAllRulesExcludingSMIL); matchAllRules(state, collector, matchingBehavior != MatchAllRulesExcludingSMIL);
...@@ -632,12 +638,15 @@ PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderS ...@@ -632,12 +638,15 @@ PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderS
applyCallbackSelectors(state); applyCallbackSelectors(state);
addContentAttrValuesToFeatures(state.contentAttrValues(), m_features); addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
}
// Cache our original display. // Cache our original display.
state.style()->setOriginalDisplay(state.style()->display()); state.style()->setOriginalDisplay(state.style()->display());
adjustRenderStyle(state, element); adjustRenderStyle(state, element);
if (activeAnimations)
activeAnimations->updateBaseRenderStyle(state.style());
}
// FIXME: The CSSWG wants to specify that the effects of animations are applied before // FIXME: The CSSWG wants to specify that the effects of animations are applied before
// important rules, but this currently happens here as we require adjustment to have happened // important rules, but this currently happens here as we require adjustment to have happened
...@@ -772,7 +781,14 @@ bool StyleResolver::pseudoStyleForElementInternal(Element& element, const Pseudo ...@@ -772,7 +781,14 @@ bool StyleResolver::pseudoStyleForElementInternal(Element& element, const Pseudo
StyleResolverParentScope::ensureParentStackIsPushed(); StyleResolverParentScope::ensureParentStackIsPushed();
if (pseudoStyleRequest.allowsInheritance(state.parentStyle())) { Element* pseudoElement = element.pseudoElement(pseudoStyleRequest.pseudoId);
ActiveAnimations* activeAnimations = pseudoElement ? pseudoElement->activeAnimations() : nullptr;
const RenderStyle* baseRenderStyle = activeAnimations ? activeAnimations->baseRenderStyle() : nullptr;
if (baseRenderStyle) {
state.setStyle(RenderStyle::clone(baseRenderStyle));
} else if (pseudoStyleRequest.allowsInheritance(state.parentStyle())) {
state.setStyle(RenderStyle::create()); state.setStyle(RenderStyle::create());
state.style()->inheritFrom(state.parentStyle()); state.style()->inheritFrom(state.parentStyle());
} else { } else {
...@@ -786,7 +802,7 @@ bool StyleResolver::pseudoStyleForElementInternal(Element& element, const Pseudo ...@@ -786,7 +802,7 @@ bool StyleResolver::pseudoStyleForElementInternal(Element& element, const Pseudo
// Since we don't use pseudo-elements in any of our quirk/print // Since we don't use pseudo-elements in any of our quirk/print
// user agent rules, don't waste time walking those rules. // user agent rules, don't waste time walking those rules.
{ if (!baseRenderStyle) {
// Check UA, user and author rules. // Check UA, user and author rules.
ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style()); ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
collector.setPseudoStyleRequest(pseudoStyleRequest); collector.setPseudoStyleRequest(pseudoStyleRequest);
...@@ -801,19 +817,22 @@ bool StyleResolver::pseudoStyleForElementInternal(Element& element, const Pseudo ...@@ -801,19 +817,22 @@ bool StyleResolver::pseudoStyleForElementInternal(Element& element, const Pseudo
applyCallbackSelectors(state); applyCallbackSelectors(state);
addContentAttrValuesToFeatures(state.contentAttrValues(), m_features); addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
}
// Cache our original display. // Cache our original display.
state.style()->setOriginalDisplay(state.style()->display()); state.style()->setOriginalDisplay(state.style()->display());
// FIXME: Passing 0 as the Element* introduces a lot of complexity // FIXME: Passing 0 as the Element* introduces a lot of complexity
// in the adjustRenderStyle code. // in the adjustRenderStyle code.
adjustRenderStyle(state, 0); adjustRenderStyle(state, 0);
if (activeAnimations)
activeAnimations->updateBaseRenderStyle(state.style());
}
// FIXME: The CSSWG wants to specify that the effects of animations are applied before // FIXME: The CSSWG wants to specify that the effects of animations are applied before
// important rules, but this currently happens here as we require adjustment to have happened // important rules, but this currently happens here as we require adjustment to have happened
// before deciding which properties to transition. // before deciding which properties to transition.
if (applyAnimatedProperties(state, element.pseudoElement(pseudoStyleRequest.pseudoId))) if (applyAnimatedProperties(state, pseudoElement))
adjustRenderStyle(state, 0); adjustRenderStyle(state, 0);
didAccess(); didAccess();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment