зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1197620 - Part 1 - Stop all animations in destroyed frames. r=bbirtles
This commit is contained in:
Родитель
e7ba3880f4
Коммит
3525eca033
|
@ -90,6 +90,7 @@ RestyleManager::RestyleManager(nsPresContext* aPresContext)
|
|||
MostRecentRefresh())
|
||||
, mAnimationGeneration(0)
|
||||
, mReframingStyleContexts(nullptr)
|
||||
, mAnimationsWithDestroyedFrame(nullptr)
|
||||
, mPendingRestyles(ELEMENT_HAS_PENDING_RESTYLE |
|
||||
ELEMENT_IS_POTENTIAL_RESTYLE_ROOT |
|
||||
ELEMENT_IS_CONDITIONAL_RESTYLE_ANCESTOR)
|
||||
|
@ -1081,6 +1082,44 @@ RestyleManager::ReframingStyleContexts::~ReframingStyleContexts()
|
|||
mRestyleManager->mPresContext->FrameConstructor()->CreateNeededFrames();
|
||||
}
|
||||
|
||||
RestyleManager::AnimationsWithDestroyedFrame::AnimationsWithDestroyedFrame(
|
||||
RestyleManager* aRestyleManager)
|
||||
: mRestyleManager(aRestyleManager)
|
||||
, mRestorePointer(mRestyleManager->mAnimationsWithDestroyedFrame)
|
||||
{
|
||||
MOZ_ASSERT(!mRestyleManager->mAnimationsWithDestroyedFrame,
|
||||
"shouldn't construct recursively");
|
||||
mRestyleManager->mAnimationsWithDestroyedFrame = this;
|
||||
}
|
||||
|
||||
void
|
||||
RestyleManager::AnimationsWithDestroyedFrame::StopAnimationsForElementsWithoutFrames()
|
||||
{
|
||||
StopAnimationsWithoutFrame(mContents,
|
||||
nsCSSPseudoElements::ePseudo_NotPseudoElement);
|
||||
StopAnimationsWithoutFrame(mBeforeContents,
|
||||
nsCSSPseudoElements::ePseudo_before);
|
||||
StopAnimationsWithoutFrame(mAfterContents,
|
||||
nsCSSPseudoElements::ePseudo_after);
|
||||
}
|
||||
|
||||
void
|
||||
RestyleManager::AnimationsWithDestroyedFrame::StopAnimationsWithoutFrame(
|
||||
nsTArray<nsRefPtr<nsIContent>>& aArray,
|
||||
nsCSSPseudoElements::Type aPseudoType)
|
||||
{
|
||||
nsAnimationManager* animationManager =
|
||||
mRestyleManager->PresContext()->AnimationManager();
|
||||
for (nsIContent* content : aArray) {
|
||||
if (content->GetPrimaryFrame()) {
|
||||
continue;
|
||||
}
|
||||
dom::Element* element = content->AsElement();
|
||||
|
||||
animationManager->StopAnimationsForElement(element, aPseudoType);
|
||||
}
|
||||
}
|
||||
|
||||
static inline dom::Element*
|
||||
ElementForStyleContext(nsIContent* aParentContent,
|
||||
nsIFrame* aFrame,
|
||||
|
@ -1780,6 +1819,10 @@ RestyleManager::EndProcessingRestyles()
|
|||
{
|
||||
FlushOverflowChangedTracker();
|
||||
|
||||
MOZ_ASSERT(mAnimationsWithDestroyedFrame);
|
||||
mAnimationsWithDestroyedFrame->
|
||||
StopAnimationsForElementsWithoutFrames();
|
||||
|
||||
// Set mInStyleRefresh to false now, since the EndUpdate call might
|
||||
// add more restyles.
|
||||
mInStyleRefresh = false;
|
||||
|
|
|
@ -49,6 +49,8 @@ private:
|
|||
{
|
||||
MOZ_ASSERT(!mReframingStyleContexts,
|
||||
"temporary member should be nulled out before destruction");
|
||||
MOZ_ASSERT(!mAnimationsWithDestroyedFrame,
|
||||
"leaving dangling pointers from AnimationsWithDestroyedFrame");
|
||||
}
|
||||
|
||||
public:
|
||||
|
@ -247,6 +249,65 @@ public:
|
|||
nsStyleContext* aOldStyleContext,
|
||||
nsRefPtr<nsStyleContext>* aNewStyleContext /* inout */);
|
||||
|
||||
// AnimationsWithDestroyedFrame is used to stop animations on elements that
|
||||
// have no frame at the end of the restyling process.
|
||||
// It only lives during the restyling process.
|
||||
class MOZ_STACK_CLASS AnimationsWithDestroyedFrame final {
|
||||
public:
|
||||
// Construct a AnimationsWithDestroyedFrame object. The caller must
|
||||
// ensure that aRestyleManager lives at least as long as the
|
||||
// object. (This is generally easy since the caller is typically a
|
||||
// method of RestyleManager.)
|
||||
explicit AnimationsWithDestroyedFrame(RestyleManager* aRestyleManager);
|
||||
~AnimationsWithDestroyedFrame()
|
||||
{
|
||||
}
|
||||
|
||||
// This method takes the content node for the generated content for
|
||||
// animation on ::before and ::after, rather than the content node for
|
||||
// the real element.
|
||||
void Put(nsIContent* aContent, nsStyleContext* aStyleContext) {
|
||||
MOZ_ASSERT(aContent);
|
||||
nsCSSPseudoElements::Type pseudoType = aStyleContext->GetPseudoType();
|
||||
if (pseudoType == nsCSSPseudoElements::ePseudo_NotPseudoElement) {
|
||||
mContents.AppendElement(aContent);
|
||||
} else if (pseudoType == nsCSSPseudoElements::ePseudo_before) {
|
||||
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentbefore);
|
||||
mBeforeContents.AppendElement(aContent->GetParent());
|
||||
} else if (pseudoType == nsCSSPseudoElements::ePseudo_after) {
|
||||
MOZ_ASSERT(aContent->NodeInfo()->NameAtom() == nsGkAtoms::mozgeneratedcontentafter);
|
||||
mAfterContents.AppendElement(aContent->GetParent());
|
||||
}
|
||||
}
|
||||
|
||||
void StopAnimationsForElementsWithoutFrames();
|
||||
|
||||
private:
|
||||
void StopAnimationsWithoutFrame(nsTArray<nsRefPtr<nsIContent>>& aArray,
|
||||
nsCSSPseudoElements::Type aPseudoType);
|
||||
|
||||
RestyleManager* mRestyleManager;
|
||||
AutoRestore<AnimationsWithDestroyedFrame*> mRestorePointer;
|
||||
|
||||
// Below three arrays might include elements that have already had their
|
||||
// animations stopped.
|
||||
//
|
||||
// mBeforeContents and mAfterContents hold the real element rather than
|
||||
// the content node for the generated content (which might change during
|
||||
// a reframe)
|
||||
nsTArray<nsRefPtr<nsIContent>> mContents;
|
||||
nsTArray<nsRefPtr<nsIContent>> mBeforeContents;
|
||||
nsTArray<nsRefPtr<nsIContent>> mAfterContents;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the current AnimationsWithDestroyedFrame struct, or null if we're
|
||||
* not currently in a restyling operation.
|
||||
*/
|
||||
AnimationsWithDestroyedFrame* GetAnimationsWithDestroyedFrame() {
|
||||
return mAnimationsWithDestroyedFrame;
|
||||
}
|
||||
|
||||
private:
|
||||
void RestyleForEmptyChange(Element* aContainer);
|
||||
|
||||
|
@ -491,6 +552,7 @@ private:
|
|||
uint64_t mAnimationGeneration;
|
||||
|
||||
ReframingStyleContexts* mReframingStyleContexts;
|
||||
AnimationsWithDestroyedFrame* mAnimationsWithDestroyedFrame;
|
||||
|
||||
RestyleTracker mPendingRestyles;
|
||||
|
||||
|
|
|
@ -225,6 +225,12 @@ RestyleTracker::DoProcessRestyles()
|
|||
docShell->GetRecordProfileTimelineMarkers(&isTimelineRecording);
|
||||
}
|
||||
|
||||
// Create a AnimationsWithDestroyedFrame during restyling process to
|
||||
// stop animations on elements that have no frame at the end of the
|
||||
// restyling process.
|
||||
RestyleManager::AnimationsWithDestroyedFrame
|
||||
animationsWithDestroyedFrame(mRestyleManager);
|
||||
|
||||
// Create a ReframingStyleContexts struct on the stack and put it in our
|
||||
// mReframingStyleContexts for almost all of the remaining scope of
|
||||
// this function.
|
||||
|
|
|
@ -687,6 +687,17 @@ nsFrame::DestroyFrom(nsIFrame* aDestructRoot)
|
|||
}
|
||||
}
|
||||
|
||||
if (nsLayoutUtils::HasCurrentAnimations(static_cast<nsIFrame*>(this))) {
|
||||
// If no new frame for this element is created by the end of the
|
||||
// restyling process, stop animations for this frame
|
||||
RestyleManager::AnimationsWithDestroyedFrame* adf =
|
||||
presContext->RestyleManager()->GetAnimationsWithDestroyedFrame();
|
||||
// AnimationsWithDestroyedFrame only lives during the restyling process.
|
||||
if (adf) {
|
||||
adf->Put(mContent, mStyleContext);
|
||||
}
|
||||
}
|
||||
|
||||
shell->NotifyDestroyingFrame(this);
|
||||
|
||||
if (mState & NS_FRAME_EXTERNAL_REFERENCE) {
|
||||
|
|
|
@ -551,6 +551,22 @@ nsAnimationManager::CheckAnimationRule(nsStyleContext* aStyleContext,
|
|||
return GetAnimationRule(aElement, aStyleContext->GetPseudoType());
|
||||
}
|
||||
|
||||
void
|
||||
nsAnimationManager::StopAnimationsForElement(
|
||||
mozilla::dom::Element* aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType)
|
||||
{
|
||||
MOZ_ASSERT(aElement);
|
||||
AnimationCollection* collection =
|
||||
GetAnimations(aElement, aPseudoType, false);
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoAnimationMutationBatch mb(aElement->OwnerDoc());
|
||||
collection->Destroy();
|
||||
}
|
||||
|
||||
struct KeyframeData {
|
||||
float mKey;
|
||||
uint32_t mIndex; // store original order since sort algorithm is not stable
|
||||
|
|
|
@ -290,6 +290,12 @@ public:
|
|||
void DispatchEvents() { mEventDispatcher.DispatchEvents(mPresContext); }
|
||||
void ClearEventQueue() { mEventDispatcher.ClearEventQueue(); }
|
||||
|
||||
// Stop animations on the element. This method takes the real element
|
||||
// rather than the element for the generated content for animations on
|
||||
// ::before and ::after.
|
||||
void StopAnimationsForElement(mozilla::dom::Element* aElement,
|
||||
nsCSSPseudoElements::Type aPseudoType);
|
||||
|
||||
protected:
|
||||
virtual ~nsAnimationManager() {}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче