Bug 1379505: Allow calling GetBaseComputedStylesForElement for an unstyled element. r=boris
Before this refactoring, getComputedStyle could have side effects, and left the
style data in the element, so we could never arrive there without data.
There are a few crashtests that caught this, but this was already broken if you
called animate() on an element deep in a display: none subtree.
MozReview-Commit-ID: 1AvOvhAyOP3
--- a/dom/animation/KeyframeEffectReadOnly.cpp
+++ b/dom/animation/KeyframeEffectReadOnly.cpp
@@ -296,18 +296,17 @@ KeyframeEffectReadOnly::UpdateProperties
{
MOZ_ASSERT(aStyleContext);
if (!mDocument->IsStyledByServo()) {
DoUpdateProperties(Move(aStyleContext));
return;
}
- const ServoComputedValues* currentStyle =
- aStyleContext->ComputedValues();
+ const ServoComputedValues* currentStyle = aStyleContext->ComputedValues();
DoUpdateProperties(currentStyle);
}
void
KeyframeEffectReadOnly::UpdateProperties(
const ServoComputedValues* aComputedValues)
{
@@ -509,49 +508,53 @@ KeyframeEffectReadOnly::EnsureBaseStyles
nsPresContext* presContext =
nsContentUtils::GetContextForContent(mTarget->mElement);
MOZ_ASSERT(presContext,
"nsPresContext should not be nullptr since this EnsureBaseStyles "
"supposed to be called right after getting computed values with "
"a valid nsPresContext");
- RefPtr<ServoComputedValues> baseComputedValues;
+ RefPtr<const ServoComputedValues> baseComputedValues;
for (const AnimationProperty& property : aProperties) {
EnsureBaseStyle(property,
mTarget->mPseudoType,
presContext,
+ aComputedValues,
baseComputedValues);
}
}
void
KeyframeEffectReadOnly::EnsureBaseStyle(
const AnimationProperty& aProperty,
CSSPseudoElementType aPseudoType,
nsPresContext* aPresContext,
- RefPtr<ServoComputedValues>& aBaseComputedValues)
+ const ServoComputedValues* aComputedStyle,
+ RefPtr<const ServoComputedValues>& aBaseComputedValues)
{
bool hasAdditiveValues = false;
for (const AnimationPropertySegment& segment : aProperty.mSegments) {
if (!segment.HasReplaceableValues()) {
hasAdditiveValues = true;
break;
}
}
if (!hasAdditiveValues) {
return;
}
if (!aBaseComputedValues) {
aBaseComputedValues =
- aPresContext->StyleSet()->AsServo()->
- GetBaseComputedValuesForElement(mTarget->mElement, aPseudoType);
+ aPresContext->StyleSet()->AsServo()->GetBaseComputedValuesForElement(
+ mTarget->mElement,
+ aPseudoType,
+ aComputedStyle);
}
RefPtr<RawServoAnimationValue> baseValue =
Servo_ComputedValues_ExtractAnimationValue(aBaseComputedValues,
aProperty.mProperty).Consume();
mBaseStyleValuesForServo.Put(aProperty.mProperty, baseValue);
}
void
--- a/dom/animation/KeyframeEffectReadOnly.h
+++ b/dom/animation/KeyframeEffectReadOnly.h
@@ -379,17 +379,18 @@ protected:
void EnsureBaseStyle(nsCSSPropertyID aProperty,
nsStyleContext* aStyleContext,
RefPtr<nsStyleContext>& aCachedBaseStyleContext);
// Stylo version of the above function that also first checks for an additive
// value in |aProperty|'s list of segments.
void EnsureBaseStyle(const AnimationProperty& aProperty,
CSSPseudoElementType aPseudoType,
nsPresContext* aPresContext,
- RefPtr<ServoComputedValues>& aBaseComputedValues);
+ const ServoComputedValues* aComputedValues,
+ RefPtr<const ServoComputedValues>& aBaseComputedValues);
Maybe<OwningAnimationTarget> mTarget;
KeyframeEffectParams mEffectOptions;
// The specified keyframes.
nsTArray<Keyframe> mKeyframes;
new file mode 100644
--- /dev/null
+++ b/dom/animation/test/crashtests/1379606-1.html
@@ -0,0 +1,21 @@
+<!doctype html>
+<style>
+div {
+ display: none;
+}
+</style>
+<div>
+<div>
+<div>
+<div>
+<div>
+<div id="target">
+</div>
+</div>
+</div>
+</div>
+</div>
+</div>
+<script>
+ target.animate({ color: "red" })
+</script>
--- a/dom/animation/test/crashtests/crashtests.list
+++ b/dom/animation/test/crashtests/crashtests.list
@@ -23,8 +23,9 @@ pref(dom.animations-api.core.enabled,tru
pref(dom.animations-api.core.enabled,true) load 1330513-1.html
pref(dom.animations-api.core.enabled,true) load 1333539-1.html
pref(dom.animations-api.core.enabled,true) load 1333539-2.html
pref(dom.animations-api.core.enabled,true) load 1334583-1.html
pref(dom.animations-api.core.enabled,true) load 1335998-1.html
pref(dom.animations-api.core.enabled,true) load 1343589-1.html
pref(dom.animations-api.core.enabled,true) load 1359658-1.html
pref(dom.animations-api.core.enabled,true) load 1373712-1.html
+pref(dom.animations-api.core.enabled,true) load 1379606-1.html
--- a/layout/style/ServoBindingList.h
+++ b/layout/style/ServoBindingList.h
@@ -536,16 +536,17 @@ SERVO_BINDING_FUNC(Servo_AssertTreeIsCle
// and if so, frees them.
SERVO_BINDING_FUNC(Servo_MaybeGCRuleTree, void, RawServoStyleSetBorrowed set)
// Returns computed values for the given element without any animations rules.
SERVO_BINDING_FUNC(Servo_StyleSet_GetBaseComputedValuesForElement,
ServoComputedValuesStrong,
RawServoStyleSetBorrowed set,
RawGeckoElementBorrowed element,
+ ServoComputedValuesBorrowed existing_style,
const mozilla::ServoElementSnapshotTable* snapshots,
mozilla::CSSPseudoElementType pseudo_type)
// For canvas font.
SERVO_BINDING_FUNC(Servo_SerializeFontValueForCanvas, void,
RawServoDeclarationBlockBorrowed declarations,
nsAString* buffer)
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -1069,21 +1069,24 @@ ServoStyleSet::GetAnimationValues(
Servo_GetAnimationValues(aDeclarations,
aElement,
aComputedValues,
mRawSet.get(),
&aAnimationValues);
}
already_AddRefed<ServoComputedValues>
-ServoStyleSet::GetBaseComputedValuesForElement(Element* aElement,
- CSSPseudoElementType aPseudoType)
+ServoStyleSet::GetBaseComputedValuesForElement(
+ Element* aElement,
+ CSSPseudoElementType aPseudoType,
+ ServoComputedValuesBorrowed aStyle)
{
return Servo_StyleSet_GetBaseComputedValuesForElement(mRawSet.get(),
aElement,
+ aStyle,
&Snapshots(),
aPseudoType).Consume();
}
already_AddRefed<RawServoAnimationValue>
ServoStyleSet::ComputeAnimationValue(
Element* aElement,
RawServoDeclarationBlock* aDeclarations,
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -379,17 +379,18 @@ public:
nsTArray<RefPtr<RawServoAnimationValue>>& aAnimationValues);
bool AppendFontFaceRules(nsTArray<nsFontFaceRuleContainer>& aArray);
nsCSSCounterStyleRule* CounterStyleRuleForName(nsIAtom* aName);
already_AddRefed<ServoComputedValues>
GetBaseComputedValuesForElement(dom::Element* aElement,
- CSSPseudoElementType aPseudoType);
+ CSSPseudoElementType aPseudoType,
+ ServoComputedValuesBorrowed aStyle);
/**
* Resolve style for a given declaration block with/without the parent style.
* If the parent style is not specified, the document default computed values
* is used.
*/
already_AddRefed<ServoComputedValues>
ResolveForDeclarations(ServoComputedValuesBorrowedOrNull aParentOrNull,
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -637,17 +637,18 @@ nsComputedDOMStyle::DoGetStyleContextNoF
MOZ_ASSERT(presContext, "Should have a prescontext if we have a frame");
if (presContext && presContext->StyleSet()->IsGecko()) {
nsStyleSet* styleSet = presContext->StyleSet()->AsGecko();
return styleSet->ResolveStyleByRemovingAnimation(
aElement, result, eRestyle_AllHintsWithAnimations);
} else {
RefPtr<ServoComputedValues> baseComputedValues =
presContext->StyleSet()->AsServo()->
- GetBaseComputedValuesForElement(aElement, pseudoType);
+ GetBaseComputedValuesForElement(
+ aElement, pseudoType, result->ComputedValues());
return ServoStyleContext::Create(nullptr, presContext, aPseudo,
pseudoType, baseComputedValues.forget());
}
}
// this function returns an addrefed style context
RefPtr<nsStyleContext> ret = result;
return ret.forget();
@@ -672,17 +673,18 @@ nsComputedDOMStyle::DoGetStyleContextNoF
: StyleRuleInclusion::All;
RefPtr<nsStyleContext> result =
servoSet->ResolveTransientStyle(aElement, aPseudo, pseudoType, rules);
if (aAnimationFlag == eWithAnimation) {
return result.forget();
}
RefPtr<ServoComputedValues> baseComputedValues =
- servoSet->GetBaseComputedValuesForElement(aElement, pseudoType);
+ servoSet->GetBaseComputedValuesForElement(
+ aElement, pseudoType, result->ComputedValues());
return ServoStyleContext::Create(nullptr, presContext, aPseudo,
pseudoType, baseComputedValues.forget());
}
RefPtr<nsStyleContext> parentContext;
nsIContent* parent = aPseudo ? aElement : aElement->GetParent();
// Don't resolve parent context for document fragments.
if (parent && parent->IsElement()) {