author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Tue, 21 Apr 2015 11:57:16 +0200 | |
changeset 240135 | ef3c6dd092347f42486e21eceeb25cf72fe88750 |
parent 240134 | c68248668189bb4af3921f79e9a860fe8a2f52ad (current diff) |
parent 240086 | 1ff8096ab54b9b8e198f1cd8334503f3d752ecb5 (diff) |
child 240166 | 3de89bd361c3c68adc7b959823e34d5ca29abf2d |
push id | 58752 |
push user | cbook@mozilla.com |
push date | Tue, 21 Apr 2015 10:39:00 +0000 |
treeherder | mozilla-inbound@b8d59286a581 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 40.0a1 |
first release with | nightly linux32
ef3c6dd09234
/
40.0a1
/
20150421030209
/
files
nightly linux64
ef3c6dd09234
/
40.0a1
/
20150421030209
/
files
nightly win32
ef3c6dd09234
/
40.0a1
/
20150421030209
/
files
nightly win64
ef3c6dd09234
/
40.0a1
/
20150421030209
/
files
nightly mac
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
releases | nightly linux32
40.0a1
/
20150421030209
/
pushlog to previous
nightly linux64
40.0a1
/
20150421030209
/
pushlog to previous
nightly win32
40.0a1
/
20150421030209
/
pushlog to previous
nightly win64
40.0a1
/
20150421030209
/
pushlog to previous
|
rename from dom/animation/AnimationPlayer.cpp rename to dom/animation/Animation.cpp --- a/dom/animation/AnimationPlayer.cpp +++ b/dom/animation/Animation.cpp @@ -1,44 +1,44 @@ /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "AnimationPlayer.h" +#include "Animation.h" #include "AnimationUtils.h" -#include "mozilla/dom/AnimationPlayerBinding.h" +#include "mozilla/dom/AnimationBinding.h" #include "mozilla/AutoRestore.h" -#include "AnimationCommon.h" // For AnimationPlayerCollection, +#include "AnimationCommon.h" // For AnimationCollection, // CommonAnimationManager #include "nsIDocument.h" // For nsIDocument #include "nsIPresShell.h" // For nsIPresShell #include "nsLayoutUtils.h" // For PostRestyleEvent (remove after bug 1073336) -#include "PendingPlayerTracker.h" // For PendingPlayerTracker +#include "PendingAnimationTracker.h" // For PendingAnimationTracker namespace mozilla { namespace dom { -NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(AnimationPlayer, mTimeline, +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(Animation, mTimeline, mEffect, mReady, mFinished) -NS_IMPL_CYCLE_COLLECTING_ADDREF(AnimationPlayer) -NS_IMPL_CYCLE_COLLECTING_RELEASE(AnimationPlayer) -NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AnimationPlayer) +NS_IMPL_CYCLE_COLLECTING_ADDREF(Animation) +NS_IMPL_CYCLE_COLLECTING_RELEASE(Animation) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(Animation) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END JSObject* -AnimationPlayer::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) +Animation::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) { - return dom::AnimationPlayerBinding::Wrap(aCx, this, aGivenProto); + return dom::AnimationBinding::Wrap(aCx, this, aGivenProto); } void -AnimationPlayer::SetStartTime(const Nullable<TimeDuration>& aNewStartTime) +Animation::SetStartTime(const Nullable<TimeDuration>& aNewStartTime) { #if 1 // Bug 1096776: once we support inactive/missing timelines we'll want to take // the disabled branch. MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(), "We don't support inactive/missing timelines yet"); #else Nullable<TimeDuration> timelineTime = mTimeline->GetCurrentTime(); @@ -69,17 +69,17 @@ AnimationPlayer::SetStartTime(const Null mReady->MaybeResolve(this); } UpdateTiming(); PostUpdate(); } Nullable<TimeDuration> -AnimationPlayer::GetCurrentTime() const +Animation::GetCurrentTime() const { Nullable<TimeDuration> result; if (!mHoldTime.IsNull()) { result = mHoldTime; return result; } if (!mStartTime.IsNull()) { @@ -89,17 +89,17 @@ AnimationPlayer::GetCurrentTime() const .MultDouble(mPlaybackRate)); } } return result; } // Implements http://w3c.github.io/web-animations/#silently-set-the-current-time void -AnimationPlayer::SilentlySetCurrentTime(const TimeDuration& aSeekTime) +Animation::SilentlySetCurrentTime(const TimeDuration& aSeekTime) { if (!mHoldTime.IsNull() || !mTimeline || mTimeline->GetCurrentTime().IsNull() || mPlaybackRate == 0.0 /*or, once supported, if we have a pending pause task*/) { mHoldTime.SetValue(aSeekTime); if (!mTimeline || mTimeline->GetCurrentTime().IsNull()) { @@ -110,58 +110,58 @@ AnimationPlayer::SilentlySetCurrentTime( (aSeekTime.MultDouble(1 / mPlaybackRate))); } mPreviousCurrentTime.SetNull(); } // Implements http://w3c.github.io/web-animations/#set-the-current-time void -AnimationPlayer::SetCurrentTime(const TimeDuration& aSeekTime) +Animation::SetCurrentTime(const TimeDuration& aSeekTime) { SilentlySetCurrentTime(aSeekTime); if (mPendingState == PendingState::PausePending) { CancelPendingTasks(); if (mReady) { mReady->MaybeResolve(this); } } UpdateFinishedState(true); UpdateEffect(); PostUpdate(); } void -AnimationPlayer::SetPlaybackRate(double aPlaybackRate) +Animation::SetPlaybackRate(double aPlaybackRate) { Nullable<TimeDuration> previousTime = GetCurrentTime(); mPlaybackRate = aPlaybackRate; if (!previousTime.IsNull()) { ErrorResult rv; SetCurrentTime(previousTime.Value()); MOZ_ASSERT(!rv.Failed(), "Should not assert for non-null time"); } } void -AnimationPlayer::SilentlySetPlaybackRate(double aPlaybackRate) +Animation::SilentlySetPlaybackRate(double aPlaybackRate) { Nullable<TimeDuration> previousTime = GetCurrentTime(); mPlaybackRate = aPlaybackRate; if (!previousTime.IsNull()) { ErrorResult rv; SilentlySetCurrentTime(previousTime.Value()); MOZ_ASSERT(!rv.Failed(), "Should not assert for non-null time"); } } AnimationPlayState -AnimationPlayer::PlayState() const +Animation::PlayState() const { if (mPendingState != PendingState::NotPending) { return AnimationPlayState::Pending; } Nullable<TimeDuration> currentTime = GetCurrentTime(); if (currentTime.IsNull()) { return AnimationPlayState::Idle; @@ -185,155 +185,156 @@ CreatePromise(DocumentTimeline* aTimelin nsIGlobalObject* global = aTimeline->GetParentObject(); if (global) { return Promise::Create(global, aRv); } return nullptr; } Promise* -AnimationPlayer::GetReady(ErrorResult& aRv) +Animation::GetReady(ErrorResult& aRv) { if (!mReady) { mReady = CreatePromise(mTimeline, aRv); // Lazily create on demand } if (!mReady) { aRv.Throw(NS_ERROR_FAILURE); } else if (PlayState() != AnimationPlayState::Pending) { mReady->MaybeResolve(this); } return mReady; } Promise* -AnimationPlayer::GetFinished(ErrorResult& aRv) +Animation::GetFinished(ErrorResult& aRv) { if (!mFinished) { mFinished = CreatePromise(mTimeline, aRv); // Lazily create on demand } if (!mFinished) { aRv.Throw(NS_ERROR_FAILURE); } else if (IsFinished()) { mFinished->MaybeResolve(this); } return mFinished; } void -AnimationPlayer::Play(LimitBehavior aLimitBehavior) +Animation::Play(LimitBehavior aLimitBehavior) { DoPlay(aLimitBehavior); PostUpdate(); } void -AnimationPlayer::Pause() +Animation::Pause() { // TODO: The DoPause() call should not be synchronous (bug 1109390). See // http://w3c.github.io/web-animations/#pausing-an-animation-section DoPause(); PostUpdate(); } Nullable<double> -AnimationPlayer::GetStartTimeAsDouble() const +Animation::GetStartTimeAsDouble() const { return AnimationUtils::TimeDurationToDouble(mStartTime); } void -AnimationPlayer::SetStartTimeAsDouble(const Nullable<double>& aStartTime) +Animation::SetStartTimeAsDouble(const Nullable<double>& aStartTime) { return SetStartTime(AnimationUtils::DoubleToTimeDuration(aStartTime)); } - + Nullable<double> -AnimationPlayer::GetCurrentTimeAsDouble() const +Animation::GetCurrentTimeAsDouble() const { return AnimationUtils::TimeDurationToDouble(GetCurrentTime()); } void -AnimationPlayer::SetCurrentTimeAsDouble(const Nullable<double>& aCurrentTime, +Animation::SetCurrentTimeAsDouble(const Nullable<double>& aCurrentTime, ErrorResult& aRv) { if (aCurrentTime.IsNull()) { if (!GetCurrentTime().IsNull()) { aRv.Throw(NS_ERROR_DOM_TYPE_ERR); } return; } return SetCurrentTime(TimeDuration::FromMilliseconds(aCurrentTime.Value())); } void -AnimationPlayer::SetEffect(KeyframeEffectReadonly* aEffect) +Animation::SetEffect(KeyframeEffectReadonly* aEffect) { if (mEffect) { mEffect->SetParentTime(Nullable<TimeDuration>()); } mEffect = aEffect; if (mEffect) { mEffect->SetParentTime(GetCurrentTime()); } UpdateRelevance(); } void -AnimationPlayer::Tick() +Animation::Tick() { // Since we are not guaranteed to get only one call per refresh driver tick, // it's possible that mPendingReadyTime is set to a time in the future. // In that case, we should wait until the next refresh driver tick before // resuming. if (mPendingState != PendingState::NotPending && !mPendingReadyTime.IsNull() && mPendingReadyTime.Value() <= mTimeline->GetCurrentTime().Value()) { FinishPendingAt(mPendingReadyTime.Value()); mPendingReadyTime.SetNull(); } - if (IsPossiblyOrphanedPendingPlayer()) { + if (IsPossiblyOrphanedPendingAnimation()) { MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(), - "Orphaned pending players should have an active timeline"); + "Orphaned pending animtaions should have an active timeline"); FinishPendingAt(mTimeline->GetCurrentTime().Value()); } UpdateTiming(); } void -AnimationPlayer::TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime) +Animation::TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime) { // Normally we expect the play state to be pending but it's possible that, - // due to the handling of possibly orphaned players in Tick(), this player got - // started whilst still being in another document's pending player map. + // due to the handling of possibly orphaned animations in Tick(), this + // animation got started whilst still being in another document's pending + // animation map. if (PlayState() != AnimationPlayState::Pending) { return; } // If aReadyTime.IsNull() we'll detect this in Tick() where we check for - // orphaned players and trigger this animation anyway + // orphaned animations and trigger this animation anyway mPendingReadyTime = aReadyTime; } void -AnimationPlayer::TriggerNow() +Animation::TriggerNow() { MOZ_ASSERT(PlayState() == AnimationPlayState::Pending, - "Expected to start a pending player"); + "Expected to start a pending animation"); MOZ_ASSERT(mTimeline && !mTimeline->GetCurrentTime().IsNull(), "Expected an active timeline"); FinishPendingAt(mTimeline->GetCurrentTime().Value()); } Nullable<TimeDuration> -AnimationPlayer::GetCurrentOrPendingStartTime() const +Animation::GetCurrentOrPendingStartTime() const { Nullable<TimeDuration> result; if (!mStartTime.IsNull()) { result = mStartTime; return result; } @@ -344,17 +345,17 @@ AnimationPlayer::GetCurrentOrPendingStar // Calculate the equivalent start time from the pending ready time. // This is the same as the calculation performed in ResumeAt and will // need to incorporate the playbackRate when implemented (bug 1127380). result.SetValue(mPendingReadyTime.Value() - mHoldTime.Value()); return result; } void -AnimationPlayer::Cancel() +Animation::Cancel() { if (mPendingState != PendingState::NotPending) { CancelPendingTasks(); if (mReady) { mReady->MaybeReject(NS_ERROR_DOM_ABORT_ERR); } } @@ -366,31 +367,31 @@ AnimationPlayer::Cancel() mHoldTime.SetNull(); mStartTime.SetNull(); UpdateEffect(); } void -AnimationPlayer::UpdateRelevance() +Animation::UpdateRelevance() { bool wasRelevant = mIsRelevant; mIsRelevant = HasCurrentEffect() || IsInEffect(); // Notify animation observers. if (wasRelevant && !mIsRelevant) { nsNodeUtils::AnimationRemoved(this); } else if (!wasRelevant && mIsRelevant) { nsNodeUtils::AnimationAdded(this); } } bool -AnimationPlayer::CanThrottle() const +Animation::CanThrottle() const { if (!mEffect || mEffect->IsFinishedTransition() || mEffect->Properties().IsEmpty()) { return true; } if (!mIsRunningOnCompositor) { @@ -405,19 +406,19 @@ AnimationPlayer::CanThrottle() const // The animation has finished but, if this is the first sample since // finishing, we need an unthrottled sample so we can apply the correct // end-of-animation behavior on the main thread (either removing the // animation style or applying the fill mode). return mFinishedAtLastComposeStyle; } void -AnimationPlayer::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule, - nsCSSPropertySet& aSetProperties, - bool& aNeedsRefreshes) +Animation::ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule, + nsCSSPropertySet& aSetProperties, + bool& aNeedsRefreshes) { if (!mEffect || mEffect->IsFinishedTransition()) { return; } AnimationPlayState playState = PlayState(); if (playState == AnimationPlayState::Running || playState == AnimationPlayState::Pending) { @@ -488,17 +489,17 @@ AnimationPlayer::ComposeStyle(nsRefPtr<c UpdateTiming(); } mFinishedAtLastComposeStyle = (playState == AnimationPlayState::Finished); } } void -AnimationPlayer::DoPlay(LimitBehavior aLimitBehavior) +Animation::DoPlay(LimitBehavior aLimitBehavior) { bool abortedPause = mPendingState == PendingState::PausePending; bool reuseReadyPromise = false; if (mPendingState != PendingState::NotPending) { CancelPendingTasks(); reuseReadyPromise = true; } @@ -543,25 +544,25 @@ AnimationPlayer::DoPlay(LimitBehavior aL mPendingState = PendingState::PlayPending; nsIDocument* doc = GetRenderedDocument(); if (!doc) { TriggerOnNextTick(Nullable<TimeDuration>()); return; } - PendingPlayerTracker* tracker = doc->GetOrCreatePendingPlayerTracker(); + PendingAnimationTracker* tracker = doc->GetOrCreatePendingAnimationTracker(); tracker->AddPlayPending(*this); // We may have updated the current time when we set the hold time above. UpdateTiming(); } void -AnimationPlayer::DoPause() +Animation::DoPause() { if (IsPausedOrPausing()) { return; } bool reuseReadyPromise = false; if (mPendingState == PendingState::PlayPending) { CancelPendingTasks(); @@ -581,32 +582,32 @@ AnimationPlayer::DoPause() mPendingState = PendingState::PausePending; nsIDocument* doc = GetRenderedDocument(); if (!doc) { TriggerOnNextTick(Nullable<TimeDuration>()); return; } - PendingPlayerTracker* tracker = doc->GetOrCreatePendingPlayerTracker(); + PendingAnimationTracker* tracker = doc->GetOrCreatePendingAnimationTracker(); tracker->AddPausePending(*this); UpdateFinishedState(); } void -AnimationPlayer::ResumeAt(const TimeDuration& aReadyTime) +Animation::ResumeAt(const TimeDuration& aReadyTime) { - // This method is only expected to be called for a player that is + // This method is only expected to be called for an animation that is // waiting to play. We can easily adapt it to handle other states // but it's currently not necessary. MOZ_ASSERT(mPendingState == PendingState::PlayPending, - "Expected to resume a play-pending player"); + "Expected to resume a play-pending animation"); MOZ_ASSERT(mHoldTime.IsNull() != mStartTime.IsNull(), - "A player in the play-pending state should have either a" + "An animation in the play-pending state should have either a" " resolved hold time or resolved start time (but not both)"); // If we aborted a pending pause operation we will already have a start time // we should use. In all other cases, we resolve it from the ready time. if (mStartTime.IsNull()) { if (mPlaybackRate != 0) { mStartTime.SetValue(aReadyTime - (mHoldTime.Value().MultDouble(1 / mPlaybackRate))); @@ -620,46 +621,46 @@ AnimationPlayer::ResumeAt(const TimeDura UpdateTiming(); if (mReady) { mReady->MaybeResolve(this); } } void -AnimationPlayer::PauseAt(const TimeDuration& aReadyTime) +Animation::PauseAt(const TimeDuration& aReadyTime) { MOZ_ASSERT(mPendingState == PendingState::PausePending, - "Expected to pause a pause-pending player"); + "Expected to pause a pause-pending animation"); if (!mStartTime.IsNull()) { mHoldTime.SetValue((aReadyTime - mStartTime.Value()) .MultDouble(mPlaybackRate)); } mStartTime.SetNull(); mPendingState = PendingState::NotPending; UpdateTiming(); if (mReady) { mReady->MaybeResolve(this); } } void -AnimationPlayer::UpdateTiming() +Animation::UpdateTiming() { // We call UpdateFinishedState before UpdateEffect because the former // can change the current time, which is used by the latter. UpdateFinishedState(); UpdateEffect(); } void -AnimationPlayer::UpdateFinishedState(bool aSeekFlag) +Animation::UpdateFinishedState(bool aSeekFlag) { Nullable<TimeDuration> currentTime = GetCurrentTime(); TimeDuration effectEnd = TimeDuration(EffectEnd()); if (!mStartTime.IsNull() && mPendingState == PendingState::NotPending) { if (mPlaybackRate > 0.0 && !currentTime.IsNull() && @@ -692,102 +693,105 @@ AnimationPlayer::UpdateFinishedState(boo bool currentFinishedState = IsFinished(); if (currentFinishedState && !mIsPreviousStateFinished) { if (mFinished) { mFinished->MaybeResolve(this); } } else if (!currentFinishedState && mIsPreviousStateFinished) { // Clear finished promise. We'll create a new one lazily. mFinished = nullptr; + if (mEffect->AsTransition()) { + mEffect->SetIsFinishedTransition(false); + } } mIsPreviousStateFinished = currentFinishedState; // We must recalculate the current time to take account of any mHoldTime // changes the code above made. mPreviousCurrentTime = GetCurrentTime(); } void -AnimationPlayer::UpdateEffect() +Animation::UpdateEffect() { if (mEffect) { mEffect->SetParentTime(GetCurrentTime()); UpdateRelevance(); } } void -AnimationPlayer::FlushStyle() const +Animation::FlushStyle() const { nsIDocument* doc = GetRenderedDocument(); if (doc) { doc->FlushPendingNotifications(Flush_Style); } } void -AnimationPlayer::PostUpdate() +Animation::PostUpdate() { - AnimationPlayerCollection* collection = GetCollection(); + AnimationCollection* collection = GetCollection(); if (collection) { - collection->NotifyPlayerUpdated(); + collection->NotifyAnimationUpdated(); } } void -AnimationPlayer::CancelPendingTasks() +Animation::CancelPendingTasks() { if (mPendingState == PendingState::NotPending) { return; } nsIDocument* doc = GetRenderedDocument(); if (doc) { - PendingPlayerTracker* tracker = doc->GetPendingPlayerTracker(); + PendingAnimationTracker* tracker = doc->GetPendingAnimationTracker(); if (tracker) { if (mPendingState == PendingState::PlayPending) { tracker->RemovePlayPending(*this); } else { tracker->RemovePausePending(*this); } } } mPendingState = PendingState::NotPending; mPendingReadyTime.SetNull(); } bool -AnimationPlayer::IsFinished() const +Animation::IsFinished() const { // Unfortunately there's some weirdness in the spec at the moment where if // you're finished and paused, the playState is paused. This prevents us // from just checking |PlayState() == AnimationPlayState::Finished| here, // and we need this much more messy check to see if we're finished. Nullable<TimeDuration> currentTime = GetCurrentTime(); return !currentTime.IsNull() && ((mPlaybackRate > 0.0 && currentTime.Value() >= EffectEnd()) || (mPlaybackRate < 0.0 && currentTime.Value().ToMilliseconds() <= 0.0)); } bool -AnimationPlayer::IsPossiblyOrphanedPendingPlayer() const +Animation::IsPossiblyOrphanedPendingAnimation() const { // Check if we are pending but might never start because we are not being // tracked. // // This covers the following cases: // // * We started playing but our effect's target element was orphaned // or bound to a different document. // (note that for the case of our effect changing we should handle // that in SetEffect) // * We started playing but our timeline became inactive. - // In this case the pending player tracker will drop us from its hashmap + // In this case the pending animation tracker will drop us from its hashmap // when we have been painted. - // * When we started playing we couldn't find a PendingPlayerTracker to + // * When we started playing we couldn't find a PendingAnimationTracker to // register with (perhaps the effect had no document) so we simply // set mPendingState in DoPlay and relied on this method to catch us on the // next tick. // If we're not pending we're ok. if (mPendingState == PendingState::NotPending) { return false; } @@ -800,86 +804,87 @@ AnimationPlayer::IsPossiblyOrphanedPendi // If we don't have an active timeline then we shouldn't start until // we do. if (!mTimeline || mTimeline->GetCurrentTime().IsNull()) { return false; } // If we have no rendered document, or we're not in our rendered document's - // PendingPlayerTracker then there's a good chance no one is tracking us. + // PendingAnimationTracker then there's a good chance no one is tracking us. // // If we're wrong and another document is tracking us then, at worst, we'll // simply start/pause the animation one tick too soon. That's better than // never starting/pausing the animation and is unlikely. nsIDocument* doc = GetRenderedDocument(); if (!doc) { return false; } - PendingPlayerTracker* tracker = doc->GetPendingPlayerTracker(); + PendingAnimationTracker* tracker = doc->GetPendingAnimationTracker(); return !tracker || (!tracker->IsWaitingToPlay(*this) && !tracker->IsWaitingToPause(*this)); } StickyTimeDuration -AnimationPlayer::EffectEnd() const +Animation::EffectEnd() const { if (!mEffect) { return StickyTimeDuration(0); } return mEffect->Timing().mDelay + mEffect->GetComputedTiming().mActiveDuration; } nsIDocument* -AnimationPlayer::GetRenderedDocument() const +Animation::GetRenderedDocument() const { if (!mEffect) { return nullptr; } Element* targetElement; nsCSSPseudoElements::Type pseudoType; mEffect->GetTarget(targetElement, pseudoType); if (!targetElement) { return nullptr; } return targetElement->GetComposedDoc(); } nsPresContext* -AnimationPlayer::GetPresContext() const +Animation::GetPresContext() const { nsIDocument* doc = GetRenderedDocument(); if (!doc) { return nullptr; } nsIPresShell* shell = doc->GetShell(); if (!shell) { return nullptr; } return shell->GetPresContext(); } -AnimationPlayerCollection* -AnimationPlayer::GetCollection() const +AnimationCollection* +Animation::GetCollection() const { css::CommonAnimationManager* manager = GetAnimationManager(); if (!manager) { return nullptr; } - MOZ_ASSERT(mEffect, "A player with an animation manager must have an effect"); + MOZ_ASSERT(mEffect, + "An animation with an animation manager must have an effect"); Element* targetElement; nsCSSPseudoElements::Type targetPseudoType; mEffect->GetTarget(targetElement, targetPseudoType); MOZ_ASSERT(targetElement, - "A player with an animation manager must have a target"); + "An animation with an animation manager must have a target"); return manager->GetAnimations(targetElement, targetPseudoType, false); } } // namespace dom } // namespace mozilla
rename from dom/animation/AnimationPlayer.h rename to dom/animation/Animation.h --- a/dom/animation/AnimationPlayer.h +++ b/dom/animation/Animation.h @@ -1,21 +1,21 @@ /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef mozilla_dom_AnimationPlayer_h -#define mozilla_dom_AnimationPlayer_h +#ifndef mozilla_dom_Animation_h +#define mozilla_dom_Animation_h #include "nsWrapperCache.h" #include "nsCycleCollectionParticipant.h" #include "mozilla/Attributes.h" #include "mozilla/TimeStamp.h" // for TimeStamp, TimeDuration -#include "mozilla/dom/AnimationPlayerBinding.h" // for AnimationPlayState +#include "mozilla/dom/AnimationBinding.h" // for AnimationPlayState #include "mozilla/dom/DocumentTimeline.h" // for DocumentTimeline #include "mozilla/dom/KeyframeEffect.h" // for KeyframeEffectReadonly #include "mozilla/dom/Promise.h" // for Promise #include "nsCSSProperty.h" // for nsCSSProperty // X11 has a #define for CurrentTime. #ifdef CurrentTime #undef CurrentTime @@ -28,63 +28,64 @@ #endif struct JSContext; class nsCSSPropertySet; class nsIDocument; class nsPresContext; namespace mozilla { -struct AnimationPlayerCollection; +struct AnimationCollection; namespace css { class AnimValuesStyleRule; class CommonAnimationManager; } // namespace css -class CSSAnimationPlayer; -class CSSTransitionPlayer; +class CSSAnimation; +class CSSTransition; namespace dom { -class AnimationPlayer : public nsISupports, - public nsWrapperCache +class Animation + : public nsISupports + , public nsWrapperCache { protected: - virtual ~AnimationPlayer() {} + virtual ~Animation() {} public: - explicit AnimationPlayer(DocumentTimeline* aTimeline) + explicit Animation(DocumentTimeline* aTimeline) : mTimeline(aTimeline) , mPlaybackRate(1.0) , mPendingState(PendingState::NotPending) , mIsRunningOnCompositor(false) , mIsPreviousStateFinished(false) , mFinishedAtLastComposeStyle(false) , mIsRelevant(false) { } NS_DECL_CYCLE_COLLECTING_ISUPPORTS - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(AnimationPlayer) + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(Animation) DocumentTimeline* GetParentObject() const { return mTimeline; } virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override; - virtual CSSAnimationPlayer* AsCSSAnimationPlayer() { return nullptr; } - virtual CSSTransitionPlayer* AsCSSTransitionPlayer() { return nullptr; } + virtual CSSAnimation* AsCSSAnimation() { return nullptr; } + virtual CSSTransition* AsCSSTransition() { return nullptr; } // Flag to pass to DoPlay to indicate that it should not carry out finishing // behavior (reset the current time to the beginning of the active duration). enum LimitBehavior { AutoRewind = 0, Continue = 1 }; - // AnimationPlayer methods + // Animation methods KeyframeEffectReadonly* GetEffect() const { return mEffect; } DocumentTimeline* Timeline() const { return mTimeline; } Nullable<TimeDuration> GetStartTime() const { return mStartTime; } void SetStartTime(const Nullable<TimeDuration>& aNewStartTime); Nullable<TimeDuration> GetCurrentTime() const; void SilentlySetCurrentTime(const TimeDuration& aNewCurrentTime); void SetCurrentTime(const TimeDuration& aNewCurrentTime); double PlaybackRate() const { return mPlaybackRate; } @@ -92,96 +93,96 @@ public: void SilentlySetPlaybackRate(double aPlaybackRate); AnimationPlayState PlayState() const; virtual Promise* GetReady(ErrorResult& aRv); virtual Promise* GetFinished(ErrorResult& aRv); virtual void Play(LimitBehavior aLimitBehavior); virtual void Pause(); bool IsRunningOnCompositor() const { return mIsRunningOnCompositor; } - // Wrapper functions for AnimationPlayer DOM methods when called + // Wrapper functions for Animation DOM methods when called // from script. We often use the same methods internally and from // script but when called from script we (or one of our subclasses) perform // extra steps such as flushing style or converting the return type. Nullable<double> GetStartTimeAsDouble() const; void SetStartTimeAsDouble(const Nullable<double>& aStartTime); Nullable<double> GetCurrentTimeAsDouble() const; void SetCurrentTimeAsDouble(const Nullable<double>& aCurrentTime, ErrorResult& aRv); virtual AnimationPlayState PlayStateFromJS() const { return PlayState(); } virtual void PlayFromJS() { Play(LimitBehavior::AutoRewind); } // PauseFromJS is currently only here for symmetry with PlayFromJS but // in future we will likely have to flush style in - // CSSAnimationPlayer::PauseFromJS so we leave it for now. + // CSSAnimation::PauseFromJS so we leave it for now. void PauseFromJS() { Pause(); } void SetEffect(KeyframeEffectReadonly* aEffect); void Tick(); /** - * Set the time to use for starting or pausing a pending player. + * Set the time to use for starting or pausing a pending animation. * - * Typically, when a player is played, it does not start immediately but is - * added to a table of pending players on the document of its effect. + * Typically, when an animation is played, it does not start immediately but + * is added to a table of pending animations on the document of its effect. * In the meantime it sets its hold time to the time from which playback * should begin. * - * When the document finishes painting, any pending players in its table + * When the document finishes painting, any pending animations in its table * are marked as being ready to start by calling StartOnNextTick. * The moment when the paint completed is also recorded, converted to a * timeline time, and passed to StartOnTick. This is so that when these - * players do start, they can be timed from the point when painting + * animations do start, they can be timed from the point when painting * completed. * - * After calling TriggerOnNextTick, players remain in the pending state until - * the next refresh driver tick. At that time they transition out of the - * pending state using the time passed to TriggerOnNextTick as the effective - * time at which they resumed. + * After calling TriggerOnNextTick, animations remain in the pending state + * until the next refresh driver tick. At that time they transition out of + * the pending state using the time passed to TriggerOnNextTick as the + * effective time at which they resumed. * * This approach means that any setup time required for performing the * initial paint of an animation such as layerization is not deducted from * the running time of the animation. Without this we can easily drop the * first few frames of an animation, or, on slower devices, the whole * animation. * * Furthermore: * - * - Starting the player immediately when painting finishes is problematic - * because the start time of the player will be ahead of its timeline + * - Starting the animation immediately when painting finishes is problematic + * because the start time of the animation will be ahead of its timeline * (since the timeline time is based on the refresh driver time). - * That's a problem because the player is playing but its timing suggests - * it starts in the future. We could update the timeline to match the start - * time of the player but then we'd also have to update the timing and style - * of all animations connected to that timeline or else be stuck in an - * inconsistent state until the next refresh driver tick. + * That's a problem because the animation is playing but its timing + * suggests it starts in the future. We could update the timeline to match + * the start time of the animation but then we'd also have to update the + * timing and style of all animations connected to that timeline or else be + * stuck in an inconsistent state until the next refresh driver tick. * * - If we simply use the refresh driver time on its next tick, the lag * between triggering an animation and its effective start is unacceptably * long. * * For pausing, we apply the same asynchronous approach. This is so that we * synchronize with animations that are running on the compositor. Otherwise * if the main thread lags behind the compositor there will be a noticeable * jump backwards when the main thread takes over. Even though main thread * animations could be paused immediately, we do it asynchronously for * consistency and so that animations paused together end up in step. * - * Note that the caller of this method is responsible for removing the player - * from any PendingPlayerTracker it may have been added to. + * Note that the caller of this method is responsible for removing the + * animation from any PendingAnimationTracker it may have been added to. */ void TriggerOnNextTick(const Nullable<TimeDuration>& aReadyTime); - // Testing only: Start or pause a pending player using the current timeline + // Testing only: Start or pause a pending animation using the current timeline // time. This is used to support existing tests that expect animations to // begin immediately. Ideally we would rewrite the those tests and get rid of // this method, but there are a lot of them. // // As with TriggerOnNextTick, the caller of this method is responsible for - // removing the player from any PendingPlayerTracker it may have been added - // to. + // removing the animation from any PendingAnimationTracker it may have been + // added to. void TriggerNow(); /** * When StartOnNextTick is called, we store the ready time but we don't apply * it until the next tick. In the meantime, GetStartTime() will return null. * * However, if we build layer animations again before the next tick, we * should initialize them with the start time that GetStartTime() will return @@ -248,21 +249,21 @@ public: void SetIsRunningOnCompositor() { mIsRunningOnCompositor = true; } void ClearIsRunningOnCompositor() { mIsRunningOnCompositor = false; } // Returns true if this animation does not currently need to update // style on the main thread (e.g. because it is empty, or is // running on the compositor). bool CanThrottle() const; - // Updates |aStyleRule| with the animation values of this player's effect, + // Updates |aStyleRule| with the animation values of this animation's effect, // if any. // Any properties already contained in |aSetProperties| are not changed. Any // properties that are changed are added to |aSetProperties|. - // |aNeedsRefreshes| will be set to true if this player expects to update + // |aNeedsRefreshes| will be set to true if this animation expects to update // the style rule on the next refresh driver tick as well (because it // is running and has an effect to sample). void ComposeStyle(nsRefPtr<css::AnimValuesStyleRule>& aStyleRule, nsCSSPropertySet& aSetProperties, bool& aNeedsRefreshes); protected: void DoPlay(LimitBehavior aLimitBehavior); @@ -281,59 +282,59 @@ protected: } void UpdateTiming(); void UpdateFinishedState(bool aSeekFlag = false); void UpdateEffect(); void FlushStyle() const; void PostUpdate(); /** - * Remove this player from the pending player tracker and reset + * Remove this animation from the pending animation tracker and reset * mPendingState as necessary. The caller is responsible for resolving or * aborting the mReady promise as necessary. */ void CancelPendingTasks(); bool IsFinished() const; - bool IsPossiblyOrphanedPendingPlayer() const; + bool IsPossiblyOrphanedPendingAnimation() const; StickyTimeDuration EffectEnd() const; nsIDocument* GetRenderedDocument() const; nsPresContext* GetPresContext() const; virtual css::CommonAnimationManager* GetAnimationManager() const = 0; - AnimationPlayerCollection* GetCollection() const; + AnimationCollection* GetCollection() const; nsRefPtr<DocumentTimeline> mTimeline; nsRefPtr<KeyframeEffectReadonly> mEffect; // The beginning of the delay period. Nullable<TimeDuration> mStartTime; // Timeline timescale - Nullable<TimeDuration> mHoldTime; // Player timescale + Nullable<TimeDuration> mHoldTime; // Animation timescale Nullable<TimeDuration> mPendingReadyTime; // Timeline timescale - Nullable<TimeDuration> mPreviousCurrentTime; // Player timescale + Nullable<TimeDuration> mPreviousCurrentTime; // Animation timescale double mPlaybackRate; // A Promise that is replaced on each call to Play() (and in future Pause()) // and fulfilled when Play() is successfully completed. // This object is lazily created by GetReady. // See http://w3c.github.io/web-animations/#current-ready-promise nsRefPtr<Promise> mReady; // A Promise that is resolved when we reach the end of the effect, or // 0 when playing backwards. The Promise is replaced if the animation is // finished but then a state change makes it not finished. // This object is lazily created by GetFinished. // See http://w3c.github.io/web-animations/#current-finished-promise nsRefPtr<Promise> mFinished; - // Indicates if the player is in the pending state (and what state it is + // Indicates if the animation is in the pending state (and what state it is // waiting to enter when it finished pending). We use this rather than - // checking if this player is tracked by a PendingPlayerTracker because the - // player will continue to be pending even after it has been removed from the - // PendingPlayerTracker while it is waiting for the next tick + // checking if this animation is tracked by a PendingAnimationTracker because + // the animation will continue to be pending even after it has been removed + // from the PendingAnimationTracker while it is waiting for the next tick // (see TriggerOnNextTick for details). enum class PendingState { NotPending, PlayPending, PausePending }; PendingState mPendingState; bool mIsRunningOnCompositor; // Indicates whether we were in the finished state during our // most recent unthrottled sample (our last ComposeStyle call). bool mIsPreviousStateFinished; // Spec calls this "previous finished state" @@ -341,9 +342,9 @@ protected: // Indicates that the animation should be exposed in an element's // getAnimations() list. bool mIsRelevant; }; } // namespace dom } // namespace mozilla -#endif // mozilla_dom_AnimationPlayer_h +#endif // mozilla_dom_Animation_h
--- a/dom/animation/KeyframeEffect.cpp +++ b/dom/animation/KeyframeEffect.cpp @@ -229,32 +229,32 @@ KeyframeEffectReadonly::ActiveDuration(c : StickyTimeDuration::Forever(); } return StickyTimeDuration( aTiming.mIterationDuration.MultDouble(aTiming.mIterationCount)); } // http://w3c.github.io/web-animations/#in-play bool -KeyframeEffectReadonly::IsInPlay(const AnimationPlayer& aPlayer) const +KeyframeEffectReadonly::IsInPlay(const Animation& aAnimation) const { if (IsFinishedTransition() || - aPlayer.PlayState() == AnimationPlayState::Finished) { + aAnimation.PlayState() == AnimationPlayState::Finished) { return false; } return GetComputedTiming().mPhase == ComputedTiming::AnimationPhase_Active; } // http://w3c.github.io/web-animations/#current bool -KeyframeEffectReadonly::IsCurrent(const AnimationPlayer& aPlayer) const +KeyframeEffectReadonly::IsCurrent(const Animation& aAnimation) const { if (IsFinishedTransition() || - aPlayer.PlayState() == AnimationPlayState::Finished) { + aAnimation.PlayState() == AnimationPlayState::Finished) { return false; } ComputedTiming computedTiming = GetComputedTiming(); return computedTiming.mPhase == ComputedTiming::AnimationPhase_Before || computedTiming.mPhase == ComputedTiming::AnimationPhase_Active; } @@ -320,17 +320,17 @@ KeyframeEffectReadonly::ComposeStyle( { const AnimationProperty& prop = mProperties[propIdx]; MOZ_ASSERT(prop.mSegments[0].mFromKey == 0.0, "incorrect first from key"); MOZ_ASSERT(prop.mSegments[prop.mSegments.Length() - 1].mToKey == 1.0, "incorrect last to key"); if (aSetProperties.HasProperty(prop.mProperty)) { - // Animations are composed by AnimationPlayerCollection by iterating + // Animations are composed by AnimationCollection by iterating // from the last animation to first. For animations targetting the // same property, the later one wins. So if this property is already set, // we should not override it. continue; } if (!prop.mWinsInCascade) { // This isn't the winning declaration, so don't add it to style.
--- a/dom/animation/KeyframeEffect.h +++ b/dom/animation/KeyframeEffect.h @@ -295,24 +295,24 @@ public: // After transitions finish they need to be retained in order to // address the issue described in // https://lists.w3.org/Archives/Public/www-style/2015Jan/0444.html . // However, finished transitions are ignored for many purposes. bool IsFinishedTransition() const { return mIsFinishedTransition; } - void SetIsFinishedTransition() { + void SetIsFinishedTransition(bool aIsFinished) { MOZ_ASSERT(AsTransition(), "Calling SetIsFinishedTransition but it's not a transition"); - mIsFinishedTransition = true; + mIsFinishedTransition = aIsFinished; } - bool IsInPlay(const AnimationPlayer& aPlayer) const; - bool IsCurrent(const AnimationPlayer& aPlayer) const; + bool IsInPlay(const Animation& aAnimation) const; + bool IsCurrent(const Animation& aAnimation) const; bool IsInEffect() const; const AnimationProperty* GetAnimationOfProperty(nsCSSProperty aProperty) const; bool HasAnimationOfProperty(nsCSSProperty aProperty) const { return GetAnimationOfProperty(aProperty) != nullptr; } bool HasAnimationOfProperties(const nsCSSProperty* aProperties,
rename from dom/animation/PendingPlayerTracker.cpp rename to dom/animation/PendingAnimationTracker.cpp --- a/dom/animation/PendingPlayerTracker.cpp +++ b/dom/animation/PendingAnimationTracker.cpp @@ -1,108 +1,108 @@ /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#include "PendingPlayerTracker.h" +#include "PendingAnimationTracker.h" #include "mozilla/dom/DocumentTimeline.h" #include "nsIFrame.h" #include "nsIPresShell.h" using namespace mozilla; namespace mozilla { -NS_IMPL_CYCLE_COLLECTION(PendingPlayerTracker, +NS_IMPL_CYCLE_COLLECTION(PendingAnimationTracker, mPlayPendingSet, mPausePendingSet, mDocument) -NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PendingPlayerTracker, AddRef) -NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PendingPlayerTracker, Release) +NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(PendingAnimationTracker, AddRef) +NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(PendingAnimationTracker, Release) void -PendingPlayerTracker::AddPending(dom::AnimationPlayer& aPlayer, - AnimationPlayerSet& aSet) +PendingAnimationTracker::AddPending(dom::Animation& aAnimation, + AnimationSet& aSet) { - aSet.PutEntry(&aPlayer); + aSet.PutEntry(&aAnimation); // Schedule a paint. Otherwise animations that don't trigger a paint by // themselves (e.g. CSS animations with an empty keyframes rule) won't // start until something else paints. EnsurePaintIsScheduled(); } void -PendingPlayerTracker::RemovePending(dom::AnimationPlayer& aPlayer, - AnimationPlayerSet& aSet) +PendingAnimationTracker::RemovePending(dom::Animation& aAnimation, + AnimationSet& aSet) { - aSet.RemoveEntry(&aPlayer); + aSet.RemoveEntry(&aAnimation); } bool -PendingPlayerTracker::IsWaiting(const dom::AnimationPlayer& aPlayer, - const AnimationPlayerSet& aSet) const +PendingAnimationTracker::IsWaiting(const dom::Animation& aAnimation, + const AnimationSet& aSet) const { - return aSet.Contains(const_cast<dom::AnimationPlayer*>(&aPlayer)); + return aSet.Contains(const_cast<dom::Animation*>(&aAnimation)); } PLDHashOperator -TriggerPlayerAtTime(nsRefPtrHashKey<dom::AnimationPlayer>* aKey, +TriggerAnimationAtTime(nsRefPtrHashKey<dom::Animation>* aKey, void* aReadyTime) { - dom::AnimationPlayer* player = aKey->GetKey(); - dom::DocumentTimeline* timeline = player->Timeline(); + dom::Animation* animation = aKey->GetKey(); + dom::DocumentTimeline* timeline = animation->Timeline(); // When the timeline's refresh driver is under test control, its values // have no correspondance to wallclock times so we shouldn't try to convert // aReadyTime (which is a wallclock time) to a timeline value. Instead, the - // animation player will be started/paused when the refresh driver is next - // advanced since this will trigger a call to TriggerPendingPlayersNow. + // animation will be started/paused when the refresh driver is next + // advanced since this will trigger a call to TriggerPendingAnimationsNow. if (timeline->IsUnderTestControl()) { return PL_DHASH_NEXT; } Nullable<TimeDuration> readyTime = timeline->ToTimelineTime(*static_cast<const TimeStamp*>(aReadyTime)); - player->TriggerOnNextTick(readyTime); + animation->TriggerOnNextTick(readyTime); return PL_DHASH_REMOVE; } void -PendingPlayerTracker::TriggerPendingPlayersOnNextTick(const TimeStamp& +PendingAnimationTracker::TriggerPendingAnimationsOnNextTick(const TimeStamp& aReadyTime) { - mPlayPendingSet.EnumerateEntries(TriggerPlayerAtTime, + mPlayPendingSet.EnumerateEntries(TriggerAnimationAtTime, const_cast<TimeStamp*>(&aReadyTime)); - mPausePendingSet.EnumerateEntries(TriggerPlayerAtTime, + mPausePendingSet.EnumerateEntries(TriggerAnimationAtTime, const_cast<TimeStamp*>(&aReadyTime)); } PLDHashOperator -TriggerPlayerNow(nsRefPtrHashKey<dom::AnimationPlayer>* aKey, void*) +TriggerAnimationNow(nsRefPtrHashKey<dom::Animation>* aKey, void*) { aKey->GetKey()->TriggerNow(); return PL_DHASH_NEXT; } void -PendingPlayerTracker::TriggerPendingPlayersNow() +PendingAnimationTracker::TriggerPendingAnimationsNow() { - mPlayPendingSet.EnumerateEntries(TriggerPlayerNow, nullptr); + mPlayPendingSet.EnumerateEntries(TriggerAnimationNow, nullptr); mPlayPendingSet.Clear(); - mPausePendingSet.EnumerateEntries(TriggerPlayerNow, nullptr); + mPausePendingSet.EnumerateEntries(TriggerAnimationNow, nullptr); mPausePendingSet.Clear(); } void -PendingPlayerTracker::EnsurePaintIsScheduled() +PendingAnimationTracker::EnsurePaintIsScheduled() { if (!mDocument) { return; } nsIPresShell* presShell = mDocument->GetShell(); if (!presShell) { return;
rename from dom/animation/PendingPlayerTracker.h rename to dom/animation/PendingAnimationTracker.h --- a/dom/animation/PendingPlayerTracker.h +++ b/dom/animation/PendingAnimationTracker.h @@ -1,86 +1,83 @@ /* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ -#ifndef mozilla_dom_PendingPlayerTracker_h -#define mozilla_dom_PendingPlayerTracker_h +#ifndef mozilla_dom_PendingAnimationTracker_h +#define mozilla_dom_PendingAnimationTracker_h -#include "mozilla/dom/AnimationPlayer.h" +#include "mozilla/dom/Animation.h" #include "nsCycleCollectionParticipant.h" #include "nsIDocument.h" #include "nsTHashtable.h" class nsIFrame; namespace mozilla { -class PendingPlayerTracker final +class PendingAnimationTracker final { public: - explicit PendingPlayerTracker(nsIDocument* aDocument) + explicit PendingAnimationTracker(nsIDocument* aDocument) : mDocument(aDocument) { } - NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PendingPlayerTracker) - NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(PendingPlayerTracker) + NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(PendingAnimationTracker) + NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(PendingAnimationTracker) - void AddPlayPending(dom::AnimationPlayer& aPlayer) + void AddPlayPending(dom::Animation& aAnimation) { - MOZ_ASSERT(!IsWaitingToPause(aPlayer), - "Player is already waiting to pause"); - AddPending(aPlayer, mPlayPendingSet); + MOZ_ASSERT(!IsWaitingToPause(aAnimation), + "Animation is already waiting to pause"); + AddPending(aAnimation, mPlayPendingSet); } - void RemovePlayPending(dom::AnimationPlayer& aPlayer) + void RemovePlayPending(dom::Animation& aAnimation) { - RemovePending(aPlayer, mPlayPendingSet); + RemovePending(aAnimation, mPlayPendingSet); } - bool IsWaitingToPlay(const dom::AnimationPlayer& aPlayer) const + bool IsWaitingToPlay(const dom::Animation& aAnimation) const { - return IsWaiting(aPlayer, mPlayPendingSet); + return IsWaiting(aAnimation, mPlayPendingSet); } - void AddPausePending(dom::AnimationPlayer& aPlayer) + void AddPausePending(dom::Animation& aAnimation) { - MOZ_ASSERT(!IsWaitingToPlay(aPlayer), - "Player is already waiting to play"); - AddPending(aPlayer, mPausePendingSet); + MOZ_ASSERT(!IsWaitingToPlay(aAnimation), + "Animation is already waiting to play"); + AddPending(aAnimation, mPausePendingSet); } - void RemovePausePending(dom::AnimationPlayer& aPlayer) + void RemovePausePending(dom::Animation& aAnimation) { - RemovePending(aPlayer, mPausePendingSet); + RemovePending(aAnimation, mPausePendingSet); } - bool IsWaitingToPause(const dom::AnimationPlayer& aPlayer) const + bool IsWaitingToPause(const dom::Animation& aAnimation) const { - return IsWaiting(aPlayer, mPausePendingSet); + return IsWaiting(aAnimation, mPausePendingSet); } - void TriggerPendingPlayersOnNextTick(const TimeStamp& aReadyTime); - void TriggerPendingPlayersNow(); - bool HasPendingPlayers() const { + void TriggerPendingAnimationsOnNextTick(const TimeStamp& aReadyTime); + void TriggerPendingAnimationsNow(); + bool HasPendingAnimations() const { return mPlayPendingSet.Count() > 0 || mPausePendingSet.Count() > 0; } private: - ~PendingPlayerTracker() { } + ~PendingAnimationTracker() { } void EnsurePaintIsScheduled(); - typedef nsTHashtable<nsRefPtrHashKey<dom::AnimationPlayer>> - AnimationPlayerSet; + typedef nsTHashtable<nsRefPtrHashKey<dom::Animation>> AnimationSet; - void AddPending(dom::AnimationPlayer& aPlayer, - AnimationPlayerSet& aSet); - void RemovePending(dom::AnimationPlayer& aPlayer, - AnimationPlayerSet& aSet); - bool IsWaiting(const dom::AnimationPlayer& aPlayer, - const AnimationPlayerSet& aSet) const; + void AddPending(dom::Animation& aAnimation, AnimationSet& aSet); + void RemovePending(dom::Animation& aAnimation, AnimationSet& aSet); + bool IsWaiting(const dom::Animation& aAnimation, + const AnimationSet& aSet) const; - AnimationPlayerSet mPlayPendingSet; - AnimationPlayerSet mPausePendingSet; + AnimationSet mPlayPendingSet; + AnimationSet mPausePendingSet; nsCOMPtr<nsIDocument> mDocument; }; } // namespace mozilla -#endif // mozilla_dom_PendingPlayerTracker_h +#endif // mozilla_dom_PendingAnimationTracker_h
--- a/dom/animation/moz.build +++ b/dom/animation/moz.build @@ -3,32 +3,32 @@ # This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. MOCHITEST_MANIFESTS += ['test/mochitest.ini'] MOCHITEST_CHROME_MANIFESTS += ['test/chrome.ini'] EXPORTS.mozilla.dom += [ + 'Animation.h', 'AnimationEffectReadonly.h', - 'AnimationPlayer.h', 'AnimationTimeline.h', 'DocumentTimeline.h', 'KeyframeEffect.h', ] EXPORTS.mozilla += [ 'AnimationUtils.h', - 'PendingPlayerTracker.h', + 'PendingAnimationTracker.h', ] UNIFIED_SOURCES += [ + 'Animation.cpp', 'AnimationEffectReadonly.cpp', - 'AnimationPlayer.cpp', 'AnimationTimeline.cpp', 'DocumentTimeline.cpp', 'KeyframeEffect.cpp', - 'PendingPlayerTracker.cpp', + 'PendingAnimationTracker.cpp', ] FAIL_ON_WARNINGS = True FINAL_LIBRARY = 'xul'
rename from dom/animation/test/css-animations/test_animation-player-currenttime.html rename to dom/animation/test/css-animations/test_animation-currenttime.html --- a/dom/animation/test/css-animations/test_animation-player-currenttime.html +++ b/dom/animation/test/css-animations/test_animation-currenttime.html @@ -188,21 +188,20 @@ function EventWatcher(watchedNode, event return this; } // The terms used for the naming of the following helper functions refer to // terms used in the Web Animations specification for specific phases of an // animation. The terms can be found here: // -// http://w3c.github.io/web-animations/#animation-node-phases-and-states +// https://w3c.github.io/web-animations/#animation-effect-phases-and-states // -// Note the distinction between "player start time" and "animation start time". -// The former is the start of the start delay. The latter is the start of the -// active interval. (If there is no delay, they are the same.) +// Note the distinction between the "animation start time" which occurs before +// the start delay and the start of the active interval which occurs after it. // Called when currentTime is set to zero (the beginning of the start delay). function checkStateOnSettingCurrentTimeToZero(animation) { // We don't test animation.currentTime since our caller just set it. assert_equals(animation.playState, 'running', 'Animation.playState should be "running" at the start of ' +
rename from dom/animation/test/css-animations/test_animation-player-finished.html rename to dom/animation/test/css-animations/test_animation-finished.html
rename from dom/animation/test/css-animations/test_animation-player-playstate.html rename to dom/animation/test/css-animations/test_animation-playstate.html
rename from dom/animation/test/css-animations/test_animation-player-ready.html rename to dom/animation/test/css-animations/test_animation-ready.html
rename from dom/animation/test/css-animations/test_animation-player-starttime.html rename to dom/animation/test/css-animations/test_animation-starttime.html --- a/dom/animation/test/css-animations/test_animation-player-starttime.html +++ b/dom/animation/test/css-animations/test_animation-starttime.html @@ -188,21 +188,20 @@ function EventWatcher(watchedNode, event return this; } // The terms used for the naming of the following helper functions refer to // terms used in the Web Animations specification for specific phases of an // animation. The terms can be found here: // -// http://w3c.github.io/web-animations/#animation-node-phases-and-states +// https://w3c.github.io/web-animations/#animation-effect-phases-and-states // -// Note the distinction between "player start time" and "animation start time". -// The former is the start of the start delay. The latter is the start of the -// active interval. (If there is no delay, they are the same.) +// Note the distinction between the "animation start time" which occurs before +// the start delay and the start of the active interval which occurs after it. // Called when the ready Promise's callbacks should happen function checkStateOnReadyPromiseResolved(animation) { assert_less_than_equal(animation.startTime, animation.timeline.currentTime, 'Animation.startTime should be less than the timeline\'s ' + 'currentTime on the first paint tick after animation creation');
rename from dom/animation/test/css-animations/test_element-get-animation-players.html rename to dom/animation/test/css-animations/test_element-get-animations.html
rename from dom/animation/test/css-transitions/test_animation-player-currenttime.html rename to dom/animation/test/css-transitions/test_animation-currenttime.html
rename from dom/animation/test/css-transitions/test_animation-player-ready.html rename to dom/animation/test/css-transitions/test_animation-ready.html
rename from dom/animation/test/css-transitions/test_animation-player-starttime.html rename to dom/animation/test/css-transitions/test_animation-starttime.html --- a/dom/animation/test/css-transitions/test_animation-player-starttime.html +++ b/dom/animation/test/css-transitions/test_animation-starttime.html @@ -178,21 +178,20 @@ function EventWatcher(watchedNode, event return this; } // The terms used for the naming of the following helper functions refer to // terms used in the Web Animations specification for specific phases of an // animation. The terms can be found here: // -// http://w3c.github.io/web-animations/#animation-effect-phases-and-states +// https://w3c.github.io/web-animations/#animation-effect-phases-and-states // -// Note the distinction between "player start time" and "animation start time". -// The former is the start of the start delay. The latter is the start of the -// active interval. (If there is no delay, they are the same.) +// Note the distinction between the "animation start time" which occurs before +// the start delay and the start of the active interval which occurs after it. // Called when the ready Promise's callbacks should happen function checkStateOnReadyPromiseResolved(animation) { assert_less_than_equal(animation.startTime, animation.timeline.currentTime, 'Animation.startTime should be less than the timeline\'s ' + 'currentTime on the first paint tick after animation creation');
rename from dom/animation/test/css-transitions/test_element-get-animation-players.html rename to dom/animation/test/css-transitions/test_element-get-animations.html
--- a/dom/animation/test/mochitest.ini +++ b/dom/animation/test/mochitest.ini @@ -1,27 +1,27 @@ [DEFAULT] support-files = testcommon.js [css-animations/test_animations-dynamic-changes.html] [css-animations/test_animation-pausing.html] -[css-animations/test_animation-player-currenttime.html] -[css-animations/test_animation-player-finished.html] -[css-animations/test_animation-player-playstate.html] -[css-animations/test_animation-player-ready.html] -[css-animations/test_animation-player-starttime.html] +[css-animations/test_animation-currenttime.html] +[css-animations/test_animation-finished.html] +[css-animations/test_animation-playstate.html] +[css-animations/test_animation-ready.html] +[css-animations/test_animation-starttime.html] [css-animations/test_effect-name.html] [css-animations/test_effect-target.html] -[css-animations/test_element-get-animation-players.html] +[css-animations/test_element-get-animations.html] skip-if = buildapp == 'mulet' [css-transitions/test_animation-pausing.html] -[css-transitions/test_animation-player-currenttime.html] -[css-transitions/test_animation-player-ready.html] -[css-transitions/test_animation-player-starttime.html] +[css-transitions/test_animation-currenttime.html] +[css-transitions/test_animation-ready.html] +[css-transitions/test_animation-starttime.html] [css-transitions/test_effect-name.html] [css-transitions/test_effect-target.html] -[css-transitions/test_element-get-animation-players.html] +[css-transitions/test_element-get-animations.html] skip-if = buildapp == 'mulet' [document-timeline/test_document-timeline.html] [document-timeline/test_request_animation_frame.html] skip-if = buildapp == 'mulet' [mozilla/test_deferred_start.html]
--- a/dom/asmjscache/AsmJSCache.cpp +++ b/dom/asmjscache/AsmJSCache.cpp @@ -999,17 +999,22 @@ MainProcessRunnable::Run() mState = eSendingCacheFile; NS_DispatchToMainThread(this); return NS_OK; } case eFailedToReadMetadata: { MOZ_ASSERT(NS_IsMainThread()); - CacheMiss(); + if (mOpenMode == eOpenForRead) { + CacheMiss(); + return NS_OK; + } + + Fail(); return NS_OK; } case eSendingMetadataForRead: { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mOpenMode == eOpenForRead); mState = eWaitingToOpenCacheFileForRead;
--- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -9,17 +9,17 @@ * of DOM Core's nsIDOMElement, implements nsIContent, provides * utility methods for subclasses, and so forth. */ #include "mozilla/dom/ElementInlines.h" #include "AnimationCommon.h" #include "mozilla/DebugOnly.h" -#include "mozilla/dom/AnimationPlayer.h" +#include "mozilla/dom/Animation.h" #include "mozilla/dom/Attr.h" #include "nsDOMAttributeMap.h" #include "nsIAtom.h" #include "nsIContentInlines.h" #include "mozilla/dom/NodeInfo.h" #include "nsIDocumentInlines.h" #include "nsIDOMNodeList.h" #include "nsIDOMDocument.h" @@ -3181,39 +3181,39 @@ Element::MozRequestFullScreen(JSContext* void Element::MozRequestPointerLock() { OwnerDoc()->RequestPointerLock(this); } void -Element::GetAnimations(nsTArray<nsRefPtr<AnimationPlayer> >& aAnimations) +Element::GetAnimations(nsTArray<nsRefPtr<Animation>>& aAnimations) { nsIDocument* doc = GetComposedDoc(); if (doc) { doc->FlushPendingNotifications(Flush_Style); } nsIAtom* properties[] = { nsGkAtoms::transitionsProperty, nsGkAtoms::animationsProperty }; for (size_t propIdx = 0; propIdx < MOZ_ARRAY_LENGTH(properties); propIdx++) { - AnimationPlayerCollection* collection = - static_cast<AnimationPlayerCollection*>( + AnimationCollection* collection = + static_cast<AnimationCollection*>( GetProperty(properties[propIdx])); if (!collection) { continue; } - for (size_t playerIdx = 0; - playerIdx < collection->mPlayers.Length(); - playerIdx++) { - AnimationPlayer* player = collection->mPlayers[playerIdx]; - if (player->IsRelevant()) { - aAnimations.AppendElement(player); + for (size_t animIdx = 0; + animIdx < collection->mAnimations.Length(); + animIdx++) { + Animation* anim = collection->mAnimations[animIdx]; + if (anim->IsRelevant()) { + aAnimations.AppendElement(anim); } } } } NS_IMETHODIMP Element::GetInnerHTML(nsAString& aInnerHTML) {
--- a/dom/base/Element.h +++ b/dom/base/Element.h @@ -116,17 +116,17 @@ namespace mozilla { class EventChainPostVisitor; class EventChainPreVisitor; class EventChainVisitor; class EventListenerManager; class EventStateManager; namespace dom { -class AnimationPlayer; +class Animation; class Link; class UndoManager; class DOMRect; class DOMRectList; class DestinationInsertionPointList; // IID for the dom::Element interface #define NS_ELEMENT_IID \ @@ -803,17 +803,17 @@ public: { return false; } virtual void SetUndoScope(bool aUndoScope, ErrorResult& aError) { } - void GetAnimations(nsTArray<nsRefPtr<AnimationPlayer> >& aAnimations); + void GetAnimations(nsTArray<nsRefPtr<Animation>>& aAnimations); NS_IMETHOD GetInnerHTML(nsAString& aInnerHTML); virtual void SetInnerHTML(const nsAString& aInnerHTML, ErrorResult& aError); void GetOuterHTML(nsAString& aOuterHTML); void SetOuterHTML(const nsAString& aOuterHTML, ErrorResult& aError); void InsertAdjacentHTML(const nsAString& aPosition, const nsAString& aText, ErrorResult& aError);
--- a/dom/base/nsDOMMutationObserver.cpp +++ b/dom/base/nsDOMMutationObserver.cpp @@ -9,17 +9,17 @@ #include "mozilla/dom/OwningNonNull.h" #include "nsError.h" #include "nsIScriptGlobalObject.h" #include "nsContentUtils.h" #include "nsThreadUtils.h" #include "nsIDOMMutationEvent.h" #include "nsTextFragment.h" #include "nsServiceManagerUtils.h" -#include "mozilla/dom/AnimationPlayer.h" +#include "mozilla/dom/Animation.h" #include "mozilla/dom/KeyframeEffect.h" nsAutoTArray<nsRefPtr<nsDOMMutationObserver>, 4>* nsDOMMutationObserver::sScheduledMutationObservers = nullptr; nsDOMMutationObserver* nsDOMMutationObserver::sCurrentObserver = nullptr; uint32_t nsDOMMutationObserver::sMutationLevel = 0; @@ -320,20 +320,20 @@ nsMutationReceiver::ContentRemoved(nsIDo void nsMutationReceiver::NodeWillBeDestroyed(const nsINode *aNode) { NS_ASSERTION(!mParent, "Shouldn't have mParent here!"); Disconnect(true); } void -nsAnimationReceiver::RecordAnimationMutation(AnimationPlayer* aPlayer, +nsAnimationReceiver::RecordAnimationMutation(Animation* aAnimation, AnimationMutation aMutationType) { - KeyframeEffectReadonly* effect = aPlayer->GetEffect(); + KeyframeEffectReadonly* effect = aAnimation->GetEffect(); if (!effect) { return; } Element* animationTarget = effect->GetTarget(); if (!animationTarget) { return; } @@ -345,66 +345,66 @@ nsAnimationReceiver::RecordAnimationMuta if (nsAutoAnimationMutationBatch::IsBatching()) { if (nsAutoAnimationMutationBatch::GetBatchTarget() != animationTarget) { return; } switch (aMutationType) { case eAnimationMutation_Added: - nsAutoAnimationMutationBatch::AnimationAdded(aPlayer); + nsAutoAnimationMutationBatch::AnimationAdded(aAnimation); break; case eAnimationMutation_Changed: - nsAutoAnimationMutationBatch::AnimationChanged(aPlayer); + nsAutoAnimationMutationBatch::AnimationChanged(aAnimation); break; case eAnimationMutation_Removed: - nsAutoAnimationMutationBatch::AnimationRemoved(aPlayer); + nsAutoAnimationMutationBatch::AnimationRemoved(aAnimation); break; } nsAutoAnimationMutationBatch::AddObserver(Observer()); return; } nsDOMMutationRecord* m = Observer()->CurrentRecord(nsGkAtoms::animations); NS_ASSERTION(!m->mTarget, "Wrong target!"); m->mTarget = animationTarget; switch (aMutationType) { case eAnimationMutation_Added: - m->mAddedAnimations.AppendElement(aPlayer); + m->mAddedAnimations.AppendElement(aAnimation); break; case eAnimationMutation_Changed: - m->mChangedAnimations.AppendElement(aPlayer); + m->mChangedAnimations.AppendElement(aAnimation); break; case eAnimationMutation_Removed: - m->mRemovedAnimations.AppendElement(aPlayer); + m->mRemovedAnimations.AppendElement(aAnimation); break; } } void -nsAnimationReceiver::AnimationAdded(AnimationPlayer* aPlayer) +nsAnimationReceiver::AnimationAdded(Animation* aAnimation) { - RecordAnimationMutation(aPlayer, eAnimationMutation_Added); + RecordAnimationMutation(aAnimation, eAnimationMutation_Added); } void -nsAnimationReceiver::AnimationChanged(AnimationPlayer* aPlayer) +nsAnimationReceiver::AnimationChanged(Animation* aAnimation) { - RecordAnimationMutation(aPlayer, eAnimationMutation_Changed); + RecordAnimationMutation(aAnimation, eAnimationMutation_Changed); } void -nsAnimationReceiver::AnimationRemoved(AnimationPlayer* aPlayer) +nsAnimationReceiver::AnimationRemoved(Animation* aAnimation) { - RecordAnimationMutation(aPlayer, eAnimationMutation_Removed); + RecordAnimationMutation(aAnimation, eAnimationMutation_Removed); } NS_IMPL_ISUPPORTS_INHERITED(nsAnimationReceiver, nsMutationReceiver, nsIAnimationObserver) // Observer NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMMutationObserver) @@ -1015,21 +1015,21 @@ nsAutoAnimationMutationBatch::Done() for (nsDOMMutationObserver* ob : mObservers) { nsRefPtr<nsDOMMutationRecord> m = new nsDOMMutationRecord(nsGkAtoms::animations, ob->GetParentObject()); m->mTarget = mBatchTarget; for (const Entry& e : mEntries) { if (e.mState == eState_Added) { - m->mAddedAnimations.AppendElement(e.mPlayer); + m->mAddedAnimations.AppendElement(e.mAnimation); } else if (e.mState == eState_Removed) { - m->mRemovedAnimations.AppendElement(e.mPlayer); + m->mRemovedAnimations.AppendElement(e.mAnimation); } else if (e.mState == eState_RemainedPresent && e.mChanged) { - m->mChangedAnimations.AppendElement(e.mPlayer); + m->mChangedAnimations.AppendElement(e.mAnimation); } } if (!m->mAddedAnimations.IsEmpty() || !m->mChangedAnimations.IsEmpty() || !m->mRemovedAnimations.IsEmpty()) { ob->AppendMutationRecord(m.forget()); ob->ScheduleForRun();
--- a/dom/base/nsDOMMutationObserver.h +++ b/dom/base/nsDOMMutationObserver.h @@ -19,29 +19,29 @@ #include "nsContentList.h" #include "mozilla/dom/Element.h" #include "nsClassHashtable.h" #include "nsNodeUtils.h" #include "nsIDOMMutationEvent.h" #include "nsWrapperCache.h" #include "mozilla/dom/MutationObserverBinding.h" #include "nsIDocument.h" -#include "mozilla/dom/AnimationPlayer.h" +#include "mozilla/dom/Animation.h" #include "nsIAnimationObserver.h" class nsDOMMutationObserver; using mozilla::dom::MutationObservingInfo; class nsDOMMutationRecord final : public nsISupports, public nsWrapperCache { virtual ~nsDOMMutationRecord() {} public: - typedef nsTArray<nsRefPtr<mozilla::dom::AnimationPlayer>> AnimationPlayerArray; + typedef nsTArray<nsRefPtr<mozilla::dom::Animation>> AnimationArray; nsDOMMutationRecord(nsIAtom* aType, nsISupports* aOwner) : mType(aType), mAttrNamespace(NullString()), mPrevValue(NullString()), mOwner(aOwner) { } nsISupports* GetParentObject() const { @@ -90,43 +90,43 @@ public: aRetVal.SetOwnedString(mAttrNamespace); } void GetOldValue(mozilla::dom::DOMString& aRetVal) const { aRetVal.SetOwnedString(mPrevValue); } - void GetAddedAnimations(AnimationPlayerArray& aRetVal) const + void GetAddedAnimations(AnimationArray& aRetVal) const { aRetVal = mAddedAnimations; } - void GetRemovedAnimations(AnimationPlayerArray& aRetVal) const + void GetRemovedAnimations(AnimationArray& aRetVal) const { aRetVal = mRemovedAnimations; } - void GetChangedAnimations(AnimationPlayerArray& aRetVal) const + void GetChangedAnimations(AnimationArray& aRetVal) const { aRetVal = mChangedAnimations; } nsCOMPtr<nsINode> mTarget; nsCOMPtr<nsIAtom> mType; nsCOMPtr<nsIAtom> mAttrName; nsString mAttrNamespace; nsString mPrevValue; nsRefPtr<nsSimpleContentList> mAddedNodes; nsRefPtr<nsSimpleContentList> mRemovedNodes; nsCOMPtr<nsINode> mPreviousSibling; nsCOMPtr<nsINode> mNextSibling; - AnimationPlayerArray mAddedAnimations; - AnimationPlayerArray mRemovedAnimations; - AnimationPlayerArray mChangedAnimations; + AnimationArray mAddedAnimations; + AnimationArray mRemovedAnimations; + AnimationArray mChangedAnimations; nsRefPtr<nsDOMMutationRecord> mNext; nsCOMPtr<nsISupports> mOwner; }; // Base class just prevents direct access to // members to make sure we go through getters/setters. class nsMutationReceiverBase : public nsStubAnimationObserver @@ -429,17 +429,17 @@ protected: private: enum AnimationMutation { eAnimationMutation_Added, eAnimationMutation_Changed, eAnimationMutation_Removed }; - void RecordAnimationMutation(mozilla::dom::AnimationPlayer* aPlayer, + void RecordAnimationMutation(mozilla::dom::Animation* aAnimation, AnimationMutation aMutationType); }; #define NS_DOM_MUTATION_OBSERVER_IID \ { 0x0c3b91f8, 0xcc3b, 0x4b08, \ { 0x9e, 0xab, 0x07, 0x47, 0xa9, 0xe4, 0x65, 0xb4 } } class nsDOMMutationObserver final : public nsISupports, @@ -751,104 +751,104 @@ public: sCurrentBatch->mObservers.AppendElement(aObserver); } static nsINode* GetBatchTarget() { return sCurrentBatch->mBatchTarget; } - static void AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer) + static void AnimationAdded(mozilla::dom::Animation* aAnimation) { if (!IsBatching()) { return; } - Entry* entry = sCurrentBatch->FindEntry(aPlayer); + Entry* entry = sCurrentBatch->FindEntry(aAnimation); if (entry) { switch (entry->mState) { case eState_RemainedAbsent: entry->mState = eState_Added; break; case eState_Removed: entry->mState = eState_RemainedPresent; break; default: NS_NOTREACHED("shouldn't have observed an animation being added " "twice"); } } else { entry = sCurrentBatch->mEntries.AppendElement(); - entry->mPlayer = aPlayer; + entry->mAnimation = aAnimation; entry->mState = eState_Added; entry->mChanged = false; } } - static void AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer) + static void AnimationChanged(mozilla::dom::Animation* aAnimation) { - Entry* entry = sCurrentBatch->FindEntry(aPlayer); + Entry* entry = sCurrentBatch->FindEntry(aAnimation); if (entry) { NS_ASSERTION(entry->mState == eState_RemainedPresent || entry->mState == eState_Added, "shouldn't have observed an animation being changed after " "being removed"); entry->mChanged = true; } else { entry = sCurrentBatch->mEntries.AppendElement(); - entry->mPlayer = aPlayer; + entry->mAnimation = aAnimation; entry->mState = eState_RemainedPresent; entry->mChanged = true; } } - static void AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer) + static void AnimationRemoved(mozilla::dom::Animation* aAnimation) { - Entry* entry = sCurrentBatch->FindEntry(aPlayer); + Entry* entry = sCurrentBatch->FindEntry(aAnimation); if (entry) { switch (entry->mState) { case eState_RemainedPresent: entry->mState = eState_Removed; break; case eState_Added: entry->mState = eState_RemainedAbsent; break; default: NS_NOTREACHED("shouldn't have observed an animation being removed " "twice"); } } else { entry = sCurrentBatch->mEntries.AppendElement(); - entry->mPlayer = aPlayer; + entry->mAnimation = aAnimation; entry->mState = eState_Removed; entry->mChanged = false; } } private: - Entry* FindEntry(mozilla::dom::AnimationPlayer* aPlayer) + Entry* FindEntry(mozilla::dom::Animation* aAnimation) { for (Entry& e : mEntries) { - if (e.mPlayer == aPlayer) { + if (e.mAnimation == aAnimation) { return &e; } } return nullptr; } enum State { eState_RemainedPresent, eState_RemainedAbsent, eState_Added, eState_Removed }; struct Entry { - nsRefPtr<mozilla::dom::AnimationPlayer> mPlayer; + nsRefPtr<mozilla::dom::Animation> mAnimation; State mState; bool mChanged; }; static nsAutoAnimationMutationBatch* sCurrentBatch; nsAutoAnimationMutationBatch* mPreviousBatch; nsAutoTArray<nsDOMMutationObserver*, 2> mObservers; nsTArray<Entry> mEntries;
--- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -14,17 +14,17 @@ #include "nsIDOMEvent.h" #include "nsQueryContentEventResult.h" #include "nsGlobalWindow.h" #include "nsIDocument.h" #include "nsFocusManager.h" #include "nsFrameManager.h" #include "nsRefreshDriver.h" #include "mozilla/dom/Touch.h" -#include "mozilla/PendingPlayerTracker.h" +#include "mozilla/PendingAnimationTracker.h" #include "nsIObjectLoadingContent.h" #include "nsFrame.h" #include "mozilla/layers/ShadowLayers.h" #include "ClientLayerManager.h" #include "nsQueryObject.h" #include "nsIScrollableFrame.h" @@ -2337,26 +2337,25 @@ ComputeAnimationValue(nsCSSProperty aPro NS_IMETHODIMP nsDOMWindowUtils::AdvanceTimeAndRefresh(int64_t aMilliseconds) { MOZ_RELEASE_ASSERT(nsContentUtils::IsCallerChrome()); // Before we advance the time, we should trigger any animations that are // waiting to start. This is because there are many tests that call this // which expect animations to start immediately. Ideally, we should make - // all these tests do an asynchronous wait on the corresponding animation - // player's 'ready' promise before continuing. Then we could remove the - // special handling here and the code path followed when testing would - // more closely match the code path during regular operation. Filed as - // bug 1112957. + // all these tests do an asynchronous wait on the corresponding animation's + // 'ready' promise before continuing. Then we could remove the special + // handling here and the code path followed when testing would more closely + // match the code path during regular operation. Filed as bug 1112957. nsCOMPtr<nsIDocument> doc = GetDocument(); if (doc) { - PendingPlayerTracker* tracker = doc->GetPendingPlayerTracker(); + PendingAnimationTracker* tracker = doc->GetPendingAnimationTracker(); if (tracker) { - tracker->TriggerPendingPlayersNow(); + tracker->TriggerPendingAnimationsNow(); } } nsRefreshDriver* driver = GetPresContext()->RefreshDriver(); driver->AdvanceTimeAndRefresh(aMilliseconds); RefPtr<LayerTransactionChild> transaction = GetLayerTransaction(); if (transaction && transaction->IPCOpen()) {
--- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -2014,17 +2014,17 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstBaseNodeWithHref) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMImplementation) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageMaps) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedEncoder) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStateObjectCached) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mUndoManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentTimeline) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingPlayerTracker) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingAnimationTracker) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTemplateContentsOwner) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildrenCollection) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRegistry) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAnonymousContents) // Traverse all our nsCOMArrays. NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStyleSheets) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOnDemandBuiltInUASheets) @@ -2098,17 +2098,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ns NS_IMPL_CYCLE_COLLECTION_UNLINK(mDisplayDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK(mFirstBaseNodeWithHref) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDOMImplementation) NS_IMPL_CYCLE_COLLECTION_UNLINK(mImageMaps) NS_IMPL_CYCLE_COLLECTION_UNLINK(mOriginalDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK(mCachedEncoder) NS_IMPL_CYCLE_COLLECTION_UNLINK(mUndoManager) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentTimeline) - NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingPlayerTracker) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingAnimationTracker) NS_IMPL_CYCLE_COLLECTION_UNLINK(mTemplateContentsOwner) NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection) NS_IMPL_CYCLE_COLLECTION_UNLINK(mRegistry) NS_IMPL_CYCLE_COLLECTION_UNLINK(mMasterDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK(mImportManager) NS_IMPL_CYCLE_COLLECTION_UNLINK(mSubImportLinks) tmp->mParentDocument = nullptr; @@ -7487,24 +7487,24 @@ nsDocument::GetAnimationController() // because they don't get OnPageShow / OnPageHide calls). if (!mIsShowing && !mIsBeingUsedAsImage) { mAnimationController->OnPageHide(); } return mAnimationController; } -PendingPlayerTracker* -nsDocument::GetOrCreatePendingPlayerTracker() -{ - if (!mPendingPlayerTracker) { - mPendingPlayerTracker = new PendingPlayerTracker(this); - } - - return mPendingPlayerTracker; +PendingAnimationTracker* +nsDocument::GetOrCreatePendingAnimationTracker() +{ + if (!mPendingAnimationTracker) { + mPendingAnimationTracker = new PendingAnimationTracker(this); + } + + return mPendingAnimationTracker; } /** * Retrieve the "direction" property of the document. * * @lina 01/09/2001 */ NS_IMETHODIMP
--- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -54,17 +54,17 @@ #include "nsILoadContext.h" #include "nsIProgressEventSink.h" #include "nsISecurityEventSink.h" #include "nsIChannelEventSink.h" #include "imgIRequest.h" #include "mozilla/EventListenerManager.h" #include "mozilla/EventStates.h" #include "mozilla/MemoryReporting.h" -#include "mozilla/PendingPlayerTracker.h" +#include "mozilla/PendingAnimationTracker.h" #include "mozilla/dom/DOMImplementation.h" #include "mozilla/dom/StyleSheetList.h" #include "nsDataHashtable.h" #include "mozilla/TimeStamp.h" #include "mozilla/Attributes.h" #include "nsIDOMXPathEvaluator.h" #include "jsfriendapi.h" #include "ImportManager.h" @@ -1045,24 +1045,24 @@ public: EnumerateExternalResources(nsSubDocEnumFunc aCallback, void* aData) override; nsTArray<nsCString> mHostObjectURIs; // Returns our (lazily-initialized) animation controller. // If HasAnimationController is true, this is guaranteed to return non-null. nsSMILAnimationController* GetAnimationController() override; - virtual mozilla::PendingPlayerTracker* - GetPendingPlayerTracker() final override + virtual mozilla::PendingAnimationTracker* + GetPendingAnimationTracker() final override { - return mPendingPlayerTracker; + return mPendingAnimationTracker; } - virtual mozilla::PendingPlayerTracker* - GetOrCreatePendingPlayerTracker() override; + virtual mozilla::PendingAnimationTracker* + GetOrCreatePendingAnimationTracker() override; void SetImagesNeedAnimating(bool aAnimating) override; virtual void SuppressEventHandling(SuppressionType aWhat, uint32_t aIncrease) override; virtual void UnsuppressEventHandlingAndFireEvents(SuppressionType aWhat, bool aFireEvents) override; @@ -1535,19 +1535,19 @@ protected: nsCOMArray<nsIStyleSheet> mStyleSheets; nsCOMArray<nsIStyleSheet> mOnDemandBuiltInUASheets; nsCOMArray<nsIStyleSheet> mAdditionalSheets[SheetTypeCount]; // Array of observers nsTObserverArray<nsIDocumentObserver*> mObservers; - // Tracker for animation players that are waiting to start. - // nullptr until GetOrCreatePendingPlayerTracker is called. - nsRefPtr<mozilla::PendingPlayerTracker> mPendingPlayerTracker; + // Tracker for animations that are waiting to start. + // nullptr until GetOrCreatePendingAnimationTracker is called. + nsRefPtr<mozilla::PendingAnimationTracker> mPendingAnimationTracker; // Weak reference to the scope object (aka the script global object) // that, unlike mScriptGlobalObject, is never unset once set. This // is a weak reference to avoid leaks due to circular references. nsWeakPtr mScopeObject; // Stack of full-screen elements. When we request full-screen we push the // full-screen element onto this stack, and when we cancel full-screen we
--- a/dom/base/nsIAnimationObserver.h +++ b/dom/base/nsIAnimationObserver.h @@ -4,59 +4,59 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef nsIAnimationObserver_h___ #define nsIAnimationObserver_h___ #include "nsIMutationObserver.h" namespace mozilla { namespace dom { -class AnimationPlayer; +class Animation; } } #define NS_IANIMATION_OBSERVER_IID \ { 0xed025fc7, 0xdeda, 0x48b9, \ { 0x9c, 0x35, 0xf2, 0xb6, 0x1e, 0xeb, 0xd0, 0x8d } } class nsIAnimationObserver : public nsIMutationObserver { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IANIMATION_OBSERVER_IID) - virtual void AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer) = 0; - virtual void AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer) = 0; - virtual void AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer) = 0; + virtual void AnimationAdded(mozilla::dom::Animation* aAnimation) = 0; + virtual void AnimationChanged(mozilla::dom::Animation* aAnimation) = 0; + virtual void AnimationRemoved(mozilla::dom::Animation* aAnimation) = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIAnimationObserver, NS_IANIMATION_OBSERVER_IID) #define NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONADDED \ - virtual void AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer) \ + virtual void AnimationAdded(mozilla::dom::Animation* aAnimation) \ override; #define NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONCHANGED \ - virtual void AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer) \ + virtual void AnimationChanged(mozilla::dom::Animation* aAnimation) \ override; #define NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONREMOVED \ - virtual void AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer) \ + virtual void AnimationRemoved(mozilla::dom::Animation* aAnimation) \ override; #define NS_IMPL_NSIANIMATIONOBSERVER_STUB(class_) \ void \ -class_::AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer) \ +class_::AnimationAdded(mozilla::dom::Animation* aAnimation) \ { \ } \ void \ -class_::AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer) \ +class_::AnimationChanged(mozilla::dom::Animation* aAnimation) \ { \ } \ void \ -class_::AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer) \ +class_::AnimationRemoved(mozilla::dom::Animation* aAnimation) \ { \ } \ NS_IMPL_NSIMUTATIONOBSERVER_CORE_STUB(class_) \ NS_IMPL_NSIMUTATIONOBSERVER_CONTENT(class_) #define NS_DECL_NSIANIMATIONOBSERVER \ NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONADDED \ NS_DECL_NSIANIMATIONOBSERVER_ANIMATIONCHANGED \
--- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -83,17 +83,17 @@ class nsDOMCaretPosition; class nsViewportInfo; class nsIGlobalObject; struct nsCSSSelectorList; namespace mozilla { class CSSStyleSheet; class ErrorResult; class EventStates; -class PendingPlayerTracker; +class PendingAnimationTracker; class SVGAttrAnimationRuleProcessor; namespace css { class Loader; class ImageLoader; } // namespace css namespace gfx { @@ -1832,26 +1832,27 @@ public: // will have a non-null return value. bool HasAnimationController() { return !!mAnimationController; } // Getter for this document's SMIL Animation Controller. Performs lazy // initialization, if this document supports animation and if // mAnimationController isn't yet initialized. virtual nsSMILAnimationController* GetAnimationController() = 0; - // Gets the tracker for animation players that are waiting to start. - // Returns nullptr if there is no pending player tracker for this document + // Gets the tracker for animations that are waiting to start. + // Returns nullptr if there is no pending animation tracker for this document // which will be the case if there have never been any CSS animations or // transitions on elements in the document. - virtual mozilla::PendingPlayerTracker* GetPendingPlayerTracker() = 0; - - // Gets the tracker for animation players that are waiting to start and + virtual mozilla::PendingAnimationTracker* GetPendingAnimationTracker() = 0; + + // Gets the tracker for animations that are waiting to start and // creates it if it doesn't already exist. As a result, the return value // will never be nullptr. - virtual mozilla::PendingPlayerTracker* GetOrCreatePendingPlayerTracker() = 0; + virtual mozilla::PendingAnimationTracker* + GetOrCreatePendingAnimationTracker() = 0; // Makes the images on this document capable of having their animation // active or suspended. An Image will animate as long as at least one of its // owning Documents needs it to animate; otherwise it can suspend. virtual void SetImagesNeedAnimating(bool aAnimating) = 0; enum SuppressionType { eAnimationsOnly = 0x1,
--- a/dom/base/nsINode.h +++ b/dom/base/nsINode.h @@ -1966,17 +1966,20 @@ public: #undef EVENT protected: static bool Traverse(nsINode *tmp, nsCycleCollectionTraversalCallback &cb); static void Unlink(nsINode *tmp); nsRefPtr<mozilla::dom::NodeInfo> mNodeInfo; - nsINode* mParent; + // mParent is an owning ref most of the time, except for the case of document + // nodes, so it cannot be represented by nsCOMPtr, so mark is as + // MOZ_OWNING_REF. + nsINode* MOZ_OWNING_REF mParent; private: // Boolean flags. uint32_t mBoolFlags; protected: // These references are non-owning and safe, as they are managed by // nsAttrAndChildArray.
--- a/dom/base/nsNodeUtils.cpp +++ b/dom/base/nsNodeUtils.cpp @@ -19,17 +19,17 @@ #include "nsPIDOMWindow.h" #include "nsDocument.h" #ifdef MOZ_XUL #include "nsXULElement.h" #endif #include "nsBindingManager.h" #include "nsGenericHTMLElement.h" #include "mozilla/Assertions.h" -#include "mozilla/dom/AnimationPlayer.h" +#include "mozilla/dom/Animation.h" #include "mozilla/dom/HTMLImageElement.h" #include "mozilla/dom/HTMLMediaElement.h" #include "mozilla/dom/KeyframeEffect.h" #include "nsWrapperCacheInlines.h" #include "nsObjectLoadingContent.h" #include "nsDOMMutationObserver.h" #include "mozilla/dom/BindingUtils.h" #include "mozilla/dom/HTMLTemplateElement.h" @@ -211,19 +211,19 @@ nsNodeUtils::ContentRemoved(nsINode* aCo } IMPL_MUTATION_NOTIFICATION(ContentRemoved, aContainer, (document, container, aChild, aIndexInContainer, aPreviousSibling)); } static inline Element* -GetTarget(AnimationPlayer* aPlayer) +GetTarget(Animation* aAnimation) { - KeyframeEffectReadonly* effect = aPlayer->GetEffect(); + KeyframeEffectReadonly* effect = aAnimation->GetEffect(); if (!effect) { return nullptr; } Element* target; nsCSSPseudoElements::Type pseudoType; effect->GetTarget(target, pseudoType); @@ -233,54 +233,54 @@ GetTarget(AnimationPlayer* aPlayer) if (pseudoType != nsCSSPseudoElements::ePseudo_NotPseudoElement) { return nullptr; } return effect->GetTarget(); } void -nsNodeUtils::AnimationAdded(AnimationPlayer* aPlayer) +nsNodeUtils::AnimationAdded(Animation* aAnimation) { - Element* target = GetTarget(aPlayer); + Element* target = GetTarget(aAnimation); if (!target) { return; } nsIDocument* doc = target->OwnerDoc(); if (doc->MayHaveAnimationObservers()) { - IMPL_ANIMATION_NOTIFICATION(AnimationAdded, target, (aPlayer)); + IMPL_ANIMATION_NOTIFICATION(AnimationAdded, target, (aAnimation)); } } void -nsNodeUtils::AnimationChanged(AnimationPlayer* aPlayer) +nsNodeUtils::AnimationChanged(Animation* aAnimation) { - Element* target = GetTarget(aPlayer); + Element* target = GetTarget(aAnimation); if (!target) { return; } nsIDocument* doc = target->OwnerDoc(); if (doc->MayHaveAnimationObservers()) { - IMPL_ANIMATION_NOTIFICATION(AnimationChanged, target, (aPlayer)); + IMPL_ANIMATION_NOTIFICATION(AnimationChanged, target, (aAnimation)); } } void -nsNodeUtils::AnimationRemoved(AnimationPlayer* aPlayer) +nsNodeUtils::AnimationRemoved(Animation* aAnimation) { - Element* target = GetTarget(aPlayer); + Element* target = GetTarget(aAnimation); if (!target) { return; } nsIDocument* doc = target->OwnerDoc(); if (doc->MayHaveAnimationObservers()) { - IMPL_ANIMATION_NOTIFICATION(AnimationRemoved, target, (aPlayer)); + IMPL_ANIMATION_NOTIFICATION(AnimationRemoved, target, (aAnimation)); } } void nsNodeUtils::LastRelease(nsINode* aNode) { nsINode::nsSlots* slots = aNode->GetExistingSlots(); if (slots) {
--- a/dom/base/nsNodeUtils.h +++ b/dom/base/nsNodeUtils.h @@ -13,17 +13,17 @@ struct CharacterDataChangeInfo; class nsIVariant; class nsIDOMNode; template<class E> class nsCOMArray; class nsCycleCollectionTraversalCallback; namespace mozilla { namespace dom { -class AnimationPlayer; +class Animation; } } class nsNodeUtils { public: /** * Send CharacterDataWillChange notifications to nsIMutationObservers. @@ -122,19 +122,19 @@ public: if (slots && !slots->mMutationObservers.IsEmpty()) { NS_OBSERVER_ARRAY_NOTIFY_OBSERVERS(slots->mMutationObservers, nsIMutationObserver, ParentChainChanged, (aContent)); } } - static void AnimationAdded(mozilla::dom::AnimationPlayer* aPlayer); - static void AnimationChanged(mozilla::dom::AnimationPlayer* aPlayer); - static void AnimationRemoved(mozilla::dom::AnimationPlayer* aPlayer); + static void AnimationAdded(mozilla::dom::Animation* aAnimation); + static void AnimationChanged(mozilla::dom::Animation* aAnimation); + static void AnimationRemoved(mozilla::dom::Animation* aAnimation); /** * To be called when reference count of aNode drops to zero. * @param aNode The node which is going to be deleted. */ static void LastRelease(nsINode* aNode); /**
--- a/dom/base/nsObjectLoadingContent.cpp +++ b/dom/base/nsObjectLoadingContent.cpp @@ -2728,18 +2728,20 @@ nsObjectLoadingContent::GetPrintFrame(ns NS_IMETHODIMP nsObjectLoadingContent::PluginDestroyed() { // Called when our plugin is destroyed from under us, usually when reloading // plugins in plugin host. Invalidate instance owner / prototype but otherwise // don't take any action. TeardownProtoChain(); - mInstanceOwner->Destroy(); - mInstanceOwner = nullptr; + if (mInstanceOwner) { + mInstanceOwner->Destroy(); + mInstanceOwner = nullptr; + } return NS_OK; } NS_IMETHODIMP nsObjectLoadingContent::PluginCrashed(nsIPluginTag* aPluginTag, const nsAString& pluginDumpID, const nsAString& browserDumpID, bool submittedCrashReport)
--- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -8599,16 +8599,36 @@ class CGStaticMethodJitinfo(CGGeneric): " JSJitInfo::AliasEverything, JSVAL_TYPE_MISSING, false, false,\n" " false, false, 0\n" "};\n" % (IDLToCIdentifier(method.identifier.name), CppKeywords.checkMethodName( IDLToCIdentifier(method.identifier.name)))) +class CGMethodIdentityTest(CGAbstractMethod): + """ + A class to generate a method-identity test for a given IDL operation. + """ + def __init__(self, descriptor, method): + self.method = method + name = "Is%sMethod" % MakeNativeName(method.identifier.name) + CGAbstractMethod.__init__(self, descriptor, name, 'bool', + [Argument('JS::Handle<JSObject*>', 'aObj')]) + + def definition_body(self): + return dedent( + """ + MOZ_ASSERT(aObj); + return js::IsFunctionObject(aObj) && + js::FunctionObjectIsNative(aObj) && + FUNCTION_VALUE_TO_JITINFO(JS::ObjectValue(*aObj)) == &%s_methodinfo; + """ % IDLToCIdentifier(self.method.identifier.name)) + + def getEnumValueName(value): # Some enum values can be empty strings. Others might have weird # characters in them. Deal with the former by returning "_empty", # deal with possible name collisions from that by throwing if the # enum value is actually "_empty", and throw on any value # containing non-ASCII chars for now. Replace all chars other than # [0-9A-Za-z_] with '_'. if re.match("[^\x20-\x7E]", value): @@ -11195,16 +11215,18 @@ class CGDescriptor(CGThing): elif descriptor.interface.hasInterfacePrototypeObject(): specializedMethod = CGSpecializedMethod(descriptor, m) cgThings.append(specializedMethod) if m.returnsPromise(): cgThings.append(CGMethodPromiseWrapper(descriptor, specializedMethod)) cgThings.append(CGMemberJITInfo(descriptor, m)) if props.isCrossOriginMethod: crossOriginMethods.add(m.identifier.name) + if m.getExtendedAttribute("MethodIdentityTestable"): + cgThings.append(CGMethodIdentityTest(descriptor, m)) elif m.isAttr(): if m.stringifier: raise TypeError("Stringifier attributes not supported yet. " "See bug 824857.\n" "%s" % m.location) if m.isStatic(): assert descriptor.interface.hasInterfaceObject() cgThings.append(CGStaticGetter(descriptor, m))
--- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -2771,17 +2771,17 @@ class IDLBuiltinType(IDLType): self._typeTag == IDLBuiltinType.Types.unrestricted_double def isUnrestricted(self): assert self.isFloat() return self._typeTag == IDLBuiltinType.Types.unrestricted_float or \ self._typeTag == IDLBuiltinType.Types.unrestricted_double def isSerializable(self): - return self.isPrimitive() or self.isDOMString() or self.isDate() + return self.isPrimitive() or self.isString() or self.isDate() def includesRestrictedFloat(self): return self.isFloat() and not self.isUnrestricted() def tag(self): return IDLBuiltinType.TagLookup[self._typeTag] def isDistinguishableFrom(self, other): @@ -4158,17 +4158,18 @@ class IDLMethod(IDLInterfaceMember, IDLS identifier == "NewObject" or identifier == "ChromeOnly" or identifier == "UnsafeInPrerendering" or identifier == "Pref" or identifier == "Deprecated" or identifier == "Func" or identifier == "AvailableIn" or identifier == "CheckPermissions" or - identifier == "BinaryName"): + identifier == "BinaryName" or + identifier == "MethodIdentityTestable"): # Known attributes that we don't need to do anything with here pass else: raise WebIDLError("Unknown extended attribute %s on method" % identifier, [attr.location]) IDLInterfaceMember.handleExtendedAttribute(self, attr) def returnsPromise(self):
--- a/dom/cache/Context.cpp +++ b/dom/cache/Context.cpp @@ -696,68 +696,77 @@ Context::ThreadsafeHandle::ContextDestro MOZ_ASSERT(!mStrongRef); MOZ_ASSERT(mWeakRef); MOZ_ASSERT(mWeakRef == aContext); mWeakRef = nullptr; } // static already_AddRefed<Context> -Context::Create(Manager* aManager, Action* aQuotaIOThreadAction) +Context::Create(Manager* aManager, Action* aQuotaIOThreadAction, + Context* aOldContext) { nsRefPtr<Context> context = new Context(aManager); + // Do this here to avoid doing an AddRef() in the constructor context->mInitRunnable = new QuotaInitRunnable(context, aManager, aQuotaIOThreadAction); - nsresult rv = context->mInitRunnable->Dispatch(); - if (NS_FAILED(rv)) { - // Shutdown must be delayed until all Contexts are destroyed. Shutdown - // must also prevent any new Contexts from being constructed. Crash - // for this invariant violation. - MOZ_CRASH("Failed to dispatch QuotaInitRunnable."); + + if (aOldContext) { + aOldContext->SetNextContext(context); + } else { + context->Start(); } return context.forget(); } Context::Context(Manager* aManager) : mManager(aManager) - , mState(STATE_CONTEXT_INIT) + , mState(STATE_CONTEXT_PREINIT) { MOZ_ASSERT(mManager); } void Context::Dispatch(nsIEventTarget* aTarget, Action* aAction) { NS_ASSERT_OWNINGTHREAD(Context); MOZ_ASSERT(aTarget); MOZ_ASSERT(aAction); MOZ_ASSERT(mState != STATE_CONTEXT_CANCELED); if (mState == STATE_CONTEXT_CANCELED) { return; - } else if (mState == STATE_CONTEXT_INIT) { + } else if (mState == STATE_CONTEXT_INIT || + mState == STATE_CONTEXT_PREINIT) { PendingAction* pending = mPendingActions.AppendElement(); pending->mTarget = aTarget; pending->mAction = aAction; return; } MOZ_ASSERT(STATE_CONTEXT_READY); DispatchAction(aTarget, aAction); } void Context::CancelAll() { NS_ASSERT_OWNINGTHREAD(Context); - if (mInitRunnable) { - MOZ_ASSERT(mState == STATE_CONTEXT_INIT); + // In PREINIT state we have not dispatch the init runnable yet. Just + // forget it. + if (mState == STATE_CONTEXT_PREINIT) { + mInitRunnable = nullptr; + + // In INIT state we have dispatched the runnable, but not received the + // async completion yet. Cancel the runnable, but don't forget about it + // until we get OnQuotaInit() callback. + } else if (mState == STATE_CONTEXT_INIT) { mInitRunnable->Cancel(); } mState = STATE_CONTEXT_CANCELED; mPendingActions.Clear(); { ActivityList::ForwardIterator iter(mActivityList); while (iter.HasMore()) { @@ -818,16 +827,44 @@ Context::~Context() NS_ASSERT_OWNINGTHREAD(Context); MOZ_ASSERT(mManager); if (mThreadsafeHandle) { mThreadsafeHandle->ContextDestroyed(this); } mManager->RemoveContext(this); + + if (mNextContext) { + mNextContext->Start(); + } +} + +void +Context::Start() +{ + NS_ASSERT_OWNINGTHREAD(Context); + + // Previous context closing delayed our start, but then we were canceled. + // In this case, just do nothing here. + if (mState == STATE_CONTEXT_CANCELED) { + MOZ_ASSERT(!mInitRunnable); + return; + } + + MOZ_ASSERT(mState == STATE_CONTEXT_PREINIT); + mState = STATE_CONTEXT_INIT; + + nsresult rv = mInitRunnable->Dispatch(); + if (NS_FAILED(rv)) { + // Shutdown must be delayed until all Contexts are destroyed. Shutdown + // must also prevent any new Contexts from being constructed. Crash + // for this invariant violation. + MOZ_CRASH("Failed to dispatch QuotaInitRunnable."); + } } void Context::DispatchAction(nsIEventTarget* aTarget, Action* aAction) { NS_ASSERT_OWNINGTHREAD(Context); nsRefPtr<ActionRunnable> runnable = @@ -900,11 +937,20 @@ Context::CreateThreadsafeHandle() NS_ASSERT_OWNINGTHREAD(Context); if (!mThreadsafeHandle) { mThreadsafeHandle = new ThreadsafeHandle(this); } nsRefPtr<ThreadsafeHandle> ref = mThreadsafeHandle; return ref.forget(); } +void +Context::SetNextContext(Context* aNextContext) +{ + NS_ASSERT_OWNINGTHREAD(Context); + MOZ_ASSERT(aNextContext); + MOZ_ASSERT(!mNextContext); + mNextContext = aNextContext; +} + } // namespace cache } // namespace dom } // namespace mozilla
--- a/dom/cache/Context.h +++ b/dom/cache/Context.h @@ -106,17 +106,17 @@ public: virtual void Cancel() = 0; virtual bool MatchesCacheId(CacheId aCacheId) const = 0; }; // Create a Context attached to the given Manager. The given Action // will run on the QuotaManager IO thread. Note, this Action must // be execute synchronously. static already_AddRefed<Context> - Create(Manager* aManager, Action* aQuotaIOThreadAction); + Create(Manager* aManager, Action* aQuotaIOThreadAction, Context* aOldContext); // Execute given action on the target once the quota manager has been // initialized. // // Only callable from the thread that created the Context. void Dispatch(nsIEventTarget* aTarget, Action* aAction); // Cancel any Actions running or waiting to run. This should allow the @@ -152,36 +152,41 @@ public: } private: class QuotaInitRunnable; class ActionRunnable; enum State { + STATE_CONTEXT_PREINIT, STATE_CONTEXT_INIT, STATE_CONTEXT_READY, STATE_CONTEXT_CANCELED }; struct PendingAction { nsCOMPtr<nsIEventTarget> mTarget; nsRefPtr<Action> mAction; }; explicit Context(Manager* aManager); ~Context(); + void Start(); void DispatchAction(nsIEventTarget* aTarget, Action* aAction); void OnQuotaInit(nsresult aRv, const QuotaInfo& aQuotaInfo, nsMainThreadPtrHandle<OfflineStorage>& aOfflineStorage); already_AddRefed<ThreadsafeHandle> CreateThreadsafeHandle(); + void + SetNextContext(Context* aNextContext); + nsRefPtr<Manager> mManager; State mState; QuotaInfo mQuotaInfo; nsRefPtr<QuotaInitRunnable> mInitRunnable; nsTArray<PendingAction> mPendingActions; // Weak refs since activites must remove themselves from this list before // being destroyed by calling RemoveActivity(). @@ -189,16 +194,17 @@ private: ActivityList mActivityList; // The ThreadsafeHandle may have a strong ref back to us. This creates // a ref-cycle that keeps the Context alive. The ref-cycle is broken // when ThreadsafeHandle::AllowToClose() is called. nsRefPtr<ThreadsafeHandle> mThreadsafeHandle; nsMainThreadPtrHandle<OfflineStorage> mOfflineStorage; + nsRefPtr<Context> mNextContext; public: NS_INLINE_DECL_REFCOUNTING(cache::Context) }; } // namespace cache } // namespace dom } // namespace mozilla
--- a/dom/cache/Manager.cpp +++ b/dom/cache/Manager.cpp @@ -152,42 +152,47 @@ public: nsRefPtr<Manager> ref = Get(aManagerId); if (!ref) { // TODO: replace this with a thread pool (bug 1119864) nsCOMPtr<nsIThread> ioThread; rv = NS_NewNamedThread("DOMCacheThread", getter_AddRefs(ioThread)); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } ref = new Manager(aManagerId, ioThread); - ref->Init(); + + // There may be an old manager for this origin in the process of + // cleaning up. We need to tell the new manager about this so + // that it won't actually start until the old manager is done. + nsRefPtr<Manager> oldManager = Get(aManagerId, Closing); + ref->Init(oldManager); MOZ_ASSERT(!sFactory->mManagerList.Contains(ref)); sFactory->mManagerList.AppendElement(ref); } ref.forget(aManagerOut); return NS_OK; } static already_AddRefed<Manager> - Get(ManagerId* aManagerId) + Get(ManagerId* aManagerId, State aState = Open) { mozilla::ipc::AssertIsOnBackgroundThread(); nsresult rv = MaybeCreateInstance(); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } - ManagerList::ForwardIterator iter(sFactory->mManagerList); + // Iterate in reverse to find the most recent, matching Manager. This + // is important when looking for a Closing Manager. If a new Manager + // chains to an old Manager we want it to be the most recent one. + ManagerList::BackwardIterator iter(sFactory->mManagerList); while (iter.HasMore()) { nsRefPtr<Manager> manager = iter.GetNext(); - // If there is an invalid Manager finishing up and a new Manager - // is created for the same origin, then the new Manager will - // be blocked until QuotaManager finishes clearing the origin. - if (!manager->IsClosing() && *manager->mManagerId == *aManagerId) { + if (aState == manager->GetState() && *manager->mManagerId == *aManagerId) { return manager.forget(); } } return nullptr; } static void @@ -1445,39 +1450,39 @@ Manager::RemoveContext(Context* aContext { NS_ASSERT_OWNINGTHREAD(Manager); MOZ_ASSERT(mContext); MOZ_ASSERT(mContext == aContext); // Whether the Context destruction was triggered from the Manager going // idle or the underlying storage being invalidated, we should know we // are closing before the Conext is destroyed. - MOZ_ASSERT(mClosing); + MOZ_ASSERT(mState == Closing); mContext = nullptr; // Once the context is gone, we can immediately remove ourself from the // Factory list. We don't need to block shutdown by staying in the list // any more. Factory::Remove(this); } void Manager::NoteClosing() { NS_ASSERT_OWNINGTHREAD(Manager); // This can be called more than once legitimately through different paths. - mClosing = true; + mState = Closing; } -bool -Manager::IsClosing() const +Manager::State +Manager::GetState() const { NS_ASSERT_OWNINGTHREAD(Manager); - return mClosing; + return mState; } void Manager::AddRefCacheId(CacheId aCacheId) { NS_ASSERT_OWNINGTHREAD(Manager); for (uint32_t i = 0; i < mCacheIdRefs.Length(); ++i) { if (mCacheIdRefs[i].mCacheId == aCacheId) { @@ -1588,17 +1593,17 @@ void Manager::ExecuteCacheOp(Listener* aListener, CacheId aCacheId, const CacheOpArgs& aOpArgs) { NS_ASSERT_OWNINGTHREAD(Manager); MOZ_ASSERT(aListener); MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCacheAddAllArgs); MOZ_ASSERT(aOpArgs.type() != CacheOpArgs::TCachePutAllArgs); - if (mClosing) { + if (mState == Closing) { aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t()); return; } nsRefPtr<Context> context = mContext; MOZ_ASSERT(!context->IsCanceled()); nsRefPtr<StreamList> streamList = new StreamList(this, context); @@ -1632,17 +1637,17 @@ Manager::ExecuteCacheOp(Listener* aListe void Manager::ExecuteStorageOp(Listener* aListener, Namespace aNamespace, const CacheOpArgs& aOpArgs) { NS_ASSERT_OWNINGTHREAD(Manager); MOZ_ASSERT(aListener); - if (mClosing) { + if (mState == Closing) { aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), void_t()); return; } nsRefPtr<Context> context = mContext; MOZ_ASSERT(!context->IsCanceled()); nsRefPtr<StreamList> streamList = new StreamList(this, context); @@ -1681,17 +1686,17 @@ void Manager::ExecutePutAll(Listener* aListener, CacheId aCacheId, const nsTArray<CacheRequestResponse>& aPutList, const nsTArray<nsCOMPtr<nsIInputStream>>& aRequestStreamList, const nsTArray<nsCOMPtr<nsIInputStream>>& aResponseStreamList) { NS_ASSERT_OWNINGTHREAD(Manager); MOZ_ASSERT(aListener); - if (mClosing) { + if (mState == Closing) { aListener->OnOpComplete(ErrorResult(NS_ERROR_FAILURE), CachePutAllResult()); return; } nsRefPtr<Context> context = mContext; MOZ_ASSERT(!context->IsCanceled()); ListenerId listenerId = SaveListener(aListener); @@ -1703,48 +1708,53 @@ Manager::ExecutePutAll(Listener* aListen context->Dispatch(mIOThread, action); } Manager::Manager(ManagerId* aManagerId, nsIThread* aIOThread) : mManagerId(aManagerId) , mIOThread(aIOThread) , mContext(nullptr) , mShuttingDown(false) - , mClosing(false) + , mState(Open) { MOZ_ASSERT(mManagerId); MOZ_ASSERT(mIOThread); } Manager::~Manager() { NS_ASSERT_OWNINGTHREAD(Manager); - MOZ_ASSERT(mClosing); + MOZ_ASSERT(mState == Closing); MOZ_ASSERT(!mContext); nsCOMPtr<nsIThread> ioThread; mIOThread.swap(ioThread); // Don't spin the event loop in the destructor waiting for the thread to // shutdown. Defer this to the main thread, instead. nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableMethod(ioThread, &nsIThread::Shutdown); MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable))); } void -Manager::Init() +Manager::Init(Manager* aOldManager) { NS_ASSERT_OWNINGTHREAD(Manager); + nsRefPtr<Context> oldContext; + if (aOldManager) { + oldContext = aOldManager->mContext; + } + // Create the context immediately. Since there can at most be one Context // per Manager now, this lets us cleanly call Factory::Remove() once the // Context goes away. nsRefPtr<Action> setupAction = new SetupAction(); - nsRefPtr<Context> ref = Context::Create(this, setupAction); + nsRefPtr<Context> ref = Context::Create(this, setupAction, oldContext); mContext = ref; } void Manager::Shutdown() { NS_ASSERT_OWNINGTHREAD(Manager);
--- a/dom/cache/Manager.h +++ b/dom/cache/Manager.h @@ -114,32 +114,39 @@ public: const nsTArray<SavedResponse>& aSavedResponseList, const nsTArray<SavedRequest>& aSavedRequestList, StreamList* aStreamList) { } protected: ~Listener() { } }; + enum State + { + Open, + Closing + }; + static nsresult GetOrCreate(ManagerId* aManagerId, Manager** aManagerOut); static already_AddRefed<Manager> Get(ManagerId* aManagerId); // Synchronously shutdown from main thread. This spins the event loop. static void ShutdownAllOnMainThread(); // Must be called by Listener objects before they are destroyed. void RemoveListener(Listener* aListener); // Must be called by Context objects before they are destroyed. void RemoveContext(Context* aContext); // Marks the Manager "invalid". Once the Context completes no new operations // will be permitted with this Manager. New actors will get a new Manager. void NoteClosing(); - bool IsClosing() const; + + State GetState() const; // If an actor represents a long term reference to a cache or body stream, // then they must call AddRefCacheId() or AddRefBodyId(). This will // cause the Manager to keep the backing data store alive for the given // object. The actor must then call ReleaseCacheId() or ReleaseBodyId() // exactly once for every AddRef*() call it made. Any delayed deletion // will then be performed. void AddRefCacheId(CacheId aCacheId); @@ -180,17 +187,17 @@ private: class StorageOpenAction; class StorageDeleteAction; class StorageKeysAction; typedef uint64_t ListenerId; Manager(ManagerId* aManagerId, nsIThread* aIOThread); ~Manager(); - void Init(); + void Init(Manager* aOldManager); void Shutdown(); already_AddRefed<Context> CurrentContext(); ListenerId SaveListener(Listener* aListener); Listener* GetListener(ListenerId aListenerId) const; bool SetCacheIdOrphanedIfRefed(CacheId aCacheId); bool SetBodyIdOrphanedIfRefed(const nsID& aBodyId); @@ -244,17 +251,17 @@ private: typedef nsTArray<ListenerEntry> ListenerList; ListenerList mListeners; static ListenerId sNextListenerId; // Weak references cleared by RemoveStreamList() in StreamList destructors. nsTArray<StreamList*> mStreamLists; bool mShuttingDown; - bool mClosing; + State mState; struct CacheIdRefCounter { CacheId mCacheId; MozRefCountType mCount; bool mOrphaned; }; nsTArray<CacheIdRefCounter> mCacheIdRefs;
--- a/dom/cache/test/mochitest/serviceworker_driver.js +++ b/dom/cache/test/mochitest/serviceworker_driver.js @@ -33,21 +33,12 @@ function serviceWorkerTestExec(testFile) var iframe = document.createElement("iframe"); iframe.src = "message_receiver.html"; iframe.onload = function() { worker.postMessage({ script: testFile }); }; document.body.appendChild(iframe); } - navigator.serviceWorker.register("worker_wrapper.js", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - e.target.onstatechange = null; - setupSW(registration); - }; - } else { - setupSW(registration); - } - }); + navigator.serviceWorker.ready.then(setupSW); + navigator.serviceWorker.register("worker_wrapper.js", {scope: "."}); }); }
--- a/dom/canvas/CanvasRenderingContext2D.cpp +++ b/dom/canvas/CanvasRenderingContext2D.cpp @@ -4264,17 +4264,20 @@ CanvasRenderingContext2D::DrawImage(cons mCurrentVideoSize.width = srcImage->GetSize().width; mCurrentVideoSize.height = srcImage->GetSize().height; gl->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGB, srcImage->GetSize().width, srcImage->GetSize().height, 0, LOCAL_GL_RGB, LOCAL_GL_UNSIGNED_SHORT_5_6_5, nullptr); gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE); gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE); gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, LOCAL_GL_LINEAR); gl->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, LOCAL_GL_LINEAR); } - bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), mVideoTexture, LOCAL_GL_TEXTURE_2D, 1); + const gl::OriginPos destOrigin = gl::OriginPos::TopLeft; + bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), + mVideoTexture, LOCAL_GL_TEXTURE_2D, + destOrigin); if (ok) { NativeSurface texSurf; texSurf.mType = NativeSurfaceType::OPENGL_TEXTURE; texSurf.mFormat = SurfaceFormat::R5G6B5; texSurf.mSize.width = mCurrentVideoSize.width; texSurf.mSize.height = mCurrentVideoSize.height; texSurf.mSurface = (void*)((uintptr_t)mVideoTexture);
--- a/dom/canvas/WebGLContext.cpp +++ b/dom/canvas/WebGLContext.cpp @@ -1832,21 +1832,23 @@ WebGLContext::TexImageFromVideoElement(c info.Height() == srcImage->GetSize().height; if (!dimensionsMatch) { // we need to allocation gl->fTexImage2D(texImageTarget.get(), level, internalFormat, srcImage->GetSize().width, srcImage->GetSize().height, 0, format, type, nullptr); } + const gl::OriginPos destOrigin = mPixelStoreFlipY ? gl::OriginPos::BottomLeft + : gl::OriginPos::TopLeft; bool ok = gl->BlitHelper()->BlitImageToTexture(srcImage.get(), srcImage->GetSize(), tex->GLName(), texImageTarget.get(), - mPixelStoreFlipY); + destOrigin); if (ok) { TexInternalFormat effectiveInternalFormat = EffectiveInternalFormatFromInternalFormatAndType(internalFormat, type); MOZ_ASSERT(effectiveInternalFormat != LOCAL_GL_NONE); tex->SetImageInfo(texImageTarget, level, srcImage->GetSize().width, srcImage->GetSize().height, 1, effectiveInternalFormat,
--- a/dom/filesystem/Directory.cpp +++ b/dom/filesystem/Directory.cpp @@ -193,39 +193,30 @@ Directory::RemoveInternal(const StringOr nsresult error = NS_OK; nsString realPath; nsRefPtr<FileImpl> file; // Check and get the target path. if (aPath.IsFile()) { file = aPath.GetAsFile().Impl(); - goto parameters_check_done; - } - - if (aPath.IsString()) { + } else if (aPath.IsString()) { if (!DOMPathToRealPath(aPath.GetAsString(), realPath)) { error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR; } - goto parameters_check_done; - } - - if (!mFileSystem->IsSafeDirectory(&aPath.GetAsDirectory())) { + } else if (!mFileSystem->IsSafeDirectory(&aPath.GetAsDirectory())) { error = NS_ERROR_DOM_SECURITY_ERR; - goto parameters_check_done; + } else { + realPath = aPath.GetAsDirectory().mPath; + // The target must be a descendant of this directory. + if (!FileSystemUtils::IsDescendantPath(mPath, realPath)) { + error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR; + } } - realPath = aPath.GetAsDirectory().mPath; - // The target must be a descendant of this directory. - if (!FileSystemUtils::IsDescendantPath(mPath, realPath)) { - error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR; - } - -parameters_check_done: - nsRefPtr<RemoveTask> task = new RemoveTask(mFileSystem, mPath, file, realPath, aRecursive, aRv); if (aRv.Failed()) { return nullptr; } task->SetError(error); FileSystemPermissionRequest::RequestForTask(task); return task->GetPromise();
--- a/dom/html/HTMLTextAreaElement.cpp +++ b/dom/html/HTMLTextAreaElement.cpp @@ -1456,25 +1456,17 @@ NS_IMETHODIMP_(bool) HTMLTextAreaElement::IsPasswordTextControl() const { return false; } NS_IMETHODIMP_(int32_t) HTMLTextAreaElement::GetCols() { - const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::cols); - if (attr) { - int32_t cols = attr->Type() == nsAttrValue::eInteger ? - attr->GetIntegerValue() : 0; - // XXX why a default of 1 char, why hide it - return (cols <= 0) ? 1 : cols; - } - - return DEFAULT_COLS; + return Cols(); } NS_IMETHODIMP_(int32_t) HTMLTextAreaElement::GetWrapCols() { // wrap=off means -1 for wrap width no matter what cols is nsHTMLTextWrap wrapProp; nsITextControlElement::GetWrapPropertyEnum(this, wrapProp);
--- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -2355,16 +2355,23 @@ ContentParent::~ContentParent() #endif } void ContentParent::InitInternal(ProcessPriority aInitialPriority, bool aSetupOffMainThreadCompositing, bool aSendRegisteredChrome) { + if (aSendRegisteredChrome) { + nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService(); + nsChromeRegistryChrome* chromeRegistry = + static_cast<nsChromeRegistryChrome*>(registrySvc.get()); + chromeRegistry->SendRegisteredChrome(this); + } + // Initialize the message manager (and load delayed scripts) now that we // have established communications with the child. mMessageManager->InitWithCallback(this); // Set the subprocess's priority. We do this early on because we're likely // /lowering/ the process's CPU and memory priority, which it has inherited // from this process. // @@ -2397,23 +2404,16 @@ ContentParent::InitInternal(ProcessPrior #endif } #ifdef MOZ_WIDGET_GONK DebugOnly<bool> opened = PSharedBufferManager::Open(this); MOZ_ASSERT(opened); #endif } - if (aSendRegisteredChrome) { - nsCOMPtr<nsIChromeRegistry> registrySvc = nsChromeRegistry::GetService(); - nsChromeRegistryChrome* chromeRegistry = - static_cast<nsChromeRegistryChrome*>(registrySvc.get()); - chromeRegistry->SendRegisteredChrome(this); - } - if (gAppData) { nsCString version(gAppData->version); nsCString buildID(gAppData->buildID); nsCString name(gAppData->name); nsCString UAName(gAppData->UAName); nsCString ID(gAppData->ID); nsCString vendor(gAppData->vendor);
--- a/dom/media/fmp4/android/AndroidDecoderModule.cpp +++ b/dom/media/fmp4/android/AndroidDecoderModule.cpp @@ -67,20 +67,24 @@ public: bool WantCopy() { // Allocating a texture is incredibly slow on PowerVR return mGLContext->Vendor() != GLVendor::Imagination; } EGLImage CopySurface(layers::Image* img) { mGLContext->MakeCurrent(); - GLuint tex = CreateTextureForOffscreen(mGLContext, mGLContext->GetGLFormats(), img->GetSize()); + GLuint tex = CreateTextureForOffscreen(mGLContext, mGLContext->GetGLFormats(), + img->GetSize()); - GLBlitHelper helper(mGLContext); - if (!helper.BlitImageToTexture(img, img->GetSize(), tex, LOCAL_GL_TEXTURE_2D)) { + auto helper = mGLContext->BlitHelper(); + const gl::OriginPos destOrigin = gl::OriginPos::TopLeft; + if (!helper->BlitImageToTexture(img, img->GetSize(), tex, LOCAL_GL_TEXTURE_2D, + destOrigin)) + { mGLContext->fDeleteTextures(1, &tex); return nullptr; } EGLint attribs[] = { LOCAL_EGL_IMAGE_PRESERVED_KHR, LOCAL_EGL_TRUE, LOCAL_EGL_NONE, LOCAL_EGL_NONE }; @@ -129,17 +133,17 @@ public: } img = mImageContainer->CreateImage(ImageFormat::EGLIMAGE); layers::EGLImageImage::Data data; data.mImage = eglImage; data.mSync = eglSync; data.mOwns = true; data.mSize = mConfig.mDisplay; - data.mOriginPos = gl::OriginPos::BottomLeft; + data.mOriginPos = gl::OriginPos::TopLeft; layers::EGLImageImage* typedImg = static_cast<layers::EGLImageImage*>(img.get()); typedImg->SetData(data); } nsresult rv; int32_t flags; NS_ENSURE_SUCCESS(rv = aInfo->Flags(&flags), rv);
--- a/dom/media/gmp/GMPAudioDecoderParent.cpp +++ b/dom/media/gmp/GMPAudioDecoderParent.cpp @@ -27,16 +27,17 @@ extern PRLogModuleInfo* GetGMPLog(); #define LOG(level, msg) #endif namespace gmp { GMPAudioDecoderParent::GMPAudioDecoderParent(GMPContentParent* aPlugin) : mIsOpen(false) , mShuttingDown(false) + , mActorDestroyed(false) , mPlugin(aPlugin) , mCallback(nullptr) { MOZ_ASSERT(mPlugin); } GMPAudioDecoderParent::~GMPAudioDecoderParent() { @@ -169,26 +170,29 @@ GMPAudioDecoderParent::Shutdown() // Notify client we're gone! Won't occur after Close() if (mCallback) { mCallback->Terminated(); mCallback = nullptr; } mIsOpen = false; - unused << SendDecodingComplete(); + if (!mActorDestroyed) { + unused << SendDecodingComplete(); + } return NS_OK; } // Note: Keep this sync'd up with DecodingComplete void GMPAudioDecoderParent::ActorDestroy(ActorDestroyReason aWhy) { mIsOpen = false; + mActorDestroyed = true; if (mCallback) { // May call Close() (and Shutdown()) immediately or with a delay mCallback->Terminated(); mCallback = nullptr; } if (mPlugin) { // Ignore any return code. It is OK for this to fail without killing the process. mPlugin->AudioDecoderDestroyed(this);
--- a/dom/media/gmp/GMPAudioDecoderParent.h +++ b/dom/media/gmp/GMPAudioDecoderParent.h @@ -50,16 +50,17 @@ private: virtual bool RecvDrainComplete() override; virtual bool RecvResetComplete() override; virtual bool RecvError(const GMPErr& aError) override; virtual bool RecvShutdown() override; virtual bool Recv__delete__() override; bool mIsOpen; bool mShuttingDown; + bool mActorDestroyed; nsRefPtr<GMPContentParent> mPlugin; GMPAudioDecoderCallbackProxy* mCallback; }; } // namespace gmp } // namespace mozilla #endif // GMPAudioDecoderParent_h_
--- a/dom/media/gmp/GMPDecryptorParent.cpp +++ b/dom/media/gmp/GMPDecryptorParent.cpp @@ -9,16 +9,17 @@ #include "mozilla/unused.h" namespace mozilla { namespace gmp { GMPDecryptorParent::GMPDecryptorParent(GMPContentParent* aPlugin) : mIsOpen(false) , mShuttingDown(false) + , mActorDestroyed(false) , mPlugin(aPlugin) , mCallback(nullptr) #ifdef DEBUG , mGMPThread(aPlugin->GMPThread()) #endif { MOZ_ASSERT(mPlugin && mGMPThread); mPluginId = aPlugin->GetPluginId(); @@ -342,24 +343,27 @@ GMPDecryptorParent::Shutdown() // Notify client we're gone! Won't occur after Close() if (mCallback) { mCallback->Terminated(); mCallback = nullptr; } mIsOpen = false; - unused << SendDecryptingComplete(); + if (!mActorDestroyed) { + unused << SendDecryptingComplete(); + } } // Note: Keep this sync'd up with Shutdown void GMPDecryptorParent::ActorDestroy(ActorDestroyReason aWhy) { mIsOpen = false; + mActorDestroyed = true; if (mCallback) { // May call Close() (and Shutdown()) immediately or with a delay mCallback->Terminated(); mCallback = nullptr; } if (mPlugin) { mPlugin->DecryptorDestroyed(this); mPlugin = nullptr;
--- a/dom/media/gmp/GMPDecryptorParent.h +++ b/dom/media/gmp/GMPDecryptorParent.h @@ -106,16 +106,17 @@ private: virtual bool RecvShutdown() override; virtual void ActorDestroy(ActorDestroyReason aWhy) override; virtual bool Recv__delete__() override; bool mIsOpen; bool mShuttingDown; + bool mActorDestroyed; nsRefPtr<GMPContentParent> mPlugin; nsCString mPluginId; GMPDecryptorProxyCallback* mCallback; #ifdef DEBUG nsIThread* const mGMPThread; #endif };
--- a/dom/media/gmp/GMPVideoDecoderParent.cpp +++ b/dom/media/gmp/GMPVideoDecoderParent.cpp @@ -42,16 +42,17 @@ namespace gmp { // on ActorDestroy -> Dead // on Shutdown -> Dead // Dead: mIsOpen == false GMPVideoDecoderParent::GMPVideoDecoderParent(GMPContentParent* aPlugin) : GMPSharedMemManager(aPlugin) , mIsOpen(false) , mShuttingDown(false) + , mActorDestroyed(false) , mPlugin(aPlugin) , mCallback(nullptr) , mVideoHost(this) { MOZ_ASSERT(mPlugin); } GMPVideoDecoderParent::~GMPVideoDecoderParent() @@ -208,26 +209,29 @@ GMPVideoDecoderParent::Shutdown() // Notify client we're gone! Won't occur after Close() if (mCallback) { mCallback->Terminated(); mCallback = nullptr; } mIsOpen = false; - unused << SendDecodingComplete(); + if (!mActorDestroyed) { + unused << SendDecodingComplete(); + } return NS_OK; } // Note: Keep this sync'd up with Shutdown void GMPVideoDecoderParent::ActorDestroy(ActorDestroyReason aWhy) { mIsOpen = false; + mActorDestroyed = true; mVideoHost.DoneWithAPI(); if (mCallback) { // May call Close() (and Shutdown()) immediately or with a delay mCallback->Terminated(); mCallback = nullptr; } if (mPlugin) {
--- a/dom/media/gmp/GMPVideoDecoderParent.h +++ b/dom/media/gmp/GMPVideoDecoderParent.h @@ -76,16 +76,17 @@ private: virtual bool RecvShutdown() override; virtual bool RecvParentShmemForPool(Shmem&& aEncodedBuffer) override; virtual bool AnswerNeedShmem(const uint32_t& aFrameBufferSize, Shmem* aMem) override; virtual bool Recv__delete__() override; bool mIsOpen; bool mShuttingDown; + bool mActorDestroyed; nsRefPtr<GMPContentParent> mPlugin; GMPVideoDecoderCallbackProxy* mCallback; GMPVideoHostImpl mVideoHost; }; } // namespace gmp } // namespace mozilla
--- a/dom/media/gmp/GMPVideoEncoderParent.cpp +++ b/dom/media/gmp/GMPVideoEncoderParent.cpp @@ -49,16 +49,17 @@ namespace gmp { // on ActorDestroy -> Dead // on Shutdown -> Dead // Dead: mIsOpen == false GMPVideoEncoderParent::GMPVideoEncoderParent(GMPContentParent *aPlugin) : GMPSharedMemManager(aPlugin), mIsOpen(false), mShuttingDown(false), + mActorDestroyed(false), mPlugin(aPlugin), mCallback(nullptr), mVideoHost(this) { MOZ_ASSERT(mPlugin); nsresult rv = NS_NewNamedThread("GMPEncoded", getter_AddRefs(mEncodedThread)); if (NS_FAILED(rv)) { @@ -230,31 +231,34 @@ GMPVideoEncoderParent::Shutdown() // Notify client we're gone! Won't occur after Close() if (mCallback) { mCallback->Terminated(); mCallback = nullptr; } mVideoHost.DoneWithAPI(); mIsOpen = false; - unused << SendEncodingComplete(); + if (!mActorDestroyed) { + unused << SendEncodingComplete(); + } } static void ShutdownEncodedThread(nsCOMPtr<nsIThread>& aThread) { aThread->Shutdown(); } // Note: Keep this sync'd up with Shutdown void GMPVideoEncoderParent::ActorDestroy(ActorDestroyReason aWhy) { LOGD(("%s::%s: %p (%d)", __CLASS__, __FUNCTION__, this, (int) aWhy)); mIsOpen = false; + mActorDestroyed = true; if (mCallback) { // May call Close() (and Shutdown()) immediately or with a delay mCallback->Terminated(); mCallback = nullptr; } // Must be shut down before VideoEncoderDestroyed(), since this can recurse // the GMPThread event loop. See bug 1049501 if (mEncodedThread) {
--- a/dom/media/gmp/GMPVideoEncoderParent.h +++ b/dom/media/gmp/GMPVideoEncoderParent.h @@ -72,16 +72,17 @@ private: virtual bool RecvShutdown() override; virtual bool RecvParentShmemForPool(Shmem&& aFrameBuffer) override; virtual bool AnswerNeedShmem(const uint32_t& aEncodedBufferSize, Shmem* aMem) override; virtual bool Recv__delete__() override; bool mIsOpen; bool mShuttingDown; + bool mActorDestroyed; nsRefPtr<GMPContentParent> mPlugin; GMPVideoEncoderCallbackProxy* mCallback; GMPVideoHostImpl mVideoHost; nsCOMPtr<nsIThread> mEncodedThread; }; } // namespace gmp } // namespace mozilla
--- a/dom/promise/Promise.cpp +++ b/dom/promise/Promise.cpp @@ -165,17 +165,17 @@ GetPromise(JSContext* aCx, JS::Handle<JS MOZ_ASSERT(promiseVal.isObject()); Promise* promise; UNWRAP_OBJECT(Promise, &promiseVal.toObject(), promise); return promise; } }; -// Main thread runnable to resolve thenables. +// Runnable to resolve thenables. // Equivalent to the specification's ResolvePromiseViaThenableTask. class ThenableResolverTask final : public nsRunnable { public: ThenableResolverTask(Promise* aPromise, JS::Handle<JSObject*> aThenable, PromiseInit* aThen) : mPromise(aPromise) @@ -196,16 +196,18 @@ public: protected: NS_IMETHOD Run() override { NS_ASSERT_OWNINGTHREAD(ThenableResolverTask); ThreadsafeAutoJSContext cx; JS::Rooted<JSObject*> wrapper(cx, mPromise->GetWrapper()); MOZ_ASSERT(wrapper); // It was preserved! + // If we ever change which compartment we're working in here, make sure to + // fix the fast-path for resolved-with-a-Promise in ResolveInternal. JSAutoCompartment ac(cx, wrapper); JS::Rooted<JSObject*> resolveFunc(cx, mPromise->CreateThenableFunction(cx, mPromise, PromiseCallback::Resolve)); if (!resolveFunc) { mPromise->HandleException(cx); return NS_OK; @@ -266,16 +268,58 @@ protected: private: nsRefPtr<Promise> mPromise; JS::PersistentRooted<JSObject*> mThenable; nsRefPtr<PromiseInit> mThen; NS_DECL_OWNINGTHREAD; }; +// Fast version of ThenableResolverTask for use in the cases when we know we're +// calling the canonical Promise.prototype.then on an actual DOM Promise. In +// that case we can just bypass the jumping into and out of JS and call +// AppendCallbacks on that promise directly. +class FastThenableResolverTask final : public nsRunnable +{ +public: + FastThenableResolverTask(PromiseCallback* aResolveCallback, + PromiseCallback* aRejectCallback, + Promise* aNextPromise) + : mResolveCallback(aResolveCallback) + , mRejectCallback(aRejectCallback) + , mNextPromise(aNextPromise) + { + MOZ_ASSERT(aResolveCallback); + MOZ_ASSERT(aRejectCallback); + MOZ_ASSERT(aNextPromise); + MOZ_COUNT_CTOR(FastThenableResolverTask); + } + + virtual + ~FastThenableResolverTask() + { + NS_ASSERT_OWNINGTHREAD(FastThenableResolverTask); + MOZ_COUNT_DTOR(FastThenableResolverTask); + } + +protected: + NS_IMETHOD + Run() override + { + NS_ASSERT_OWNINGTHREAD(FastThenableResolverTask); + mNextPromise->AppendCallbacks(mResolveCallback, mRejectCallback); + return NS_OK; + } + +private: + nsRefPtr<PromiseCallback> mResolveCallback; + nsRefPtr<PromiseCallback> mRejectCallback; + nsRefPtr<Promise> mNextPromise; +}; + // Promise NS_IMPL_CYCLE_COLLECTION_CLASS(Promise) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Promise) #if defined(DOM_PROMISE_DEPRECATED_REPORTING) tmp->MaybeReportRejectedOnce(); #else @@ -1193,16 +1237,47 @@ Promise::ResolveInternal(JSContext* aCx, if (!JS_GetProperty(aCx, valueObj, "then", &then)) { HandleException(aCx); return; } if (then.isObject() && JS::IsCallable(&then.toObject())) { // This is the then() function of the thenable aValueObj. JS::Rooted<JSObject*> thenObj(aCx, &then.toObject()); + + // Add a fast path for the case when we're resolved with an actual + // Promise. This has two requirements: + // + // 1) valueObj is a Promise. + // 2) thenObj is a JSFunction backed by our actual Promise::Then + // implementation. + // + // If those requirements are satisfied, then we know exactly what + // thenObj.call(valueObj) will do, so we can optimize a bit and avoid ever + // entering JS for this stuff. + Promise* nextPromise; + if (PromiseBinding::IsThenMethod(thenObj) && + NS_SUCCEEDED(UNWRAP_OBJECT(Promise, valueObj, nextPromise))) { + // If we were taking the codepath that involves ThenableResolverTask and + // PromiseInit below, then eventually, in ThenableResolverTask::Run, we + // would create some JSFunctions in the compartment of + // this->GetWrapper() and pass them to the PromiseInit. So by the time + // we'd see the resolution value it would be wrapped into the + // compartment of this->GetWrapper(). The global of that compartment is + // this->GetGlobalJSObject(), so use that as the global for + // ResolvePromiseCallback/RejectPromiseCallback. + JS::Rooted<JSObject*> glob(aCx, GlobalJSObject()); + nsRefPtr<PromiseCallback> resolveCb = new ResolvePromiseCallback(this, glob); + nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(this, glob); + nsRefPtr<FastThenableResolverTask> task = + new FastThenableResolverTask(resolveCb, rejectCb, nextPromise); + DispatchToMicroTask(task); + return; + } + nsRefPtr<PromiseInit> thenCallback = new PromiseInit(thenObj, mozilla::dom::GetIncumbentGlobal()); nsRefPtr<ThenableResolverTask> task = new ThenableResolverTask(this, valueObj, thenCallback); DispatchToMicroTask(task); return; } }
--- a/dom/promise/Promise.h +++ b/dom/promise/Promise.h @@ -80,16 +80,17 @@ class Promise : public nsISupports, #if defined(DOM_PROMISE_DEPRECATED_REPORTING) friend class PromiseReportRejectFeature; #endif // defined(DOM_PROMISE_DEPRECATED_REPORTING) friend class PromiseWorkerProxy; friend class PromiseWorkerProxyRunnable; friend class RejectPromiseCallback; friend class ResolvePromiseCallback; friend class ThenableResolverTask; + friend class FastThenableResolverTask; friend class WrapperPromiseCallback; public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_PROMISE_IID) NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_SKIPPABLE_SCRIPT_HOLDER_CLASS(Promise) MOZ_DECLARE_REFCOUNTED_TYPENAME(Promise)
--- a/dom/promise/tests/mochitest.ini +++ b/dom/promise/tests/mochitest.ini @@ -1,8 +1,9 @@ [DEFAULT] [test_abortable_promise.html] [test_bug883683.html] [test_promise.html] [test_promise_utils.html] [test_resolve.html] [test_resolver_return_value.html] +[test_thenable_vs_promise_ordering.html]
new file mode 100644 --- /dev/null +++ b/dom/promise/tests/test_thenable_vs_promise_ordering.html @@ -0,0 +1,27 @@ +<!DOCTYPE html> +<meta charset=utf-8> +<title>Test for promise resolution ordering with thenables and promises</title> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<div id="log"></div> +<script> +var t = async_test("A promise resolved first (with a thenable) should trigger its callbacks before a promise resolved second (with a promise)."); +t.step(function() { + var customThenCalled = false; + var p0 = Promise.resolve(); + p0.then = function(resolved, rejected) { + customThenCalled = true; + Promise.prototype.then.call(this, resolved, rejected); + } + var p1 = new Promise(function(r) { r(p0); }); + delete p0.then; + var p2 = new Promise(function(r) { r(p0); }); + var resolutionOrder = ""; + Promise.all([ p1.then(function() { resolutionOrder += "1"; }), + p2.then(function() { resolutionOrder += "2"; }) ]) + .then(t.step_func_done(function() { + assert_true(customThenCalled, "Should have called custom then"); + assert_equals(resolutionOrder, "12"); + })); +}); +</script>
--- a/dom/push/test/test_has_permissions.html +++ b/dom/push/test/test_has_permissions.html @@ -30,16 +30,18 @@ http://creativecommons.org/licenses/publ function start() { return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."}) .then((swr) => registration = swr); } function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function hasPermission(swr) { var p = new Promise(function(res, rej) { swr.pushManager.hasPermission().then( function(status) { debug("status: " + status);
--- a/dom/push/test/test_multiple_register.html +++ b/dom/push/test/test_multiple_register.html @@ -30,16 +30,18 @@ http://creativecommons.org/licenses/publ function start() { return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."}) .then((swr) => registration = swr); } function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function setupPushNotification(swr) { var p = new Promise(function(res, rej) { swr.pushManager.subscribe().then( function(pushSubscription) { ok(true, "successful registered for push notification");
--- a/dom/push/test/test_permissions.html +++ b/dom/push/test/test_permissions.html @@ -30,16 +30,18 @@ http://creativecommons.org/licenses/publ function start() { return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."}) .then((swr) => registration = swr); } function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function setupPushNotification(swr) { var p = new Promise(function(res, rej) { swr.pushManager.subscribe().then( function(pushSubscription) { ok(false, "subscribe() should fail because no permission for push");
--- a/dom/push/test/test_register.html +++ b/dom/push/test/test_register.html @@ -62,16 +62,18 @@ http://creativecommons.org/licenses/publ function start() { return navigator.serviceWorker.register("worker.js" + "?" + (Math.random()), {scope: "."}) .then((swr) => registration = swr); } function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function setupPushNotification(swr) { var p = new Promise(function(res, rej) { swr.pushManager.subscribe().then( function(pushSubscription) { ok(true, "successful registered for push notification");
--- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -125,22 +125,22 @@ var interfaceNamesInGlobalScope = [ // IMPORTANT: Do not change this list without review from a DOM peer! {name: "MozAbortablePromise", pref: "dom.abortablepromise.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer! {name: "AlarmsManager", pref: "dom.mozAlarms.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer! "AnalyserNode", // IMPORTANT: Do not change this list without review from a DOM peer! + {name: "Animation", pref: "dom.animations-api.core.enabled"}, +// IMPORTANT: Do not change this list without review from a DOM peer! {name: "AnimationEffectReadonly", pref: "dom.animations-api.core.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer! "AnimationEvent", // IMPORTANT: Do not change this list without review from a DOM peer! - {name: "AnimationPlayer", pref: "dom.animations-api.core.enabled"}, -// IMPORTANT: Do not change this list without review from a DOM peer! {name: "AnimationTimeline", pref: "dom.animations-api.core.enabled"}, // IMPORTANT: Do not change this list without review from a DOM peer! "Attr", // IMPORTANT: Do not change this list without review from a DOM peer! "Audio", // IMPORTANT: Do not change this list without review from a DOM peer! "AudioBuffer", // IMPORTANT: Do not change this list without review from a DOM peer!
--- a/dom/webidl/Animatable.webidl +++ b/dom/webidl/Animatable.webidl @@ -8,10 +8,10 @@ * * Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C * liability, trademark and document use rules apply. */ [NoInterfaceObject] interface Animatable { [Func="nsDocument::IsWebAnimationsEnabled"] - sequence<AnimationPlayer> getAnimations(); + sequence<Animation> getAnimations(); };
rename from dom/webidl/AnimationPlayer.webidl rename to dom/webidl/Animation.webidl --- a/dom/webidl/AnimationPlayer.webidl +++ b/dom/webidl/Animation.webidl @@ -1,49 +1,49 @@ /* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. * * The origin of this IDL file is - * http://dev.w3.org/fxtf/web-animations/#idl-def-AnimationPlayer + * http://w3c.github.io/web-animations/#the-animation-interface * - * Copyright © 2014 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C + * Copyright © 2015 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C * liability, trademark and document use rules apply. */ enum AnimationPlayState { "idle", "pending", "running", "paused", "finished" }; [Func="nsDocument::IsWebAnimationsEnabled"] -interface AnimationPlayer { +interface Animation { // Bug 1049975: Make 'effect' writeable [Pure] readonly attribute AnimationEffectReadonly? effect; readonly attribute AnimationTimeline timeline; [BinaryName="startTimeAsDouble"] attribute double? startTime; [SetterThrows, BinaryName="currentTimeAsDouble"] attribute double? currentTime; attribute double playbackRate; [BinaryName="playStateFromJS"] readonly attribute AnimationPlayState playState; [Throws] - readonly attribute Promise<AnimationPlayer> ready; + readonly attribute Promise<Animation> ready; [Throws] - readonly attribute Promise<AnimationPlayer> finished; + readonly attribute Promise<Animation> finished; /* void cancel (); void finish (); */ [BinaryName="playFromJS"] void play (); [BinaryName="pauseFromJS"] void pause (); /* void reverse (); */ }; // Non-standard extensions -partial interface AnimationPlayer { +partial interface Animation { [ChromeOnly] readonly attribute boolean isRunningOnCompositor; };
--- a/dom/webidl/AnimationTimeline.webidl +++ b/dom/webidl/AnimationTimeline.webidl @@ -10,11 +10,11 @@ * liability, trademark and document use rules apply. */ [Func="nsDocument::IsWebAnimationsEnabled"] interface AnimationTimeline { [BinaryName="currentTimeAsDouble"] readonly attribute double? currentTime; // Not yet implemented: - // AnimationPlayer play (optional TimedItem? source = null); - // sequence<AnimationPlayer> getAnimations (); + // Animation play (optional TimedItem? source = null); + // sequence<Animation> getAnimations (); };
--- a/dom/webidl/MutationObserver.webidl +++ b/dom/webidl/MutationObserver.webidl @@ -24,21 +24,21 @@ interface MutationRecord { readonly attribute Node? nextSibling; [Constant] readonly attribute DOMString? attributeName; [Constant] readonly attribute DOMString? attributeNamespace; [Constant] readonly attribute DOMString? oldValue; [Constant,Cached,ChromeOnly] - readonly attribute sequence<AnimationPlayer> addedAnimations; + readonly attribute sequence<Animation> addedAnimations; [Constant,Cached,ChromeOnly] - readonly attribute sequence<AnimationPlayer> changedAnimations; + readonly attribute sequence<Animation> changedAnimations; [Constant,Cached,ChromeOnly] - readonly attribute sequence<AnimationPlayer> removedAnimations; + readonly attribute sequence<Animation> removedAnimations; }; [Constructor(MutationCallback mutationCallback)] interface MutationObserver { [Throws] void observe(Node target, optional MutationObserverInit options); void disconnect(); sequence<MutationRecord> takeRecords();
--- a/dom/webidl/Promise.webidl +++ b/dom/webidl/Promise.webidl @@ -29,17 +29,17 @@ interface _Promise { // first. [NewObject] static Promise<any> resolve(optional any value); [NewObject] static Promise<void> reject(optional any value); // The [TreatNonCallableAsNull] annotation is required since then() should do // nothing instead of throwing errors when non-callable arguments are passed. - [NewObject] + [NewObject, MethodIdentityTestable] Promise<any> then([TreatNonCallableAsNull] optional AnyCallback? fulfillCallback = null, [TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null); [NewObject] Promise<any> catch([TreatNonCallableAsNull] optional AnyCallback? rejectCallback = null); [NewObject] static Promise<any> all(sequence<any> iterable);
--- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -17,19 +17,19 @@ PREPROCESSED_WEBIDL_FILES = [ WEBIDL_FILES = [ 'AbortablePromise.webidl', 'AbstractWorker.webidl', 'ActivityRequestHandler.webidl', 'AlarmsManager.webidl', 'AnalyserNode.webidl', 'Animatable.webidl', + 'Animation.webidl', 'AnimationEffectReadonly.webidl', 'AnimationEvent.webidl', - 'AnimationPlayer.webidl', 'AnimationTimeline.webidl', 'AnonymousContent.webidl', 'AppInfo.webidl', 'AppNotificationServiceOptions.webidl', 'Apps.webidl', 'APZTestData.webidl', 'ArchiveReader.webidl', 'ArchiveRequest.webidl',
--- a/dom/workers/test/serviceworkers/controller/index.html +++ b/dom/workers/test/serviceworkers/controller/index.html @@ -45,17 +45,23 @@ my_ok("scope" in e, "ServiceWorkerRegistration.scope exists."); my_ok(e.scope.match(/serviceworkers\/controller\/$/), "Scope is serviceworker/controller " + e.scope); my_ok("unregister" in e, "ServiceWorkerRegistration.unregister exists."); my_ok(navigator.serviceWorker.controller.scriptURL.match(/worker\.js$/), "Controller is still worker.js"); - finish(); + + e.unregister().then(function(result) { + my_ok(result, "Unregistering the SW should succeed"); + finish(); + }, function(e) { + dump("Error unregistering the SW: " + e + "\n"); + }); }); } else { my_ok(false, "Should've been controlled!"); finish(); } }).catch(function(e) { my_ok(false, "Some test threw an error " + e); finish();
--- a/dom/workers/test/serviceworkers/fetch/context/register.html +++ b/dom/workers/test/serviceworkers/fetch/context/register.html @@ -1,26 +1,14 @@ <!DOCTYPE html> <script> function ok(v, msg) { window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*"); } - var isDone = false; function done(reg) { - if (!isDone) { - ok(reg.waiting || reg.active, "Either active or waiting worker should be available."); - window.parent.postMessage({status: "registrationdone"}, "*"); - isDone = true; - } + ok(reg.active, "The active worker should be available."); + window.parent.postMessage({status: "registrationdone"}, "*"); } - navigator.serviceWorker.register("context_test.js", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - done(registration); - }; - } else { - done(registration); - } - }); + navigator.serviceWorker.ready.then(done); + navigator.serviceWorker.register("context_test.js", {scope: "."}); </script>
--- a/dom/workers/test/serviceworkers/fetch/context/unregister.html +++ b/dom/workers/test/serviceworkers/fetch/context/unregister.html @@ -1,10 +1,12 @@ <!DOCTYPE html> <script> navigator.serviceWorker.getRegistration(".").then(function(registration) { registration.unregister().then(function(success) { if (success) { window.parent.postMessage({status: "unregistrationdone"}, "*"); } + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); }); </script>
--- a/dom/workers/test/serviceworkers/fetch/fetch_tests.js +++ b/dom/workers/test/serviceworkers/fetch/fetch_tests.js @@ -105,20 +105,20 @@ fetchXHR('hello.gz', function(xhr) { my_ok(xhr.status == 200, "gzip load should be successful"); my_ok(xhr.responseText == expectedUncompressedResponse, "gzip load should have synthesized response."); my_ok(xhr.getResponseHeader("Content-Encoding") == "gzip", "Content-Encoding should be gzip."); my_ok(xhr.getResponseHeader("Content-Length") == "35", "Content-Length should be of original gzipped file."); finish(); }); fetchXHR('hello-after-extracting.gz', function(xhr) { - my_ok(xhr.status == 200, "gzip load should be successful"); - my_ok(xhr.responseText == expectedUncompressedResponse, "gzip load should have synthesized response."); - my_ok(xhr.getResponseHeader("Content-Encoding") == "gzip", "Content-Encoding should be gzip."); - my_ok(xhr.getResponseHeader("Content-Length") == "35", "Content-Length should be of original gzipped file."); + my_ok(xhr.status == 200, "gzip load after extracting should be successful"); + my_ok(xhr.responseText == expectedUncompressedResponse, "gzip load after extracting should have synthesized response."); + my_ok(xhr.getResponseHeader("Content-Encoding") == "gzip", "Content-Encoding after extracting should be gzip."); + my_ok(xhr.getResponseHeader("Content-Length") == "35", "Content-Length after extracting should be of original gzipped file."); finish(); }); fetchXHR('http://example.com/tests/dom/base/test/file_CrossSiteXHR_server.sjs?status=200&allowOrigin=*', function(xhr) { my_ok(xhr.status == 200, "cross origin load with correct headers should be successful"); my_ok(xhr.getResponseHeader("access-control-allow-origin") == null, "cors headers should be filtered out"); finish(); });
--- a/dom/workers/test/serviceworkers/fetch/https/clonedresponse/register.html +++ b/dom/workers/test/serviceworkers/fetch/https/clonedresponse/register.html @@ -1,26 +1,14 @@ <!DOCTYPE html> <script> function ok(v, msg) { window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*"); } - var isDone = false; function done(reg) { - if (!isDone) { - ok(reg.waiting || reg.active, "Either active or waiting worker should be available."); - window.parent.postMessage({status: "registrationdone"}, "*"); - isDone = true; - } + ok(reg.active, "The active worker should be available."); + window.parent.postMessage({status: "registrationdone"}, "*"); } - navigator.serviceWorker.register("https_test.js", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - done(registration); - }; - } else { - done(registration); - } - }); + navigator.serviceWorker.ready.then(done); + navigator.serviceWorker.register("https_test.js", {scope: "."}); </script>
--- a/dom/workers/test/serviceworkers/fetch/https/clonedresponse/unregister.html +++ b/dom/workers/test/serviceworkers/fetch/https/clonedresponse/unregister.html @@ -1,10 +1,12 @@ <!DOCTYPE html> <script> navigator.serviceWorker.getRegistration(".").then(function(registration) { registration.unregister().then(function(success) { if (success) { window.parent.postMessage({status: "unregistrationdone"}, "*"); } + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); }); </script>
--- a/dom/workers/test/serviceworkers/fetch/https/register.html +++ b/dom/workers/test/serviceworkers/fetch/https/register.html @@ -1,26 +1,14 @@ <!DOCTYPE html> <script> function ok(v, msg) { window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*"); } - var isDone = false; function done(reg) { - if (!isDone) { - ok(reg.waiting || reg.active, "Either active or waiting worker should be available."); - window.parent.postMessage({status: "registrationdone"}, "*"); - isDone = true; - } + ok(reg.active, "The active worker should be available."); + window.parent.postMessage({status: "registrationdone"}, "*"); } - navigator.serviceWorker.register("https_test.js", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - done(registration); - }; - } else { - done(registration); - } - }); + navigator.serviceWorker.ready.then(done); + navigator.serviceWorker.register("https_test.js", {scope: "."}); </script>
--- a/dom/workers/test/serviceworkers/fetch/https/unregister.html +++ b/dom/workers/test/serviceworkers/fetch/https/unregister.html @@ -1,10 +1,12 @@ <!DOCTYPE html> <script> navigator.serviceWorker.getRegistration(".").then(function(registration) { registration.unregister().then(function(success) { if (success) { window.parent.postMessage({status: "unregistrationdone"}, "*"); } + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); }); </script>
--- a/dom/workers/test/serviceworkers/fetch/sandbox/register.html +++ b/dom/workers/test/serviceworkers/fetch/sandbox/register.html @@ -1,26 +1,14 @@ <!DOCTYPE html> <script> function ok(v, msg) { window.parent.postMessage({status: "ok", result: !!v, message: msg}, "*"); } - var isDone = false; function done(reg) { - if (!isDone) { - ok(reg.waiting || reg.active, "Either active or waiting worker should be available."); - window.parent.postMessage({status: "registrationdone"}, "*"); - isDone = true; - } + ok(reg.active, "The active worker should be available."); + window.parent.postMessage({status: "registrationdone"}, "*"); } - navigator.serviceWorker.register("sandbox_test.js", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - done(registration); - }; - } else { - done(registration); - } - }); + navigator.serviceWorker.ready.then(done); + navigator.serviceWorker.register("sandbox_test.js", {scope: "."}); </script>
--- a/dom/workers/test/serviceworkers/fetch/sandbox/unregister.html +++ b/dom/workers/test/serviceworkers/fetch/sandbox/unregister.html @@ -1,10 +1,12 @@ <!DOCTYPE html> <script> navigator.serviceWorker.getRegistration(".").then(function(registration) { registration.unregister().then(function(success) { if (success) { window.parent.postMessage({status: "unregistrationdone"}, "*"); } + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); }); </script>
--- a/dom/workers/test/serviceworkers/mochitest.ini +++ b/dom/workers/test/serviceworkers/mochitest.ini @@ -98,9 +98,8 @@ skip-if = os != "linux" # Bug 1136780 [test_match_all_client_id.html] [test_sandbox_intercept.html] [test_request_context.html] [test_importscript.html] [test_client_focus.html] [test_bug1151916.html] [test_empty_serviceworker.html] [test_periodic_update.html] -skip-if = true # bug 1151974
--- a/dom/workers/test/serviceworkers/periodic/register.html +++ b/dom/workers/test/serviceworkers/periodic/register.html @@ -1,21 +1,9 @@ <!DOCTYPE html> <script> - var isDone = false; function done() { - if (!isDone) { - parent.callback(); - isDone = true; - } + parent.callback(); } - navigator.serviceWorker.register("../periodic.sjs", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - done(); - }; - } else { - done(); - } - }); + navigator.serviceWorker.ready.then(done); + navigator.serviceWorker.register("../periodic.sjs", {scope: "."}); </script>
--- a/dom/workers/test/serviceworkers/periodic/unregister.html +++ b/dom/workers/test/serviceworkers/periodic/unregister.html @@ -2,11 +2,13 @@ <script> navigator.serviceWorker.getRegistration(".").then(function(registration) { registration.unregister().then(function(success) { if (success) { parent.callback(); } else { dump("Unregister failed\n"); } + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); }); </script>
--- a/dom/workers/test/serviceworkers/test_client_focus.html +++ b/dom/workers/test/serviceworkers/test_client_focus.html @@ -25,16 +25,18 @@ return navigator.serviceWorker.register("client_focus_worker.js", { scope: "./sw_clients/focus_stealing_client.html" }) .then((swr) => registration = swr); } function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function loseFocus() { var p = new Promise(function(res, rej) { window.onmessage = function(e) { if (e.data == "READY") { ok(true, "iframe created.");
--- a/dom/workers/test/serviceworkers/test_close.html +++ b/dom/workers/test/serviceworkers/test_close.html @@ -14,27 +14,18 @@ <div id="content" style="display: none"> <iframe></iframe> </div> <pre id="test"></pre> <script class="testbody" type="text/javascript"> var iframe; function runTest() { - navigator.serviceWorker.register("close_test.js", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - setupSW(registration); - e.target.onstatechange = null; - }; - } else { - setupSW(registration); - } - }); + navigator.serviceWorker.ready.then(setupSW); + navigator.serviceWorker.register("close_test.js", {scope: "."}); function setupSW(registration) { var worker = registration.waiting || registration.active; var iframe = document.createElement("iframe"); iframe.src = "message_receiver.html"; iframe.onload = function() { worker.postMessage({ message: "start" }); @@ -42,17 +33,21 @@ document.body.appendChild(iframe); } window.onmessage = function(e) { if (e.data.status == "ok") { ok(e.data.result, e.data.message); } else if (e.data.status == "done") { navigator.serviceWorker.getRegistration().then(function(registration) { - registration.unregister().then(function() { + registration.unregister().then(function(result) { + ok(result, "Unregistering the service worker should succeed"); + SimpleTest.finish(); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); SimpleTest.finish(); }); }); } }; } SimpleTest.waitForExplicitFinish();
--- a/dom/workers/test/serviceworkers/test_controller.html +++ b/dom/workers/test/serviceworkers/test_controller.html @@ -12,20 +12,32 @@ <body> <p id="display"></p> <div id="content" style="display: none"></div> <pre id="test"></pre> <script class="testbody" type="text/javascript"> var content; var iframe; + var registration; function simpleRegister() { // We use the control scope for the less specific registration. The window will register a worker on controller/ - return navigator.serviceWorker.register("worker.js", { scope: "./control" }); + return navigator.serviceWorker.register("worker.js", { scope: "./control" }) + .then(function(reg) { + registration = reg; + });; + } + + function unregister() { + return registration.unregister().then(function(result) { + ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed: " + e + "\n"); + }); } function testController() { var p = new Promise(function(resolve, reject) { window.onmessage = function(e) { if (e.data.status == "ok") { ok(e.data.result, e.data.message); } else if (e.data.status == "done") { @@ -45,16 +57,17 @@ return p; } // This document just flips the prefs and opens the iframe for the actual test. function runTest() { simpleRegister() .then(testController) + .then(unregister) .then(function() { SimpleTest.finish(); }).catch(function(e) { ok(false, "Some test failed with error " + e); SimpleTest.finish(); }); }
--- a/dom/workers/test/serviceworkers/test_empty_serviceworker.html +++ b/dom/workers/test/serviceworkers/test_empty_serviceworker.html @@ -12,34 +12,28 @@ <body> <p id="display"></p> <div id="content" style="display: none"> </div> <pre id="test"></pre> <script class="testbody" type="text/javascript"> function runTest() { - navigator.serviceWorker.register("empty.js", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - e.target.onstatechange = null; - done(registration); - }; - } else { - done(registration); - } - }); + navigator.serviceWorker.ready.then(done); + navigator.serviceWorker.register("empty.js", {scope: "."}); } function done(registration) { ok(registration.waiting || registration.active, "registration worked"); registration.unregister().then(function(success) { ok(success, "unregister worked"); SimpleTest.finish(); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); + SimpleTest.finish(); }); } SimpleTest.waitForExplicitFinish(); onload = function() { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.serviceWorkers.enabled", true],
--- a/dom/workers/test/serviceworkers/test_fetch_event.html +++ b/dom/workers/test/serviceworkers/test_fetch_event.html @@ -11,25 +11,35 @@ </head> <body> <p id="display"></p> <div id="content" style="display: none"></div> <pre id="test"></pre> <script class="testbody" type="text/javascript"> SimpleTest.requestCompleteLog(); + var registration; function simpleRegister() { var p = navigator.serviceWorker.register("fetch_event_worker.js", { scope: "./fetch" }); return p.then(function(swr) { + registration = swr; return new Promise(function(resolve) { swr.installing.onstatechange = resolve; }); }); } + function unregister() { + return registration.unregister().then(function(success) { + ok(success, "Service worker should be unregistered successfully"); + }, function(e) { + dump("SW unregistration error: " + e + "\n"); + }); + } + function testController() { var p = new Promise(function(resolve, reject) { var reloaded = false; window.onmessage = function(e) { if (e.data.status == "ok") { ok(e.data.result, e.data.message); } else if (e.data.status == "done") { if (reloaded) { @@ -46,16 +56,17 @@ var w = window.open("fetch/index.html"); return p; } function runTest() { simpleRegister() .then(testController) + .then(unregister) .then(function() { SimpleTest.finish(); }).catch(function(e) { ok(false, "Some test failed with error " + e); SimpleTest.finish(); }); }
--- a/dom/workers/test/serviceworkers/test_importscript.html +++ b/dom/workers/test/serviceworkers/test_importscript.html @@ -16,16 +16,18 @@ return navigator.serviceWorker.register("importscript_worker.js", { scope: "./sw_clients/" }) .then((swr) => registration = swr); } function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function testPostMessage(swr) { var p = new Promise(function(res, rej) { window.onmessage = function(e) { if (e.data === "READY") { swr.active.postMessage("do magic");
--- a/dom/workers/test/serviceworkers/test_installation_simple.html +++ b/dom/workers/test/serviceworkers/test_installation_simple.html @@ -64,16 +64,21 @@ ok(wr.scope == (new URL("realworker", document.baseURI)).href, "Scope should match"); // active, waiting, installing should return valid worker instances // because the registration is for the realworker scope, so the workers // should be obtained for that scope and not for // test_installation_simple.html var worker = wr.installing; ok(worker && wr.scope.match(/realworker$/) && worker.scriptURL.match(/worker.js$/), "Valid worker instance should be available."); + return wr.unregister().then(function(success) { + ok(success, "The worker should be unregistered successfully"); + }, function(e) { + dump("Error unregistering the worker: " + e + "\n"); + }); }, function(e) { info("Error: " + e.name); ok(false, "realWorker Registration should have succeeded!"); }); } function networkError404() { return navigator.serviceWorker.register("404.js", { scope: "network_error/"}).then(function(w) { @@ -112,30 +117,39 @@ frame.setAttribute("src", new URL("simpleregister/index.html", document.baseURI).href); document.body.appendChild(frame); var resolve, reject; var p = new Promise(function(res, rej) { resolve = res; reject = rej; }); + var reg; function continueTest() { - navigator.serviceWorker.register("worker2.js", { scope: "simpleregister/" }); + navigator.serviceWorker.register("worker2.js", { scope: "simpleregister/" }) + .then(function(r) { + reg = r; + });; } window.onmessage = function(e) { if (e.data.type == "ready") { continueTest(); } else if (e.data.type == "finish") { window.onmessage = null; // We have to make frame navigate away, otherwise it will call // MaybeStopControlling() when this document is unloaded. At that point // the pref has been disabled, so the ServiceWorkerManager is not available. frame.setAttribute("src", new URL("about:blank").href); - resolve(); + reg.unregister().then(function(success) { + ok(success, "The worker should be unregistered successfully"); + resolve(); + }, function(e) { + dump("Error unregistering the worker: " + e + "\n"); + }); } else if (e.data.type == "check") { ok(e.data.status, e.data.msg); } } return p; } var readyPromiseResolved = false;
--- a/dom/workers/test/serviceworkers/test_match_all.html +++ b/dom/workers/test/serviceworkers/test_match_all.html @@ -26,16 +26,18 @@ .then((swr) => registration = swr); } function closeAndUnregister() { content.removeChild(iframe); return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function openClient() { var p = new Promise(function(resolve, reject) { window.onmessage = function(e) { if (e.data === "READY") { resolve();
--- a/dom/workers/test/serviceworkers/test_match_all_advanced.html +++ b/dom/workers/test/serviceworkers/test_match_all_advanced.html @@ -28,16 +28,18 @@ } } }); } function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function testMatchAll() { var p = new Promise(function(res, rej) { navigator.serviceWorker.onmessage = function (e) { ok(e.data === client_iframes.length, "MatchAll returned the correct number of clients.");
--- a/dom/workers/test/serviceworkers/test_match_all_client_id.html +++ b/dom/workers/test/serviceworkers/test_match_all_client_id.html @@ -20,16 +20,18 @@ return navigator.serviceWorker.register("match_all_client_id_worker.js", { scope: "./match_all_client/" }) .then((swr) => registration = swr); } function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function getMessageListener() { return new Promise(function(res, rej) { window.onmessage = function(e) { ok(e.data, "Same client id for multiple calls."); @@ -65,16 +67,17 @@ return p.then(() => w.close()); } function runTest() { info(window.opener == undefined); start() .then(testAuxiliaryWindow) .then(testNestedWindow) + .then(unregister) .catch(function(e) { ok(false, "Some test failed with error " + e); }).then(SimpleTest.finish); } SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true],
--- a/dom/workers/test/serviceworkers/test_match_all_client_properties.html +++ b/dom/workers/test/serviceworkers/test_match_all_client_properties.html @@ -20,16 +20,18 @@ return navigator.serviceWorker.register("match_all_properties_worker.js", { scope: "./match_all_clients/" }) .then((swr) => registration = swr); } function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function getMessageListener() { return new Promise(function(res, rej) { window.onmessage = function(e) { if (e.data.message === undefined) { info("rejecting promise"); @@ -72,16 +74,17 @@ } function runTest() { info("catalin"); info(window.opener == undefined); start() .then(testAuxiliaryWindow) .then(testNestedWindow) + .then(unregister) .catch(function(e) { ok(false, "Some test failed with error " + e); }).then(SimpleTest.finish); } SimpleTest.waitForExplicitFinish(); SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true],
--- a/dom/workers/test/serviceworkers/test_post_message.html +++ b/dom/workers/test/serviceworkers/test_post_message.html @@ -20,16 +20,18 @@ return navigator.serviceWorker.register("message_posting_worker.js", { scope: "./sw_clients/" }) .then((swr) => registration = swr); } function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function testPostMessage(swr) { var p = new Promise(function(res, rej) { window.onmessage = function(e) { if (e.data === "READY") {
--- a/dom/workers/test/serviceworkers/test_post_message_advanced.html +++ b/dom/workers/test/serviceworkers/test_post_message_advanced.html @@ -50,16 +50,18 @@ return navigator.serviceWorker.register("message_posting_worker.js", { scope: "./sw_clients/" }) .then((swr) => registration = swr); } function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function testPostMessageObject(obj, test) { var p = new Promise(function(res, rej) { window.onmessage = function(e) { if (e.data === "READY") { registration.active.postMessage(obj)
--- a/dom/workers/test/serviceworkers/test_post_message_source.html +++ b/dom/workers/test/serviceworkers/test_post_message_source.html @@ -20,16 +20,18 @@ return navigator.serviceWorker.register("source_message_posting_worker.js", { scope: "./nonexistent_scope/" }) .then((swr) => registration = swr); } function unregister() { return registration.unregister().then(function(result) { ok(result, "Unregister should return true."); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); }); } function testPostMessage(swr) { var p = new Promise(function(res, rej) { navigator.serviceWorker.onmessage = function(e) { ok(e.data === magic_value, "Worker posted the correct value.");
--- a/dom/workers/test/serviceworkers/test_serviceworker_interfaces.html +++ b/dom/workers/test/serviceworkers/test_serviceworker_interfaces.html @@ -15,16 +15,19 @@ var worker = registration.waiting || registration.active; window.onmessage = function(event) { if (event.data.type == 'finish') { registration.unregister().then(function(success) { ok(success, "The service worker should be unregistered successfully"); SimpleTest.finish(); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); + SimpleTest.finish(); }); } else if (event.data.type == 'status') { ok(event.data.status, event.data.msg); } else if (event.data.type == 'getPrefs') { var result = {}; event.data.prefs.forEach(function(pref) { result[pref] = SpecialPowers.Services.prefs.getBoolPref(pref); @@ -80,27 +83,18 @@ iframe.src = "message_receiver.html"; iframe.onload = function() { worker.postMessage({ script: "test_serviceworker_interfaces.js" }); }; document.body.appendChild(iframe); } function runTest() { - navigator.serviceWorker.register("serviceworker_wrapper.js", {scope: "."}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - setupSW(registration); - e.target.onstatechange = null; - }; - } else { - setupSW(registration); - } - }); + navigator.serviceWorker.ready.then(setupSW); + navigator.serviceWorker.register("serviceworker_wrapper.js", {scope: "."}); } SimpleTest.waitForExplicitFinish(); onload = function() { SpecialPowers.pushPrefEnv({"set": [ ["dom.serviceWorkers.exemptFromPerDomainMax", true], ["dom.serviceWorkers.enabled", true], ["dom.serviceWorkers.testing.enabled", true],
--- a/dom/workers/test/serviceworkers/test_serviceworker_not_sharedworker.html +++ b/dom/workers/test/serviceworkers/test_serviceworker_not_sharedworker.html @@ -15,28 +15,19 @@ <iframe></iframe> </div> <pre id="test"></pre> <script class="testbody" type="text/javascript"> var iframe; const SCOPE = "http://mochi.test:8888/tests/dom/workers/test/serviceworkers/"; function runTest() { + navigator.serviceWorker.ready.then(setupSW); navigator.serviceWorker.register("serviceworker_not_sharedworker.js", - {scope: SCOPE}) - .then(function(registration) { - if (registration.installing) { - registration.installing.onstatechange = function(e) { - e.target.onstatechange = null; - setupSW(registration); - }; - } else { - setupSW(registration); - } - }); + {scope: SCOPE}); } var sw, worker; function setupSW(registration) { sw = registration.waiting || registration.active; worker = new SharedWorker("serviceworker_not_sharedworker.js", SCOPE); worker.port.start(); iframe = document.querySelector("iframe"); @@ -45,16 +36,19 @@ window.onmessage = function(e) { is(e.data.result, "serviceworker", "We should be talking to a service worker"); window.onmessage = null; worker.port.onmessage = function(e) { is(e.data.result, "sharedworker", "We should be talking to a shared worker"); registration.unregister().then(function(success) { ok(success, "unregister should succeed"); SimpleTest.finish(); + }, function(e) { + dump("Unregistering the SW failed with " + e + "\n"); + SimpleTest.finish(); }); }; worker.port.postMessage({msg: "whoareyou"}); }; sw.postMessage({msg: "whoareyou"}); }; }
--- a/dom/xul/nsXULContentSink.cpp +++ b/dom/xul/nsXULContentSink.cpp @@ -157,55 +157,52 @@ XULContentSinkImpl::ContextStack::Traver //---------------------------------------------------------------------- XULContentSinkImpl::XULContentSinkImpl() : mText(nullptr), mTextLength(0), mTextSize(0), mConstrainSize(true), - mState(eInProlog), - mParser(nullptr) + mState(eInProlog) { #ifdef PR_LOGGING if (! gContentSinkLog) gContentSinkLog = PR_NewLogModule("nsXULContentSink"); #endif } XULContentSinkImpl::~XULContentSinkImpl() { - NS_IF_RELEASE(mParser); // XXX should've been released by now, unless error. - // The context stack _should_ be empty, unless something has gone wrong. NS_ASSERTION(mContextStack.Depth() == 0, "Context stack not empty?"); mContextStack.Clear(); free(mText); } //---------------------------------------------------------------------- // nsISupports interface NS_IMPL_CYCLE_COLLECTION_CLASS(XULContentSinkImpl) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XULContentSinkImpl) NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager) tmp->mContextStack.Clear(); NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrototype) - NS_IF_RELEASE(tmp->mParser); + NS_IMPL_CYCLE_COLLECTION_UNLINK(mParser) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XULContentSinkImpl) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager) tmp->mContextStack.Traverse(cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrototype) - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_RAWPTR(mParser) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XULContentSinkImpl) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIXMLContentSink) NS_INTERFACE_MAP_ENTRY(nsIXMLContentSink) NS_INTERFACE_MAP_ENTRY(nsIExpatSink) NS_INTERFACE_MAP_ENTRY(nsIContentSink) NS_INTERFACE_MAP_END @@ -236,17 +233,17 @@ XULContentSinkImpl::DidBuildModel(bool a nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument); if (doc) { doc->EndLoad(); mDocument = nullptr; } // Drop our reference to the parser to get rid of a circular // reference. - NS_IF_RELEASE(mParser); + mParser = nullptr; return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::WillInterrupt(void) { // XXX Notify the docshell, if necessary return NS_OK; @@ -257,19 +254,17 @@ XULContentSinkImpl::WillResume(void) { // XXX Notify the docshell, if necessary return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::SetParser(nsParserBase* aParser) { - NS_IF_RELEASE(mParser); mParser = aParser; - NS_IF_ADDREF(mParser); return NS_OK; } NS_IMETHODIMP XULContentSinkImpl::SetDocumentCharset(nsACString& aCharset) { nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument); if (doc) {
--- a/dom/xul/nsXULContentSink.h +++ b/dom/xul/nsXULContentSink.h @@ -139,14 +139,13 @@ protected: friend class ContextStack; ContextStack mContextStack; nsWeakPtr mDocument; // [OWNER] nsCOMPtr<nsIURI> mDocumentURL; // [OWNER] nsRefPtr<nsXULPrototypeDocument> mPrototype; // [OWNER] - // We use regular pointer b/c of funky exports on nsIParser: - nsParserBase* mParser; // [OWNER] + nsRefPtr<nsParserBase> mParser; nsCOMPtr<nsIScriptSecurityManager> mSecMan; }; #endif /* nsXULContentSink_h__ */
new file mode 100644 --- /dev/null +++ b/gfx/doc/Silk.md @@ -0,0 +1,227 @@ +Silk Architecture Overview +================= + +#Architecture +Our current architecture is to align three components to hardware vsync timers: + +1. Compositor +2. RefreshDriver / Painting +3. Input Events + +The flow of our rendering engine is as follows: + +1. Hardware Vsync event occurs on an OS specific *Hardware Vsync Thread* on a per monitor basis. +2. The *Hardware Vsync Thread* attached to the monitor notifies the **CompositorVsyncDispatchers** and **RefreshTimerVsyncDispatcher**. +3. For every Firefox window on the specific monitor, notify a **CompositorVsyncDispatcher**. The **CompositorVsyncDispatcher** is specific to one window. +4. The **CompositorVsyncDispatcher** notifies the **Compositor** that a vsync has occured. +5. The **RefreshTimerVsyncDispatcher** notifies the Chrome **RefreshTimer** that a vsync has occured. +6. The **RefreshTimerVsyncDispatcher** sends IPC messages to all content processes to tick their respective active **RefreshTimer**. +7. The **Compositor** dispatches input events on the *Compositor Thread*, then composites. Input events are only dispatched on the *Compositor Thread* on b2g. +8. The **RefreshDriver** paints on the *Main Thread*. + +The implementation is broken into the following sections and will reference this figure. Note that **Objects** are bold fonts while *Threads* are italicized. + +<img src="architecture.png" width="900px" height="630px" /> + +#Hardware Vsync +Hardware vsync events from (1), occur on a specific **Display** Object. +The **Display** object is responsible for enabling / disabling vsync on a per connected display basis. +For example, if two monitors are connected, two **Display** objects will be created, each listening to vsync events for their respective displays. +We require one **Display** object per monitor as each monitor may have different vsync rates. +As a fallback solution, we have one global **Display** object that can synchronize across all connected displays. +The global **Display** is useful if a window is positioned halfway between the two monitors. +Each platform will have to implement a specific **Display** object to hook and listen to vsync events. +As of this writing, both Firefox OS and OS X create their own hardware specific *Hardware Vsync Thread* that executes after a vsync has occured. +OS X creates one *Hardware Vsync Thread* per **CVDisplayLinkRef**. +We do not currently support multiple displays, so we use one global **CVDisplayLinkRef** that works across all active displays. +On Windows, we have to create a new platform *thread* that waits for DwmFlush(), which works across all active displays. +Once the thread wakes up from DwmFlush(), the actual vsync timestamp is retrieved from DwmGetCompositionTimingInfo(), which is the timestamp that is actually passed into the compositor and refresh driver. + +When a vsync occurs on a **Display**, the *Hardware Vsync Thread* callback fetches all **CompositorVsyncDispatchers** associated with the **Display**. +Each **CompositorVsyncDispatcher** is notified that a vsync has occured with the vsync's timestamp. +It is the responsibility of the **CompositorVsyncDispatcher** to notify the **Compositor** that is awaiting vsync notifications. +The **Display** will then notify the associated **RefreshTimerVsyncDispatcher**, which should notify all active **RefreshDrivers** to tick. + +All **Display** objects are encapsulated in a **VsyncSource** object. +The **VsyncSource** object lives in **gfxPlatform** and is instantiated only on the parent process when **gfxPlatform** is created. +The **VsyncSource** is destroyed when **gfxPlatform** is destroyed. +There is only one **VsyncSource** object throughout the entire lifetime of Firefox. +Each platform is expected to implement their own **VsyncSource** to manage vsync events. +On Firefox OS, this is through the **HwcComposer2D**. +On OS X, this is through **CVDisplayLinkRef**. +On Windows, it should be through **DwmGetCompositionTimingInfo**. + +#Compositor +When the **CompositorVsyncDispatcher** is notified of the vsync event, the **CompositorVsyncObserver** associated with the **CompositorVsyncDispatcher** begins execution. +Since the **CompositorVsyncDispatcher** executes on the *Hardware Vsync Thread* and the **Compositor** composites on the *CompositorThread*, the **CompositorVsyncObserver** posts a task to the *CompositorThread*. +The **CompositorParent** then composites. +The model where the **CompositorVsyncDispatcher** notifies components on the *Hardware Vsync Thread*, and the component schedules the task on the appropriate thread is used everywhere. + +The **CompositorVsyncObserver** listens to vsync events as needed and stops listening to vsync when composites are no longer scheduled or required. +Every **CompositorParent** is associated and tied to one **CompositorVsyncObserver**, which is associated with the **CompositorVsyncDispatcher**. +Each **CompositorParent** is associated with one widget and is created when a new platform window or **nsBaseWidget** is created. +The **CompositorParent**, **CompositorVsyncDispatcher**, **CompositorVsyncObserver**, and **nsBaseWidget** all have the same lifetimes, which are created and destroyed together. + +###CompositorVsyncDispatcher +The **CompositorVsyncDispatcher** executes on the *Hardware Vsync Thread*. +It contains references to the **nsBaseWidget** it is associated with and has a lifetime equal to the **nsBaseWidget**. +The **CompositorVsyncDispatcher** is responsible for notifying the **CompositorParent** that a vsync event has occured. +There can be multiple **CompositorVsyncDispatchers** per **Display**, one **CompositorVsyncDispatcher** per window. +The only responsibility of the **CompositorVsyncDispatcher** is to notify components when a vsync event has occured, and to stop listening to vsync when no components require vsync events. +We require one **CompositorVsyncDispatcher** per window so that we can handle multiple **Displays**. + +###Multiple Displays +The **VsyncSource** has an API to switch a **CompositorVsyncDispatcher** from one **Display** to another **Display**. +For example, when one window either goes into full screen mode or moves from one connected monitor to another. +When one window moves to another monitor, we expect a platform specific notification to occur. +The detection of when a window enters full screen mode or moves is not covered by Silk itself, but the framework is built to support this use case. +The expected flow is that the OS notification occurs on **nsIWidget**, which retrieves the associated **CompositorVsyncDispatcher**. +The **CompositorVsyncDispatcher** then notifies the **VsyncSource** to switch to the correct **Display** the **CompositorVsyncDispatcher** is connected to. +Because the notification works through the **nsIWidget**, the actual switching of the **CompositorVsyncDispatcher** to the correct **Display** should occur on the *Main Thread*. +The current implementation of Silk does not handle this case and needs to be built out. + +###CompositorVsyncObserver +The **CompositorVsyncObserver** handles the vsync notifications and interactions with the **CompositorVsyncDispatcher**. +When the **Compositor** requires a scheduled composite, it notifies the **CompositorVsyncObserver** that it needs to listen to vsync. +The **CompositorVsyncObserver** then observes / unobserves vsync as needed from the **CompositorVsyncDispatcher** to enable composites. + +###GeckoTouchDispatcher +The **GeckoTouchDispatcher** is a singleton that resamples touch events to smooth out jank while tracking a user's finger. +Because input and composite are linked together, the **CompositorVsyncObserver** has a reference to the **GeckoTouchDispatcher** and vice versa. + +###Input Events +One large goal of Silk is to align touch events with vsync events. +On Firefox OS, touchscreens often have different touch scan rates than the display refreshes. +A Flame device has a touch refresh rate of 75 HZ, while a Nexus 4 has a touch refresh rate of 100 HZ, while the device's display refresh rate is 60HZ. +When a vsync event occurs, we resample touch events, and then dispatch the resampled touch event to APZ. +Touch events on Firefox OS occur on a *Touch Input Thread* whereas they are processed by APZ on the *APZ Controller Thread*. +We use [Google Android's touch resampling](http://www.masonchang.com/blog/2014/8/25/androids-touch-resampling-algorithm) algorithm to resample touch events. + +Currently, we have a strict ordering between Composites and touch events. +When a touch event occurs on the *Touch Input Thread*, we store the touch event in a queue. +When a vsync event occurs, the **CompositorVsyncDispatcher** notifies the **Compositor** of a vsync event, which notifies the **GeckoTouchDispatcher**. +The **GeckoTouchDispatcher** processes the touch event first on the *APZ Controller Thread*, which is the same as the *Compositor Thread* on b2g, then the **Compositor** finishes compositing. +We require this strict ordering because if a vsync notification is dispatched to both the **Compositor** and **GeckoTouchDispatcher** at the same time, a race condition occurs between processing the touch event and therefore position versus compositing. +In practice, this creates very janky scrolling. +As of this writing, we have not analyzed input events on desktop platforms. + +One slight quirk is that input events can start a composite, for example during a scroll and after the **Compositor** is no longer listening to vsync events. +In these cases, we notify the **Compositor** to observe vsync so that it dispatches touch events. +If touch events were not dispatched, and since the **Compositor** is not listening to vsync events, the touch events would never be dispatched. +The **GeckoTouchDispatcher** handles this case by always forcing the **Compositor** to listen to vsync events while touch events are occurring. + +###Widget, Compositor, CompositorVsyncDispatcher, GeckoTouchDispatcher Shutdown Procedure +When the [nsBaseWidget shuts down](http://hg.mozilla.org/mozilla-central/file/0df249a0e4d3/widget/nsBaseWidget.cpp#l182) - It calls nsBaseWidget::DestroyCompositor on the *Gecko Main Thread*. +During nsBaseWidget::DestroyCompositor, it first destroys the CompositorChild. +CompositorChild sends a sync IPC call to CompositorParent::RecvStop, which calls [CompositorParent::Destroy](http://hg.mozilla.org/mozilla-central/file/ab0490972e1e/gfx/layers/ipc/CompositorParent.cpp#l509). +During this time, the *main thread* is blocked on the parent process. +CompositorParent::RecvStop runs on the *Compositor thread* and cleans up some resources, including setting the **CompositorVsyncObserver** to nullptr. +CompositorParent::RecvStop also explicitly keeps the CompositorParent alive and posts another task to run CompositorParent::DeferredDestroy on the Compositor loop so that all ipdl code can finish executing. +The **CompositorVsyncObserver** also unobserves from vsync and cancels any pending composite tasks. +Once CompositorParent::RecvStop finishes, the *main thread* in the parent process continues shutting down the nsBaseWidget. + +At the same time, the *Compositor thread* is executing tasks until CompositorParent::DeferredDestroy runs, which flushes the compositor message loop. +Now we have two tasks as both the nsBaseWidget releases a reference to the Compositor on the *main thread* during destruction and the CompositorParent::DeferredDestroy releases a reference to the CompositorParent on the *Compositor Thread*. +Finally, the CompositorParent itself is destroyed on the *main thread* once both references are gone due to explicit [main thread destruction](http://hg.mozilla.org/mozilla-central/file/50b95032152c/gfx/layers/ipc/CompositorParent.h#l148). + +With the **CompositorVsyncObserver**, any accesses to the widget after nsBaseWidget::DestroyCompositor executes are invalid. +Any accesses to the compositor between the time the nsBaseWidget::DestroyCompositor runs and the CompositorVsyncObserver's destructor runs aren't safe yet a hardware vsync event could occur between these times. +Since any tasks posted on the Compositor loop after CompositorParent::DeferredDestroy is posted are invalid, we make sure that no vsync tasks can be posted once CompositorParent::RecvStop executes and DeferredDestroy is posted on the Compositor thread. +When the sync call to CompositorParent::RecvStop executes, we explicitly set the CompositorVsyncObserver to null to prevent vsync notifications from occurring. +If vsync notifications were allowed to occur, since the **CompositorVsyncObserver**'s vsync notification executes on the *hardware vsync thread*, it would post a task to the Compositor loop and may execute after CompositorParent::DeferredDestroy. +Thus, we explicitly shut down vsync events in the **CompositorVsyncDispatcher** and **CompositorVsyncObserver** during nsBaseWidget::Shutdown to prevent any vsync tasks from executing after CompositorParent::DeferredDestroy. + +The **CompositorVsyncDispatcher** may be destroyed on either the *main thread* or *Compositor Thread*, since both the nsBaseWidget and **CompositorVsyncObserver** race to destroy on different threads. +nsBaseWidget is destroyed on the *main thread* and releases a reference to the **CompositorVsyncDispatcher** during destruction. +The **CompositorVsyncObserver** has a race to be destroyed either during CompositorParent shutdown or from the **GeckoTouchDispatcher** which is destroyed on the main thread with [ClearOnShutdown](http://hg.mozilla.org/mozilla-central/file/21567e9a6e40/xpcom/base/ClearOnShutdown.h#l15). +Whichever object, the CompositorParent or the **GeckoTouchDispatcher** is destroyed last will hold the last reference to the **CompositorVsyncDispatcher**, which destroys the object. + +#Refresh Driver +The Refresh Driver is ticked from a [single active timer](http://hg.mozilla.org/mozilla-central/file/ab0490972e1e/layout/base/nsRefreshDriver.cpp#l11). +The assumption is that there are multiple **RefreshDrivers** connected to a single **RefreshTimer**. +There are two **RefreshTimers**: an active and an inactive **RefreshTimer**. +Each Tab has its own **RefreshDriver**, which connects to one of the global **RefreshTimers**. +The **RefreshTimers** execute on the *Main Thread* and tick their connected **RefreshDrivers**. +We do not want to break this model of multiple **RefreshDrivers** per a set of two global **RefreshTimers**. +Each **RefreshDriver** switches between the active and inactive **RefreshTimer**. + +Instead, we create a new **RefreshTimer**, the **VsyncRefreshTimer** which ticks based on vsync messages. +We replace the current active timer with a **VsyncRefreshTimer**. +All tabs will then tick based on this new active timer. +Since the **RefreshTimer** has a lifetime of the process, we only need to create a single **RefreshTimerVsyncDispatcher** per **Display** when Firefox starts. +Even if we do not have any content processes, the Chrome process will still need a **VsyncRefreshTimer**, thus we can associate the **RefreshTimerVsyncDispatcher** with each **Display**. + +When Firefox starts, we initially create a new **VsyncRefreshTimer** in the Chrome process. +The **VsyncRefreshTimer** will listen to vsync notifications from **RefreshTimerVsyncDispatcher** on the global **Display**. +When nsRefreshDriver::Shutdown executes, it will delete the **VsyncRefreshTimer**. +This creates a problem as all the **RefreshTimers** are currently manually memory managed whereas **VsyncObservers** are ref counted. +To work around this problem, we create a new **RefreshDriverVsyncObserver** as an inner class to **VsyncRefreshTimer**, which actually receives vsync notifications. It then ticks the **RefreshDrivers** inside **VsyncRefreshTimer**. + +With Content processes, the start up process is more complicated. +We send vsync IPC messages via the use of the PBackground thread on the parent process, which allows us to send messages from the Parent process' without waiting on the *main thread*. +This sends messages from the Parent::*PBackground Thread* to the Child::*Main Thread*. +The *main thread* receiving IPC messages on the content process is acceptable because **RefreshDrivers** must execute on the *main thread*. +However, there is some amount of time required to setup the IPC connection upon process creation and during this time, the **RefreshDrivers** must tick to set up the process. +To get around this, we initially use software **RefreshTimers** that already exist during content process startup and swap in the **VsyncRefreshTimer** once the IPC connection is created. + +During nsRefreshDriver::ChooseTimer, we create an async PBackground IPC open request to create a **VsyncParent** and **VsyncChild**. +At the same time, we create a software **RefreshTimer** and tick the **RefreshDrivers** as normal. +Once the PBackground callback is executed and an IPC connection exists, we swap all **RefreshDrivers** currently associated with the active **RefreshTimer** and swap the **RefreshDrivers** to use the **VsyncRefreshTimer**. +Since all interactions on the content process occur on the main thread, there are no need for locks. +The **VsyncParent** listens to vsync events through the **VsyncRefreshTimerDispatcher** on the parent side and sends vsync IPC messages to the **VsyncChild**. +The **VsyncChild** notifies the **VsyncRefreshTimer** on the content process. + +During the shutdown process of the content process, ActorDestroy is called on the **VsyncChild** and **VsyncParent** due to the normal PBackground shutdown process. +Once ActorDestroy is called, no IPC messages should be sent across the channel. +After ActorDestroy is called, the IPDL machinery will delete the **VsyncParent/Child** pair. +The **VsyncParent**, due to being a **VsyncObserver**, is ref counted. +After **VsyncParent::ActorDestroy** is called, it unregisters itself from the **RefreshTimerVsyncDispatcher**, which holds the last reference to the **VsyncParent**, and the object will be deleted. + +Thus the overall flow during normal execution is: + +1. VsyncSource::Display::RefreshTimerVsyncDispatcher receives a Vsync notification from the OS in the parent process. +2. RefreshTimerVsyncDispatcher notifies VsyncRefreshTimer::RefreshDriverVsyncObserver that a vsync occured on the parent process on the hardware vsync thread. +3. RefreshTimerVsyncDispatcher notifies the VsyncParent on the hardware vsync thread that a vsync occured. +4. The VsyncRefreshTimer::RefreshDriverVsyncObserver in the parent process posts a task to the main thread that ticks the refresh drivers. +5. VsyncParent posts a task to the PBackground thread to send a vsync IPC message to VsyncChild. +6. VsyncChild receive a vsync notification on the content process on the main thread and ticks their respective RefreshDrivers. + +###Compressing Vsync Messages +Vsync messages occur quite often and the *main thread* can be busy for long periods of time due to JavaScript. +Consistently sending vsync messages to the refresh driver timer can flood the *main thread* with refresh driver ticks, causing even more delays. +To avoid this problem, we compress vsync messages on both the parent and child processes. + +On the parent process, newer vsync messages update a vsync timestamp but do not actually queue any tasks on the *main thread*. +Once the parent process' *main thread* executes the refresh driver tick, it uses the most updated vsync timestamp to tick the refresh driver. +After the refresh driver has ticked, one single vsync message is queued for another refresh driver tick task. +On the content process, the IPDL **compress** keyword automatically compresses IPC messages. + +### Multiple Monitors +In order to have multiple monitor support for the **RefreshDrivers**, we have multiple active **RefreshTimers**. +Each **RefreshTimer** is associated with a specific **Display** via an id and tick when it's respective **Display** vsync occurs. +We have **N RefreshTimers**, where N is the number of connected displays. +Each **RefreshTimer** still has multiple **RefreshDrivers**. + +When a tab or window changes monitors, the **nsIWidget** receives a display changed notification. +Based on which display the window is on, the window switches to the correct **RefreshTimerVsyncDispatcher** and **CompositorVsyncDispatcher** on the parent process based on the display id. +Each **TabParent** should also send a notification to their child. +Each **TabChild**, given the display ID, switches to the correct **RefreshTimer** associated with the display ID. +When each display vsync occurs, it sends one IPC message to notify vsync. +The vsync message contains a display ID, to tick the appropriate **RefreshTimer** on the content process. +There is still only one **VsyncParent/VsyncChild** pair, just each vsync notification will include a display ID, which maps to the correct **RefreshTimer**. + +#Object Lifetime +1. CompositorVsyncDispatcher - Lives as long as the nsBaseWidget associated with the VsyncDispatcher +2. CompositorVsyncObserver - Lives and dies the same time as the CompositorParent. +3. RefreshTimerVsyncDispatcher - As long as the associated display object, which is the lifetime of Firefox. +4. VsyncSource - Lives as long as the gfxPlatform on the chrome process, which is the lifetime of Firefox. +5. VsyncParent/VsyncChild - Lives as long as the content process +6. RefreshTimer - Lives as long as the process + +#Threads +All **VsyncObservers** are notified on the *Hardware Vsync Thread*. It is the responsibility of the **VsyncObservers** to post tasks to their respective correct thread. For example, the **CompositorVsyncObserver** will be notified on the *Hardware Vsync Thread*, and post a task to the *Compositor Thread* to do the actual composition. + +1. Compositor Thread - Nothing changes +2. Main Thread - PVsyncChild receives IPC messages on the main thread. We also enable/disable vsync on the main thread. +3. PBackground Thread - Creates a connection from the PBackground thread on the parent process to the main thread in the content process. +4. Hardware Vsync Thread - Every platform is different, but we always have the concept of a hardware vsync thread. Sometimes this is actually created by the host OS. On Windows, we have to create a separate platform thread that blocks on DwmFlush().
new file mode 100644 index 0000000000000000000000000000000000000000..938c585e403523ba840091173608b6b35a8dbe5c GIT binary patch literal 221047 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
--- a/gfx/gl/GLBlitHelper.cpp +++ b/gfx/gl/GLBlitHelper.cpp @@ -685,17 +685,17 @@ GLBlitHelper::BindAndUploadEGLImage(EGLI mGL->fBindTexture(target, mSrcTexEGL); } mGL->fEGLImageTargetTexture2D(target, image); } #ifdef MOZ_WIDGET_GONK bool -GLBlitHelper::BlitGrallocImage(layers::GrallocImage* grallocImage, bool yflip) +GLBlitHelper::BlitGrallocImage(layers::GrallocImage* grallocImage) { ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0); mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT); EGLint attrs[] = { LOCAL_EGL_IMAGE_PRESERVED, LOCAL_EGL_TRUE, LOCAL_EGL_NONE, LOCAL_EGL_NONE }; @@ -706,32 +706,30 @@ GLBlitHelper::BlitGrallocImage(layers::G if (image == EGL_NO_IMAGE) return false; int oldBinding = 0; mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL_OES, &oldBinding); BindAndUploadEGLImage(image, LOCAL_GL_TEXTURE_EXTERNAL_OES); - mGL->fUniform1f(mYFlipLoc, yflip ? (float)1.0f : (float)0.0f); - mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); sEGLLibrary.fDestroyImage(sEGLLibrary.Display(), image); mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES, oldBinding); return true; } #endif #ifdef MOZ_WIDGET_ANDROID #define ATTACH_WAIT_MS 50 bool -GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage, bool yflip) +GLBlitHelper::BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage) { AndroidSurfaceTexture* surfaceTexture = stImage->GetData()->mSurfTex; ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0); if (NS_FAILED(surfaceTexture->Attach(mGL, PR_MillisecondsToInterval(ATTACH_WAIT_MS)))) return false; @@ -741,27 +739,26 @@ GLBlitHelper::BlitSurfaceTextureImage(la mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_EXTERNAL, &oldBinding); surfaceTexture->UpdateTexImage(); gfx::Matrix4x4 transform; surfaceTexture->GetTransformMatrix(transform); mGL->fUniformMatrix4fv(mTextureTransformLoc, 1, false, &transform._11); - mGL->fUniform1f(mYFlipLoc, yflip ? 1.0f : 0.0f); mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); surfaceTexture->Detach(); mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL, oldBinding); return true; } bool -GLBlitHelper::BlitEGLImageImage(layers::EGLImageImage* image, bool yflip) +GLBlitHelper::BlitEGLImageImage(layers::EGLImageImage* image) { EGLImage eglImage = image->GetData()->mImage; EGLSync eglSync = image->GetData()->mSync; if (eglSync) { EGLint status = sEGLLibrary.fClientWaitSync(EGL_DISPLAY(), eglSync, 0, LOCAL_EGL_FOREVER); if (status != LOCAL_EGL_CONDITION_SATISFIED) { return false; @@ -770,28 +767,26 @@ GLBlitHelper::BlitEGLImageImage(layers:: ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0); int oldBinding = 0; mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldBinding); BindAndUploadEGLImage(eglImage, LOCAL_GL_TEXTURE_2D); - mGL->fUniform1f(mYFlipLoc, yflip ? 1.0f : 0.0f); - mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); mGL->fBindTexture(LOCAL_GL_TEXTURE_EXTERNAL_OES, oldBinding); return true; } #endif bool -GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage, bool yflip) +GLBlitHelper::BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage) { ScopedBindTextureUnit boundTU(mGL, LOCAL_GL_TEXTURE0); const PlanarYCbCrData* yuvData = yuvImage->GetData(); bool needsAllocation = false; if (mTexWidth != yuvData->mYStride || mTexHeight != yuvData->mYSize.height) { mTexWidth = yuvData->mYStride; mTexHeight = yuvData->mYSize.height; @@ -802,18 +797,16 @@ GLBlitHelper::BlitPlanarYCbCrImage(layer for (int i = 0; i < 3; i++) { mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i); mGL->fGetIntegerv(LOCAL_GL_TEXTURE_BINDING_2D, &oldTex[i]); } BindAndUploadYUVTexture(Channel_Y, yuvData->mYStride, yuvData->mYSize.height, yuvData->mYChannel, needsAllocation); BindAndUploadYUVTexture(Channel_Cb, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCbChannel, needsAllocation); BindAndUploadYUVTexture(Channel_Cr, yuvData->mCbCrStride, yuvData->mCbCrSize.height, yuvData->mCrChannel, needsAllocation); - mGL->fUniform1f(mYFlipLoc, yflip ? (float)1.0 : (float)0.0); - if (needsAllocation) { mGL->fUniform2f(mYTexScaleLoc, (float)yuvData->mYSize.width/yuvData->mYStride, 1.0f); mGL->fUniform2f(mCbCrTexScaleLoc, (float)yuvData->mCbCrSize.width/yuvData->mCbCrStride, 1.0f); } mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); for (int i = 0; i < 3; i++) { mGL->fActiveTexture(LOCAL_GL_TEXTURE0 + i); @@ -821,157 +814,156 @@ GLBlitHelper::BlitPlanarYCbCrImage(layer } return true; } bool GLBlitHelper::BlitImageToFramebuffer(layers::Image* srcImage, const gfx::IntSize& destSize, GLuint destFB, - bool yflip, - GLuint xoffset, - GLuint yoffset, - GLuint cropWidth, - GLuint cropHeight) + OriginPos destOrigin) { ScopedGLDrawState autoStates(mGL); BlitType type; + OriginPos srcOrigin; + switch (srcImage->GetFormat()) { case ImageFormat::PLANAR_YCBCR: type = ConvertPlanarYCbCr; + srcOrigin = OriginPos::TopLeft; break; + +#ifdef MOZ_WIDGET_GONK case ImageFormat::GRALLOC_PLANAR_YCBCR: -#ifdef MOZ_WIDGET_GONK type = ConvertGralloc; + srcOrigin = OriginPos::TopLeft; break; #endif + #ifdef MOZ_WIDGET_ANDROID case ImageFormat::SURFACE_TEXTURE: type = ConvertSurfaceTexture; + srcOrigin = static_cast<layers::SurfaceTextureImage*>(srcImage)->GetData() + ->mOriginPos; break; + case ImageFormat::EGLIMAGE: type = ConvertEGLImage; + srcOrigin = static_cast<layers::EGLImageImage*>(srcImage)->GetData()->mOriginPos; break; #endif + default: return false; } bool init = InitTexQuadProgram(type); if (!init) { return false; } + const bool needsYFlip = (srcOrigin != destOrigin); + mGL->fUniform1f(mYFlipLoc, needsYFlip ? (float)1.0 : (float)0.0); + ScopedBindFramebuffer boundFB(mGL, destFB); mGL->fColorMask(LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE, LOCAL_GL_TRUE); mGL->fViewport(0, 0, destSize.width, destSize.height); - if (xoffset != 0 && yoffset != 0 && cropWidth != 0 && cropHeight != 0) { - mGL->fEnable(LOCAL_GL_SCISSOR_TEST); - mGL->fScissor(xoffset, yoffset, (GLsizei)cropWidth, (GLsizei)cropHeight); - } + switch (type) { #ifdef MOZ_WIDGET_GONK - if (type == ConvertGralloc) { - layers::GrallocImage* grallocImage = static_cast<layers::GrallocImage*>(srcImage); - return BlitGrallocImage(grallocImage, yflip); - } -#endif - if (type == ConvertPlanarYCbCr) { - mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); - PlanarYCbCrImage* yuvImage = static_cast<PlanarYCbCrImage*>(srcImage); - return BlitPlanarYCbCrImage(yuvImage, yflip); - } -#ifdef MOZ_WIDGET_ANDROID - if (type == ConvertSurfaceTexture) { - layers::SurfaceTextureImage* stImage = static_cast<layers::SurfaceTextureImage*>(srcImage); - return BlitSurfaceTextureImage(stImage, yflip); - } - if (type == ConvertEGLImage) { - layers::EGLImageImage* eglImage = static_cast<layers::EGLImageImage*>(srcImage); - return BlitEGLImageImage(eglImage, yflip); - } + case ConvertGralloc: + return BlitGrallocImage(static_cast<layers::GrallocImage*>(srcImage)); #endif - return false; + case ConvertPlanarYCbCr: + mGL->fPixelStorei(LOCAL_GL_UNPACK_ALIGNMENT, 1); + return BlitPlanarYCbCrImage(static_cast<PlanarYCbCrImage*>(srcImage)); + +#ifdef MOZ_WIDGET_ANDROID + case ConvertSurfaceTexture: + return BlitSurfaceTextureImage(static_cast<layers::SurfaceTextureImage*>(srcImage)); + + case ConvertEGLImage: + return BlitEGLImageImage(static_cast<layers::EGLImageImage*>(srcImage)); +#endif + + default: + return false; + } } bool GLBlitHelper::BlitImageToTexture(layers::Image* srcImage, const gfx::IntSize& destSize, GLuint destTex, GLenum destTarget, - bool yflip, - GLuint xoffset, - GLuint yoffset, - GLuint cropWidth, - GLuint cropHeight) + OriginPos destOrigin) { - ScopedGLDrawState autoStates(mGL); + ScopedFramebufferForTexture autoFBForTex(mGL, destTex, destTarget); - if (!mFBO) - mGL->fGenFramebuffers(1, &mFBO); + if (!autoFBForTex.IsComplete()) { + MOZ_CRASH("ScopedFramebufferForTexture failed."); + } - ScopedBindFramebuffer boundFB(mGL, mFBO); - mGL->fFramebufferTexture2D(LOCAL_GL_FRAMEBUFFER, LOCAL_GL_COLOR_ATTACHMENT0, - destTarget, destTex, 0); - return BlitImageToFramebuffer(srcImage, destSize, mFBO, yflip, xoffset, yoffset, - cropWidth, cropHeight); + return BlitImageToFramebuffer(srcImage, destSize, autoFBForTex.FB(), destOrigin); } void GLBlitHelper::BlitTextureToFramebuffer(GLuint srcTex, GLuint destFB, const gfx::IntSize& srcSize, const gfx::IntSize& destSize, GLenum srcTarget, bool internalFBs) { MOZ_ASSERT(mGL->fIsTexture(srcTex)); MOZ_ASSERT(!destFB || mGL->fIsFramebuffer(destFB)); if (mGL->IsSupported(GLFeature::framebuffer_blit)) { ScopedFramebufferForTexture srcWrapper(mGL, srcTex, srcTarget); - MOZ_ASSERT(srcWrapper.IsComplete()); + MOZ_DIAGNOSTIC_ASSERT(srcWrapper.IsComplete()); BlitFramebufferToFramebuffer(srcWrapper.FB(), destFB, srcSize, destSize, internalFBs); return; } BlitType type; - switch (srcTarget) - { + switch (srcTarget) { case LOCAL_GL_TEXTURE_2D: type = BlitTex2D; break; case LOCAL_GL_TEXTURE_RECTANGLE_ARB: type = BlitTexRect; break; default: - printf_stderr("Fatal Error: Failed to prepare to blit texture->framebuffer.\n"); - MOZ_CRASH(); + MOZ_CRASH("Fatal Error: Bad `srcTarget`."); break; } ScopedGLDrawState autoStates(mGL); if (internalFBs) { mGL->Screen()->BindFB_Internal(destFB); } else { mGL->BindFB(destFB); } // Does destructive things to (only!) what we just saved above. bool good = UseTexQuadProgram(type, srcSize); if (!good) { // We're up against the wall, so bail. - // This should really be MOZ_CRASH(why) or MOZ_RUNTIME_ASSERT(good). - printf_stderr("Fatal Error: Failed to prepare to blit texture->framebuffer.\n"); - MOZ_CRASH(); + MOZ_DIAGNOSTIC_ASSERT(false, + "Error: Failed to prepare to blit texture->framebuffer.\n"); + mGL->fScissor(0, 0, destSize.width, destSize.height); + mGL->fColorMask(1, 1, 1, 1); + mGL->fClear(LOCAL_GL_COLOR_BUFFER_BIT); + return; } + mGL->fDrawArrays(LOCAL_GL_TRIANGLE_STRIP, 0, 4); } void GLBlitHelper::BlitFramebufferToTexture(GLuint srcFB, GLuint destTex, const gfx::IntSize& srcSize, const gfx::IntSize& destSize, GLenum destTarget,
--- a/gfx/gl/GLBlitHelper.h +++ b/gfx/gl/GLBlitHelper.h @@ -140,28 +140,30 @@ class GLBlitHelper final bool UseTexQuadProgram(BlitType target, const gfx::IntSize& srcSize); bool InitTexQuadProgram(BlitType target = BlitTex2D); void DeleteTexBlitProgram(); void BindAndUploadYUVTexture(Channel which, uint32_t width, uint32_t height, void* data, bool allocation); void BindAndUploadEGLImage(EGLImage image, GLuint target); #ifdef MOZ_WIDGET_GONK - bool BlitGrallocImage(layers::GrallocImage* grallocImage, bool yflip); + bool BlitGrallocImage(layers::GrallocImage* grallocImage); #endif - bool BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage, bool yflip); + bool BlitPlanarYCbCrImage(layers::PlanarYCbCrImage* yuvImage); #ifdef MOZ_WIDGET_ANDROID // Blit onto the current FB. - bool BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage, bool yflip); - bool BlitEGLImageImage(layers::EGLImageImage* eglImage, bool yflip); + bool BlitSurfaceTextureImage(layers::SurfaceTextureImage* stImage); + bool BlitEGLImageImage(layers::EGLImageImage* eglImage); #endif -public: + explicit GLBlitHelper(GLContext* gl); - explicit GLBlitHelper(GLContext* gl); + friend class GLContext; + +public: ~GLBlitHelper(); // If you don't have |srcFormats| for the 2nd definition, // then you'll need the framebuffer_blit extensions to use // the first BlitFramebufferToFramebuffer. void BlitFramebufferToFramebuffer(GLuint srcFB, GLuint destFB, const gfx::IntSize& srcSize, const gfx::IntSize& destSize, @@ -182,20 +184,17 @@ public: GLenum destTarget = LOCAL_GL_TEXTURE_2D, bool internalFBs = false); void BlitTextureToTexture(GLuint srcTex, GLuint destTex, const gfx::IntSize& srcSize, const gfx::IntSize& destSize, GLenum srcTarget = LOCAL_GL_TEXTURE_2D, GLenum destTarget = LOCAL_GL_TEXTURE_2D); bool BlitImageToFramebuffer(layers::Image* srcImage, const gfx::IntSize& destSize, - GLuint destFB, bool yflip = false, GLuint xoffset = 0, - GLuint yoffset = 0, GLuint width = 0, GLuint height = 0); + GLuint destFB, OriginPos destOrigin); bool BlitImageToTexture(layers::Image* srcImage, const gfx::IntSize& destSize, - GLuint destTex, GLenum destTarget, bool yflip = false, - GLuint xoffset = 0, GLuint yoffset = 0, GLuint width = 0, - GLuint height = 0); + GLuint destTex, GLenum destTarget, OriginPos destOrigin); }; } // namespace gl } // namespace mozilla #endif // GLBLITHELPER_H_
--- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -975,31 +975,33 @@ GLContext::InitWithPrefix(const char *pr // superset of EXT_transform_feedback/NV_transform_feedback // and adds glPauseTransformFeedback & // glResumeTransformFeedback, which are required for WebGL2. if (IsSupported(GLFeature::transform_feedback2)) { SymLoadStruct coreSymbols[] = { { (PRFuncPtr*) &mSymbols.fBindBufferBase, { "BindBufferBase", nullptr } }, { (PRFuncPtr*) &mSymbols.fBindBufferRange, { "BindBufferRange", nullptr } }, { (PRFuncPtr*) &mSymbols.fGenTransformFeedbacks, { "GenTransformFeedbacks", nullptr } }, + { (PRFuncPtr*) &mSymbols.fBindTransformFeedback, { "BindTransformFeedback", nullptr } }, { (PRFuncPtr*) &mSymbols.fDeleteTransformFeedbacks, { "DeleteTransformFeedbacks", nullptr } }, { (PRFuncPtr*) &mSymbols.fIsTransformFeedback, { "IsTransformFeedback", nullptr } }, { (PRFuncPtr*) &mSymbols.fBeginTransformFeedback, { "BeginTransformFeedback", nullptr } }, { (PRFuncPtr*) &mSymbols.fEndTransformFeedback, { "EndTransformFeedback", nullptr } }, { (PRFuncPtr*) &mSymbols.fTransformFeedbackVaryings, { "TransformFeedbackVaryings", nullptr } }, { (PRFuncPtr*) &mSymbols.fGetTransformFeedbackVarying, { "GetTransformFeedbackVarying", nullptr } }, { (PRFuncPtr*) &mSymbols.fPauseTransformFeedback, { "PauseTransformFeedback", nullptr } }, { (PRFuncPtr*) &mSymbols.fResumeTransformFeedback, { "ResumeTransformFeedback", nullptr } }, END_SYMBOLS }; SymLoadStruct extSymbols[] = { { (PRFuncPtr*) &mSymbols.fBindBufferBase, { "BindBufferBaseEXT", "BindBufferBaseNV", nullptr } }, { (PRFuncPtr*) &mSymbols.fBindBufferRange, { "BindBufferRangeEXT", "BindBufferRangeNV", nullptr } }, { (PRFuncPtr*) &mSymbols.fGenTransformFeedbacks, { "GenTransformFeedbacksNV", nullptr } }, + { (PRFuncPtr*) &mSymbols.fBindTransformFeedback, { "BindTransformFeedbackNV", nullptr } }, { (PRFuncPtr*) &mSymbols.fDeleteTransformFeedbacks, { "DeleteTransformFeedbacksNV", nullptr } }, { (PRFuncPtr*) &mSymbols.fIsTransformFeedback, { "IsTransformFeedbackNV", nullptr } }, { (PRFuncPtr*) &mSymbols.fBeginTransformFeedback, { "BeginTransformFeedbackEXT", "BeginTransformFeedbackNV", nullptr } }, { (PRFuncPtr*) &mSymbols.fEndTransformFeedback, { "EndTransformFeedbackEXT", "EndTransformFeedbackNV", nullptr } }, { (PRFuncPtr*) &mSymbols.fTransformFeedbackVaryings, { "TransformFeedbackVaryingsEXT", "TransformFeedbackVaryingsNV", nullptr } }, { (PRFuncPtr*) &mSymbols.fGetTransformFeedbackVarying, { "GetTransformFeedbackVaryingEXT", "GetTransformFeedbackVaryingNV", nullptr } }, { (PRFuncPtr*) &mSymbols.fPauseTransformFeedback, { "PauseTransformFeedbackNV", nullptr } }, { (PRFuncPtr*) &mSymbols.fResumeTransformFeedback, { "ResumeTransformFeedbackNV", nullptr } }, @@ -2396,17 +2398,17 @@ GLContext::IsOwningThreadCurrent() { return PlatformThread::CurrentId() == mOwningThreadId; } GLBlitHelper* GLContext::BlitHelper() { if (!mBlitHelper) { - mBlitHelper = MakeUnique<GLBlitHelper>(this); + mBlitHelper.reset(new GLBlitHelper(this)); } return mBlitHelper.get(); } GLReadTexImageHelper* GLContext::ReadTexImageHelper() {
--- a/gfx/layers/GLImages.cpp +++ b/gfx/layers/GLImages.cpp @@ -52,29 +52,35 @@ GLImage::GetAsSourceSurface() gfx::IntSize size = GetSize(); sSnapshotContext->fTexImage2D(LOCAL_GL_TEXTURE_2D, 0, LOCAL_GL_RGBA, size.width, size.height, 0, LOCAL_GL_RGBA, LOCAL_GL_UNSIGNED_BYTE, nullptr); - ScopedFramebufferForTexture fb(sSnapshotContext, scopedTex.Texture()); + ScopedFramebufferForTexture autoFBForTex(sSnapshotContext, scopedTex.Texture()); + if (!autoFBForTex.IsComplete()) { + MOZ_CRASH("ScopedFramebufferForTexture failed."); + } - GLBlitHelper helper(sSnapshotContext); + const gl::OriginPos destOrigin = gl::OriginPos::TopLeft; - if (!helper.BlitImageToFramebuffer(this, size, fb.FB(), true)) { + if (!sSnapshotContext->BlitHelper()->BlitImageToFramebuffer(this, size, + autoFBForTex.FB(), + destOrigin)) + { return nullptr; } RefPtr<gfx::DataSourceSurface> source = gfx::Factory::CreateDataSourceSurface(size, gfx::SurfaceFormat::B8G8R8A8); if (NS_WARN_IF(!source)) { return nullptr; } - ScopedBindFramebuffer bind(sSnapshotContext, fb.FB()); + ScopedBindFramebuffer bind(sSnapshotContext, autoFBForTex.FB()); ReadPixelsIntoDataSurface(sSnapshotContext, source); return source.forget(); } } // layers } // mozilla
--- a/gfx/layers/Layers.cpp +++ b/gfx/layers/Layers.cpp @@ -16,17 +16,17 @@ #include "ReadbackLayer.h" // for ReadbackLayer #include "UnitTransforms.h" // for ViewAs #include "gfxPlatform.h" // for gfxPlatform #include "gfxPrefs.h" #include "gfxUtils.h" // for gfxUtils, etc #include "gfx2DGlue.h" #include "mozilla/DebugOnly.h" // for DebugOnly #include "mozilla/Telemetry.h" // for Accumulate -#include "mozilla/dom/AnimationPlayer.h" // for ComputedTimingFunction +#include "mozilla/dom/Animation.h" // for ComputedTimingFunction #include "mozilla/gfx/2D.h" // for DrawTarget #include "mozilla/gfx/BaseSize.h" // for BaseSize #include "mozilla/gfx/Matrix.h" // for Matrix4x4 #include "mozilla/layers/Compositor.h" // for Compositor #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/LayerManagerComposite.h" // for LayerComposite #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper #include "mozilla/layers/LayersMessages.h" // for TransformFunction, etc
--- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -29,17 +29,17 @@ #include "mozilla/BasicEvents.h" // for Modifiers, MODIFIER_* #include "mozilla/ClearOnShutdown.h" // for ClearOnShutdown #include "mozilla/Constants.h" // for M_PI #include "mozilla/EventForwards.h" // for nsEventStatus_* #include "mozilla/Preferences.h" // for Preferences #include "mozilla/ReentrantMonitor.h" // for ReentrantMonitorAutoEnter, etc #include "mozilla/StaticPtr.h" // for StaticAutoPtr #include "mozilla/TimeStamp.h" // for TimeDuration, TimeStamp -#include "mozilla/dom/AnimationPlayer.h" // for ComputedTimingFunction +#include "mozilla/dom/KeyframeEffect.h" // for ComputedTimingFunction #include "mozilla/dom/Touch.h" // for Touch #include "mozilla/gfx/BasePoint.h" // for BasePoint #include "mozilla/gfx/BaseRect.h" // for BaseRect #include "mozilla/gfx/Point.h" // for Point, RoundedToInt, etc #include "mozilla/gfx/Rect.h" // for RoundedIn #include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor #include "mozilla/layers/APZCTreeManager.h" // for ScrollableLayerGuid #include "mozilla/layers/APZThreadUtils.h" // for AssertOnControllerThread, etc
--- a/gfx/layers/apz/src/Axis.cpp +++ b/gfx/layers/apz/src/Axis.cpp @@ -3,17 +3,17 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "Axis.h" #include <math.h> // for fabsf, pow, powf #include <algorithm> // for max #include "AsyncPanZoomController.h" // for AsyncPanZoomController -#include "mozilla/dom/AnimationPlayer.h" // for ComputedTimingFunction +#include "mozilla/dom/KeyframeEffect.h" // for ComputedTimingFunction #include "mozilla/layers/APZCTreeManager.h" // for APZCTreeManager #include "mozilla/layers/APZThreadUtils.h" // for AssertOnControllerThread #include "FrameMetrics.h" // for FrameMetrics #include "mozilla/Attributes.h" // for final #include "mozilla/Preferences.h" // for Preferences #include "mozilla/gfx/Rect.h" // for RoundedIn #include "mozilla/mozalloc.h" // for operator new #include "mozilla/FloatingPoint.h" // for FuzzyEqualsAdditive
--- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -12,16 +12,17 @@ #include "mozilla/layers/ShadowLayers.h" #include "nsIScrollableFrame.h" #include "nsLayoutUtils.h" #include "nsIDOMElement.h" #include "nsIInterfaceRequestorUtils.h" #include "nsIContent.h" #include "nsIDocument.h" #include "nsIDOMWindow.h" +#include "nsRefreshDriver.h" #define APZCCH_LOG(...) // #define APZCCH_LOG(...) printf_stderr("APZCCH: " __VA_ARGS__) namespace mozilla { namespace layers { using dom::TabParent;
--- a/gfx/layers/apz/util/APZThreadUtils.cpp +++ b/gfx/layers/apz/util/APZThreadUtils.cpp @@ -1,16 +1,19 @@ /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "mozilla/layers/APZThreadUtils.h" #include "mozilla/layers/Compositor.h" +#ifdef MOZ_ANDROID_APZ +#include "AndroidBridge.h" +#endif namespace mozilla { namespace layers { static bool sThreadAssertionsEnabled = true; static MessageLoop* sControllerThread; /*static*/ void @@ -47,25 +50,36 @@ APZThreadUtils::AssertOnCompositorThread if (GetThreadAssertionsEnabled()) { Compositor::AssertOnCompositorThread(); } } /*static*/ void APZThreadUtils::RunOnControllerThread(Task* aTask) { +#ifdef MOZ_ANDROID_APZ + // This is needed while nsWindow::ConfigureAPZControllerThread is not propper + // implemented. + if (AndroidBridge::IsJavaUiThread()) { + aTask->Run(); + delete aTask; + } else { + AndroidBridge::Bridge()->PostTaskToUiThread(aTask, 0); + } +#else if (!sControllerThread) { // Could happen on startup NS_WARNING("Dropping task posted to controller thread\n"); delete aTask; return; } if (sControllerThread == MessageLoop::current()) { aTask->Run(); delete aTask; } else { sControllerThread->PostTask(FROM_HERE, aTask); } +#endif } } // namespace layers } // namespace mozilla
--- a/gfx/layers/composite/AsyncCompositionManager.cpp +++ b/gfx/layers/composite/AsyncCompositionManager.cpp @@ -8,17 +8,16 @@ #include <stdint.h> // for uint32_t #include "apz/src/AsyncPanZoomController.h" #include "FrameMetrics.h" // for FrameMetrics #include "LayerManagerComposite.h" // for LayerManagerComposite, etc #include "Layers.h" // for Layer, ContainerLayer, etc #include "gfxPoint.h" // for gfxPoint, gfxSize #include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc #include "mozilla/WidgetUtils.h" // for ComputeTransformForRotation -#include "mozilla/dom/AnimationPlayer.h" // for AnimationPlayer #include "mozilla/dom/KeyframeEffect.h" // for KeyframeEffectReadonly #include "mozilla/gfx/BaseRect.h" // for BaseRect #include "mozilla/gfx/Point.h" // for RoundedToInt, PointTyped #include "mozilla/gfx/Rect.h" // for RoundedToInt, RectTyped #include "mozilla/gfx/ScaleFactor.h" // for ScaleFactor #include "mozilla/layers/Compositor.h" // for Compositor #include "mozilla/layers/CompositorParent.h" // for CompositorParent, etc #include "mozilla/layers/LayerMetricsWrapper.h" // for LayerMetricsWrapper
--- a/image/test/unit/xpcshell.ini +++ b/image/test/unit/xpcshell.ini @@ -29,16 +29,18 @@ support-files = image4gif16x16bmp24bpp.ico image4gif16x16bmp32bpp.ico image4gif32x32bmp24bpp.ico image4gif32x32bmp32bpp.ico image_load_helpers.js [test_async_notification.js] +# Bug 1156452: frequent crash on Android 4.3 +skip-if = android_version == "18" [test_async_notification_404.js] [test_async_notification_animated.js] [test_encoder_apng.js] [test_encoder_png.js] [test_imgtools.js] # Bug 676968: test fails consistently on Android fail-if = os == "android" [test_moz_icon_uri.js]
--- a/js/src/asmjs/AsmJSLink.cpp +++ b/js/src/asmjs/AsmJSLink.cpp @@ -55,18 +55,16 @@ using mozilla::PodZero; static bool CloneModule(JSContext* cx, MutableHandle<AsmJSModuleObject*> moduleObj) { ScopedJSDeletePtr<AsmJSModule> module; if (!moduleObj->module().clone(cx, &module)) return false; - module->staticallyLink(cx); - AsmJSModuleObject* newModuleObj = AsmJSModuleObject::create(cx, &module); if (!newModuleObj) return false; moduleObj.set(newModuleObj); return true; } @@ -1044,37 +1042,29 @@ LinkAsmJS(JSContext* cx, unsigned argc, { CallArgs args = CallArgsFromVp(argc, vp); // The LinkAsmJS builtin (created by NewAsmJSModuleFunction) is an extended // function and stores its module in an extended slot. RootedFunction fun(cx, &args.callee().as<JSFunction>()); Rooted<AsmJSModuleObject*> moduleObj(cx, &ModuleFunctionToModuleObject(fun)); - // All ICache flushing of the module being linked has been inhibited under the - // assumption that the module is flushed after dynamic linking (when the last code - // mutation occurs). Thus, enter an AutoFlushICache context for the entire module - // now. The module range is set below. - AutoFlushICache afc("LinkAsmJS"); // When a module is linked, it is dynamically specialized to the given // arguments (buffer, ffis). Thus, if the module is linked again (it is just // a function so it can be called multiple times), we need to clone a new // module. - if (moduleObj->module().isDynamicallyLinked()) { - if (!CloneModule(cx, &moduleObj)) - return false; - } else { - // CloneModule already calls setAutoFlushICacheRange internally before patching - // the cloned module, so avoid calling twice. - moduleObj->module().setAutoFlushICacheRange(); - } + if (moduleObj->module().isDynamicallyLinked() && !CloneModule(cx, &moduleObj)) + return false; AsmJSModule& module = moduleObj->module(); + AutoFlushICache afc("LinkAsmJS"); + module.setAutoFlushICacheRange(); + // Link the module by performing the link-time validation checks in the // asm.js spec and then patching the generated module to associate it with // the given heap (ArrayBuffer) and a new global data segment (the closure // state shared by the inner asm.js functions). if (!DynamicallyLinkModule(cx, args, module)) { // Linking failed, so reparse the entire asm.js module from scratch to // get normal interpreted bytecode which we can simply Invoke. Very slow. RootedPropertyName name(cx, fun->name());
--- a/js/src/asmjs/AsmJSModule.cpp +++ b/js/src/asmjs/AsmJSModule.cpp @@ -756,36 +756,59 @@ AsmJSModule::staticallyLink(ExclusiveCon interruptExit_ = code_ + staticLinkData_.interruptExitOffset; outOfBoundsExit_ = code_ + staticLinkData_.outOfBoundsExitOffset; for (size_t i = 0; i < staticLinkData_.relativeLinks.length(); i++) { RelativeLink link = staticLinkData_.relativeLinks[i]; uint8_t* patchAt = code_ + link.patchAtOffset; uint8_t* target = code_ + link.targetOffset; + + // In the case of function-pointer tables and long-jumps on MIPS, the + // RelativeLink is used to patch a pointer to the function entry. If + // profiling is enabled (by cloning a module with profiling enabled), + // the target should be the profiling entry. + if (profilingEnabled_) { + const CodeRange* codeRange = lookupCodeRange(target); + if (codeRange && codeRange->isFunction() && link.targetOffset == codeRange->entry()) + target = code_ + codeRange->profilingEntry(); + } + if (link.isRawPointerPatch()) *(uint8_t**)(patchAt) = target; else Assembler::PatchInstructionImmediate(patchAt, PatchedImmPtr(target)); } - for (size_t imm = 0; imm < AsmJSImm_Limit; imm++) { - const AsmJSModule::OffsetVector& offsets = staticLinkData_.absoluteLinks[imm]; - void* target = AddressOf(AsmJSImmKind(imm), cx); + for (size_t immIndex = 0; immIndex < AsmJSImm_Limit; immIndex++) { + AsmJSImmKind imm = AsmJSImmKind(immIndex); + const OffsetVector& offsets = staticLinkData_.absoluteLinks[imm]; for (size_t i = 0; i < offsets.length(); i++) { - Assembler::PatchDataWithValueCheck(CodeLocationLabel(code_ + offsets[i]), + uint8_t* patchAt = code_ + offsets[i]; + void* target = AddressOf(imm, cx); + + // Builtin calls are another case where, when profiling is enabled, + // we must point to the profiling entry. + AsmJSExit::BuiltinKind builtin; + if (profilingEnabled_ && ImmKindIsBuiltin(imm, &builtin)) { + const CodeRange* codeRange = lookupCodeRange(patchAt); + if (codeRange->isFunction()) + target = code_ + builtinThunkOffsets_[builtin]; + } + + Assembler::PatchDataWithValueCheck(CodeLocationLabel(patchAt), PatchedImmPtr(target), PatchedImmPtr((void*)-1)); } } // Initialize global data segment for (size_t i = 0; i < exits_.length(); i++) { - AsmJSModule::ExitDatum& exitDatum = exitIndexToGlobalDatum(i); + ExitDatum& exitDatum = exitIndexToGlobalDatum(i); exitDatum.exit = interpExitTrampoline(exits_[i]); exitDatum.fun = nullptr; exitDatum.baselineScript = nullptr; } MOZ_ASSERT(isStaticallyLinked()); } @@ -925,16 +948,19 @@ AsmJSModule::detachHeap(JSContext* cx) } // Even if this->active(), to reach here, the activation must have called // out via an FFI stub. FFI stubs check if heapDatum() is null on reentry // and throw an exception if so. MOZ_ASSERT_IF(active(), activation()->exitReason() == AsmJSExit::Reason_JitFFI || activation()->exitReason() == AsmJSExit::Reason_SlowFFI); + AutoFlushICache afc("AsmJSModule::detachHeap"); + setAutoFlushICacheRange(); + restoreHeapToInitialState(maybeHeap_); MOZ_ASSERT(hasDetachedHeap()); return true; } bool js::OnDetachAsmJSArrayBuffer(JSContext* cx, Handle<ArrayBufferObject*> buffer) @@ -1649,21 +1675,23 @@ AsmJSModule::clone(JSContext* cx, Scoped return false; for (size_t i = 0; i < profilingLabels_.length(); i++) { out.profilingLabels_[i] = DuplicateString(cx, profilingLabels_[i].get()); if (!out.profilingLabels_[i]) return false; } } - // We already know the exact extent of areas that need to be patched, just make sure we - // flush all of them at once. + + // Delay flushing until dynamic linking. + AutoFlushICache afc("AsmJSModule::clone", /* inhibit = */ true); out.setAutoFlushICacheRange(); out.restoreToInitialState(maybeHeap_, code_, cx); + out.staticallyLink(cx); return true; } bool AsmJSModule::changeHeap(Handle<ArrayBufferObject*> newHeap, JSContext* cx) { MOZ_ASSERT(hasArrayView()); @@ -1742,17 +1770,17 @@ AsmJSModule::setProfilingEnabled(bool en #else # error "Missing architecture" #endif const CodeRange* codeRange = lookupCodeRange(callee); if (codeRange->kind() != CodeRange::Function) continue; - uint8_t* profilingEntry = code_ + codeRange->begin(); + uint8_t* profilingEntry = code_ + codeRange->profilingEntry(); uint8_t* entry = code_ + codeRange->entry(); MOZ_ASSERT_IF(profilingEnabled_, callee == profilingEntry); MOZ_ASSERT_IF(!profilingEnabled_, callee == entry); uint8_t* newCallee = enabled ? profilingEntry : entry; #if defined(JS_CODEGEN_X86) || defined(JS_CODEGEN_X64) X86Encoding::SetRel32(callerRetAddr, newCallee); #elif defined(JS_CODEGEN_ARM) @@ -1771,17 +1799,17 @@ AsmJSModule::setProfilingEnabled(bool en // Update all the addresses in the function-pointer tables to point to the // profiling prologues: for (size_t i = 0; i < funcPtrTables_.length(); i++) { FuncPtrTable& funcPtrTable = funcPtrTables_[i]; uint8_t** array = globalDataOffsetToFuncPtrTable(funcPtrTable.globalDataOffset()); for (size_t j = 0; j < funcPtrTable.numElems(); j++) { void* callee = array[j]; const CodeRange* codeRange = lookupCodeRange(callee); - uint8_t* profilingEntry = code_ + codeRange->begin(); + uint8_t* profilingEntry = code_ + codeRange->profilingEntry(); uint8_t* entry = code_ + codeRange->entry(); MOZ_ASSERT_IF(profilingEnabled_, callee == profilingEntry); MOZ_ASSERT_IF(!profilingEnabled_, callee == entry); if (enabled) array[j] = profilingEntry; else array[j] = entry; } @@ -2245,20 +2273,18 @@ js::LookupAsmJSModuleInCache(ExclusiveCo bool atEnd = cursor == entry.memory + entry.serializedSize; MOZ_ASSERT(atEnd, "Corrupt cache file"); if (!atEnd) return true; parser.tokenStream.advance(module->srcEndBeforeCurly()); { - // No need to flush the instruction cache now, it will be flushed when - // dynamically linking. We already know the exact extent of areas that need - // to be patched, just make sure we flush all of them at once. - AutoFlushICache afc("LookupAsmJSModuleInCache", /* inhibit= */ true); + // Delay flushing until dynamic linking. + AutoFlushICache afc("LookupAsmJSModuleInCache", /* inhibit = */ true); module->setAutoFlushICacheRange(); module->staticallyLink(cx); } int64_t usecAfter = PRMJ_Now(); int ms = (usecAfter - usecBefore) / PRMJ_USEC_PER_MSEC; *compilationTimeReport = JS_smprintf("loaded from cache in %dms", ms);
--- a/js/src/asmjs/AsmJSModule.h +++ b/js/src/asmjs/AsmJSModule.h @@ -576,16 +576,19 @@ class AsmJSModule bool isEntry() const { return kind() == Entry; } bool isFFI() const { return kind() == JitFFI || kind() == SlowFFI; } bool isInterrupt() const { return kind() == Interrupt; } bool isThunk() const { return kind() == Thunk; } uint32_t begin() const { return begin_; } + uint32_t profilingEntry() const { + return begin(); + } uint32_t entry() const { MOZ_ASSERT(isFunction()); return begin_ + u.func.beginToEntry_; } uint32_t end() const { return end_; } uint32_t profilingJump() const {
--- a/js/src/asmjs/AsmJSValidate.cpp +++ b/js/src/asmjs/AsmJSValidate.cpp @@ -9374,18 +9374,19 @@ CheckModule(ExclusiveContext* cx, AsmJSP return false; TokenKind tk; if (!PeekToken(m.parser(), &tk)) return false; if (tk != TOK_EOF && tk != TOK_RC) return m.fail(nullptr, "top-level export (return) must be the last statement"); - // The instruction cache is flushed when dynamically linking, so can inhibit now. - AutoFlushICache afc("CheckModule", /* inhibit= */ true); + // Delay flushing until dynamic linking. The inhibited range is set by the + // masm.executableCopy() called transitively by FinishModule. + AutoFlushICache afc("CheckModule", /* inhibit = */ true); ScopedJSDeletePtr<AsmJSModule> module; if (!FinishModule(m, &module)) return false; JS::AsmJSCacheResult cacheResult = StoreAsmJSModuleInCache(parser, *module, cx); module->staticallyLink(cx);
--- a/js/src/gc/Marking.cpp +++ b/js/src/gc/Marking.cpp @@ -37,49 +37,60 @@ using mozilla::DebugOnly; using mozilla::IsBaseOf; using mozilla::IsSame; using mozilla::MakeRange; void * const js::NullPtr::constNullValue = nullptr; JS_PUBLIC_DATA(void * const) JS::NullPtr::constNullValue = nullptr; -static inline void +static void PushMarkStack(GCMarker* gcmarker, JSObject* thing) { gcmarker->traverse(thing); } -static inline void -PushMarkStack(GCMarker* gcmarker, JSFunction* thing) { - gcmarker->traverse(static_cast<JSObject*>(thing)); -} -static inline void +static void PushMarkStack(GCMarker* gcmarker, ObjectGroup* thing) { gcmarker->traverse(thing); } static void PushMarkStack(GCMarker* gcmarker, jit::JitCode* thing) { gcmarker->traverse(thing); } -static inline void +static void PushMarkStack(GCMarker* gcmarker, JSScript* thing) { gcmarker->traverse(thing); } -static inline void +static void PushMarkStack(GCMarker* gcmarker, LazyScript* thing) { gcmarker->traverse(thing); } +static void +PushMarkStack(GCMarker* gcmarker, Shape* thing) { + gcmarker->traverse(thing); +} +static void +PushMarkStack(GCMarker* gcmarker, BaseShape* thing) { + gcmarker->traverse(thing); +} +static void +PushMarkStack(GCMarker* gcmarker, JSString* str) { + // Permanent atoms might not be associated with this runtime. + if (str->isPermanentAtom()) + return; -static inline void -PushMarkStack(GCMarker* gcmarker, Shape* thing); -static inline void -PushMarkStack(GCMarker* gcmarker, BaseShape* thing); -static inline void -PushMarkStack(GCMarker* gcmarker, JSString* thing); -static inline void -PushMarkStack(GCMarker* gcmarker, JS::Symbol* thing); + gcmarker->traverse(str); +} +static void +PushMarkStack(GCMarker* gcmarker, JS::Symbol* sym) { + // Well-known symbols might not be associated with this runtime. + if (sym->isWellKnownSymbol()) + return; + + gcmarker->traverse(sym); +} /*** Object Marking ***/ #if defined(DEBUG) template<typename T> static inline bool IsThingPoisoned(T* thing) { @@ -231,17 +242,17 @@ CheckMarkedThing<jsid>(JSTracer* trc, js #define JS_ROOT_MARKING_ASSERT(trc) \ MOZ_ASSERT_IF(trc->isMarkingTracer(), \ trc->runtime()->gc.state() == NO_INCREMENTAL || \ trc->runtime()->gc.state() == MARK_ROOTS); // A C++ version of JSGCTraceKind enum class TraceKind { -#define NAMES(name, _) name, +#define NAMES(name, _, __) name, FOR_EACH_GC_LAYOUT(NAMES) #undef NAMES }; #define FOR_EACH_GC_POINTER_TYPE(D) \ D(BaseShape*) \ D(UnownedBaseShape*) \ D(jit::JitCode*) \ @@ -293,17 +304,17 @@ template <typename T, : IsBaseOf<JS::Symbol, T>::value ? TraceKind::Symbol : IsBaseOf<JSScript, T>::value ? TraceKind::Script : IsBaseOf<Shape, T>::value ? TraceKind::Shape : IsBaseOf<BaseShape, T>::value ? TraceKind::BaseShape : IsBaseOf<jit::JitCode, T>::value ? TraceKind::JitCode : IsBaseOf<LazyScript, T>::value ? TraceKind::LazyScript : TraceKind::ObjectGroup> struct BaseGCType; -#define IMPL_BASE_GC_TYPE(name, type_) \ +#define IMPL_BASE_GC_TYPE(name, type_, _) \ template <typename T> struct BaseGCType<T, TraceKind:: name> { typedef type_ type; }; FOR_EACH_GC_LAYOUT(IMPL_BASE_GC_TYPE); #undef IMPL_BASE_GC_TYPE // Our barrier templates are parameterized on the pointer types so that we can // share the definitions with Value and jsid. Thus, we need to strip the // pointer before sending the type to BaseGCType and re-add it on the other // side. As such: @@ -407,17 +418,17 @@ template void js::TraceCrossCompartmentE // This method is responsible for dynamic dispatch to the real tracer // implementation. Consider replacing this choke point with virtual dispatch: // a sufficiently smart C++ compiler may be able to devirtualize some paths. template <typename T> void DispatchToTracer(JSTracer* trc, T* thingp, const char* name) { -#define IS_SAME_TYPE_OR(name, type) mozilla::IsSame<type*, T>::value || +#define IS_SAME_TYPE_OR(name, type, _) mozilla::IsSame<type*, T>::value || static_assert( FOR_EACH_GC_LAYOUT(IS_SAME_TYPE_OR) mozilla::IsSame<T, JS::Value>::value || mozilla::IsSame<T, jsid>::value, "Only the base cell layout types are allowed into marking/tracing internals"); #undef IS_SAME_TYPE_OR CheckMarkedThing(trc, *thingp); @@ -545,17 +556,17 @@ MarkWellKnownSymbol(JSTracer* trc, JS::S DoCallback(trc->asCallbackTracer(), &sym, "wellKnownSymbol"); } } template <typename T> static inline void CheckIsMarkedThing(T* thingp) { -#define IS_SAME_TYPE_OR(name, type) mozilla::IsSame<type*, T>::value || +#define IS_SAME_TYPE_OR(name, type, _) mozilla::IsSame<type*, T>::value || static_assert( FOR_EACH_GC_LAYOUT(IS_SAME_TYPE_OR) false, "Only the base cell layout types are allowed into marking/tracing internals"); #undef IS_SAME_TYPE_OR #ifdef DEBUG MOZ_ASSERT(thingp); MOZ_ASSERT(*thingp); @@ -925,97 +936,69 @@ static void MaybePushMarkStackBetweenSlices(GCMarker* gcmarker, JSObject* thing) { MOZ_ASSERT_IF(gcmarker->runtime()->isHeapBusy(), !IsInsideNursery(thing)); if (!IsInsideNursery(thing)) gcmarker->traverse(thing); } -static void -ScanShape(GCMarker* gcmarker, Shape* shape); - -static void -PushMarkStack(GCMarker* gcmarker, Shape* thing) -{ - JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing); - MOZ_ASSERT(!IsInsideNursery(thing)); - - /* We mark shapes directly rather than pushing on the stack. */ - if (thing->markIfUnmarked(gcmarker->markColor())) - ScanShape(gcmarker, thing); -} - -static inline void -ScanBaseShape(GCMarker* gcmarker, BaseShape* base); - void BaseShape::traceChildren(JSTracer* trc) { if (isOwned()) TraceEdge(trc, &unowned_, "base"); JSObject* global = compartment()->unsafeUnbarrieredMaybeGlobal(); if (global) TraceManuallyBarrieredEdge(trc, &global, "global"); } -static void -PushMarkStack(GCMarker* gcmarker, BaseShape* thing) -{ - JS_COMPARTMENT_ASSERT(gcmarker->runtime(), thing); - MOZ_ASSERT(!IsInsideNursery(thing)); - - /* We mark base shapes directly rather than pushing on the stack. */ - if (thing->markIfUnmarked(gcmarker->markColor())) - ScanBaseShape(gcmarker, thing); -} - -static void -ScanShape(GCMarker* gcmarker, Shape* shape) +inline void +GCMarker::eagerlyMarkChildren(Shape* shape) { restart: - PushMarkStack(gcmarker, shape->base()); + PushMarkStack(this, shape->base()); const BarrieredBase<jsid>& id = shape->propidRef(); if (JSID_IS_STRING(id)) - PushMarkStack(gcmarker, JSID_TO_STRING(id)); + PushMarkStack(this, JSID_TO_STRING(id)); else if (JSID_IS_SYMBOL(id)) - PushMarkStack(gcmarker, JSID_TO_SYMBOL(id)); + PushMarkStack(this, JSID_TO_SYMBOL(id)); if (shape->hasGetterObject()) - MaybePushMarkStackBetweenSlices(gcmarker, shape->getterObject()); + MaybePushMarkStackBetweenSlices(this, shape->getterObject()); if (shape->hasSetterObject()) - MaybePushMarkStackBetweenSlices(gcmarker, shape->setterObject()); + MaybePushMarkStackBetweenSlices(this, shape->setterObject()); shape = shape->previous(); - if (shape && shape->markIfUnmarked(gcmarker->markColor())) + if (shape && shape->markIfUnmarked(this->markColor())) goto restart; } -static inline void -ScanBaseShape(GCMarker* gcmarker, BaseShape* base) +inline void +GCMarker::eagerlyMarkChildren(BaseShape* base) { base->assertConsistency(); base->compartment()->mark(); if (GlobalObject* global = base->compartment()->unsafeUnbarrieredMaybeGlobal()) - gcmarker->traverse(global); + traverse(global); /* * All children of the owned base shape are consistent with its * unowned one, thus we do not need to trace through children of the * unowned base shape. */ if (base->isOwned()) { UnownedBaseShape* unowned = base->baseUnowned(); MOZ_ASSERT(base->compartment() == unowned->compartment()); - unowned->markIfUnmarked(gcmarker->markColor()); + unowned->markIfUnmarked(markColor()); } } static inline void ScanLinearString(GCMarker* gcmarker, JSLinearString* str) { JS_COMPARTMENT_ASSERT(gcmarker->runtime(), str); MOZ_ASSERT(str->isMarked()); @@ -1086,62 +1069,30 @@ ScanRope(GCMarker* gcmarker, JSRope* rop rope = reinterpret_cast<JSRope*>(gcmarker->stack.pop()); } else { break; } } MOZ_ASSERT(savedPos == gcmarker->stack.position()); } -static inline void -ScanString(GCMarker* gcmarker, JSString* str) +inline void +GCMarker::eagerlyMarkChildren(JSString* str) { if (str->isLinear()) - ScanLinearString(gcmarker, &str->asLinear()); + ScanLinearString(this, &str->asLinear()); else - ScanRope(gcmarker, &str->asRope()); + ScanRope(this, &str->asRope()); } -static inline void -PushMarkStack(GCMarker* gcmarker, JSString* str) -{ - // Permanent atoms might not be associated with this runtime. - if (str->isPermanentAtom()) - return; - - JS_COMPARTMENT_ASSERT(gcmarker->runtime(), str); - - /* - * As string can only refer to other strings we fully scan its GC graph - * using the explicit stack when navigating the rope tree to avoid - * dealing with strings on the stack in drainMarkStack. - */ - if (str->markIfUnmarked()) - ScanString(gcmarker, str); -} - -static inline void -ScanSymbol(GCMarker* gcmarker, JS::Symbol* sym) +inline void +GCMarker::eagerlyMarkChildren(JS::Symbol* sym) { if (JSString* desc = sym->description()) - PushMarkStack(gcmarker, desc); -} - -static inline void -PushMarkStack(GCMarker* gcmarker, JS::Symbol* sym) -{ - // Well-known symbols might not be associated with this runtime. - if (sym->isWellKnownSymbol()) - return; - - JS_COMPARTMENT_ASSERT(gcmarker->runtime(), sym); - MOZ_ASSERT(!IsInsideNursery(sym)); - - if (sym->markIfUnmarked()) - ScanSymbol(gcmarker, sym); + PushMarkStack(this, desc); } /* * This function is used by the cycle collector to trace through a * shape. The cycle collector does not care about shapes or base * shapes, so those are not marked. Instead, any shapes or base shapes * that are encountered have their children marked. Stack space is * bounded. @@ -1436,28 +1387,28 @@ GCMarker::processMarkStackOther(uintptr_ MOZ_ALWAYS_INLINE void GCMarker::markAndScanString(JSObject* source, JSString* str) { if (!str->isPermanentAtom()) { JS_COMPARTMENT_ASSERT(runtime(), str); MOZ_ASSERT(runtime()->isAtomsZone(str->zone()) || str->zone() == source->zone()); if (str->markIfUnmarked()) - ScanString(this, str); + eagerlyMarkChildren(str); } } MOZ_ALWAYS_INLINE void GCMarker::markAndScanSymbol(JSObject* source, JS::Symbol* sym) { if (!sym->isWellKnownSymbol()) { JS_COMPARTMENT_ASSERT(runtime(), sym); MOZ_ASSERT(runtime()->isAtomsZone(sym->zone()) || sym->zone() == source->zone()); if (sym->markIfUnmarked()) - ScanSymbol(this, sym); + eagerlyMarkChildren(sym); } } inline void GCMarker::processMarkStackTop(SliceBudget& budget) { /* * The function uses explicit goto and implements the scanning of the @@ -1693,16 +1644,27 @@ GCMarker::drainMarkStack(SliceBudget& bu template <typename T> void GCMarker::dispatchToTraceChildren(T* thing) { thing->traceChildren(this); } +template <typename T> +bool +GCMarker::mark(T* thing) +{ + JS_COMPARTMENT_ASSERT(runtime(), thing); + MOZ_ASSERT(!IsInsideNursery(gc::TenuredCell::fromPointer(thing))); + return gc::ParticipatesInCC<T>::value + ? gc::TenuredCell::fromPointer(thing)->markIfUnmarked(markColor()) + : gc::TenuredCell::fromPointer(thing)->markIfUnmarked(gc::BLACK); +} + struct TraceChildrenFunctor { template <typename T> void operator()(JSTracer* trc, void* thing) { static_cast<T*>(thing)->traceChildren(trc); } }; void
--- a/js/src/gc/Tracer.cpp +++ b/js/src/gc/Tracer.cpp @@ -32,17 +32,17 @@ using mozilla::DebugOnly; template <typename T> void DoCallback(JS::CallbackTracer* trc, T* thingp, const char* name) { JSGCTraceKind kind = MapTypeToTraceKind<typename mozilla::RemovePointer<T>::Type>::kind; JS::AutoTracingName ctx(trc, name); trc->invoke((void**)thingp, kind); } -#define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(name, type) \ +#define INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS(name, type, _) \ template void DoCallback<type*>(JS::CallbackTracer*, type**, const char*); FOR_EACH_GC_LAYOUT(INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS); #undef INSTANTIATE_ALL_VALID_TRACE_FUNCTIONS template <> void DoCallback<Value>(JS::CallbackTracer* trc, Value* vp, const char* name) {
--- a/js/src/gc/Tracer.h +++ b/js/src/gc/Tracer.h @@ -156,16 +156,21 @@ class GCMarker : public JSTracer void start(); void stop(); void reset(); // Mark the given GC thing and traverse its children at some point. void traverse(JSObject* thing) { markAndPush(ObjectTag, thing); } void traverse(ObjectGroup* thing) { markAndPush(GroupTag, thing); } void traverse(jit::JitCode* thing) { markAndPush(JitCodeTag, thing); } + // Mark the given GC thing and then eagerly mark all children. + void traverse(Shape* thing) { markAndScan(thing); } + void traverse(BaseShape* thing) { markAndScan(thing); } + void traverse(JSString* thing) { markAndScan(thing); } + void traverse(JS::Symbol* thing) { markAndScan(thing); } // The following traverse methods traverse immediately, go out-of-line to do so. void traverse(JSScript* thing) { markAndTraverse(thing); } void traverse(LazyScript* thing) { markAndTraverse(thing); } // The other types are marked immediately and inline via a ScanFoo shared // between PushMarkStack and the processMarkStackTop. Since ScanFoo is // inline in Marking.cpp, we cannot inline it here, yet. /* @@ -246,33 +251,39 @@ class GCMarker : public JSTracer template <typename T> void markAndPush(StackTag tag, T* thing) { if (mark(thing)) pushTaggedPtr(tag, thing); } template <typename T> + void markAndScan(T* thing) { + if (mark(thing)) + eagerlyMarkChildren(thing); + } + void eagerlyMarkChildren(Shape* shape); + void eagerlyMarkChildren(BaseShape* base); + void eagerlyMarkChildren(JSString* str); + void eagerlyMarkChildren(JS::Symbol* sym); + + template <typename T> void markAndTraverse(T* thing) { if (mark(thing)) dispatchToTraceChildren(thing); } // We may not have concrete types yet, so this has to be out of the header. template <typename T> void dispatchToTraceChildren(T* thing); // Mark the given GC thing, but do not trace its children. Return true // if the thing became marked. template <typename T> - bool mark(T* thing) { - JS_COMPARTMENT_ASSERT(runtime(), thing); - MOZ_ASSERT(!IsInsideNursery(gc::TenuredCell::fromPointer(thing))); - return gc::TenuredCell::fromPointer(thing)->markIfUnmarked(markColor()); - } + bool mark(T* thing); void pushTaggedPtr(StackTag tag, void* ptr) { checkZone(ptr); uintptr_t addr = reinterpret_cast<uintptr_t>(ptr); MOZ_ASSERT(!(addr & StackTagMask)); if (!stack.push(addr | uintptr_t(tag))) delayMarkingChildren(ptr); }
--- a/js/src/jit-test/tests/asm.js/testProfiling.js +++ b/js/src/jit-test/tests/asm.js/testProfiling.js @@ -58,72 +58,87 @@ var ffi = function(enable) { enableSPSProfiling(); enableSingleStepProfiling(); stacks = disableSingleStepProfiling(); if (enable == -1) disableSPSProfiling(); } var f = asmLink(asmCompile('global','ffis',USE_ASM + "var ffi=ffis.ffi; function g(i) { i=i|0; ffi(i|0) } function f(i) { i=i|0; g(i|0) } return f"), null, {ffi}); f(0); -assertStackContainsSeq(stacks, "", true); +assertStackContainsSeq(stacks, ""); f(+1); -assertStackContainsSeq(stacks, "", true); +assertStackContainsSeq(stacks, ""); f(0); -assertStackContainsSeq(stacks, "<,g,f,>", true); +assertStackContainsSeq(stacks, "<,g,f,>"); f(-1); -assertStackContainsSeq(stacks, "<,g,f,>", true); +assertStackContainsSeq(stacks, "<,g,f,>"); f(0); -assertStackContainsSeq(stacks, "", true); +assertStackContainsSeq(stacks, ""); // Enable profiling for the rest of the tests. enableSPSProfiling(); var f = asmLink(asmCompile(USE_ASM + "function f() { return 42 } return f")); enableSingleStepProfiling(); assertEq(f(), 42); var stacks = disableSingleStepProfiling(); assertStackContainsSeq(stacks, ">,f,>,>"); -var f = asmLink(asmCompile(USE_ASM + "function g(i) { i=i|0; return (i+1)|0 } function f() { return g(42)|0 } return f")); -enableSingleStepProfiling(); -assertEq(f(), 43); -var stacks = disableSingleStepProfiling(); -assertStackContainsSeq(stacks, ">,f,>,g,f,>,f,>,>"); +var m = asmCompile(USE_ASM + "function g(i) { i=i|0; return (i+1)|0 } function f() { return g(42)|0 } return f"); +for (var i = 0; i < 3; i++) { + var f = asmLink(m); + enableSingleStepProfiling(); + assertEq(f(), 43); + var stacks = disableSingleStepProfiling(); + assertStackContainsSeq(stacks, ">,f,>,g,f,>,f,>,>"); +} -var f = asmLink(asmCompile(USE_ASM + "function g1() { return 1 } function g2() { return 2 } function f(i) { i=i|0; return TBL[i&1]()|0 } var TBL=[g1,g2]; return f")); -enableSingleStepProfiling(); -assertEq(f(0), 1); -assertEq(f(1), 2); -var stacks = disableSingleStepProfiling(); -assertStackContainsSeq(stacks, ">,f,>,g1,f,>,f,>,>,>,f,>,g2,f,>,f,>,>"); +var m = asmCompile(USE_ASM + "function g1() { return 1 } function g2() { return 2 } function f(i) { i=i|0; return TBL[i&1]()|0 } var TBL=[g1,g2]; return f"); +for (var i = 0; i < 3; i++) { + var f = asmLink(m); + enableSingleStepProfiling(); + assertEq(f(0), 1); + assertEq(f(1), 2); + var stacks = disableSingleStepProfiling(); + assertStackContainsSeq(stacks, ">,f,>,g1,f,>,f,>,>,>,f,>,g2,f,>,f,>,>"); +} function testBuiltinD2D(name) { - var f = asmLink(asmCompile('g', USE_ASM + "var fun=g.Math." + name + "; function f(d) { d=+d; return +fun(d) } return f"), this); - enableSingleStepProfiling(); - assertEq(f(.1), eval("Math." + name + "(.1)")); - var stacks = disableSingleStepProfiling(); - assertStackContainsSeq(stacks, ">,f,>,Math." + name + ",f,>,f,>,>"); + var m = asmCompile('g', USE_ASM + "var fun=g.Math." + name + "; function f(d) { d=+d; return +fun(d) } return f"); + for (var i = 0; i < 3; i++) { + var f = asmLink(m, this); + enableSingleStepProfiling(); + assertEq(f(.1), eval("Math." + name + "(.1)")); + var stacks = disableSingleStepProfiling(); + assertStackContainsSeq(stacks, ">,f,>,Math." + name + ",f,>,f,>,>"); + } } for (name of ['sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'ceil', 'floor', 'exp', 'log']) testBuiltinD2D(name); function testBuiltinF2F(name) { - var f = asmLink(asmCompile('g', USE_ASM + "var tof=g.Math.fround; var fun=g.Math." + name + "; function f(d) { d=tof(d); return tof(fun(d)) } return f"), this); - enableSingleStepProfiling(); - assertEq(f(.1), eval("Math.fround(Math." + name + "(Math.fround(.1)))")); - var stacks = disableSingleStepProfiling(); - assertStackContainsSeq(stacks, ">,f,>,Math." + name + ",f,>,f,>,>"); + var m = asmCompile('g', USE_ASM + "var tof=g.Math.fround; var fun=g.Math." + name + "; function f(d) { d=tof(d); return tof(fun(d)) } return f"); + for (var i = 0; i < 3; i++) { + var f = asmLink(m, this); + enableSingleStepProfiling(); + assertEq(f(.1), eval("Math.fround(Math." + name + "(Math.fround(.1)))")); + var stacks = disableSingleStepProfiling(); + assertStackContainsSeq(stacks, ">,f,>,Math." + name + ",f,>,f,>,>"); + } } for (name of ['ceil', 'floor']) testBuiltinF2F(name); function testBuiltinDD2D(name) { - var f = asmLink(asmCompile('g', USE_ASM + "var fun=g.Math." + name + "; function f(d, e) { d=+d; e=+e; return +fun(d,e) } return f"), this); - enableSingleStepProfiling(); - assertEq(f(.1, .2), eval("Math." + name + "(.1, .2)")); - var stacks = disableSingleStepProfiling(); - assertStackContainsSeq(stacks, ">,f,>,Math." + name + ",f,>,f,>,>"); + var m = asmCompile('g', USE_ASM + "var fun=g.Math." + name + "; function f(d, e) { d=+d; e=+e; return +fun(d,e) } return f"); + for (var i = 0; i < 3; i++) { + var f = asmLink(m, this); + enableSingleStepProfiling(); + assertEq(f(.1, .2), eval("Math." + name + "(.1, .2)")); + var stacks = disableSingleStepProfiling(); + assertStackContainsSeq(stacks, ">,f,>,Math." + name + ",f,>,f,>,>"); + } } for (name of ['atan2', 'pow']) testBuiltinDD2D(name); // FFI tests: setJitCompilerOption("ion.warmup.trigger", 10); setJitCompilerOption("baseline.warmup.trigger", 0); setJitCompilerOption("offthread-compilation.enable", 0);
--- a/js/src/jit-test/tests/atomics/basic-tests.js +++ b/js/src/jit-test/tests/atomics/basic-tests.js @@ -11,16 +11,23 @@ function dprint(...xs) { if (!DEBUG) return; var s = ""; for ( var x in xs ) s += String(xs[x]); print(s); } +// Clone a function so that we get reliable inlining of primitives with --ion-eager. +// For eg testMethod and testFunction that are polymorphic in the array a, +// the inliner gets confused and stops inlining after Int8 -- not what we want. +function CLONE(f) { + return this.eval("(" + f.toSource() + ")"); +} + function testMethod(a, ...indices) { dprint("Method: " + a.constructor.name); var poison; switch (a.BYTES_PER_ELEMENT) { case 1: poison = 0x5A; break; case 2: poison = 0x5A5A; break; case 4: poison = 0x5A5A5A5A; break; } @@ -197,17 +204,17 @@ function testRangeCAS(a) { assertEq(Atomics.compareExchange(a, "hi", 0, 1), undefined); // invalid => undefined, no effect assertEq(a[0], 0); a[0] = 0; assertEq(Atomics.compareExchange(a, a.length + 5, 0, 1), undefined); // out of range => undefined, no effect assertEq(a[0], 0); } -// Ad-hoc tests for extreme and out-of-range values +// Ad-hoc tests for extreme and out-of-range values. // None of these should throw function testInt8Extremes(a) { dprint("Int8 extremes"); a[10] = 0; a[11] = 0; @@ -233,17 +240,17 @@ function testInt8Extremes(a) { Atomics.and(a, 10, -1); // Preserve all assertEq(a[10], -2); assertEq(Atomics.load(a, 10), -2); Atomics.and(a, 10, 256); // Preserve none assertEq(a[10], 0); assertEq(Atomics.load(a, 10), 0); - + assertEq(a[11], 0); } function testUint8Extremes(a) { dprint("Uint8 extremes"); a[10] = 0; a[11] = 0; @@ -266,17 +273,17 @@ function testUint8Extremes(a) { Atomics.and(a, 10, -1); // Preserve all assertEq(a[10], 254); assertEq(Atomics.load(a, 10), 254); Atomics.and(a, 10, 256); // Preserve none assertEq(a[10], 0); assertEq(Atomics.load(a, 10), 0); - + assertEq(a[11], 0); } function testInt16Extremes(a) { dprint("Int16 extremes"); a[10] = 0; a[11] = 0; @@ -350,65 +357,65 @@ function runTests() { t1[0] = 37; if (is_little) assertEq(t2[0], 37); else assertEq(t2[0], 37 << 16); t1[0] = 0; // Test that invoking as Atomics.whatever() works, on correct arguments - testMethod(new SharedInt8Array(sab), 0, 42, 4095); - testMethod(new SharedUint8Array(sab), 0, 42, 4095); - testMethod(new SharedUint8ClampedArray(sab), 0, 42, 4095); - testMethod(new SharedInt16Array(sab), 0, 42, 2047); - testMethod(new SharedUint16Array(sab), 0, 42, 2047); - testMethod(new SharedInt32Array(sab), 0, 42, 1023); - testMethod(new SharedUint32Array(sab), 0, 42, 1023); + CLONE(testMethod)(new SharedInt8Array(sab), 0, 42, 4095); + CLONE(testMethod)(new SharedUint8Array(sab), 0, 42, 4095); + CLONE(testMethod)(new SharedUint8ClampedArray(sab), 0, 42, 4095); + CLONE(testMethod)(new SharedInt16Array(sab), 0, 42, 2047); + CLONE(testMethod)(new SharedUint16Array(sab), 0, 42, 2047); + CLONE(testMethod)(new SharedInt32Array(sab), 0, 42, 1023); + CLONE(testMethod)(new SharedUint32Array(sab), 0, 42, 1023); // Test that invoking as v = Atomics.whatever; v() works, on correct arguments gAtomics_compareExchange = Atomics.compareExchange; gAtomics_load = Atomics.load; gAtomics_store = Atomics.store; gAtomics_fence = Atomics.fence; gAtomics_add = Atomics.add; gAtomics_sub = Atomics.sub; gAtomics_and = Atomics.and; gAtomics_or = Atomics.or; gAtomics_xor = Atomics.xor; - testFunction(new SharedInt8Array(sab), 0, 42, 4095); - testFunction(new SharedUint8Array(sab), 0, 42, 4095); - testFunction(new SharedUint8ClampedArray(sab), 0, 42, 4095); - testFunction(new SharedInt16Array(sab), 0, 42, 2047); - testFunction(new SharedUint16Array(sab), 0, 42, 2047); - testFunction(new SharedInt32Array(sab), 0, 42, 1023); - testFunction(new SharedUint32Array(sab), 0, 42, 1023); + CLONE(testFunction)(new SharedInt8Array(sab), 0, 42, 4095); + CLONE(testFunction)(new SharedUint8Array(sab), 0, 42, 4095); + CLONE(testFunction)(new SharedUint8ClampedArray(sab), 0, 42, 4095); + CLONE(testFunction)(new SharedInt16Array(sab), 0, 42, 2047); + CLONE(testFunction)(new SharedUint16Array(sab), 0, 42, 2047); + CLONE(testFunction)(new SharedInt32Array(sab), 0, 42, 1023); + CLONE(testFunction)(new SharedUint32Array(sab), 0, 42, 1023); // Test various range and type conditions var v8 = new SharedInt8Array(sab); var v32 = new SharedInt32Array(sab); - testTypeCAS(v8); - testTypeCAS(v32); + CLONE(testTypeCAS)(v8); + CLONE(testTypeCAS)(v32); - testTypeBinop(v8, Atomics.add); - testTypeBinop(v8, Atomics.sub); - testTypeBinop(v8, Atomics.and); - testTypeBinop(v8, Atomics.or); - testTypeBinop(v8, Atomics.xor); + CLONE(testTypeBinop)(v8, Atomics.add); + CLONE(testTypeBinop)(v8, Atomics.sub); + CLONE(testTypeBinop)(v8, Atomics.and); + CLONE(testTypeBinop)(v8, Atomics.or); + CLONE(testTypeBinop)(v8, Atomics.xor); - testTypeBinop(v32, Atomics.add); - testTypeBinop(v32, Atomics.sub); - testTypeBinop(v32, Atomics.and); - testTypeBinop(v32, Atomics.or); - testTypeBinop(v32, Atomics.xor); + CLONE(testTypeBinop)(v32, Atomics.add); + CLONE(testTypeBinop)(v32, Atomics.sub); + CLONE(testTypeBinop)(v32, Atomics.and); + CLONE(testTypeBinop)(v32, Atomics.or); + CLONE(testTypeBinop)(v32, Atomics.xor); // Test out-of-range references - testRangeCAS(v8); - testRangeCAS(v32); + CLONE(testRangeCAS)(v8); + CLONE(testRangeCAS)(v32); // Test extreme values testInt8Extremes(new SharedInt8Array(sab)); testUint8Extremes(new SharedUint8Array(sab)); testInt16Extremes(new SharedInt16Array(sab)); testUint32(new SharedUint32Array(sab)); }
--- a/js/src/jit/arm/Architecture-arm.h +++ b/js/src/jit/arm/Architecture-arm.h @@ -78,22 +78,22 @@ class Registers typedef RegisterID Encoding; // Content spilled during bailouts. union RegisterContent { uintptr_t r; }; static const char* GetName(Code code) { + MOZ_ASSERT(code < Total); static const char * const Names[] = { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "r14", "pc"}; return Names[code]; } - static const char* GetName(uint32_t i) { - MOZ_ASSERT(i < Total); + static const char* GetName(Encoding i) { return GetName(Code(i)); } static Code FromName(const char* name); static const Encoding StackPointer = sp; static const Encoding Invalid = invalid_reg;
--- a/js/src/jit/arm/Simulator-arm.cpp +++ b/js/src/jit/arm/Simulator-arm.cpp @@ -3103,16 +3103,29 @@ Simulator::decodeType3(SimInstruction* i set_register(rd, (rm_val & 0xFF)); } else { // Uxtab. uint32_t rn_val = get_register(rn); uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), instr->bits(11, 10)); set_register(rd, rn_val + (rm_val & 0xFF)); } + } else if ((instr->bit(20) == 1) && (instr->bits(9, 6) == 1)) { + if (instr->bits(19, 16) == 0xF) { + // Uxth. + uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), + instr->bits(11, 10)); + set_register(rd, (rm_val & 0xFFFF)); + } else { + // Uxtah. + uint32_t rn_val = get_register(rn); + uint32_t rm_val = rotateBytes(get_register(instr->rmValue()), + instr->bits(11, 10)); + set_register(rd, rn_val + (rm_val & 0xFFFF)); + } } else { MOZ_CRASH(); } break; } } return; }
--- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -19,26 +19,27 @@ #include "js/GCAPI.h" #include "js/SliceBudget.h" #include "js/Vector.h" #include "vm/NativeObject.h" #define FOR_EACH_GC_LAYOUT(D) \ - D(Object, JSObject) \ - D(String, JSString) \ - D(Symbol, JS::Symbol) \ - D(Script, JSScript) \ - D(AccessorShape, js::AccessorShape) \ - D(Shape, js::Shape) \ - D(BaseShape, js::BaseShape) \ - D(JitCode, js::jit::JitCode) \ - D(LazyScript, js::LazyScript) \ - D(ObjectGroup, js::ObjectGroup) + /* PrettyName TypeName AddToCCKind */ \ + D(AccessorShape, js::AccessorShape, true) \ + D(BaseShape, js::BaseShape, true) \ + D(JitCode, js::jit::JitCode, true) \ + D(LazyScript, js::LazyScript, true) \ + D(Object, JSObject, true) \ + D(ObjectGroup, js::ObjectGroup, true) \ + D(Script, JSScript, true) \ + D(Shape, js::Shape, true) \ + D(String, JSString, false) \ + D(Symbol, JS::Symbol, false) namespace js { unsigned GetCPUCount(); enum HeapState { Idle, // doing nothing with the GC heap Tracing, // tracing the GC heap without collecting, e.g. IterateCompartments() @@ -79,16 +80,22 @@ template <> struct MapTypeToFinalizeKind template <> struct MapTypeToFinalizeKind<BaseShape> { static const AllocKind kind = AllocKind::BASE_SHAPE; }; template <> struct MapTypeToFinalizeKind<ObjectGroup> { static const AllocKind kind = AllocKind::OBJECT_GROUP; }; template <> struct MapTypeToFinalizeKind<JSFatInlineString> { static const AllocKind kind = AllocKind::FAT_INLINE_STRING; }; template <> struct MapTypeToFinalizeKind<JSString> { static const AllocKind kind = AllocKind::STRING; }; template <> struct MapTypeToFinalizeKind<JSExternalString> { static const AllocKind kind = AllocKind::EXTERNAL_STRING; }; template <> struct MapTypeToFinalizeKind<JS::Symbol> { static const AllocKind kind = AllocKind::SYMBOL; }; template <> struct MapTypeToFinalizeKind<jit::JitCode> { static const AllocKind kind = AllocKind::JITCODE; }; +template <typename T> struct ParticipatesInCC {}; +#define EXPAND_PARTICIPATES_IN_CC(_, type, addToCCKind) \ + template <> struct ParticipatesInCC<type> { static const bool value = addToCCKind; }; +FOR_EACH_GC_LAYOUT(EXPAND_PARTICIPATES_IN_CC) +#undef EXPAND_PARTICIPATES_IN_CC + static inline bool IsNurseryAllocable(AllocKind kind) { MOZ_ASSERT(IsValidAllocKind(kind)); static const bool map[] = { false, /* AllocKind::OBJECT0 */ true, /* AllocKind::OBJECT0_BACKGROUND */ false, /* AllocKind::OBJECT2 */
--- a/js/src/vm/Stack.cpp +++ b/js/src/vm/Stack.cpp @@ -1609,28 +1609,22 @@ jit::JitActivation::markIonRecovery(JSTr for (RInstructionResults* it = ionRecovery_.begin(); it != ionRecovery_.end(); it++) it->trace(trc); } AsmJSActivation::AsmJSActivation(JSContext* cx, AsmJSModule& module) : Activation(cx, AsmJS), module_(module), entrySP_(nullptr), - profiler_(nullptr), resumePC_(nullptr), fp_(nullptr), exitReason_(AsmJSExit::None) { (void) entrySP_; // squelch GCC warning - // NB: this is a hack and can be removed once Ion switches over to - // JS::ProfilingFrameIterator. - if (cx->runtime()->spsProfiler.enabled()) - profiler_ = &cx->runtime()->spsProfiler; - prevAsmJSForModule_ = module.activation(); module.activation() = this; prevAsmJS_ = cx->runtime()->asmJSActivationStack_; cx->runtime()->asmJSActivationStack_ = this; // Now that the AsmJSActivation is fully initialized, make it visible to // asynchronous profiling.
--- a/js/src/vm/Stack.h +++ b/js/src/vm/Stack.h @@ -1518,17 +1518,16 @@ class InterpreterFrameIterator // efficient calls back and forth but requires that we can walk the stack for // all kinds of jit code. class AsmJSActivation : public Activation { AsmJSModule& module_; AsmJSActivation* prevAsmJS_; AsmJSActivation* prevAsmJSForModule_; void* entrySP_; - SPSProfiler* profiler_; void* resumePC_; uint8_t* fp_; AsmJSExit::Reason exitReason_; public: AsmJSActivation(JSContext* cx, AsmJSModule& module); ~AsmJSActivation();
--- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -3324,41 +3324,16 @@ ContainerState::ChooseAnimatedGeometryRo // should result in the least invalidation when scrolling. *aAnimatedGeometryRoot = nsLayoutUtils::GetAnimatedGeometryRootFor(item, mBuilder, mManager); return true; } return false; } -/* Checks if aPotentialScrollItem is a scroll layer item and aPotentialScrollbarItem - * is an overlay scrollbar item for the same scroll frame. - */ -static bool -IsScrollLayerItemAndOverlayScrollbarForScrollFrame( - nsDisplayItem* aPotentialScrollItem, nsDisplayItem* aPotentialScrollbarItem) -{ - if (aPotentialScrollItem->GetType() == nsDisplayItem::TYPE_SCROLL_LAYER && - aPotentialScrollbarItem && - aPotentialScrollbarItem->GetType() == nsDisplayItem::TYPE_OWN_LAYER && - LookAndFeel::GetInt(LookAndFeel::eIntID_UseOverlayScrollbars)) { - nsDisplayScrollLayer* scrollItem = - static_cast<nsDisplayScrollLayer*>(aPotentialScrollItem); - nsDisplayOwnLayer* layerItem = - static_cast<nsDisplayOwnLayer*>(aPotentialScrollbarItem); - if ((layerItem->GetFlags() & - (nsDisplayOwnLayer::VERTICAL_SCROLLBAR | - nsDisplayOwnLayer::HORIZONTAL_SCROLLBAR)) && - layerItem->Frame()->GetParent() == scrollItem->GetScrollFrame()) { - return true; - } - } - return false; -} - nsIntRegion ContainerState::ComputeOpaqueRect(nsDisplayItem* aItem, const nsIFrame* aAnimatedGeometryRoot, const nsIFrame* aFixedPosFrame, const DisplayItemClip& aClip, nsDisplayList* aList, bool* aHideAllLayersBelow, bool* aOpaqueForAnimatedGeometryRootParent) @@ -3448,52 +3423,44 @@ ContainerState::ProcessDisplayItems(nsDi // Peek ahead to the next item and try merging with it or swapping with it // if necessary. nsDisplayItem* aboveItem; while ((aboveItem = aList->GetBottom()) != nullptr) { if (aboveItem->TryMerge(mBuilder, item)) { aList->RemoveBottom(); item->~nsDisplayItem(); item = aboveItem; - } else if (IsScrollLayerItemAndOverlayScrollbarForScrollFrame(aboveItem, item)) { - // If an overlay scrollbar item is between a scroll layer item and the - // other scroll layer items that we need to merge with just move the - // scrollbar item up, that way it will be on top of the scrolled content - // and we can try to merge all the scroll layer items. - aList->RemoveBottom(); - aList->AppendToBottom(item); - item = aboveItem; } else { break; } } - nsDisplayList* itemSameCoordinateSystemChildren - = item->GetSameCoordinateSystemChildren(); - if (item->ShouldFlattenAway(mBuilder)) { - aList->AppendToBottom(itemSameCoordinateSystemChildren); - item->~nsDisplayItem(); - continue; - } - nsDisplayItem::Type itemType = item->GetType(); if (itemType == nsDisplayItem::TYPE_SCROLL_INFO_LAYER && mLayerBuilder->GetContainingContainerState()) { // We have encountered a scrollable area inside a nested (inactive) // layer manager, so we need to hoist the item out into the parent; that // way we will still generate a scrollinfo layer for it and the APZ can // drive main-thread sync scrolling. // Note: |item| is removed from aList and will be attached into the parent // list, so we don't delete it here. nsDisplayScrollInfoLayer* scrollInfoItem = static_cast<nsDisplayScrollInfoLayer*>(item); scrollInfoItem->MarkHoisted(); mLayerBuilder->GetContainingContainerState()->AddHoistedItem(scrollInfoItem); continue; } + nsDisplayList* itemSameCoordinateSystemChildren + = item->GetSameCoordinateSystemChildren(); + if (item->ShouldFlattenAway(mBuilder)) { + aList->AppendToBottom(itemSameCoordinateSystemChildren); + item->~nsDisplayItem(); + continue; + } + savedItems.AppendToTop(item); NS_ASSERTION(mAppUnitsPerDevPixel == AppUnitsPerDevPixel(item), "items in a container layer should all have the same app units per dev pixel"); if (mBuilder->NeedToForceTransparentSurfaceForItem(item)) { aList->SetNeedsTransparentSurface(); } @@ -3727,21 +3694,19 @@ ContainerState::ProcessDisplayItems(nsDi newLayerEntry->mOpaqueRegion = ComputeOpaqueRect(item, animatedGeometryRoot, fixedPosFrame, itemClip, aList, &newLayerEntry->mHideAllLayersBelow, &newLayerEntry->mOpaqueForAnimatedGeometryRootParent); } else { SetOuterVisibleRegionForLayer(ownLayer, itemVisibleRect, layerContentsVisibleRect.width >= 0 ? &layerContentsVisibleRect : nullptr); } - if (itemType == nsDisplayItem::TYPE_SCROLL_LAYER || - itemType == nsDisplayItem::TYPE_SCROLL_INFO_LAYER) { - nsDisplayScrollLayer* scrollItem = static_cast<nsDisplayScrollLayer*>(item); - newLayerEntry->mOpaqueForAnimatedGeometryRootParent = - scrollItem->IsDisplayPortOpaque(); + if (itemType == nsDisplayItem::TYPE_SCROLL_INFO_LAYER) { + nsDisplayScrollInfoLayer* scrollItem = static_cast<nsDisplayScrollInfoLayer*>(item); + newLayerEntry->mOpaqueForAnimatedGeometryRootParent = false; newLayerEntry->mBaseFrameMetrics = scrollItem->ComputeFrameMetrics(ownLayer, mParameters); } else if ((itemType == nsDisplayItem::TYPE_SUBDOCUMENT || itemType == nsDisplayItem::TYPE_ZOOM || itemType == nsDisplayItem::TYPE_RESOLUTION) && gfxPrefs::LayoutUseContainersForRootFrames()) { newLayerEntry->mBaseFrameMetrics = @@ -4445,18 +4410,17 @@ ContainerState::Finish(uint32_t* aTextCo item->ShouldFixToViewport(mManager); const nsIFrame* fixedPosFrame = FindFixedPosFrameForLayerData(animatedGeometryRoot, shouldFixToViewport); NewLayerEntry scrollInfoLayerEntry; scrollInfoLayerEntry.mLayer = scrollInfoLayer; scrollInfoLayerEntry.mAnimatedGeometryRoot = animatedGeometryRoot; scrollInfoLayerEntry.mFixedPosFrameForLayerData = fixedPosFrame; - scrollInfoLayerEntry.mOpaqueForAnimatedGeometryRootParent = - item->IsDisplayPortOpaque(); + scrollInfoLayerEntry.mOpaqueForAnimatedGeometryRootParent = false; scrollInfoLayerEntry.mBaseFrameMetrics = item->ComputeFrameMetrics(scrollInfoLayer, mParameters); SetupScrollingMetadata(&scrollInfoLayerEntry); if (!scrollInfoLayer->GetParent()) { // This is not currently a child of the container, so just add it // now. mContainerLayer->InsertAfter(scrollInfoLayer, layer);
--- a/layout/base/RestyleManager.cpp +++ b/layout/base/RestyleManager.cpp @@ -1228,20 +1228,20 @@ RestyleManager::GetMaxAnimationGeneratio { nsIContent* content = aFrame->GetContent(); if (!content || !content->IsElement()) { return 0; } nsCSSPseudoElements::Type pseudoType = aFrame->StyleContext()->GetPseudoType(); - AnimationPlayerCollection* transitions = + AnimationCollection* transitions = aFrame->PresContext()->TransitionManager()->GetAnimations( content->AsElement(), pseudoType, false /* don't create */); - AnimationPlayerCollection* animations = + AnimationCollection* animations = aFrame->PresContext()->AnimationManager()->GetAnimations( content->AsElement(), pseudoType, false /* don't create */); return std::max(transitions ? transitions->mAnimationGeneration : 0, animations ? animations->mAnimationGeneration : 0); } void
--- a/layout/base/nsDisplayItemTypesList.h +++ b/layout/base/nsDisplayItemTypesList.h @@ -40,17 +40,16 @@ DECLARE_DISPLAY_ITEM_TYPE(PAGE_CONTENT) DECLARE_DISPLAY_ITEM_TYPE(PAGE_SEQUENCE) DECLARE_DISPLAY_ITEM_TYPE(PLUGIN) DECLARE_DISPLAY_ITEM_TYPE(PLUGIN_READBACK) DECLARE_DISPLAY_ITEM_TYPE(PLUGIN_VIDEO) DECLARE_DISPLAY_ITEM_TYPE(PRINT_PLUGIN) DECLARE_DISPLAY_ITEM_TYPE(REMOTE) DECLARE_DISPLAY_ITEM_TYPE(REMOTE_SHADOW) DECLARE_DISPLAY_ITEM_TYPE(RESOLUTION) -DECLARE_DISPLAY_ITEM_TYPE(SCROLL_LAYER) DECLARE_DISPLAY_ITEM_TYPE(SCROLL_INFO_LAYER) DECLARE_DISPLAY_ITEM_TYPE(SELECTION_OVERLAY) DECLARE_DISPLAY_ITEM_TYPE(SOLID_COLOR) DECLARE_DISPLAY_ITEM_TYPE(SUBDOCUMENT) DECLARE_DISPLAY_ITEM_TYPE(SVG_EFFECTS) DECLARE_DISPLAY_ITEM_TYPE(SVG_GLYPHS) DECLARE_DISPLAY_ITEM_TYPE(SVG_OUTER_SVG) DECLARE_DISPLAY_ITEM_TYPE(SVG_PATH_GEOMETRY)
--- a/layout/base/nsDisplayList.cpp +++ b/layout/base/nsDisplayList.cpp @@ -51,17 +51,17 @@ #include "nsTransitionManager.h" #include "nsViewManager.h" #include "ImageLayers.h" #include "ImageContainer.h" #include "nsCanvasFrame.h" #include "StickyScrollContainer.h" #include "mozilla/EventStates.h" #include "mozilla/LookAndFeel.h" -#include "mozilla/PendingPlayerTracker.h" +#include "mozilla/PendingAnimationTracker.h" #include "mozilla/Preferences.h" #include "mozilla/UniquePtr.h" #include "ActiveLayerTracker.h" #include "nsContentUtils.h" #include "nsPrintfCString.h" #include "UnitTransforms.h" #include "LayersLogging.h" #include "FrameLayerBuilder.h" @@ -343,39 +343,38 @@ ToTimingFunction(const ComputedTimingFun } uint32_t type = aCTF.GetType() == nsTimingFunction::StepStart ? 1 : 2; return TimingFunction(StepFunction(aCTF.GetSteps(), type)); } static void AddAnimationForProperty(nsIFrame* aFrame, const AnimationProperty& aProperty, - AnimationPlayer* aPlayer, Layer* aLayer, + dom::Animation* aAnimation, Layer* aLayer, AnimationData& aData, bool aPending) { MOZ_ASSERT(aLayer->AsContainerLayer(), "Should only animate ContainerLayer"); - MOZ_ASSERT(aPlayer->GetEffect(), - "Should not be adding an animation for a player without" - " an effect"); + MOZ_ASSERT(aAnimation->GetEffect(), + "Should not be adding an animation without an effect"); nsStyleContext* styleContext = aFrame->StyleContext(); nsPresContext* presContext = aFrame->PresContext(); nsRect bounds = nsDisplayTransform::GetFrameBoundsForTransform(aFrame); layers::Animation* animation = aPending ? aLayer->AddAnimationForNextTransaction() : aLayer->AddAnimation(); - const AnimationTiming& timing = aPlayer->GetEffect()->Timing(); - Nullable<TimeDuration> startTime = aPlayer->GetCurrentOrPendingStartTime(); + const AnimationTiming& timing = aAnimation->GetEffect()->Timing(); + Nullable<TimeDuration> startTime = aAnimation->GetCurrentOrPendingStartTime(); animation->startTime() = startTime.IsNull() ? TimeStamp() - : aPlayer->Timeline()->ToTimeStamp( + : aAnimation->Timeline()->ToTimeStamp( startTime.Value() + timing.mDelay); - animation->initialCurrentTime() = aPlayer->GetCurrentTime().Value() + animation->initialCurrentTime() = aAnimation->GetCurrentTime().Value() - timing.mDelay; animation->duration() = timing.mIterationDuration; animation->iterationCount() = timing.mIterationCount; animation->direction() = timing.mDirection; animation->property() = aProperty.mProperty; animation->data() = aData; for (uint32_t segIdx = 0; segIdx < aProperty.mSegments.Length(); segIdx++) { @@ -402,32 +401,32 @@ AddAnimationForProperty(nsIFrame* aFrame animSegment->startPortion() = segment.mFromKey; animSegment->endPortion() = segment.mToKey; animSegment->sampleFn() = ToTimingFunction(segment.mTimingFunction); } } static void AddAnimationsForProperty(nsIFrame* aFrame, nsCSSProperty aProperty, - AnimationPlayerPtrArray& aPlayers, + AnimationPtrArray& aAnimations, Layer* aLayer, AnimationData& aData, bool aPending) { MOZ_ASSERT(nsCSSProps::PropHasFlags(aProperty, CSS_PROPERTY_CAN_ANIMATE_ON_COMPOSITOR), "inconsistent property flags"); // Add from first to last (since last overrides) - for (size_t playerIdx = 0; playerIdx < aPlayers.Length(); playerIdx++) { - AnimationPlayer* player = aPlayers[playerIdx]; - if (!player->IsPlaying()) { + for (size_t animIdx = 0; animIdx < aAnimations.Length(); animIdx++) { + dom::Animation* anim = aAnimations[animIdx]; + if (!anim->IsPlaying()) { continue; } - dom::KeyframeEffectReadonly* effect = player->GetEffect(); - MOZ_ASSERT(effect, "A playing player should have an effect"); + dom::KeyframeEffectReadonly* effect = anim->GetEffect(); + MOZ_ASSERT(effect, "A playing animation should have an effect"); const AnimationProperty* property = effect->GetAnimationOfProperty(aProperty); if (!property) { continue; } // Note that if mWinsInCascade on property was false, // GetAnimationOfProperty returns null instead. @@ -445,25 +444,25 @@ AddAnimationsForProperty(nsIFrame* aFram // refresh driver is under test control. This is because any pending // animations on layers will have their start time updated with the // current timestamp but when the refresh driver is under test control // its refresh times are unrelated to timestamp values. // // Instead we leave the animation running on the main thread and the // next time the refresh driver is advanced it will trigger any pending // animations. - if (player->PlayState() == AnimationPlayState::Pending) { - nsRefreshDriver* driver = player->Timeline()->GetRefreshDriver(); + if (anim->PlayState() == AnimationPlayState::Pending) { + nsRefreshDriver* driver = anim->Timeline()->GetRefreshDriver(); if (driver && driver->IsTestControllingRefreshesEnabled()) { continue; } } - AddAnimationForProperty(aFrame, *property, player, aLayer, aData, aPending); - player->SetIsRunningOnCompositor(); + AddAnimationForProperty(aFrame, *property, anim, aLayer, aData, aPending); + anim->SetIsRunningOnCompositor(); } } /* static */ void nsDisplayListBuilder::AddAnimationsAndTransitionsToLayer(Layer* aLayer, nsDisplayListBuilder* aBuilder, nsDisplayItem* aItem, nsIFrame* aFrame, @@ -498,19 +497,19 @@ nsDisplayListBuilder::AddAnimationsAndTr uint64_t animationGeneration = RestyleManager::GetMaxAnimationGenerationForFrame(aFrame); aLayer->SetAnimationGeneration(animationGeneration); nsIContent* content = aFrame->GetContent(); if (!content) { return; } - AnimationPlayerCollection* transitions = + AnimationCollection* transitions = nsTransitionManager::GetAnimationsForCompositor(content, aProperty); - AnimationPlayerCollection* animations = + AnimationCollection* animations = nsAnimationManager::GetAnimationsForCompositor(content, aProperty); if (!animations && !transitions) { return; } // If the frame is not prerendered, bail out. // Do this check only during layer construction; during updating the @@ -561,22 +560,22 @@ nsDisplayListBuilder::AddAnimationsAndTr aFrame->PresContext()->AppUnitsPerDevPixel()); } else if (aProperty == eCSSProperty_opacity) { data = null_t(); } // When both are running, animations override transitions. We want // to add the ones that override last. if (transitions) { - AddAnimationsForProperty(aFrame, aProperty, transitions->mPlayers, + AddAnimationsForProperty(aFrame, aProperty, transitions->mAnimations, aLayer, data, pending); } if (animations) { - AddAnimationsForProperty(aFrame, aProperty, animations->mPlayers, + AddAnimationsForProperty(aFrame, aProperty, animations->mAnimations, aLayer, data, pending); } } nsDisplayListBuilder::nsDisplayListBuilder(nsIFrame* aReferenceFrame, Mode aMode, bool aBuildCaret) : mReferenceFrame(aReferenceFrame), mIgnoreScrollFrame(nullptr), @@ -733,247 +732,16 @@ static void UnmarkFrameForDisplay(nsIFra for (nsIFrame* f = aFrame; f; f = nsLayoutUtils::GetParentOrPlaceholderFor(f)) { if (!(f->GetStateBits() & NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO)) return; f->RemoveStateBits(NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO); } } -/* static */ FrameMetrics -nsDisplayScrollLayer::ComputeFrameMetrics(nsIFrame* aForFrame, - nsIFrame* aScrollFrame, - nsIContent* aContent, - const nsIFrame* aReferenceFrame, - Layer* aLayer, - ViewID aScrollParentId, -