mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-14 13:55:43 +00:00
Bug 1435214: Optimize @keyframes rule insertions. r=xidorn,hiro
Also add some missing test for the tag name invalidations (bug 1407522) and an empty stylesheet just for sanity. MozReview-Commit-ID: AHwhZynLBv
This commit is contained in:
parent
73cea96890
commit
beaed0f565
@ -245,6 +245,7 @@ public:
|
||||
mozilla::EffectCompositor* EffectCompositor() { return mEffectCompositor; }
|
||||
nsTransitionManager* TransitionManager() { return mTransitionManager; }
|
||||
nsAnimationManager* AnimationManager() { return mAnimationManager; }
|
||||
const nsAnimationManager* AnimationManager() const { return mAnimationManager; }
|
||||
|
||||
nsRefreshDriver* RefreshDriver() { return mRefreshDriver; }
|
||||
|
||||
|
@ -367,6 +367,14 @@ Gecko_NoteAnimationOnlyDirtyElement(RawGeckoElementBorrowed aElement)
|
||||
const_cast<Element*>(aElement)->NoteAnimationOnlyDirtyForServo();
|
||||
}
|
||||
|
||||
bool Gecko_AnimationNameMayBeReferencedFromStyle(
|
||||
RawGeckoPresContextBorrowed aPresContext,
|
||||
nsAtom* aName)
|
||||
{
|
||||
MOZ_ASSERT(aPresContext);
|
||||
return aPresContext->AnimationManager()->AnimationMayBeReferenced(aName);
|
||||
}
|
||||
|
||||
CSSPseudoElementType
|
||||
Gecko_GetImplementedPseudo(RawGeckoElementBorrowed aElement)
|
||||
{
|
||||
|
@ -395,6 +395,10 @@ void Gecko_NoteDirtyElement(RawGeckoElementBorrowed element);
|
||||
void Gecko_NoteDirtySubtreeForInvalidation(RawGeckoElementBorrowed element);
|
||||
void Gecko_NoteAnimationOnlyDirtyElement(RawGeckoElementBorrowed element);
|
||||
|
||||
bool Gecko_AnimationNameMayBeReferencedFromStyle(
|
||||
RawGeckoPresContextBorrowed pres_context,
|
||||
nsAtom* name);
|
||||
|
||||
// Incremental restyle.
|
||||
mozilla::CSSPseudoElementType Gecko_GetImplementedPseudo(RawGeckoElementBorrowed element);
|
||||
// We'd like to return `nsChangeHint` here, but bindgen bitfield enums don't
|
||||
|
@ -1008,20 +1008,23 @@ BuildAnimations(nsPresContext* aPresContext,
|
||||
const NonOwningAnimationTarget& aTarget,
|
||||
const nsStyleDisplay& aStyleDisplay,
|
||||
BuilderType& aBuilder,
|
||||
nsAnimationManager::CSSAnimationCollection* aCollection)
|
||||
nsAnimationManager::CSSAnimationCollection* aCollection,
|
||||
nsTHashtable<nsRefPtrHashKey<nsAtom>>& aReferencedAnimations)
|
||||
{
|
||||
nsAnimationManager::OwningCSSAnimationPtrArray result;
|
||||
|
||||
for (size_t animIdx = aStyleDisplay.mAnimationNameCount; animIdx-- != 0;) {
|
||||
nsAtom* name = aStyleDisplay.GetAnimationName(animIdx);
|
||||
// CSS Animations whose animation-name does not match a @keyframes rule do
|
||||
// not generate animation events. This includes when the animation-name is
|
||||
// "none" which is represented by an empty name in the StyleAnimation.
|
||||
// Since such animations neither affect style nor dispatch events, we do
|
||||
// not generate a corresponding CSSAnimation for them.
|
||||
if (aStyleDisplay.GetAnimationName(animIdx) == nsGkAtoms::_empty) {
|
||||
if (name == nsGkAtoms::_empty) {
|
||||
continue;
|
||||
}
|
||||
|
||||
aReferencedAnimations.PutEntry(name);
|
||||
RefPtr<CSSAnimation> dest = BuildAnimation(aPresContext,
|
||||
aTarget,
|
||||
aStyleDisplay,
|
||||
@ -1125,7 +1128,8 @@ nsAnimationManager::DoUpdateAnimations(
|
||||
aTarget,
|
||||
aStyleDisplay,
|
||||
aBuilder,
|
||||
collection);
|
||||
collection,
|
||||
mMaybeReferencedAnimations);
|
||||
|
||||
if (newAnimations.IsEmpty()) {
|
||||
if (collection) {
|
||||
|
@ -345,10 +345,23 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
bool AnimationMayBeReferenced(nsAtom* aName) const
|
||||
{
|
||||
return mMaybeReferencedAnimations.Contains(aName);
|
||||
}
|
||||
|
||||
protected:
|
||||
~nsAnimationManager() override = default;
|
||||
|
||||
private:
|
||||
// This includes all animation names referenced regardless of whether a
|
||||
// corresponding `@keyframes` rule is available.
|
||||
//
|
||||
// It may contain names which are no longer referenced, but it should always
|
||||
// contain names which are currently referenced, so that it is usable for
|
||||
// style invalidation.
|
||||
nsTHashtable<nsRefPtrHashKey<nsAtom>> mMaybeReferencedAnimations;
|
||||
|
||||
template<class BuilderType>
|
||||
void DoUpdateAnimations(
|
||||
const mozilla::NonOwningAnimationTarget& aTarget,
|
||||
|
@ -30,10 +30,14 @@ const TESTS = [
|
||||
{ selector: "#idScope", restyle: true },
|
||||
{ selector: "#nonexistentIdScope", restyle: false },
|
||||
{ selector: "#nonexistentIdScope div + bar", restyle: false },
|
||||
{ selector: "baz", restyle: false },
|
||||
{ cssText: " ", restyle: false },
|
||||
{ cssText: "@keyframes foo { from { color: green } to { color: red } } #whatever { animation-name: foo; }", restyle: false },
|
||||
];
|
||||
|
||||
for (const test of TESTS) {
|
||||
target.innerHTML = test.selector + " { color: green; }";
|
||||
let cssText = test.cssText ? test.cssText : (test.selector + " { color: green; }");
|
||||
target.innerHTML = cssText;
|
||||
|
||||
document.body.offsetWidth;
|
||||
const prevGeneration = utils.restyleGeneration;
|
||||
@ -42,19 +46,22 @@ for (const test of TESTS) {
|
||||
|
||||
document.body.offsetWidth;
|
||||
(test.restyle ? isnot : is)(utils.restyleGeneration, prevGeneration,
|
||||
`Stylesheet removal with ${test.selector} should ${test.restyle ? "have" : "not have"} caused a restyle`);
|
||||
`Stylesheet removal with ${cssText} should ${test.restyle ? "have" : "not have"} caused a restyle`);
|
||||
|
||||
target.disabled = false; // Make the stylesheet effective.
|
||||
|
||||
let element = document.querySelector(test.selector);
|
||||
if (element) {
|
||||
is(test.restyle, true, "How could we not expect a restyle?");
|
||||
is(getComputedStyle(element).color, "rgb(0, 128, 0)",
|
||||
"Element style should've changed appropriately");
|
||||
if (test.selector) {
|
||||
let element = document.querySelector(test.selector);
|
||||
if (element) {
|
||||
is(test.restyle, true, "How could we not expect a restyle?");
|
||||
is(getComputedStyle(element).color, "rgb(0, 128, 0)",
|
||||
"Element style should've changed appropriately");
|
||||
}
|
||||
}
|
||||
|
||||
document.body.offsetWidth;
|
||||
(test.restyle ? isnot : is)(utils.restyleGeneration, prevGeneration,
|
||||
`Stylesheet addition with ${test.selector} should ${test.restyle ? "have" : "not have"} caused a restyle`);
|
||||
`Stylesheet addition with ${cssText} should ${test.restyle ? "have" : "not have"} caused a restyle`);
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
|
Loading…
Reference in New Issue
Block a user