Bug 1330190 - Part 1: Add nsComputedDOMStyle::GetStyleContextForElementWithoutAnimation. r?heycam
We need another variant of GetStyleContextForElement() that does not consider
animation rules at all to get the base styles of the target element (i.e.
styles without animations).
In subsequent patches we also skip nsAnimationManager::UpdateAnimations() and
EffectCompositor::UpdateEffectProperties() to avoid (indirect) recursive calls
for resolving style of the same element.
MozReview-Commit-ID: G5olgXIMtvY
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -443,22 +443,62 @@ nsComputedDOMStyle::GetStyleContextForEl
}
presShell->FlushPendingNotifications(FlushType::Style);
return GetStyleContextForElementNoFlush(aElement, aPseudo, presShell,
aStyleType);
}
-/* static */
+namespace {
+class MOZ_STACK_CLASS AutoSkipAnimationRules final
+{
+public:
+ AutoSkipAnimationRules(nsPresContext* aPresContext,
+ nsComputedDOMStyle::AnimationFlag aAnimationFlag)
+ {
+ MOZ_ASSERT(aPresContext);
+
+ // Nothing to do if we are going to resolve style *with* animation.
+ if (aAnimationFlag == nsComputedDOMStyle::eWithAnimation) {
+ return;
+ }
+
+ // Set SkipAnimationRules flag if we are going to resolve style without
+ // animation.
+ if (aPresContext->RestyleManager()->IsGecko()) {
+ mRestyleManager = aPresContext->RestyleManager()->AsGecko();
+
+ mOldSkipAnimationRules = mRestyleManager->SkipAnimationRules();
+ mRestyleManager->SetSkipAnimationRules(true);
+ } else {
+ NS_WARNING("stylo: can't skip animaition rules yet");
+ }
+ }
+
+ ~AutoSkipAnimationRules()
+ {
+ if (mRestyleManager) {
+ mRestyleManager->SetSkipAnimationRules(mOldSkipAnimationRules);
+ }
+ }
+
+private:
+ RestyleManager* mRestyleManager = nullptr;
+ bool mOldSkipAnimationRules = false;
+};
+}
+
already_AddRefed<nsStyleContext>
-nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
- nsIAtom* aPseudo,
- nsIPresShell* aPresShell,
- StyleType aStyleType)
+nsComputedDOMStyle::DoGetStyleContextForElementNoFlush(
+ Element* aElement,
+ nsIAtom* aPseudo,
+ nsIPresShell* aPresShell,
+ StyleType aStyleType,
+ AnimationFlag aAnimationFlag)
{
MOZ_ASSERT(aElement, "NULL element");
// If the content has a pres shell, we must use it. Otherwise we'd
// potentially mix rule trees by using the wrong pres shell's style
// set. Using the pres shell from the content also means that any
// content that's actually *in* a document will get the style from the
// correct document.
nsIPresShell *presShell = GetPresShellForContent(aElement);
@@ -516,20 +556,23 @@ nsComputedDOMStyle::GetStyleContextForEl
}
return servoSet->ResolveTransientStyle(aElement, type);
}
RefPtr<nsStyleContext> sc;
RefPtr<nsStyleContext> parentContext;
nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
// Don't resolve parent context for document fragments.
- if (parent && parent->IsElement())
+ if (parent && parent->IsElement()) {
parentContext = GetStyleContextForElementNoFlush(parent->AsElement(),
nullptr, aPresShell,
aStyleType);
+ }
+
+ AutoSkipAnimationRules autoSkipAnimationRule(presContext, aAnimationFlag);
if (type != CSSPseudoElementType::NotPseudo) {
nsIFrame* frame = nsLayoutUtils::GetStyleFrame(aElement);
Element* pseudoElement =
frame && inDocWithShell ? frame->GetPseudoElement(type) : nullptr;
sc = styleSet->ResolvePseudoElementStyle(aElement, type, parentContext,
pseudoElement);
} else {
@@ -558,16 +601,59 @@ nsComputedDOMStyle::GetStyleContextForEl
}
sc = styleSet->AsGecko()->ResolveStyleForRules(parentContext, rules);
}
return sc.forget();
}
+
+/* static */
+already_AddRefed<nsStyleContext>
+nsComputedDOMStyle::GetStyleContextForElementNoFlush(Element* aElement,
+ nsIAtom* aPseudo,
+ nsIPresShell* aPresShell,
+ StyleType aStyleType)
+{
+ return DoGetStyleContextForElementNoFlush(aElement,
+ aPseudo,
+ aPresShell,
+ aStyleType,
+ eWithAnimation);
+}
+
+/* static */
+already_AddRefed<nsStyleContext>
+nsComputedDOMStyle::GetStyleContextForElementWithoutAnimation(
+ Element* aElement,
+ nsIAtom* aPseudo,
+ nsIPresShell* aPresShell)
+{
+ // If the content has a pres shell, we must use it. Otherwise we'd
+ // potentially mix rule trees by using the wrong pres shell's style
+ // set. Using the pres shell from the content also means that any
+ // content that's actually *in* a document will get the style from the
+ // correct document.
+ nsCOMPtr<nsIPresShell> presShell = GetPresShellForContent(aElement);
+ if (!presShell) {
+ presShell = aPresShell;
+ if (!presShell)
+ return nullptr;
+ }
+
+ presShell->FlushPendingNotifications(FlushType::Style);
+
+ return DoGetStyleContextForElementNoFlush(aElement,
+ aPseudo,
+ presShell,
+ eAll,
+ eWithoutAnimation);
+}
+
nsMargin
nsComputedDOMStyle::GetAdjustedValuesForBoxSizing()
{
// We want the width/height of whatever parts 'width' or 'height' controls,
// which can be different depending on the value of the 'box-sizing' property.
const nsStylePosition* stylePos = StylePosition();
nsMargin adjustment;
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -84,16 +84,26 @@ public:
return mContent;
}
static already_AddRefed<nsStyleContext>
GetStyleContextForElement(mozilla::dom::Element* aElement, nsIAtom* aPseudo,
nsIPresShell* aPresShell,
StyleType aStyleType = eAll);
+ enum AnimationFlag {
+ eWithAnimation,
+ eWithoutAnimation,
+ };
+ // Similar to the above but ignoring animation rules and with StyleType::eAll.
+ static already_AddRefed<nsStyleContext>
+ GetStyleContextForElementWithoutAnimation(mozilla::dom::Element* aElement,
+ nsIAtom* aPseudo,
+ nsIPresShell* aPresShell);
+
static already_AddRefed<nsStyleContext>
GetStyleContextForElementNoFlush(mozilla::dom::Element* aElement,
nsIAtom* aPseudo,
nsIPresShell* aPresShell,
StyleType aStyleType = eAll);
static nsIPresShell*
GetPresShellForContent(nsIContent* aContent);
@@ -139,16 +149,23 @@ private:
void UpdateCurrentStyleSources(bool aNeedsLayoutFlush);
void ClearCurrentStyleSources();
// Helper functions called by UpdateCurrentStyleSources.
void ClearStyleContext();
void SetResolvedStyleContext(RefPtr<nsStyleContext>&& aContext);
void SetFrameStyleContext(nsStyleContext* aContext);
+ static already_AddRefed<nsStyleContext>
+ DoGetStyleContextForElementNoFlush(mozilla::dom::Element* aElement,
+ nsIAtom* aPseudo,
+ nsIPresShell* aPresShell,
+ StyleType aStyleType,
+ AnimationFlag aAnimationFlag);
+
#define STYLE_STRUCT(name_, checkdata_cb_) \
const nsStyle##name_ * Style##name_() { \
return mStyleContext->Style##name_(); \
}
#include "nsStyleStructList.h"
#undef STYLE_STRUCT
already_AddRefed<CSSValue> GetEllipseRadii(const nsStyleCorners& aRadius,