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 @@
namespace blink {
ActiveAnimations::ActiveAnimations()
: m_animationStyleChange(false)
{
}
ActiveAnimations::~ActiveAnimations()
{
#if !ENABLE(OILPAN)
......@@ -85,4 +90,26 @@ void ActiveAnimations::trace(Visitor* visitor)
#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
......@@ -49,11 +49,7 @@ typedef WillBeHeapHashCountedSet<RawPtrWillBeWeakMember<AnimationPlayer> > Anima
class ActiveAnimations : public NoBaseWillBeGarbageCollectedFinalized<ActiveAnimations> {
WTF_MAKE_NONCOPYABLE(ActiveAnimations);
public:
ActiveAnimations()
: m_animationStyleChange(false)
{
}
ActiveAnimations();
~ActiveAnimations();
// Animations that are currently active for this element, their effects will be applied
......@@ -76,6 +72,9 @@ public:
void updateAnimationFlags(RenderStyle&);
void setAnimationStyleChange(bool animationStyleChange) { m_animationStyleChange = animationStyleChange; }
const RenderStyle* baseRenderStyle() const;
void updateBaseRenderStyle(const RenderStyle*);
#if !ENABLE(OILPAN)
void addAnimation(Animation* animation) { m_animations.append(animation); }
void notifyAnimationDestroyed(Animation* animation) { m_animations.remove(m_animations.find(animation)); }
......@@ -90,6 +89,7 @@ private:
CSSAnimations m_cssAnimations;
AnimationPlayerCountedSet m_players;
bool m_animationStyleChange;
RefPtr<RenderStyle> m_baseRenderStyle;
#if !ENABLE(OILPAN)
// FIXME: Oilpan: This is to avoid a reference cycle that keeps Elements alive
......
......@@ -589,7 +589,12 @@ PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderS
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.style()->inheritFrom(state.parentStyle(), isAtShadowBoundary(element) ? RenderStyle::AtShadowBoundary : RenderStyle::NotAtShadowBoundary);
} else {
......@@ -618,12 +623,13 @@ PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderS
state.style()->setInsideLink(linkState);
}
bool needsCollection = false;
CSSDefaultStyleSheets::instance().ensureDefaultStyleSheetsForElement(element, needsCollection);
if (needsCollection)
collectFeatures();
if (!baseRenderStyle) {
bool needsCollection = false;
CSSDefaultStyleSheets::instance().ensureDefaultStyleSheetsForElement(element, needsCollection);
if (needsCollection)
collectFeatures();
{
ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
matchAllRules(state, collector, matchingBehavior != MatchAllRulesExcludingSMIL);
......@@ -632,12 +638,15 @@ PassRefPtr<RenderStyle> StyleResolver::styleForElement(Element* element, RenderS
applyCallbackSelectors(state);
addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
}
// Cache our original display.
state.style()->setOriginalDisplay(state.style()->display());
// Cache our original 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
// 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
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.style()->inheritFrom(state.parentStyle());
} else {
......@@ -786,7 +802,7 @@ bool StyleResolver::pseudoStyleForElementInternal(Element& element, const Pseudo
// Since we don't use pseudo-elements in any of our quirk/print
// user agent rules, don't waste time walking those rules.
{
if (!baseRenderStyle) {
// Check UA, user and author rules.
ElementRuleCollector collector(state.elementContext(), m_selectorFilter, state.style());
collector.setPseudoStyleRequest(pseudoStyleRequest);
......@@ -801,19 +817,22 @@ bool StyleResolver::pseudoStyleForElementInternal(Element& element, const Pseudo
applyCallbackSelectors(state);
addContentAttrValuesToFeatures(state.contentAttrValues(), m_features);
}
// Cache our original display.
state.style()->setOriginalDisplay(state.style()->display());
// Cache our original display.
state.style()->setOriginalDisplay(state.style()->display());
// FIXME: Passing 0 as the Element* introduces a lot of complexity
// in the adjustRenderStyle code.
adjustRenderStyle(state, 0);
// FIXME: Passing 0 as the Element* introduces a lot of complexity
// in the adjustRenderStyle code.
adjustRenderStyle(state, 0);
if (activeAnimations)
activeAnimations->updateBaseRenderStyle(state.style());
}
// 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
// before deciding which properties to transition.
if (applyAnimatedProperties(state, element.pseudoElement(pseudoStyleRequest.pseudoId)))
if (applyAnimatedProperties(state, pseudoElement))
adjustRenderStyle(state, 0);
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