diff --git a/browser/base/content/test/general/audio.ogg b/browser/base/content/test/general/audio.ogg index 7e6ef77ec4..477544875d 100644 Binary files a/browser/base/content/test/general/audio.ogg and b/browser/base/content/test/general/audio.ogg differ diff --git a/docshell/shistory/src/nsSHistory.cpp b/docshell/shistory/src/nsSHistory.cpp index 7017716bfe..57ebd35877 100644 --- a/docshell/shistory/src/nsSHistory.cpp +++ b/docshell/shistory/src/nsSHistory.cpp @@ -1390,8 +1390,8 @@ nsSHistory::RemoveEntries(nsTArray& aIDs, int32_t aStartIndex) } if (didRemove && mRootDocShell) { nsCOMPtr ev = - NS_NewRunnableMethod(static_cast(mRootDocShell), - &nsDocShell::FireDummyOnLocationChange); + NewRunnableMethod(static_cast(mRootDocShell), + &nsDocShell::FireDummyOnLocationChange); NS_DispatchToCurrentThread(ev); } } diff --git a/dom/animation/Animation.cpp b/dom/animation/Animation.cpp index c4299a19f0..c24fe0c99a 100644 --- a/dom/animation/Animation.cpp +++ b/dom/animation/Animation.cpp @@ -1236,7 +1236,7 @@ Animation::DoFinishNotification(SyncNotifyFlag aSyncNotifyFlag) DoFinishNotificationImmediately(); } else if (!mFinishNotificationTask.IsPending()) { RefPtr> runnable = - NS_NewRunnableMethod(this, &Animation::DoFinishNotificationImmediately); + NewRunnableMethod(this, &Animation::DoFinishNotificationImmediately); runtime->DispatchToMicroTask(runnable); mFinishNotificationTask = runnable; } diff --git a/dom/archivereader/ArchiveEvent.cpp b/dom/archivereader/ArchiveEvent.cpp index 164a03eb2d..b1b3dcd823 100644 --- a/dom/archivereader/ArchiveEvent.cpp +++ b/dom/archivereader/ArchiveEvent.cpp @@ -86,8 +86,7 @@ ArchiveReaderEvent::RunShare(nsresult aStatus) { mStatus = aStatus; - nsCOMPtr event = NS_NewRunnableMethod(this, &ArchiveReaderEvent::ShareMainThread); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(NewRunnableMethod(this, &ArchiveReaderEvent::ShareMainThread)); return NS_OK; } diff --git a/dom/audiochannel/AudioChannelAgent.cpp b/dom/audiochannel/AudioChannelAgent.cpp index 09e3c303b3..c20006cebf 100644 --- a/dom/audiochannel/AudioChannelAgent.cpp +++ b/dom/audiochannel/AudioChannelAgent.cpp @@ -207,17 +207,12 @@ AudioChannelAgent::InitInternal(nsIDOMWindow* aWindow, int32_t aChannelType, return NS_OK; } -NS_IMETHODIMP AudioChannelAgent::NotifyStartedPlaying(float *aVolume, - bool* aMuted) +NS_IMETHODIMP +AudioChannelAgent::NotifyStartedPlaying(AudioPlaybackConfig* aConfig, + bool aAudible) { - MOZ_ASSERT(aVolume); - MOZ_ASSERT(aMuted); - - // Window-less AudioChannelAgents are muted by default. - if (!mWindow) { - *aVolume = 0; - *aMuted = true; - return NS_OK; + if (NS_WARN_IF(!aConfig)) { + return NS_ERROR_FAILURE; } RefPtr service = AudioChannelService::GetOrCreate(); @@ -226,20 +221,26 @@ NS_IMETHODIMP AudioChannelAgent::NotifyStartedPlaying(float *aVolume, return NS_ERROR_FAILURE; } + MOZ_ASSERT(AudioChannelService::AudibleState::eAudible == true && + AudioChannelService::AudibleState::eNotAudible == false); service->RegisterAudioChannelAgent(this, - static_cast(mAudioChannelType)); + static_cast(aAudible)); - service->GetState(mWindow, mAudioChannelType, aVolume, aMuted); + AudioPlaybackConfig config = service->GetMediaConfig(mWindow, + mAudioChannelType); MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug, - ("AudioChannelAgent, NotifyStartedPlaying, this = %p, mute = %d, " - "volume = %f\n", this, *aMuted, *aVolume)); + ("AudioChannelAgent, NotifyStartedPlaying, this = %p, " + "mute = %d, volume = %f, suspend = %d\n", this, + config.mMuted, config.mVolume, config.mSuspend)); + aConfig->SetConfig(config.mVolume, config.mMuted, config.mSuspend); mIsRegToService = true; return NS_OK; } -NS_IMETHODIMP AudioChannelAgent::NotifyStoppedPlaying() +NS_IMETHODIMP +AudioChannelAgent::NotifyStoppedPlaying() { if (mAudioChannelType == AUDIO_AGENT_CHANNEL_ERROR || !mIsRegToService) { @@ -258,6 +259,23 @@ NS_IMETHODIMP AudioChannelAgent::NotifyStoppedPlaying() return NS_OK; } +NS_IMETHODIMP +AudioChannelAgent::NotifyStartedAudible(bool aAudible) +{ + MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug, + ("AudioChannelAgent, NotifyStartedAudible, this = %p, " + "audible = %d\n", this, aAudible)); + + RefPtr service = AudioChannelService::GetOrCreate(); + if (NS_WARN_IF(!service)) { + return NS_ERROR_FAILURE; + } + + service->AudioAudibleChanged( + this, static_cast(aAudible)); + return NS_OK; +} + already_AddRefed AudioChannelAgent::GetCallback() { @@ -276,19 +294,49 @@ AudioChannelAgent::WindowVolumeChanged() return; } - float volume = 1.0; - bool muted = false; + AudioPlaybackConfig config = GetMediaConfig(); + MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug, + ("AudioChannelAgent, WindowVolumeChanged, this = %p, mute = %d, " + "volume = %f\n", this, config.mMuted, config.mVolume)); - RefPtr service = AudioChannelService::GetOrCreate(); - if (service) { - service->GetState(mWindow, mAudioChannelType, &volume, &muted); + callback->WindowVolumeChanged(config.mVolume, config.mMuted); +} + +void +AudioChannelAgent::WindowSuspendChanged(nsSuspendedTypes aSuspend) +{ + nsCOMPtr callback = GetCallback(); + if (!callback) { + return; + } + + if (!IsDisposableSuspend(aSuspend)) { + aSuspend = GetMediaConfig().mSuspend; } MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug, - ("AudioChannelAgent, WindowVolumeChanged, this = %p, mute = %d, " - "volume = %f\n", this, muted, volume)); + ("AudioChannelAgent, WindowSuspendChanged, this = %p, " + "suspended = %d\n", this, aSuspend)); - callback->WindowVolumeChanged(volume, muted); + callback->WindowSuspendChanged(aSuspend); +} + +AudioPlaybackConfig +AudioChannelAgent::GetMediaConfig() +{ + RefPtr service = AudioChannelService::GetOrCreate(); + AudioPlaybackConfig config(1.0, false, nsISuspendedTypes::NONE_SUSPENDED); + if (service) { + config = service->GetMediaConfig(mWindow, mAudioChannelType); + } + return config; +} + +bool +AudioChannelAgent::IsDisposableSuspend(nsSuspendedTypes aSuspend) const +{ + return (aSuspend == nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE || + aSuspend == nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE); } uint64_t diff --git a/dom/audiochannel/AudioChannelAgent.h b/dom/audiochannel/AudioChannelAgent.h index e50fafb33a..43d289cbd7 100644 --- a/dom/audiochannel/AudioChannelAgent.h +++ b/dom/audiochannel/AudioChannelAgent.h @@ -22,6 +22,8 @@ class nsPIDOMWindow; namespace mozilla { namespace dom { +class AudioPlaybackConfig; + /* Header file */ class AudioChannelAgent : public nsIAudioChannelAgent { @@ -34,6 +36,7 @@ public: AudioChannelAgent(); void WindowVolumeChanged(); + void WindowSuspendChanged(nsSuspendedTypes aSuspend); void WindowAudioCaptureChanged(uint64_t aInnerWindowID, bool aCapture); nsPIDOMWindow* Window() const @@ -47,6 +50,9 @@ public: private: virtual ~AudioChannelAgent(); + AudioPlaybackConfig GetMediaConfig(); + bool IsDisposableSuspend(nsSuspendedTypes aSuspend) const; + // Returns mCallback if that's non-null, or otherwise tries to get an // nsIAudioChannelAgentCallback out of mWeakCallback. already_AddRefed GetCallback(); diff --git a/dom/audiochannel/AudioChannelService.cpp b/dom/audiochannel/AudioChannelService.cpp index 16dfa6a7f2..05946ba1c8 100644 --- a/dom/audiochannel/AudioChannelService.cpp +++ b/dom/audiochannel/AudioChannelService.cpp @@ -94,15 +94,6 @@ private: const bool mActive; }; -void -NotifyChannelActive(uint64_t aWindowID, AudioChannel aAudioChannel, - bool aActive) -{ - RefPtr runnable = - new NotifyChannelActiveRunnable(aWindowID, aAudioChannel, aActive); - NS_DispatchToCurrentThread(runnable); -} - already_AddRefed GetTopWindow(nsPIDOMWindow* aWindow) { @@ -122,10 +113,10 @@ IsParentProcess() return XRE_GetProcessType() == GeckoProcessType_Default; } -class MediaPlaybackRunnable : public Runnable +class AudioPlaybackRunnable final : public Runnable { public: - MediaPlaybackRunnable(nsIDOMWindow* aWindow, bool aActive) + AudioPlaybackRunnable(nsPIDOMWindow* aWindow, bool aActive) : mWindow(aWindow) , mActive(aActive) {} @@ -134,14 +125,17 @@ public: { nsCOMPtr observerService = services::GetObserverService(); - if (observerService) { - observerService->NotifyObservers( - ToSupports(mWindow), - "media-playback", - mActive ? MOZ_UTF16("active") - : MOZ_UTF16("inactive")); + if (NS_WARN_IF(!observerService)) { + return NS_ERROR_FAILURE; } + observerService->NotifyObservers(ToSupports(mWindow), + "audio-playback", + mActive ? MOZ_UTF16("active") + : MOZ_UTF16("inactive")); + + MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug, + ("AudioPlaybackRunnable, active = %d\n", mActive)); return NS_OK; } @@ -268,8 +262,10 @@ AudioChannelService::~AudioChannelService() void AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent, - AudioChannel aChannel) + AudibleState aAudible) { + MOZ_ASSERT(aAgent); + uint64_t windowID = aAgent->WindowID(); AudioChannelWindow* winData = GetWindowData(windowID); if (!winData) { @@ -277,29 +273,11 @@ AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent, mWindows.AppendElement(winData); } - MOZ_ASSERT(!winData->mAgents.Contains(aAgent)); - winData->mAgents.AppendElement(aAgent); - - ++winData->mChannels[(uint32_t)aChannel].mNumberOfAgents; - - // The first one, we must inform the BrowserElementAudioChannel. - if (winData->mChannels[(uint32_t)aChannel].mNumberOfAgents == 1) { - NotifyChannelActive(aAgent->WindowID(), aChannel, true); - } - - // If this is the first agent for this window, we must notify the observers. - if (winData->mAgents.Length() == 1) { - RefPtr runnable = - new MediaPlaybackRunnable(aAgent->Window(), true /* active */); - NS_DispatchToCurrentThread(runnable); - } - - // If the window has already been captured, the agent of that window should - // also be captured. - if (winData->mIsAudioCaptured) { - aAgent->WindowAudioCaptureChanged(aAgent->InnerWindowID(), - winData->mIsAudioCaptured); - } + // To make sure agent would be alive because AppendAgent() would trigger the + // callback function of AudioChannelAgentOwner that means the agent might be + // released in their callback. + RefPtr kungFuDeathGrip(aAgent); + winData->AppendAgent(aAgent, aAudible); MaybeSendStatusUpdate(); } @@ -307,27 +285,18 @@ AudioChannelService::RegisterAudioChannelAgent(AudioChannelAgent* aAgent, void AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent) { + MOZ_ASSERT(aAgent); + AudioChannelWindow* winData = GetWindowData(aAgent->WindowID()); if (!winData) { return; } - if (winData->mAgents.Contains(aAgent)) { - int32_t channel = aAgent->AudioChannelType(); - uint64_t windowID = aAgent->WindowID(); - - // aAgent can be freed after this call. - winData->mAgents.RemoveElement(aAgent); - - MOZ_ASSERT(winData->mChannels[channel].mNumberOfAgents > 0); - - --winData->mChannels[channel].mNumberOfAgents; - - // The last one, we must inform the BrowserElementAudioChannel. - if (winData->mChannels[channel].mNumberOfAgents == 0) { - NotifyChannelActive(windowID, static_cast(channel), false); - } - } + // To make sure agent would be alive because AppendAgent() would trigger the + // callback function of AudioChannelAgentOwner that means the agent might be + // released in their callback. + RefPtr kungFuDeathGrip(aAgent); + winData->RemoveAgent(aAgent); #ifdef MOZ_WIDGET_GONK bool active = AnyAudioChannelIsActive(); @@ -336,18 +305,6 @@ AudioChannelService::UnregisterAudioChannelAgent(AudioChannelAgent* aAgent) } #endif - // If this is the last agent for this window, we must notify the observers. - if (winData->mAgents.IsEmpty()) { - RefPtr runnable = - new MediaPlaybackRunnable(aAgent->Window(), false /* active */); - NS_DispatchToCurrentThread(runnable); - } - - // No need to capture non-audible object. - if (winData->mIsAudioCaptured) { - aAgent->WindowAudioCaptureChanged(aAgent->InnerWindowID(), false); - } - MaybeSendStatusUpdate(); } @@ -366,24 +323,22 @@ AudioChannelService::UnregisterTabParent(TabParent* aTabParent) mTabParents.RemoveElement(aTabParent); } -void -AudioChannelService::GetState(nsPIDOMWindow* aWindow, uint32_t aAudioChannel, - float* aVolume, bool* aMuted) +AudioPlaybackConfig +AudioChannelService::GetMediaConfig(nsPIDOMWindow* aWindow, + uint32_t aAudioChannel) const { MOZ_ASSERT(!aWindow || aWindow->IsOuterWindow()); - MOZ_ASSERT(aVolume && aMuted); MOZ_ASSERT(aAudioChannel < NUMBER_OF_AUDIO_CHANNELS); + AudioPlaybackConfig config(1.0, false, + nsISuspendedTypes::NONE_SUSPENDED); if (!aWindow || !aWindow->IsOuterWindow()) { - *aVolume = 0.0; - *aMuted = true; - return; + config.SetConfig(0.0, true, + nsISuspendedTypes::SUSPENDED_BLOCK); + return config; } - *aVolume = 1.0; - *aMuted = false; - AudioChannelWindow* winData = nullptr; nsCOMPtr window = aWindow; @@ -392,13 +347,16 @@ AudioChannelService::GetState(nsPIDOMWindow* aWindow, uint32_t aAudioChannel, do { winData = GetWindowData(window->WindowID()); if (winData) { - *aVolume *= winData->mChannels[aAudioChannel].mVolume; - *aMuted = *aMuted || winData->mChannels[aAudioChannel].mMuted; + config.mVolume *= winData->mChannels[aAudioChannel].mVolume; + config.mMuted = config.mMuted || winData->mChannels[aAudioChannel].mMuted; } - *aVolume *= window->GetAudioVolume(); - // TODO : distiguish between suspend and mute, it would be done in bug1242874. - *aMuted = *aMuted || window->GetMediaSuspended() || window->GetAudioMuted(); + config.mVolume *= window->GetAudioVolume(); + config.mMuted = config.mMuted || window->GetAudioMuted(); + + // If the mSuspend is already suspended, we don't need to set it again. + config.mSuspend = (config.mSuspend == nsISuspendedTypes::NONE_SUSPENDED) ? + window->GetMediaSuspend() : config.mSuspend; nsCOMPtr win = window->GetScriptableParentOrNull(); if (!win) { @@ -409,6 +367,21 @@ AudioChannelService::GetState(nsPIDOMWindow* aWindow, uint32_t aAudioChannel, // If there is no parent, or we are the toplevel we don't continue. } while (window && window != aWindow); + + return config; +} + +void +AudioChannelService::AudioAudibleChanged(AudioChannelAgent* aAgent, + AudibleState aAudible) +{ + MOZ_ASSERT(aAgent); + + uint64_t windowID = aAgent->WindowID(); + AudioChannelWindow* winData = GetWindowData(windowID); + if (winData) { + winData->AudioAudibleChanged(aAgent, aAudible); + } } bool @@ -613,7 +586,8 @@ AudioChannelService::RefreshAgentsVolumeAndPropagate(AudioChannel aAudioChannel, } void -AudioChannelService::RefreshAgentsVolume(nsPIDOMWindow* aWindow) +AudioChannelService::RefreshAgents(nsPIDOMWindow* aWindow, + mozilla::function aFunc) { MOZ_ASSERT(aWindow); MOZ_ASSERT(aWindow->IsOuterWindow()); @@ -631,10 +605,27 @@ AudioChannelService::RefreshAgentsVolume(nsPIDOMWindow* aWindow) nsTObserverArray::ForwardIterator iter(winData->mAgents); while (iter.HasMore()) { - iter.GetNext()->WindowVolumeChanged(); + aFunc(iter.GetNext()); } } +void +AudioChannelService::RefreshAgentsVolume(nsPIDOMWindow* aWindow) +{ + RefreshAgents(aWindow, [] (AudioChannelAgent* agent) { + agent->WindowVolumeChanged(); + }); +} + +void +AudioChannelService::RefreshAgentsSuspend(nsPIDOMWindow* aWindow, + nsSuspendedTypes aSuspend) +{ + RefreshAgents(aWindow, [aSuspend] (AudioChannelAgent* agent) { + agent->WindowSuspendChanged(aSuspend); + }); +} + void AudioChannelService::SetWindowAudioCaptured(nsPIDOMWindow* aWindow, uint64_t aInnerWindowID, @@ -1032,3 +1023,146 @@ AudioChannelService::IsAudioChannelMutedByDefault() CreateServiceIfNeeded(); return sAudioChannelMutedByDefault; } + +void +AudioChannelService::AudioChannelWindow::AppendAgent(AudioChannelAgent* aAgent, + AudibleState aAudible) +{ + MOZ_ASSERT(aAgent); + + AppendAgentAndIncreaseAgentsNum(aAgent); + AudioCapturedChanged(aAgent, AudioCaptureState::eCapturing); + AudioAudibleChanged(aAgent, aAudible); +} + +void +AudioChannelService::AudioChannelWindow::RemoveAgent(AudioChannelAgent* aAgent) +{ + MOZ_ASSERT(aAgent); + + RemoveAgentAndReduceAgentsNum(aAgent); + AudioCapturedChanged(aAgent, AudioCaptureState::eNotCapturing); + AudioAudibleChanged(aAgent, AudibleState::eNotAudible); +} + +void +AudioChannelService::AudioChannelWindow::AppendAgentAndIncreaseAgentsNum(AudioChannelAgent* aAgent) +{ + MOZ_ASSERT(aAgent); + MOZ_ASSERT(!mAgents.Contains(aAgent)); + + int32_t channel = aAgent->AudioChannelType(); + mAgents.AppendElement(aAgent); + + ++mChannels[channel].mNumberOfAgents; + + // The first one, we must inform the BrowserElementAudioChannel. + if (mChannels[channel].mNumberOfAgents == 1) { + NotifyChannelActive(aAgent->WindowID(), + static_cast(channel), + true); + } +} + +void +AudioChannelService::AudioChannelWindow::RemoveAgentAndReduceAgentsNum(AudioChannelAgent* aAgent) +{ + MOZ_ASSERT(aAgent); + MOZ_ASSERT(mAgents.Contains(aAgent)); + + int32_t channel = aAgent->AudioChannelType(); + mAgents.RemoveElement(aAgent); + + MOZ_ASSERT(mChannels[channel].mNumberOfAgents > 0); + --mChannels[channel].mNumberOfAgents; + + if (mChannels[channel].mNumberOfAgents == 0) { + NotifyChannelActive(aAgent->WindowID(), + static_cast(channel), + false); + } +} + +void +AudioChannelService::AudioChannelWindow::AudioCapturedChanged(AudioChannelAgent* aAgent, + AudioCaptureState aCapture) +{ + MOZ_ASSERT(aAgent); + + if (mIsAudioCaptured) { + aAgent->WindowAudioCaptureChanged(aAgent->InnerWindowID(), aCapture); + } +} + +void +AudioChannelService::AudioChannelWindow::AudioAudibleChanged(AudioChannelAgent* aAgent, + AudibleState aAudible) +{ + MOZ_ASSERT(aAgent); + + if (aAudible) { + AppendAudibleAgentIfNotContained(aAgent); + } else { + RemoveAudibleAgentIfContained(aAgent); + } +} + +void +AudioChannelService::AudioChannelWindow::AppendAudibleAgentIfNotContained(AudioChannelAgent* aAgent) +{ + MOZ_ASSERT(aAgent); + MOZ_ASSERT(mAgents.Contains(aAgent)); + + if (!mAudibleAgents.Contains(aAgent)) { + mAudibleAgents.AppendElement(aAgent); + if (IsFirstAudibleAgent()) { + NotifyAudioAudibleChanged(aAgent->Window(), AudibleState::eAudible); + } + } +} + +void +AudioChannelService::AudioChannelWindow::RemoveAudibleAgentIfContained(AudioChannelAgent* aAgent) +{ + MOZ_ASSERT(aAgent); + + if (mAudibleAgents.Contains(aAgent)) { + mAudibleAgents.RemoveElement(aAgent); + if (IsLastAudibleAgent()) { + NotifyAudioAudibleChanged(aAgent->Window(), AudibleState::eNotAudible); + } + } +} + +bool +AudioChannelService::AudioChannelWindow::IsFirstAudibleAgent() const +{ + return (mAudibleAgents.Length() == 1); +} + +bool +AudioChannelService::AudioChannelWindow::IsLastAudibleAgent() const +{ + return mAudibleAgents.IsEmpty(); +} + +void +AudioChannelService::AudioChannelWindow::NotifyAudioAudibleChanged(nsPIDOMWindow* aWindow, + AudibleState aAudible) +{ + RefPtr runnable = + new AudioPlaybackRunnable(aWindow, aAudible); + nsresult rv = NS_DispatchToCurrentThread(runnable); + NS_WARN_IF(NS_FAILED(rv)); +} + +void +AudioChannelService::AudioChannelWindow::NotifyChannelActive(uint64_t aWindowID, + AudioChannel aChannel, + bool aActive) +{ + RefPtr runnable = + new NotifyChannelActiveRunnable(aWindowID, aChannel, aActive); + nsresult rv = NS_DispatchToCurrentThread(runnable); + NS_WARN_IF(NS_FAILED(rv)); +} diff --git a/dom/audiochannel/AudioChannelService.h b/dom/audiochannel/AudioChannelService.h index b3f6485162..10f03080e6 100644 --- a/dom/audiochannel/AudioChannelService.h +++ b/dom/audiochannel/AudioChannelService.h @@ -16,6 +16,7 @@ #include "AudioChannelAgent.h" #include "nsAttrValue.h" #include "mozilla/dom/AudioChannelBinding.h" +#include "mozilla/Function.h" class nsIRunnable; class nsPIDOMWindow; @@ -32,6 +33,33 @@ class TabParent; #define NUMBER_OF_AUDIO_CHANNELS (uint32_t)AudioChannel::EndGuard_ +class AudioPlaybackConfig +{ +public: + AudioPlaybackConfig() + : mVolume(1.0) + , mMuted(false) + , mSuspend(nsISuspendedTypes::NONE_SUSPENDED) + {} + + AudioPlaybackConfig(float aVolume, bool aMuted, uint32_t aSuspended) + : mVolume(aVolume) + , mMuted(aMuted) + , mSuspend(aSuspended) + {} + + void SetConfig(float aVolume, bool aMuted, uint32_t aSuspended) + { + mVolume = aVolume; + mMuted = aMuted; + mSuspend = aSuspended; + } + + float mVolume; + bool mMuted; + uint32_t mSuspend; +}; + class AudioChannelService final : public nsIAudioChannelService , public nsIObserver { @@ -40,6 +68,16 @@ public: NS_DECL_NSIOBSERVER NS_DECL_NSIAUDIOCHANNELSERVICE + enum AudibleState : bool { + eAudible = true, + eNotAudible = false + }; + + enum AudioCaptureState : bool { + eCapturing = true, + eNotCapturing = false + }; + /** * Returns the AudioChannelServce singleton. * If AudioChannelServce is not exist, create and return new one. @@ -56,7 +94,7 @@ public: * this service, sharing the AudioChannel. */ void RegisterAudioChannelAgent(AudioChannelAgent* aAgent, - AudioChannel aChannel); + AudibleState aAudible); /** * Any audio channel agent that stops playing should unregister itself to @@ -72,10 +110,17 @@ public: /** * Return the state to indicate this audioChannel for his window should keep - * playing/muted. + * playing/muted/suspended. */ - void GetState(nsPIDOMWindow* aWindow, uint32_t aChannel, - float* aVolume, bool* aMuted); + AudioPlaybackConfig GetMediaConfig(nsPIDOMWindow* aWindow, + uint32_t aAudioChannel) const; + + /** + * Called this method when the audible state of the audio playback changed, + * it would dispatch the playback event to observers which want to know the + * actual audible state of the window. + */ + void AudioAudibleChanged(AudioChannelAgent* aAgent, AudibleState aAudible); /* Methods for the BrowserElementAudioChannel */ float GetAudioChannelVolume(nsPIDOMWindow* aWindow, AudioChannel aChannel); @@ -114,6 +159,8 @@ public: bool AnyAudioChannelIsActive(); void RefreshAgentsVolume(nsPIDOMWindow* aWindow); + void RefreshAgentsSuspend(nsPIDOMWindow* aWindow, + nsSuspendedTypes aSuspend); void RefreshAgentsVolumeAndPropagate(AudioChannel aAudioChannel, nsPIDOMWindow* aWindow); @@ -156,6 +203,9 @@ private: AudioChannelService(); ~AudioChannelService(); + void RefreshAgents(nsPIDOMWindow* aWindow, + mozilla::function aFunc); + static void CreateServiceIfNeeded(); /** @@ -171,22 +221,21 @@ private: void SetDefaultVolumeControlChannelInternal(int32_t aChannel, bool aVisible, uint64_t aChildID); - struct AudioChannelConfig final + class AudioChannelConfig final : public AudioPlaybackConfig { + public: AudioChannelConfig() - : mVolume(1.0) - , mMuted(IsAudioChannelMutedByDefault()) + : AudioPlaybackConfig(1.0, IsAudioChannelMutedByDefault(), + nsISuspendedTypes::NONE_SUSPENDED) , mNumberOfAgents(0) {} - float mVolume; - bool mMuted; - uint32_t mNumberOfAgents; }; - struct AudioChannelWindow final + class AudioChannelWindow final { + public: explicit AudioChannelWindow(uint64_t aWindowID) : mWindowID(aWindowID), mIsAudioCaptured(false) @@ -195,12 +244,36 @@ private: mChannels[(int16_t)AudioChannel::System].mMuted = false; } + void AudioAudibleChanged(AudioChannelAgent* aAgent, AudibleState aAudible); + + void AppendAgent(AudioChannelAgent* aAgent, AudibleState aAudible); + void RemoveAgent(AudioChannelAgent* aAgent); + uint64_t mWindowID; bool mIsAudioCaptured; AudioChannelConfig mChannels[NUMBER_OF_AUDIO_CHANNELS]; // Raw pointer because the AudioChannelAgent must unregister itself. nsTObserverArray mAgents; + nsTObserverArray mAudibleAgents; + + private: + void AudioCapturedChanged(AudioChannelAgent* aAgent, + AudioCaptureState aCapture); + + void AppendAudibleAgentIfNotContained(AudioChannelAgent* aAgent); + void RemoveAudibleAgentIfContained(AudioChannelAgent* aAgent); + + void AppendAgentAndIncreaseAgentsNum(AudioChannelAgent* aAgent); + void RemoveAgentAndReduceAgentsNum(AudioChannelAgent* aAgent); + + bool IsFirstAudibleAgent() const; + bool IsLastAudibleAgent() const; + + void NotifyAudioAudibleChanged(nsPIDOMWindow* aWindow, + AudibleState aAudible); + void NotifyChannelActive(uint64_t aWindowID, AudioChannel aChannel, + bool aActive); }; AudioChannelWindow* diff --git a/dom/audiochannel/nsIAudioChannelAgent.idl b/dom/audiochannel/nsIAudioChannelAgent.idl index cad9d96ca4..1767bfc282 100644 --- a/dom/audiochannel/nsIAudioChannelAgent.idl +++ b/dom/audiochannel/nsIAudioChannelAgent.idl @@ -6,6 +6,65 @@ interface nsIDOMWindow; +typedef uint32_t nsSuspendedTypes; + +[scriptable, builtinclass, uuid(2822a840-f009-11e5-a837-0800200c9a66)] +interface nsISuspendedTypes : nsISupports +{ + /** + * The suspended enum is used in three different situations, + * - platform audio focus (Fennec/B2G) + * - remote media control (Fennec) + * - block auto-play video in non-active page + * + * Note: the "remote side" must control the AudioChannelAgent using + * nsIAudioChannelAgentCallback.windowSuspendChanged() callback instead using + * play/pause methods or any button in the webpage. + * + * - SUSPENDED_PAUSE : + * It's used when transiently losing audio focus, the media can't be resumed + * until we gain the audio focus again. It would change the internal state of + * MediaElement when it's being suspended/resumed, and it would trigger the + * related JS event. eg. "play" and "pause" event. + * + * - SUSPENDED_BLOCK + * It's used to prevent auto-playing media in inactive page in order to + * reduce the power consumption, and the media can't be resumed until the + * page becomes active again. It would change the internal state of + * MediaElement when it's being blocked/resumed, so it won't trigger the + * related JS event. eg. "play" and "pause" event. + * + * - SUSPENDED_PAUSE_DISPOSABLE + * It's used for remote media-control to pause the playing media and when we + * lose audio focus permanently. It's disposable suspended, so the media can + * be resumed arbitrary after that. Same as SUSPENDED_PAUSE, it would change + * the internal state of MediaElement when it's being suspended. + * + * - SUSPENDED_STOP_DISPOSABLE + * It's used for remote media-control to stop the playing media. The remote + * control would disappear after stopping the media, so we would disconnect + * the audio channel agent. It's disposable suspended, so the media can be + * resumed arbitrary after that. Same as SUSPENDED_PAUSE, it would change + * the internal state of MediaElement when it's being suspended. + */ + + const uint32_t NONE_SUSPENDED = 0; + const uint32_t SUSPENDED_PAUSE = 1; + const uint32_t SUSPENDED_BLOCK = 2; + const uint32_t SUSPENDED_PAUSE_DISPOSABLE = 3; + const uint32_t SUSPENDED_STOP_DISPOSABLE = 4; +}; + +%{C++ +namespace mozilla { +namespace dom { +// It's defined in dom/audiochannel/AudioChannelService.h. +class AudioPlaybackConfig; +} +} +%} +[ptr] native AudioPlaybackConfig(mozilla::dom::AudioPlaybackConfig); + [uuid(0a451ee0-972e-11e5-a837-0800200c9a66)] interface nsIAudioChannelAgentCallback : nsISupports { @@ -14,6 +73,11 @@ interface nsIAudioChannelAgentCallback : nsISupports */ void windowVolumeChanged(in float aVolume, in bool aMuted); + /** + * Notified when the window needs to be suspended or resumed. + */ + void windowSuspendChanged(in uint32_t aSuspend); + /** * Notified when the capture state is changed. */ @@ -25,10 +89,8 @@ interface nsIAudioChannelAgentCallback : nsISupports * in the audio channel service. Gecko components are responsible for * 1. Indicating what channel type they are using (via the init() member * function). - * 2. Before playing, checking the playable status of the channel. - * 3. Notifying the agent when they start/stop using this channel. - * 4. Notifying the agent of changes to the visibility of the component using - * this channel. + * 2. Notifying the agent when they start/stop using this channel. + * 3. Notifying the agent when they are audible. * * The agent will invoke a callback to notify Gecko components of * 1. Changes to the playable status of this channel. @@ -98,15 +160,10 @@ interface nsIAudioChannelAgent : nsISupports * Note: Gecko component SHOULD call this function first then start to * play audio stream only when return value is true. * - * @return - * normal state: the agent has registered with audio channel service and - * the component should start playback. - * muted state: the agent has registered with audio channel service but - * the component should not start playback. - * faded state: the agent has registered with audio channel service the - * component should start playback as well as reducing the volume. + * @param config + * It contains the playback related states (volume/mute/suspend) */ - void notifyStartedPlaying(out float volume, out bool muted); + void notifyStartedPlaying(in AudioPlaybackConfig config, in bool audible); /** * Notify the agent we no longer want to play. @@ -117,4 +174,14 @@ interface nsIAudioChannelAgent : nsISupports * called to unregister the agent with the channel service. */ void notifyStoppedPlaying(); + + + /** + * Notify agent that we already start producing audible data. + * + * Note : sometime audio might become silent during playing, this method is used to + * notify the actually audible state to other services which want to know + * about that, ex. tab sound indicator. + */ + void notifyStartedAudible(in bool audible); }; diff --git a/dom/base/Element.cpp b/dom/base/Element.cpp index 49c647ba69..6c9caf33ba 100644 --- a/dom/base/Element.cpp +++ b/dom/base/Element.cpp @@ -523,7 +523,7 @@ Element::WrapObject(JSContext *aCx, JS::Handle aGivenProto) } else { nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler)); + NewRunnableMethod(binding, &nsXBLBinding::ExecuteAttachedHandler)); } } } diff --git a/dom/base/EventSource.cpp b/dom/base/EventSource.cpp index c43b538e77..4688f6a114 100644 --- a/dom/base/EventSource.cpp +++ b/dom/base/EventSource.cpp @@ -363,11 +363,7 @@ EventSource::OnStartRequest(nsIRequest *aRequest, return NS_ERROR_ABORT; } - nsCOMPtr event = - NS_NewRunnableMethod(this, &EventSource::AnnounceConnection); - NS_ENSURE_STATE(event); - - rv = NS_DispatchToMainThread(event); + rv = NS_DispatchToMainThread(NewRunnableMethod(this, &EventSource::AnnounceConnection)); NS_ENSURE_SUCCESS(rv, rv); mStatus = PARSE_STATE_BEGIN_OF_STREAM; @@ -473,11 +469,7 @@ EventSource::OnStopRequest(nsIRequest *aRequest, ClearFields(); - nsCOMPtr event = - NS_NewRunnableMethod(this, &EventSource::ReestablishConnection); - NS_ENSURE_STATE(event); - - rv = NS_DispatchToMainThread(event); + rv = NS_DispatchToMainThread(NewRunnableMethod(this, &EventSource::ReestablishConnection)); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; @@ -899,11 +891,8 @@ EventSource::ConsoleError() nsresult EventSource::DispatchFailConnection() { - nsCOMPtr event = - NS_NewRunnableMethod(this, &EventSource::FailConnection); - NS_ENSURE_STATE(event); - return NS_DispatchToMainThread(event); + return NS_DispatchToMainThread(NewRunnableMethod(this, &EventSource::FailConnection)); } void @@ -977,7 +966,7 @@ EventSource::Thaw() nsresult rv; if (!mGoingToDispatchAllMessages && mMessagesToDispatch.GetSize() > 0) { nsCOMPtr event = - NS_NewRunnableMethod(this, &EventSource::DispatchAllMessageEvents); + NewRunnableMethod(this, &EventSource::DispatchAllMessageEvents); NS_ENSURE_STATE(event); mGoingToDispatchAllMessages = true; @@ -1037,7 +1026,7 @@ EventSource::DispatchCurrentMessageEvent() if (!mGoingToDispatchAllMessages) { nsCOMPtr event = - NS_NewRunnableMethod(this, &EventSource::DispatchAllMessageEvents); + NewRunnableMethod(this, &EventSource::DispatchAllMessageEvents); NS_ENSURE_STATE(event); mGoingToDispatchAllMessages = true; diff --git a/dom/base/ScreenOrientation.cpp b/dom/base/ScreenOrientation.cpp index e3fb76c15e..93c838206a 100644 --- a/dom/base/ScreenOrientation.cpp +++ b/dom/base/ScreenOrientation.cpp @@ -540,7 +540,7 @@ ScreenOrientation::Notify(const hal::ScreenConfiguration& aConfiguration) doc->SetOrientationPendingPromise(nullptr); } - nsCOMPtr runnable = NS_NewRunnableMethod(this, + nsCOMPtr runnable = NewRunnableMethod(this, &ScreenOrientation::DispatchChangeEvent); rv = NS_DispatchToMainThread(runnable); NS_WARN_IF(NS_FAILED(rv)); @@ -615,7 +615,7 @@ ScreenOrientation::VisibleEventListener::HandleEvent(nsIDOMEvent* aEvent) doc->SetOrientationPendingPromise(nullptr); } - nsCOMPtr runnable = NS_NewRunnableMethod(orientation, + nsCOMPtr runnable = NewRunnableMethod(orientation, &ScreenOrientation::DispatchChangeEvent); rv = NS_DispatchToMainThread(runnable); if (NS_WARN_IF(rv.Failed())) { diff --git a/dom/base/WindowNamedPropertiesHandler.cpp b/dom/base/WindowNamedPropertiesHandler.cpp index 2ebf18df6f..0a910746a1 100644 --- a/dom/base/WindowNamedPropertiesHandler.cpp +++ b/dom/base/WindowNamedPropertiesHandler.cpp @@ -218,7 +218,9 @@ WindowNamedPropertiesHandler::ownPropNames(JSContext* aCx, return true; } nsHTMLDocument* document = static_cast(htmlDoc.get()); - document->GetSupportedNames(flags, names); + // Document names are enumerable, so we want to get them no matter what flags + // is. + document->GetSupportedNames(names); JS::AutoIdVector docProps(aCx); if (!AppendNamedPropertyIds(aCx, aProxy, names, false, docProps)) { diff --git a/dom/base/WindowNamedPropertiesHandler.h b/dom/base/WindowNamedPropertiesHandler.h index 628a27b608..11de900d40 100644 --- a/dom/base/WindowNamedPropertiesHandler.h +++ b/dom/base/WindowNamedPropertiesHandler.h @@ -37,9 +37,9 @@ public: delete_(JSContext* aCx, JS::Handle aProxy, JS::Handle aId, JS::ObjectOpResult &aResult) const override; - // No need for getPrototypeIfOrdinary here: this object shouldn't have a - // lazy prototype, so this trap would never be called (and the inherited - // version, from BaseProxyHandler, just crashes). + // No need for getPrototypeIfOrdinary here: window named-properties objects + // have static prototypes, so the version inherited from BaseDOMProxyHandler + // will do the right thing. virtual bool preventExtensions(JSContext* aCx, JS::Handle aProxy, diff --git a/dom/base/nsContentList.cpp b/dom/base/nsContentList.cpp index 3dea767ca8..c768fadf12 100644 --- a/dom/base/nsContentList.cpp +++ b/dom/base/nsContentList.cpp @@ -538,12 +538,8 @@ nsContentList::NamedItem(const nsAString& aName, bool aDoFlush) } void -nsContentList::GetSupportedNames(unsigned aFlags, nsTArray& aNames) +nsContentList::GetSupportedNames(nsTArray& aNames) { - if (!(aFlags & JSITER_HIDDEN)) { - return; - } - BringSelfUpToDate(true); AutoTArray atoms; diff --git a/dom/base/nsContentList.h b/dom/base/nsContentList.h index 7a34700b5d..c9b671ab82 100644 --- a/dom/base/nsContentList.h +++ b/dom/base/nsContentList.h @@ -294,8 +294,7 @@ public: aFound = !!item; return item; } - virtual void GetSupportedNames(unsigned aFlags, - nsTArray& aNames) override; + virtual void GetSupportedNames(nsTArray& aNames) override; // nsContentList public methods uint32_t Length(bool aDoFlush); diff --git a/dom/base/nsContentSink.cpp b/dom/base/nsContentSink.cpp index bc235fd64f..4ff53159ce 100644 --- a/dom/base/nsContentSink.cpp +++ b/dom/base/nsContentSink.cpp @@ -271,7 +271,7 @@ nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel) "Already dispatched an event?"); mProcessLinkHeaderEvent = - NS_NewNonOwningRunnableMethod(this, + NewNonOwningRunnableMethod(this, &nsContentSink::DoProcessLinkHeader); rv = NS_DispatchToCurrentThread(mProcessLinkHeaderEvent.get()); if (NS_FAILED(rv)) { diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index bea4366b9e..41874d3dc2 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -5035,22 +5035,29 @@ nsContentUtils::WarnScriptWasIgnored(nsIDocument* aDocument) /* static */ bool -nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable) +nsContentUtils::AddScriptRunner(already_AddRefed aRunnable) { - if (!aRunnable) { + nsCOMPtr runnable = aRunnable; + if (!runnable) { return false; } if (sScriptBlockerCount) { - return sBlockedScriptRunners->AppendElement(aRunnable) != nullptr; + return sBlockedScriptRunners->AppendElement(runnable.forget()) != nullptr; } - nsCOMPtr run = aRunnable; - run->Run(); + runnable->Run(); return true; } +/* static */ +bool +nsContentUtils::AddScriptRunner(nsIRunnable* aRunnable) { + nsCOMPtr runnable = aRunnable; + return AddScriptRunner(runnable.forget()); +} + /* static */ void nsContentUtils::RunInStableState(already_AddRefed aRunnable) diff --git a/dom/base/nsContentUtils.h b/dom/base/nsContentUtils.h index bda2c2d109..409200a303 100644 --- a/dom/base/nsContentUtils.h +++ b/dom/base/nsContentUtils.h @@ -1592,6 +1592,7 @@ public: * has not yet been AddRefed. * @return false on out of memory, true otherwise. */ + static bool AddScriptRunner(already_AddRefed aRunnable); static bool AddScriptRunner(nsIRunnable* aRunnable); /** diff --git a/dom/base/nsDOMAttributeMap.cpp b/dom/base/nsDOMAttributeMap.cpp index 948603c7ff..fe7de268ba 100644 --- a/dom/base/nsDOMAttributeMap.cpp +++ b/dom/base/nsDOMAttributeMap.cpp @@ -163,20 +163,9 @@ nsDOMAttributeMap::NamedGetter(const nsAString& aAttrName, bool& aFound) return GetAttribute(ni); } -bool -nsDOMAttributeMap::NameIsEnumerable(const nsAString& aName) -{ - return false; -} - void -nsDOMAttributeMap::GetSupportedNames(unsigned aFlags, - nsTArray& aNames) +nsDOMAttributeMap::GetSupportedNames(nsTArray& aNames) { - if (!(aFlags & JSITER_HIDDEN)) { - return; - } - // For HTML elements in HTML documents, only include names that are still the // same after ASCII-lowercasing, since our named getter will end up // ASCII-lowercasing the given string. diff --git a/dom/base/nsDOMAttributeMap.h b/dom/base/nsDOMAttributeMap.h index 07e4111d27..31eb701e35 100644 --- a/dom/base/nsDOMAttributeMap.h +++ b/dom/base/nsDOMAttributeMap.h @@ -139,7 +139,6 @@ public: // WebIDL Attr* GetNamedItem(const nsAString& aAttrName); Attr* NamedGetter(const nsAString& aAttrName, bool& aFound); - bool NameIsEnumerable(const nsAString& aName); already_AddRefed RemoveNamedItem(mozilla::dom::NodeInfo* aNodeInfo, ErrorResult& aError); already_AddRefed @@ -159,7 +158,7 @@ public: ErrorResult& aError); void - GetSupportedNames(unsigned aFlags, nsTArray& aNames); + GetSupportedNames(nsTArray& aNames); size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 9ebbe41c47..bdc39a7a57 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -1044,7 +1044,7 @@ nsDOMWindowUtils::SendNativeKeyEvent(int32_t aNativeKeyboardLayout, if (!widget) return NS_ERROR_FAILURE; - NS_DispatchToMainThread(NS_NewRunnableMethodWithArgs + NS_DispatchToMainThread(NewRunnableMethod (widget, &nsIWidget::SynthesizeNativeKeyEvent, aNativeKeyboardLayout, aNativeKeyCode, aModifiers, aCharacters, aUnmodifiedCharacters, aObserver)); @@ -1066,7 +1066,7 @@ nsDOMWindowUtils::SendNativeMouseEvent(int32_t aScreenX, if (!widget) return NS_ERROR_FAILURE; - NS_DispatchToMainThread(NS_NewRunnableMethodWithArgs + NS_DispatchToMainThread(NewRunnableMethod (widget, &nsIWidget::SynthesizeNativeMouseEvent, LayoutDeviceIntPoint(aScreenX, aScreenY), aNativeMessage, aModifierFlags, @@ -1085,7 +1085,7 @@ nsDOMWindowUtils::SendNativeMouseMove(int32_t aScreenX, if (!widget) return NS_ERROR_FAILURE; - NS_DispatchToMainThread(NS_NewRunnableMethodWithArgs + NS_DispatchToMainThread(NewRunnableMethod (widget, &nsIWidget::SynthesizeNativeMouseMove, LayoutDeviceIntPoint(aScreenX, aScreenY), aObserver)); @@ -1112,7 +1112,7 @@ nsDOMWindowUtils::SendNativeMouseScrollEvent(int32_t aScreenX, return NS_ERROR_FAILURE; } - NS_DispatchToMainThread(NS_NewRunnableMethodWithArgs + NS_DispatchToMainThread(NewRunnableMethod (widget, &nsIWidget::SynthesizeNativeMouseScrollEvent, LayoutDeviceIntPoint(aScreenX, aScreenY), aNativeMessage, aDeltaX, aDeltaY, @@ -1140,7 +1140,7 @@ nsDOMWindowUtils::SendNativeTouchPoint(uint32_t aPointerId, return NS_ERROR_INVALID_ARG; } - NS_DispatchToMainThread(NS_NewRunnableMethodWithArgs + NS_DispatchToMainThread(NewRunnableMethod (widget, &nsIWidget::SynthesizeNativeTouchPoint, aPointerId, (nsIWidget::TouchPointerState)aTouchState, @@ -1162,7 +1162,7 @@ nsDOMWindowUtils::SendNativeTouchTap(int32_t aScreenX, return NS_ERROR_FAILURE; } - NS_DispatchToMainThread(NS_NewRunnableMethodWithArgs + NS_DispatchToMainThread(NewRunnableMethod (widget, &nsIWidget::SynthesizeNativeTouchTap, LayoutDeviceIntPoint(aScreenX, aScreenY), aLongTap, aObserver)); @@ -1179,7 +1179,7 @@ nsDOMWindowUtils::ClearNativeTouchSequence(nsIObserver* aObserver) return NS_ERROR_FAILURE; } - NS_DispatchToMainThread(NS_NewRunnableMethodWithArgs + NS_DispatchToMainThread(NewRunnableMethod (widget, &nsIWidget::ClearNativeTouchSequence, aObserver)); return NS_OK; } @@ -3763,22 +3763,22 @@ nsDOMWindowUtils::PostRestyleSelfEvent(nsIDOMElement* aElement) } NS_IMETHODIMP -nsDOMWindowUtils::GetMediaSuspended(bool* aSuspended) +nsDOMWindowUtils::GetMediaSuspend(uint32_t* aSuspend) { nsCOMPtr window = do_QueryReferent(mWindow); NS_ENSURE_STATE(window); - *aSuspended = window->GetMediaSuspended(); + *aSuspend = window->GetMediaSuspend(); return NS_OK; } NS_IMETHODIMP -nsDOMWindowUtils::SetMediaSuspended(bool aSuspended) +nsDOMWindowUtils::SetMediaSuspend(uint32_t aSuspend) { nsCOMPtr window = do_QueryReferent(mWindow); NS_ENSURE_STATE(window); - window->SetMediaSuspended(aSuspended); + window->SetMediaSuspend(aSuspend); return NS_OK; } diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 8017c2e750..b2076ef26a 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -4351,7 +4351,7 @@ nsDocument::SetStyleSheetApplicableState(StyleSheetHandle aSheet, } if (!mSSApplicableStateNotificationPending) { - nsCOMPtr notification = NS_NewRunnableMethod(this, + nsCOMPtr notification = NewRunnableMethod(this, &nsDocument::NotifyStyleSheetApplicableStateChanged); mSSApplicableStateNotificationPending = NS_SUCCEEDED(NS_DispatchToCurrentThread(notification)); @@ -4944,7 +4944,7 @@ nsDocument::MaybeEndOutermostXBLUpdate() BindingManager()->EndOutermostUpdate(); } else if (!mInDestructor) { nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &nsDocument::MaybeEndOutermostXBLUpdate)); + NewRunnableMethod(this, &nsDocument::MaybeEndOutermostXBLUpdate)); } } } @@ -5262,7 +5262,7 @@ nsDocument::UnblockDOMContentLoaded() MOZ_ASSERT(mReadyState == READYSTATE_INTERACTIVE); if (!mSynchronousDOMContentLoaded) { nsCOMPtr ev = - NS_NewRunnableMethod(this, &nsDocument::DispatchContentLoadedEvents); + NewRunnableMethod(this, &nsDocument::DispatchContentLoadedEvents); NS_DispatchToCurrentThread(ev); } else { DispatchContentLoadedEvents(); @@ -7243,7 +7243,7 @@ nsDocument::NotifyPossibleTitleChange(bool aBoundTitleElement) return; RefPtr > event = - NS_NewNonOwningRunnableMethod(this, + NewNonOwningRunnableMethod(this, &nsDocument::DoNotifyPossibleTitleChange); nsresult rv = NS_DispatchToCurrentThread(event); if (NS_SUCCEEDED(rv)) { @@ -7392,7 +7392,7 @@ nsDocument::InitializeFrameLoader(nsFrameLoader* aLoader) mInitializableFrameLoaders.AppendElement(aLoader); if (!mFrameLoaderRunner) { mFrameLoaderRunner = - NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders); + NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders); NS_ENSURE_TRUE(mFrameLoaderRunner, NS_ERROR_OUT_OF_MEMORY); nsContentUtils::AddScriptRunner(mFrameLoaderRunner); } @@ -7410,7 +7410,7 @@ nsDocument::FinalizeFrameLoader(nsFrameLoader* aLoader, nsIRunnable* aFinalizer) mFrameLoaderFinalizers.AppendElement(aFinalizer); if (!mFrameLoaderRunner) { mFrameLoaderRunner = - NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders); + NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders); NS_ENSURE_TRUE(mFrameLoaderRunner, NS_ERROR_OUT_OF_MEMORY); nsContentUtils::AddScriptRunner(mFrameLoaderRunner); } @@ -7434,7 +7434,7 @@ nsDocument::MaybeInitializeFinalizeFrameLoaders() (mInitializableFrameLoaders.Length() || mFrameLoaderFinalizers.Length())) { mFrameLoaderRunner = - NS_NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders); + NewRunnableMethod(this, &nsDocument::MaybeInitializeFinalizeFrameLoaders); nsContentUtils::AddScriptRunner(mFrameLoaderRunner); } return; @@ -9032,7 +9032,7 @@ nsDocument::BlockOnload() ++mAsyncOnloadBlockCount; if (mAsyncOnloadBlockCount == 1) { bool success = nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &nsDocument::AsyncBlockOnload)); + NewRunnableMethod(this, &nsDocument::AsyncBlockOnload)); // The script runner shouldn't fail to add. But if somebody broke // something and it does, we'll thrash at 100% cpu forever. The best @@ -12724,7 +12724,7 @@ nsDocument::GetVisibilityState() const nsDocument::PostVisibilityUpdateEvent() { nsCOMPtr event = - NS_NewRunnableMethod(this, &nsDocument::UpdateVisibilityState); + NewRunnableMethod(this, &nsDocument::UpdateVisibilityState); NS_DispatchToMainThread(event); } @@ -13445,7 +13445,7 @@ nsIDocument::RebuildUserFontSet() // change reflow). if (!mPostedFlushUserFontSet) { nsCOMPtr ev = - NS_NewRunnableMethod(this, &nsIDocument::HandleRebuildUserFontSet); + NewRunnableMethod(this, &nsIDocument::HandleRebuildUserFontSet); if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) { mPostedFlushUserFontSet = true; } diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index a1f35d88b6..ad71990461 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -619,7 +619,8 @@ nsPIDOMWindow::nsPIDOMWindow(nsPIDOMWindow *aOuterWindow) mMayHavePointerEnterLeaveEventListener(false), mInnerObjectsFreed(false), mIsModalContentWindow(false), - mIsActive(false), mIsBackground(false), mMediaSuspended(false), + mIsActive(false), mIsBackground(false), + mMediaSuspend(nsISuspendedTypes::NONE_SUSPENDED), mAudioMuted(false), mAudioVolume(1.0), mAudioCaptured(false), mDesktopModeViewport(false), mInnerWindow(nullptr), mOuterWindow(aOuterWindow), @@ -911,13 +912,14 @@ nsOuterWindowProxy::getPrototypeIfOrdinary(JSContext* cx, // // https://html.spec.whatwg.org/multipage/browsers.html#windowproxy-getprototypeof // - // We nonetheless can implement it here using a non-"lazy" [[Prototype]], - // because wrapper-class handlers (particularly, XOW in FilteringWrapper.cpp) - // supply all the non-ordinary behavior. + // We nonetheless can implement it with a static [[Prototype]], because + // wrapper-class handlers (particularly, XOW in FilteringWrapper.cpp) supply + // all non-ordinary behavior. // // But from a spec point of view, it's the exact same object in both cases -- - // only the observer's changed. So both cases *must* report non-ordinary, - // even if non-"lazy" [[Prototype]] usually means ordinary. + // only the observer's changed. So this getPrototypeIfOrdinary trap on the + // non-wrapper object *must* report non-ordinary, even if static [[Prototype]] + // usually means ordinary. *isOrdinary = false; return true; } @@ -2637,7 +2639,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, under normal circumstances, but bug 49615 describes a case.) */ nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &nsGlobalWindow::ClearStatus)); + NewRunnableMethod(this, &nsGlobalWindow::ClearStatus)); // Sometimes, WouldReuseInnerWindow() returns true even if there's no inner // window (see bug 776497). Be safe. @@ -2954,8 +2956,8 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, // up with the outer. See bug 969156. if (createdInnerWindow) { nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(newInnerWindow, - &nsGlobalWindow::FireOnNewGlobalObject)); + NewRunnableMethod(newInnerWindow, + &nsGlobalWindow::FireOnNewGlobalObject)); } if (newInnerWindow && !newInnerWindow->mHasNotifiedGlobalCreated && mDoc) { @@ -2968,7 +2970,7 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, nsContentUtils::IsSystemPrincipal(mDoc->NodePrincipal())) { newInnerWindow->mHasNotifiedGlobalCreated = true; nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &nsGlobalWindow::DispatchDOMWindowCreated)); + NewRunnableMethod(this, &nsGlobalWindow::DispatchDOMWindowCreated)); } } @@ -3917,30 +3919,29 @@ nsPIDOMWindow::CreatePerformanceObjectIfNeeded() } } -bool -nsPIDOMWindow::GetMediaSuspended() const +SuspendTypes +nsPIDOMWindow::GetMediaSuspend() const { if (IsInnerWindow()) { - return mOuterWindow->GetMediaSuspended(); + return mOuterWindow->GetMediaSuspend(); } - return mMediaSuspended; + return mMediaSuspend; } void -nsPIDOMWindow::SetMediaSuspended(bool aSuspended) +nsPIDOMWindow::SetMediaSuspend(SuspendTypes aSuspend) { if (IsInnerWindow()) { - mOuterWindow->SetMediaSuspended(aSuspended); + mOuterWindow->SetMediaSuspend(aSuspend); return; } - if (mMediaSuspended == aSuspended) { - return; + if (!IsDisposableSuspend(aSuspend)) { + mMediaSuspend = aSuspend; } - mMediaSuspended = aSuspended; - RefreshMediaElements(); + RefreshMediaElementsSuspend(aSuspend); } bool @@ -3966,7 +3967,7 @@ nsPIDOMWindow::SetAudioMuted(bool aMuted) } mAudioMuted = aMuted; - RefreshMediaElements(); + RefreshMediaElementsVolume(); } float @@ -3995,12 +3996,12 @@ nsPIDOMWindow::SetAudioVolume(float aVolume) } mAudioVolume = aVolume; - RefreshMediaElements(); + RefreshMediaElementsVolume(); return NS_OK; } void -nsPIDOMWindow::RefreshMediaElements() +nsPIDOMWindow::RefreshMediaElementsVolume() { RefPtr service = AudioChannelService::GetOrCreate(); if (service) { @@ -4008,6 +4009,22 @@ nsPIDOMWindow::RefreshMediaElements() } } +void +nsPIDOMWindow::RefreshMediaElementsSuspend(SuspendTypes aSuspend) +{ + RefPtr service = AudioChannelService::GetOrCreate(); + if (service) { + service->RefreshAgentsSuspend(GetOuterWindow(), aSuspend); + } +} + +bool +nsPIDOMWindow::IsDisposableSuspend(SuspendTypes aSuspend) const +{ + return (aSuspend == nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE || + aSuspend == nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE); +} + void nsPIDOMWindow::SetServiceWorkersTestingEnabled(bool aEnabled) { @@ -12256,7 +12273,7 @@ public: ~AutoUnblockScriptClosing() { void (nsGlobalWindow::*run)() = &nsGlobalWindow::UnblockScriptedClosing; - NS_DispatchToCurrentThread(NS_NewRunnableMethod(mWin, run)); + NS_DispatchToCurrentThread(NewRunnableMethod(mWin, run)); } }; diff --git a/dom/base/nsMimeTypeArray.cpp b/dom/base/nsMimeTypeArray.cpp index 210648d9f3..a74151858a 100644 --- a/dom/base/nsMimeTypeArray.cpp +++ b/dom/base/nsMimeTypeArray.cpp @@ -90,7 +90,7 @@ nsMimeTypeArray::IndexedGetter(uint32_t aIndex, bool &aFound) } static nsMimeType* -FindMimeType(const nsTArray >& aMimeTypes, +FindMimeType(const nsTArray>& aMimeTypes, const nsAString& aType) { for (uint32_t i = 0; i < aMimeTypes.Length(); ++i) { @@ -122,12 +122,6 @@ nsMimeTypeArray::NamedGetter(const nsAString& aName, bool &aFound) return nullptr; } -bool -nsMimeTypeArray::NameIsEnumerable(const nsAString& aName) -{ - return true; -} - uint32_t nsMimeTypeArray::Length() { @@ -137,7 +131,7 @@ nsMimeTypeArray::Length() } void -nsMimeTypeArray::GetSupportedNames(unsigned, nsTArray< nsString >& aRetval) +nsMimeTypeArray::GetSupportedNames(nsTArray& aRetval) { EnsurePluginMimeTypes(); diff --git a/dom/base/nsMimeTypeArray.h b/dom/base/nsMimeTypeArray.h index 180c17bb1f..3bc86e6609 100644 --- a/dom/base/nsMimeTypeArray.h +++ b/dom/base/nsMimeTypeArray.h @@ -35,9 +35,8 @@ public: nsMimeType* NamedItem(const nsAString& name); nsMimeType* IndexedGetter(uint32_t index, bool &found); nsMimeType* NamedGetter(const nsAString& name, bool &found); - bool NameIsEnumerable(const nsAString& name); uint32_t Length(); - void GetSupportedNames(unsigned, nsTArray< nsString >& retval); + void GetSupportedNames(nsTArray& retval); protected: virtual ~nsMimeTypeArray(); diff --git a/dom/base/nsPIDOMWindow.h b/dom/base/nsPIDOMWindow.h index 611d89b015..d5b6e5f536 100644 --- a/dom/base/nsPIDOMWindow.h +++ b/dom/base/nsPIDOMWindow.h @@ -35,6 +35,8 @@ class nsPIWindowRoot; class nsXBLPrototypeHandler; struct nsTimeout; +typedef uint32_t SuspendTypes; + namespace mozilla { namespace dom { class AudioContext; @@ -208,8 +210,8 @@ public: virtual bool IsRunningTimeout() = 0; // Audio API - bool GetMediaSuspended() const; - void SetMediaSuspended(bool aSuspended); + SuspendTypes GetMediaSuspend() const; + void SetMediaSuspend(SuspendTypes aSuspend); bool GetAudioMuted() const; void SetAudioMuted(bool aMuted); @@ -233,7 +235,9 @@ protected: void MaybeCreateDoc(); float GetAudioGlobalVolumeInternal(float aVolume); - void RefreshMediaElements(); + void RefreshMediaElementsVolume(); + void RefreshMediaElementsSuspend(SuspendTypes aSuspend); + bool IsDisposableSuspend(SuspendTypes aSuspend) const; public: // Internal getter/setter for the frame element, this version of the @@ -850,7 +854,19 @@ protected: // "active". Only used on outer windows. bool mIsBackground; - bool mMediaSuspended; + /** + * The suspended types can be "disposable" or "permanent". This varable only + * stores the value about permanent suspend. + * - disposable + * To pause all playing media in that window, but doesn't affect the media + * which starts after that. + * + * - permanent + * To pause all media in that window, and also affect the media which starts + * after that. + */ + SuspendTypes mMediaSuspend; + bool mAudioMuted; float mAudioVolume; diff --git a/dom/base/nsPluginArray.cpp b/dom/base/nsPluginArray.cpp index 857184c1ea..70a6973e53 100644 --- a/dom/base/nsPluginArray.cpp +++ b/dom/base/nsPluginArray.cpp @@ -225,12 +225,6 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound) return plugin; } -bool -nsPluginArray::NameIsEnumerable(const nsAString& aName) -{ - return true; -} - uint32_t nsPluginArray::Length() { @@ -244,7 +238,7 @@ nsPluginArray::Length() } void -nsPluginArray::GetSupportedNames(unsigned, nsTArray& aRetval) +nsPluginArray::GetSupportedNames(nsTArray& aRetval) { aRetval.Clear(); @@ -420,12 +414,6 @@ nsPluginElement::NamedGetter(const nsAString& aName, bool &aFound) return nullptr; } -bool -nsPluginElement::NameIsEnumerable(const nsAString& aName) -{ - return true; -} - uint32_t nsPluginElement::Length() { @@ -435,7 +423,7 @@ nsPluginElement::Length() } void -nsPluginElement::GetSupportedNames(unsigned, nsTArray& retval) +nsPluginElement::GetSupportedNames(nsTArray& retval) { EnsurePluginMimeTypes(); diff --git a/dom/base/nsPluginArray.h b/dom/base/nsPluginArray.h index aa6142ea8f..90acdfda0a 100644 --- a/dom/base/nsPluginArray.h +++ b/dom/base/nsPluginArray.h @@ -49,9 +49,8 @@ public: void Refresh(bool aReloadDocuments); nsPluginElement* IndexedGetter(uint32_t aIndex, bool &aFound); nsPluginElement* NamedGetter(const nsAString& aName, bool &aFound); - bool NameIsEnumerable(const nsAString& aName); uint32_t Length(); - void GetSupportedNames(unsigned, nsTArray& aRetval); + void GetSupportedNames(nsTArray& aRetval); private: virtual ~nsPluginArray(); @@ -90,9 +89,8 @@ public: nsMimeType* NamedItem(const nsAString& name); nsMimeType* IndexedGetter(uint32_t index, bool &found); nsMimeType* NamedGetter(const nsAString& name, bool &found); - bool NameIsEnumerable(const nsAString& aName); uint32_t Length(); - void GetSupportedNames(unsigned, nsTArray& retval); + void GetSupportedNames(nsTArray& retval); nsTArray >& MimeTypes(); diff --git a/dom/base/nsScriptLoader.cpp b/dom/base/nsScriptLoader.cpp index 935c83a83b..81e1e6db80 100644 --- a/dom/base/nsScriptLoader.cpp +++ b/dom/base/nsScriptLoader.cpp @@ -523,8 +523,8 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) if (!scriptURI) { // Asynchronously report the failure to create a URI object NS_DispatchToCurrentThread( - NS_NewRunnableMethod(aElement, - &nsIScriptElement::FireErrorEvent)); + NewRunnableMethod(aElement, + &nsIScriptElement::FireErrorEvent)); return false; } @@ -590,8 +590,8 @@ nsScriptLoader::ProcessScriptElement(nsIScriptElement *aElement) if (NS_FAILED(rv)) { // Asynchronously report the load failure NS_DispatchToCurrentThread( - NS_NewRunnableMethod(aElement, - &nsIScriptElement::FireErrorEvent)); + NewRunnableMethod(aElement, + &nsIScriptElement::FireErrorEvent)); return false; } } @@ -1170,10 +1170,8 @@ void nsScriptLoader::ProcessPendingRequestsAsync() { if (mParserBlockingRequest || !mPendingChildLoaders.IsEmpty()) { - nsCOMPtr ev = NS_NewRunnableMethod(this, - &nsScriptLoader::ProcessPendingRequests); - - NS_DispatchToCurrentThread(ev); + NS_DispatchToCurrentThread(NewRunnableMethod(this, + &nsScriptLoader::ProcessPendingRequests)); } } diff --git a/dom/base/nsTextNode.cpp b/dom/base/nsTextNode.cpp index 2ee7b82b15..25c2d35256 100644 --- a/dom/base/nsTextNode.cpp +++ b/dom/base/nsTextNode.cpp @@ -273,8 +273,7 @@ nsAttributeTextNode::AttributeChanged(nsIDocument* aDocument, // that if we get unbound while the event is up that's ok -- we'll just // have no grandparent when it fires, and will do nothing. void (nsAttributeTextNode::*update)() = &nsAttributeTextNode::UpdateText; - nsCOMPtr ev = NS_NewRunnableMethod(this, update); - nsContentUtils::AddScriptRunner(ev); + nsContentUtils::AddScriptRunner(NewRunnableMethod(this, update)); } } diff --git a/dom/base/test/audio.ogg b/dom/base/test/audio.ogg index d7f6a0ccf4..bed764fbf1 100644 Binary files a/dom/base/test/audio.ogg and b/dom/base/test/audio.ogg differ diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index 6d9c2b5128..2f2ae4f7ff 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -10975,15 +10975,11 @@ class CGDOMJSProxyHandler_getOwnPropDescriptor(ClassMethod): if self.descriptor.supportsNamedProperties(): operations = self.descriptor.operations readonly = toStringBool(operations['NamedSetter'] is None) - enumerable = ( - "self->NameIsEnumerable(Constify(%s))" % - # First [0] means first (and only) signature, [1] means - # "arguments" as opposed to return type, [0] means first (and - # only) argument. - operations['NamedGetter'].signatures()[0][1][0].identifier.name) fillDescriptor = ( "FillPropertyDescriptor(desc, proxy, %s, %s);\n" - "return true;\n" % (readonly, enumerable)) + "return true;\n" % + (readonly, + toStringBool(self.descriptor.namedPropertiesEnumerable))) templateValues = {'jsvalRef': 'desc.value()', 'jsvalHandle': 'desc.value()', 'obj': 'proxy', 'successCode': fillDescriptor} @@ -11299,14 +11295,17 @@ class CGDOMJSProxyHandler_ownPropNames(ClassMethod): shadow = "false" addNames = fill( """ - nsTArray names; - UnwrapProxy(proxy)->GetSupportedNames(flags, names); + UnwrapProxy(proxy)->GetSupportedNames(names); if (!AppendNamedPropertyIds(cx, proxy, names, ${shadow}, props)) { return false; } """, shadow=shadow) + if not self.descriptor.namedPropertiesEnumerable: + addNames = CGIfWrapper(CGGeneric(addNames), + "flags & JSITER_HIDDEN").define() + addNames = "\n" + addNames else: addNames = "" @@ -11666,6 +11665,23 @@ class CGDOMJSProxyHandler_getInstance(ClassMethod): """) +class CGDOMJSProxyHandler_getPrototypeIfOrdinary(ClassMethod): + def __init__(self): + args = [Argument('JSContext*', 'cx'), + Argument('JS::Handle', 'proxy'), + Argument('bool*', 'isOrdinary'), + Argument('JS::MutableHandle', 'proto')] + + ClassMethod.__init__(self, "getPrototypeIfOrdinary", "bool", args, + virtual=True, override=True, const=True) + + def getBody(self): + return dedent(""" + *isOrdinary = false; + return true; + """) + + class CGDOMJSProxyHandler_call(ClassMethod): def __init__(self): args = [Argument('JSContext*', 'cx'), @@ -11697,7 +11713,8 @@ class CGDOMJSProxyHandler_isCallable(ClassMethod): class CGDOMJSProxyHandler(CGClass): def __init__(self, descriptor): assert (descriptor.supportsIndexedProperties() or - descriptor.supportsNamedProperties()) + descriptor.supportsNamedProperties() or + descriptor.hasNonOrdinaryGetPrototypeOf()) methods = [CGDOMJSProxyHandler_getOwnPropDescriptor(descriptor), CGDOMJSProxyHandler_defineProperty(descriptor), ClassUsingDeclaration("mozilla::dom::DOMProxyHandler", @@ -11724,6 +11741,8 @@ class CGDOMJSProxyHandler(CGClass): (descriptor.operations['NamedSetter'] is not None and descriptor.interface.getExtendedAttribute('OverrideBuiltins'))): methods.append(CGDOMJSProxyHandler_setCustom(descriptor)) + if descriptor.hasNonOrdinaryGetPrototypeOf(): + methods.append(CGDOMJSProxyHandler_getPrototypeIfOrdinary()) if descriptor.operations['LegacyCaller']: methods.append(CGDOMJSProxyHandler_call()) methods.append(CGDOMJSProxyHandler_isCallable()) @@ -14107,7 +14126,7 @@ class CGBindingImplClass(CGClass): []), {"infallible": True})) # And if we support named properties we need to be able to - # enumerate the supported names and test whether they're enumerable. + # enumerate the supported names. if descriptor.supportsNamedProperties(): self.methodDecls.append( CGNativeMember( @@ -14115,20 +14134,7 @@ class CGBindingImplClass(CGClass): "GetSupportedNames", (IDLSequenceType(None, BuiltinTypes[IDLBuiltinType.Types.domstring]), - # Let's use unsigned long for the type here, though really - # it's just a C++ "unsigned"... - [FakeArgument(BuiltinTypes[IDLBuiltinType.Types.unsigned_long], - FakeMember(), - name="aFlags")]), - {"infallible": True})) - self.methodDecls.append( - CGNativeMember( - descriptor, FakeMember(), - "NameIsEnumerable", - (BuiltinTypes[IDLBuiltinType.Types.boolean], - [FakeArgument(BuiltinTypes[IDLBuiltinType.Types.domstring], - FakeMember(), - name="aName")]), + []), {"infallible": True})) wrapArgs = [Argument('JSContext*', 'aCx'), diff --git a/dom/bindings/Configuration.py b/dom/bindings/Configuration.py index 5845639130..b52167deef 100644 --- a/dom/bindings/Configuration.py +++ b/dom/bindings/Configuration.py @@ -515,7 +515,8 @@ class Descriptor(DescriptorProvider): self.proxy = (self.supportsIndexedProperties() or (self.supportsNamedProperties() and - not self.hasNamedPropertiesObject)) + not self.hasNamedPropertiesObject) or + self.hasNonOrdinaryGetPrototypeOf()) if self.proxy: if (not self.operations['IndexedGetter'] and @@ -747,6 +748,9 @@ class Descriptor(DescriptorProvider): def supportsNamedProperties(self): return self.operations['NamedGetter'] is not None + def hasNonOrdinaryGetPrototypeOf(self): + return self.interface.getExtendedAttribute("NonOrdinaryGetPrototypeOf") + def needsConstructHookHolder(self): assert self.interface.hasInterfaceObject() return False @@ -806,6 +810,20 @@ class Descriptor(DescriptorProvider): return (self.interface.getExtendedAttribute("Global") or self.interface.getExtendedAttribute("PrimaryGlobal")) + @property + def namedPropertiesEnumerable(self): + """ + Returns whether this interface should have enumerable named properties + """ + assert self.proxy + assert self.supportsNamedProperties() + iface = self.interface + while iface: + if iface.getExtendedAttribute("LegacyUnenumerableNamedProperties"): + return False + iface = iface.parent + return True + # Some utility methods def getTypesFromDescriptor(descriptor): diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index 4d8fe57e48..4a63d45556 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -251,6 +251,16 @@ BaseDOMProxyHandler::ownPropertyKeys(JSContext* cx, return ownPropNames(cx, proxy, JSITER_OWNONLY | JSITER_HIDDEN | JSITER_SYMBOLS, props); } +bool +BaseDOMProxyHandler::getPrototypeIfOrdinary(JSContext* cx, JS::Handle proxy, + bool* isOrdinary, + JS::MutableHandle proto) const +{ + *isOrdinary = true; + proto.set(GetStaticPrototype(proxy)); + return true; +} + bool BaseDOMProxyHandler::getOwnEnumerablePropertyKeys(JSContext* cx, JS::Handle proxy, diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h index 799c3a61ae..bb740832b0 100644 --- a/dom/bindings/DOMJSProxyHandler.h +++ b/dom/bindings/DOMJSProxyHandler.h @@ -59,6 +59,10 @@ public: virtual bool ownPropertyKeys(JSContext* cx, JS::Handle proxy, JS::AutoIdVector &props) const override; + virtual bool getPrototypeIfOrdinary(JSContext* cx, JS::Handle proxy, + bool* isOrdinary, + JS::MutableHandle proto) const override; + // We override getOwnEnumerablePropertyKeys() and implement it directly // instead of using the default implementation, which would call // ownPropertyKeys and then filter out the non-enumerable ones. This avoids diff --git a/dom/bindings/parser/WebIDL.py b/dom/bindings/parser/WebIDL.py index b922c7c0fd..41613d869d 100644 --- a/dom/bindings/parser/WebIDL.py +++ b/dom/bindings/parser/WebIDL.py @@ -1078,6 +1078,23 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): specialMembersSeen[memberType] = member + if self.getExtendedAttribute("LegacyUnenumerableNamedProperties"): + # Check that we have a named getter. + if "named getters" not in specialMembersSeen: + raise WebIDLError( + "Interface with [LegacyUnenumerableNamedProperties] does " + "not have a named getter", + [self.location]) + ancestor = self.parent + while ancestor: + if ancestor.getExtendedAttribute("LegacyUnenumerableNamedProperties"): + raise WebIDLError( + "Interface with [LegacyUnenumerableNamedProperties] " + "inherits from another interface with " + "[LegacyUnenumerableNamedProperties]", + [self.location, ancestor.location]) + ancestor = ancestor.parent + if self._isOnGlobalProtoChain: # Make sure we have no named setters, creators, or deleters for memberType in ["setter", "creator", "deleter"]: @@ -1464,7 +1481,9 @@ class IDLInterface(IDLObjectWithScope, IDLExposureMixins): identifier == "Unforgeable" or identifier == "UnsafeInPrerendering" or identifier == "LegacyEventInit" or - identifier == "ProbablyShortLivingObject"): + identifier == "ProbablyShortLivingObject" or + identifier == "LegacyUnenumerableNamedProperties" or + identifier == "NonOrdinaryGetPrototypeOf"): # Known extended attributes that do not take values if not attr.noArguments(): raise WebIDLError("[%s] must take no arguments" % identifier, diff --git a/dom/bindings/parser/tests/test_unenumerable_own_properties.py b/dom/bindings/parser/tests/test_unenumerable_own_properties.py new file mode 100644 index 0000000000..d017d5ce09 --- /dev/null +++ b/dom/bindings/parser/tests/test_unenumerable_own_properties.py @@ -0,0 +1,64 @@ +def WebIDLTest(parser, harness): + + parser.parse( + """ + interface Foo {}; + [LegacyUnenumerableNamedProperties] + interface Bar : Foo { + getter long(DOMString name); + }; + interface Baz : Bar { + getter long(DOMString name); + }; + """); + results = parser.finish(); + harness.check(len(results), 3, "Should have three interfaces") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [LegacyUnenumerableNamedProperties] + interface NoNamedGetter { + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [LegacyUnenumerableNamedProperties=Foo] + interface ShouldNotHaveArg { + getter long(DOMString name); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") + + parser = parser.reset() + threw = False + try: + parser.parse(""" + [LegacyUnenumerableNamedProperties] + interface Foo { + getter long(DOMString name); + }; + interface Bar : Foo {}; + [LegacyUnenumerableNamedProperties] + interface Baz : Bar { + getter long(DOMString name); + }; + """) + + results = parser.finish() + except Exception, x: + threw = True + harness.ok(threw, "Should have thrown.") diff --git a/dom/bindings/test/TestBindingHeader.h b/dom/bindings/test/TestBindingHeader.h index 88bba7069b..91055044db 100644 --- a/dom/bindings/test/TestBindingHeader.h +++ b/dom/bindings/test/TestBindingHeader.h @@ -1137,8 +1137,7 @@ public: virtual nsISupports* GetParentObject(); void NamedGetter(const nsAString&, bool&, nsAString&); - bool NameIsEnumerable(const nsAString&); - void GetSupportedNames(unsigned, nsTArray&); + void GetSupportedNames(nsTArray&); }; class TestIndexedGetterAndSetterAndNamedGetterInterface : public nsISupports, @@ -1151,8 +1150,7 @@ public: virtual nsISupports* GetParentObject(); void NamedGetter(const nsAString&, bool&, nsAString&); - bool NameIsEnumerable(const nsAString&); - void GetSupportedNames(unsigned, nsTArray&); + void GetSupportedNames(nsTArray&); int32_t IndexedGetter(uint32_t, bool&); void IndexedSetter(uint32_t, int32_t); uint32_t Length(); @@ -1169,10 +1167,9 @@ public: uint32_t IndexedGetter(uint32_t, bool&); void NamedGetter(const nsAString&, bool&, nsAString&); - bool NameIsEnumerable(const nsAString&); void NamedItem(const nsAString&, nsAString&); uint32_t Length(); - void GetSupportedNames(unsigned, nsTArray&); + void GetSupportedNames(nsTArray&); }; class TestIndexedSetterInterface : public nsISupports, @@ -1201,8 +1198,7 @@ public: void NamedSetter(const nsAString&, TestIndexedSetterInterface&); TestIndexedSetterInterface* NamedGetter(const nsAString&, bool&); - bool NameIsEnumerable(const nsAString&); - void GetSupportedNames(unsigned, nsTArray&); + void GetSupportedNames(nsTArray&); }; class TestIndexedAndNamedSetterInterface : public nsISupports, @@ -1219,9 +1215,8 @@ public: uint32_t Length(); void NamedSetter(const nsAString&, TestIndexedSetterInterface&); TestIndexedSetterInterface* NamedGetter(const nsAString&, bool&); - bool NameIsEnumerable(const nsAString&); void SetNamedItem(const nsAString&, TestIndexedSetterInterface&); - void GetSupportedNames(unsigned, nsTArray&); + void GetSupportedNames(nsTArray&); }; class TestIndexedAndNamedGetterAndSetterInterface : public TestIndexedSetterInterface @@ -1230,14 +1225,13 @@ public: uint32_t IndexedGetter(uint32_t, bool&); uint32_t Item(uint32_t); void NamedGetter(const nsAString&, bool&, nsAString&); - bool NameIsEnumerable(const nsAString&); void NamedItem(const nsAString&, nsAString&); void IndexedSetter(uint32_t, int32_t&); void IndexedSetter(uint32_t, const nsAString&) = delete; void NamedSetter(const nsAString&, const nsAString&); void Stringify(nsAString&); uint32_t Length(); - void GetSupportedNames(unsigned, nsTArray&); + void GetSupportedNames(nsTArray&); }; class TestCppKeywordNamedMethodsInterface : public nsISupports, @@ -1299,8 +1293,7 @@ public: void NamedDeleter(const nsAString&, bool&); long NamedGetter(const nsAString&, bool&); - bool NameIsEnumerable(const nsAString&); - void GetSupportedNames(unsigned, nsTArray&); + void GetSupportedNames(nsTArray&); }; class TestNamedDeleterWithRetvalInterface : public nsISupports, @@ -1315,10 +1308,9 @@ public: bool NamedDeleter(const nsAString&, bool&); bool NamedDeleter(const nsAString&) = delete; long NamedGetter(const nsAString&, bool&); - bool NameIsEnumerable(const nsAString&); bool DelNamedItem(const nsAString&); bool DelNamedItem(const nsAString&, bool&) = delete; - void GetSupportedNames(unsigned, nsTArray&); + void GetSupportedNames(nsTArray&); }; class TestIndexedAndNamedDeleterInterface : public nsISupports, @@ -1337,10 +1329,9 @@ public: void NamedDeleter(const nsAString&, bool&); void NamedDeleter(const nsAString&) = delete; long NamedGetter(const nsAString&, bool&); - bool NameIsEnumerable(const nsAString&); void DelNamedItem(const nsAString&); void DelNamedItem(const nsAString&, bool&) = delete; - void GetSupportedNames(unsigned, nsTArray&); + void GetSupportedNames(nsTArray&); }; class TestParentInterface : public nsISupports, diff --git a/dom/browser-element/mochitest/audio.ogg b/dom/browser-element/mochitest/audio.ogg index d7f6a0ccf4..44ab64f811 100644 Binary files a/dom/browser-element/mochitest/audio.ogg and b/dom/browser-element/mochitest/audio.ogg differ diff --git a/dom/cache/Context.cpp b/dom/cache/Context.cpp index 4e0d308942..2b1b914692 100644 --- a/dom/cache/Context.cpp +++ b/dom/cache/Context.cpp @@ -687,7 +687,7 @@ Context::ThreadsafeHandle::AllowToClose() // Dispatch is guaranteed to succeed here because we block shutdown until // all Contexts have been destroyed. nsCOMPtr runnable = - NS_NewRunnableMethod(this, &ThreadsafeHandle::AllowToCloseOnOwningThread); + NewRunnableMethod(this, &ThreadsafeHandle::AllowToCloseOnOwningThread); MOZ_ALWAYS_SUCCEEDS( mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL)); } @@ -703,7 +703,7 @@ Context::ThreadsafeHandle::InvalidateAndAllowToClose() // Dispatch is guaranteed to succeed here because we block shutdown until // all Contexts have been destroyed. nsCOMPtr runnable = - NS_NewRunnableMethod(this, &ThreadsafeHandle::InvalidateAndAllowToCloseOnOwningThread); + NewRunnableMethod(this, &ThreadsafeHandle::InvalidateAndAllowToCloseOnOwningThread); MOZ_ALWAYS_SUCCEEDS( mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL)); } @@ -727,10 +727,7 @@ Context::ThreadsafeHandle::~ThreadsafeHandle() // Dispatch is guaranteed to succeed here because we block shutdown until // all Contexts have been destroyed. - nsCOMPtr runnable = - NS_NewNonOwningRunnableMethod(mStrongRef.forget().take(), &Context::Release); - MOZ_ALWAYS_SUCCEEDS( - mOwningThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL)); + NS_ProxyRelease(mOwningThread, mStrongRef.forget()); } void diff --git a/dom/cache/Manager.cpp b/dom/cache/Manager.cpp index d61b7a2b70..28012c9f57 100644 --- a/dom/cache/Manager.cpp +++ b/dom/cache/Manager.cpp @@ -1028,7 +1028,7 @@ private: // May be on any thread, including STS event target. Non-owning runnable // here since we are guaranteed the Action will survive until // CompleteOnInitiatingThread is called. - nsCOMPtr runnable = NS_NewNonOwningRunnableMethodWithArgs( + nsCOMPtr runnable = NewNonOwningRunnableMethod( this, &CachePutAllAction::OnAsyncCopyComplete, aRv); MOZ_ALWAYS_SUCCEEDS( mTargetThread->Dispatch(runnable, nsIThread::DISPATCH_NORMAL)); @@ -1877,9 +1877,7 @@ Manager::~Manager() // Don't spin the event loop in the destructor waiting for the thread to // shutdown. Defer this to the main thread, instead. - nsCOMPtr runnable = - NS_NewRunnableMethod(ioThread, &nsIThread::Shutdown); - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewRunnableMethod(ioThread, &nsIThread::Shutdown))); } void diff --git a/dom/camera/CameraPreviewMediaStream.cpp b/dom/camera/CameraPreviewMediaStream.cpp index 32af686eac..0233c5e518 100644 --- a/dom/camera/CameraPreviewMediaStream.cpp +++ b/dom/camera/CameraPreviewMediaStream.cpp @@ -171,9 +171,7 @@ CameraPreviewMediaStream::SetCurrentFrame(const gfx::IntSize& aIntrinsicSize, Im ++mInvalidatePending; } - nsCOMPtr event = - NS_NewRunnableMethod(this, &CameraPreviewMediaStream::Invalidate); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(NewRunnableMethod(this, &CameraPreviewMediaStream::Invalidate)); } void @@ -184,9 +182,7 @@ CameraPreviewMediaStream::ClearCurrentFrame() for (nsTArray >::size_type i = 0; i < mVideoOutputs.Length(); ++i) { VideoFrameContainer* output = mVideoOutputs[i]; output->ClearCurrentFrame(); - nsCOMPtr event = - NS_NewRunnableMethod(output, &VideoFrameContainer::Invalidate); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(NewRunnableMethod(output, &VideoFrameContainer::Invalidate)); } } diff --git a/dom/camera/DOMCameraCapabilities.cpp b/dom/camera/DOMCameraCapabilities.cpp index 366f48c9a8..4186df0b80 100644 --- a/dom/camera/DOMCameraCapabilities.cpp +++ b/dom/camera/DOMCameraCapabilities.cpp @@ -239,10 +239,10 @@ CameraRecorderProfiles::~CameraRecorderProfiles() } void -CameraRecorderProfiles::GetSupportedNames(unsigned aFlags, nsTArray& aNames) +CameraRecorderProfiles::GetSupportedNames(nsTArray& aNames) { - DOM_CAMERA_LOGT("%s:%d : this=%p, flags=0x%x\n", - __func__, __LINE__, this, aFlags); + DOM_CAMERA_LOGT("%s:%d : this=%p\n", + __func__, __LINE__, this); if (!mCameraControl) { aNames.Clear(); return; @@ -275,15 +275,6 @@ CameraRecorderProfiles::NamedGetter(const nsAString& aName, bool& aFound) return profile; } -bool -CameraRecorderProfiles::NameIsEnumerable(const nsAString& aName) -{ - DOM_CAMERA_LOGT("%s:%d : this=%p, name='%s' (always returns true)\n", - __func__, __LINE__, this, NS_ConvertUTF16toUTF8(aName).get()); - - return true; -} - void CameraRecorderProfiles::OnHardwareClosed() { diff --git a/dom/camera/DOMCameraCapabilities.h b/dom/camera/DOMCameraCapabilities.h index 7d0264db79..310ddc5a28 100644 --- a/dom/camera/DOMCameraCapabilities.h +++ b/dom/camera/DOMCameraCapabilities.h @@ -161,8 +161,7 @@ public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; CameraRecorderProfile* NamedGetter(const nsAString& aName, bool& aFound); - bool NameIsEnumerable(const nsAString& aName); - void GetSupportedNames(unsigned aFlags, nsTArray& aNames); + void GetSupportedNames(nsTArray& aNames); virtual void OnHardwareClosed(); diff --git a/dom/camera/DOMCameraControl.cpp b/dom/camera/DOMCameraControl.cpp index 3894315e28..32b240376f 100644 --- a/dom/camera/DOMCameraControl.cpp +++ b/dom/camera/DOMCameraControl.cpp @@ -73,10 +73,8 @@ public: TrackID aInputTrackID) override { if (aTrackEvents & TRACK_EVENT_CREATED) { - nsCOMPtr runnable = - NS_NewRunnableMethodWithArgs( - this, &TrackCreatedListener::DoNotifyTrackCreated, aID); - aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget()); + aGraph->DispatchToMainThreadAfterStreamStateUpdate(NewRunnableMethod( + this, &TrackCreatedListener::DoNotifyTrackCreated, aID)); } } diff --git a/dom/camera/DOMCameraManager.cpp b/dom/camera/DOMCameraManager.cpp index 84a8bf1eec..4993f82ae0 100644 --- a/dom/camera/DOMCameraManager.cpp +++ b/dom/camera/DOMCameraManager.cpp @@ -233,11 +233,11 @@ CameraPermissionRequest::DispatchCallback(uint32_t aPermission) { nsCOMPtr callbackRunnable; if (aPermission == nsIPermissionManager::ALLOW_ACTION) { - callbackRunnable = NS_NewRunnableMethod(this, &CameraPermissionRequest::CallAllow); + callbackRunnable = NewRunnableMethod(this, &CameraPermissionRequest::CallAllow); } else { - callbackRunnable = NS_NewRunnableMethod(this, &CameraPermissionRequest::CallCancel); + callbackRunnable = NewRunnableMethod(this, &CameraPermissionRequest::CallCancel); } - return NS_DispatchToMainThread(callbackRunnable); + return NS_DispatchToMainThread(callbackRunnable.forget()); } void diff --git a/dom/devicestorage/DeviceStorageStatics.cpp b/dom/devicestorage/DeviceStorageStatics.cpp index f02d904fdc..b8de88f5ff 100644 --- a/dom/devicestorage/DeviceStorageStatics.cpp +++ b/dom/devicestorage/DeviceStorageStatics.cpp @@ -488,7 +488,7 @@ DeviceStorageStatics::AddListener(nsDOMDeviceStorage* aListener) MOZ_ASSERT(sInstance->mInitialized); if (sInstance->mListeners.IsEmpty()) { NS_DispatchToMainThread( - NS_NewRunnableMethod(sInstance.get(), &DeviceStorageStatics::Register)); + NewRunnableMethod(sInstance.get(), &DeviceStorageStatics::Register)); } RefPtr wrapper = @@ -519,7 +519,7 @@ DeviceStorageStatics::RemoveListener(nsDOMDeviceStorage* aListener) if (removed && sInstance->mListeners.IsEmpty()) { NS_DispatchToMainThread( - NS_NewRunnableMethod(sInstance.get(), &DeviceStorageStatics::Deregister)); + NewRunnableMethod(sInstance.get(), &DeviceStorageStatics::Deregister)); } } diff --git a/dom/events/EventListenerService.cpp b/dom/events/EventListenerService.cpp index dee437b422..9b154d4ed2 100644 --- a/dom/events/EventListenerService.cpp +++ b/dom/events/EventListenerService.cpp @@ -371,9 +371,8 @@ EventListenerService::NotifyAboutMainThreadListenerChangeInternal(dom::EventTarg if (!mPendingListenerChanges) { mPendingListenerChanges = nsArrayBase::Create(); - nsCOMPtr runnable = NS_NewRunnableMethod(this, - &EventListenerService::NotifyPendingChanges); - NS_DispatchToCurrentThread(runnable); + NS_DispatchToCurrentThread(NewRunnableMethod(this, + &EventListenerService::NotifyPendingChanges)); } RefPtr changes = mPendingListenerChangesSet.Get(aTarget); diff --git a/dom/fetch/FetchDriver.cpp b/dom/fetch/FetchDriver.cpp index 3b2c994365..0d7990c0cc 100644 --- a/dom/fetch/FetchDriver.cpp +++ b/dom/fetch/FetchDriver.cpp @@ -79,9 +79,7 @@ FetchDriver::Fetch(FetchDriverObserver* aObserver) MOZ_RELEASE_ASSERT(!mRequest->IsSynchronous(), "Synchronous fetch not supported"); - nsCOMPtr r = - NS_NewRunnableMethod(this, &FetchDriver::ContinueFetch); - return NS_DispatchToCurrentThread(r); + return NS_DispatchToCurrentThread(NewRunnableMethod(this, &FetchDriver::ContinueFetch)); } nsresult diff --git a/dom/fmradio/FMRadio.cpp b/dom/fmradio/FMRadio.cpp index 0a1f82c50b..d07b8cc952 100644 --- a/dom/fmradio/FMRadio.cpp +++ b/dom/fmradio/FMRadio.cpp @@ -14,6 +14,7 @@ #include "mozilla/dom/PFMRadioChild.h" #include "mozilla/dom/FMRadioService.h" #include "mozilla/dom/TypedArray.h" +#include "AudioChannelService.h" #include "DOMRequest.h" #include "nsDOMClassInfo.h" #include "nsIDocShell.h" @@ -452,10 +453,15 @@ FMRadio::EnableAudioChannelAgent() { NS_ENSURE_TRUE_VOID(mAudioChannelAgent); - float volume = 0.0; - bool muted = true; - mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted); - WindowVolumeChanged(volume, muted); + AudioPlaybackConfig config; + nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config, + AudioChannelService::AudibleState::eAudible); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + WindowVolumeChanged(config.mVolume, config.mMuted); + WindowSuspendChanged(config.mSuspend); mAudioChannelAgentEnabled = true; } @@ -463,8 +469,16 @@ FMRadio::EnableAudioChannelAgent() NS_IMETHODIMP FMRadio::WindowVolumeChanged(float aVolume, bool aMuted) { + // TODO : Not support to change volume now, so we just close it. IFMRadioService::Singleton()->EnableAudio(!aMuted); - // TODO: what about the volume? + return NS_OK; +} + +NS_IMETHODIMP +FMRadio::WindowSuspendChanged(nsSuspendedTypes aSuspend) +{ + bool enable = (aSuspend == nsISuspendedTypes::NONE_SUSPENDED); + IFMRadioService::Singleton()->EnableAudio(enable); return NS_OK; } diff --git a/dom/html/HTMLAllCollection.cpp b/dom/html/HTMLAllCollection.cpp index edf9bbe658..afa160e0ce 100644 --- a/dom/html/HTMLAllCollection.cpp +++ b/dom/html/HTMLAllCollection.cpp @@ -160,12 +160,8 @@ HTMLAllCollection::NamedGetter(const nsAString& aID, } void -HTMLAllCollection::GetSupportedNames(unsigned aFlags, nsTArray& aNames) +HTMLAllCollection::GetSupportedNames(nsTArray& aNames) { - if (!(aFlags & JSITER_HIDDEN)) { - return; - } - // XXXbz this is very similar to nsContentList::GetSupportedNames, // but has to check IsAllNamedElement for the name case. AutoTArray atoms; diff --git a/dom/html/HTMLAllCollection.h b/dom/html/HTMLAllCollection.h index 61f0f170b2..2410e5ea58 100644 --- a/dom/html/HTMLAllCollection.h +++ b/dom/html/HTMLAllCollection.h @@ -62,11 +62,7 @@ public: void NamedGetter(const nsAString& aName, bool& aFound, Nullable& aResult); - void GetSupportedNames(unsigned aFlags, nsTArray& aNames); - bool NameIsEnumerable(const nsAString& aName) - { - return false; - } + void GetSupportedNames(nsTArray& aNames); void LegacyCall(JS::Handle, const nsAString& aName, Nullable& aResult) { diff --git a/dom/html/HTMLCanvasElement.cpp b/dom/html/HTMLCanvasElement.cpp index 0c7fa0c4c5..35bc7a826e 100644 --- a/dom/html/HTMLCanvasElement.cpp +++ b/dom/html/HTMLCanvasElement.cpp @@ -223,7 +223,7 @@ HTMLCanvasPrintState::Done() mCanvas->InvalidateCanvas(); } RefPtr > doneEvent = - NS_NewRunnableMethod(this, &HTMLCanvasPrintState::NotifyDone); + NewRunnableMethod(this, &HTMLCanvasPrintState::NotifyDone); if (NS_SUCCEEDED(NS_DispatchToCurrentThread(doneEvent))) { mPendingNotify = true; } @@ -503,7 +503,7 @@ HTMLCanvasElement::DispatchPrintCallback(nsITimerCallback* aCallback) mPrintState = new HTMLCanvasPrintState(this, mCurrentContext, aCallback); RefPtr > renderEvent = - NS_NewRunnableMethod(this, &HTMLCanvasElement::CallPrintCallback); + NewRunnableMethod(this, &HTMLCanvasElement::CallPrintCallback); return NS_DispatchToCurrentThread(renderEvent); } diff --git a/dom/html/HTMLFormControlsCollection.cpp b/dom/html/HTMLFormControlsCollection.cpp index f420a6f755..e4f0ab7d9a 100644 --- a/dom/html/HTMLFormControlsCollection.cpp +++ b/dom/html/HTMLFormControlsCollection.cpp @@ -390,13 +390,8 @@ HTMLFormControlsCollection::NamedGetter(const nsAString& aName, } void -HTMLFormControlsCollection::GetSupportedNames(unsigned aFlags, - nsTArray& aNames) +HTMLFormControlsCollection::GetSupportedNames(nsTArray& aNames) { - if (!(aFlags & JSITER_HIDDEN)) { - return; - } - FlushPendingNotifications(); // Just enumerate mNameLookupTable. This won't guarantee order, but // that's OK, because the HTML5 spec doesn't define an order for diff --git a/dom/html/HTMLFormControlsCollection.h b/dom/html/HTMLFormControlsCollection.h index 73f86036e3..1b8e1e62b3 100644 --- a/dom/html/HTMLFormControlsCollection.h +++ b/dom/html/HTMLFormControlsCollection.h @@ -53,8 +53,7 @@ public: bool dummy; NamedGetter(aName, dummy, aResult); } - virtual void GetSupportedNames(unsigned aFlags, - nsTArray& aNames) override; + virtual void GetSupportedNames(nsTArray& aNames) override; nsresult AddElementToTable(nsGenericHTMLFormElement* aChild, const nsAString& aName); diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index 189a2b83ad..b6eae0a462 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -1540,14 +1540,8 @@ HTMLFormElement::NamedGetter(const nsAString& aName, bool &aFound) return nullptr; } -bool -HTMLFormElement::NameIsEnumerable(const nsAString& aName) -{ - return true; -} - void -HTMLFormElement::GetSupportedNames(unsigned, nsTArray& aRetval) +HTMLFormElement::GetSupportedNames(nsTArray& aRetval) { // TODO https://www.w3.org/Bugs/Public/show_bug.cgi?id=22320 } diff --git a/dom/html/HTMLFormElement.h b/dom/html/HTMLFormElement.h index 2bba4f0ce7..f98b387e5d 100644 --- a/dom/html/HTMLFormElement.h +++ b/dom/html/HTMLFormElement.h @@ -393,9 +393,7 @@ public: already_AddRefed NamedGetter(const nsAString& aName, bool &aFound); - bool NameIsEnumerable(const nsAString& aName); - - void GetSupportedNames(unsigned, nsTArray& aRetval); + void GetSupportedNames(nsTArray& aRetval); static int32_t CompareFormControlPosition(Element* aElement1, Element* aElement2, diff --git a/dom/html/HTMLImageElement.cpp b/dom/html/HTMLImageElement.cpp index 63daceb986..0e643e16af 100644 --- a/dom/html/HTMLImageElement.cpp +++ b/dom/html/HTMLImageElement.cpp @@ -614,7 +614,7 @@ HTMLImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, // loading. if (LoadingEnabled()) { nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &HTMLImageElement::MaybeLoadImage)); + NewRunnableMethod(this, &HTMLImageElement::MaybeLoadImage)); } } @@ -821,7 +821,7 @@ HTMLImageElement::CopyInnerTo(Element* aDest) if (!dest->InResponsiveMode() && dest->HasAttr(kNameSpaceID_None, nsGkAtoms::src)) { nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(dest, &HTMLImageElement::MaybeLoadImage)); + NewRunnableMethod(dest, &HTMLImageElement::MaybeLoadImage)); } } diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index 3ad434d7e1..0060c0caf0 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -4353,7 +4353,7 @@ HTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, ClearBrokenState(); RemoveStatesSilently(NS_EVENT_STATE_BROKEN); nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &HTMLInputElement::MaybeLoadImage)); + NewRunnableMethod(this, &HTMLInputElement::MaybeLoadImage)); } } diff --git a/dom/html/HTMLLinkElement.cpp b/dom/html/HTMLLinkElement.cpp index ab7a37d9ee..8de01a6f08 100644 --- a/dom/html/HTMLLinkElement.cpp +++ b/dom/html/HTMLLinkElement.cpp @@ -184,10 +184,10 @@ HTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, } void (HTMLLinkElement::*update)() = &HTMLLinkElement::UpdateStyleSheetInternal; - nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update)); + nsContentUtils::AddScriptRunner(NewRunnableMethod(this, update)); void (HTMLLinkElement::*updateImport)() = &HTMLLinkElement::UpdateImport; - nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, updateImport)); + nsContentUtils::AddScriptRunner(NewRunnableMethod(this, updateImport)); CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMLinkAdded")); diff --git a/dom/html/HTMLMediaElement.cpp b/dom/html/HTMLMediaElement.cpp index 90c71ff66f..7418a3a9b9 100644 --- a/dom/html/HTMLMediaElement.cpp +++ b/dom/html/HTMLMediaElement.cpp @@ -827,8 +827,8 @@ void HTMLMediaElement::QueueLoadFromSourceTask() { ChangeDelayLoadStatus(true); ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_LOADING); - RunInStableState( - NS_NewRunnableMethod(this, &HTMLMediaElement::LoadFromSourceChildren)); + RefPtr r = NewRunnableMethod(this, &HTMLMediaElement::LoadFromSourceChildren); + RunInStableState(r); } void HTMLMediaElement::QueueSelectResourceTask() @@ -838,8 +838,8 @@ void HTMLMediaElement::QueueSelectResourceTask() return; mHaveQueuedSelectResource = true; ChangeNetworkState(nsIDOMHTMLMediaElement::NETWORK_NO_SOURCE); - RunInStableState( - NS_NewRunnableMethod(this, &HTMLMediaElement::SelectResourceWrapper)); + RefPtr r = NewRunnableMethod(this, &HTMLMediaElement::SelectResourceWrapper); + RunInStableState(r); } NS_IMETHODIMP HTMLMediaElement::Load() @@ -1147,16 +1147,6 @@ static bool IsAutoplayEnabled() return Preferences::GetBool("media.autoplay.enabled"); } -static bool IsScriptedAutoplayEnabled() -{ - return Preferences::GetBool("media.autoplay.allowscripted"); -} - -static bool UseAudioChannelAPI() -{ - return Preferences::GetBool("media.useAudioChannelAPI"); -} - void HTMLMediaElement::UpdatePreloadAction() { PreloadAction nextAction = PRELOAD_UNDEFINED; @@ -2213,6 +2203,7 @@ HTMLMediaElement::HTMLMediaElement(already_AddRefed& aNo mAutoplayEnabled(true), mPaused(true), mMuted(0), + mAudioChannelSuspended(nsISuspendedTypes::NONE_SUSPENDED), mStatsShowing(false), mAllowCasting(false), mIsCasting(false), @@ -2373,21 +2364,7 @@ HTMLMediaElement::Play(ErrorResult& aRv) nsresult HTMLMediaElement::PlayInternal(bool aCallerIsChrome) { - // Prevent media element from being auto-started by a script when - // media.autoplay.enabled=false - if (!mHasUserInteraction - && !IsAutoplayEnabled() - && !IsScriptedAutoplayEnabled() - && !EventStateManager::IsHandlingUserInput() - && !aCallerIsChrome) { - LOG(LogLevel::Debug, ("%p Blocked attempt to autoplay media.", this)); -#if defined(MOZ_WIDGET_ANDROID) - nsContentUtils::DispatchTrustedEvent(OwnerDoc(), - static_cast(this), - NS_LITERAL_STRING("MozAutoplayMediaBlocked"), - false, - false); -#endif + if (!IsAllowedToPlay()) { return NS_OK; } @@ -2452,6 +2429,8 @@ HTMLMediaElement::PlayInternal(bool aCallerIsChrome) mPaused = false; mAutoplaying = false; + SetAudioChannelSuspended(nsISuspendedTypes::NONE_SUSPENDED); + // We changed mPaused and mAutoplaying which can affect AddRemoveSelfReference // and our preload status. AddRemoveSelfReference(); @@ -2768,7 +2747,7 @@ nsresult HTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParen if (mDecoder) { // When the MediaElement is binding to tree, the dormant status is // aligned to document's hidden status. - mDecoder->NotifyOwnerActivityChanged(); + mDecoder->NotifyOwnerActivityChanged(!IsHidden()); } return rv; @@ -2857,7 +2836,7 @@ void HTMLMediaElement::UnbindFromTree(bool aDeep, if (mDecoder) { MOZ_ASSERT(IsHidden()); - mDecoder->NotifyOwnerActivityChanged(); + mDecoder->NotifyOwnerActivityChanged(false); } } @@ -3145,9 +3124,9 @@ public: { nsCOMPtr event; if (aBlocked == BLOCKED) { - event = NS_NewRunnableMethod(this, &StreamListener::DoNotifyBlocked); + event = NewRunnableMethod(this, &StreamListener::DoNotifyBlocked); } else { - event = NS_NewRunnableMethod(this, &StreamListener::DoNotifyUnblocked); + event = NewRunnableMethod(this, &StreamListener::DoNotifyUnblocked); } aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); } @@ -3156,7 +3135,7 @@ public: { if (event == EVENT_FINISHED) { nsCOMPtr event = - NS_NewRunnableMethod(this, &StreamListener::DoNotifyFinished); + NewRunnableMethod(this, &StreamListener::DoNotifyFinished); aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); } } @@ -3164,7 +3143,7 @@ public: { MutexAutoLock lock(mMutex); nsCOMPtr event = - NS_NewRunnableMethod(this, &StreamListener::DoNotifyHaveCurrentData); + NewRunnableMethod(this, &StreamListener::DoNotifyHaveCurrentData); aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); } virtual void NotifyOutput(MediaStreamGraph* aGraph, @@ -3175,7 +3154,7 @@ public: return; mPendingNotifyOutput = true; nsCOMPtr event = - NS_NewRunnableMethod(this, &StreamListener::DoNotifyOutput); + NewRunnableMethod(this, &StreamListener::DoNotifyOutput); aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); } @@ -3225,11 +3204,13 @@ public: const VideoSegment& video = static_cast(aQueuedMedia); for (VideoSegment::ConstChunkIterator c(video); !c.IsEnded(); c.Next()) { if (c->mFrame.GetIntrinsicSize() != gfx::IntSize(0,0)) { + mInitialSizeFound = true; nsCOMPtr event = - NS_NewRunnableMethodWithArgs( + NewRunnableMethod( this, &StreamSizeListener::ReceivedSize, c->mFrame.GetIntrinsicSize()); aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); + return; } } } @@ -3346,6 +3327,10 @@ void HTMLMediaElement::UpdateSrcMediaStreamPlaying(uint32_t aFlags) mMediaStreamListener->Forget(); mMediaStreamListener = nullptr; } + + // If the input is a media stream, we don't check its data and always regard + // it as audible when it's playing. + NotifyAudibleStateChanged(shouldPlay); } void HTMLMediaElement::SetupSrcMediaStreamPlayback(DOMMediaStream* aStream) @@ -4453,12 +4438,7 @@ bool HTMLMediaElement::IsBeingDestroyed() void HTMLMediaElement::NotifyOwnerDocumentActivityChanged() { bool pauseElement = NotifyOwnerDocumentActivityChangedInternal(); - if (pauseElement && mAudioChannelAgent && - // On B2G, NotifyOwnerDocumentActivityChangedInternal may return true for - // two reasons: the document no longer being active, or the element being - // paused by the audio channel. However we are only interested in the - // first case here, so we need to filter out the second case. - (!UseAudioChannelAPI() || !ComputedMuted())) { + if (pauseElement && mAudioChannelAgent) { // If the element is being paused since we are navigating away from the // document, notify the audio channel agent. // Be careful to ignore this event during a docshell frame swap. @@ -4475,21 +4455,11 @@ void HTMLMediaElement::NotifyOwnerDocumentActivityChanged() bool HTMLMediaElement::NotifyOwnerDocumentActivityChangedInternal() { - nsIDocument* ownerDoc = OwnerDoc(); if (mDecoder && !IsBeingDestroyed()) { - mDecoder->SetElementVisibility(!ownerDoc->Hidden()); - mDecoder->NotifyOwnerActivityChanged(); + mDecoder->NotifyOwnerActivityChanged(!IsHidden()); } bool pauseElement = !IsActive(); - // Only pause the element when we start playing. If we pause without playing - // audio, the resource loading would be affected unexpectedly. For example, - // the media element is muted by default, but we don't want this behavior - // interrupting the loading process. - if (UseAudioChannelAPI() && mAudioChannelAgent) { - pauseElement |= ComputedMuted(); - } - SuspendOrResumeElement(pauseElement, !IsActive()); if (!mPausedForInactiveDocumentOrChannel && @@ -4537,7 +4507,7 @@ void HTMLMediaElement::AddRemoveSelfReference() // Dispatch Release asynchronously so that we don't destroy this object // inside a call stack of method calls on this object nsCOMPtr event = - NS_NewRunnableMethod(this, &HTMLMediaElement::DoRemoveSelfReference); + NewRunnableMethod(this, &HTMLMediaElement::DoRemoveSelfReference); NS_DispatchToMainThread(event); } } @@ -4903,33 +4873,6 @@ ImageContainer* HTMLMediaElement::GetImageContainer() return container ? container->GetImageContainer() : nullptr; } -nsresult HTMLMediaElement::UpdateChannelMuteState(float aVolume, bool aMuted) -{ - if (mAudioChannelVolume != aVolume) { - mAudioChannelVolume = aVolume; - SetVolumeInternal(); - } - - // We have to mute this channel. - if (aMuted && !ComputedMuted()) { - SetMutedInternal(mMuted | MUTED_BY_AUDIO_CHANNEL); - if (UseAudioChannelAPI()) { - DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptbegin")); - } - } else if (!aMuted && ComputedMuted()) { - SetMutedInternal(mMuted & ~MUTED_BY_AUDIO_CHANNEL); - if (UseAudioChannelAPI()) { - DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptend")); - } - } - - if (UseAudioChannelAPI()) { - SuspendOrResumeElement(ComputedMuted(), false); - } - - return NS_OK; -} - bool HTMLMediaElement::MaybeCreateAudioChannelAgent() { @@ -4950,6 +4893,11 @@ HTMLMediaElement::MaybeCreateAudioChannelAgent() bool HTMLMediaElement::IsPlayingThroughTheAudioChannel() const { + // It might be resumed from remote, we should keep the audio channel agent. + if (IsSuspendedByAudioChannel()) { + return true; + } + // Are we paused or muted if (mPaused || Muted()) { return false; @@ -5026,29 +4974,197 @@ HTMLMediaElement::NotifyAudioChannelAgent(bool aPlaying) AutoNoJSAPI nojsapi; if (aPlaying) { - float volume = 0.0; - bool muted = true; - mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted); - WindowVolumeChanged(volume, muted); + // The reason we don't call NotifyStartedPlaying after the media element + // really becomes audible is because there is another case needs to block + // element as early as we can, we would hear sound leaking if we block it + // too late. In that case (block autoplay in non-visited-tab), we need to + // create a connection before decoding, because we don't want user hearing + // any sound. + AudioPlaybackConfig config; + nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config, + mIsAudioTrackAudible); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + WindowVolumeChanged(config.mVolume, config.mMuted); + WindowSuspendChanged(config.mSuspend); } else { mAudioChannelAgent->NotifyStoppedPlaying(); mAudioChannelAgent = nullptr; } } -NS_IMETHODIMP HTMLMediaElement::WindowVolumeChanged(float aVolume, bool aMuted) +NS_IMETHODIMP +HTMLMediaElement::WindowVolumeChanged(float aVolume, bool aMuted) { - MOZ_ASSERT(NS_IsMainThread()); + MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug, + ("HTMLMediaElement, WindowVolumeChanged, this = %p, " + "aVolume = %f, aMuted = %d\n", this, aVolume, aMuted)); - UpdateChannelMuteState(aVolume, aMuted); + if (mAudioChannelVolume != aVolume) { + mAudioChannelVolume = aVolume; + SetVolumeInternal(); + } - if (UseAudioChannelAPI()) { - mPaused.SetCanPlay(!aMuted); + if (aMuted && !ComputedMuted()) { + SetMutedInternal(mMuted | MUTED_BY_AUDIO_CHANNEL); + } else if (!aMuted && ComputedMuted()) { + SetMutedInternal(mMuted & ~MUTED_BY_AUDIO_CHANNEL); } return NS_OK; } +NS_IMETHODIMP +HTMLMediaElement::WindowSuspendChanged(SuspendTypes aSuspend) +{ + MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug, + ("HTMLMediaElement, WindowSuspendChanged, this = %p, " + "aSuspend = %d\n", this, aSuspend)); + + switch (aSuspend) { + case nsISuspendedTypes::NONE_SUSPENDED: + ResumeFromAudioChannel(); + break; + case nsISuspendedTypes::SUSPENDED_PAUSE: + case nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE: + PauseByAudioChannel(aSuspend); + break; + case nsISuspendedTypes::SUSPENDED_BLOCK: + BlockByAudioChannel(); + break; + case nsISuspendedTypes::SUSPENDED_STOP_DISPOSABLE: + Pause(); + break; + default: + MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug, + ("HTMLMediaElement, WindowSuspendChanged, this = %p, " + "Error : unknown suspended type!\n", this)); + } + + return NS_OK; +} + +void +HTMLMediaElement::ResumeFromAudioChannel() +{ + if (!IsSuspendedByAudioChannel()) { + return; + } + + switch (mAudioChannelSuspended) { + case nsISuspendedTypes::SUSPENDED_PAUSE: + case nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE: + ResumeFromAudioChannelPaused(mAudioChannelSuspended); + break; + case nsISuspendedTypes::SUSPENDED_BLOCK: + ResumeFromAudioChannelBlocked(); + break; + default: + MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug, + ("HTMLMediaElement, ResumeFromAudioChannel, this = %p, " + "Error : resume without suspended!\n", this)); + } +} + +void +HTMLMediaElement::ResumeFromAudioChannelPaused(SuspendTypes aSuspend) +{ + MOZ_ASSERT(mAudioChannelSuspended == nsISuspendedTypes::SUSPENDED_PAUSE || + mAudioChannelSuspended == nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE); + + SetAudioChannelSuspended(nsISuspendedTypes::NONE_SUSPENDED); + nsresult rv = PlayInternal(nsContentUtils::IsCallerChrome()); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptend")); +} + +void +HTMLMediaElement::ResumeFromAudioChannelBlocked() +{ + MOZ_ASSERT(mAudioChannelSuspended == nsISuspendedTypes::SUSPENDED_BLOCK); + + SetAudioChannelSuspended(nsISuspendedTypes::NONE_SUSPENDED); + mPaused.SetCanPlay(true); + SuspendOrResumeElement(false /* resume */, false); +} + +void +HTMLMediaElement::PauseByAudioChannel(SuspendTypes aSuspend) +{ + if (IsSuspendedByAudioChannel()) { + return; + } + + SetAudioChannelSuspended(aSuspend); + Pause(); + DispatchAsyncEvent(NS_LITERAL_STRING("mozinterruptbegin")); +} + +void +HTMLMediaElement::BlockByAudioChannel() +{ + if (IsSuspendedByAudioChannel()) { + return; + } + + SetAudioChannelSuspended(nsISuspendedTypes::SUSPENDED_BLOCK); + SuspendOrResumeElement(true /* suspend */, false); + mPaused.SetCanPlay(false); +} + +void +HTMLMediaElement::SetAudioChannelSuspended(SuspendTypes aSuspend) +{ + if (mAudioChannelSuspended == aSuspend) { + return; + } + + mAudioChannelSuspended = aSuspend; + MOZ_LOG(AudioChannelService::GetAudioChannelLog(), LogLevel::Debug, + ("HTMLMediaElement, SetAudioChannelSuspended, this = %p, " + "aSuspend = %d\n", this, aSuspend)); +} + +bool +HTMLMediaElement::IsSuspendedByAudioChannel() const +{ + return (mAudioChannelSuspended == nsISuspendedTypes::SUSPENDED_PAUSE || + mAudioChannelSuspended == nsISuspendedTypes::SUSPENDED_PAUSE_DISPOSABLE || + mAudioChannelSuspended == nsISuspendedTypes::SUSPENDED_BLOCK); +} + +bool +HTMLMediaElement::IsAllowedToPlay() +{ + // Prevent media element from being auto-started by a script when + // media.autoplay.enabled=false + if (!mHasUserInteraction && + !IsAutoplayEnabled() && + !EventStateManager::IsHandlingUserInput() && + !nsContentUtils::IsCallerChrome()) { +#if defined(MOZ_WIDGET_ANDROID) + nsContentUtils::DispatchTrustedEvent(OwnerDoc(), + static_cast(this), + NS_LITERAL_STRING("MozAutoplayMediaBlocked"), + false, + false); +#endif + return false; + } + + // The MediaElement can't start playback until it's resumed by audio channel. + if (mAudioChannelSuspended == nsISuspendedTypes::SUSPENDED_PAUSE || + mAudioChannelSuspended == nsISuspendedTypes::SUSPENDED_BLOCK) { + return false; + } + + return true; +} + #ifdef MOZ_EME MediaKeys* HTMLMediaElement::GetMediaKeys() const @@ -5388,6 +5504,12 @@ HTMLMediaElement::ComputedMuted() const return (mMuted & MUTED_BY_AUDIO_CHANNEL); } +nsSuspendedTypes +HTMLMediaElement::ComputedSuspended() const +{ + return mAudioChannelSuspended; +} + bool HTMLMediaElement::IsCurrentlyPlaying() const { @@ -5414,7 +5536,15 @@ HTMLMediaElement::NotifyAudibleStateChanged(bool aAudible) { if (mIsAudioTrackAudible != aAudible) { mIsAudioTrackAudible = aAudible; - // To do ... + NotifyAudioPlaybackChanged(); + } +} + +void +HTMLMediaElement::NotifyAudioPlaybackChanged() +{ + if (mAudioChannelAgent) { + mAudioChannelAgent->NotifyStartedAudible(mIsAudioTrackAudible); } } diff --git a/dom/html/HTMLMediaElement.h b/dom/html/HTMLMediaElement.h index c114270e6e..d7ffed5e03 100644 --- a/dom/html/HTMLMediaElement.h +++ b/dom/html/HTMLMediaElement.h @@ -35,6 +35,7 @@ typedef uint16_t nsMediaNetworkState; typedef uint16_t nsMediaReadyState; +typedef uint32_t SuspendTypes; namespace mozilla { class DecoderDoctorDiagnostics; @@ -448,9 +449,13 @@ public: // when the connection between Rtsp server and client gets lost. virtual void ResetConnectionState() final override; - // Called by media decoder when the audible state changed. + // Called by media decoder when the audible state changed or when input is + // a media stream. virtual void NotifyAudibleStateChanged(bool aAudible) final override; + // Notify agent when the MediaElement changes its audible state. + void NotifyAudioPlaybackChanged(); + // XPCOM GetPreload() is OK void SetPreload(const nsAString& aValue, ErrorResult& aRv) { @@ -719,9 +724,10 @@ public: IMPL_EVENT_HANDLER(mozinterruptbegin) IMPL_EVENT_HANDLER(mozinterruptend) - // This is for testing only + // These are used for testing only float ComputedVolume() const; bool ComputedMuted() const; + nsSuspendedTypes ComputedSuspended() const; protected: virtual ~HTMLMediaElement(); @@ -1112,9 +1118,6 @@ protected: // Check the permissions for audiochannel. bool CheckAudioChannelPermissions(const nsAString& aType); - // This method does the check for muting/nmuting the audio channel. - nsresult UpdateChannelMuteState(float aVolume, bool aMuted); - // Seeks to aTime seconds. aSeekType can be Exact to seek to exactly the // seek target, or PrevSyncPoint if a quicker but less precise seek is // desired, and we'll seek to the sync point (keyframe and/or start of the @@ -1149,6 +1152,38 @@ protected: // channel agent is ready to be used. bool MaybeCreateAudioChannelAgent(); + /** + * We have different kinds of suspended cases, + * - SUSPENDED_PAUSE + * It's used when we temporary lost platform audio focus. MediaElement can + * only be resumed when we gain the audio focus again. + * + * - SUSPENDED_PAUSE_DISPOSABLE + * It's used when user press the pause botton on the remote media-control. + * MediaElement can be resumed by reomte media-control or via play(). + * + * - SUSPENDED_BLOCK + * It's used to reduce the power comsuption, we won't play the auto-play + * audio/video in the page we have never visited before. MediaElement would + * be resumed when the page is active. See bug647429 for more details. + * + * - SUSPENDED_STOP_DISPOSABLE + * When we permanently lost platform audio focus, we shuold stop playing + * and stop the audio channel agent. MediaElement can only be restarted by + * play(). + */ + void PauseByAudioChannel(SuspendTypes aSuspend); + void BlockByAudioChannel(); + + void ResumeFromAudioChannel(); + void ResumeFromAudioChannelPaused(SuspendTypes aSuspend); + void ResumeFromAudioChannelBlocked(); + + bool IsSuspendedByAudioChannel() const; + void SetAudioChannelSuspended(SuspendTypes aSuspend); + + bool IsAllowedToPlay(); + class nsAsyncEventRunner; using nsGenericHTMLElement::DispatchEvent; // For nsAsyncEventRunner. @@ -1363,6 +1398,7 @@ protected: }; uint32_t mMuted; + SuspendTypes mAudioChannelSuspended; // True if the media statistics are currently being shown by the builtin // video controls diff --git a/dom/html/HTMLObjectElement.cpp b/dom/html/HTMLObjectElement.cpp index a955a0c8bf..f623f2e058 100644 --- a/dom/html/HTMLObjectElement.cpp +++ b/dom/html/HTMLObjectElement.cpp @@ -280,7 +280,7 @@ HTMLObjectElement::BindToTree(nsIDocument *aDocument, // If we already have all the children, start the load. if (mIsDoneAddingChildren && !pluginDoc) { void (HTMLObjectElement::*start)() = &HTMLObjectElement::StartObjectLoad; - nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, start)); + nsContentUtils::AddScriptRunner(NewRunnableMethod(this, start)); } return NS_OK; diff --git a/dom/html/HTMLOptionsCollection.cpp b/dom/html/HTMLOptionsCollection.cpp index 1435706179..1fce684aed 100644 --- a/dom/html/HTMLOptionsCollection.cpp +++ b/dom/html/HTMLOptionsCollection.cpp @@ -280,13 +280,8 @@ HTMLOptionsCollection::NamedItem(const nsAString& aName, } void -HTMLOptionsCollection::GetSupportedNames(unsigned aFlags, - nsTArray& aNames) +HTMLOptionsCollection::GetSupportedNames(nsTArray& aNames) { - if (!(aFlags & JSITER_HIDDEN)) { - return; - } - AutoTArray atoms; for (uint32_t i = 0; i < mElements.Length(); ++i) { HTMLOptionElement* content = mElements.ElementAt(i); diff --git a/dom/html/HTMLOptionsCollection.h b/dom/html/HTMLOptionsCollection.h index 3bdd1e3d61..21123b3d21 100644 --- a/dom/html/HTMLOptionsCollection.h +++ b/dom/html/HTMLOptionsCollection.h @@ -154,8 +154,7 @@ public: { aError = SetOption(aIndex, aOption); } - virtual void GetSupportedNames(unsigned aFlags, - nsTArray& aNames) override; + virtual void GetSupportedNames(nsTArray& aNames) override; private: /** The list of options (holds strong references). This is infallible, so diff --git a/dom/html/HTMLPropertiesCollection.cpp b/dom/html/HTMLPropertiesCollection.cpp index 3eb340a9d0..7ed09376d5 100644 --- a/dom/html/HTMLPropertiesCollection.cpp +++ b/dom/html/HTMLPropertiesCollection.cpp @@ -288,7 +288,7 @@ HTMLPropertiesCollection::CrawlSubtree(Element* aElement) } void -HTMLPropertiesCollection::GetSupportedNames(unsigned, nsTArray& aNames) +HTMLPropertiesCollection::GetSupportedNames(nsTArray& aNames) { EnsureFresh(); mNames->CopyList(aNames); diff --git a/dom/html/HTMLPropertiesCollection.h b/dom/html/HTMLPropertiesCollection.h index 3f5f8ef9f1..d6f086180d 100644 --- a/dom/html/HTMLPropertiesCollection.h +++ b/dom/html/HTMLPropertiesCollection.h @@ -90,17 +90,12 @@ public: aFound = IsSupportedNamedProperty(aName); return aFound ? NamedItem(aName) : nullptr; } - bool NameIsEnumerable(const nsAString& aName) - { - return true; - } DOMStringList* Names() { EnsureFresh(); return mNames; } - virtual void GetSupportedNames(unsigned, - nsTArray& aNames) override; + virtual void GetSupportedNames(nsTArray& aNames) override; NS_DECL_NSIDOMHTMLCOLLECTION diff --git a/dom/html/HTMLSharedObjectElement.cpp b/dom/html/HTMLSharedObjectElement.cpp index 9d28b48165..6d591d1894 100644 --- a/dom/html/HTMLSharedObjectElement.cpp +++ b/dom/html/HTMLSharedObjectElement.cpp @@ -153,7 +153,7 @@ HTMLSharedObjectElement::BindToTree(nsIDocument *aDocument, if (mIsDoneAddingChildren && !pluginDoc) { void (HTMLSharedObjectElement::*start)() = &HTMLSharedObjectElement::StartObjectLoad; - nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, start)); + nsContentUtils::AddScriptRunner(NewRunnableMethod(this, start)); } return NS_OK; diff --git a/dom/html/HTMLStyleElement.cpp b/dom/html/HTMLStyleElement.cpp index ec690fc0b4..ba44c9600c 100644 --- a/dom/html/HTMLStyleElement.cpp +++ b/dom/html/HTMLStyleElement.cpp @@ -147,7 +147,7 @@ HTMLStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, NS_ENSURE_SUCCESS(rv, rv); void (HTMLStyleElement::*update)() = &HTMLStyleElement::UpdateStyleSheetInternal; - nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update)); + nsContentUtils::AddScriptRunner(NewRunnableMethod(this, update)); return rv; } diff --git a/dom/html/HTMLTableElement.cpp b/dom/html/HTMLTableElement.cpp index f3f52bffdb..4dc6b68017 100644 --- a/dom/html/HTMLTableElement.cpp +++ b/dom/html/HTMLTableElement.cpp @@ -41,8 +41,7 @@ public: virtual Element* GetFirstNamedElement(const nsAString& aName, bool& aFound) override; - virtual void GetSupportedNames(unsigned aFlags, - nsTArray& aNames) override; + virtual void GetSupportedNames(nsTArray& aNames) override; NS_IMETHOD ParentDestroyed(); @@ -236,18 +235,13 @@ TableRowsCollection::GetFirstNamedElement(const nsAString& aName, bool& aFound) } void -TableRowsCollection::GetSupportedNames(unsigned aFlags, - nsTArray& aNames) +TableRowsCollection::GetSupportedNames(nsTArray& aNames) { - if (!(aFlags & JSITER_HIDDEN)) { - return; - } - DO_FOR_EACH_ROWGROUP( nsTArray names; nsCOMPtr coll = do_QueryInterface(rows); if (coll) { - coll->GetSupportedNames(aFlags, names); + coll->GetSupportedNames(names); for (uint32_t i = 0; i < names.Length(); ++i) { if (!aNames.Contains(names[i])) { aNames.AppendElement(names[i]); diff --git a/dom/html/HTMLTrackElement.cpp b/dom/html/HTMLTrackElement.cpp index 6a47128dfd..516f648dbe 100644 --- a/dom/html/HTMLTrackElement.cpp +++ b/dom/html/HTMLTrackElement.cpp @@ -260,8 +260,8 @@ HTMLTrackElement::BindToTree(nsIDocument* aDocument, media->NotifyAddedSource(); LOG(LogLevel::Debug, ("Track element sent notification to parent.")); - mMediaParent->RunInStableState( - NS_NewRunnableMethod(this, &HTMLTrackElement::LoadResource)); + RefPtr r = NewRunnableMethod(this, &HTMLTrackElement::LoadResource); + mMediaParent->RunInStableState(r); } return NS_OK; @@ -314,7 +314,7 @@ void HTMLTrackElement::DispatchTrackRunnable(const nsString& aEventName) { nsCOMPtr runnable = - NS_NewRunnableMethodWithArg + NewRunnableMethod (this, &HTMLTrackElement::DispatchTrustedEvent, aEventName); diff --git a/dom/html/ImageDocument.cpp b/dom/html/ImageDocument.cpp index d5c75b68c8..779d59fe77 100644 --- a/dom/html/ImageDocument.cpp +++ b/dom/html/ImageDocument.cpp @@ -473,7 +473,7 @@ ImageDocument::Notify(imgIRequest* aRequest, int32_t aType, const nsIntRect* aDa // come during painting and this will trigger invalidation. if (aType == imgINotificationObserver::HAS_TRANSPARENCY) { nsCOMPtr runnable = - NS_NewRunnableMethod(this, &ImageDocument::OnHasTransparency); + NewRunnableMethod(this, &ImageDocument::OnHasTransparency); nsContentUtils::AddScriptRunner(runnable); } @@ -534,7 +534,7 @@ ImageDocument::OnSizeAvailable(imgIRequest* aRequest, imgIContainer* aImage) aImage->GetHeight(&mImageHeight); nsCOMPtr runnable = - NS_NewRunnableMethod(this, &ImageDocument::DefaultCheckOverflowing); + NewRunnableMethod(this, &ImageDocument::DefaultCheckOverflowing); nsContentUtils::AddScriptRunner(runnable); UpdateTitleAndCharset(); diff --git a/dom/html/nsDOMStringMap.cpp b/dom/html/nsDOMStringMap.cpp index a476ab1e86..e9cac5e38c 100644 --- a/dom/html/nsDOMStringMap.cpp +++ b/dom/html/nsDOMStringMap.cpp @@ -89,12 +89,6 @@ nsDOMStringMap::NamedGetter(const nsAString& aProp, bool& found, found = mElement->GetAttr(attr, aResult); } -bool -nsDOMStringMap::NameIsEnumerable(const nsAString& aName) -{ - return true; -} - void nsDOMStringMap::NamedSetter(const nsAString& aProp, const nsAString& aValue, @@ -149,7 +143,7 @@ nsDOMStringMap::NamedDeleter(const nsAString& aProp, bool& found) } void -nsDOMStringMap::GetSupportedNames(unsigned, nsTArray& aNames) +nsDOMStringMap::GetSupportedNames(nsTArray& aNames) { uint32_t attrCount = mElement->GetAttrCount(); diff --git a/dom/html/nsDOMStringMap.h b/dom/html/nsDOMStringMap.h index e38e71351a..ffb6ab5257 100644 --- a/dom/html/nsDOMStringMap.h +++ b/dom/html/nsDOMStringMap.h @@ -42,8 +42,7 @@ public: void NamedSetter(const nsAString& aProp, const nsAString& aValue, mozilla::ErrorResult& rv); void NamedDeleter(const nsAString& aProp, bool &found); - bool NameIsEnumerable(const nsAString& aName); - void GetSupportedNames(unsigned, nsTArray& aNames); + void GetSupportedNames(nsTArray& aNames); js::ExpandoAndGeneration mExpandoAndGeneration; diff --git a/dom/html/nsHTMLDocument.cpp b/dom/html/nsHTMLDocument.cpp index 529507ae2f..f49f5ab864 100644 --- a/dom/html/nsHTMLDocument.cpp +++ b/dom/html/nsHTMLDocument.cpp @@ -2326,14 +2326,8 @@ nsHTMLDocument::NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound, aRetval.set(&val.toObject()); } -bool -nsHTMLDocument::NameIsEnumerable(const nsAString& aName) -{ - return true; -} - void -nsHTMLDocument::GetSupportedNames(unsigned, nsTArray& aNames) +nsHTMLDocument::GetSupportedNames(nsTArray& aNames) { for (auto iter = mIdentifierMap.Iter(); !iter.Done(); iter.Next()) { nsIdentifierMapEntry* entry = iter.Get(); @@ -2506,7 +2500,7 @@ nsHTMLDocument::MaybeEditingStateChanged() EditingStateChanged(); } else if (!mInDestructor) { nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &nsHTMLDocument::MaybeEditingStateChanged)); + NewRunnableMethod(this, &nsHTMLDocument::MaybeEditingStateChanged)); } } } diff --git a/dom/html/nsHTMLDocument.h b/dom/html/nsHTMLDocument.h index 5568b8da29..011ca1e84f 100644 --- a/dom/html/nsHTMLDocument.h +++ b/dom/html/nsHTMLDocument.h @@ -174,8 +174,7 @@ public: void NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound, JS::MutableHandle aRetval, mozilla::ErrorResult& rv); - bool NameIsEnumerable(const nsAString& aName); - void GetSupportedNames(unsigned, nsTArray& aNames); + void GetSupportedNames(nsTArray& aNames); nsGenericHTMLElement *GetBody(); void SetBody(nsGenericHTMLElement* aBody, mozilla::ErrorResult& rv); mozilla::dom::HTMLSharedElement *GetHead() { diff --git a/dom/html/nsIHTMLCollection.h b/dom/html/nsIHTMLCollection.h index 11925ab177..7dbfe87665 100644 --- a/dom/html/nsIHTMLCollection.h +++ b/dom/html/nsIHTMLCollection.h @@ -69,15 +69,10 @@ public: { return GetFirstNamedElement(aName, aFound); } - bool NameIsEnumerable(const nsAString& aName) - { - return false; - } virtual mozilla::dom::Element* GetFirstNamedElement(const nsAString& aName, bool& aFound) = 0; - virtual void GetSupportedNames(unsigned aFlags, - nsTArray& aNames) = 0; + virtual void GetSupportedNames(nsTArray& aNames) = 0; JSObject* GetWrapperPreserveColor() { diff --git a/dom/indexedDB/ActorsParent.cpp b/dom/indexedDB/ActorsParent.cpp index e316f4c6c9..d59451ecf7 100644 --- a/dom/indexedDB/ActorsParent.cpp +++ b/dom/indexedDB/ActorsParent.cpp @@ -11599,7 +11599,7 @@ ConnectionPool::ShutdownThread(ThreadInfo& aThreadInfo) MOZ_ALWAYS_SUCCEEDS(thread->Dispatch(runnable, NS_DISPATCH_NORMAL)); nsCOMPtr shutdownRunnable = - NS_NewRunnableMethod(thread, &nsIThread::Shutdown); + NewRunnableMethod(thread, &nsIThread::Shutdown); MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(shutdownRunnable)); mTotalThreadCount--; @@ -13451,7 +13451,7 @@ Database::MaybeCloseConnection() IsClosed() && mDirectoryLock) { nsCOMPtr callback = - NS_NewRunnableMethod(this, &Database::ConnectionClosedCallback); + NewRunnableMethod(this, &Database::ConnectionClosedCallback); RefPtr helper = new WaitForTransactionsHelper(Id(), callback); @@ -17153,7 +17153,7 @@ QuotaClient::StartIdleMaintenance() } nsCOMPtr runnable = - NS_NewRunnableMethodWithArg( + NewRunnableMethod( this, &QuotaClient::FindDatabasesForIdleMaintenance, mMaintenanceRunId); @@ -17379,7 +17379,7 @@ QuotaClient::FindDatabasesForIdleMaintenance(uint32_t aRunId) if (!databasePaths.IsEmpty()) { nsCOMPtr runnable = - NS_NewRunnableMethodWithArgs( + NewRunnableMethod( this, &QuotaClient::GetDirectoryLockForIdleMaintenance, aRunId, @@ -17448,7 +17448,7 @@ QuotaClient::ScheduleIdleMaintenance(uint32_t aRunId, for (const nsString& databasePath : aMaintenanceInfo.mDatabasePaths) { nsCOMPtr runnable = - NS_NewRunnableMethodWithArgs( this, @@ -17483,7 +17483,7 @@ QuotaClient::PerformIdleMaintenanceOnDatabase( PerformIdleMaintenanceOnDatabaseInternal(aRunId, aMaintenanceInfo); nsCOMPtr runnable = - NS_NewRunnableMethodWithArgs( + NewRunnableMethod( this, &QuotaClient::MaybeReleaseDirectoryLockForIdleMaintenance, aKey, @@ -21084,7 +21084,7 @@ OpenDatabaseOp::SendResults() mDatabase = nullptr; } else if (mDirectoryLock) { nsCOMPtr callback = - NS_NewRunnableMethod(this, &OpenDatabaseOp::ConnectionClosedCallback); + NewRunnableMethod(this, &OpenDatabaseOp::ConnectionClosedCallback); RefPtr helper = new WaitForTransactionsHelper(mDatabaseId, callback); diff --git a/dom/indexedDB/FileSnapshot.cpp b/dom/indexedDB/FileSnapshot.cpp index 3faecdd62e..f4f0d6dd57 100644 --- a/dom/indexedDB/FileSnapshot.cpp +++ b/dom/indexedDB/FileSnapshot.cpp @@ -87,7 +87,7 @@ private: } nsCOMPtr destroyRunnable = - NS_NewNonOwningRunnableMethod(this, &StreamWrapper::Destroy); + NewNonOwningRunnableMethod(this, &StreamWrapper::Destroy); MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(destroyRunnable, NS_DISPATCH_NORMAL)); diff --git a/dom/indexedDB/IDBDatabase.cpp b/dom/indexedDB/IDBDatabase.cpp index 4e08c1e2af..fa8eab4ebb 100644 --- a/dom/indexedDB/IDBDatabase.cpp +++ b/dom/indexedDB/IDBDatabase.cpp @@ -1038,9 +1038,9 @@ IDBDatabase::DelayedMaybeExpireFileActors() } nsCOMPtr runnable = - NS_NewRunnableMethodWithArg(this, - &IDBDatabase::ExpireFileActors, - /* aExpireAll */ false); + NewRunnableMethod(this, + &IDBDatabase::ExpireFileActors, + /* aExpireAll */ false); MOZ_ASSERT(runnable); if (!NS_IsMainThread()) { diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index b17472a0fc..e0488b1872 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -1744,10 +1744,10 @@ interface nsIDOMWindowUtils : nsISupports { void postRestyleSelfEvent(in nsIDOMElement aElement); /** - * Used to pause or resume all MediaElements in this window. Use-cases are - * audio competing and remote media control. + * Used to pause or resume all media in this window. Use-cases are audio + * competing, remote media control and to prevent auto-playing media. */ - attribute boolean mediaSuspended; + attribute uint32_t mediaSuspend; /** * With this it's possible to mute all the MediaElements in this window. diff --git a/dom/ipc/Blob.cpp b/dom/ipc/Blob.cpp index adddee64e2..263324bf87 100644 --- a/dom/ipc/Blob.cpp +++ b/dom/ipc/Blob.cpp @@ -293,7 +293,7 @@ ReleaseOnTarget(SmartPtr& aDoomed, nsIEventTarget* aTarget) auto* doomedSupports = static_cast(doomedRaw); nsCOMPtr releaseRunnable = - NS_NewNonOwningRunnableMethod(doomedSupports, &nsISupports::Release); + NewNonOwningRunnableMethod(doomedSupports, &nsISupports::Release); MOZ_ASSERT(releaseRunnable); if (aTarget) { @@ -1600,11 +1600,7 @@ private: NS_WARN_IF_FALSE(NS_SUCCEEDED(stream->Close()), "Failed to close stream!"); - nsCOMPtr shutdownRunnable = - NS_NewRunnableMethod(ioTarget, &nsIThread::Shutdown); - MOZ_ASSERT(shutdownRunnable); - - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(shutdownRunnable)); + MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(NewRunnableMethod(ioTarget, &nsIThread::Shutdown))); return NS_OK; } @@ -2138,7 +2134,7 @@ RemoteBlobImpl::Destroy() } nsCOMPtr destroyRunnable = - NS_NewNonOwningRunnableMethod(this, &RemoteBlobImpl::Destroy); + NewNonOwningRunnableMethod(this, &RemoteBlobImpl::Destroy); if (mActorTarget) { destroyRunnable = @@ -2566,7 +2562,7 @@ RemoteBlobImpl::Destroy() } nsCOMPtr destroyRunnable = - NS_NewNonOwningRunnableMethod(this, &RemoteBlobImpl::Destroy); + NewNonOwningRunnableMethod(this, &RemoteBlobImpl::Destroy); if (mActorTarget) { destroyRunnable = @@ -3422,7 +3418,7 @@ BlobChild::NoteDyingRemoteBlobImpl() // on the owning thread, so we proxy here if necessary. if (!IsOnOwningThread()) { nsCOMPtr runnable = - NS_NewNonOwningRunnableMethod(this, &BlobChild::NoteDyingRemoteBlobImpl); + NewNonOwningRunnableMethod(this, &BlobChild::NoteDyingRemoteBlobImpl); if (mEventTarget) { runnable = new CancelableRunnableWrapper(runnable, mEventTarget); @@ -4001,7 +3997,7 @@ BlobParent::NoteDyingRemoteBlobImpl() // on the main thread, so we proxy here if necessary. if (!IsOnOwningThread()) { nsCOMPtr runnable = - NS_NewNonOwningRunnableMethod(this, &BlobParent::NoteDyingRemoteBlobImpl); + NewNonOwningRunnableMethod(this, &BlobParent::NoteDyingRemoteBlobImpl); if (mEventTarget) { runnable = new CancelableRunnableWrapper(runnable, mEventTarget); diff --git a/dom/ipc/ContentBridgeChild.cpp b/dom/ipc/ContentBridgeChild.cpp index 30dbfc720f..d40d9d5a2d 100644 --- a/dom/ipc/ContentBridgeChild.cpp +++ b/dom/ipc/ContentBridgeChild.cpp @@ -34,8 +34,7 @@ ContentBridgeChild::~ContentBridgeChild() void ContentBridgeChild::ActorDestroy(ActorDestroyReason aWhy) { - MessageLoop::current()->PostTask( - NewRunnableMethod(this, &ContentBridgeChild::DeferredDestroy)); + MessageLoop::current()->PostTask(NewRunnableMethod(this, &ContentBridgeChild::DeferredDestroy)); } /*static*/ ContentBridgeChild* diff --git a/dom/ipc/ContentBridgeParent.cpp b/dom/ipc/ContentBridgeParent.cpp index 608f7f2abc..e71febd056 100644 --- a/dom/ipc/ContentBridgeParent.cpp +++ b/dom/ipc/ContentBridgeParent.cpp @@ -37,8 +37,7 @@ ContentBridgeParent::ActorDestroy(ActorDestroyReason aWhy) if (os) { os->RemoveObserver(this, "content-child-shutdown"); } - MessageLoop::current()->PostTask( - NewRunnableMethod(this, &ContentBridgeParent::DeferredDestroy)); + MessageLoop::current()->PostTask(NewRunnableMethod(this, &ContentBridgeParent::DeferredDestroy)); } /*static*/ ContentBridgeParent* @@ -168,8 +167,7 @@ ContentBridgeParent::NotifyTabDestroyed() { int32_t numLiveTabs = ManagedPBrowserParent().Count(); if (numLiveTabs == 1) { - MessageLoop::current()->PostTask( - NewRunnableMethod(this, &ContentBridgeParent::Close)); + MessageLoop::current()->PostTask(NewRunnableMethod(this, &ContentBridgeParent::Close)); } } diff --git a/dom/ipc/ContentBridgeParent.h b/dom/ipc/ContentBridgeParent.h index 2094bc8251..18c46d4325 100644 --- a/dom/ipc/ContentBridgeParent.h +++ b/dom/ipc/ContentBridgeParent.h @@ -79,6 +79,12 @@ protected: mIsForBrowser = aIsForBrowser; } + void Close() + { + // Trick NewRunnableMethod + PContentBridgeParent::Close(); + } + protected: virtual bool RecvSyncMessage(const nsString& aMsg, diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index a31e1c3328..8219a3cf05 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1573,7 +1573,7 @@ ContentChild::RecvPBrowserConstructor(PBrowserChild* aActor, hasRunOnce = true; MOZ_ASSERT(!sFirstIdleTask); - RefPtr firstIdleTask = NewRunnableFunction(FirstIdle); + RefPtr firstIdleTask = NewCancelableRunnableFunction(FirstIdle); sFirstIdleTask = firstIdleTask; MessageLoop::current()->PostIdleTask(firstIdleTask.forget()); diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 9dba21f430..a95428f36e 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -81,6 +81,7 @@ #include "mozilla/jsipc/CrossProcessObjectWrappers.h" #include "mozilla/layers/PAPZParent.h" #include "mozilla/layers/CompositorBridgeParent.h" +#include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/ImageBridgeParent.h" #include "mozilla/layers/SharedBufferManagerParent.h" #include "mozilla/layout/RenderFrameParent.h" @@ -2166,9 +2167,10 @@ ContentParent::ActorDestroy(ActorDestroyReason why) // Destroy any processes created by this ContentParent for(uint32_t i = 0; i < childIDArray.Length(); i++) { ContentParent* cp = cpm->GetContentProcessById(childIDArray[i]); - MessageLoop::current()->PostTask( - NewRunnableMethod(cp, &ContentParent::ShutDownProcess, - SEND_SHUTDOWN_MESSAGE)); + MessageLoop::current()->PostTask(NewRunnableMethod + (cp, + &ContentParent::ShutDownProcess, + SEND_SHUTDOWN_MESSAGE)); } cpm->RemoveContentProcess(this->ChildID()); @@ -2249,9 +2251,10 @@ ContentParent::NotifyTabDestroyed(const TabId& aTabId, if (tabIds.Length() == 1) { // In the case of normal shutdown, send a shutdown message to child to // allow it to perform shutdown tasks. - MessageLoop::current()->PostTask( - NewRunnableMethod(this, &ContentParent::ShutDownProcess, - SEND_SHUTDOWN_MESSAGE)); + MessageLoop::current()->PostTask(NewRunnableMethod + (this, + &ContentParent::ShutDownProcess, + SEND_SHUTDOWN_MESSAGE)); } } @@ -2540,7 +2543,7 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority, // PBrowsers are created, because they rely on the Compositor // already being around. (Creation is async, so can't happen // on demand.) - bool useOffMainThreadCompositing = !!CompositorBridgeParent::CompositorLoop(); + bool useOffMainThreadCompositing = !!CompositorThreadHolder::Loop(); if (useOffMainThreadCompositing) { DebugOnly opened = PCompositorBridge::Open(this); MOZ_ASSERT(opened); diff --git a/dom/ipc/PreallocatedProcessManager.cpp b/dom/ipc/PreallocatedProcessManager.cpp index 8566f6c1eb..6ba07bd0cc 100644 --- a/dom/ipc/PreallocatedProcessManager.cpp +++ b/dom/ipc/PreallocatedProcessManager.cpp @@ -217,8 +217,7 @@ PreallocatedProcessManagerImpl::AllocateOnIdle() return; } - MessageLoop::current()->PostIdleTask( - NewRunnableMethod(this, &PreallocatedProcessManagerImpl::AllocateNow)); + MessageLoop::current()->PostIdleTask(NewRunnableMethod(this, &PreallocatedProcessManagerImpl::AllocateNow)); } void @@ -243,7 +242,7 @@ PreallocatedProcessManagerImpl::ScheduleDelayedNuwaFork() return; } - RefPtr task = NewRunnableMethod( + RefPtr task = NS_NewCancelableRunnableMethod( this, &PreallocatedProcessManagerImpl::DelayedNuwaFork); mPreallocateAppProcessTask = task; MessageLoop::current()->PostDelayedTask(task.forget(), diff --git a/dom/ipc/ProcessHangMonitor.cpp b/dom/ipc/ProcessHangMonitor.cpp index 39d832e768..c7171ee78f 100644 --- a/dom/ipc/ProcessHangMonitor.cpp +++ b/dom/ipc/ProcessHangMonitor.cpp @@ -230,22 +230,6 @@ public: } // namespace -template<> -struct RunnableMethodTraits -{ - typedef HangMonitorChild Class; - static void RetainCallee(Class* obj) { } - static void ReleaseCallee(Class* obj) { } -}; - -template<> -struct RunnableMethodTraits -{ - typedef HangMonitorParent Class; - static void RetainCallee(Class* obj) { } - static void ReleaseCallee(Class* obj) { } -}; - /* HangMonitorChild implementation */ HangMonitorChild::HangMonitorChild(ProcessHangMonitor* aMonitor) @@ -303,8 +287,7 @@ HangMonitorChild::ActorDestroy(ActorDestroyReason aWhy) // We use a task here to ensure that IPDL is finished with this // HangMonitorChild before it gets deleted on the main thread. - MonitorLoop()->PostTask( - NewRunnableMethod(this, &HangMonitorChild::ShutdownOnThread)); + MonitorLoop()->PostTask(NewNonOwningRunnableMethod(this, &HangMonitorChild::ShutdownOnThread)); } bool @@ -390,9 +373,10 @@ HangMonitorChild::NotifySlowScript(nsITabChild* aTabChild, } nsAutoCString filename(aFileName); - MonitorLoop()->PostTask( - NewRunnableMethod(this, &HangMonitorChild::NotifySlowScriptAsync, - id, filename, aLineNo)); + MonitorLoop()->PostTask(NewNonOwningRunnableMethod + (this, + &HangMonitorChild::NotifySlowScriptAsync, + id, filename, aLineNo)); return SlowScriptAction::Continue; } @@ -420,10 +404,9 @@ HangMonitorChild::NotifyPluginHang(uint32_t aPluginId) mSentReport = true; // bounce to background thread - MonitorLoop()->PostTask( - NewRunnableMethod(this, - &HangMonitorChild::NotifyPluginHangAsync, - aPluginId)); + MonitorLoop()->PostTask(NewNonOwningRunnableMethod(this, + &HangMonitorChild::NotifyPluginHangAsync, + aPluginId)); } void @@ -445,8 +428,7 @@ HangMonitorChild::ClearHang() if (mSentReport) { // bounce to background thread - MonitorLoop()->PostTask( - NewRunnableMethod(this, &HangMonitorChild::ClearHangAsync)); + MonitorLoop()->PostTask(NewNonOwningRunnableMethod(this, &HangMonitorChild::ClearHangAsync)); MonitorAutoLock lock(mMonitor); mSentReport = false; @@ -511,8 +493,8 @@ HangMonitorParent::Shutdown() mProcess = nullptr; } - MonitorLoop()->PostTask( - NewRunnableMethod(this, &HangMonitorParent::ShutdownOnThread)); + MonitorLoop()->PostTask(NewNonOwningRunnableMethod(this, + &HangMonitorParent::ShutdownOnThread)); while (!mShutdownDone) { mMonitor.Wait(); @@ -832,8 +814,8 @@ HangMonitoredProcess::TerminateScript() return NS_ERROR_UNEXPECTED; } - ProcessHangMonitor::Get()->MonitorLoop()->PostTask( - NewRunnableMethod(mActor, &HangMonitorParent::TerminateScript)); + ProcessHangMonitor::Get()->MonitorLoop()->PostTask(NewNonOwningRunnableMethod(mActor, + &HangMonitorParent::TerminateScript)); return NS_OK; } @@ -849,8 +831,8 @@ HangMonitoredProcess::BeginStartingDebugger() return NS_ERROR_UNEXPECTED; } - ProcessHangMonitor::Get()->MonitorLoop()->PostTask( - NewRunnableMethod(mActor, &HangMonitorParent::BeginStartingDebugger)); + ProcessHangMonitor::Get()->MonitorLoop()->PostTask(NewNonOwningRunnableMethod(mActor, + &HangMonitorParent::BeginStartingDebugger)); return NS_OK; } @@ -866,8 +848,8 @@ HangMonitoredProcess::EndStartingDebugger() return NS_ERROR_UNEXPECTED; } - ProcessHangMonitor::Get()->MonitorLoop()->PostTask( - NewRunnableMethod(mActor, &HangMonitorParent::EndStartingDebugger)); + ProcessHangMonitor::Get()->MonitorLoop()->PostTask(NewNonOwningRunnableMethod(mActor, + &HangMonitorParent::EndStartingDebugger)); return NS_OK; } @@ -1045,9 +1027,13 @@ mozilla::CreateHangMonitorParent(ContentParent* aContentParent, HangMonitoredProcess* process = new HangMonitoredProcess(parent, aContentParent); parent->SetProcess(process); - monitor->MonitorLoop()->PostTask( - NewRunnableMethod(parent, &HangMonitorParent::Open, - aTransport, aOtherPid, XRE_GetIOMessageLoop())); + monitor->MonitorLoop()->PostTask(NewNonOwningRunnableMethod + (parent, + &HangMonitorParent::Open, + aTransport, aOtherPid, + XRE_GetIOMessageLoop())); return parent; } @@ -1061,9 +1047,13 @@ mozilla::CreateHangMonitorChild(mozilla::ipc::Transport* aTransport, ProcessHangMonitor* monitor = ProcessHangMonitor::GetOrCreate(); HangMonitorChild* child = new HangMonitorChild(monitor); - monitor->MonitorLoop()->PostTask( - NewRunnableMethod(child, &HangMonitorChild::Open, - aTransport, aOtherPid, XRE_GetIOMessageLoop())); + monitor->MonitorLoop()->PostTask(NewNonOwningRunnableMethod + (child, + &HangMonitorChild::Open, + aTransport, aOtherPid, + XRE_GetIOMessageLoop())); return child; } diff --git a/dom/jsurl/nsJSProtocolHandler.cpp b/dom/jsurl/nsJSProtocolHandler.cpp index fd36c51144..e5b369154f 100644 --- a/dom/jsurl/nsJSProtocolHandler.cpp +++ b/dom/jsurl/nsJSProtocolHandler.cpp @@ -660,8 +660,7 @@ nsJSChannel::AsyncOpen(nsIStreamListener *aListener, nsISupports *aContext) method = &nsJSChannel::NotifyListener; } - nsCOMPtr ev = NS_NewRunnableMethod(this, method); - nsresult rv = NS_DispatchToCurrentThread(ev); + nsresult rv = NS_DispatchToCurrentThread(mozilla::NewRunnableMethod(this, method)); if (NS_FAILED(rv)) { loadGroup->RemoveRequest(this, nullptr, rv); diff --git a/dom/locales/en-US/chrome/dom/dom.properties b/dom/locales/en-US/chrome/dom/dom.properties index f126a4b96c..e807e0c86a 100644 --- a/dom/locales/en-US/chrome/dom/dom.properties +++ b/dom/locales/en-US/chrome/dom/dom.properties @@ -221,3 +221,4 @@ RewriteYoutubeEmbed=Rewriting old-style Youtube Flash embed (%S) to iframe embed RewriteYoutubeEmbedInvalidQuery=Rewriting old-style Youtube Flash embed (%S) to iframe embed (%S). Query was invalid and removed from URL. Please update page to use iframe instead of embed/object, if possible. # LOCALIZATION NOTE: Do not translate "ServiceWorker". %1$S is the ServiceWorker scope URL. %2$S is an error string. PushMessageDecryptionFailure=The ServiceWorker for scope '%1$S' encountered an error decrypting a push message: '%2$S'. For help with encryption, please see https://developer.mozilla.org/en-US/docs/Web/API/Push_API/Using_the_Push_API#Encryption +IIRFilterChannelCountChangeWarning=IIRFilterNode channel count changes may produce audio glitches. diff --git a/dom/media/AbstractMediaDecoder.h b/dom/media/AbstractMediaDecoder.h index f4764bbbd3..4d4a1c8110 100644 --- a/dom/media/AbstractMediaDecoder.h +++ b/dom/media/AbstractMediaDecoder.h @@ -62,7 +62,7 @@ public: // Return an event that will be notified when data arrives in MediaResource. // MediaDecoderReader will register with this event to receive notifications - // in order to udpate buffer ranges. + // in order to update buffer ranges. // Return null if this decoder doesn't support the event. virtual MediaEventSource* DataArrivedEvent() { @@ -74,10 +74,9 @@ protected: public: void DispatchUpdateEstimatedMediaDuration(int64_t aDuration) { - nsCOMPtr r = - NS_NewRunnableMethodWithArg(this, &AbstractMediaDecoder::UpdateEstimatedMediaDuration, - aDuration); - NS_DispatchToMainThread(r); + NS_DispatchToMainThread(NewRunnableMethod(this, + &AbstractMediaDecoder::UpdateEstimatedMediaDuration, + aDuration)); } virtual VideoFrameContainer* GetVideoFrameContainer() = 0; diff --git a/dom/media/DOMMediaStream.cpp b/dom/media/DOMMediaStream.cpp index 7076936071..73e7b835c9 100644 --- a/dom/media/DOMMediaStream.cpp +++ b/dom/media/DOMMediaStream.cpp @@ -192,13 +192,13 @@ public: { if (aTrackEvents & TRACK_EVENT_CREATED) { nsCOMPtr runnable = - NS_NewRunnableMethodWithArgs( + NewRunnableMethod( this, &OwnedStreamListener::DoNotifyTrackCreated, aID, aQueuedMedia.GetType(), aInputStream, aInputTrackID); aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget()); } else if (aTrackEvents & TRACK_EVENT_ENDED) { nsCOMPtr runnable = - NS_NewRunnableMethodWithArgs( + NewRunnableMethod( this, &OwnedStreamListener::DoNotifyTrackEnded, aInputStream, aInputTrackID); aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget()); @@ -282,7 +282,7 @@ public: { if (aTrackEvents & TRACK_EVENT_ENDED) { nsCOMPtr runnable = - NS_NewRunnableMethodWithArgs, TrackID>( + NewRunnableMethod, TrackID>( this, &PlaybackStreamListener::DoNotifyTrackEnded, aInputStream, aInputTrackID); aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget()); } @@ -291,7 +291,7 @@ public: void NotifyFinishedTrackCreation(MediaStreamGraph* aGraph) override { nsCOMPtr runnable = - NS_NewRunnableMethod(this, &PlaybackStreamListener::DoNotifyFinishedTrackCreation); + NewRunnableMethod(this, &PlaybackStreamListener::DoNotifyFinishedTrackCreation); aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget()); } diff --git a/dom/media/MediaDecoder.cpp b/dom/media/MediaDecoder.cpp index 311595b5c8..d22212ef00 100644 --- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -287,7 +287,7 @@ MediaDecoder::ResourceCallback::NotifyBytesConsumed(int64_t aBytes, } void -MediaDecoder::NotifyOwnerActivityChanged() +MediaDecoder::NotifyOwnerActivityChanged(bool aIsVisible) { MOZ_ASSERT(NS_IsMainThread()); @@ -295,6 +295,8 @@ MediaDecoder::NotifyOwnerActivityChanged() return; } + SetElementVisibility(aIsVisible); + UpdateDormantState(false /* aDormantTimeout */, false /* aActivity */); // Start dormant timer if necessary StartDormantTimer(); @@ -330,10 +332,10 @@ MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity) } DECODER_LOG("UpdateDormantState aTimeout=%d aActivity=%d mIsDormant=%d " - "ownerActive=%d ownerHidden=%d mIsHeuristicDormant=%d " + "ownerActive=%d mIsVisible=%d mIsHeuristicDormant=%d " "mPlayState=%s encrypted=%s", aDormantTimeout, aActivity, mIsDormant, mOwner->IsActive(), - mOwner->IsHidden(), mIsHeuristicDormant, PlayStateStr(), + mIsVisible.Ref(), mIsHeuristicDormant, PlayStateStr(), (!mInfo ? "Unknown" : (mInfo->IsEncrypted() ? "1" : "0"))); bool prevDormant = mIsDormant; @@ -350,7 +352,7 @@ MediaDecoder::UpdateDormantState(bool aDormantTimeout, bool aActivity) // Try to enable dormant by idle heuristic, when the owner is hidden. bool prevHeuristicDormant = mIsHeuristicDormant; mIsHeuristicDormant = false; - if (IsHeuristicDormantSupported() && mOwner->IsHidden()) { + if (IsHeuristicDormantSupported() && !mIsVisible) { if (aDormantTimeout && !aActivity && (mPlayState == PLAY_STATE_PAUSED || IsEnded())) { // Enable heuristic dormant @@ -406,7 +408,7 @@ MediaDecoder::StartDormantTimer() if (mIsHeuristicDormant || mShuttingDown || - !mOwner->IsHidden() || + mIsVisible || (mPlayState != PLAY_STATE_PAUSED && !IsEnded())) { @@ -572,6 +574,8 @@ MediaDecoder::MediaDecoder(MediaDecoderOwner* aOwner) "MediaDecoder::mMediaSeekable (Canonical)") , mMediaSeekableOnlyInBufferedRanges(AbstractThread::MainThread(), false, "MediaDecoder::mMediaSeekableOnlyInBufferedRanges (Canonical)") + , mIsVisible(AbstractThread::MainThread(), !mOwner->IsHidden(), + "MediaDecoder::mIsVisible (Canonical)") , mTelemetryReported(false) { MOZ_COUNT_CTOR(MediaDecoder); @@ -1361,6 +1365,13 @@ MediaDecoder::DurationChanged() } } +void +MediaDecoder::SetElementVisibility(bool aIsVisible) +{ + MOZ_ASSERT(NS_IsMainThread()); + mIsVisible = aIsVisible; +} + void MediaDecoder::UpdateEstimatedMediaDuration(int64_t aDuration) { diff --git a/dom/media/MediaDecoder.h b/dom/media/MediaDecoder.h index a40f7d3844..c0ef7068c1 100644 --- a/dom/media/MediaDecoder.h +++ b/dom/media/MediaDecoder.h @@ -180,7 +180,7 @@ public: // Dormant state is a state to free all scarce media resources // (like hw video codec), did not decoding and stay dormant. // It is used to share scarece media resources in system. - virtual void NotifyOwnerActivityChanged(); + virtual void NotifyOwnerActivityChanged(bool aIsVisible); void UpdateDormantState(bool aDormantTimeout, bool aActivity); @@ -250,9 +250,6 @@ protected: void UpdateEstimatedMediaDuration(int64_t aDuration) override; public: - // Called from HTMLMediaElement when owner document activity changes - virtual void SetElementVisibility(bool aIsVisible) {} - // Set a flag indicating whether random seeking is supported void SetMediaSeekable(bool aMediaSeekable); // Set a flag indicating whether seeking is supported only in buffered ranges @@ -368,6 +365,9 @@ private: void SetAudioChannel(dom::AudioChannel aChannel) { mAudioChannel = aChannel; } dom::AudioChannel GetAudioChannel() { return mAudioChannel; } + // Called from HTMLMediaElement when owner document activity changes + virtual void SetElementVisibility(bool aIsVisible); + /****** * The following methods must only be called on the main * thread. @@ -744,7 +744,7 @@ protected: // start playing back again. Mirror mPlaybackPosition; - // Used to distiguish whether the audio is producing sound. + // Used to distinguish whether the audio is producing sound. Mirror mIsAudioDataAudible; // Volume of playback. 0.0 = muted. 1.0 = full volume. @@ -806,6 +806,9 @@ protected: // True if the media is only seekable within its buffered ranges. Canonical mMediaSeekableOnlyInBufferedRanges; + // True if the decoder is visible. + Canonical mIsVisible; + public: AbstractCanonical* CanonicalDurationOrNull() override; AbstractCanonical* CanonicalVolume() { @@ -853,6 +856,9 @@ public: AbstractCanonical* CanonicalMediaSeekableOnlyInBufferedRanges() { return &mMediaSeekableOnlyInBufferedRanges; } + AbstractCanonical* CanonicalIsVisible() { + return &mIsVisible; + } private: // Notify owner when the audible state changed diff --git a/dom/media/MediaDecoderReader.cpp b/dom/media/MediaDecoderReader.cpp index 65a06c57f6..5425cfe7a4 100644 --- a/dom/media/MediaDecoderReader.cpp +++ b/dom/media/MediaDecoderReader.cpp @@ -85,8 +85,7 @@ MediaDecoderReader::MediaDecoderReader(AbstractMediaDecoder* aDecoder) } // Dispatch initialization that needs to happen on that task queue. - nsCOMPtr r = NS_NewRunnableMethod(this, &MediaDecoderReader::InitializationTask); - mTaskQueue->Dispatch(r.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &MediaDecoderReader::InitializationTask)); } void @@ -133,17 +132,18 @@ size_t MediaDecoderReader::SizeOfAudioQueueInFrames() return mAudioQueue.GetSize(); } -nsresult MediaDecoderReader::ResetDecode() +nsresult MediaDecoderReader::ResetDecode(TargetQueues aQueues /*= AUDIO_VIDEO*/) { VideoQueue().Reset(); - AudioQueue().Reset(); - - mAudioDiscontinuity = true; mVideoDiscontinuity = true; - - mBaseAudioPromise.RejectIfExists(CANCELED, __func__); mBaseVideoPromise.RejectIfExists(CANCELED, __func__); + if (aQueues == AUDIO_VIDEO) { + AudioQueue().Reset(); + mAudioDiscontinuity = true; + mBaseAudioPromise.RejectIfExists(CANCELED, __func__); + } + return NS_OK; } @@ -184,6 +184,10 @@ MediaDecoderReader::UpdateBuffered() mBuffered = GetBuffered(); } +void +MediaDecoderReader::VisibilityChanged() +{} + media::TimeIntervals MediaDecoderReader::GetBuffered() { diff --git a/dom/media/MediaDecoderReader.h b/dom/media/MediaDecoderReader.h index de4ab48aba..f0c94d5db6 100644 --- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -73,6 +73,11 @@ public: CANCELED }; + enum TargetQueues { + VIDEO_ONLY, + AUDIO_VIDEO + }; + using MetadataPromise = MozPromise, ReadMetadataFailureReason, IsExclusive>; using MediaDataPromise = @@ -125,7 +130,7 @@ public: // The first samples of every stream produced after a ResetDecode() call // *must* be marked as "discontinuities". If it's not, seeking work won't // properly! - virtual nsresult ResetDecode(); + virtual nsresult ResetDecode(TargetQueues aQueues = AUDIO_VIDEO); // Requests one audio sample from the reader. // @@ -395,6 +400,8 @@ private: // Recomputes mBuffered. virtual void UpdateBuffered(); + virtual void VisibilityChanged(); + virtual void NotifyDataArrivedInternal() {} // Overrides of this function should decodes an unspecified amount of diff --git a/dom/media/MediaDecoderReaderWrapper.cpp b/dom/media/MediaDecoderReaderWrapper.cpp index 4bed533f1c..ae3b8d6186 100644 --- a/dom/media/MediaDecoderReaderWrapper.cpp +++ b/dom/media/MediaDecoderReaderWrapper.cpp @@ -316,7 +316,7 @@ MediaDecoderReaderWrapper::ReleaseMediaResources() { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); nsCOMPtr r = - NS_NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources); + NewRunnableMethod(mReader, &MediaDecoderReader::ReleaseMediaResources); mReader->OwnerThread()->Dispatch(r.forget()); } @@ -325,12 +325,12 @@ MediaDecoderReaderWrapper::SetIdle() { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); nsCOMPtr r = - NS_NewRunnableMethod(mReader, &MediaDecoderReader::SetIdle); + NewRunnableMethod(mReader, &MediaDecoderReader::SetIdle); mReader->OwnerThread()->Dispatch(r.forget()); } void -MediaDecoderReaderWrapper::ResetDecode() +MediaDecoderReaderWrapper::ResetDecode(TargetQueues aQueues) { MOZ_ASSERT(mOwnerThread->IsCurrentThreadIn()); @@ -338,7 +338,9 @@ MediaDecoderReaderWrapper::ResetDecode() mVideoDataRequest.DisconnectIfExists(); nsCOMPtr r = - NS_NewRunnableMethod(mReader, &MediaDecoderReader::ResetDecode); + NewRunnableMethod(mReader, + &MediaDecoderReader::ResetDecode, + aQueues); mReader->OwnerThread()->Dispatch(r.forget()); } diff --git a/dom/media/MediaDecoderReaderWrapper.h b/dom/media/MediaDecoderReaderWrapper.h index 231591ebee..34c2c64b1d 100644 --- a/dom/media/MediaDecoderReaderWrapper.h +++ b/dom/media/MediaDecoderReaderWrapper.h @@ -32,6 +32,7 @@ class MediaDecoderReaderWrapper { typedef MediaDecoderReader::SeekPromise SeekPromise; typedef MediaDecoderReader::WaitForDataPromise WaitForDataPromise; typedef MediaDecoderReader::BufferedUpdatePromise BufferedUpdatePromise; + typedef MediaDecoderReader::TargetQueues TargetQueues; NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReaderWrapper); /* @@ -255,7 +256,7 @@ public: void ReleaseMediaResources(); void SetIdle(); - void ResetDecode(); + void ResetDecode(TargetQueues aQueues); nsresult Init() { return mReader->Init(); } bool IsWaitForDataSupported() const { return mReader->IsWaitForDataSupported(); } diff --git a/dom/media/MediaDecoderStateMachine.cpp b/dom/media/MediaDecoderStateMachine.cpp index c733a24438..5202e9b040 100644 --- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -122,11 +122,6 @@ static const int AUDIO_DURATION_USECS = 40000; // increase it by more. static const int THRESHOLD_FACTOR = 2; -// When the continuous silent data is over this threshold, means the a/v does -// not produce any sound. This time is decided by UX suggestion, see -// https://bugzilla.mozilla.org/show_bug.cgi?id=1235612#c18 -static const uint32_t SILENT_DATA_THRESHOLD_USECS = 10000000; - namespace detail { // If we have less than this much undecoded data available, we'll consider @@ -206,6 +201,21 @@ static void InitVideoQueuePrefs() { } } +static bool sSuspendBackgroundVideos = true; + +static void +InitSuspendBackgroundPref() +{ + MOZ_ASSERT(NS_IsMainThread(), "Must be on main thread."); + + static bool sSetupPrefCache = false; + if (!sSetupPrefCache) { + sSetupPrefCache = true; + Preferences::AddBoolVarCache(&sSuspendBackgroundVideos, + "media.suspend-bkgnd-video.enabled", true); + } +} + MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder, MediaDecoderReader* aReader, bool aRealTime) : @@ -247,7 +257,6 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder, mOutputStreamManager(new OutputStreamManager()), mResource(aDecoder->GetResource()), mAudioOffloading(false), - mSilentDataDuration(0), mBuffered(mTaskQueue, TimeIntervals(), "MediaDecoderStateMachine::mBuffered (Mirror)"), mEstimatedDuration(mTaskQueue, NullableTimeUnit(), @@ -277,6 +286,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder, "MediaDecoderStateMachine::mMediaSeekable (Mirror)"), mMediaSeekableOnlyInBufferedRanges(mTaskQueue, false, "MediaDecoderStateMachine::mMediaSeekableOnlyInBufferedRanges (Mirror)"), + mIsVisible(mTaskQueue, true, "MediaDecoderStateMachine::mIsVisible (Mirror)"), mDuration(mTaskQueue, NullableTimeUnit(), "MediaDecoderStateMachine::mDuration (Canonical"), mIsShutdown(mTaskQueue, false, @@ -294,6 +304,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder, NS_ASSERTION(NS_IsMainThread(), "Should be on main thread."); InitVideoQueuePrefs(); + InitSuspendBackgroundPref(); mBufferingWait = IsRealTime() ? 0 : 15; mLowDataThresholdUsecs = IsRealTime() ? 0 : detail::LOW_DATA_THRESHOLD_USECS; @@ -339,6 +350,7 @@ MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder) mDecoderPosition.Connect(aDecoder->CanonicalDecoderPosition()); mMediaSeekable.Connect(aDecoder->CanonicalMediaSeekable()); mMediaSeekableOnlyInBufferedRanges.Connect(aDecoder->CanonicalMediaSeekableOnlyInBufferedRanges()); + mIsVisible.Connect(aDecoder->CanonicalIsVisible()); // Initialize watchers. mWatchManager.Watch(mBuffered, &MediaDecoderStateMachine::BufferedRangeUpdated); @@ -352,20 +364,31 @@ MediaDecoderStateMachine::InitializationTask(MediaDecoder* aDecoder) mWatchManager.Watch(mExplicitDuration, &MediaDecoderStateMachine::RecomputeDuration); mWatchManager.Watch(mObservedDuration, &MediaDecoderStateMachine::RecomputeDuration); mWatchManager.Watch(mPlayState, &MediaDecoderStateMachine::PlayStateChanged); + mWatchManager.Watch(mIsVisible, &MediaDecoderStateMachine::VisibilityChanged); // Configure MediaDecoderReaderWrapper. SetMediaDecoderReaderWrapperCallback(); } +void +MediaDecoderStateMachine::AudioAudibleChanged(bool aAudible) +{ + mIsAudioDataAudible = aAudible; +} + media::MediaSink* MediaDecoderStateMachine::CreateAudioSink() { RefPtr self = this; auto audioSinkCreator = [self] () { MOZ_ASSERT(self->OnTaskQueue()); - return new DecodedAudioDataSink( + DecodedAudioDataSink* audioSink = new DecodedAudioDataSink( self->mTaskQueue, self->mAudioQueue, self->GetMediaTime(), self->mInfo.mAudio, self->mAudioChannel); + + self->mAudibleListener = audioSink->AudibleEvent().Connect( + self->mTaskQueue, self.get(), &MediaDecoderStateMachine::AudioAudibleChanged); + return audioSink; }; return new AudioSinkWrapper(mTaskQueue, audioSinkCreator); } @@ -463,6 +486,10 @@ bool MediaDecoderStateMachine::HaveEnoughDecodedVideo() { MOZ_ASSERT(OnTaskQueue()); + if (IsVideoDecodeSuspended()) { + return true; + } + if (VideoQueue().GetSize() == 0) { return false; } @@ -623,26 +650,6 @@ MediaDecoderStateMachine::Push(MediaData* aSample, MediaData::Type aSampleType) DispatchDecodeTasksIfNeeded(); } -void -MediaDecoderStateMachine::CheckIsAudible(const MediaData* aSample) -{ - MOZ_ASSERT(OnTaskQueue()); - MOZ_ASSERT(aSample->mType == MediaData::AUDIO_DATA); - - const AudioData* data = aSample->As(); - bool isAudible = data->IsAudible(); - if (isAudible && !mIsAudioDataAudible) { - mIsAudioDataAudible = true; - mSilentDataDuration = 0; - } else if (isAudible && mIsAudioDataAudible) { - mSilentDataDuration += data->mDuration; - if (mSilentDataDuration > SILENT_DATA_THRESHOLD_USECS) { - mIsAudioDataAudible = false; - mSilentDataDuration = 0; - } - } -} - void MediaDecoderStateMachine::OnAudioPopped(const RefPtr& aSample) { @@ -651,8 +658,6 @@ MediaDecoderStateMachine::OnAudioPopped(const RefPtr& aSample) mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset); UpdateNextFrameStatus(); DispatchAudioDecodeTaskIfNeeded(); - MaybeStartBuffering(); - CheckIsAudible(aSample); } void @@ -662,7 +667,6 @@ MediaDecoderStateMachine::OnVideoPopped(const RefPtr& aSample) mPlaybackOffset = std::max(mPlaybackOffset.Ref(), aSample->mOffset); UpdateNextFrameStatus(); DispatchVideoDecodeTaskIfNeeded(); - MaybeStartBuffering(); } void @@ -894,7 +898,7 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoder* aDecoder) MOZ_ASSERT(NS_IsMainThread()); // Dispatch initialization that needs to happen on that task queue. - nsCOMPtr r = NS_NewRunnableMethodWithArg>( + nsCOMPtr r = NewRunnableMethod>( this, &MediaDecoderStateMachine::InitializationTask, aDecoder); mTaskQueue->Dispatch(r.forget()); @@ -917,8 +921,7 @@ nsresult MediaDecoderStateMachine::Init(MediaDecoder* aDecoder) nsresult rv = mReader->Init(); NS_ENSURE_SUCCESS(rv, rv); - r = NS_NewRunnableMethod(this, &MediaDecoderStateMachine::ReadMetadata); - OwnerThread()->Dispatch(r.forget()); + OwnerThread()->Dispatch(NewRunnableMethod(this, &MediaDecoderStateMachine::ReadMetadata)); return NS_OK; } @@ -1119,7 +1122,7 @@ void MediaDecoderStateMachine::RecomputeDuration() void MediaDecoderStateMachine::DispatchSetDormant(bool aDormant) { - nsCOMPtr r = NS_NewRunnableMethodWithArg( + nsCOMPtr r = NewRunnableMethod( this, &MediaDecoderStateMachine::SetDormant, aDormant); OwnerThread()->Dispatch(r.forget()); } @@ -1326,6 +1329,85 @@ void MediaDecoderStateMachine::PlayStateChanged() ScheduleStateMachine(); } +void MediaDecoderStateMachine::VisibilityChanged() +{ + MOZ_ASSERT(OnTaskQueue()); + DECODER_LOG("VisibilityChanged: is visible = %d", mIsVisible.Ref()); + + // Not suspending background videos so there's nothing to do. + if (!sSuspendBackgroundVideos) { + return; + } + + if (!HasVideo()) { + return; + } + + // If not transitioning to visible and not playing then there's + // nothing to do. + if (!mIsVisible || mPlayState != MediaDecoder::PLAY_STATE_PLAYING) { + return; + } + + // If an existing seek is in flight don't bother creating a new one to catch + // up. + if (mSeekTask || mQueuedSeek.Exists()) { + return; + } + + // Start video-only seek to the current time... + InitiateVideoDecodeRecoverySeek(); +} + +// InitiateVideoDecodeRecoverySeek is responsible for setting up a video-only +// seek using the seek task. When suspension of decoding for videos that are in +// background tabs (ie. invisible) is enabled, the audio keeps playing and when +// switching back to decoding video, it is highly desirable to not cause the +// audio to pause as the video is seeked else there be a noticeable audio glitch +// as the tab becomes visible. +void MediaDecoderStateMachine::InitiateVideoDecodeRecoverySeek() +{ + MOZ_ASSERT(OnTaskQueue()); + + SeekJob seekJob; + seekJob.mTarget = SeekTarget(GetMediaTime(), + SeekTarget::Type::AccurateVideoOnly, + MediaDecoderEventVisibility::Suppressed); + + SetState(DECODER_STATE_SEEKING); + + // Discard the existing seek task. + DiscardSeekTaskIfExist(); + + mSeekTaskRequest.DisconnectIfExists(); + + // SeekTask will register its callbacks to MediaDecoderReaderWrapper. + CancelMediaDecoderReaderWrapperCallback(); + + // Create a new SeekTask instance for the incoming seek task. + mSeekTask = SeekTask::CreateSeekTask(mDecoderID, OwnerThread(), + mReader.get(), Move(seekJob), + mInfo, Duration(), GetMediaTime()); + + mOnSeekingStart.Notify(MediaDecoderEventVisibility::Suppressed); + + // Reset our state machine and decoding pipeline before seeking. + if (mSeekTask->NeedToResetMDSM()) { + Reset(MediaDecoderReader::VIDEO_ONLY); + } + + // Do the seek. + mSeekTaskRequest.Begin( + mSeekTask->Seek(Duration())->Then(OwnerThread(), __func__, this, + &MediaDecoderStateMachine::OnSeekTaskResolved, + &MediaDecoderStateMachine::OnSeekTaskRejected)); + // Nobody is listening to this as OnSeekTaskResolved handles what is + // required but the promise needs to exist or SeekJob::Exists() will + // assert. + RefPtr unused = + mSeekTask->GetSeekJob().mPromise.Ensure(__func__); +} + void MediaDecoderStateMachine::BufferedRangeUpdated() { MOZ_ASSERT(OnTaskQueue()); @@ -1409,6 +1491,8 @@ void MediaDecoderStateMachine::StopMediaSink() MOZ_ASSERT(OnTaskQueue()); if (mMediaSink->IsStarted()) { DECODER_LOG("Stop MediaSink"); + mAudibleListener.DisconnectIfExists(); + mMediaSink->Stop(); mMediaSinkAudioPromise.DisconnectIfExists(); mMediaSinkVideoPromise.DisconnectIfExists(); @@ -1673,6 +1757,13 @@ MediaDecoderStateMachine::EnsureVideoDecodeTaskQueued() return NS_OK; } + if (IsVideoDecodeSuspended() && !IsDecodingFirstFrame()) { + // The element is invisible and background videos should be suspended. + // If the first frame has already been decoded, don't request anymore video + // frames. + return NS_OK; + } + if (!IsVideoDecoding() || mReader->IsRequestingVidoeData() || mVideoWaitRequest.Exists()) { return NS_OK; @@ -2005,7 +2096,7 @@ MediaDecoderStateMachine::SeekCompleted() // Change state to DECODING or COMPLETED now. bool isLiveStream = mResource->IsLiveStream(); State nextState; - if (GetMediaTime() == Duration().ToMicroseconds() && !isLiveStream) { + if (newCurrentTime == Duration().ToMicroseconds() && !isLiveStream) { // Seeked to end of media, move to COMPLETED state. Note we don't do // this when playing a live stream, since the end of media will advance // once we download more data! @@ -2099,6 +2190,7 @@ MediaDecoderStateMachine::FinishShutdown() mDecoderPosition.DisconnectIfConnected(); mMediaSeekable.DisconnectIfConnected(); mMediaSeekableOnlyInBufferedRanges.DisconnectIfConnected(); + mIsVisible.DisconnectIfConnected(); mDuration.DisconnectAll(); mIsShutdown.DisconnectAll(); @@ -2154,6 +2246,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine() NS_ASSERTION(!IsPlaying() || IsStateMachineScheduled(), "Must have timer scheduled"); + MaybeStartBuffering(); return NS_OK; } @@ -2252,7 +2345,7 @@ nsresult MediaDecoderStateMachine::RunStateMachine() } void -MediaDecoderStateMachine::Reset() +MediaDecoderStateMachine::Reset(MediaDecoderReader::TargetQueues aQueues /*= AUDIO_VIDEO*/) { MOZ_ASSERT(OnTaskQueue()); DECODER_LOG("MediaDecoderStateMachine::Reset"); @@ -2265,26 +2358,29 @@ MediaDecoderStateMachine::Reset() mState == DECODER_STATE_SEEKING || mState == DECODER_STATE_DORMANT); - // Stop the audio thread. Otherwise, MediaSink might be accessing AudioQueue - // outside of the decoder monitor while we are clearing the queue and causes - // crash for no samples to be popped. - StopMediaSink(); mDecodedVideoEndTime = 0; - mDecodedAudioEndTime = 0; - mAudioCompleted = false; mVideoCompleted = false; - AudioQueue().Reset(); VideoQueue().Reset(); + mVideoWaitRequest.DisconnectIfExists(); + + if (aQueues == MediaDecoderReader::AUDIO_VIDEO) { + // Stop the audio thread. Otherwise, MediaSink might be accessing AudioQueue + // outside of the decoder monitor while we are clearing the queue and causes + // crash for no samples to be popped. + StopMediaSink(); + mDecodedAudioEndTime = 0; + mAudioCompleted = false; + AudioQueue().Reset(); + mAudioWaitRequest.DisconnectIfExists(); + } mMetadataRequest.DisconnectIfExists(); - mAudioWaitRequest.DisconnectIfExists(); - mVideoWaitRequest.DisconnectIfExists(); mSeekTaskRequest.DisconnectIfExists(); mPlaybackOffset = 0; - mReader->ResetDecode(); + mReader->ResetDecode(aQueues); } int64_t @@ -2410,10 +2506,6 @@ void MediaDecoderStateMachine::StartBuffering() return; } - // Update playback position again before entering BUFFERING so the currentTime - // of the media element is more accurate during buffering. - UpdatePlaybackPositionPeriodically(); - if (IsPlaying()) { StopPlayback(); } @@ -2445,9 +2537,7 @@ MediaDecoderStateMachine::ScheduleStateMachine() } mDispatchedStateMachine = true; - nsCOMPtr task = - NS_NewRunnableMethod(this, &MediaDecoderStateMachine::RunStateMachine); - OwnerThread()->Dispatch(task.forget()); + OwnerThread()->Dispatch(NewRunnableMethod(this, &MediaDecoderStateMachine::RunStateMachine)); } void @@ -2490,6 +2580,12 @@ bool MediaDecoderStateMachine::IsStateMachineScheduled() const return mDispatchedStateMachine || mDelayedScheduler.IsScheduled(); } +bool MediaDecoderStateMachine::IsVideoDecodeSuspended() const +{ + MOZ_ASSERT(OnTaskQueue()); + return sSuspendBackgroundVideos && !mIsVisible; +} + void MediaDecoderStateMachine::LogicalPlaybackRateChanged() { @@ -2706,7 +2802,7 @@ void MediaDecoderStateMachine::AddOutputStream(ProcessedMediaStream* aStream, MOZ_ASSERT(NS_IsMainThread()); DECODER_LOG("AddOutputStream aStream=%p!", aStream); mOutputStreamManager->Add(aStream, aFinishWhenEnded); - nsCOMPtr r = NS_NewRunnableMethodWithArg( + nsCOMPtr r = NewRunnableMethod( this, &MediaDecoderStateMachine::SetAudioCaptured, true); OwnerThread()->Dispatch(r.forget()); } @@ -2717,7 +2813,7 @@ void MediaDecoderStateMachine::RemoveOutputStream(MediaStream* aStream) DECODER_LOG("RemoveOutputStream=%p!", aStream); mOutputStreamManager->Remove(aStream); if (mOutputStreamManager->IsEmpty()) { - nsCOMPtr r = NS_NewRunnableMethodWithArg( + nsCOMPtr r = NewRunnableMethod( this, &MediaDecoderStateMachine::SetAudioCaptured, false); OwnerThread()->Dispatch(r.forget()); } diff --git a/dom/media/MediaDecoderStateMachine.h b/dom/media/MediaDecoderStateMachine.h index f65273c522..abd0489489 100644 --- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -368,7 +368,7 @@ private: // Resets all state related to decoding and playback, emptying all buffers // and aborting all pending operations on the decode task queue. - void Reset(); + void Reset(MediaDecoderReader::TargetQueues aQueues = MediaDecoderReader::AUDIO_VIDEO); protected: virtual ~MediaDecoderStateMachine(); @@ -385,7 +385,8 @@ protected: void OnAudioPopped(const RefPtr& aSample); void OnVideoPopped(const RefPtr& aSample); - void CheckIsAudible(const MediaData* aSample); + void AudioAudibleChanged(bool aAudible); + void VolumeChanged(); void LogicalPlaybackRateChanged(); void PreservesPitchChanged(); @@ -471,6 +472,9 @@ protected: // Notification method invoked when mPlayState changes. void PlayStateChanged(); + // Notification method invoked when mIsVisible changes. + void VisibilityChanged(); + // Sets internal state which causes playback of media to pause. // The decoder monitor must be held. void StopPlayback(); @@ -506,10 +510,15 @@ protected: void EnqueueFirstFrameLoadedEvent(); - // Clears any previous seeking state and initiates a new see on the decoder. + // Clears any previous seeking state and initiates a new seek on the decoder. // The decoder monitor must be held. void InitiateSeek(SeekJob aSeekJob); + // Clears any previous seeking state and initiates a video-only seek on the + // decoder to catch up the video to the current audio position, when recovering + // from video decoding being suspended in background. + void InitiateVideoDecodeRecoverySeek(); + nsresult DispatchAudioDecodeTaskIfNeeded(); // Ensures a task to decode audio has been dispatched to the decode task queue. @@ -592,6 +601,10 @@ protected: // case as it may not be needed again. bool IsPausedAndDecoderWaiting(); + // Returns true if the video decoding is suspended because the element is not + // visible + bool IsVideoDecodeSuspended() const; + // These return true if the respective stream's decode has not yet reached // the end of stream. bool IsAudioDecoding(); @@ -753,7 +766,7 @@ private: // At the start of decoding we want to "preroll" the decode until we've // got a few frames decoded before we consider whether decode is falling // behind. Otherwise our "we're falling behind" logic will trigger - // unneccessarily if we start playing as soon as the first sample is + // unnecessarily if we start playing as soon as the first sample is // decoded. These two fields store how many video frames and audio // samples we must consume before are considered to be finished prerolling. uint32_t AudioPrerollUsecs() const @@ -778,7 +791,8 @@ private: bool DonePrerollingVideo() { MOZ_ASSERT(OnTaskQueue()); - return !IsVideoDecoding() || + return !mIsVisible || + !IsVideoDecoding() || static_cast(VideoQueue().GetSize()) >= VideoPrerollFrames() * mPlaybackRate + 1; } @@ -859,7 +873,7 @@ private: // True if we've dispatched an event to the decode task queue to call // DecodeThreadRun(). We use this flag to prevent us from dispatching - // unneccessary runnables, since the decode thread runs in a loop. + // unnecessary runnables, since the decode thread runs in a loop. bool mDispatchedEventToDecode; // If this is true while we're in buffering mode, we can exit early, @@ -901,7 +915,7 @@ private: MozPromiseRequestHolder mBufferedUpdateRequest; // True if we need to call FinishDecodeFirstFrame() upon frame decoding - // successeeding. + // succeeding. bool mDecodingFirstFrame; // True if we are back from DECODER_STATE_DORMANT state and @@ -928,6 +942,7 @@ private: MediaEventListener mAudioQueueListener; MediaEventListener mVideoQueueListener; + MediaEventListener mAudibleListener; MediaEventProducerExc, nsAutoPtr, @@ -942,9 +957,6 @@ private: // Playback will not start when audio is offloading. bool mAudioOffloading; - // Duration of the continuous silent data. - uint32_t mSilentDataDuration; - #ifdef MOZ_EME void OnCDMProxyReady(RefPtr aProxy); void OnCDMProxyNotReady(); @@ -1000,6 +1012,9 @@ private: // True if the media is seekable only in buffered ranges. Mirror mMediaSeekableOnlyInBufferedRanges; + // IsVisible, mirrored from the media decoder. + Mirror mIsVisible; + // Duration of the media. This is guaranteed to be non-null after we finish // decoding the first frame. Canonical mDuration; @@ -1019,7 +1034,7 @@ private: // Current playback position in the stream in bytes. Canonical mPlaybackOffset; - // Used to distiguish whether the audio is producing sound. + // Used to distinguish whether the audio is producing sound. Canonical mIsAudioDataAudible; public: diff --git a/dom/media/MediaFormatReader.cpp b/dom/media/MediaFormatReader.cpp index 9ce80a7afb..09b91eac76 100644 --- a/dom/media/MediaFormatReader.cpp +++ b/dom/media/MediaFormatReader.cpp @@ -70,6 +70,7 @@ MediaFormatReader::MediaFormatReader(AbstractMediaDecoder* aDecoder, , mIsEncrypted(false) , mTrackDemuxersMayBlock(false) , mDemuxOnly(false) + , mSeekScheduled(false) , mVideoFrameContainer(aVideoFrameContainer) { MOZ_ASSERT(aDemuxer); @@ -96,7 +97,7 @@ MediaFormatReader::Shutdown() mSkipRequest.DisconnectIfExists(); if (mAudio.mDecoder) { - Flush(TrackInfo::kAudioTrack); + Reset(TrackInfo::kAudioTrack); if (mAudio.HasPromise()) { mAudio.RejectPromise(CANCELED, __func__); } @@ -113,10 +114,10 @@ MediaFormatReader::Shutdown() mAudio.mTaskQueue->AwaitShutdownAndIdle(); mAudio.mTaskQueue = nullptr; } - MOZ_ASSERT(mAudio.mPromise.IsEmpty()); + MOZ_ASSERT(!mAudio.HasPromise()); if (mVideo.mDecoder) { - Flush(TrackInfo::kVideoTrack); + Reset(TrackInfo::kVideoTrack); if (mVideo.HasPromise()) { mVideo.RejectPromise(CANCELED, __func__); } @@ -133,7 +134,7 @@ MediaFormatReader::Shutdown() mVideo.mTaskQueue->AwaitShutdownAndIdle(); mVideo.mTaskQueue = nullptr; } - MOZ_ASSERT(mVideo.mPromise.IsEmpty()); + MOZ_ASSERT(!mVideo.HasPromise()); mDemuxer = nullptr; @@ -488,7 +489,10 @@ MediaFormatReader::ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThr if (NS_FAILED(rv)) { return aSkipToNextKeyframe; } - return nextKeyframe < aTimeThreshold && nextKeyframe.ToMicroseconds() >= 0; + return (nextKeyframe < aTimeThreshold || + (mVideo.mTimeThreshold && + mVideo.mTimeThreshold.ref().mTime < aTimeThreshold)) && + nextKeyframe.ToMicroseconds() >= 0; } RefPtr @@ -520,24 +524,16 @@ MediaFormatReader::RequestVideoData(bool aSkipToNextKeyframe, } media::TimeUnit timeThreshold{media::TimeUnit::FromMicroseconds(aTimeThreshold)}; - if (ShouldSkip(aSkipToNextKeyframe, timeThreshold)) { - // Cancel any pending demux request. - mVideo.mDemuxRequest.DisconnectIfExists(); - - // I think it's still possible for an output to have been sent from the decoder - // and is currently sitting in our event queue waiting to be processed. The following - // flush won't clear it, and when we return to the event loop it'll be added to our - // output queue and be used. - // This code will count that as dropped, which was the intent, but not quite true. - mDecoder->NotifyDecodedFrames(0, 0, SizeOfVideoQueueInFrames()); - - Flush(TrackInfo::kVideoTrack); - RefPtr p = mVideo.mPromise.Ensure(__func__); + // Ensure we have no pending seek going as ShouldSkip could return out of date + // information. + if (!mVideo.HasInternalSeekPending() && + ShouldSkip(aSkipToNextKeyframe, timeThreshold)) { + RefPtr p = mVideo.EnsurePromise(__func__); SkipVideoDemuxToNextKeyFrame(timeThreshold); return p; } - RefPtr p = mVideo.mPromise.Ensure(__func__); + RefPtr p = mVideo.EnsurePromise(__func__); NotifyDecodingRequested(TrackInfo::kVideoTrack); return p; @@ -623,7 +619,7 @@ MediaFormatReader::RequestAudioData() return MediaDataPromise::CreateAndReject(CANCELED, __func__); } - RefPtr p = mAudio.mPromise.Ensure(__func__); + RefPtr p = mAudio.EnsurePromise(__func__); NotifyDecodingRequested(TrackInfo::kAudioTrack); return p; @@ -736,7 +732,6 @@ MediaFormatReader::NotifyDecodingRequested(TrackType aTrack) bool MediaFormatReader::NeedInput(DecoderData& aDecoder) { - MOZ_ASSERT(OnTaskQueue()); // We try to keep a few more compressed samples input than decoded samples // have been output, provided the state machine has requested we send it a // decoded sample. To account for H.264 streams which may require a longer @@ -747,6 +742,7 @@ MediaFormatReader::NeedInput(DecoderData& aDecoder) !aDecoder.mError && aDecoder.mDecodingRequested && !aDecoder.mDemuxRequest.Exists() && + !aDecoder.HasInternalSeekPending() && aDecoder.mOutput.Length() <= aDecoder.mDecodeAhead && (aDecoder.mInputExhausted || !aDecoder.mQueuedSamples.IsEmpty() || aDecoder.mTimeThreshold.isSome() || @@ -767,7 +763,7 @@ MediaFormatReader::ScheduleUpdate(TrackType aTrack) LOGV("SchedulingUpdate(%s)", TrackTypeToStr(aTrack)); decoder.mUpdateScheduled = true; RefPtr task( - NS_NewRunnableMethodWithArg(this, &MediaFormatReader::Update, aTrack)); + NewRunnableMethod(this, &MediaFormatReader::Update, aTrack)); OwnerThread()->Dispatch(task.forget()); } @@ -784,6 +780,21 @@ MediaFormatReader::UpdateReceivedNewData(TrackType aTrack) // Update our cached TimeRange. decoder.mTimeRanges = decoder.mTrackDemuxer->GetBuffered(); + // We do not want to clear mWaitingForData while there are pending + // demuxing or seeking operations that could affect the value of this flag. + // This is in order to ensure that we will retry once they complete as we may + // now have new data that could potentially allow those operations to + // successfully complete if tried again. + if (decoder.mSeekRequest.Exists()) { + // Nothing more to do until this operation complete. + return true; + } + if (decoder.mDemuxRequest.Exists()) { + // We may have pending operations to process, so we want to continue + // after UpdateReceivedNewData returns. + return false; + } + if (decoder.mDrainComplete || decoder.mDraining) { // We do not want to clear mWaitingForData or mDemuxEOS while // a drain is in progress in order to properly complete the operation. @@ -809,20 +820,31 @@ MediaFormatReader::UpdateReceivedNewData(TrackType aTrack) if (decoder.mError) { return false; } - if (decoder.HasWaitingPromise()) { - MOZ_ASSERT(!decoder.HasPromise()); - LOG("We have new data. Resolving WaitingPromise"); - decoder.mWaitingPromise.Resolve(decoder.mType, __func__); - return true; - } + if (!mSeekPromise.IsEmpty()) { MOZ_ASSERT(!decoder.HasPromise()); + MOZ_DIAGNOSTIC_ASSERT(!mAudio.mTimeThreshold && !mVideo.mTimeThreshold, + "InternalSeek must have been aborted when Seek was first called"); + MOZ_DIAGNOSTIC_ASSERT(!mAudio.HasWaitingPromise() && !mVideo.HasWaitingPromise(), + "Waiting promises must have been rejected when Seek was first called"); if (mVideo.mSeekRequest.Exists() || mAudio.mSeekRequest.Exists()) { // Already waiting for a seek to complete. Nothing more to do. return true; } LOG("Attempting Seek"); - AttemptSeek(); + ScheduleSeek(); + return true; + } + if (decoder.HasInternalSeekPending() || decoder.HasWaitingPromise()) { + if (decoder.HasInternalSeekPending()) { + LOG("Attempting Internal Seek"); + InternalSeek(aTrack, decoder.mTimeThreshold.ref()); + } + if (decoder.HasWaitingPromise()) { + MOZ_ASSERT(!decoder.HasPromise()); + LOG("We have new data. Resolving WaitingPromise"); + decoder.mWaitingPromise.Resolve(decoder.mType, __func__); + } return true; } return false; @@ -923,9 +945,9 @@ MediaFormatReader::HandleDemuxedSamples(TrackType aTrack, decoder.mInfo = info; decoder.mLastStreamSourceID = info->GetID(); decoder.mNextStreamSourceID.reset(); - // Flush will clear our array of queued samples. So make a copy now. + // Reset will clear our array of queued samples. So make a copy now. nsTArray> samples{decoder.mQueuedSamples}; - Flush(aTrack); + Reset(aTrack); decoder.ShutdownDecoder(); if (sample->mKeyframe) { decoder.mQueuedSamples.AppendElements(Move(samples)); @@ -973,15 +995,22 @@ void MediaFormatReader::InternalSeek(TrackType aTrack, const InternalSeekTarget& aTarget) { MOZ_ASSERT(OnTaskQueue()); + LOG("%s internal seek to %f", + TrackTypeToStr(aTrack), aTarget.mTime.ToSeconds()); + auto& decoder = GetDecoderData(aTrack); + decoder.Flush(); + decoder.ResetDemuxer(); decoder.mTimeThreshold = Some(aTarget); RefPtr self = this; - decoder.ResetDemuxer(); decoder.mSeekRequest.Begin(decoder.mTrackDemuxer->Seek(decoder.mTimeThreshold.ref().mTime) ->Then(OwnerThread(), __func__, [self, aTrack] (media::TimeUnit aTime) { auto& decoder = self->GetDecoderData(aTrack); decoder.mSeekRequest.Complete(); + MOZ_ASSERT(decoder.mTimeThreshold, + "Seek promise must be disconnected when timethreshold is reset"); + decoder.mTimeThreshold.ref().mHasSeeked = true; self->NotifyDecodingRequested(aTrack); }, [self, aTrack] (DemuxerFailureReason aResult) { @@ -992,16 +1021,18 @@ MediaFormatReader::InternalSeek(TrackType aTrack, const InternalSeekTarget& aTar self->NotifyWaitingForData(aTrack); break; case DemuxerFailureReason::END_OF_STREAM: + decoder.mTimeThreshold.reset(); self->NotifyEndOfStream(aTrack); break; case DemuxerFailureReason::CANCELED: case DemuxerFailureReason::SHUTDOWN: + decoder.mTimeThreshold.reset(); break; default: + decoder.mTimeThreshold.reset(); self->NotifyError(aTrack); break; } - decoder.mTimeThreshold.reset(); })); } @@ -1053,6 +1084,16 @@ MediaFormatReader::Update(TrackType aTrack) return; } + if (decoder.mSeekRequest.Exists()) { + LOGV("Seeking hasn't completed, nothing more to do"); + return; + } + + MOZ_DIAGNOSTIC_ASSERT(!decoder.HasInternalSeekPending() || + (!decoder.mOutput.Length() && + !decoder.mQueuedSamples.Length()), + "No frames can be demuxed or decoded while an internal seek is pending"); + // Record number of frames decoded and parsed. Automatically update the // stats counters using the AutoNotifyDecoded stack-based class. AbstractMediaDecoder::AutoNotifyDecoded a(mDecoder); @@ -1066,7 +1107,7 @@ MediaFormatReader::Update(TrackType aTrack) // We have reached our internal seek target. decoder.mTimeThreshold.reset(); } - if (time < target.mTime || target.mDropTarget) { + if (time < target.mTime || (target.mDropTarget && time == target.mTime)) { LOGV("Internal Seeking: Dropping %s frame time:%f wanted:%f (kf:%d)", TrackTypeToStr(aTrack), media::TimeUnit::FromMicroseconds(output->mTime).ToSeconds(), @@ -1124,7 +1165,7 @@ MediaFormatReader::Update(TrackType aTrack) // Now that draining has completed, we check if we have received // new data again as the result may now be different from the earlier // run. - if (UpdateReceivedNewData(aTrack)) { + if (UpdateReceivedNewData(aTrack) || decoder.mSeekRequest.Exists()) { LOGV("Nothing more to do"); return; } @@ -1174,6 +1215,9 @@ MediaFormatReader::ReturnOutput(MediaData* aData, TrackType aTrack) aData->mDiscontinuity = true; } + LOG("Resolved data promise for %s [%lld, %lld]", TrackTypeToStr(aTrack), + aData->mTime, aData->GetEndTime()); + if (aTrack == TrackInfo::kAudioTrack) { if (aData->mType != MediaData::RAW_DATA) { AudioData* audioData = static_cast(aData); @@ -1187,7 +1231,7 @@ MediaFormatReader::ReturnOutput(MediaData* aData, TrackType aTrack) mInfo.mAudio.mChannels = audioData->mChannels; } } - mAudio.mPromise.Resolve(aData, __func__); + mAudio.ResolvePromise(aData, __func__); } else if (aTrack == TrackInfo::kVideoTrack) { if (aData->mType != MediaData::RAW_DATA) { VideoData* videoData = static_cast(aData); @@ -1199,9 +1243,8 @@ MediaFormatReader::ReturnOutput(MediaData* aData, TrackType aTrack) mInfo.mVideo.mDisplay = videoData->mDisplay; } } - mVideo.mPromise.Resolve(aData, __func__); + mVideo.ResolvePromise(aData, __func__); } - LOG("Resolved data promise for %s", TrackTypeToStr(aTrack)); } size_t @@ -1240,13 +1283,11 @@ MediaFormatReader::WaitForData(MediaData::Type aType) } nsresult -MediaFormatReader::ResetDecode() +MediaFormatReader::ResetDecode(TargetQueues aQueues) { MOZ_ASSERT(OnTaskQueue()); LOGV(""); - mAudio.mSeekRequest.DisconnectIfExists(); - mVideo.mSeekRequest.DisconnectIfExists(); mSeekPromise.RejectIfExists(NS_OK, __func__); mSkipRequest.DisconnectIfExists(); @@ -1257,21 +1298,35 @@ MediaFormatReader::ResetDecode() // Reset miscellaneous seeking state. mPendingSeekTime.reset(); + ResetDemuxers(); + if (HasVideo()) { - mVideo.ResetDemuxer(); - Flush(TrackInfo::kVideoTrack); + Reset(TrackInfo::kVideoTrack); if (mVideo.HasPromise()) { mVideo.RejectPromise(CANCELED, __func__); } } - if (HasAudio()) { - mAudio.ResetDemuxer(); - Flush(TrackInfo::kAudioTrack); + + if (HasAudio() && aQueues == AUDIO_VIDEO) { + Reset(TrackInfo::kAudioTrack); if (mAudio.HasPromise()) { mAudio.RejectPromise(CANCELED, __func__); } } - return MediaDecoderReader::ResetDecode(); + return MediaDecoderReader::ResetDecode(aQueues); +} + +void +MediaFormatReader::ResetDemuxers() +{ + if (HasVideo()) { + mVideo.ResetDemuxer(); + mVideo.ResetState(); + } + if (HasAudio()) { + mAudio.ResetDemuxer(); + mAudio.ResetState(); + } } void @@ -1288,7 +1343,7 @@ MediaFormatReader::Output(TrackType aTrack, MediaData* aSample) } RefPtr task = - NS_NewRunnableMethodWithArgs( + NewRunnableMethod( this, &MediaFormatReader::NotifyNewOutput, aTrack, aSample); OwnerThread()->Dispatch(task.forget()); } @@ -1297,7 +1352,7 @@ void MediaFormatReader::DrainComplete(TrackType aTrack) { RefPtr task = - NS_NewRunnableMethodWithArg( + NewRunnableMethod( this, &MediaFormatReader::NotifyDrainComplete, aTrack); OwnerThread()->Dispatch(task.forget()); } @@ -1306,7 +1361,7 @@ void MediaFormatReader::InputExhausted(TrackType aTrack) { RefPtr task = - NS_NewRunnableMethodWithArg( + NewRunnableMethod( this, &MediaFormatReader::NotifyInputExhausted, aTrack); OwnerThread()->Dispatch(task.forget()); } @@ -1315,42 +1370,50 @@ void MediaFormatReader::Error(TrackType aTrack) { RefPtr task = - NS_NewRunnableMethodWithArg( + NewRunnableMethod( this, &MediaFormatReader::NotifyError, aTrack); OwnerThread()->Dispatch(task.forget()); } void -MediaFormatReader::Flush(TrackType aTrack) +MediaFormatReader::Reset(TrackType aTrack) { MOZ_ASSERT(OnTaskQueue()); - LOG("Flush(%s) BEGIN", TrackTypeToStr(aTrack)); + LOG("Reset(%s) BEGIN", TrackTypeToStr(aTrack)); auto& decoder = GetDecoderData(aTrack); - if (!decoder.mDecoder) { - decoder.ResetState(); - return; - } - decoder.mDecoder->Flush(); - // Purge the current decoder's state. - // ResetState clears mOutputRequested flag so that we ignore all output until - // the next request for more data. decoder.ResetState(); - LOG("Flush(%s) END", TrackTypeToStr(aTrack)); + decoder.Flush(); + + LOG("Reset(%s) END", TrackTypeToStr(aTrack)); } void MediaFormatReader::SkipVideoDemuxToNextKeyFrame(media::TimeUnit aTimeThreshold) { MOZ_ASSERT(OnTaskQueue()); - - MOZ_ASSERT(mVideo.mDecoder); MOZ_ASSERT(mVideo.HasPromise()); - MOZ_ASSERT(!mVideo.mDecodingRequested); LOG("Skipping up to %lld", aTimeThreshold.ToMicroseconds()); + // Cancel any pending demux request and pending demuxed samples. + mVideo.mDemuxRequest.DisconnectIfExists(); + + // I think it's still possible for an output to have been sent from the decoder + // and is currently sitting in our event queue waiting to be processed. The following + // flush won't clear it, and when we return to the event loop it'll be added to our + // output queue and be used. + // This code will count that as dropped, which was the intent, but not quite true. + mDecoder->NotifyDecodedFrames(0, 0, SizeOfVideoQueueInFrames()); + + if (mVideo.mTimeThreshold) { + LOGV("Internal Seek pending, cancelling it"); + } + Reset(TrackInfo::kVideoTrack); + if (mVideo.mError) { + // We have flushed the decoder, and we are in error state, we can + // immediately reject the promise as there is nothing more to do. mVideo.RejectPromise(DECODE_ERROR, __func__); return; } @@ -1435,24 +1498,32 @@ MediaFormatReader::Seek(SeekTarget aTarget, int64_t aUnused) RefPtr p = mSeekPromise.Ensure(__func__); - RefPtr task( - NS_NewRunnableMethod(this, &MediaFormatReader::AttemptSeek)); - OwnerThread()->Dispatch(task.forget()); + ScheduleSeek(); return p; } +void +MediaFormatReader::ScheduleSeek() +{ + if (mSeekScheduled) { + return; + } + mSeekScheduled = true; + OwnerThread()->Dispatch(NewRunnableMethod(this, &MediaFormatReader::AttemptSeek)); +} + void MediaFormatReader::AttemptSeek() { MOZ_ASSERT(OnTaskQueue()); + + mSeekScheduled = false; + if (mPendingSeekTime.isNothing()) { return; } - // An internal seek may be pending due to Seek queueing multiple tasks calling - // AttemptSeek ; we can ignore those by resetting any pending demuxer's seek. - mAudio.mSeekRequest.DisconnectIfExists(); - mVideo.mSeekRequest.DisconnectIfExists(); + ResetDemuxers(); if (HasVideo()) { DoVideoSeek(); } else if (HasAudio()) { @@ -1529,9 +1600,10 @@ MediaFormatReader::OnVideoSeekCompleted(media::TimeUnit aTime) LOGV("Video seeked to %lld", aTime.ToMicroseconds()); mVideo.mSeekRequest.Complete(); - if (HasAudio()) { - MOZ_ASSERT(mPendingSeekTime.isSome() && mOriginalSeekTarget.isSome()); - if (mOriginalSeekTarget.ref().IsFast()) { + MOZ_ASSERT(mOriginalSeekTarget.isSome()); + if (HasAudio() && !mOriginalSeekTarget->IsVideoOnly()) { + MOZ_ASSERT(mPendingSeekTime.isSome()); + if (mOriginalSeekTarget->IsFast()) { // We are performing a fast seek. We need to seek audio to where the // video seeked to, to ensure proper A/V sync once playback resume. mPendingSeekTime = Some(aTime); @@ -1653,6 +1725,8 @@ MediaFormatReader::NotifyDemuxer() return; } + LOGV(""); + mDemuxer->NotifyDataArrived(); if (!mInitDone) { @@ -1707,12 +1781,48 @@ MediaFormatReader::GetMozDebugReaderData(nsAString& aString) result += nsPrintfCString("audio decoder: %s\n", audioName); result += nsPrintfCString("audio frames decoded: %lld\n", mAudio.mNumSamplesOutputTotal); + if (HasAudio()) { + result += nsPrintfCString("audio state: ni=%d no=%d ie=%d demuxr:%d demuxq:%d decoder:%d tt:%f tths:%d in:%llu out:%llu qs=%u pending:%u waiting:%d sid:%u\n", + NeedInput(mAudio), mAudio.HasPromise(), + mAudio.mInputExhausted, + mAudio.mDemuxRequest.Exists(), + int(mAudio.mQueuedSamples.Length()), + mAudio.mDecodingRequested, + mAudio.mTimeThreshold + ? mAudio.mTimeThreshold.ref().mTime.ToSeconds() + : -1.0, + mAudio.mTimeThreshold + ? mAudio.mTimeThreshold.ref().mHasSeeked + : -1, + mAudio.mNumSamplesInput, mAudio.mNumSamplesOutput, + unsigned(size_t(mAudio.mSizeOfQueue)), + unsigned(mAudio.mOutput.Length()), + mAudio.mWaitingForData, mAudio.mLastStreamSourceID); + } result += nsPrintfCString("video decoder: %s\n", videoName); result += nsPrintfCString("hardware video decoding: %s\n", VideoIsHardwareAccelerated() ? "enabled" : "disabled"); result += nsPrintfCString("video frames decoded: %lld (skipped:%lld)\n", mVideo.mNumSamplesOutputTotal, mVideo.mNumSamplesSkippedTotal); + if (HasVideo()) { + result += nsPrintfCString("video state: ni=%d no=%d ie=%d demuxr:%d demuxq:%d decoder:%d tt:%f tths:%d in:%llu out:%llu qs=%u pending:%u waiting:%d sid:%u\n", + NeedInput(mVideo), mVideo.HasPromise(), + mVideo.mInputExhausted, + mVideo.mDemuxRequest.Exists(), + int(mVideo.mQueuedSamples.Length()), + mVideo.mDecodingRequested, + mVideo.mTimeThreshold + ? mVideo.mTimeThreshold.ref().mTime.ToSeconds() + : -1.0, + mVideo.mTimeThreshold + ? mVideo.mTimeThreshold.ref().mHasSeeked + : -1, + mVideo.mNumSamplesInput, mVideo.mNumSamplesOutput, + unsigned(size_t(mVideo.mSizeOfQueue)), + unsigned(mVideo.mOutput.Length()), + mVideo.mWaitingForData, mVideo.mLastStreamSourceID); + } aString += NS_ConvertUTF8toUTF16(result); } diff --git a/dom/media/MediaFormatReader.h b/dom/media/MediaFormatReader.h index 3207d81cf8..d7f810b1a5 100644 --- a/dom/media/MediaFormatReader.h +++ b/dom/media/MediaFormatReader.h @@ -62,7 +62,7 @@ public: // For Media Resource Management void ReleaseMediaResources() override; - nsresult ResetDecode() override; + nsresult ResetDecode(TargetQueues aQueues) override; RefPtr Shutdown() override; @@ -82,7 +82,7 @@ public: mDemuxOnly = aDemuxedOnly; return; } - nsCOMPtr r = NS_NewRunnableMethodWithArg( + nsCOMPtr r = NewRunnableMethod( this, &MediaDecoderReader::SetDemuxOnly, aDemuxedOnly); OwnerThread()->Dispatch(r.forget()); } @@ -137,12 +137,15 @@ private: : mTime(aTime) , mDropTarget(aDropTarget) , mWaiting(false) + , mHasSeeked(false) {} media::TimeUnit mTime; bool mDropTarget; bool mWaiting; + bool mHasSeeked; }; + // Perform an internal seek to aTime. If aDropTarget is true then // the first sample past the target will be dropped. void InternalSeek(TrackType aTrack, const InternalSeekTarget& aTarget); @@ -167,10 +170,11 @@ private: void Output(TrackType aType, MediaData* aSample); void InputExhausted(TrackType aTrack); void Error(TrackType aTrack); - void Flush(TrackType aTrack); + void Reset(TrackType aTrack); void DrainComplete(TrackType aTrack); bool ShouldSkip(bool aSkipToNextKeyframe, media::TimeUnit aTimeThreshold); + void ResetDemuxers(); size_t SizeOfQueue(TrackType aTrack); @@ -291,6 +295,8 @@ private: MozPromiseRequestHolder mInitPromise; // False when decoder is created. True when decoder Init() promise is resolved. bool mDecoderInitialized; + // Set when decoding can proceed. It is reset when a decoding promise is + // rejected or prior a seek operation. bool mDecodingRequested; bool mOutputRequested; bool mInputExhausted; @@ -316,20 +322,47 @@ private: uint64_t mNumSamplesOutputTotalSinceTelemetry; uint64_t mNumSamplesSkippedTotalSinceTelemetry; - // These get overriden in the templated concrete class. + // These get overridden in the templated concrete class. // Indicate if we have a pending promise for decoded frame. // Rejecting the promise will stop the reader from decoding ahead. - virtual bool HasPromise() = 0; + virtual bool HasPromise() const = 0; + virtual RefPtr EnsurePromise(const char* aMethodName) = 0; + virtual void ResolvePromise(MediaData* aData, const char* aMethodName) = 0; virtual void RejectPromise(MediaDecoderReader::NotDecodedReason aReason, const char* aMethodName) = 0; + // Clear track demuxer related data. void ResetDemuxer() { - // Clear demuxer related data. mDemuxRequest.DisconnectIfExists(); + mSeekRequest.DisconnectIfExists(); mTrackDemuxer->Reset(); + mQueuedSamples.Clear(); } + // Flush the decoder if present and reset decoding related data. + // Decoding will be suspended until mInputRequested is set again. + // Following a flush, the decoder is ready to accept any new data. + void Flush() + { + if (mDecoder) { + mDecoder->Flush(); + } + mDecodingRequested = false; + mOutputRequested = false; + mInputExhausted = false; + mOutput.Clear(); + mNumSamplesInput = 0; + mNumSamplesOutput = 0; + mSizeOfQueue = 0; + mDraining = false; + mDrainComplete = false; + } + + // Reset the state of the DecoderData, clearing all queued frames + // (pending demuxed and decoded). + // Decoding will be suspended until mInputRequested is set again. + // The track demuxer is *not* reset. void ResetState() { MOZ_ASSERT(mOwner->OnTaskQueue()); @@ -353,6 +386,11 @@ private: mNextStreamSourceID.reset(); } + bool HasInternalSeekPending() const + { + return mTimeThreshold && !mTimeThreshold.ref().mHasSeeked; + } + // Used by the MDSM for logging purposes. Atomic mSizeOfQueue; // Used by the MDSM to determine if video decoding is hardware accelerated. @@ -366,19 +404,33 @@ private: RefPtr mInfo; }; - struct DecoderDataWithPromise : public DecoderData { + class DecoderDataWithPromise : public DecoderData { + public: DecoderDataWithPromise(MediaFormatReader* aOwner, MediaData::Type aType, - uint32_t aDecodeAhead) : - DecoderData(aOwner, aType, aDecodeAhead) + uint32_t aDecodeAhead) + : DecoderData(aOwner, aType, aDecodeAhead) + , mHasPromise(false) + {} - MozPromiseHolder mPromise; + bool HasPromise() const override + { + return mHasPromise; + } - bool HasPromise() override + RefPtr EnsurePromise(const char* aMethodName) override { MOZ_ASSERT(mOwner->OnTaskQueue()); - return !mPromise.IsEmpty(); + mHasPromise = true; + return mPromise.Ensure(aMethodName); + } + + void ResolvePromise(MediaData* aData, const char* aMethodName) override + { + MOZ_ASSERT(mOwner->OnTaskQueue()); + mPromise.Resolve(aData, aMethodName); + mHasPromise = false; } void RejectPromise(MediaDecoderReader::NotDecodedReason aReason, @@ -387,7 +439,12 @@ private: MOZ_ASSERT(mOwner->OnTaskQueue()); mPromise.Reject(aReason, aMethodName); mDecodingRequested = false; + mHasPromise = false; } + + private: + MozPromiseHolder mPromise; + Atomic mHasPromise; }; DecoderDataWithPromise mAudio; @@ -451,6 +508,7 @@ private: // Seeking objects. bool IsSeeking() const { return mPendingSeekTime.isSome(); } + void ScheduleSeek(); void AttemptSeek(); void OnSeekFailed(TrackType aTrack, DemuxerFailureReason aFailure); void DoVideoSeek(); @@ -459,6 +517,7 @@ private: { OnSeekFailed(TrackType::kVideoTrack, aFailure); } + bool mSeekScheduled; void DoAudioSeek(); void OnAudioSeekCompleted(media::TimeUnit aTime); diff --git a/dom/media/MediaManager.h b/dom/media/MediaManager.h index f034124adb..e35a1bff00 100644 --- a/dom/media/MediaManager.h +++ b/dom/media/MediaManager.h @@ -277,11 +277,11 @@ public: switch (aEvent) { case EVENT_FINISHED: NS_DispatchToMainThread( - NS_NewRunnableMethod(this, &GetUserMediaCallbackMediaStreamListener::NotifyFinished)); + NewRunnableMethod(this, &GetUserMediaCallbackMediaStreamListener::NotifyFinished)); break; case EVENT_REMOVED: NS_DispatchToMainThread( - NS_NewRunnableMethod(this, &GetUserMediaCallbackMediaStreamListener::NotifyRemoved)); + NewRunnableMethod(this, &GetUserMediaCallbackMediaStreamListener::NotifyRemoved)); break; case EVENT_HAS_DIRECT_LISTENERS: NotifyDirectListeners(aGraph, true); diff --git a/dom/media/MediaRecorder.cpp b/dom/media/MediaRecorder.cpp index b006fb77e1..0d93ecf404 100644 --- a/dom/media/MediaRecorder.cpp +++ b/dom/media/MediaRecorder.cpp @@ -832,10 +832,8 @@ private: new DispatchStartEventRunnable(this, NS_LITERAL_STRING("start"))); if (NS_FAILED(rv)) { - nsCOMPtr runnable = - NS_NewRunnableMethodWithArg(mRecorder, - &MediaRecorder::NotifyError, rv); - NS_DispatchToMainThread(runnable); + NS_DispatchToMainThread(NewRunnableMethod(mRecorder, + &MediaRecorder::NotifyError, rv)); } if (NS_FAILED(NS_DispatchToMainThread(new EncoderErrorNotifierRunnable(this)))) { MOZ_ASSERT(false, "NS_DispatchToMainThread EncoderErrorNotifierRunnable failed"); diff --git a/dom/media/MediaResource.cpp b/dom/media/MediaResource.cpp index 66cd7a01f5..b5b47bc23e 100644 --- a/dom/media/MediaResource.cpp +++ b/dom/media/MediaResource.cpp @@ -56,9 +56,8 @@ MediaResource::Destroy() delete this; return; } - nsCOMPtr destroyRunnable = - NS_NewNonOwningRunnableMethod(this, &MediaResource::Destroy); - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(destroyRunnable)); + MOZ_ALWAYS_SUCCEEDS( + NS_DispatchToMainThread(NewNonOwningRunnableMethod(this, &MediaResource::Destroy))); } NS_IMPL_ADDREF(MediaResource) @@ -871,7 +870,7 @@ ChannelMediaResource::CacheClientNotifyDataReceived() return; mDataReceivedEvent = - NS_NewNonOwningRunnableMethod(this, &ChannelMediaResource::DoNotifyDataReceived); + NewNonOwningRunnableMethod(this, &ChannelMediaResource::DoNotifyDataReceived); NS_DispatchToMainThread(mDataReceivedEvent.get()); } diff --git a/dom/media/MediaStreamTrack.cpp b/dom/media/MediaStreamTrack.cpp index 001076a1da..5b78598f49 100644 --- a/dom/media/MediaStreamTrack.cpp +++ b/dom/media/MediaStreamTrack.cpp @@ -89,7 +89,7 @@ public: const PrincipalHandle& aNewPrincipalHandle) override { nsCOMPtr runnable = - NS_NewRunnableMethodWithArgs>( + NewRunnableMethod>( this, &PrincipalHandleListener::DoNotifyPrincipalHandleChanged, aNewPrincipalHandle); aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget()); } diff --git a/dom/media/MediaTimer.cpp b/dom/media/MediaTimer.cpp index 89b14e26a8..1420d6aca1 100644 --- a/dom/media/MediaTimer.cpp +++ b/dom/media/MediaTimer.cpp @@ -38,12 +38,12 @@ MediaTimer::MediaTimer() void MediaTimer::DispatchDestroy() { - nsCOMPtr task = NS_NewNonOwningRunnableMethod(this, &MediaTimer::Destroy); // Hold a strong reference to the thread so that it doesn't get deleted in // Destroy(), which may run completely before the stack if Dispatch() begins // to unwind. nsCOMPtr thread = mThread; - nsresult rv = thread->Dispatch(task, NS_DISPATCH_NORMAL); + nsresult rv = thread->Dispatch(NewNonOwningRunnableMethod(this, &MediaTimer::Destroy), + NS_DISPATCH_NORMAL); MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); (void) rv; } @@ -97,8 +97,8 @@ MediaTimer::ScheduleUpdate() } mUpdateScheduled = true; - nsCOMPtr task = NS_NewRunnableMethod(this, &MediaTimer::Update); - nsresult rv = mThread->Dispatch(task, NS_DISPATCH_NORMAL); + nsresult rv = mThread->Dispatch(NewRunnableMethod(this, &MediaTimer::Update), + NS_DISPATCH_NORMAL); MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv)); (void) rv; } diff --git a/dom/media/RtspMediaResource.cpp b/dom/media/RtspMediaResource.cpp index 42a8c53bb8..8188579670 100644 --- a/dom/media/RtspMediaResource.cpp +++ b/dom/media/RtspMediaResource.cpp @@ -525,8 +525,8 @@ void RtspMediaResource::SetSuspend(bool aIsSuspend) RTSPMLOG("SetSuspend %d",aIsSuspend); nsCOMPtr runnable = - NS_NewRunnableMethodWithArg(this, &RtspMediaResource::NotifySuspend, - aIsSuspend); + NewRunnableMethod(this, &RtspMediaResource::NotifySuspend, + aIsSuspend); NS_DispatchToMainThread(runnable); } diff --git a/dom/media/SeekJob.cpp b/dom/media/SeekJob.cpp index 8c9bc94356..bc956cce1e 100644 --- a/dom/media/SeekJob.cpp +++ b/dom/media/SeekJob.cpp @@ -33,7 +33,7 @@ SeekJob& SeekJob::operator=(SeekJob&& aOther) return *this; } -bool SeekJob::Exists() +bool SeekJob::Exists() const { MOZ_ASSERT(mTarget.IsValid() == !mPromise.IsEmpty()); return mTarget.IsValid(); diff --git a/dom/media/SeekJob.h b/dom/media/SeekJob.h index b5391d641b..de158591a3 100644 --- a/dom/media/SeekJob.h +++ b/dom/media/SeekJob.h @@ -21,7 +21,7 @@ struct SeekJob { SeekJob& operator=(SeekJob&& aOther); - bool Exists(); + bool Exists() const; void Resolve(bool aAtEnd, const char* aCallSite); diff --git a/dom/media/SeekTarget.h b/dom/media/SeekTarget.h index 0d81ac58c6..0f1a04743e 100644 --- a/dom/media/SeekTarget.h +++ b/dom/media/SeekTarget.h @@ -17,12 +17,14 @@ enum class MediaDecoderEventVisibility : int8_t { }; // Stores the seek target; the time to seek to, and whether an Accurate, -// or "Fast" (nearest keyframe) seek was requested. +// "Fast" (nearest keyframe), or "Video Only" (no audio seek) seek was +// requested. struct SeekTarget { enum Type { Invalid, PrevSyncPoint, - Accurate + Accurate, + AccurateVideoOnly, }; SeekTarget() : mEventVisibility(MediaDecoderEventVisibility::Observable) @@ -78,6 +80,9 @@ struct SeekTarget { bool IsAccurate() const { return mType == SeekTarget::Type::Accurate; } + bool IsVideoOnly() const { + return mType == SeekTarget::Type::AccurateVideoOnly; + } MediaDecoderEventVisibility mEventVisibility; @@ -85,7 +90,7 @@ private: // Seek target time. media::TimeUnit mTime; // Whether we should seek "Fast", or "Accurate". - // "Fast" seeks to the seek point preceeding mTime, whereas + // "Fast" seeks to the seek point preceding mTime, whereas // "Accurate" seeks as close as possible to mTime. Type mType; }; diff --git a/dom/media/SeekTask.cpp b/dom/media/SeekTask.cpp index 9761f58973..c8093e6142 100644 --- a/dom/media/SeekTask.cpp +++ b/dom/media/SeekTask.cpp @@ -177,7 +177,7 @@ SeekTask::GetSeekJob() } bool -SeekTask::Exists() +SeekTask::Exists() const { return mSeekJob.Exists(); } @@ -422,6 +422,7 @@ SeekTask::IsAudioSeekComplete() mSeekJob.Exists(), mDropAudioUntilNextDiscontinuity, mIsAudioQueueFinished, !!mSeekedAudioData); return !HasAudio() || + mSeekJob.mTarget.IsVideoOnly() || (Exists() && !mDropAudioUntilNextDiscontinuity && (mIsAudioQueueFinished || mSeekedAudioData)); } @@ -478,8 +479,10 @@ SeekTask::OnSeekResolved(media::TimeUnit) mSeekRequest.Complete(); // We must decode the first samples of active streams, so we can determine // the new stream time. So dispatch tasks to do that. - EnsureAudioDecodeTaskQueued(); EnsureVideoDecodeTaskQueued(); + if (!mSeekJob.mTarget.IsVideoOnly()) { + EnsureAudioDecodeTaskQueued(); + } } void diff --git a/dom/media/SeekTask.h b/dom/media/SeekTask.h index 9929b27b5e..f9196ff3dd 100644 --- a/dom/media/SeekTask.h +++ b/dom/media/SeekTask.h @@ -63,7 +63,7 @@ public: SeekJob& GetSeekJob(); - bool Exists(); + bool Exists() const; protected: SeekTask(const void* aDecoderID, diff --git a/dom/media/android/AndroidMediaReader.cpp b/dom/media/android/AndroidMediaReader.cpp index 15153cb966..0197379e7c 100644 --- a/dom/media/android/AndroidMediaReader.cpp +++ b/dom/media/android/AndroidMediaReader.cpp @@ -95,7 +95,7 @@ nsresult AndroidMediaReader::ReadMetadata(MediaInfo* aInfo, RefPtr AndroidMediaReader::Shutdown() { - ResetDecode(); + ResetDecode(AUDIO_VIDEO); if (mPlugin) { GetAndroidMediaPluginHost()->DestroyDecoder(mPlugin); mPlugin = nullptr; @@ -105,14 +105,14 @@ AndroidMediaReader::Shutdown() } // Resets all state related to decoding, emptying all buffers etc. -nsresult AndroidMediaReader::ResetDecode() +nsresult AndroidMediaReader::ResetDecode(TargetQueues aQueues) { if (mLastVideoFrame) { mLastVideoFrame = nullptr; } mSeekRequest.DisconnectIfExists(); mSeekPromise.RejectIfExists(NS_OK, __func__); - return MediaDecoderReader::ResetDecode(); + return MediaDecoderReader::ResetDecode(aQueues); } bool AndroidMediaReader::DecodeVideoFrame(bool &aKeyframeSkip, diff --git a/dom/media/android/AndroidMediaReader.h b/dom/media/android/AndroidMediaReader.h index 0f6092a0f8..1b5b0c49a3 100644 --- a/dom/media/android/AndroidMediaReader.h +++ b/dom/media/android/AndroidMediaReader.h @@ -42,7 +42,7 @@ public: AndroidMediaReader(AbstractMediaDecoder* aDecoder, const nsACString& aContentType); - nsresult ResetDecode() override; + nsresult ResetDecode(TargetQueues aQueues) override; bool DecodeAudioData() override; bool DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) override; diff --git a/dom/media/gmp/GMPContentParent.cpp b/dom/media/gmp/GMPContentParent.cpp index 83d523c91a..4eea05ae2d 100644 --- a/dom/media/gmp/GMPContentParent.cpp +++ b/dom/media/gmp/GMPContentParent.cpp @@ -134,8 +134,8 @@ GMPContentParent::CloseIfUnused() GeckoMediaPluginServiceChild::GetSingleton()); gmp->RemoveGMPContentParent(toClose); } - NS_DispatchToCurrentThread(NS_NewRunnableMethod(toClose, - &GMPContentParent::Close)); + NS_DispatchToCurrentThread(NewRunnableMethod(toClose, + &GMPContentParent::Close)); } } diff --git a/dom/media/gmp/GMPContentParent.h b/dom/media/gmp/GMPContentParent.h index 0003b5e1af..38fd775f7c 100644 --- a/dom/media/gmp/GMPContentParent.h +++ b/dom/media/gmp/GMPContentParent.h @@ -79,7 +79,7 @@ private: bool DeallocPGMPAudioDecoderParent(PGMPAudioDecoderParent* aActor) override; void CloseIfUnused(); - // Needed because NS_NewRunnableMethod tried to use the class that the method + // Needed because NewRunnableMethod tried to use the class that the method // lives on to store the receiver, but PGMPContentParent isn't refcounted. void Close() { diff --git a/dom/media/gmp/GMPDecryptorChild.cpp b/dom/media/gmp/GMPDecryptorChild.cpp index 0627aad15e..ebecf239e8 100644 --- a/dom/media/gmp/GMPDecryptorChild.cpp +++ b/dom/media/gmp/GMPDecryptorChild.cpp @@ -61,7 +61,8 @@ GMPDecryptorChild::CallOnGMPThread(MethodType aMethod, ParamType&&... aParams) // Use const reference when we have to. auto m = &GMPDecryptorChild::CallMethod< decltype(aMethod), typename AddConstReference::Type...>; - RefPtr t = NewRunnableMethod(this, m, aMethod, Forward(aParams)...); + RefPtr t = + dont_add_new_uses_of_this::NewRunnableMethod(this, m, aMethod, Forward(aParams)...); mPlugin->GMPMessageLoop()->PostTask(t.forget()); } } @@ -170,8 +171,10 @@ GMPDecryptorChild::Decrypted(GMPBuffer* aBuffer, GMPErr aResult) if (!ON_GMP_THREAD()) { // We should run this whole method on the GMP thread since the buffer needs // to be deleted after the SendDecrypted call. - RefPtr t = NewRunnableMethod(this, &GMPDecryptorChild::Decrypted, aBuffer, aResult); - mPlugin->GMPMessageLoop()->PostTask(t.forget()); + mPlugin->GMPMessageLoop()->PostTask(NewRunnableMethod + (this, + &GMPDecryptorChild::Decrypted, + aBuffer, aResult)); return; } diff --git a/dom/media/gmp/GMPDiskStorage.cpp b/dom/media/gmp/GMPDiskStorage.cpp new file mode 100644 index 0000000000..e67f90f7d1 --- /dev/null +++ b/dom/media/gmp/GMPDiskStorage.cpp @@ -0,0 +1,499 @@ +/* -*- 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 "plhash.h" +#include "nsDirectoryServiceUtils.h" +#include "nsDirectoryServiceDefs.h" +#include "nsAppDirectoryServiceDefs.h" +#include "GMPParent.h" +#include "gmp-storage.h" +#include "mozilla/unused.h" +#include "mozilla/Endian.h" +#include "nsClassHashtable.h" +#include "prio.h" +#include "mozIGeckoMediaPluginService.h" +#include "nsContentCID.h" +#include "nsServiceManagerUtils.h" +#include "nsISimpleEnumerator.h" + +namespace mozilla { + +#ifdef LOG +#undef LOG +#endif + +extern LogModule* GetGMPLog(); + +#define LOGD(msg) MOZ_LOG(GetGMPLog(), mozilla::LogLevel::Debug, msg) +#define LOG(level, msg) MOZ_LOG(GetGMPLog(), (level), msg) + +namespace gmp { + +// We store the records for a given GMP as files in the profile dir. +// $profileDir/gmp/$platform/$gmpName/storage/$nodeId/ +static nsresult +GetGMPStorageDir(nsIFile** aTempDir, + const nsString& aGMPName, + const nsCString& aNodeId) +{ + if (NS_WARN_IF(!aTempDir)) { + return NS_ERROR_INVALID_ARG; + } + + nsCOMPtr mps = + do_GetService("@mozilla.org/gecko-media-plugin-service;1"); + if (NS_WARN_IF(!mps)) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr tmpFile; + nsresult rv = mps->GetStorageDir(getter_AddRefs(tmpFile)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = tmpFile->Append(aGMPName); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); + if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = tmpFile->AppendNative(NS_LITERAL_CSTRING("storage")); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); + if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = tmpFile->AppendNative(aNodeId); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); + if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + tmpFile.forget(aTempDir); + + return NS_OK; +} + +// Disk-backed GMP storage. Records are stored in files on disk in +// the profile directory. The record name is a hash of the filename, +// and we resolve hash collisions by just adding 1 to the hash code. +// The format of records on disk is: +// 4 byte, uint32_t $recordNameLength, in little-endian byte order, +// record name (i.e. $recordNameLength bytes, no null terminator) +// record bytes (entire remainder of file) +class GMPDiskStorage : public GMPStorage { +public: + explicit GMPDiskStorage(const nsCString& aNodeId, + const nsString& aGMPName) + : mNodeId(aNodeId) + , mGMPName(aGMPName) + { + } + + ~GMPDiskStorage() { + // Close all open file handles. + for (auto iter = mRecords.ConstIter(); !iter.Done(); iter.Next()) { + Record* record = iter.UserData(); + if (record->mFileDesc) { + PR_Close(record->mFileDesc); + record->mFileDesc = nullptr; + } + } + } + + nsresult Init() { + // Build our index of records on disk. + nsCOMPtr storageDir; + nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mGMPName, mNodeId); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NS_ERROR_FAILURE; + } + + DirectoryEnumerator iter(storageDir, DirectoryEnumerator::FilesAndDirs); + for (nsCOMPtr dirEntry; (dirEntry = iter.Next()) != nullptr;) { + PRFileDesc* fd = nullptr; + if (NS_FAILED(dirEntry->OpenNSPRFileDesc(PR_RDONLY, 0, &fd))) { + continue; + } + int32_t recordLength = 0; + nsCString recordName; + nsresult err = ReadRecordMetadata(fd, recordLength, recordName); + PR_Close(fd); + if (NS_FAILED(err)) { + // File is not a valid storage file. Don't index it. Delete the file, + // to make our indexing faster in future. + dirEntry->Remove(false); + continue; + } + + nsAutoString filename; + rv = dirEntry->GetLeafName(filename); + if (NS_FAILED(rv)) { + continue; + } + + mRecords.Put(recordName, new Record(filename, recordName)); + } + + return NS_OK; + } + + GMPErr Open(const nsCString& aRecordName) override + { + MOZ_ASSERT(!IsOpen(aRecordName)); + nsresult rv; + Record* record = nullptr; + if (!mRecords.Get(aRecordName, &record)) { + // New file. + nsAutoString filename; + rv = GetUnusedFilename(aRecordName, filename); + if (NS_WARN_IF(NS_FAILED(rv))) { + return GMPGenericErr; + } + record = new Record(filename, aRecordName); + mRecords.Put(aRecordName, record); + } + + MOZ_ASSERT(record); + if (record->mFileDesc) { + NS_WARNING("Tried to open already open record"); + return GMPRecordInUse; + } + + rv = OpenStorageFile(record->mFilename, ReadWrite, &record->mFileDesc); + if (NS_WARN_IF(NS_FAILED(rv))) { + return GMPGenericErr; + } + + MOZ_ASSERT(IsOpen(aRecordName)); + + return GMPNoErr; + } + + bool IsOpen(const nsCString& aRecordName) const override { + // We are open if we have a record indexed, and it has a valid + // file descriptor. + const Record* record = mRecords.Get(aRecordName); + return record && !!record->mFileDesc; + } + + GMPErr Read(const nsCString& aRecordName, + nsTArray& aOutBytes) override + { + if (!IsOpen(aRecordName)) { + return GMPClosedErr; + } + + Record* record = nullptr; + mRecords.Get(aRecordName, &record); + MOZ_ASSERT(record && !!record->mFileDesc); // IsOpen() guarantees this. + + // Our error strategy is to report records with invalid contents as + // containing 0 bytes. Zero length records are considered "deleted" by + // the GMPStorage API. + aOutBytes.SetLength(0); + + int32_t recordLength = 0; + nsCString recordName; + nsresult err = ReadRecordMetadata(record->mFileDesc, + recordLength, + recordName); + if (NS_FAILED(err) || recordLength == 0) { + // We failed to read the record metadata. Or the record is 0 length. + // Treat damaged records as empty. + // ReadRecordMetadata() could fail if the GMP opened a new record and + // tried to read it before anything was written to it.. + return GMPNoErr; + } + + if (!aRecordName.Equals(recordName)) { + NS_WARNING("Record file contains some other record's contents!"); + return GMPRecordCorrupted; + } + + // After calling ReadRecordMetadata, we should be ready to read the + // record data. + if (PR_Available(record->mFileDesc) != recordLength) { + NS_WARNING("Record file length mismatch!"); + return GMPRecordCorrupted; + } + + aOutBytes.SetLength(recordLength); + int32_t bytesRead = PR_Read(record->mFileDesc, aOutBytes.Elements(), recordLength); + return (bytesRead == recordLength) ? GMPNoErr : GMPRecordCorrupted; + } + + GMPErr Write(const nsCString& aRecordName, + const nsTArray& aBytes) override + { + if (!IsOpen(aRecordName)) { + return GMPClosedErr; + } + + Record* record = nullptr; + mRecords.Get(aRecordName, &record); + MOZ_ASSERT(record && !!record->mFileDesc); // IsOpen() guarantees this. + + // Write operations overwrite the entire record. So close it now. + PR_Close(record->mFileDesc); + record->mFileDesc = nullptr; + + // Writing 0 bytes means removing (deleting) the file. + if (aBytes.Length() == 0) { + nsresult rv = RemoveStorageFile(record->mFilename); + if (NS_WARN_IF(NS_FAILED(rv))) { + // Could not delete file -> Continue with trying to erase the contents. + } else { + return GMPNoErr; + } + } + + // Write operations overwrite the entire record. So re-open the file + // in truncate mode, to clear its contents. + if (NS_FAILED(OpenStorageFile(record->mFilename, + Truncate, + &record->mFileDesc))) { + return GMPGenericErr; + } + + // Store the length of the record name followed by the record name + // at the start of the file. + int32_t bytesWritten = 0; + char buf[sizeof(uint32_t)] = {0}; + LittleEndian::writeUint32(buf, aRecordName.Length()); + bytesWritten = PR_Write(record->mFileDesc, buf, MOZ_ARRAY_LENGTH(buf)); + if (bytesWritten != MOZ_ARRAY_LENGTH(buf)) { + NS_WARNING("Failed to write GMPStorage record name length."); + return GMPRecordCorrupted; + } + bytesWritten = PR_Write(record->mFileDesc, + aRecordName.get(), + aRecordName.Length()); + if (bytesWritten != (int32_t)aRecordName.Length()) { + NS_WARNING("Failed to write GMPStorage record name."); + return GMPRecordCorrupted; + } + + bytesWritten = PR_Write(record->mFileDesc, aBytes.Elements(), aBytes.Length()); + if (bytesWritten != (int32_t)aBytes.Length()) { + NS_WARNING("Failed to write GMPStorage record data."); + return GMPRecordCorrupted; + } + + // Try to sync the file to disk, so that in the event of a crash, + // the record is less likely to be corrupted. + PR_Sync(record->mFileDesc); + + return GMPNoErr; + } + + GMPErr GetRecordNames(nsTArray& aOutRecordNames) const override + { + for (auto iter = mRecords.ConstIter(); !iter.Done(); iter.Next()) { + aOutRecordNames.AppendElement(iter.UserData()->mRecordName); + } + return GMPNoErr; + } + + void Close(const nsCString& aRecordName) override + { + Record* record = nullptr; + mRecords.Get(aRecordName, &record); + if (record && !!record->mFileDesc) { + PR_Close(record->mFileDesc); + record->mFileDesc = nullptr; + } + MOZ_ASSERT(!IsOpen(aRecordName)); + } + +private: + + // We store records in a file which is a hash of the record name. + // If there is a hash collision, we just keep adding 1 to the hash + // code, until we find a free slot. + nsresult GetUnusedFilename(const nsACString& aRecordName, + nsString& aOutFilename) + { + nsCOMPtr storageDir; + nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mGMPName, mNodeId); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + uint64_t recordNameHash = HashString(PromiseFlatCString(aRecordName).get()); + for (int i = 0; i < 1000000; i++) { + nsCOMPtr f; + rv = storageDir->Clone(getter_AddRefs(f)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + nsAutoString hashStr; + hashStr.AppendInt(recordNameHash); + rv = f->Append(hashStr); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + bool exists = false; + f->Exists(&exists); + if (!exists) { + // Filename not in use, we can write into this file. + aOutFilename = hashStr; + return NS_OK; + } else { + // Hash collision; just increment the hash name and try that again. + ++recordNameHash; + continue; + } + } + // Somehow, we've managed to completely fail to find a vacant file name. + // Give up. + NS_WARNING("GetUnusedFilename had extreme hash collision!"); + return NS_ERROR_FAILURE; + } + + enum OpenFileMode { ReadWrite, Truncate }; + + nsresult OpenStorageFile(const nsAString& aFileLeafName, + const OpenFileMode aMode, + PRFileDesc** aOutFD) + { + MOZ_ASSERT(aOutFD); + + nsCOMPtr f; + nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mGMPName, mNodeId); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + f->Append(aFileLeafName); + + auto mode = PR_RDWR | PR_CREATE_FILE; + if (aMode == Truncate) { + mode |= PR_TRUNCATE; + } + + return f->OpenNSPRFileDesc(mode, PR_IRWXU, aOutFD); + } + + nsresult ReadRecordMetadata(PRFileDesc* aFd, + int32_t& aOutRecordLength, + nsACString& aOutRecordName) + { + int32_t offset = PR_Seek(aFd, 0, PR_SEEK_END); + PR_Seek(aFd, 0, PR_SEEK_SET); + + if (offset < 0 || offset > GMP_MAX_RECORD_SIZE) { + // Refuse to read big records, or records where we can't get a length. + return NS_ERROR_FAILURE; + } + const uint32_t fileLength = static_cast(offset); + + // At the start of the file the length of the record name is stored in a + // uint32_t (little endian byte order) followed by the record name at the + // start of the file. The record name is not null terminated. The remainder + // of the file is the record's data. + + if (fileLength < sizeof(uint32_t)) { + // Record file doesn't have enough contents to store the record name + // length. Fail. + return NS_ERROR_FAILURE; + } + + // Read length, and convert to host byte order. + uint32_t recordNameLength = 0; + char buf[sizeof(recordNameLength)] = { 0 }; + int32_t bytesRead = PR_Read(aFd, &buf, sizeof(recordNameLength)); + recordNameLength = LittleEndian::readUint32(buf); + if (sizeof(recordNameLength) != bytesRead || + recordNameLength == 0 || + recordNameLength + sizeof(recordNameLength) > fileLength || + recordNameLength > GMP_MAX_RECORD_NAME_SIZE) { + // Record file has invalid contents. Fail. + return NS_ERROR_FAILURE; + } + + nsCString recordName; + recordName.SetLength(recordNameLength); + bytesRead = PR_Read(aFd, recordName.BeginWriting(), recordNameLength); + if ((uint32_t)bytesRead != recordNameLength) { + // Read failed. + return NS_ERROR_FAILURE; + } + + MOZ_ASSERT(fileLength >= sizeof(recordNameLength) + recordNameLength); + int32_t recordLength = fileLength - (sizeof(recordNameLength) + recordNameLength); + + aOutRecordLength = recordLength; + aOutRecordName = recordName; + + // Read cursor should be positioned after the record name, before the record contents. + if (PR_Seek(aFd, 0, PR_SEEK_CUR) != (int32_t)(sizeof(recordNameLength) + recordNameLength)) { + NS_WARNING("Read cursor mismatch after ReadRecordMetadata()"); + return NS_ERROR_FAILURE; + } + + return NS_OK; + } + + nsresult RemoveStorageFile(const nsString& aFilename) + { + nsCOMPtr f; + nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mGMPName, mNodeId); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + rv = f->Append(aFilename); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + return f->Remove(/* bool recursive= */ false); + } + + struct Record { + Record(const nsAString& aFilename, + const nsACString& aRecordName) + : mFilename(aFilename) + , mRecordName(aRecordName) + , mFileDesc(0) + {} + ~Record() { + MOZ_ASSERT(!mFileDesc); + } + nsString mFilename; + nsCString mRecordName; + PRFileDesc* mFileDesc; + }; + + // Hash record name to record data. + nsClassHashtable mRecords; + const nsCString mNodeId; + const nsString mGMPName; +}; + +already_AddRefed CreateGMPDiskStorage(const nsCString& aNodeId, + const nsString& aGMPName) +{ + RefPtr storage(new GMPDiskStorage(aNodeId, aGMPName)); + if (NS_FAILED(storage->Init())) { + NS_WARNING("Failed to initialize on disk GMP storage"); + return nullptr; + } + return storage.forget(); +} + +} // namespace gmp +} // namespace mozilla diff --git a/dom/media/gmp/GMPMemoryStorage.cpp b/dom/media/gmp/GMPMemoryStorage.cpp new file mode 100644 index 0000000000..dc799caa12 --- /dev/null +++ b/dom/media/gmp/GMPMemoryStorage.cpp @@ -0,0 +1,95 @@ +/* -*- 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 "GMPStorage.h" +#include "nsClassHashtable.h" + +namespace mozilla { +namespace gmp { + +class GMPMemoryStorage : public GMPStorage { +public: + GMPErr Open(const nsCString& aRecordName) override + { + MOZ_ASSERT(!IsOpen(aRecordName)); + + Record* record = nullptr; + if (!mRecords.Get(aRecordName, &record)) { + record = new Record(); + mRecords.Put(aRecordName, record); + } + record->mIsOpen = true; + return GMPNoErr; + } + + bool IsOpen(const nsCString& aRecordName) const override { + const Record* record = mRecords.Get(aRecordName); + if (!record) { + return false; + } + return record->mIsOpen; + } + + GMPErr Read(const nsCString& aRecordName, + nsTArray& aOutBytes) override + { + const Record* record = mRecords.Get(aRecordName); + if (!record) { + return GMPGenericErr; + } + aOutBytes = record->mData; + return GMPNoErr; + } + + GMPErr Write(const nsCString& aRecordName, + const nsTArray& aBytes) override + { + Record* record = nullptr; + if (!mRecords.Get(aRecordName, &record)) { + return GMPClosedErr; + } + record->mData = aBytes; + return GMPNoErr; + } + + GMPErr GetRecordNames(nsTArray& aOutRecordNames) const override + { + for (auto iter = mRecords.ConstIter(); !iter.Done(); iter.Next()) { + aOutRecordNames.AppendElement(iter.Key()); + } + return GMPNoErr; + } + + void Close(const nsCString& aRecordName) override + { + Record* record = nullptr; + if (!mRecords.Get(aRecordName, &record)) { + return; + } + if (!record->mData.Length()) { + // Record is empty, delete. + mRecords.Remove(aRecordName); + } else { + record->mIsOpen = false; + } + } + +private: + + struct Record { + nsTArray mData; + bool mIsOpen = false; + }; + + nsClassHashtable mRecords; +}; + +already_AddRefed CreateGMPMemoryStorage() +{ + return RefPtr(new GMPMemoryStorage()).forget(); +} + +} // namespace gmp +} // namespace mozilla diff --git a/dom/media/gmp/GMPParent.cpp b/dom/media/gmp/GMPParent.cpp index d9af06adaa..a68a72f1e9 100644 --- a/dom/media/gmp/GMPParent.cpp +++ b/dom/media/gmp/GMPParent.cpp @@ -507,7 +507,7 @@ GMPParent::ChildTerminated() // removed so there is no harm in not trying to remove it again. LOGD("%s::%s: GMPThread() returned nullptr.", __CLASS__, __FUNCTION__); } else { - gmpThread->Dispatch(NS_NewRunnableMethodWithArg>( + gmpThread->Dispatch(NewRunnableMethod>( mService, &GeckoMediaPluginServiceParent::PluginTerminated, self), @@ -526,7 +526,7 @@ GMPParent::DeleteProcess() mState = GMPStateClosing; Close(); } - mProcess->Delete(NS_NewRunnableMethod(this, &GMPParent::ChildTerminated)); + mProcess->Delete(NewRunnableMethod(this, &GMPParent::ChildTerminated)); LOGD("%s: Shut down process", __FUNCTION__); mProcess = nullptr; mState = GMPStateNotLoaded; diff --git a/dom/media/gmp/GMPPlatform.cpp b/dom/media/gmp/GMPPlatform.cpp index 0c7b273a24..4746795700 100644 --- a/dom/media/gmp/GMPPlatform.cpp +++ b/dom/media/gmp/GMPPlatform.cpp @@ -121,7 +121,7 @@ RunOnMainThread(GMPTask* aTask) } RefPtr r = new GMPRunnable(aTask); - sMainLoop->PostTask(NewRunnableMethod(r.get(), &GMPRunnable::Run)); + sMainLoop->PostTask(NewRunnableMethod(r, &GMPRunnable::Run)); return GMPNoErr; } @@ -253,7 +253,6 @@ GMPThreadImpl::Post(GMPTask* aTask) } RefPtr r = new GMPRunnable(aTask); - mThread.message_loop()->PostTask(NewRunnableMethod(r.get(), &GMPRunnable::Run)); } diff --git a/dom/media/gmp/GMPProcessParent.cpp b/dom/media/gmp/GMPProcessParent.cpp index 94116c56e4..ed1903bce4 100644 --- a/dom/media/gmp/GMPProcessParent.cpp +++ b/dom/media/gmp/GMPProcessParent.cpp @@ -24,13 +24,6 @@ using mozilla::gmp::GMPProcessParent; using mozilla::ipc::GeckoChildProcessHost; using base::ProcessArchitecture; -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(GMPProcessParent* obj) { } - static void ReleaseCallee(GMPProcessParent* obj) { } -}; - namespace mozilla { namespace gmp { @@ -85,7 +78,7 @@ void GMPProcessParent::Delete(nsCOMPtr aCallback) { mDeletedCallback = aCallback; - XRE_GetIOMessageLoop()->PostTask(NewRunnableMethod(this, &GMPProcessParent::DoDelete)); + XRE_GetIOMessageLoop()->PostTask(NewNonOwningRunnableMethod(this, &GMPProcessParent::DoDelete)); } void diff --git a/dom/media/gmp/GMPService.cpp b/dom/media/gmp/GMPService.cpp index 48dffe4cb8..10e3b1ea94 100644 --- a/dom/media/gmp/GMPService.cpp +++ b/dom/media/gmp/GMPService.cpp @@ -326,7 +326,16 @@ GeckoMediaPluginService::ShutdownGMPThread() } nsresult -GeckoMediaPluginService::GMPDispatch(nsIRunnable* event, uint32_t flags) +GeckoMediaPluginService::GMPDispatch(nsIRunnable* event, + uint32_t flags) +{ + nsCOMPtr r(event); + return GMPDispatch(r.forget()); +} + +nsresult +GeckoMediaPluginService::GMPDispatch(already_AddRefed event, + uint32_t flags) { nsCOMPtr r(event); nsCOMPtr thread; diff --git a/dom/media/gmp/GMPService.h b/dom/media/gmp/GMPService.h index af329923d7..1efa6a9774 100644 --- a/dom/media/gmp/GMPService.h +++ b/dom/media/gmp/GMPService.h @@ -90,6 +90,7 @@ protected: UniquePtr&& aCallback) = 0; nsresult GMPDispatch(nsIRunnable* event, uint32_t flags = NS_DISPATCH_NORMAL); + nsresult GMPDispatch(already_AddRefed event, uint32_t flags = NS_DISPATCH_NORMAL); void ShutdownGMPThread(); Mutex mMutex; // Protects mGMPThread and mGMPThreadShutdown and some members diff --git a/dom/media/gmp/GMPServiceParent.cpp b/dom/media/gmp/GMPServiceParent.cpp index b9e75fb78f..450ac20261 100644 --- a/dom/media/gmp/GMPServiceParent.cpp +++ b/dom/media/gmp/GMPServiceParent.cpp @@ -419,8 +419,8 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject, NS_LITERAL_CSTRING("Dispatching UnloadPlugins")); #endif gmpThread->Dispatch( - NS_NewRunnableMethod(this, - &GeckoMediaPluginServiceParent::UnloadPlugins), + NewRunnableMethod(this, + &GeckoMediaPluginServiceParent::UnloadPlugins), NS_DISPATCH_NORMAL); #ifdef MOZ_CRASHREPORTER @@ -493,7 +493,7 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject, } else if (!strcmp("browser:purge-session-history", aTopic)) { // Clear everything! if (!aSomeData || nsDependentString(aSomeData).IsEmpty()) { - return GMPDispatch(NS_NewRunnableMethod( + return GMPDispatch(NewRunnableMethod( this, &GeckoMediaPluginServiceParent::ClearStorage)); } @@ -503,7 +503,7 @@ GeckoMediaPluginServiceParent::Observe(nsISupports* aSubject, if (NS_FAILED(rv)) { return rv; } - return GMPDispatch(NS_NewRunnableMethodWithArg( + return GMPDispatch(NewRunnableMethod( this, &GeckoMediaPluginServiceParent::ClearRecentHistoryOnGMPThread, t)); } @@ -605,7 +605,7 @@ GeckoMediaPluginServiceParent::AsyncShutdownComplete(GMPParent* aParent) if (mShuttingDownOnGMPThread) { // The main thread may be waiting for async shutdown of plugins, // one of which has completed. Wake up the main thread by sending a task. - nsCOMPtr task(NS_NewRunnableMethod( + nsCOMPtr task(NewRunnableMethod( this, &GeckoMediaPluginServiceParent::NotifyAsyncShutdownComplete)); NS_DispatchToMainThread(task); } @@ -737,7 +737,7 @@ GeckoMediaPluginServiceParent::UnloadPlugins() SetAsyncShutdownPluginState(nullptr, '3', NS_LITERAL_CSTRING("Dispatching sync-shutdown-complete")); #endif - nsCOMPtr task(NS_NewRunnableMethod( + nsCOMPtr task(NewRunnableMethod( this, &GeckoMediaPluginServiceParent::NotifySyncShutdownComplete)); NS_DispatchToMainThread(task); } @@ -1300,6 +1300,17 @@ ReadSalt(nsIFile* aPath, nsACString& aOutData) } +already_AddRefed +GeckoMediaPluginServiceParent::GetMemoryStorageFor(const nsACString& aNodeId) +{ + RefPtr s; + if (!mTempGMPStorage.Get(aNodeId, getter_AddRefs(s))) { + s = CreateGMPMemoryStorage(); + mTempGMPStorage.Put(aNodeId, s); + } + return s.forget(); +} + NS_IMETHODIMP GeckoMediaPluginServiceParent::IsPersistentStorageAllowed(const nsACString& aNodeId, bool* aOutAllowed) @@ -1749,7 +1760,7 @@ NS_IMETHODIMP GeckoMediaPluginServiceParent::ForgetThisSite(const nsAString& aSite) { MOZ_ASSERT(NS_IsMainThread()); - return GMPDispatch(NS_NewRunnableMethodWithArg( + return GMPDispatch(NewRunnableMethod( this, &GeckoMediaPluginServiceParent::ForgetThisSiteOnGMPThread, NS_ConvertUTF16toUTF8(aSite))); } @@ -1776,6 +1787,10 @@ GeckoMediaPluginServiceParent::ClearStorage() if (NS_FAILED(DeleteDir(path))) { NS_WARNING("Failed to delete GMP storage directory"); } + + // Clear private-browsing storage. + mTempGMPStorage.Clear(); + NS_DispatchToMainThread(new NotifyObserversTask("gmp-clear-storage-complete"), NS_DISPATCH_NORMAL); } diff --git a/dom/media/gmp/GMPServiceParent.h b/dom/media/gmp/GMPServiceParent.h index 3a5d0987a1..5f456c4c1a 100644 --- a/dom/media/gmp/GMPServiceParent.h +++ b/dom/media/gmp/GMPServiceParent.h @@ -14,6 +14,7 @@ #include "mozilla/Atomics.h" #include "nsThreadUtils.h" #include "mozilla/MozPromise.h" +#include "GMPStorage.h" template struct already_AddRefed; @@ -62,6 +63,8 @@ public: // GMP thread access only bool IsShuttingDown(); + already_AddRefed GetMemoryStorageFor(const nsACString& aNodeId); + private: friend class GMPServiceParent; @@ -204,6 +207,9 @@ private: Monitor mInitPromiseMonitor; MozPromiseHolder mInitPromise; bool mLoadPluginsFromDiskComplete; + + // Hashes nodeId to the hashtable of storage for that nodeId. + nsRefPtrHashtable mTempGMPStorage; }; nsresult ReadSalt(nsIFile* aPath, nsACString& aOutData); diff --git a/dom/media/gmp/GMPStorage.h b/dom/media/gmp/GMPStorage.h new file mode 100644 index 0000000000..db3aebc8c7 --- /dev/null +++ b/dom/media/gmp/GMPStorage.h @@ -0,0 +1,41 @@ +/* -*- 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/. */ + +#ifndef GMPStorage_h_ +#define GMPStorage_h_ + +#include "gmp-storage.h" +#include "mozilla/AlreadyAddRefed.h" +#include "nsISupportsImpl.h" +#include "nsString.h" +#include "nsTArray.h" + +namespace mozilla { +namespace gmp { + +class GMPStorage { +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(GMPStorage) + + virtual GMPErr Open(const nsCString& aRecordName) = 0; + virtual bool IsOpen(const nsCString& aRecordName) const = 0; + virtual GMPErr Read(const nsCString& aRecordName, + nsTArray& aOutBytes) = 0; + virtual GMPErr Write(const nsCString& aRecordName, + const nsTArray& aBytes) = 0; + virtual GMPErr GetRecordNames(nsTArray& aOutRecordNames) const = 0; + virtual void Close(const nsCString& aRecordName) = 0; +protected: + virtual ~GMPStorage() {} +}; + +already_AddRefed CreateGMPMemoryStorage(); +already_AddRefed CreateGMPDiskStorage(const nsCString& aNodeId, + const nsString& aGMPName); + +} // namespace gmp +} // namespace mozilla + +#endif \ No newline at end of file diff --git a/dom/media/gmp/GMPStorageChild.cpp b/dom/media/gmp/GMPStorageChild.cpp index 62056cd8ff..37186c16bd 100644 --- a/dom/media/gmp/GMPStorageChild.cpp +++ b/dom/media/gmp/GMPStorageChild.cpp @@ -15,7 +15,7 @@ _func(__VA_ARGS__); \ } else { \ mPlugin->GMPMessageLoop()->PostTask( \ - NewRunnableMethod(this, &GMPStorageChild::_func, ##__VA_ARGS__) \ + dont_add_new_uses_of_this::NewRunnableMethod(this, &GMPStorageChild::_func, ##__VA_ARGS__) \ ); \ } \ } while(false) diff --git a/dom/media/gmp/GMPStorageParent.cpp b/dom/media/gmp/GMPStorageParent.cpp index 5a83b5adb8..be7543bd76 100644 --- a/dom/media/gmp/GMPStorageParent.cpp +++ b/dom/media/gmp/GMPStorageParent.cpp @@ -4,20 +4,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "GMPStorageParent.h" -#include "plhash.h" -#include "nsDirectoryServiceUtils.h" -#include "nsDirectoryServiceDefs.h" -#include "nsAppDirectoryServiceDefs.h" #include "GMPParent.h" #include "gmp-storage.h" #include "mozilla/unused.h" -#include "mozilla/Endian.h" -#include "nsClassHashtable.h" -#include "prio.h" #include "mozIGeckoMediaPluginService.h" -#include "nsContentCID.h" -#include "nsServiceManagerUtils.h" -#include "nsISimpleEnumerator.h" namespace mozilla { @@ -32,538 +22,6 @@ extern LogModule* GetGMPLog(); namespace gmp { -// We store the records for a given GMP as files in the profile dir. -// $profileDir/gmp/$platform/$gmpName/storage/$nodeId/ -static nsresult -GetGMPStorageDir(nsIFile** aTempDir, - const nsString& aGMPName, - const nsCString& aNodeId) -{ - if (NS_WARN_IF(!aTempDir)) { - return NS_ERROR_INVALID_ARG; - } - - nsCOMPtr mps = - do_GetService("@mozilla.org/gecko-media-plugin-service;1"); - if (NS_WARN_IF(!mps)) { - return NS_ERROR_FAILURE; - } - - nsCOMPtr tmpFile; - nsresult rv = mps->GetStorageDir(getter_AddRefs(tmpFile)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = tmpFile->Append(aGMPName); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); - if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = tmpFile->AppendNative(NS_LITERAL_CSTRING("storage")); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); - if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = tmpFile->AppendNative(aNodeId); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - rv = tmpFile->Create(nsIFile::DIRECTORY_TYPE, 0700); - if (rv != NS_ERROR_FILE_ALREADY_EXISTS && NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - tmpFile.forget(aTempDir); - - return NS_OK; -} - -// Disk-backed GMP storage. Records are stored in files on disk in -// the profile directory. The record name is a hash of the filename, -// and we resolve hash collisions by just adding 1 to the hash code. -// The format of records on disk is: -// 4 byte, uint32_t $recordNameLength, in little-endian byte order, -// record name (i.e. $recordNameLength bytes, no null terminator) -// record bytes (entire remainder of file) -class GMPDiskStorage : public GMPStorage { -public: - explicit GMPDiskStorage(const nsCString& aNodeId, - const nsString& aGMPName) - : mNodeId(aNodeId) - , mGMPName(aGMPName) - { - } - - ~GMPDiskStorage() { - // Close all open file handles. - for (auto iter = mRecords.ConstIter(); !iter.Done(); iter.Next()) { - Record* record = iter.UserData(); - if (record->mFileDesc) { - PR_Close(record->mFileDesc); - record->mFileDesc = nullptr; - } - } - } - - nsresult Init() { - // Build our index of records on disk. - nsCOMPtr storageDir; - nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mGMPName, mNodeId); - if (NS_WARN_IF(NS_FAILED(rv))) { - return NS_ERROR_FAILURE; - } - - DirectoryEnumerator iter(storageDir, DirectoryEnumerator::FilesAndDirs); - for (nsCOMPtr dirEntry; (dirEntry = iter.Next()) != nullptr;) { - PRFileDesc* fd = nullptr; - if (NS_FAILED(dirEntry->OpenNSPRFileDesc(PR_RDONLY, 0, &fd))) { - continue; - } - int32_t recordLength = 0; - nsCString recordName; - nsresult err = ReadRecordMetadata(fd, recordLength, recordName); - PR_Close(fd); - if (NS_FAILED(err)) { - // File is not a valid storage file. Don't index it. Delete the file, - // to make our indexing faster in future. - dirEntry->Remove(false); - continue; - } - - nsAutoString filename; - rv = dirEntry->GetLeafName(filename); - if (NS_FAILED(rv)) { - continue; - } - - mRecords.Put(recordName, new Record(filename, recordName)); - } - - return NS_OK; - } - - GMPErr Open(const nsCString& aRecordName) override - { - MOZ_ASSERT(!IsOpen(aRecordName)); - nsresult rv; - Record* record = nullptr; - if (!mRecords.Get(aRecordName, &record)) { - // New file. - nsAutoString filename; - rv = GetUnusedFilename(aRecordName, filename); - if (NS_WARN_IF(NS_FAILED(rv))) { - return GMPGenericErr; - } - record = new Record(filename, aRecordName); - mRecords.Put(aRecordName, record); - } - - MOZ_ASSERT(record); - if (record->mFileDesc) { - NS_WARNING("Tried to open already open record"); - return GMPRecordInUse; - } - - rv = OpenStorageFile(record->mFilename, ReadWrite, &record->mFileDesc); - if (NS_WARN_IF(NS_FAILED(rv))) { - return GMPGenericErr; - } - - MOZ_ASSERT(IsOpen(aRecordName)); - - return GMPNoErr; - } - - bool IsOpen(const nsCString& aRecordName) override { - // We are open if we have a record indexed, and it has a valid - // file descriptor. - Record* record = nullptr; - return mRecords.Get(aRecordName, &record) && - !!record->mFileDesc; - } - - GMPErr Read(const nsCString& aRecordName, - nsTArray& aOutBytes) override - { - if (!IsOpen(aRecordName)) { - return GMPClosedErr; - } - - Record* record = nullptr; - mRecords.Get(aRecordName, &record); - MOZ_ASSERT(record && !!record->mFileDesc); // IsOpen() guarantees this. - - // Our error strategy is to report records with invalid contents as - // containing 0 bytes. Zero length records are considered "deleted" by - // the GMPStorage API. - aOutBytes.SetLength(0); - - int32_t recordLength = 0; - nsCString recordName; - nsresult err = ReadRecordMetadata(record->mFileDesc, - recordLength, - recordName); - if (NS_FAILED(err) || recordLength == 0) { - // We failed to read the record metadata. Or the record is 0 length. - // Treat damaged records as empty. - // ReadRecordMetadata() could fail if the GMP opened a new record and - // tried to read it before anything was written to it.. - return GMPNoErr; - } - - if (!aRecordName.Equals(recordName)) { - NS_WARNING("Record file contains some other record's contents!"); - return GMPRecordCorrupted; - } - - // After calling ReadRecordMetadata, we should be ready to read the - // record data. - if (PR_Available(record->mFileDesc) != recordLength) { - NS_WARNING("Record file length mismatch!"); - return GMPRecordCorrupted; - } - - aOutBytes.SetLength(recordLength); - int32_t bytesRead = PR_Read(record->mFileDesc, aOutBytes.Elements(), recordLength); - return (bytesRead == recordLength) ? GMPNoErr : GMPRecordCorrupted; - } - - GMPErr Write(const nsCString& aRecordName, - const nsTArray& aBytes) override - { - if (!IsOpen(aRecordName)) { - return GMPClosedErr; - } - - Record* record = nullptr; - mRecords.Get(aRecordName, &record); - MOZ_ASSERT(record && !!record->mFileDesc); // IsOpen() guarantees this. - - // Write operations overwrite the entire record. So close it now. - PR_Close(record->mFileDesc); - record->mFileDesc = nullptr; - - // Writing 0 bytes means removing (deleting) the file. - if (aBytes.Length() == 0) { - nsresult rv = RemoveStorageFile(record->mFilename); - if (NS_WARN_IF(NS_FAILED(rv))) { - // Could not delete file -> Continue with trying to erase the contents. - } else { - return GMPNoErr; - } - } - - // Write operations overwrite the entire record. So re-open the file - // in truncate mode, to clear its contents. - if (NS_FAILED(OpenStorageFile(record->mFilename, - Truncate, - &record->mFileDesc))) { - return GMPGenericErr; - } - - // Store the length of the record name followed by the record name - // at the start of the file. - int32_t bytesWritten = 0; - char buf[sizeof(uint32_t)] = {0}; - LittleEndian::writeUint32(buf, aRecordName.Length()); - bytesWritten = PR_Write(record->mFileDesc, buf, MOZ_ARRAY_LENGTH(buf)); - if (bytesWritten != MOZ_ARRAY_LENGTH(buf)) { - NS_WARNING("Failed to write GMPStorage record name length."); - return GMPRecordCorrupted; - } - bytesWritten = PR_Write(record->mFileDesc, - aRecordName.get(), - aRecordName.Length()); - if (bytesWritten != (int32_t)aRecordName.Length()) { - NS_WARNING("Failed to write GMPStorage record name."); - return GMPRecordCorrupted; - } - - bytesWritten = PR_Write(record->mFileDesc, aBytes.Elements(), aBytes.Length()); - if (bytesWritten != (int32_t)aBytes.Length()) { - NS_WARNING("Failed to write GMPStorage record data."); - return GMPRecordCorrupted; - } - - // Try to sync the file to disk, so that in the event of a crash, - // the record is less likely to be corrupted. - PR_Sync(record->mFileDesc); - - return GMPNoErr; - } - - GMPErr GetRecordNames(nsTArray& aOutRecordNames) override - { - for (auto iter = mRecords.ConstIter(); !iter.Done(); iter.Next()) { - aOutRecordNames.AppendElement(iter.UserData()->mRecordName); - } - return GMPNoErr; - } - - void Close(const nsCString& aRecordName) override - { - Record* record = nullptr; - mRecords.Get(aRecordName, &record); - if (record && !!record->mFileDesc) { - PR_Close(record->mFileDesc); - record->mFileDesc = nullptr; - } - MOZ_ASSERT(!IsOpen(aRecordName)); - } - -private: - - // We store records in a file which is a hash of the record name. - // If there is a hash collision, we just keep adding 1 to the hash - // code, until we find a free slot. - nsresult GetUnusedFilename(const nsACString& aRecordName, - nsString& aOutFilename) - { - nsCOMPtr storageDir; - nsresult rv = GetGMPStorageDir(getter_AddRefs(storageDir), mGMPName, mNodeId); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - - uint64_t recordNameHash = HashString(PromiseFlatCString(aRecordName).get()); - for (int i = 0; i < 1000000; i++) { - nsCOMPtr f; - rv = storageDir->Clone(getter_AddRefs(f)); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - nsAutoString hashStr; - hashStr.AppendInt(recordNameHash); - rv = f->Append(hashStr); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - bool exists = false; - f->Exists(&exists); - if (!exists) { - // Filename not in use, we can write into this file. - aOutFilename = hashStr; - return NS_OK; - } else { - // Hash collision; just increment the hash name and try that again. - ++recordNameHash; - continue; - } - } - // Somehow, we've managed to completely fail to find a vacant file name. - // Give up. - NS_WARNING("GetUnusedFilename had extreme hash collision!"); - return NS_ERROR_FAILURE; - } - - enum OpenFileMode { ReadWrite, Truncate }; - - nsresult OpenStorageFile(const nsAString& aFileLeafName, - const OpenFileMode aMode, - PRFileDesc** aOutFD) - { - MOZ_ASSERT(aOutFD); - - nsCOMPtr f; - nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mGMPName, mNodeId); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - f->Append(aFileLeafName); - - auto mode = PR_RDWR | PR_CREATE_FILE; - if (aMode == Truncate) { - mode |= PR_TRUNCATE; - } - - return f->OpenNSPRFileDesc(mode, PR_IRWXU, aOutFD); - } - - nsresult ReadRecordMetadata(PRFileDesc* aFd, - int32_t& aOutRecordLength, - nsACString& aOutRecordName) - { - int32_t offset = PR_Seek(aFd, 0, PR_SEEK_END); - PR_Seek(aFd, 0, PR_SEEK_SET); - - if (offset < 0 || offset > GMP_MAX_RECORD_SIZE) { - // Refuse to read big records, or records where we can't get a length. - return NS_ERROR_FAILURE; - } - const uint32_t fileLength = static_cast(offset); - - // At the start of the file the length of the record name is stored in a - // uint32_t (little endian byte order) followed by the record name at the - // start of the file. The record name is not null terminated. The remainder - // of the file is the record's data. - - if (fileLength < sizeof(uint32_t)) { - // Record file doesn't have enough contents to store the record name - // length. Fail. - return NS_ERROR_FAILURE; - } - - // Read length, and convert to host byte order. - uint32_t recordNameLength = 0; - char buf[sizeof(recordNameLength)] = { 0 }; - int32_t bytesRead = PR_Read(aFd, &buf, sizeof(recordNameLength)); - recordNameLength = LittleEndian::readUint32(buf); - if (sizeof(recordNameLength) != bytesRead || - recordNameLength == 0 || - recordNameLength + sizeof(recordNameLength) > fileLength || - recordNameLength > GMP_MAX_RECORD_NAME_SIZE) { - // Record file has invalid contents. Fail. - return NS_ERROR_FAILURE; - } - - nsCString recordName; - recordName.SetLength(recordNameLength); - bytesRead = PR_Read(aFd, recordName.BeginWriting(), recordNameLength); - if ((uint32_t)bytesRead != recordNameLength) { - // Read failed. - return NS_ERROR_FAILURE; - } - - MOZ_ASSERT(fileLength >= sizeof(recordNameLength) + recordNameLength); - int32_t recordLength = fileLength - (sizeof(recordNameLength) + recordNameLength); - - aOutRecordLength = recordLength; - aOutRecordName = recordName; - - // Read cursor should be positioned after the record name, before the record contents. - if (PR_Seek(aFd, 0, PR_SEEK_CUR) != (int32_t)(sizeof(recordNameLength) + recordNameLength)) { - NS_WARNING("Read cursor mismatch after ReadRecordMetadata()"); - return NS_ERROR_FAILURE; - } - - return NS_OK; - } - - nsresult RemoveStorageFile(const nsString& aFilename) - { - nsCOMPtr f; - nsresult rv = GetGMPStorageDir(getter_AddRefs(f), mGMPName, mNodeId); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - rv = f->Append(aFilename); - if (NS_WARN_IF(NS_FAILED(rv))) { - return rv; - } - return f->Remove(/* bool recursive= */ false); - } - - struct Record { - Record(const nsAString& aFilename, - const nsACString& aRecordName) - : mFilename(aFilename) - , mRecordName(aRecordName) - , mFileDesc(0) - {} - ~Record() { - MOZ_ASSERT(!mFileDesc); - } - nsString mFilename; - nsCString mRecordName; - PRFileDesc* mFileDesc; - }; - - // Hash record name to record data. - nsClassHashtable mRecords; - const nsCString mNodeId; - const nsString mGMPName; -}; - -class GMPMemoryStorage : public GMPStorage { -public: - GMPErr Open(const nsCString& aRecordName) override - { - MOZ_ASSERT(!IsOpen(aRecordName)); - - Record* record = nullptr; - if (!mRecords.Get(aRecordName, &record)) { - record = new Record(); - mRecords.Put(aRecordName, record); - } - record->mIsOpen = true; - return GMPNoErr; - } - - bool IsOpen(const nsCString& aRecordName) override { - Record* record = nullptr; - if (!mRecords.Get(aRecordName, &record)) { - return false; - } - return record->mIsOpen; - } - - GMPErr Read(const nsCString& aRecordName, - nsTArray& aOutBytes) override - { - Record* record = nullptr; - if (!mRecords.Get(aRecordName, &record)) { - return GMPGenericErr; - } - aOutBytes = record->mData; - return GMPNoErr; - } - - GMPErr Write(const nsCString& aRecordName, - const nsTArray& aBytes) override - { - Record* record = nullptr; - if (!mRecords.Get(aRecordName, &record)) { - return GMPClosedErr; - } - record->mData = aBytes; - return GMPNoErr; - } - - GMPErr GetRecordNames(nsTArray& aOutRecordNames) override - { - for (auto iter = mRecords.ConstIter(); !iter.Done(); iter.Next()) { - aOutRecordNames.AppendElement(iter.Key()); - } - return GMPNoErr; - } - - void Close(const nsCString& aRecordName) override - { - Record* record = nullptr; - if (!mRecords.Get(aRecordName, &record)) { - return; - } - if (!record->mData.Length()) { - // Record is empty, delete. - mRecords.Remove(aRecordName); - } else { - record->mIsOpen = false; - } - } - -private: - - struct Record { - Record() : mIsOpen(false) {} - nsTArray mData; - bool mIsOpen; - }; - - nsClassHashtable mRecords; -}; - GMPStorageParent::GMPStorageParent(const nsCString& aNodeId, GMPParent* aPlugin) : mNodeId(aNodeId) @@ -580,8 +38,7 @@ GMPStorageParent::Init() if (NS_WARN_IF(mNodeId.IsEmpty())) { return NS_ERROR_FAILURE; } - nsCOMPtr mps = - do_GetService("@mozilla.org/gecko-media-plugin-service;1"); + RefPtr mps(GeckoMediaPluginServiceParent::GetSingleton()); if (NS_WARN_IF(!mps)) { return NS_ERROR_FAILURE; } @@ -591,15 +48,12 @@ GMPStorageParent::Init() return NS_ERROR_FAILURE; } if (persistent) { - UniquePtr storage = - MakeUnique(mNodeId, mPlugin->GetPluginBaseName()); - if (NS_FAILED(storage->Init())) { - NS_WARNING("Failed to initialize on disk GMP storage"); - return NS_ERROR_FAILURE; - } - mStorage = Move(storage); + mStorage = CreateGMPDiskStorage(mNodeId, mPlugin->GetPluginBaseName()); } else { - mStorage = MakeUnique(); + mStorage = mps->GetMemoryStorageFor(mNodeId); + } + if (!mStorage) { + return NS_ERROR_FAILURE; } mShutdown = false; diff --git a/dom/media/gmp/GMPStorageParent.h b/dom/media/gmp/GMPStorageParent.h index 60cbea9d8c..3d2ea69ac6 100644 --- a/dom/media/gmp/GMPStorageParent.h +++ b/dom/media/gmp/GMPStorageParent.h @@ -7,28 +7,13 @@ #define GMPStorageParent_h_ #include "mozilla/gmp/PGMPStorageParent.h" -#include "gmp-storage.h" -#include "mozilla/UniquePtr.h" +#include "GMPStorage.h" namespace mozilla { namespace gmp { class GMPParent; -class GMPStorage { -public: - virtual ~GMPStorage() {} - - virtual GMPErr Open(const nsCString& aRecordName) = 0; - virtual bool IsOpen(const nsCString& aRecordName) = 0; - virtual GMPErr Read(const nsCString& aRecordName, - nsTArray& aOutBytes) = 0; - virtual GMPErr Write(const nsCString& aRecordName, - const nsTArray& aBytes) = 0; - virtual GMPErr GetRecordNames(nsTArray& aOutRecordNames) = 0; - virtual void Close(const nsCString& aRecordName) = 0; -}; - class GMPStorageParent : public PGMPStorageParent { public: NS_INLINE_DECL_REFCOUNTING(GMPStorageParent) @@ -50,7 +35,7 @@ protected: private: ~GMPStorageParent() {} - UniquePtr mStorage; + RefPtr mStorage; const nsCString mNodeId; RefPtr mPlugin; diff --git a/dom/media/gmp/GMPVideoDecoderChild.cpp b/dom/media/gmp/GMPVideoDecoderChild.cpp index 4d0074a272..2596906287 100644 --- a/dom/media/gmp/GMPVideoDecoderChild.cpp +++ b/dom/media/gmp/GMPVideoDecoderChild.cpp @@ -226,7 +226,8 @@ GMPVideoDecoderChild::Alloc(size_t aSize, rv = CallNeedShmem(aSize, aMem); --mNeedShmemIntrCount; if (mPendingDecodeComplete) { - mPlugin->GMPMessageLoop()->PostTask(NewRunnableMethod(this, &GMPVideoDecoderChild::RecvDecodingComplete)); + mPlugin->GMPMessageLoop()->PostTask( + NewRunnableMethod(this, &GMPVideoDecoderChild::RecvDecodingComplete)); } #else #ifdef GMP_SAFE_SHMEM diff --git a/dom/media/gmp/GMPVideoEncoderChild.cpp b/dom/media/gmp/GMPVideoEncoderChild.cpp index 319450cb0d..fa139cef49 100644 --- a/dom/media/gmp/GMPVideoEncoderChild.cpp +++ b/dom/media/gmp/GMPVideoEncoderChild.cpp @@ -207,7 +207,8 @@ GMPVideoEncoderChild::Alloc(size_t aSize, rv = CallNeedShmem(aSize, aMem); --mNeedShmemIntrCount; if (mPendingEncodeComplete) { - mPlugin->GMPMessageLoop()->PostTask(NewRunnableMethod(this, &GMPVideoEncoderChild::RecvEncodingComplete)); + mPlugin->GMPMessageLoop()->PostTask( + NewRunnableMethod(this, &GMPVideoEncoderChild::RecvEncodingComplete)); } #else #ifdef GMP_SAFE_SHMEM diff --git a/dom/media/gmp/moz.build b/dom/media/gmp/moz.build index 69f68d4d28..f923ca7c53 100644 --- a/dom/media/gmp/moz.build +++ b/dom/media/gmp/moz.build @@ -52,6 +52,7 @@ EXPORTS += [ 'GMPServiceChild.h', 'GMPServiceParent.h', 'GMPSharedMemManager.h', + 'GMPStorage.h', 'GMPStorageChild.h', 'GMPStorageParent.h', 'GMPTimerChild.h', @@ -85,7 +86,9 @@ UNIFIED_SOURCES += [ 'GMPContentParent.cpp', 'GMPDecryptorChild.cpp', 'GMPDecryptorParent.cpp', + 'GMPDiskStorage.cpp', 'GMPEncryptedBufferDataImpl.cpp', + 'GMPMemoryStorage.cpp', 'GMPParent.cpp', 'GMPPlatform.cpp', 'GMPProcessChild.cpp', diff --git a/dom/media/gtest/GMPTestMonitor.h b/dom/media/gtest/GMPTestMonitor.h index d5b6d59c15..8ce6f8ddd8 100644 --- a/dom/media/gtest/GMPTestMonitor.h +++ b/dom/media/gtest/GMPTestMonitor.h @@ -36,8 +36,8 @@ private: public: void SetFinished() { - NS_DispatchToMainThread(NS_NewNonOwningRunnableMethod(this, - &GMPTestMonitor::MarkFinished)); + NS_DispatchToMainThread(mozilla::NewNonOwningRunnableMethod(this, + &GMPTestMonitor::MarkFinished)); } private: diff --git a/dom/media/gtest/TestGMPCrossOrigin.cpp b/dom/media/gtest/TestGMPCrossOrigin.cpp index 16a9f549e2..ead44cf6ed 100644 --- a/dom/media/gtest/TestGMPCrossOrigin.cpp +++ b/dom/media/gtest/TestGMPCrossOrigin.cpp @@ -304,8 +304,8 @@ EnumerateGMPStorageDir(const nsACString& aDir, T&& aDirIter) class GMPShutdownObserver : public nsIRunnable , public nsIObserver { public: - GMPShutdownObserver(nsIRunnable* aShutdownTask, - nsIRunnable* Continuation, + GMPShutdownObserver(already_AddRefed aShutdownTask, + already_AddRefed Continuation, const nsACString& aNodeId) : mShutdownTask(aShutdownTask) , mContinuation(Continuation) @@ -371,7 +371,7 @@ public: class ClearGMPStorageTask : public nsIRunnable , public nsIObserver { public: - ClearGMPStorageTask(nsIRunnable* Continuation, + ClearGMPStorageTask(already_AddRefed Continuation, nsIThread* aTarget, PRTime aSince) : mContinuation(Continuation) , mTarget(aTarget) @@ -421,11 +421,11 @@ private: NS_IMPL_ISUPPORTS(ClearGMPStorageTask, nsIRunnable, nsIObserver) static void -ClearGMPStorage(nsIRunnable* aContinuation, +ClearGMPStorage(already_AddRefed aContinuation, nsIThread* aTarget, PRTime aSince = -1) { RefPtr task( - new ClearGMPStorageTask(aContinuation, aTarget, aSince)); + new ClearGMPStorageTask(Move(aContinuation), aTarget, aSince)); NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL); } @@ -516,7 +516,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback void DoTest(void (GMPStorageTest::*aTestMethod)()) { EnsureNSSInitializedChromeOrContent(); nsCOMPtr thread(GetGMPThread()); - ClearGMPStorage(NS_NewRunnableMethod(this, aTestMethod), thread); + ClearGMPStorage(NewRunnableMethod(this, aTestMethod), thread); AwaitFinished(); } @@ -569,7 +569,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback EXPECT_TRUE(!PBnodeId2.Equals(nodeId2)); nsCOMPtr thread(GetGMPThread()); - ClearGMPStorage(NS_NewRunnableMethodWithArg( + ClearGMPStorage(NewRunnableMethod( this, &GMPStorageTest::TestGetNodeId_Continuation, nodeId1), thread); } @@ -681,7 +681,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback // It sends us a "test-storage complete" message when its passed, or // some other message if its tests fail. Expect(NS_LITERAL_CSTRING("test-storage complete"), - NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); + NewRunnableMethod(this, &GMPStorageTest::SetFinished)); CreateDecryptor(NS_LITERAL_STRING("http://example1.com"), NS_LITERAL_STRING("http://example2.com"), @@ -700,9 +700,9 @@ class GMPStorageTest : public GMPDecryptorProxyCallback EXPECT_TRUE(IsGMPStorageIsEmpty()); // Generate storage data for some site. - nsCOMPtr r = NS_NewRunnableMethod( + nsCOMPtr r = NewRunnableMethod( this, &GMPStorageTest::TestForgetThisSite_AnotherSite); - Expect(NS_LITERAL_CSTRING("test-storage complete"), r); + Expect(NS_LITERAL_CSTRING("test-storage complete"), r.forget()); CreateDecryptor(NS_LITERAL_STRING("http://example1.com"), NS_LITERAL_STRING("http://example2.com"), @@ -714,9 +714,9 @@ class GMPStorageTest : public GMPDecryptorProxyCallback Shutdown(); // Generate storage data for another site. - nsCOMPtr r = NS_NewRunnableMethod( + nsCOMPtr r = NewRunnableMethod( this, &GMPStorageTest::TestForgetThisSite_CollectSiteInfo); - Expect(NS_LITERAL_CSTRING("test-storage complete"), r); + Expect(NS_LITERAL_CSTRING("test-storage complete"), r.forget()); CreateDecryptor(NS_LITERAL_STRING("http://example3.com"), NS_LITERAL_STRING("http://example4.com"), @@ -751,7 +751,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback // Collect nodeIds that are expected to remain for later comparison. EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), NodeIdCollector(siteInfo)); // Invoke "Forget this site" on the main thread. - NS_DispatchToMainThread(NS_NewRunnableMethodWithArg>( + NS_DispatchToMainThread(NewRunnableMethod>( this, &GMPStorageTest::TestForgetThisSite_Forget, siteInfo)); } @@ -763,11 +763,11 @@ class GMPStorageTest : public GMPDecryptorProxyCallback nsCOMPtr thread; service->GetThread(getter_AddRefs(thread)); - nsCOMPtr r = NS_NewRunnableMethodWithArg>( + nsCOMPtr r = NewRunnableMethod>( this, &GMPStorageTest::TestForgetThisSite_Verify, aSiteInfo); thread->Dispatch(r, NS_DISPATCH_NORMAL); - nsCOMPtr f = NS_NewRunnableMethod( + nsCOMPtr f = NewRunnableMethod( this, &GMPStorageTest::SetFinished); thread->Dispatch(f, NS_DISPATCH_NORMAL); } @@ -833,9 +833,9 @@ class GMPStorageTest : public GMPDecryptorProxyCallback EXPECT_TRUE(IsGMPStorageIsEmpty()); // Generate storage data for some site. - nsCOMPtr r = NS_NewRunnableMethod( + nsCOMPtr r = NewRunnableMethod( this, &GMPStorageTest::TestClearRecentHistory1_Clear); - Expect(NS_LITERAL_CSTRING("test-storage complete"), r); + Expect(NS_LITERAL_CSTRING("test-storage complete"), r.forget()); CreateDecryptor(NS_LITERAL_STRING("http://example1.com"), NS_LITERAL_STRING("http://example2.com"), @@ -855,9 +855,9 @@ class GMPStorageTest : public GMPDecryptorProxyCallback EXPECT_TRUE(IsGMPStorageIsEmpty()); // Generate storage data for some site. - nsCOMPtr r = NS_NewRunnableMethod( + nsCOMPtr r = NewRunnableMethod( this, &GMPStorageTest::TestClearRecentHistory2_Clear); - Expect(NS_LITERAL_CSTRING("test-storage complete"), r); + Expect(NS_LITERAL_CSTRING("test-storage complete"), r.forget()); CreateDecryptor(NS_LITERAL_STRING("http://example1.com"), NS_LITERAL_STRING("http://example2.com"), @@ -877,9 +877,9 @@ class GMPStorageTest : public GMPDecryptorProxyCallback EXPECT_TRUE(IsGMPStorageIsEmpty()); // Generate storage data for some site. - nsCOMPtr r = NS_NewRunnableMethod( + nsCOMPtr r = NewRunnableMethod( this, &GMPStorageTest::TestClearRecentHistory3_Clear); - Expect(NS_LITERAL_CSTRING("test-storage complete"), r); + Expect(NS_LITERAL_CSTRING("test-storage complete"), r.forget()); CreateDecryptor(NS_LITERAL_STRING("http://example1.com"), NS_LITERAL_STRING("http://example2.com"), @@ -908,10 +908,10 @@ class GMPStorageTest : public GMPDecryptorProxyCallback nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("id"), f); EXPECT_TRUE(NS_SUCCEEDED(rv)); - nsCOMPtr r = NS_NewRunnableMethod( + nsCOMPtr r = NewRunnableMethod( this, &GMPStorageTest::TestClearRecentHistory_CheckEmpty); nsCOMPtr t(GetGMPThread()); - ClearGMPStorage(r, t, f.GetResult()); + ClearGMPStorage(r.forget(), t, f.GetResult()); } void TestClearRecentHistory2_Clear() { @@ -919,10 +919,10 @@ class GMPStorageTest : public GMPDecryptorProxyCallback nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), f); EXPECT_TRUE(NS_SUCCEEDED(rv)); - nsCOMPtr r = NS_NewRunnableMethod( + nsCOMPtr r = NewRunnableMethod( this, &GMPStorageTest::TestClearRecentHistory_CheckEmpty); nsCOMPtr t(GetGMPThread()); - ClearGMPStorage(r, t, f.GetResult()); + ClearGMPStorage(r.forget(), t, f.GetResult()); } void TestClearRecentHistory3_Clear() { @@ -930,10 +930,10 @@ class GMPStorageTest : public GMPDecryptorProxyCallback nsresult rv = EnumerateGMPStorageDir(NS_LITERAL_CSTRING("storage"), f); EXPECT_TRUE(NS_SUCCEEDED(rv)); - nsCOMPtr r = NS_NewRunnableMethod( + nsCOMPtr r = NewRunnableMethod( this, &GMPStorageTest::TestClearRecentHistory_CheckNonEmpty); nsCOMPtr t(GetGMPThread()); - ClearGMPStorage(r, t, f.GetResult() + 1); + ClearGMPStorage(r.forget(), t, f.GetResult() + 1); } class FileCounter { @@ -987,7 +987,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback auto t = time(0); nsCString response("stored crossOriginTestRecordId "); response.AppendInt((int64_t)t); - Expect(response, NS_NewRunnableMethod(this, + Expect(response, NewRunnableMethod(this, &GMPStorageTest::TestCrossOriginStorage_RecordStoredContinuation)); nsCString update("store crossOriginTestRecordId "); @@ -1007,7 +1007,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback Shutdown(); Expect(NS_LITERAL_CSTRING("retrieve crossOriginTestRecordId succeeded (length 0 bytes)"), - NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); + NewRunnableMethod(this, &GMPStorageTest::SetFinished)); CreateDecryptor(NS_LITERAL_STRING("http://example5.com"), NS_LITERAL_STRING("http://example6.com"), @@ -1019,7 +1019,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback // Send the decryptor the message "store recordid $time" // Wait for the decrytor to send us "stored recordid $time" nsCString response("stored pbdata test-pb-data"); - Expect(response, NS_NewRunnableMethod(this, + Expect(response, NewRunnableMethod(this, &GMPStorageTest::TestPBStorage_RecordStoredContinuation)); // Open decryptor on one, origin, write a record, close decryptor, @@ -1036,7 +1036,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback Shutdown(); Expect(NS_LITERAL_CSTRING("retrieve pbdata succeeded (length 12 bytes)"), - NS_NewRunnableMethod(this, + NewRunnableMethod(this, &GMPStorageTest::TestPBStorage_RecordRetrievedContinuation)); CreateDecryptor(NS_LITERAL_STRING("http://pb1.com"), @@ -1050,7 +1050,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback SimulatePBModeExit(); Expect(NS_LITERAL_CSTRING("retrieve pbdata succeeded (length 0 bytes)"), - NS_NewRunnableMethod(this, + NewRunnableMethod(this, &GMPStorageTest::SetFinished)); CreateDecryptor(NS_LITERAL_STRING("http://pb1.com"), @@ -1073,10 +1073,10 @@ class GMPStorageTest : public GMPDecryptorProxyCallback const nsAString& aOrigin2, void (GMPStorageTest::*aCallback)()) { nsCOMPtr continuation( - NS_NewRunnableMethodWithArg>( + NewRunnableMethod>( this, &GMPStorageTest::NextAsyncShutdownTimeoutTest, - NS_NewRunnableMethod(this, aCallback))); + NewRunnableMethod(this, aCallback))); CreateDecryptor(aOrigin1, aOrigin2, false, continuation); } @@ -1115,7 +1115,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback // the token. nsCString response("shutdown-token received "); response.Append(token); - Expect(response, NS_NewRunnableMethodWithArg(this, + Expect(response, NewRunnableMethod(this, &GMPStorageTest::TestAsyncShutdownStorage_ReceivedShutdownToken, token)); // Test that a GMP can write to storage during shutdown, and retrieve @@ -1127,7 +1127,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback } void TestAsyncShutdownStorage_ReceivedShutdownToken(const nsCString& aToken) { - ShutdownThen(NS_NewRunnableMethodWithArg(this, + ShutdownThen(NewRunnableMethod(this, &GMPStorageTest::TestAsyncShutdownStorage_AsyncShutdownComplete, aToken)); } @@ -1137,7 +1137,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback nsCString response("retrieved shutdown-token "); response.Append(aToken); Expect(response, - NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); + NewRunnableMethod(this, &GMPStorageTest::SetFinished)); CreateDecryptor(NS_LITERAL_STRING("http://example13.com"), NS_LITERAL_STRING("http://example14.com"), @@ -1150,7 +1150,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback Shutdown(); Expect(NS_LITERAL_CSTRING("OP tests completed"), - NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); + NewRunnableMethod(this, &GMPStorageTest::SetFinished)); CreateDecryptor(NS_LITERAL_STRING("http://example15.com"), NS_LITERAL_STRING("http://example16.com"), @@ -1161,7 +1161,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback void TestPluginVoucher() { Expect(NS_LITERAL_CSTRING("retrieved plugin-voucher: gmp-fake placeholder voucher"), - NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); + NewRunnableMethod(this, &GMPStorageTest::SetFinished)); CreateDecryptor(NS_LITERAL_STRING("http://example17.com"), NS_LITERAL_STRING("http://example18.com"), @@ -1205,12 +1205,12 @@ class GMPStorageTest : public GMPDecryptorProxyCallback update.AppendLiteral(" test-data"); AppendIntPadded(update, i); - nsIRunnable* continuation = nullptr; + nsCOMPtr continuation; if (i + 1 == num) { continuation = - NS_NewRunnableMethod(this, &GMPStorageTest::TestGetRecordNames_QueryNames); + NewRunnableMethod(this, &GMPStorageTest::TestGetRecordNames_QueryNames); } - Expect(response, continuation); + Expect(response, continuation.forget()); } CreateDecryptor(NS_LITERAL_STRING("http://foo.com"), @@ -1223,7 +1223,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback nsCString response("record-names "); response.Append(mRecordNames); Expect(response, - NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); + NewRunnableMethod(this, &GMPStorageTest::SetFinished)); Update(NS_LITERAL_CSTRING("retrieve-record-names")); } @@ -1260,7 +1260,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback response.Append(longRecordName); response.AppendLiteral(" "); response.Append(data); - Expect(response, NS_NewRunnableMethod(this, &GMPStorageTest::SetFinished)); + Expect(response, NewRunnableMethod(this, &GMPStorageTest::SetFinished)); nsCString update("store "); update.Append(longRecordName); @@ -1272,8 +1272,8 @@ class GMPStorageTest : public GMPDecryptorProxyCallback update); } - void Expect(const nsCString& aMessage, nsIRunnable* aContinuation) { - mExpected.AppendElement(ExpectedMessage(aMessage, aContinuation)); + void Expect(const nsCString& aMessage, already_AddRefed aContinuation) { + mExpected.AppendElement(ExpectedMessage(aMessage, Move(aContinuation))); } void AwaitFinished() { @@ -1283,15 +1283,15 @@ class GMPStorageTest : public GMPDecryptorProxyCallback mFinished = false; } - void ShutdownThen(nsIRunnable* aContinuation) { + void ShutdownThen(already_AddRefed aContinuation) { EXPECT_TRUE(!!mDecryptor); if (!mDecryptor) { return; } EXPECT_FALSE(mNodeId.IsEmpty()); RefPtr task( - new GMPShutdownObserver(NS_NewRunnableMethod(this, &GMPStorageTest::Shutdown), - aContinuation, mNodeId)); + new GMPShutdownObserver(NewRunnableMethod(this, &GMPStorageTest::Shutdown), + Move(aContinuation), mNodeId)); NS_DispatchToMainThread(task, NS_DISPATCH_NORMAL); } @@ -1309,7 +1309,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback void SetFinished() { mFinished = true; Shutdown(); - NS_DispatchToMainThread(NS_NewRunnableMethod(this, &GMPStorageTest::Dummy)); + NS_DispatchToMainThread(NewRunnableMethod(this, &GMPStorageTest::Dummy)); } void SessionMessage(const nsCString& aSessionId, @@ -1364,7 +1364,7 @@ private: ~GMPStorageTest() { } struct ExpectedMessage { - ExpectedMessage(const nsCString& aMessage, nsIRunnable* aContinuation) + ExpectedMessage(const nsCString& aMessage, already_AddRefed aContinuation) : mMessage(aMessage) , mContinuation(aContinuation) {} @@ -1386,9 +1386,9 @@ GMPTestRunner::DoTest(void (GMPTestRunner::*aTestMethod)(GMPTestMonitor&)) nsCOMPtr thread(GetGMPThread()); GMPTestMonitor monitor; - thread->Dispatch(NS_NewRunnableMethodWithArg(this, - aTestMethod, - monitor), + thread->Dispatch(NewRunnableMethod(this, + aTestMethod, + monitor), NS_DISPATCH_NORMAL); monitor.AwaitFinished(); } diff --git a/dom/media/gtest/TestGMPRemoveAndDelete.cpp b/dom/media/gtest/TestGMPRemoveAndDelete.cpp index ef6b8b22d1..ffedf4d30e 100644 --- a/dom/media/gtest/TestGMPRemoveAndDelete.cpp +++ b/dom/media/gtest/TestGMPRemoveAndDelete.cpp @@ -260,7 +260,7 @@ GMPRemoveTest::CreateVideoDecoder(nsCString aNodeId) GMPVideoDecoderProxy* decoder = nullptr; mGMPThread->Dispatch( - NS_NewNonOwningRunnableMethodWithArgs( + NewNonOwningRunnableMethod( this, &GMPRemoveTest::gmp_GetVideoDecoder, aNodeId, &decoder, &host), NS_DISPATCH_NORMAL); @@ -276,7 +276,7 @@ GMPRemoveTest::CreateVideoDecoder(nsCString aNodeId) nsTArray empty; mGMPThread->Dispatch( - NS_NewNonOwningRunnableMethodWithArgs&, GMPVideoDecoderCallbackProxy*, int32_t>( + NewNonOwningRunnableMethod&, GMPVideoDecoderCallbackProxy*, int32_t>( decoder, &GMPVideoDecoderProxy::InitDecode, codec, empty, this, 1 /* core count */), NS_DISPATCH_SYNC); @@ -328,7 +328,7 @@ void GMPRemoveTest::CloseVideoDecoder() { mGMPThread->Dispatch( - NS_NewNonOwningRunnableMethod(mDecoder, &GMPVideoDecoderProxy::Close), + NewNonOwningRunnableMethod(mDecoder, &GMPVideoDecoderProxy::Close), NS_DISPATCH_SYNC); mDecoder = nullptr; @@ -345,7 +345,7 @@ GMPErr GMPRemoveTest::Decode() { mGMPThread->Dispatch( - NS_NewNonOwningRunnableMethod(this, &GMPRemoveTest::gmp_Decode), + NewNonOwningRunnableMethod(this, &GMPRemoveTest::gmp_Decode), NS_DISPATCH_NORMAL); mTestMonitor.AwaitFinished(); diff --git a/dom/media/gtest/TestMP4Reader.cpp b/dom/media/gtest/TestMP4Reader.cpp index c0120c12a3..f08f7a40da 100644 --- a/dom/media/gtest/TestMP4Reader.cpp +++ b/dom/media/gtest/TestMP4Reader.cpp @@ -43,8 +43,8 @@ public: void Init() { nsCOMPtr thread; - nsresult rv = NS_NewThread(getter_AddRefs(thread), - NS_NewRunnableMethod(this, &TestBinding::ReadMetadata)); + nsCOMPtr r = NewRunnableMethod(this, &TestBinding::ReadMetadata); + nsresult rv = NS_NewThread(getter_AddRefs(thread), r); EXPECT_EQ(NS_OK, rv); thread->Shutdown(); } @@ -54,7 +54,7 @@ private: { { RefPtr queue = reader->OwnerThread(); - nsCOMPtr task = NS_NewRunnableMethod(reader, &MP4Reader::Shutdown); + nsCOMPtr task = NewRunnableMethod(reader, &MP4Reader::Shutdown); // Hackily bypass the tail dispatcher so that we can AwaitShutdownAndIdle. // In production code we'd use BeginShutdown + promises. queue->Dispatch(task.forget(), AbstractThread::AssertDispatchSuccess, diff --git a/dom/media/mediasink/DecodedAudioDataSink.cpp b/dom/media/mediasink/DecodedAudioDataSink.cpp index 89f94d200b..85a9520e00 100644 --- a/dom/media/mediasink/DecodedAudioDataSink.cpp +++ b/dom/media/mediasink/DecodedAudioDataSink.cpp @@ -51,6 +51,7 @@ DecodedAudioDataSink::DecodedAudioDataSink(AbstractThread* aThread, , mProcessedQueueLength(0) , mFramesParsed(0) , mLastEndTime(0) + , mIsAudioDataAudible(false) { bool resampling = gfxPrefs::AudioSinkResampling(); @@ -318,6 +319,7 @@ DecodedAudioDataSink::PopFrames(uint32_t aFrames) // We can now safely pop the audio packet from the processed queue. // This will fire the popped event, triggering a call to NotifyAudioNeeded. RefPtr releaseMe = mProcessedQueue.PopFront(); + CheckIsAudible(releaseMe); } return chunk; @@ -338,6 +340,18 @@ DecodedAudioDataSink::Drained() mEndPromise.ResolveIfExists(true, __func__); } +void +DecodedAudioDataSink::CheckIsAudible(const AudioData* aData) +{ + MOZ_ASSERT(aData); + + bool isAudible = aData->IsAudible(); + if (isAudible != mIsAudioDataAudible) { + mIsAudioDataAudible = isAudible; + mAudibleEvent.Notify(mIsAudioDataAudible); + } +} + void DecodedAudioDataSink::OnAudioPopped(const RefPtr& aSample) { diff --git a/dom/media/mediasink/DecodedAudioDataSink.h b/dom/media/mediasink/DecodedAudioDataSink.h index af6e935e08..36412984a3 100644 --- a/dom/media/mediasink/DecodedAudioDataSink.h +++ b/dom/media/mediasink/DecodedAudioDataSink.h @@ -58,6 +58,10 @@ public: void SetPreservesPitch(bool aPreservesPitch) override; void SetPlaying(bool aPlaying) override; + MediaEventSource& AudibleEvent() { + return mAudibleEvent; + } + private: virtual ~DecodedAudioDataSink(); @@ -70,6 +74,8 @@ private: bool Ended() const override; void Drained() override; + void CheckIsAudible(const AudioData* aData); + // The audio stream resource. Used on the task queue of MDSM only. RefPtr mAudioStream; @@ -146,6 +152,11 @@ private: // Never modifed after construction. uint32_t mOutputRate; uint32_t mOutputChannels; + + // True when audio is producing audible sound, false when audio is silent. + bool mIsAudioDataAudible; + + MediaEventProducer mAudibleEvent; }; } // namespace media diff --git a/dom/media/mediasink/DecodedStream.cpp b/dom/media/mediasink/DecodedStream.cpp index 1acd2779f8..ac82f074f0 100644 --- a/dom/media/mediasink/DecodedStream.cpp +++ b/dom/media/mediasink/DecodedStream.cpp @@ -54,7 +54,7 @@ public: { if (event == EVENT_FINISHED) { nsCOMPtr event = - NS_NewRunnableMethod(this, &DecodedStreamGraphListener::DoNotifyFinished); + NewRunnableMethod(this, &DecodedStreamGraphListener::DoNotifyFinished); aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); } } @@ -99,9 +99,9 @@ UpdateStreamSuspended(MediaStream* aStream, bool aBlocking) } else { nsCOMPtr r; if (aBlocking) { - r = NS_NewRunnableMethod(aStream, &MediaStream::Suspend); + r = NewRunnableMethod(aStream, &MediaStream::Suspend); } else { - r = NS_NewRunnableMethod(aStream, &MediaStream::Resume); + r = NewRunnableMethod(aStream, &MediaStream::Resume); } AbstractThread::MainThread()->Dispatch(r.forget()); } diff --git a/dom/media/mediasource/MediaSourceDemuxer.cpp b/dom/media/mediasource/MediaSourceDemuxer.cpp index 715dc9858e..6ffb655277 100644 --- a/dom/media/mediasource/MediaSourceDemuxer.cpp +++ b/dom/media/mediasource/MediaSourceDemuxer.cpp @@ -177,7 +177,7 @@ void MediaSourceDemuxer::AttachSourceBuffer(TrackBuffersManager* aSourceBuffer) { nsCOMPtr task = - NS_NewRunnableMethodWithArg( + NewRunnableMethod( this, &MediaSourceDemuxer::DoAttachSourceBuffer, aSourceBuffer); GetTaskQueue()->Dispatch(task.forget()); @@ -195,7 +195,7 @@ void MediaSourceDemuxer::DetachSourceBuffer(TrackBuffersManager* aSourceBuffer) { nsCOMPtr task = - NS_NewRunnableMethodWithArg( + NewRunnableMethod( this, &MediaSourceDemuxer::DoDetachSourceBuffer, aSourceBuffer); GetTaskQueue()->Dispatch(task.forget()); diff --git a/dom/media/mediasource/TrackBuffersManager.cpp b/dom/media/mediasource/TrackBuffersManager.cpp index f28577097b..9d001721b7 100644 --- a/dom/media/mediasource/TrackBuffersManager.cpp +++ b/dom/media/mediasource/TrackBuffersManager.cpp @@ -173,9 +173,7 @@ TrackBuffersManager::ProcessTasks() NS_WARNING("Invalid Task"); } } - nsCOMPtr task = - NS_NewRunnableMethod(this, &TrackBuffersManager::ProcessTasks); - GetTaskQueue()->Dispatch(task.forget()); + GetTaskQueue()->Dispatch(NewRunnableMethod(this, &TrackBuffersManager::ProcessTasks)); } // A PromiseHolder will assert upon destruction if it has a pending promise @@ -768,9 +766,7 @@ TrackBuffersManager::ScheduleSegmentParserLoop() if (mDetached) { return; } - nsCOMPtr task = - NS_NewRunnableMethod(this, &TrackBuffersManager::SegmentParserLoop); - GetTaskQueue()->Dispatch(task.forget()); + GetTaskQueue()->Dispatch(NewRunnableMethod(this, &TrackBuffersManager::SegmentParserLoop)); } void @@ -956,11 +952,10 @@ TrackBuffersManager::OnDemuxerInitDone(nsresult) int64_t duration = std::max(videoDuration, audioDuration); // 1. Update the duration attribute if it currently equals NaN. // Those steps are performed by the MediaSourceDecoder::SetInitialDuration - nsCOMPtr task = - NS_NewRunnableMethodWithArg(mParentDecoder, - &MediaSourceDecoder::SetInitialDuration, - duration ? duration : -1); - AbstractThread::MainThread()->Dispatch(task.forget()); + AbstractThread::MainThread()->Dispatch(NewRunnableMethod + (mParentDecoder, + &MediaSourceDecoder::SetInitialDuration, + duration ? duration : -1)); // 2. If the initialization segment has no audio, video, or text tracks, then // run the append error algorithm with the decode error parameter set to true diff --git a/dom/media/mediasource/test/test_ResumeAfterClearing_mp4.html b/dom/media/mediasource/test/test_ResumeAfterClearing_mp4.html index 9b6622149c..b6769cb1b4 100644 --- a/dom/media/mediasource/test/test_ResumeAfterClearing_mp4.html +++ b/dom/media/mediasource/test/test_ResumeAfterClearing_mp4.html @@ -38,7 +38,7 @@ runWithMSE(function(ms, v) { }).then(function() { var promises = []; promises.push(once(v, "playing")); - promises.push(fetchAndLoad(sb, 'bipbop/bipbop', range(1,3), '.m4s')); + promises.push(fetchAndLoad(sb, 'bipbop/bipbop', range(1,4), '.m4s')); return Promise.all(promises); }).then(function() { ms.endOfStream(); diff --git a/dom/media/ogg/OggReader.cpp b/dom/media/ogg/OggReader.cpp index 3ffabd7c84..730329fc0d 100644 --- a/dom/media/ogg/OggReader.cpp +++ b/dom/media/ogg/OggReader.cpp @@ -169,17 +169,17 @@ nsresult OggReader::Init() { return NS_OK; } -nsresult OggReader::ResetDecode() +nsresult OggReader::ResetDecode(TargetQueues aQueues) { - return ResetDecode(false); + return ResetDecode(false, aQueues); } -nsresult OggReader::ResetDecode(bool start) +nsresult OggReader::ResetDecode(bool start, TargetQueues aQueues) { MOZ_ASSERT(OnTaskQueue()); nsresult res = NS_OK; - if (NS_FAILED(MediaDecoderReader::ResetDecode())) { + if (NS_FAILED(MediaDecoderReader::ResetDecode(aQueues))) { res = NS_ERROR_FAILURE; } diff --git a/dom/media/ogg/OggReader.h b/dom/media/ogg/OggReader.h index ba24aefde5..2c59940854 100644 --- a/dom/media/ogg/OggReader.h +++ b/dom/media/ogg/OggReader.h @@ -51,7 +51,7 @@ protected: public: nsresult Init() override; - nsresult ResetDecode() override; + nsresult ResetDecode(TargetQueues aQueues = AUDIO_VIDEO) override; bool DecodeAudioData() override; // If the Theora granulepos has not been captured, it may read several packets @@ -86,7 +86,7 @@ private: // Specialized Reset() method to signal if the seek is // to the start of the stream. - nsresult ResetDecode(bool start); + nsresult ResetDecode(bool start, TargetQueues aQueues = AUDIO_VIDEO); nsresult SeekInternal(int64_t aTime, int64_t aEndTime); @@ -94,7 +94,7 @@ private: return mSkeletonState != 0 && mSkeletonState->mActive; } - // Seeks to the keyframe preceeding the target time using available + // Seeks to the keyframe preceding the target time using available // keyframe indexes. enum IndexedSeekResult { SEEK_OK, // Success. diff --git a/dom/media/omx/AudioOffloadPlayer.cpp b/dom/media/omx/AudioOffloadPlayer.cpp index 05e5a45e67..ccdd82ba84 100644 --- a/dom/media/omx/AudioOffloadPlayer.cpp +++ b/dom/media/omx/AudioOffloadPlayer.cpp @@ -354,7 +354,7 @@ status_t AudioOffloadPlayer::DoSeek() if (!mSeekPromise.IsEmpty()) { nsCOMPtr nsEvent = - NS_NewRunnableMethodWithArg( + NewRunnableMethod( mObserver, &MediaDecoder::SeekingStarted, mSeekTarget.mEventVisibility); @@ -425,16 +425,14 @@ void AudioOffloadPlayer::NotifyAudioEOS() MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility); mSeekPromise.Resolve(val, __func__); } - nsCOMPtr nsEvent = NS_NewRunnableMethod(mObserver, - &MediaDecoder::PlaybackEnded); - NS_DispatchToMainThread(nsEvent); + NS_DispatchToMainThread(NewRunnableMethod(mObserver, + &MediaDecoder::PlaybackEnded)); } void AudioOffloadPlayer::NotifyPositionChanged() { - nsCOMPtr nsEvent = - NS_NewRunnableMethod(mObserver, &MediaOmxCommonDecoder::NotifyOffloadPlayerPositionChanged); - NS_DispatchToMainThread(nsEvent); + NS_DispatchToMainThread(NewRunnableMethod(mObserver, + &MediaOmxCommonDecoder::NotifyOffloadPlayerPositionChanged)); } void AudioOffloadPlayer::NotifyAudioTearDown() @@ -448,9 +446,8 @@ void AudioOffloadPlayer::NotifyAudioTearDown() MediaDecoder::SeekResolveValue val(mReachedEOS, mSeekTarget.mEventVisibility); mSeekPromise.Resolve(val, __func__); } - nsCOMPtr nsEvent = NS_NewRunnableMethod(mObserver, - &MediaOmxCommonDecoder::AudioOffloadTearDown); - NS_DispatchToMainThread(nsEvent); + NS_DispatchToMainThread(NewRunnableMethod(mObserver, + &MediaOmxCommonDecoder::AudioOffloadTearDown)); } // static diff --git a/dom/media/omx/MediaOmxCommonDecoder.cpp b/dom/media/omx/MediaOmxCommonDecoder.cpp index 613fe02682..11eef8a00c 100644 --- a/dom/media/omx/MediaOmxCommonDecoder.cpp +++ b/dom/media/omx/MediaOmxCommonDecoder.cpp @@ -252,6 +252,7 @@ void MediaOmxCommonDecoder::SetElementVisibility(bool aIsVisible) { MOZ_ASSERT(NS_IsMainThread()); + MediaDecoder::SetElementVisibility(aIsVisible); if (mAudioOffloadPlayer) { mAudioOffloadPlayer->SetElementVisibility(aIsVisible); } diff --git a/dom/media/platforms/agnostic/OpusDecoder.cpp b/dom/media/platforms/agnostic/OpusDecoder.cpp index e2cbba3139..9fa5e91f55 100644 --- a/dom/media/platforms/agnostic/OpusDecoder.cpp +++ b/dom/media/platforms/agnostic/OpusDecoder.cpp @@ -10,6 +10,7 @@ #include "VorbisDecoder.h" // For VorbisLayout #include "mozilla/Endian.h" #include "mozilla/PodOperations.h" +#include "mozilla/SyncRunnable.h" #include #include // For PRId64 @@ -21,7 +22,7 @@ extern mozilla::LogModule* GetPDMLog(); namespace mozilla { OpusDataDecoder::OpusDataDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback) : mInfo(aConfig) , mTaskQueue(aTaskQueue) @@ -31,6 +32,7 @@ OpusDataDecoder::OpusDataDecoder(const AudioInfo& aConfig, , mDecodedHeader(false) , mPaddingDiscarded(false) , mFrames(0) + , mIsFlushing(false) { } @@ -132,18 +134,18 @@ OpusDataDecoder::DecodeHeader(const unsigned char* aData, size_t aLength) nsresult OpusDataDecoder::Input(MediaRawData* aSample) { - nsCOMPtr runnable( - NS_NewRunnableMethodWithArg>( - this, &OpusDataDecoder::Decode, - RefPtr(aSample))); - mTaskQueue->Dispatch(runnable.forget()); + mTaskQueue->Dispatch(NewRunnableMethod>( + this, &OpusDataDecoder::ProcessDecode, aSample)); return NS_OK; } void -OpusDataDecoder::Decode(MediaRawData* aSample) +OpusDataDecoder::ProcessDecode(MediaRawData* aSample) { + if (mIsFlushing) { + return; + } if (DoDecode(aSample) == -1) { mCallback->Error(); } else if(mTaskQueue->IsEmpty()) { @@ -301,7 +303,7 @@ OpusDataDecoder::DoDecode(MediaRawData* aSample) } void -OpusDataDecoder::DoDrain() +OpusDataDecoder::ProcessDrain() { mCallback->DrainComplete(); } @@ -309,23 +311,27 @@ OpusDataDecoder::DoDrain() nsresult OpusDataDecoder::Drain() { - RefPtr runnable( - NS_NewRunnableMethod(this, &OpusDataDecoder::DoDrain)); - mTaskQueue->Dispatch(runnable.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &OpusDataDecoder::ProcessDrain)); return NS_OK; } nsresult OpusDataDecoder::Flush() { - mTaskQueue->Flush(); - if (mOpusDecoder) { + if (!mOpusDecoder) { + return NS_OK; + } + mIsFlushing = true; + nsCOMPtr runnable = NS_NewRunnableFunction([this] () { + MOZ_ASSERT(mOpusDecoder); // Reset the decoder. opus_multistream_decoder_ctl(mOpusDecoder, OPUS_RESET_STATE); mSkip = mOpusParser->mPreSkip; mPaddingDiscarded = false; mLastFrameTime.reset(); - } + }); + SyncRunnable::DispatchToThread(mTaskQueue, runnable); + mIsFlushing = false; return NS_OK; } diff --git a/dom/media/platforms/agnostic/OpusDecoder.h b/dom/media/platforms/agnostic/OpusDecoder.h index 88df529697..13572471cb 100644 --- a/dom/media/platforms/agnostic/OpusDecoder.h +++ b/dom/media/platforms/agnostic/OpusDecoder.h @@ -18,7 +18,7 @@ class OpusDataDecoder : public MediaDataDecoder { public: OpusDataDecoder(const AudioInfo& aConfig, - FlushableTaskQueue* aTaskQueue, + TaskQueue* aTaskQueue, MediaDataDecoderCallback* aCallback); ~OpusDataDecoder(); @@ -38,12 +38,12 @@ public: private: nsresult DecodeHeader(const unsigned char* aData, size_t aLength); - void Decode (MediaRawData* aSample); - int DoDecode (MediaRawData* aSample); - void DoDrain (); + void ProcessDecode(MediaRawData* aSample); + int DoDecode(MediaRawData* aSample); + void ProcessDrain(); const AudioInfo& mInfo; - RefPtr mTaskQueue; + const RefPtr mTaskQueue; MediaDataDecoderCallback* mCallback; // Opus decoder state @@ -60,6 +60,8 @@ private: int64_t mFrames; Maybe mLastFrameTime; uint8_t mMappingTable[MAX_AUDIO_CHANNELS]; // Channel mapping table. + + Atomic mIsFlushing; }; } // namespace mozilla diff --git a/dom/media/platforms/agnostic/VPXDecoder.cpp b/dom/media/platforms/agnostic/VPXDecoder.cpp index 644361ecaa..6b1f5ad2ce 100644 --- a/dom/media/platforms/agnostic/VPXDecoder.cpp +++ b/dom/media/platforms/agnostic/VPXDecoder.cpp @@ -186,11 +186,9 @@ VPXDecoder::DecodeFrame(MediaRawData* aSample) nsresult VPXDecoder::Input(MediaRawData* aSample) { - nsCOMPtr runnable( - NS_NewRunnableMethodWithArg>( - this, &VPXDecoder::DecodeFrame, - RefPtr(aSample))); - mTaskQueue->Dispatch(runnable.forget()); + mTaskQueue->Dispatch(NewRunnableMethod>( + this, &VPXDecoder::DecodeFrame, + RefPtr(aSample))); return NS_OK; } @@ -204,9 +202,7 @@ VPXDecoder::DoDrain() nsresult VPXDecoder::Drain() { - nsCOMPtr runnable( - NS_NewRunnableMethod(this, &VPXDecoder::DoDrain)); - mTaskQueue->Dispatch(runnable.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &VPXDecoder::DoDrain)); return NS_OK; } diff --git a/dom/media/platforms/agnostic/VorbisDecoder.cpp b/dom/media/platforms/agnostic/VorbisDecoder.cpp index 259df44d78..ed7217c457 100644 --- a/dom/media/platforms/agnostic/VorbisDecoder.cpp +++ b/dom/media/platforms/agnostic/VorbisDecoder.cpp @@ -129,11 +129,9 @@ VorbisDataDecoder::DecodeHeader(const unsigned char* aData, size_t aLength) nsresult VorbisDataDecoder::Input(MediaRawData* aSample) { - nsCOMPtr runnable( - NS_NewRunnableMethodWithArg>( - this, &VorbisDataDecoder::Decode, - RefPtr(aSample))); - mTaskQueue->Dispatch(runnable.forget()); + mTaskQueue->Dispatch(NewRunnableMethod>( + this, &VorbisDataDecoder::Decode, + RefPtr(aSample))); return NS_OK; } @@ -265,9 +263,7 @@ VorbisDataDecoder::DoDrain() nsresult VorbisDataDecoder::Drain() { - nsCOMPtr runnable( - NS_NewRunnableMethod(this, &VorbisDataDecoder::DoDrain)); - mTaskQueue->Dispatch(runnable.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &VorbisDataDecoder::DoDrain)); return NS_OK; } diff --git a/dom/media/platforms/agnostic/WAVDecoder.cpp b/dom/media/platforms/agnostic/WAVDecoder.cpp index 677e68b436..d31d514379 100644 --- a/dom/media/platforms/agnostic/WAVDecoder.cpp +++ b/dom/media/platforms/agnostic/WAVDecoder.cpp @@ -70,11 +70,9 @@ WaveDataDecoder::Init() nsresult WaveDataDecoder::Input(MediaRawData* aSample) { - nsCOMPtr runnable( - NS_NewRunnableMethodWithArg>( - this, &WaveDataDecoder::Decode, - RefPtr(aSample))); - mTaskQueue->Dispatch(runnable.forget()); + mTaskQueue->Dispatch(NewRunnableMethod>( + this, &WaveDataDecoder::Decode, + RefPtr(aSample))); return NS_OK; } @@ -158,9 +156,7 @@ WaveDataDecoder::DoDrain() nsresult WaveDataDecoder::Drain() { - nsCOMPtr runnable( - NS_NewRunnableMethod(this, &WaveDataDecoder::DoDrain)); - mTaskQueue->Dispatch(runnable.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &WaveDataDecoder::DoDrain)); return NS_OK; } @@ -186,4 +182,4 @@ WaveDataDecoder::IsWave(const nsACString& aMimeType) } } // namespace mozilla -#undef LOG \ No newline at end of file +#undef LOG diff --git a/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.cpp b/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.cpp index 8808ff23b9..503de5380f 100644 --- a/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.cpp +++ b/dom/media/platforms/agnostic/gmp/MediaDataDecoderProxy.cpp @@ -58,9 +58,7 @@ MediaDataDecoderProxy::Flush() mFlushComplete.Set(false); - nsCOMPtr task; - task = NS_NewRunnableMethod(mProxyDecoder, &MediaDataDecoder::Flush); - mProxyThread->Dispatch(task.forget()); + mProxyThread->Dispatch(NewRunnableMethod(mProxyDecoder, &MediaDataDecoder::Flush)); mFlushComplete.WaitUntil(true); @@ -73,9 +71,7 @@ MediaDataDecoderProxy::Drain() MOZ_ASSERT(!IsOnProxyThread()); MOZ_ASSERT(!mIsShutdown); - nsCOMPtr task; - task = NS_NewRunnableMethod(mProxyDecoder, &MediaDataDecoder::Drain); - mProxyThread->Dispatch(task.forget()); + mProxyThread->Dispatch(NewRunnableMethod(mProxyDecoder, &MediaDataDecoder::Drain)); return NS_OK; } @@ -87,9 +83,9 @@ MediaDataDecoderProxy::Shutdown() #if defined(DEBUG) mIsShutdown = true; #endif - nsCOMPtr task; - task = NS_NewRunnableMethod(mProxyDecoder, &MediaDataDecoder::Shutdown); - nsresult rv = mProxyThread->AsXPCOMThread()->Dispatch(task, NS_DISPATCH_SYNC); + nsresult rv = mProxyThread->AsXPCOMThread()->Dispatch(NewRunnableMethod(mProxyDecoder, + &MediaDataDecoder::Shutdown), + NS_DISPATCH_SYNC); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; } diff --git a/dom/media/platforms/android/AndroidDecoderModule.cpp b/dom/media/platforms/android/AndroidDecoderModule.cpp index cc09d2c228..f878f49354 100644 --- a/dom/media/platforms/android/AndroidDecoderModule.cpp +++ b/dom/media/platforms/android/AndroidDecoderModule.cpp @@ -389,9 +389,8 @@ MediaCodecDataDecoder::InitDecoder(Surface::Param aSurface) NS_ENSURE_SUCCESS(rv = ResetInputBuffers(), rv); NS_ENSURE_SUCCESS(rv = ResetOutputBuffers(), rv); - rv = NS_NewNamedThread( - "MC Decoder", getter_AddRefs(mThread), - NS_NewRunnableMethod(this, &MediaCodecDataDecoder::DecoderLoop)); + nsCOMPtr r = NewRunnableMethod(this, &MediaCodecDataDecoder::DecoderLoop); + rv = NS_NewNamedThread("MC Decoder", getter_AddRefs(mThread), r); return rv; } diff --git a/dom/media/platforms/apple/AppleATDecoder.cpp b/dom/media/platforms/apple/AppleATDecoder.cpp index 6d364c25d9..a5da492aa1 100644 --- a/dom/media/platforms/apple/AppleATDecoder.cpp +++ b/dom/media/platforms/apple/AppleATDecoder.cpp @@ -74,7 +74,7 @@ AppleATDecoder::Input(MediaRawData* aSample) // Queue a task to perform the actual decoding on a separate thread. nsCOMPtr runnable = - NS_NewRunnableMethodWithArg>( + NewRunnableMethod>( this, &AppleATDecoder::SubmitSample, RefPtr(aSample)); diff --git a/dom/media/platforms/apple/AppleVDADecoder.cpp b/dom/media/platforms/apple/AppleVDADecoder.cpp index 89b5e66c8d..2c96100401 100644 --- a/dom/media/platforms/apple/AppleVDADecoder.cpp +++ b/dom/media/platforms/apple/AppleVDADecoder.cpp @@ -100,7 +100,7 @@ AppleVDADecoder::Shutdown() mIsShutDown = true; if (mTaskQueue) { nsCOMPtr runnable = - NS_NewRunnableMethod(this, &AppleVDADecoder::ProcessShutdown); + NewRunnableMethod(this, &AppleVDADecoder::ProcessShutdown); mTaskQueue->Dispatch(runnable.forget()); } else { ProcessShutdown(); @@ -133,7 +133,7 @@ AppleVDADecoder::Input(MediaRawData* aSample) mInputIncoming++; nsCOMPtr runnable = - NS_NewRunnableMethodWithArg>( + NewRunnableMethod>( this, &AppleVDADecoder::SubmitFrame, RefPtr(aSample)); @@ -148,7 +148,7 @@ AppleVDADecoder::Flush() mIsFlushing = true; mTaskQueue->Flush(); nsCOMPtr runnable = - NS_NewRunnableMethod(this, &AppleVDADecoder::ProcessFlush); + NewRunnableMethod(this, &AppleVDADecoder::ProcessFlush); MonitorAutoLock mon(mMonitor); mTaskQueue->Dispatch(runnable.forget()); while (mIsFlushing) { @@ -163,7 +163,7 @@ AppleVDADecoder::Drain() { MOZ_ASSERT(mCallback->OnReaderTaskQueue()); nsCOMPtr runnable = - NS_NewRunnableMethod(this, &AppleVDADecoder::ProcessDrain); + NewRunnableMethod(this, &AppleVDADecoder::ProcessDrain); mTaskQueue->Dispatch(runnable.forget()); return NS_OK; } diff --git a/dom/media/platforms/apple/AppleVTDecoder.cpp b/dom/media/platforms/apple/AppleVTDecoder.cpp index 000f95c638..d3e444688c 100644 --- a/dom/media/platforms/apple/AppleVTDecoder.cpp +++ b/dom/media/platforms/apple/AppleVTDecoder.cpp @@ -107,7 +107,7 @@ AppleVTDecoder::Input(MediaRawData* aSample) mInputIncoming++; nsCOMPtr runnable = - NS_NewRunnableMethodWithArg>( + NewRunnableMethod>( this, &AppleVTDecoder::SubmitFrame, aSample); mTaskQueue->Dispatch(runnable.forget()); return NS_OK; diff --git a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp index 802f5d9859..c06e449388 100644 --- a/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegAudioDecoder.cpp @@ -232,7 +232,7 @@ FFmpegAudioDecoder::DecodePacket(MediaRawData* aSample) nsresult FFmpegAudioDecoder::Input(MediaRawData* aSample) { - nsCOMPtr runnable(NS_NewRunnableMethodWithArg>( + nsCOMPtr runnable(NewRunnableMethod>( this, &FFmpegAudioDecoder::DecodePacket, RefPtr(aSample))); mTaskQueue->Dispatch(runnable.forget()); return NS_OK; diff --git a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp index 6f0a1ab21d..fecec59617 100644 --- a/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegDataDecoder.cpp @@ -127,7 +127,7 @@ FFmpegDataDecoder::Shutdown() { if (mTaskQueue) { nsCOMPtr runnable = - NS_NewRunnableMethod(this, &FFmpegDataDecoder::ProcessShutdown); + NewRunnableMethod(this, &FFmpegDataDecoder::ProcessShutdown); mTaskQueue->Dispatch(runnable.forget()); } else { ProcessShutdown(); @@ -142,7 +142,7 @@ FFmpegDataDecoder::Flush() mIsFlushing = true; mTaskQueue->Flush(); nsCOMPtr runnable = - NS_NewRunnableMethod(this, &FFmpegDataDecoder::ProcessFlush); + NewRunnableMethod(this, &FFmpegDataDecoder::ProcessFlush); MonitorAutoLock mon(mMonitor); mTaskQueue->Dispatch(runnable.forget()); while (mIsFlushing) { @@ -156,7 +156,7 @@ FFmpegDataDecoder::Drain() { MOZ_ASSERT(mCallback->OnReaderTaskQueue()); nsCOMPtr runnable = - NS_NewRunnableMethod(this, &FFmpegDataDecoder::ProcessDrain); + NewRunnableMethod(this, &FFmpegDataDecoder::ProcessDrain); mTaskQueue->Dispatch(runnable.forget()); return NS_OK; } diff --git a/dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp b/dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp index 93f4bb17d6..facf89d424 100644 --- a/dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp +++ b/dom/media/platforms/ffmpeg/FFmpegH264Decoder.cpp @@ -367,7 +367,7 @@ nsresult FFmpegH264Decoder::Input(MediaRawData* aSample) { nsCOMPtr runnable( - NS_NewRunnableMethodWithArg>( + NewRunnableMethod>( this, &FFmpegH264Decoder::DecodeFrame, RefPtr(aSample))); mTaskQueue->Dispatch(runnable.forget()); diff --git a/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp b/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp index db263df98c..a947d110a2 100644 --- a/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp +++ b/dom/media/platforms/wmf/WMFMediaDataDecoder.cpp @@ -45,9 +45,7 @@ WMFMediaDataDecoder::Shutdown() MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown); if (mTaskQueue) { - nsCOMPtr runnable = - NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessShutdown); - mTaskQueue->Dispatch(runnable.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessShutdown)); } else { ProcessShutdown(); } @@ -75,7 +73,7 @@ WMFMediaDataDecoder::Input(MediaRawData* aSample) MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown); nsCOMPtr runnable = - NS_NewRunnableMethodWithArg>( + NewRunnableMethod>( this, &WMFMediaDataDecoder::ProcessDecode, RefPtr(aSample)); @@ -151,11 +149,9 @@ WMFMediaDataDecoder::Flush() MOZ_ASSERT(mCallback->OnReaderTaskQueue()); MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown); - nsCOMPtr runnable = - NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessFlush); MonitorAutoLock mon(mMonitor); mIsFlushing = true; - mTaskQueue->Dispatch(runnable.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessFlush)); while (mIsFlushing) { mon.Wait(); } @@ -185,9 +181,7 @@ WMFMediaDataDecoder::Drain() MOZ_ASSERT(mCallback->OnReaderTaskQueue()); MOZ_DIAGNOSTIC_ASSERT(!mIsShutDown); - nsCOMPtr runnable = - NS_NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessDrain); - mTaskQueue->Dispatch(runnable.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &WMFMediaDataDecoder::ProcessDrain)); return NS_OK; } @@ -204,7 +198,7 @@ WMFMediaDataDecoder::ConfigurationChanged(const TrackInfo& aConfig) MOZ_ASSERT(mCallback->OnReaderTaskQueue()); nsCOMPtr runnable = - NS_NewRunnableMethodWithArg&&>( + NewRunnableMethod&&>( this, &WMFMediaDataDecoder::ProcessConfigurationChanged, aConfig.Clone()); diff --git a/dom/media/platforms/wrappers/FuzzingWrapper.cpp b/dom/media/platforms/wrappers/FuzzingWrapper.cpp index 0cb776c582..3e4081f19d 100644 --- a/dom/media/platforms/wrappers/FuzzingWrapper.cpp +++ b/dom/media/platforms/wrappers/FuzzingWrapper.cpp @@ -136,7 +136,7 @@ DecoderCallbackFuzzingWrapper::Output(MediaData* aData) { if (!mTaskQueue->IsCurrentThreadIn()) { nsCOMPtr task = - NS_NewRunnableMethodWithArg>( + NewRunnableMethod>( this, &DecoderCallbackFuzzingWrapper::Output, aData); mTaskQueue->Dispatch(task.forget()); return; @@ -176,9 +176,7 @@ void DecoderCallbackFuzzingWrapper::Error() { if (!mTaskQueue->IsCurrentThreadIn()) { - nsCOMPtr task = - NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::Error); - mTaskQueue->Dispatch(task.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::Error)); return; } CFW_LOGV(""); @@ -191,9 +189,7 @@ void DecoderCallbackFuzzingWrapper::InputExhausted() { if (!mTaskQueue->IsCurrentThreadIn()) { - nsCOMPtr task = - NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::InputExhausted); - mTaskQueue->Dispatch(task.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::InputExhausted)); return; } if (!mDontDelayInputExhausted && !mDelayedOutput.empty()) { @@ -212,9 +208,7 @@ void DecoderCallbackFuzzingWrapper::DrainComplete() { if (!mTaskQueue->IsCurrentThreadIn()) { - nsCOMPtr task = - NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::DrainComplete); - mTaskQueue->Dispatch(task.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::DrainComplete)); return; } MOZ_ASSERT(mCallback); @@ -233,9 +227,7 @@ void DecoderCallbackFuzzingWrapper::ReleaseMediaResources() { if (!mTaskQueue->IsCurrentThreadIn()) { - nsCOMPtr task = - NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::ReleaseMediaResources); - mTaskQueue->Dispatch(task.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::ReleaseMediaResources)); return; } CFW_LOGV(""); @@ -317,9 +309,7 @@ DecoderCallbackFuzzingWrapper::ClearDelayedOutput() { if (!mTaskQueue->IsCurrentThreadIn()) { DFW_LOGV("(dispatching self)"); - nsCOMPtr task = - NS_NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::ClearDelayedOutput); - mTaskQueue->Dispatch(task.forget()); + mTaskQueue->Dispatch(NewRunnableMethod(this, &DecoderCallbackFuzzingWrapper::ClearDelayedOutput)); return; } DFW_LOGV(""); diff --git a/dom/media/raw/RawReader.cpp b/dom/media/raw/RawReader.cpp index aa562d53d9..3b1a0c0527 100644 --- a/dom/media/raw/RawReader.cpp +++ b/dom/media/raw/RawReader.cpp @@ -27,10 +27,10 @@ RawReader::~RawReader() MOZ_COUNT_DTOR(RawReader); } -nsresult RawReader::ResetDecode() +nsresult RawReader::ResetDecode(TargetQueues aQueues) { mCurrentFrame = 0; - return MediaDecoderReader::ResetDecode(); + return MediaDecoderReader::ResetDecode(aQueues); } nsresult RawReader::ReadMetadata(MediaInfo* aInfo, diff --git a/dom/media/raw/RawReader.h b/dom/media/raw/RawReader.h index d73d22fc32..0c7696893c 100644 --- a/dom/media/raw/RawReader.h +++ b/dom/media/raw/RawReader.h @@ -20,7 +20,7 @@ protected: ~RawReader(); public: - nsresult ResetDecode() override; + nsresult ResetDecode(TargetQueues aQueues) override; bool DecodeAudioData() override; bool DecodeVideoFrame(bool &aKeyframeSkip, diff --git a/dom/media/systemservices/MediaSystemResourceManager.cpp b/dom/media/systemservices/MediaSystemResourceManager.cpp index 4d833dd239..88dcc7080e 100644 --- a/dom/media/systemservices/MediaSystemResourceManager.cpp +++ b/dom/media/systemservices/MediaSystemResourceManager.cpp @@ -199,7 +199,7 @@ MediaSystemResourceManager::Acquire(MediaSystemResourceClient* aClient) } aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_WAITING; ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask( - NewRunnableMethod( + NewRunnableMethod( this, &MediaSystemResourceManager::DoAcquire, aClient->mId)); @@ -242,7 +242,7 @@ MediaSystemResourceManager::AcquireSyncNoWait(MediaSystemResourceClient* aClient } ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask( - NewRunnableMethod( + NewRunnableMethod( this, &MediaSystemResourceManager::DoAcquire, aClient->mId)); @@ -309,7 +309,7 @@ MediaSystemResourceManager::ReleaseResource(MediaSystemResourceClient* aClient) aClient->mResourceState = MediaSystemResourceClient::RESOURCE_STATE_END; ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask( - NewRunnableMethod( + NewRunnableMethod( this, &MediaSystemResourceManager::DoRelease, aClient->mId)); @@ -337,7 +337,7 @@ MediaSystemResourceManager::HandleAcquireResult(uint32_t aId, bool aSuccess) { if (!InImageBridgeChildThread()) { ImageBridgeChild::GetSingleton()->GetMessageLoop()->PostTask( - NewRunnableMethod( + NewRunnableMethod( this, &MediaSystemResourceManager::HandleAcquireResult, aId, diff --git a/dom/media/webaudio/AudioContext.cpp b/dom/media/webaudio/AudioContext.cpp index 0fed87d8de..818dbccd46 100644 --- a/dom/media/webaudio/AudioContext.cpp +++ b/dom/media/webaudio/AudioContext.cpp @@ -30,6 +30,7 @@ #include "DelayNode.h" #include "DynamicsCompressorNode.h" #include "GainNode.h" +#include "IIRFilterNode.h" #include "MediaElementAudioSourceNode.h" #include "MediaStreamAudioDestinationNode.h" #include "MediaStreamAudioSourceNode.h" @@ -505,6 +506,42 @@ AudioContext::CreateBiquadFilter(ErrorResult& aRv) return filterNode.forget(); } +already_AddRefed +AudioContext::CreateIIRFilter(const mozilla::dom::binding_detail::AutoSequence& aFeedforward, + const mozilla::dom::binding_detail::AutoSequence& aFeedback, + mozilla::ErrorResult& aRv) +{ + if (CheckClosed(aRv)) { + return nullptr; + } + + if (aFeedforward.Length() == 0 || aFeedforward.Length() > 20) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } + + if (aFeedback.Length() == 0 || aFeedback.Length() > 20) { + aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return nullptr; + } + + bool feedforwardAllZeros = true; + for (size_t i = 0; i < aFeedforward.Length(); ++i) { + if (aFeedforward.Elements()[i] != 0.0) { + feedforwardAllZeros = false; + } + } + + if (feedforwardAllZeros || aFeedback.Elements()[0] == 0.0) { + aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); + return nullptr; + } + + RefPtr filterNode = + new IIRFilterNode(this, aFeedforward, aFeedback); + return filterNode.forget(); +} + already_AddRefed AudioContext::CreateOscillator(ErrorResult& aRv) { diff --git a/dom/media/webaudio/AudioContext.h b/dom/media/webaudio/AudioContext.h index 619b122ade..50a605996d 100644 --- a/dom/media/webaudio/AudioContext.h +++ b/dom/media/webaudio/AudioContext.h @@ -57,9 +57,10 @@ class ConvolverNode; class DelayNode; class DynamicsCompressorNode; class GainNode; -class HTMLMediaElement; -class MediaElementAudioSourceNode; class GlobalObject; +class HTMLMediaElement; +class IIRFilterNode; +class MediaElementAudioSourceNode; class MediaStreamAudioDestinationNode; class MediaStreamAudioSourceNode; class OscillatorNode; @@ -251,6 +252,11 @@ public: already_AddRefed CreateBiquadFilter(ErrorResult& aRv); + already_AddRefed + CreateIIRFilter(const mozilla::dom::binding_detail::AutoSequence& aFeedforward, + const mozilla::dom::binding_detail::AutoSequence& aFeedback, + mozilla::ErrorResult& aRv); + already_AddRefed CreateOscillator(ErrorResult& aRv); diff --git a/dom/media/webaudio/AudioDestinationNode.cpp b/dom/media/webaudio/AudioDestinationNode.cpp index 978f922b0b..e10edd6c55 100644 --- a/dom/media/webaudio/AudioDestinationNode.cpp +++ b/dom/media/webaudio/AudioDestinationNode.cpp @@ -305,11 +305,6 @@ private: bool mSuspended; }; -static bool UseAudioChannelAPI() -{ - return Preferences::GetBool("media.useAudioChannelAPI"); -} - NS_IMPL_CYCLE_COLLECTION_INHERITED(AudioDestinationNode, AudioNode, mAudioChannelAgent, mOfflineRenderingPromise) @@ -331,7 +326,7 @@ AudioDestinationNode::AudioDestinationNode(AudioContext* aContext, , mFramesToProduce(aLength) , mAudioChannel(AudioChannel::Normal) , mIsOffline(aIsOffline) - , mAudioChannelAgentPlaying(false) + , mAudioChannelSuspended(false) , mCaptured(false) { MediaStreamGraph* graph = aIsOffline ? @@ -410,9 +405,8 @@ AudioDestinationNode::NotifyMainThreadStreamFinished() MOZ_ASSERT(mStream->IsFinished()); if (mIsOffline) { - nsCOMPtr runnable = - NS_NewRunnableMethod(this, &AudioDestinationNode::FireOfflineCompletionEvent); - NS_DispatchToCurrentThread(runnable); + NS_DispatchToCurrentThread(NewRunnableMethod(this, + &AudioDestinationNode::FireOfflineCompletionEvent)); } } @@ -501,31 +495,36 @@ AudioDestinationNode::StartRendering(Promise* aPromise) mStream->Graph()->StartNonRealtimeProcessing(mFramesToProduce); } -void -AudioDestinationNode::SetCanPlay(float aVolume, bool aMuted) -{ - if (!mStream) { - return; - } - - mStream->SetTrackEnabled(AudioNodeStream::AUDIO_TRACK, !aMuted); - mStream->SetAudioOutputVolume(&gWebAudioOutputKey, aVolume); -} - NS_IMETHODIMP AudioDestinationNode::WindowVolumeChanged(float aVolume, bool aMuted) { - if (aMuted != mAudioChannelAgentPlaying) { - mAudioChannelAgentPlaying = aMuted; - - if (UseAudioChannelAPI()) { - Context()->DispatchTrustedEvent( - !aMuted ? NS_LITERAL_STRING("mozinterruptend") - : NS_LITERAL_STRING("mozinterruptbegin")); - } + if (!mStream) { + return NS_OK; } - SetCanPlay(aVolume, aMuted); + float volume = aMuted ? 0.0 : aVolume; + mStream->SetAudioOutputVolume(&gWebAudioOutputKey, volume); + return NS_OK; +} + +NS_IMETHODIMP +AudioDestinationNode::WindowSuspendChanged(nsSuspendedTypes aSuspend) +{ + if (!mStream) { + return NS_OK; + } + + bool suspended = (aSuspend != nsISuspendedTypes::NONE_SUSPENDED); + if (mAudioChannelSuspended == suspended) { + return NS_OK; + } + + mAudioChannelSuspended = suspended; + Context()->DispatchTrustedEvent(!suspended ? + NS_LITERAL_STRING("mozinterruptend") : + NS_LITERAL_STRING("mozinterruptbegin")); + + mStream->SetTrackEnabled(AudioNodeStream::AUDIO_TRACK, !suspended); return NS_OK; } @@ -664,14 +663,15 @@ AudioDestinationNode::InputMuted(bool aMuted) return; } - float volume = 0.0; - bool muted = true; - nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted); + AudioPlaybackConfig config; + nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config, + AudioChannelService::AudibleState::eAudible); if (NS_WARN_IF(NS_FAILED(rv))) { return; } - WindowVolumeChanged(volume, muted); + WindowVolumeChanged(config.mVolume, config.mMuted); + WindowSuspendChanged(config.mSuspend); } } // namespace dom diff --git a/dom/media/webaudio/AudioDestinationNode.h b/dom/media/webaudio/AudioDestinationNode.h index 708cd1cc6e..cf0db78627 100644 --- a/dom/media/webaudio/AudioDestinationNode.h +++ b/dom/media/webaudio/AudioDestinationNode.h @@ -92,8 +92,6 @@ private: void SetMozAudioChannelType(AudioChannel aValue, ErrorResult& aRv); bool CheckAudioChannelPermissions(AudioChannel aValue); - void SetCanPlay(float aVolume, bool aMuted); - SelfReference mOfflineRenderingRef; uint32_t mFramesToProduce; @@ -105,7 +103,7 @@ private: // Audio Channel Type. AudioChannel mAudioChannel; bool mIsOffline; - bool mAudioChannelAgentPlaying; + bool mAudioChannelSuspended; bool mCaptured; }; diff --git a/dom/media/webaudio/IIRFilterNode.cpp b/dom/media/webaudio/IIRFilterNode.cpp new file mode 100644 index 0000000000..c39b5d33e3 --- /dev/null +++ b/dom/media/webaudio/IIRFilterNode.cpp @@ -0,0 +1,225 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 "IIRFilterNode.h" +#include "AudioNodeEngine.h" + +#include "blink/IIRFilter.h" + +namespace mozilla { +namespace dom { + +NS_IMPL_ISUPPORTS_INHERITED0(IIRFilterNode, AudioNode) + +class IIRFilterNodeEngine final : public AudioNodeEngine +{ +public: + IIRFilterNodeEngine(AudioNode* aNode, AudioDestinationNode* aDestination, + const AudioDoubleArray &aFeedforward, + const AudioDoubleArray &aFeedback, + uint64_t aWindowID) + : AudioNodeEngine(aNode) + , mDestination(aDestination->Stream()) + , mFeedforward(aFeedforward) + , mFeedback(aFeedback) + , mWindowID(aWindowID) + { + } + + void ProcessBlock(AudioNodeStream* aStream, + GraphTime aFrom, + const AudioBlock& aInput, + AudioBlock* aOutput, + bool* aFinished) override + { + float inputBuffer[WEBAUDIO_BLOCK_SIZE + 4]; + float* alignedInputBuffer = ALIGNED16(inputBuffer); + ASSERT_ALIGNED16(alignedInputBuffer); + + if (aInput.IsNull()) { + if (!mIIRFilters.IsEmpty()) { + bool allZero = true; + for (uint32_t i = 0; i < mIIRFilters.Length(); ++i) { + allZero &= mIIRFilters[i]->buffersAreZero(); + } + + // all filter buffer values are zero, so the output will be zero + // as well. + if (allZero) { + mIIRFilters.Clear(); + aStream->ScheduleCheckForInactive(); + + RefPtr refchanged = + new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::RELEASE); + aStream->Graph()-> + DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget()); + + aOutput->SetNull(WEBAUDIO_BLOCK_SIZE); + return; + } + + PodZero(alignedInputBuffer, WEBAUDIO_BLOCK_SIZE); + } + } else if(mIIRFilters.Length() != aInput.ChannelCount()){ + if (mIIRFilters.IsEmpty()) { + RefPtr refchanged = + new PlayingRefChangeHandler(aStream, PlayingRefChangeHandler::ADDREF); + aStream->Graph()-> + DispatchToMainThreadAfterStreamStateUpdate(refchanged.forget()); + } else { + WebAudioUtils::LogToDeveloperConsole(mWindowID, + "IIRFilterChannelCountChangeWarning"); + } + + // Adjust the number of filters based on the number of channels + mIIRFilters.SetLength(aInput.ChannelCount()); + for (size_t i = 0; i < aInput.ChannelCount(); ++i) { + mIIRFilters[i] = new blink::IIRFilter(&mFeedforward, &mFeedback); + } + } + + uint32_t numberOfChannels = mIIRFilters.Length(); + aOutput->AllocateChannels(numberOfChannels); + + for (uint32_t i = 0; i < numberOfChannels; ++i) { + const float* input; + if (aInput.IsNull()) { + input = alignedInputBuffer; + } else { + input = static_cast(aInput.mChannelData[i]); + if (aInput.mVolume != 1.0) { + AudioBlockCopyChannelWithScale(input, aInput.mVolume, alignedInputBuffer); + input = alignedInputBuffer; + } + } + + mIIRFilters[i]->process(input, + aOutput->ChannelFloatsForWrite(i), + aInput.GetDuration()); + } + } + + bool IsActive() const override + { + return !mIIRFilters.IsEmpty(); + } + + size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override + { + // Not owned: + // - mDestination - probably not owned + // - AudioParamTimelines - counted in the AudioNode + size_t amount = AudioNodeEngine::SizeOfExcludingThis(aMallocSizeOf); + amount += mIIRFilters.ShallowSizeOfExcludingThis(aMallocSizeOf); + return amount; + } + + size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override + { + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); + } + +private: + AudioNodeStream* mDestination; + nsTArray> mIIRFilters; + AudioDoubleArray mFeedforward; + AudioDoubleArray mFeedback; + uint64_t mWindowID; +}; + +IIRFilterNode::IIRFilterNode(AudioContext* aContext, + const mozilla::dom::binding_detail::AutoSequence& aFeedforward, + const mozilla::dom::binding_detail::AutoSequence& aFeedback) + : AudioNode(aContext, + 2, + ChannelCountMode::Max, + ChannelInterpretation::Speakers) +{ + mFeedforward.SetLength(aFeedforward.Length()); + PodCopy(mFeedforward.Elements(), aFeedforward.Elements(), aFeedforward.Length()); + mFeedback.SetLength(aFeedback.Length()); + PodCopy(mFeedback.Elements(), aFeedback.Elements(), aFeedback.Length()); + + // Scale coefficients -- we guarantee that mFeedback != 0 when creating + // the IIRFilterNode. + double scale = mFeedback[0]; + double* elements = mFeedforward.Elements(); + for (size_t i = 0; i < mFeedforward.Length(); ++i) { + elements[i] /= scale; + } + + elements = mFeedback.Elements(); + for (size_t i = 0; i < mFeedback.Length(); ++i) { + elements[i] /= scale; + } + + // We check that this is exactly equal to one later in blink/IIRFilter.cpp + elements[0] = 1.0; + + uint64_t windowID = aContext->GetParentObject()->WindowID(); + IIRFilterNodeEngine* engine = new IIRFilterNodeEngine(this, aContext->Destination(), mFeedforward, mFeedback, windowID); + mStream = AudioNodeStream::Create(aContext, engine, + AudioNodeStream::NO_STREAM_FLAGS); +} + +IIRFilterNode::~IIRFilterNode() +{ +} + +size_t +IIRFilterNode::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const +{ + size_t amount = AudioNode::SizeOfExcludingThis(aMallocSizeOf); + return amount; +} + +size_t +IIRFilterNode::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const +{ + return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf); +} + +JSObject* +IIRFilterNode::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return IIRFilterNodeBinding::Wrap(aCx, this, aGivenProto); +} + +void +IIRFilterNode::GetFrequencyResponse(const Float32Array& aFrequencyHz, + const Float32Array& aMagResponse, + const Float32Array& aPhaseResponse) +{ + aFrequencyHz.ComputeLengthAndData(); + aMagResponse.ComputeLengthAndData(); + aPhaseResponse.ComputeLengthAndData(); + + uint32_t length = std::min(std::min(aFrequencyHz.Length(), + aMagResponse.Length()), + aPhaseResponse.Length()); + if (!length) { + return; + } + + auto frequencies = MakeUnique(length); + float* frequencyHz = aFrequencyHz.Data(); + const double nyquist = Context()->SampleRate() * 0.5; + + // Normalize the frequencies + for (uint32_t i = 0; i < length; ++i) { + if (frequencyHz[i] >= 0 && frequencyHz[i] <= nyquist) { + frequencies[i] = static_cast(frequencyHz[i] / nyquist); + } else { + frequencies[i] = std::numeric_limits::quiet_NaN(); + } + } + + blink::IIRFilter filter(&mFeedforward, &mFeedback); + filter.getFrequencyResponse(int(length), frequencies.get(), aMagResponse.Data(), aPhaseResponse.Data()); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/media/webaudio/IIRFilterNode.h b/dom/media/webaudio/IIRFilterNode.h new file mode 100644 index 0000000000..78546c3e54 --- /dev/null +++ b/dom/media/webaudio/IIRFilterNode.h @@ -0,0 +1,55 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* 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 IIRFilterNode_h_ +#define IIRFilterNode_h_ + +#include "AudioNode.h" +#include "AudioParam.h" +#include "mozilla/dom/IIRFilterNodeBinding.h" + +namespace mozilla { +namespace dom { + +class AudioContext; + +class IIRFilterNode final : public AudioNode +{ +public: + explicit IIRFilterNode(AudioContext* aContext, + const mozilla::dom::binding_detail::AutoSequence& aFeedforward, + const mozilla::dom::binding_detail::AutoSequence& aFeedback); + + NS_DECL_ISUPPORTS_INHERITED + + JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + + void GetFrequencyResponse(const Float32Array& aFrequencyHz, + const Float32Array& aMagResponse, + const Float32Array& aPhaseResponse); + + const char* NodeType() const override + { + return "IIRFilterNode"; + } + + size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const override; + size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const override; + +protected: + virtual ~IIRFilterNode(); + +private: + nsTArray mFeedback; + nsTArray mFeedforward; +}; + +} // namespace dom +} // namespace mozilla + +#endif + diff --git a/dom/media/webaudio/MediaBufferDecoder.cpp b/dom/media/webaudio/MediaBufferDecoder.cpp index 48ab297ebf..fcd76fc564 100644 --- a/dom/media/webaudio/MediaBufferDecoder.cpp +++ b/dom/media/webaudio/MediaBufferDecoder.cpp @@ -122,7 +122,7 @@ private: mDecodeJob.OnFailure(aErrorCode); } else { // Take extra care to cleanup on the main thread - NS_DispatchToMainThread(NS_NewRunnableMethod(this, &MediaDecodeTask::Cleanup)); + NS_DispatchToMainThread(NewRunnableMethod(this, &MediaDecodeTask::Cleanup)); nsCOMPtr event = new ReportResultTask(mDecodeJob, &WebAudioDecodeJob::OnFailure, aErrorCode); diff --git a/dom/media/webaudio/WebAudioUtils.cpp b/dom/media/webaudio/WebAudioUtils.cpp index db9fbc3846..6289f803b3 100644 --- a/dom/media/webaudio/WebAudioUtils.cpp +++ b/dom/media/webaudio/WebAudioUtils.cpp @@ -8,6 +8,10 @@ #include "AudioNodeStream.h" #include "blink/HRTFDatabaseLoader.h" +#include "nsContentUtils.h" +#include "nsIConsoleService.h" +#include "nsIScriptError.h" + namespace mozilla { LazyLogModule gWebAudioAPILog("WebAudioAPI"); @@ -89,5 +93,59 @@ WebAudioUtils::SpeexResamplerProcess(SpeexResamplerState* aResampler, #endif } +void +WebAudioUtils::LogToDeveloperConsole(uint64_t aWindowID, const char* aKey) +{ + // This implementation is derived from dom/media/VideoUtils.cpp, but we + // use a windowID so that the message is delivered to the developer console. + // It is similar to ContentUtils::ReportToConsole, but also works off main + // thread. + if (!NS_IsMainThread()) { + nsCOMPtr task = + NS_NewRunnableFunction([aWindowID, aKey]() { LogToDeveloperConsole(aWindowID, aKey); }); + NS_DispatchToMainThread(task.forget(), NS_DISPATCH_NORMAL); + return; + } + + nsCOMPtr console( + do_GetService("@mozilla.org/consoleservice;1")); + if (!console) { + NS_WARNING("Failed to log message to console."); + return; + } + + nsAutoCString spec; + uint32_t aLineNumber, aColumnNumber; + JSContext *cx = nsContentUtils::GetCurrentJSContext(); + if (cx) { + nsJSUtils::GetCallingLocation(cx, spec, &aLineNumber, &aColumnNumber); + } + + nsresult rv; + nsCOMPtr errorObject = + do_CreateInstance(NS_SCRIPTERROR_CONTRACTID, &rv); + if (!errorObject) { + NS_WARNING("Failed to log message to console."); + return; + } + + nsXPIDLString result; + rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES, + aKey, result); + + if (NS_FAILED(rv)) { + NS_WARNING("Failed to log message to console."); + return; + } + + errorObject->InitWithWindowID(result, + NS_ConvertUTF8toUTF16(spec), + EmptyString(), + aLineNumber, aColumnNumber, + nsIScriptError::warningFlag, "Web Audio", + aWindowID); + console->LogMessage(errorObject); +} + } // namespace dom } // namespace mozilla diff --git a/dom/media/webaudio/WebAudioUtils.h b/dom/media/webaudio/WebAudioUtils.h index dcf0037122..c0b27b8379 100644 --- a/dom/media/webaudio/WebAudioUtils.h +++ b/dom/media/webaudio/WebAudioUtils.h @@ -225,6 +225,10 @@ namespace WebAudioUtils { uint32_t aChannel, const int16_t* aIn, uint32_t* aInLen, int16_t* aOut, uint32_t* aOutLen); + + void + LogToDeveloperConsole(uint64_t aWindowID, const char* aKey); + } // namespace WebAudioUtils } // namespace dom diff --git a/dom/media/webaudio/blink/Biquad.cpp b/dom/media/webaudio/blink/Biquad.cpp index 38c92ff113..fbc4cf0776 100644 --- a/dom/media/webaudio/blink/Biquad.cpp +++ b/dom/media/webaudio/blink/Biquad.cpp @@ -76,6 +76,7 @@ void Biquad::process(const float* sourceP, float* destP, size_t framesToProcess) // Avoid introducing a stream of subnormals when input is silent and the // tail approaches zero. + // TODO: Remove this code when Bug 1157635 is fixed. if (x1 == 0.0 && x2 == 0.0 && (y1 != 0.0 || y2 != 0.0) && fabs(y1) < FLT_MIN && fabs(y2) < FLT_MIN) { // Flush future values to zero (until there is new input). diff --git a/dom/media/webaudio/blink/IIRFilter.cpp b/dom/media/webaudio/blink/IIRFilter.cpp new file mode 100644 index 0000000000..3bfafbce36 --- /dev/null +++ b/dom/media/webaudio/blink/IIRFilter.cpp @@ -0,0 +1,158 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "IIRFilter.h" + +#include + +namespace blink { + +// The length of the memory buffers for the IIR filter. This MUST be a power of two and must be +// greater than the possible length of the filter coefficients. +const int kBufferLength = 32; +static_assert(kBufferLength >= IIRFilter::kMaxOrder + 1, + "Internal IIR buffer length must be greater than maximum IIR Filter order."); + +IIRFilter::IIRFilter(const AudioDoubleArray* feedforwardCoef, const AudioDoubleArray* feedbackCoef) + : m_bufferIndex(0) + , m_feedback(feedbackCoef) + , m_feedforward(feedforwardCoef) +{ + m_xBuffer.SetLength(kBufferLength); + m_yBuffer.SetLength(kBufferLength); + reset(); +} + +IIRFilter::~IIRFilter() +{ +} + +void IIRFilter::reset() +{ + memset(m_xBuffer.Elements(), 0, m_xBuffer.Length() * sizeof(double)); + memset(m_yBuffer.Elements(), 0, m_yBuffer.Length() * sizeof(double)); +} + +static std::complex evaluatePolynomial(const double* coef, std::complex z, int order) +{ + // Use Horner's method to evaluate the polynomial P(z) = sum(coef[k]*z^k, k, 0, order); + std::complex result = 0; + + for (int k = order; k >= 0; --k) + result = result * z + std::complex(coef[k]); + + return result; +} + +void IIRFilter::process(const float* sourceP, float* destP, size_t framesToProcess) +{ + // Compute + // + // y[n] = sum(b[k] * x[n - k], k = 0, M) - sum(a[k] * y[n - k], k = 1, N) + // + // where b[k] are the feedforward coefficients and a[k] are the feedback coefficients of the + // filter. + + // This is a Direct Form I implementation of an IIR Filter. Should we consider doing a + // different implementation such as Transposed Direct Form II? + const double* feedback = m_feedback->Elements(); + const double* feedforward = m_feedforward->Elements(); + + MOZ_ASSERT(feedback); + MOZ_ASSERT(feedforward); + + // Sanity check to see if the feedback coefficients have been scaled appropriately. It must + // be EXACTLY 1! + MOZ_ASSERT(feedback[0] == 1); + + int feedbackLength = m_feedback->Length(); + int feedforwardLength = m_feedforward->Length(); + int minLength = std::min(feedbackLength, feedforwardLength); + + double* xBuffer = m_xBuffer.Elements(); + double* yBuffer = m_yBuffer.Elements(); + + for (size_t n = 0; n < framesToProcess; ++n) { + // To help minimize roundoff, we compute using double's, even though the filter coefficients + // only have single precision values. + double yn = feedforward[0] * sourceP[n]; + + // Run both the feedforward and feedback terms together, when possible. + for (int k = 1; k < minLength; ++k) { + int n = (m_bufferIndex - k) & (kBufferLength - 1); + yn += feedforward[k] * xBuffer[n]; + yn -= feedback[k] * yBuffer[n]; + } + + // Handle any remaining feedforward or feedback terms. + for (int k = minLength; k < feedforwardLength; ++k) + yn += feedforward[k] * xBuffer[(m_bufferIndex - k) & (kBufferLength - 1)]; + + for (int k = minLength; k < feedbackLength; ++k) + yn -= feedback[k] * yBuffer[(m_bufferIndex - k) & (kBufferLength - 1)]; + + // Save the current input and output values in the memory buffers for the next output. + m_xBuffer[m_bufferIndex] = sourceP[n]; + m_yBuffer[m_bufferIndex] = yn; + + m_bufferIndex = (m_bufferIndex + 1) & (kBufferLength - 1); + + // Avoid introducing a stream of subnormals + // TODO: Remove this code when Bug 1157635 is fixed. + if (fabs(yn) >= FLT_MIN) { + destP[n] = yn; + } else { + destP[n] = 0.0; + } + } +} + +void IIRFilter::getFrequencyResponse(int nFrequencies, const float* frequency, float* magResponse, float* phaseResponse) +{ + // Evaluate the z-transform of the filter at the given normalized frequencies from 0 to 1. (One + // corresponds to the Nyquist frequency.) + // + // The z-tranform of the filter is + // + // H(z) = sum(b[k]*z^(-k), k, 0, M) / sum(a[k]*z^(-k), k, 0, N); + // + // The desired frequency response is H(exp(j*omega)), where omega is in [0, 1). + // + // Let P(x) = sum(c[k]*x^k, k, 0, P) be a polynomial of order P. Then each of the sums in H(z) + // is equivalent to evaluating a polynomial at the point 1/z. + + for (int k = 0; k < nFrequencies; ++k) { + // zRecip = 1/z = exp(-j*frequency) + double omega = -M_PI * frequency[k]; + std::complex zRecip = std::complex(cos(omega), sin(omega)); + + std::complex numerator = evaluatePolynomial(m_feedforward->Elements(), zRecip, m_feedforward->Length() - 1); + std::complex denominator = evaluatePolynomial(m_feedback->Elements(), zRecip, m_feedback->Length() - 1); + std::complex response = numerator / denominator; + magResponse[k] = static_cast(abs(response)); + phaseResponse[k] = static_cast(atan2(imag(response), real(response))); + } +} + +bool IIRFilter::buffersAreZero() +{ + double* xBuffer = m_xBuffer.Elements(); + double* yBuffer = m_yBuffer.Elements(); + + for (size_t k = 0; k < m_feedforward->Length(); ++k) { + if (xBuffer[(m_bufferIndex - k) & (kBufferLength - 1)] != 0.0) { + return false; + } + } + + for (size_t k = 0; k < m_feedback->Length(); ++k) { + if (fabs(yBuffer[(m_bufferIndex - k) & (kBufferLength - 1)]) >= FLT_MIN) { + return false; + } + } + + return true; +} + +} // namespace blink diff --git a/dom/media/webaudio/blink/IIRFilter.h b/dom/media/webaudio/blink/IIRFilter.h new file mode 100644 index 0000000000..5656d959a4 --- /dev/null +++ b/dom/media/webaudio/blink/IIRFilter.h @@ -0,0 +1,58 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef IIRFilter_h +#define IIRFilter_h + +typedef nsTArray AudioDoubleArray; + +namespace blink { + +class IIRFilter final { +public: + // The maximum IIR filter order. This also limits the number of feedforward coefficients. The + // maximum number of coefficients is 20 according to the spec. + const static size_t kMaxOrder = 19; + IIRFilter(const AudioDoubleArray* feedforwardCoef, const AudioDoubleArray* feedbackCoef); + ~IIRFilter(); + + void process(const float* sourceP, float* destP, size_t framesToProcess); + + void reset(); + + void getFrequencyResponse(int nFrequencies, + const float* frequency, + float* magResponse, + float* phaseResponse); + + bool buffersAreZero(); + +private: + // Filter memory + // + // For simplicity, we assume |m_xBuffer| and |m_yBuffer| have the same length, and the length is + // a power of two. Since the number of coefficients has a fixed upper length, the size of + // xBuffer and yBuffer is fixed. |m_xBuffer| holds the old input values and |m_yBuffer| holds + // the old output values needed to compute the new output value. + // + // m_yBuffer[m_bufferIndex] holds the most recent output value, say, y[n]. Then + // m_yBuffer[m_bufferIndex - k] is y[n - k]. Similarly for m_xBuffer. + // + // To minimize roundoff, these arrays are double's instead of floats. + AudioDoubleArray m_xBuffer; + AudioDoubleArray m_yBuffer; + + // Index into the xBuffer and yBuffer arrays where the most current x and y values should be + // stored. xBuffer[bufferIndex] corresponds to x[n], the current x input value and + // yBuffer[bufferIndex] is where y[n], the current output value. + int m_bufferIndex; + + // Coefficients of the IIR filter. + const AudioDoubleArray* m_feedback; + const AudioDoubleArray* m_feedforward; +}; + +} // namespace blink + +#endif // IIRFilter_h diff --git a/dom/media/webaudio/blink/ReverbConvolver.cpp b/dom/media/webaudio/blink/ReverbConvolver.cpp index 712ba6420d..e739400aee 100644 --- a/dom/media/webaudio/blink/ReverbConvolver.cpp +++ b/dom/media/webaudio/blink/ReverbConvolver.cpp @@ -31,13 +31,6 @@ using namespace mozilla; -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(WebCore::ReverbConvolver* obj) {} - static void ReleaseCallee(WebCore::ReverbConvolver* obj) {} -}; - namespace WebCore { const int InputBufferSize = 8 * 16384; @@ -158,8 +151,8 @@ ReverbConvolver::ReverbConvolver(const float* impulseResponseData, NS_WARNING("Cannot start convolver thread."); return; } - m_backgroundThread.message_loop()->PostTask( - NewRunnableMethod(this, &ReverbConvolver::backgroundThreadEntry)); + m_backgroundThread.message_loop()->PostTask(NewNonOwningRunnableMethod(this, + &ReverbConvolver::backgroundThreadEntry)); } } diff --git a/dom/media/webaudio/blink/moz.build b/dom/media/webaudio/blink/moz.build index 5af26ad282..c0e1b0f234 100644 --- a/dom/media/webaudio/blink/moz.build +++ b/dom/media/webaudio/blink/moz.build @@ -14,6 +14,7 @@ UNIFIED_SOURCES += [ 'HRTFElevation.cpp', 'HRTFKernel.cpp', 'HRTFPanner.cpp', + 'IIRFilter.cpp', 'PeriodicWave.cpp', 'Reverb.cpp', 'ReverbAccumulationBuffer.cpp', diff --git a/dom/media/webaudio/moz.build b/dom/media/webaudio/moz.build index 1c66d72fcb..71d3496f9b 100644 --- a/dom/media/webaudio/moz.build +++ b/dom/media/webaudio/moz.build @@ -50,6 +50,7 @@ EXPORTS.mozilla.dom += [ 'DelayNode.h', 'DynamicsCompressorNode.h', 'GainNode.h', + 'IIRFilterNode.h', 'MediaElementAudioSourceNode.h', 'MediaStreamAudioDestinationNode.h', 'MediaStreamAudioSourceNode.h', @@ -86,6 +87,7 @@ UNIFIED_SOURCES += [ 'DynamicsCompressorNode.cpp', 'FFTBlock.cpp', 'GainNode.cpp', + 'IIRFilterNode.cpp', 'MediaBufferDecoder.cpp', 'MediaElementAudioSourceNode.cpp', 'MediaStreamAudioDestinationNode.cpp', diff --git a/dom/media/webspeech/synth/nsSpeechTask.cpp b/dom/media/webspeech/synth/nsSpeechTask.cpp index 9e4e821cf0..0e8e916acc 100644 --- a/dom/media/webspeech/synth/nsSpeechTask.cpp +++ b/dom/media/webspeech/synth/nsSpeechTask.cpp @@ -58,9 +58,16 @@ public: switch (event) { case EVENT_FINISHED: { - nsCOMPtr runnable = - NS_NewRunnableMethod(this, &SynthStreamListener::DoNotifyFinished); - aGraph->DispatchToMainThreadAfterStreamStateUpdate(runnable.forget()); + if (!mStarted) { + mStarted = true; + nsCOMPtr startRunnable = + NewRunnableMethod(this, &SynthStreamListener::DoNotifyStarted); + aGraph->DispatchToMainThreadAfterStreamStateUpdate(startRunnable.forget()); + } + + nsCOMPtr endRunnable = + NewRunnableMethod(this, &SynthStreamListener::DoNotifyFinished); + aGraph->DispatchToMainThreadAfterStreamStateUpdate(endRunnable.forget()); } break; case EVENT_REMOVED: @@ -78,7 +85,7 @@ public: if (aBlocked == MediaStreamListener::UNBLOCKED && !mStarted) { mStarted = true; nsCOMPtr event = - NS_NewRunnableMethod(this, &SynthStreamListener::DoNotifyStarted); + NewRunnableMethod(this, &SynthStreamListener::DoNotifyStarted); aGraph->DispatchToMainThreadAfterStreamStateUpdate(event.forget()); } } @@ -705,9 +712,16 @@ nsSpeechTask::CreateAudioChannelAgent() mAudioChannelAgent->InitWithWeakCallback(mUtterance->GetOwner(), static_cast(AudioChannelService::GetDefaultAudioChannel()), this); - float volume = 0.0f; - bool muted = true; - mAudioChannelAgent->NotifyStartedPlaying(&volume, &muted); + + AudioPlaybackConfig config; + nsresult rv = mAudioChannelAgent->NotifyStartedPlaying(&config, + AudioChannelService::AudibleState::eAudible); + if (NS_WARN_IF(NS_FAILED(rv))) { + return; + } + + WindowVolumeChanged(config.mVolume, config.mMuted); + WindowSuspendChanged(config.mSuspend); } void @@ -726,6 +740,19 @@ nsSpeechTask::WindowVolumeChanged(float aVolume, bool aMuted) return NS_OK; } +NS_IMETHODIMP +nsSpeechTask::WindowSuspendChanged(nsSuspendedTypes aSuspend) +{ + if (aSuspend == nsISuspendedTypes::NONE_SUSPENDED && + mUtterance->mPaused) { + Resume(); + } else if (aSuspend != nsISuspendedTypes::NONE_SUSPENDED && + !mUtterance->mPaused) { + Pause(); + } + return NS_OK; +} + NS_IMETHODIMP nsSpeechTask::WindowAudioCaptureChanged(bool aCapture) { diff --git a/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp b/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp index 6566d31be4..b046709e1f 100644 --- a/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp +++ b/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp @@ -659,12 +659,11 @@ nsSynthVoiceRegistry::SpeakUtterance(SpeechSynthesisUtterance& aUtterance, nsCOMPtr topWindow = do_QueryInterface(aUtterance.GetOwner()); if (topWindow) { - float audioVolume = 1.0f; - bool muted = false; - service->GetState(topWindow->GetOuterWindow(), - static_cast(AudioChannelService::GetDefaultAudioChannel()), - &audioVolume, &muted); - volume = muted ? 0.0f : audioVolume * volume; + // TODO : use audio channel agent, open new bug to fix it. + uint32_t channel = static_cast(AudioChannelService::GetDefaultAudioChannel()); + AudioPlaybackConfig config = service->GetMediaConfig(topWindow->GetOuterWindow(), + channel); + volume = config.mMuted ? 0.0f : config.mVolume * volume; } } diff --git a/dom/media/webspeech/synth/pico/nsPicoService.cpp b/dom/media/webspeech/synth/pico/nsPicoService.cpp index c68b4f853c..cd91ac4266 100644 --- a/dom/media/webspeech/synth/pico/nsPicoService.cpp +++ b/dom/media/webspeech/synth/pico/nsPicoService.cpp @@ -469,7 +469,7 @@ nsPicoService::Observe(nsISupports* aSubject, const char* aTopic, DebugOnly rv = NS_NewNamedThread("Pico Worker", getter_AddRefs(mThread)); MOZ_ASSERT(NS_SUCCEEDED(rv)); return mThread->Dispatch( - NS_NewRunnableMethod(this, &nsPicoService::Init), NS_DISPATCH_NORMAL); + NewRunnableMethod(this, &nsPicoService::Init), NS_DISPATCH_NORMAL); } // nsISpeechService @@ -576,7 +576,7 @@ nsPicoService::Init() rv = dirIterator->HasMoreElements(&hasMoreElements); } - NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsPicoService::RegisterVoices)); + NS_DispatchToMainThread(NewRunnableMethod(this, &nsPicoService::RegisterVoices)); } void diff --git a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp index bf39eb0e82..028b5355b2 100644 --- a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp +++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp @@ -268,7 +268,7 @@ speechd_cb(size_t msg_id, size_t client_id, SPDNotificationType state) if (service) { NS_DispatchToMainThread( - NS_NewRunnableMethodWithArgs( + NewRunnableMethod( service, &SpeechDispatcherService::EventNotify, static_cast(msg_id), state)); } @@ -305,7 +305,7 @@ SpeechDispatcherService::Init() getter_AddRefs(mInitThread)); MOZ_ASSERT(NS_SUCCEEDED(rv)); rv = mInitThread->Dispatch( - NS_NewRunnableMethod(this, &SpeechDispatcherService::Setup), NS_DISPATCH_NORMAL); + NewRunnableMethod(this, &SpeechDispatcherService::Setup), NS_DISPATCH_NORMAL); MOZ_ASSERT(NS_SUCCEEDED(rv)); } @@ -406,7 +406,7 @@ SpeechDispatcherService::Setup() } } - NS_DispatchToMainThread(NS_NewRunnableMethod(this, &SpeechDispatcherService::RegisterVoices)); + NS_DispatchToMainThread(NewRunnableMethod(this, &SpeechDispatcherService::RegisterVoices)); //mInitialized = true; } @@ -511,10 +511,10 @@ SpeechDispatcherService::Speak(const nsAString& aText, const nsAString& aUri, // Speech dispatcher does not work well with empty strings. // In that case, don't send empty string to speechd, // and just emulate a speechd start and end event. - NS_DispatchToMainThread(NS_NewRunnableMethodWithArgs( + NS_DispatchToMainThread(NewRunnableMethod( callback, &SpeechDispatcherCallback::OnSpeechEvent, SPD_EVENT_BEGIN)); - NS_DispatchToMainThread(NS_NewRunnableMethodWithArgs( + NS_DispatchToMainThread(NewRunnableMethod( callback, &SpeechDispatcherCallback::OnSpeechEvent, SPD_EVENT_END)); } diff --git a/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp b/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp index 4e34e72008..582ff35510 100644 --- a/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp +++ b/dom/media/webspeech/synth/test/nsFakeSynthServices.cpp @@ -356,7 +356,7 @@ nsFakeSynthServices::Observe(nsISupports* aSubject, const char* aTopic, } if (Preferences::GetBool("media.webspeech.synth.test")) { - NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsFakeSynthServices::Init)); + NS_DispatchToMainThread(NewRunnableMethod(this, &nsFakeSynthServices::Init)); } return NS_OK; diff --git a/dom/notification/Notification.cpp b/dom/notification/Notification.cpp index 995376e09f..c62e6621bd 100644 --- a/dom/notification/Notification.cpp +++ b/dom/notification/Notification.cpp @@ -46,6 +46,7 @@ #include "nsProxyRelease.h" #include "nsServiceManagerUtils.h" #include "nsStructuredCloneContainer.h" +#include "nsThreadUtils.h" #include "nsToolkitCompsCID.h" #include "nsXULAppAPI.h" #include "ServiceWorkerManager.h" @@ -646,9 +647,8 @@ NotificationPermissionRequest::GetRequester(nsIContentPermissionRequester** aReq inline nsresult NotificationPermissionRequest::DispatchResolvePromise() { - nsCOMPtr resolveRunnable = NS_NewRunnableMethod(this, - &NotificationPermissionRequest::ResolvePromise); - return NS_DispatchToMainThread(resolveRunnable); + return NS_DispatchToMainThread(NewRunnableMethod(this, + &NotificationPermissionRequest::ResolvePromise)); } nsresult diff --git a/dom/plugins/base/nsNPAPIPlugin.cpp b/dom/plugins/base/nsNPAPIPlugin.cpp index c50606608d..4e3d86d4b2 100644 --- a/dom/plugins/base/nsNPAPIPlugin.cpp +++ b/dom/plugins/base/nsNPAPIPlugin.cpp @@ -107,6 +107,7 @@ using mozilla::plugins::PluginModuleContentParent; #endif #include "nsIAudioChannelAgent.h" +#include "AudioChannelService.h" using namespace mozilla; using namespace mozilla::plugins::parent; @@ -2441,14 +2442,20 @@ _setvalue(NPP npp, NPPVariable variable, void *result) return NPERR_NO_ERROR; } } else { - float volume = 0.0; - bool muted = true; - rv = agent->NotifyStartedPlaying(&volume, &muted); + + dom::AudioPlaybackConfig config; + rv = agent->NotifyStartedPlaying(&config, + dom::AudioChannelService::AudibleState::eAudible); if (NS_WARN_IF(NS_FAILED(rv))) { return NPERR_NO_ERROR; } - rv = inst->WindowVolumeChanged(volume, muted); + rv = inst->WindowVolumeChanged(config.mVolume, config.mMuted); + if (NS_WARN_IF(NS_FAILED(rv))) { + return NPERR_NO_ERROR; + } + + rv = inst->WindowSuspendChanged(config.mSuspend); if (NS_WARN_IF(NS_FAILED(rv))) { return NPERR_NO_ERROR; } diff --git a/dom/plugins/base/nsNPAPIPluginInstance.cpp b/dom/plugins/base/nsNPAPIPluginInstance.cpp index 4967bc705a..1063a483ef 100644 --- a/dom/plugins/base/nsNPAPIPluginInstance.cpp +++ b/dom/plugins/base/nsNPAPIPluginInstance.cpp @@ -891,7 +891,7 @@ already_AddRefed nsNPAPIPluginInstance::CreateSurfaceText return nullptr; } - nsCOMPtr frameCallback = NS_NewRunnableMethod(this, &nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable); + nsCOMPtr frameCallback = NewRunnableMethod(this, &nsNPAPIPluginInstance::OnSurfaceTextureFrameAvailable); surface->SetFrameAvailableCallback(frameCallback); return surface.forget(); } @@ -1848,6 +1848,15 @@ nsNPAPIPluginInstance::WindowVolumeChanged(float aVolume, bool aMuted) return rv; } +NS_IMETHODIMP +nsNPAPIPluginInstance::WindowSuspendChanged(nsSuspendedTypes aSuspend) +{ + // It doesn't support suspended, so we just do something like mute/unmute. + WindowVolumeChanged(1.0, /* useless */ + aSuspend != nsISuspendedTypes::NONE_SUSPENDED); + return NS_OK; +} + NS_IMETHODIMP nsNPAPIPluginInstance::WindowAudioCaptureChanged(bool aCapture) { diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp index 5de8453a08..a6ed968bde 100644 --- a/dom/plugins/ipc/PluginInstanceChild.cpp +++ b/dom/plugins/ipc/PluginInstanceChild.cpp @@ -112,13 +112,6 @@ static const TCHAR kPluginIgnoreSubclassProperty[] = TEXT("PluginIgnoreSubclassP #include "PluginUtilsOSX.h" #endif // defined(XP_MACOSX) -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(PluginInstanceChild* obj) { } - static void ReleaseCallee(PluginInstanceChild* obj) { } -}; - /** * We can't use gfxPlatform::CreateDrawTargetForSurface() because calling * gfxPlatform::GetPlatform() instantiates the prefs service, and that's not @@ -3299,11 +3292,8 @@ PluginInstanceChild::RecvAsyncSetWindow(const gfxSurfaceType& aSurfaceType, // RPC call, and both Flash and Java don't expect to receive setwindow calls // at arbitrary times. mCurrentAsyncSetWindowTask = - NewRunnableMethod - (this, &PluginInstanceChild::DoAsyncSetWindow, - aSurfaceType, aWindow, true); + NewNonOwningCancelableRunnableMethod + (this, &PluginInstanceChild::DoAsyncSetWindow, aSurfaceType, aWindow, true); RefPtr addrefedTask = mCurrentAsyncSetWindowTask; MessageLoop::current()->PostTask(addrefedTask.forget()); @@ -4223,7 +4213,7 @@ PluginInstanceChild::AsyncShowPluginFrame(void) } mCurrentInvalidateTask = - NewRunnableMethod(this, &PluginInstanceChild::InvalidateRectDelayed); + NewNonOwningCancelableRunnableMethod(this, &PluginInstanceChild::InvalidateRectDelayed); RefPtr addrefedTask = mCurrentInvalidateTask; MessageLoop::current()->PostTask(addrefedTask.forget()); } diff --git a/dom/plugins/ipc/PluginInstanceParent.cpp b/dom/plugins/ipc/PluginInstanceParent.cpp index 1aa5abdc54..ddfcd31cb9 100644 --- a/dom/plugins/ipc/PluginInstanceParent.cpp +++ b/dom/plugins/ipc/PluginInstanceParent.cpp @@ -118,13 +118,6 @@ PluginInstanceParent::LookupPluginInstanceByID(uintptr_t aId) } #endif -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(PluginInstanceParent* obj) { } - static void ReleaseCallee(PluginInstanceParent* obj) { } -}; - PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent, NPP npp, const nsCString& aMimeType, @@ -1223,7 +1216,7 @@ PluginInstanceParent::ScheduleScrollCapture(int aTimeout) } CAPTURE_LOG("delayed scroll capture requested."); mCaptureRefreshTask = - NewRunnableMethod(this, &PluginInstanceParent::ScheduledUpdateScrollCaptureCallback); + NewNonOwningCancelableRunnableMethod(this, &PluginInstanceParent::ScheduledUpdateScrollCaptureCallback); RefPtr addrefedTask = mCaptureRefreshTask; MessageLoop::current()->PostDelayedTask(addrefedTask.forget(), kScrollCaptureDelayMs); diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp index b12581b628..d554dad9c9 100644 --- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -104,13 +104,6 @@ static GetWindowInfoPtr sGetWindowInfoPtrStub = nullptr; static HWND sBrowserHwnd = nullptr; #endif -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(PluginModuleChild* obj) { } - static void ReleaseCallee(PluginModuleChild* obj) { } -}; - /* static */ PluginModuleChild* PluginModuleChild::CreateForContentProcess(mozilla::ipc::Transport* aTransport, diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index d2db50ab20..81f04a6d96 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -96,14 +96,6 @@ static const char kHangUIMinDisplayPref[] = "dom.ipc.plugins.hangUIMinDisplaySec #define CHILD_TIMEOUT_PREF kChildTimeoutPref #endif -template<> -struct RunnableMethodTraits -{ - typedef mozilla::plugins::PluginModuleParent Class; - static void RetainCallee(Class* obj) { } - static void ReleaseCallee(Class* obj) { } -}; - bool mozilla::plugins::SetupBridge(uint32_t aPluginId, dom::ContentParent* aContentParent, diff --git a/dom/plugins/ipc/PluginProcessParent.cpp b/dom/plugins/ipc/PluginProcessParent.cpp index 955b030e40..6842cd85ec 100644 --- a/dom/plugins/ipc/PluginProcessParent.cpp +++ b/dom/plugins/ipc/PluginProcessParent.cpp @@ -27,13 +27,6 @@ using mozilla::plugins::LaunchCompleteTask; using mozilla::plugins::PluginProcessParent; using base::ProcessArchitecture; -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(PluginProcessParent* obj) { } - static void ReleaseCallee(PluginProcessParent* obj) { } -}; - PluginProcessParent::PluginProcessParent(const std::string& aPluginFilePath) : GeckoChildProcessHost(GeckoProcessType_Plugin), mPluginFilePath(aPluginFilePath), @@ -194,7 +187,7 @@ PluginProcessParent::Delete() return; } - ioLoop->PostTask(NewRunnableMethod(this, &PluginProcessParent::Delete)); + ioLoop->PostTask(NewNonOwningRunnableMethod(this, &PluginProcessParent::Delete)); } void diff --git a/dom/presentation/PresentationAvailability.cpp b/dom/presentation/PresentationAvailability.cpp index ed2303b1cd..058ef1ed7c 100644 --- a/dom/presentation/PresentationAvailability.cpp +++ b/dom/presentation/PresentationAvailability.cpp @@ -107,11 +107,10 @@ PresentationAvailability::Value() const NS_IMETHODIMP PresentationAvailability::NotifyAvailableChange(bool aIsAvailable) { - nsCOMPtr runnable = - NS_NewRunnableMethodWithArg(this, - &PresentationAvailability::UpdateAvailabilityAndDispatchEvent, - aIsAvailable); - return NS_DispatchToCurrentThread(runnable); + return NS_DispatchToCurrentThread(NewRunnableMethod + (this, + &PresentationAvailability::UpdateAvailabilityAndDispatchEvent, + aIsAvailable)); } void diff --git a/dom/presentation/PresentationDeviceManager.cpp b/dom/presentation/PresentationDeviceManager.cpp index 474c83b73f..ce8c6fde9c 100644 --- a/dom/presentation/PresentationDeviceManager.cpp +++ b/dom/presentation/PresentationDeviceManager.cpp @@ -155,7 +155,7 @@ PresentationDeviceManager::GetAvailableDevices(nsIArray** aRetVal) // Bug 1194049: some providers may discontinue discovery after timeout. // Call |ForceDiscovery()| here to make sure device lists are updated. NS_DispatchToMainThread( - NS_NewRunnableMethod(this, &PresentationDeviceManager::ForceDiscovery)); + NewRunnableMethod(this, &PresentationDeviceManager::ForceDiscovery)); nsCOMPtr devices = do_CreateInstance(NS_ARRAY_CONTRACTID); for (uint32_t i = 0; i < mDevices.Length(); ++i) { diff --git a/dom/presentation/PresentationSessionInfo.cpp b/dom/presentation/PresentationSessionInfo.cpp index 1ed4125a5e..d727be47e5 100644 --- a/dom/presentation/PresentationSessionInfo.cpp +++ b/dom/presentation/PresentationSessionInfo.cpp @@ -117,9 +117,9 @@ PresentationNetworkHelper::OnGetWifiIPAddress(const nsACString& aIPAddress) MOZ_ASSERT(mFunc); NS_DispatchToMainThread( - NS_NewRunnableMethodWithArg(mInfo, - mFunc, - aIPAddress)); + NewRunnableMethod(mInfo, + mFunc, + aIPAddress)); return NS_OK; } @@ -513,7 +513,7 @@ PresentationControllingInfo::GetAddress() // To make consistent code sequence, following function call is dispatched // into main thread instead of calling it directly. NS_DispatchToMainThread( - NS_NewRunnableMethodWithArg( + NewRunnableMethod( this, &PresentationControllingInfo::OnGetAddress, NS_ConvertUTF16toUTF8(ip))); @@ -534,7 +534,7 @@ PresentationControllingInfo::GetAddress() // TODO Get host IP via other platforms. NS_DispatchToMainThread( - NS_NewRunnableMethodWithArg( + NewRunnableMethod( this, &PresentationControllingInfo::OnGetAddress, EmptyCString())); diff --git a/dom/presentation/provider/MulticastDNSDeviceProvider.cpp b/dom/presentation/provider/MulticastDNSDeviceProvider.cpp index 1fec9d5af4..f7aba97cc1 100644 --- a/dom/presentation/provider/MulticastDNSDeviceProvider.cpp +++ b/dom/presentation/provider/MulticastDNSDeviceProvider.cpp @@ -768,7 +768,7 @@ MulticastDNSDeviceProvider::OnRegistrationFailed(nsIDNSServiceInfo* aServiceInfo if (aErrorCode == nsIDNSRegistrationListener::ERROR_SERVICE_NOT_RUNNING) { return NS_DispatchToMainThread( - NS_NewRunnableMethod(this, &MulticastDNSDeviceProvider::RegisterService)); + NewRunnableMethod(this, &MulticastDNSDeviceProvider::RegisterService)); } return NS_OK; diff --git a/dom/quota/QuotaManager.cpp b/dom/quota/QuotaManager.cpp index 86ad06923b..3ebbf52025 100644 --- a/dom/quota/QuotaManager.cpp +++ b/dom/quota/QuotaManager.cpp @@ -3860,7 +3860,7 @@ QuotaManager::Observe(nsISupports* aSubject, // Give clients a chance to cleanup IO thread only objects. nsCOMPtr runnable = - NS_NewRunnableMethod(this, &QuotaManager::ReleaseIOThreadObjects); + NewRunnableMethod(this, &QuotaManager::ReleaseIOThreadObjects); if (!runnable) { NS_WARNING("Failed to create runnable!"); } diff --git a/dom/storage/DOMStorage.cpp b/dom/storage/DOMStorage.cpp index 064b483b9d..1019a2b675 100644 --- a/dom/storage/DOMStorage.cpp +++ b/dom/storage/DOMStorage.cpp @@ -296,7 +296,7 @@ DOMStorage::CanAccess(nsIPrincipal* aPrincipal) } void -DOMStorage::GetSupportedNames(unsigned, nsTArray& aKeys) +DOMStorage::GetSupportedNames(nsTArray& aKeys) { if (!CanUseStorage(nullptr, this)) { // return just an empty array diff --git a/dom/storage/DOMStorage.h b/dom/storage/DOMStorage.h index 711c7fb88c..effac81ea2 100644 --- a/dom/storage/DOMStorage.h +++ b/dom/storage/DOMStorage.h @@ -82,12 +82,7 @@ public: void GetItem(const nsAString& aKey, nsAString& aResult, ErrorResult& aRv); - bool NameIsEnumerable(const nsAString& aName) const - { - return true; - } - - void GetSupportedNames(unsigned, nsTArray& aKeys); + void GetSupportedNames(nsTArray& aKeys); void NamedGetter(const nsAString& aKey, bool& aFound, nsAString& aResult, ErrorResult& aRv) diff --git a/dom/storage/DOMStorageCache.cpp b/dom/storage/DOMStorageCache.cpp index fa39a7e129..746533ed57 100644 --- a/dom/storage/DOMStorageCache.cpp +++ b/dom/storage/DOMStorageCache.cpp @@ -110,8 +110,8 @@ DOMStorageCache::Release(void) } RefPtr > event = - NS_NewNonOwningRunnableMethod(static_cast(this), - &DOMStorageCacheBridge::Release); + NewNonOwningRunnableMethod(static_cast(this), + &DOMStorageCacheBridge::Release); nsresult rv = NS_DispatchToMainThread(event); if (NS_FAILED(rv)) { @@ -264,10 +264,7 @@ DOMStorageCache::KeepAlive() if (!NS_IsMainThread()) { // Timer and the holder must be initialized on the main thread. - RefPtr > event = - NS_NewRunnableMethod(this, &DOMStorageCache::KeepAlive); - - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(NewRunnableMethod(this, &DOMStorageCache::KeepAlive)); return; } @@ -547,9 +544,16 @@ DOMStorageCache::Clear(const DOMStorage* aStorage) void DOMStorageCache::CloneFrom(const DOMStorageCache* aThat) { - mLoaded = aThat->mLoaded; + // This will never be called on anything else than SessionStorage. + // This means mData will never be touched on any other thread than + // the main thread and it never went through the loading process. + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(!mPersistent); + MOZ_ASSERT(!(bool)aThat->mLoaded); + + mLoaded = false; mInitialized = aThat->mInitialized; - mPersistent = aThat->mPersistent; + mPersistent = false; mSessionOnlyDataSetActive = aThat->mSessionOnlyDataSetActive; for (uint32_t i = 0; i < kDataSetCount; ++i) { diff --git a/dom/storage/DOMStorageCache.h b/dom/storage/DOMStorageCache.h index 1b24f41b36..171964f282 100644 --- a/dom/storage/DOMStorageCache.h +++ b/dom/storage/DOMStorageCache.h @@ -15,6 +15,7 @@ #include "nsHashKeys.h" #include "mozilla/Monitor.h" #include "mozilla/Telemetry.h" +#include "mozilla/Atomics.h" #include "nsAutoPtr.h" namespace mozilla { @@ -203,8 +204,9 @@ private: // Flag that is initially false. When the cache is about to work with // the database (i.e. it is persistent) this flags is set to true after // all keys and coresponding values are loaded from the database. - // This flag never goes from true back to false. - bool mLoaded; + // This flag never goes from true back to false. Since this flag is + // critical for mData hashtable synchronization, it's made atomic. + Atomic mLoaded; // Result of load from the database. Valid after mLoaded flag has been set. nsresult mLoadResult; diff --git a/dom/storage/DOMStorageDBThread.cpp b/dom/storage/DOMStorageDBThread.cpp index 9d7eda6c48..1e0cf4eb7d 100644 --- a/dom/storage/DOMStorageDBThread.cpp +++ b/dom/storage/DOMStorageDBThread.cpp @@ -727,7 +727,7 @@ DOMStorageDBThread::NotifyFlushCompletion() #ifdef DOM_STORAGE_TESTS if (!NS_IsMainThread()) { RefPtr > event = - NS_NewNonOwningRunnableMethod(this, &DOMStorageDBThread::NotifyFlushCompletion); + NewNonOwningRunnableMethod(this, &DOMStorageDBThread::NotifyFlushCompletion); NS_DispatchToMainThread(event); return; } diff --git a/dom/svg/SVGFEImageElement.cpp b/dom/svg/SVGFEImageElement.cpp index e085f00895..b2ebfbe0fd 100644 --- a/dom/svg/SVGFEImageElement.cpp +++ b/dom/svg/SVGFEImageElement.cpp @@ -155,7 +155,7 @@ SVGFEImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, ClearBrokenState(); RemoveStatesSilently(NS_EVENT_STATE_BROKEN); nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &SVGFEImageElement::MaybeLoadSVGImage)); + NewRunnableMethod(this, &SVGFEImageElement::MaybeLoadSVGImage)); } return rv; diff --git a/dom/svg/SVGImageElement.cpp b/dom/svg/SVGImageElement.cpp index 144e375f2d..6d5af4128e 100644 --- a/dom/svg/SVGImageElement.cpp +++ b/dom/svg/SVGImageElement.cpp @@ -183,7 +183,7 @@ SVGImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, ClearBrokenState(); RemoveStatesSilently(NS_EVENT_STATE_BROKEN); nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &SVGImageElement::MaybeLoadSVGImage)); + NewRunnableMethod(this, &SVGImageElement::MaybeLoadSVGImage)); } return rv; diff --git a/dom/svg/SVGStyleElement.cpp b/dom/svg/SVGStyleElement.cpp index 33437f7ba7..22fb204dff 100644 --- a/dom/svg/SVGStyleElement.cpp +++ b/dom/svg/SVGStyleElement.cpp @@ -78,7 +78,7 @@ SVGStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, NS_ENSURE_SUCCESS(rv, rv); void (SVGStyleElement::*update)() = &SVGStyleElement::UpdateStyleSheetInternal; - nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update)); + nsContentUtils::AddScriptRunner(NewRunnableMethod(this, update)); return rv; } diff --git a/dom/telephony/Telephony.cpp b/dom/telephony/Telephony.cpp index d973acdb6b..2c1a1f1bca 100644 --- a/dom/telephony/Telephony.cpp +++ b/dom/telephony/Telephony.cpp @@ -560,9 +560,9 @@ Telephony::HandleAudioAgentState() } } else if (!activeCall.IsNull() && !mIsAudioStartPlaying) { mIsAudioStartPlaying = true; - float volume; - bool muted; - rv = mAudioAgent->NotifyStartedPlaying(&volume, &muted); + AudioPlaybackConfig config; + rv = mAudioAgent->NotifyStartedPlaying(&config, + AudioChannelService::AudibleState::eAudible); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -576,9 +576,12 @@ Telephony::HandleAudioAgentState() // because the modem have not changed the call state yet. It causes that // the telephony can't be resumed. Therefore, we don't mute the telephony // at the beginning. - volume = 1.0; - muted = false; - rv = WindowVolumeChanged(volume, muted); + rv = WindowVolumeChanged(1.0, false); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + rv = WindowSuspendChanged(config.mSuspend); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -710,6 +713,13 @@ Telephony::WindowVolumeChanged(float aVolume, bool aMuted) return NS_OK; } +NS_IMETHODIMP +Telephony::WindowSuspendChanged(nsSuspendedTypes aSuspend) +{ + // Not support yet. + return NS_OK; +} + NS_IMETHODIMP Telephony::WindowAudioCaptureChanged(bool aCapture) { diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 8ee3c638e1..0caa9ca557 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -697,6 +697,8 @@ var interfaceNamesInGlobalScope = "IDBTransaction", // IMPORTANT: Do not change this list without review from a DOM peer! "IDBVersionChangeEvent", +// IMPORTANT: Do not change this list without review from a DOM peer! + "IIRFilterNode", // IMPORTANT: Do not change this list without review from a DOM peer! "Image", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/tv/TVSource.cpp b/dom/tv/TVSource.cpp index 0b4e4fb691..b76f4cde8e 100644 --- a/dom/tv/TVSource.cpp +++ b/dom/tv/TVSource.cpp @@ -372,9 +372,9 @@ TVSource::DispatchCurrentChannelChangedEvent(TVChannel* aChannel) NS_LITERAL_STRING("currentchannelchanged"), init); nsCOMPtr runnable = - NS_NewRunnableMethodWithArg>(this, - &TVSource::DispatchTVEvent, - event); + NewRunnableMethod>(this, + &TVSource::DispatchTVEvent, + event); return NS_DispatchToCurrentThread(runnable); } @@ -390,9 +390,9 @@ TVSource::DispatchScanningStateChangedEvent(TVScanningState aState, NS_LITERAL_STRING("scanningstatechanged"), init); nsCOMPtr runnable = - NS_NewRunnableMethodWithArg>(this, - &TVSource::DispatchTVEvent, - event); + NewRunnableMethod>(this, + &TVSource::DispatchTVEvent, + event); return NS_DispatchToCurrentThread(runnable); } @@ -406,9 +406,9 @@ TVSource::DispatchEITBroadcastedEvent(const Sequence>& NS_LITERAL_STRING("eitbroadcasted"), init); nsCOMPtr runnable = - NS_NewRunnableMethodWithArg>(this, - &TVSource::DispatchTVEvent, - event); + NewRunnableMethod>(this, + &TVSource::DispatchTVEvent, + event); return NS_DispatchToCurrentThread(runnable); } diff --git a/dom/tv/TVTuner.cpp b/dom/tv/TVTuner.cpp index 5ea452eddb..963389499d 100644 --- a/dom/tv/TVTuner.cpp +++ b/dom/tv/TVTuner.cpp @@ -315,9 +315,9 @@ TVTuner::DispatchCurrentSourceChangedEvent(TVSource* aSource) NS_LITERAL_STRING("currentsourcechanged"), init); nsCOMPtr runnable = - NS_NewRunnableMethodWithArg>(this, - &TVTuner::DispatchTVEvent, - event); + NewRunnableMethod>(this, + &TVTuner::DispatchTVEvent, + event); return NS_DispatchToCurrentThread(runnable); } diff --git a/dom/webidl/AudioContext.webidl b/dom/webidl/AudioContext.webidl index 654f04ee46..93056ba593 100644 --- a/dom/webidl/AudioContext.webidl +++ b/dom/webidl/AudioContext.webidl @@ -75,6 +75,8 @@ interface AudioContext : EventTarget { [NewObject, Throws] BiquadFilterNode createBiquadFilter(); [NewObject, Throws] + IIRFilterNode createIIRFilter(sequence feedforward, sequence feedback); + [NewObject, Throws] WaveShaperNode createWaveShaper(); [NewObject, Throws] PannerNode createPanner(); diff --git a/dom/webidl/HTMLAllCollection.webidl b/dom/webidl/HTMLAllCollection.webidl index 433ad2aa52..b352138888 100644 --- a/dom/webidl/HTMLAllCollection.webidl +++ b/dom/webidl/HTMLAllCollection.webidl @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ /* Emulates undefined through Codegen.py. */ +[LegacyUnenumerableNamedProperties] interface HTMLAllCollection { readonly attribute unsigned long length; getter Node? (unsigned long index); diff --git a/dom/webidl/HTMLCollection.webidl b/dom/webidl/HTMLCollection.webidl index 178986a86d..f7f020c0ff 100644 --- a/dom/webidl/HTMLCollection.webidl +++ b/dom/webidl/HTMLCollection.webidl @@ -10,6 +10,7 @@ * liability, trademark and document use rules apply. */ +[LegacyUnenumerableNamedProperties] interface HTMLCollection { readonly attribute unsigned long length; getter Element? item(unsigned long index); diff --git a/dom/webidl/HTMLFormElement.webidl b/dom/webidl/HTMLFormElement.webidl index 1581d19fd4..d7964689f3 100644 --- a/dom/webidl/HTMLFormElement.webidl +++ b/dom/webidl/HTMLFormElement.webidl @@ -11,6 +11,8 @@ * and create derivative works of this document. */ +// Should be LegacyUnenumerableNamedProperties. See +// https://bugzilla.mozilla.org/show_bug.cgi?id=1270369 [OverrideBuiltins] interface HTMLFormElement : HTMLElement { [Pure, SetterThrows] diff --git a/dom/webidl/HTMLMediaElement.webidl b/dom/webidl/HTMLMediaElement.webidl index 0385c6a01a..92ce2d6365 100644 --- a/dom/webidl/HTMLMediaElement.webidl +++ b/dom/webidl/HTMLMediaElement.webidl @@ -177,4 +177,6 @@ partial interface HTMLMediaElement { readonly attribute double computedVolume; [Pref="media.useAudioChannelService.testing"] readonly attribute boolean computedMuted; + [Pref="media.useAudioChannelService.testing"] + readonly attribute unsigned long computedSuspended; }; diff --git a/dom/webidl/IIRFilterNode.webidl b/dom/webidl/IIRFilterNode.webidl new file mode 100644 index 0000000000..4442e28ef1 --- /dev/null +++ b/dom/webidl/IIRFilterNode.webidl @@ -0,0 +1,17 @@ +/* -*- 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 https://www.w3.org/TR/webaudio + * + * Copyright © 2016 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C + * liability, trademark and document use rules apply. + */ + +interface IIRFilterNode : AudioNode { + void getFrequencyResponse(Float32Array frequencyHz, Float32Array magResponse, Float32Array phaseResponse); +}; + +// Mozilla extension +IIRFilterNode implements AudioNodePassThrough; diff --git a/dom/webidl/Location.webidl b/dom/webidl/Location.webidl index 3d6b39ff9f..fa017156a9 100644 --- a/dom/webidl/Location.webidl +++ b/dom/webidl/Location.webidl @@ -11,7 +11,7 @@ * and create derivative works of this document. */ -[Unforgeable] +[Unforgeable, NonOrdinaryGetPrototypeOf] interface Location { // Bug 824857: no support for stringifier attributes yet. // stringifier attribute USVString href; diff --git a/dom/webidl/MimeTypeArray.webidl b/dom/webidl/MimeTypeArray.webidl index 0187f8413f..21bfc6dc0d 100644 --- a/dom/webidl/MimeTypeArray.webidl +++ b/dom/webidl/MimeTypeArray.webidl @@ -4,6 +4,9 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// [LegacyUnenumerableNamedProperties] +// Named properties enumerable for now; see +// https://bugzilla.mozilla.org/show_bug.cgi?id=1270364 interface MimeTypeArray { readonly attribute unsigned long length; diff --git a/dom/webidl/NamedNodeMap.webidl b/dom/webidl/NamedNodeMap.webidl index 82a8730195..41fbfcbb43 100644 --- a/dom/webidl/NamedNodeMap.webidl +++ b/dom/webidl/NamedNodeMap.webidl @@ -3,6 +3,7 @@ * 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/. */ +[LegacyUnenumerableNamedProperties] interface NamedNodeMap { getter Attr? getNamedItem(DOMString name); [Throws, BinaryName="setNamedItemNS"] diff --git a/dom/webidl/Plugin.webidl b/dom/webidl/Plugin.webidl index 0af7c4d6af..018d65a05c 100644 --- a/dom/webidl/Plugin.webidl +++ b/dom/webidl/Plugin.webidl @@ -4,6 +4,9 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// [LegacyUnenumerableNamedProperties] +// Named properties enumerable for now; see +// https://bugzilla.mozilla.org/show_bug.cgi?id=1270366 interface Plugin { readonly attribute DOMString description; readonly attribute DOMString filename; diff --git a/dom/webidl/PluginArray.webidl b/dom/webidl/PluginArray.webidl index 27bd318df7..617bb1f9a6 100644 --- a/dom/webidl/PluginArray.webidl +++ b/dom/webidl/PluginArray.webidl @@ -4,6 +4,9 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ +// [LegacyUnenumerableNamedProperties] +// Named properties enumerable for now; see +// https://bugzilla.mozilla.org/show_bug.cgi?id=1270366 interface PluginArray { readonly attribute unsigned long length; diff --git a/dom/webidl/Window.webidl b/dom/webidl/Window.webidl index 9e89f951c9..d591787a93 100644 --- a/dom/webidl/Window.webidl +++ b/dom/webidl/Window.webidl @@ -24,7 +24,7 @@ interface nsIDOMCrypto; typedef any Transferable; // http://www.whatwg.org/specs/web-apps/current-work/ -[PrimaryGlobal, NeedResolve] +[PrimaryGlobal, LegacyUnenumerableNamedProperties, NeedResolve] /*sealed*/ interface Window : EventTarget { // the current browsing context [Unforgeable, Constant, StoreInSlot, diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index aaa50aa9a5..194a305448 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -266,6 +266,7 @@ WEBIDL_FILES = [ 'IDBRequest.webidl', 'IDBTransaction.webidl', 'IDBVersionChangeEvent.webidl', + 'IIRFilterNode.webidl', 'ImageBitmap.webidl', 'ImageBitmapRenderingContext.webidl', 'ImageCapture.webidl', diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index f7f9a42606..bfa5cbed50 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -716,11 +716,9 @@ private: if (aStatus >= Terminating && !mCanceled) { mCanceled = true; - nsCOMPtr runnable = - NS_NewRunnableMethod(this, - &ScriptLoaderRunnable::CancelMainThreadWithBindingAborted); - NS_ASSERTION(runnable, "This should never fail!"); - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); + MOZ_ALWAYS_SUCCEEDS( + NS_DispatchToMainThread(NewRunnableMethod(this, + &ScriptLoaderRunnable::CancelMainThreadWithBindingAborted))); } return true; diff --git a/dom/workers/ServiceWorkerEvents.cpp b/dom/workers/ServiceWorkerEvents.cpp index 2be5e3df1d..94973d4770 100644 --- a/dom/workers/ServiceWorkerEvents.cpp +++ b/dom/workers/ServiceWorkerEvents.cpp @@ -849,9 +849,8 @@ public: mColumn = column; } - nsCOMPtr runnable = - NS_NewRunnableMethod(this, &WaitUntilHandler::ReportOnMainThread); - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable.forget())); + MOZ_ALWAYS_SUCCEEDS( + NS_DispatchToMainThread(NewRunnableMethod(this, &WaitUntilHandler::ReportOnMainThread))); } void diff --git a/dom/workers/ServiceWorkerJob.cpp b/dom/workers/ServiceWorkerJob.cpp index c634fb9154..73716fab61 100644 --- a/dom/workers/ServiceWorkerJob.cpp +++ b/dom/workers/ServiceWorkerJob.cpp @@ -95,7 +95,7 @@ ServiceWorkerJob::Start(Callback* aFinalCallback) mState = State::Started; nsCOMPtr runnable = - NS_NewRunnableMethod(this, &ServiceWorkerJob::AsyncExecute); + NewRunnableMethod(this, &ServiceWorkerJob::AsyncExecute); // We may have to wait for the PBackground actor to be initialized // before proceeding. We should always be able to get a ServiceWorkerManager, diff --git a/dom/workers/ServiceWorkerPrivate.cpp b/dom/workers/ServiceWorkerPrivate.cpp index 4866ff1c65..5ea443cda3 100644 --- a/dom/workers/ServiceWorkerPrivate.cpp +++ b/dom/workers/ServiceWorkerPrivate.cpp @@ -616,7 +616,7 @@ public: return; } nsCOMPtr runnable = - NS_NewRunnableMethodWithArg(this, + NewRunnableMethod(this, &PushErrorReporter::ReportOnMainThread, aReason); MOZ_ALWAYS_SUCCEEDS( NS_DispatchToMainThread(runnable.forget())); @@ -1451,7 +1451,7 @@ ServiceWorkerPrivate::SendFetchEvent(nsIInterceptedChannel* aChannel, // if the ServiceWorker script fails to load for some reason, just resume // the original channel. nsCOMPtr failRunnable = - NS_NewRunnableMethod(aChannel, &nsIInterceptedChannel::ResetInterception); + NewRunnableMethod(aChannel, &nsIInterceptedChannel::ResetInterception); nsresult rv = SpawnWorkerIfNeeded(FetchEvent, failRunnable, aLoadGroup); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/workers/ServiceWorkerRegistrar.cpp b/dom/workers/ServiceWorkerRegistrar.cpp index a20d2f51d1..d242e06502 100644 --- a/dom/workers/ServiceWorkerRegistrar.cpp +++ b/dom/workers/ServiceWorkerRegistrar.cpp @@ -540,7 +540,7 @@ public: service->SaveData(); RefPtr runnable = - NS_NewRunnableMethod(service, &ServiceWorkerRegistrar::DataSaved); + NewRunnableMethod(service, &ServiceWorkerRegistrar::DataSaved); nsresult rv = mThread->Dispatch(runnable, NS_DISPATCH_NORMAL); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -614,7 +614,7 @@ ServiceWorkerRegistrar::MaybeScheduleShutdownCompleted() } RefPtr runnable = - NS_NewRunnableMethod(this, &ServiceWorkerRegistrar::ShutdownCompleted); + NewRunnableMethod(this, &ServiceWorkerRegistrar::ShutdownCompleted); nsresult rv = NS_DispatchToMainThread(runnable); if (NS_WARN_IF(NS_FAILED(rv))) { return; @@ -744,7 +744,7 @@ ServiceWorkerRegistrar::ProfileStarted() MOZ_ASSERT(target, "Must have stream transport service"); nsCOMPtr runnable = - NS_NewRunnableMethod(this, &ServiceWorkerRegistrar::LoadData); + NewRunnableMethod(this, &ServiceWorkerRegistrar::LoadData); rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) { NS_WARNING("Failed to dispatch the LoadDataRunnable."); diff --git a/dom/workers/ServiceWorkerRegistrationInfo.cpp b/dom/workers/ServiceWorkerRegistrationInfo.cpp index cebafca6c6..2dd5432c2d 100644 --- a/dom/workers/ServiceWorkerRegistrationInfo.cpp +++ b/dom/workers/ServiceWorkerRegistrationInfo.cpp @@ -201,10 +201,9 @@ ServiceWorkerRegistrationInfo::GetServiceWorkerInfoById(uint64_t aId) void ServiceWorkerRegistrationInfo::TryToActivateAsync() { - nsCOMPtr r = - NS_NewRunnableMethod(this, - &ServiceWorkerRegistrationInfo::TryToActivate); - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); + MOZ_ALWAYS_SUCCEEDS( + NS_DispatchToMainThread(NewRunnableMethod(this, + &ServiceWorkerRegistrationInfo::TryToActivate))); } /* @@ -236,14 +235,14 @@ ServiceWorkerRegistrationInfo::Activate() // "Queue a task to fire a simple event named controllerchange..." nsCOMPtr controllerChangeRunnable = - NS_NewRunnableMethodWithArg>( + NewRunnableMethod>( swm, &ServiceWorkerManager::FireControllerChange, this); NS_DispatchToMainThread(controllerChangeRunnable); nsCOMPtr failRunnable = - NS_NewRunnableMethodWithArg(this, - &ServiceWorkerRegistrationInfo::FinishActivate, - false /* success */); + NewRunnableMethod(this, + &ServiceWorkerRegistrationInfo::FinishActivate, + false /* success */); nsMainThreadPtrHandle handle( new nsMainThreadPtrHolder(this)); diff --git a/dom/workers/ServiceWorkerUpdateJob.cpp b/dom/workers/ServiceWorkerUpdateJob.cpp index d1f20a3452..337c3dca36 100644 --- a/dom/workers/ServiceWorkerUpdateJob.cpp +++ b/dom/workers/ServiceWorkerUpdateJob.cpp @@ -489,7 +489,7 @@ ServiceWorkerUpdateJob::Install() // fire the updatefound event nsCOMPtr upr = - NS_NewRunnableMethodWithArg>( + NewRunnableMethod>( swm, &ServiceWorkerManager::FireUpdateFoundOnServiceWorkerRegistrations, mRegistration); @@ -497,7 +497,7 @@ ServiceWorkerUpdateJob::Install() // Call ContinueAfterInstallEvent(false) on main thread if the SW // script fails to load. - nsCOMPtr failRunnable = NS_NewRunnableMethodWithArgs + nsCOMPtr failRunnable = NewRunnableMethod (this, &ServiceWorkerUpdateJob::ContinueAfterInstallEvent, false); nsMainThreadPtrHandle handle( diff --git a/dom/xbl/nsBindingManager.cpp b/dom/xbl/nsBindingManager.cpp index 9e2bb52771..b3ee9b121a 100644 --- a/dom/xbl/nsBindingManager.cpp +++ b/dom/xbl/nsBindingManager.cpp @@ -347,7 +347,7 @@ void nsBindingManager::PostProcessAttachedQueueEvent() { mProcessAttachedQueueEvent = - NS_NewRunnableMethod(this, &nsBindingManager::DoProcessAttachedQueue); + NewRunnableMethod(this, &nsBindingManager::DoProcessAttachedQueue); nsresult rv = NS_DispatchToCurrentThread(mProcessAttachedQueueEvent); if (NS_SUCCEEDED(rv) && mDocument) { mDocument->BlockOnload(); diff --git a/dom/xml/XMLStylesheetProcessingInstruction.cpp b/dom/xml/XMLStylesheetProcessingInstruction.cpp index cc5734c6a4..3d94e179b4 100644 --- a/dom/xml/XMLStylesheetProcessingInstruction.cpp +++ b/dom/xml/XMLStylesheetProcessingInstruction.cpp @@ -63,7 +63,7 @@ XMLStylesheetProcessingInstruction::BindToTree(nsIDocument* aDocument, void (XMLStylesheetProcessingInstruction::*update)() = &XMLStylesheetProcessingInstruction::UpdateStyleSheetInternal; - nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, update)); + nsContentUtils::AddScriptRunner(NewRunnableMethod(this, update)); return rv; } diff --git a/dom/xml/nsXMLContentSink.cpp b/dom/xml/nsXMLContentSink.cpp index 811ea755a6..9935b9ba5d 100644 --- a/dom/xml/nsXMLContentSink.cpp +++ b/dom/xml/nsXMLContentSink.cpp @@ -1558,7 +1558,7 @@ nsXMLContentSink::ContinueInterruptedParsingIfEnabled() void nsXMLContentSink::ContinueInterruptedParsingAsync() { - nsCOMPtr ev = NS_NewRunnableMethod(this, + nsCOMPtr ev = NewRunnableMethod(this, &nsXMLContentSink::ContinueInterruptedParsingIfEnabled); NS_DispatchToCurrentThread(ev); diff --git a/dom/xml/nsXMLPrettyPrinter.cpp b/dom/xml/nsXMLPrettyPrinter.cpp index 6a4ba8c7d5..939c3b2c95 100644 --- a/dom/xml/nsXMLPrettyPrinter.cpp +++ b/dom/xml/nsXMLPrettyPrinter.cpp @@ -193,7 +193,7 @@ nsXMLPrettyPrinter::MaybeUnhook(nsIContent* aContent) // synchronously mUnhookPending = true; nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &nsXMLPrettyPrinter::Unhook)); + NewRunnableMethod(this, &nsXMLPrettyPrinter::Unhook)); } } diff --git a/dom/xul/XULDocument.cpp b/dom/xul/XULDocument.cpp index 80e4e603ce..70ab05cf13 100644 --- a/dom/xul/XULDocument.cpp +++ b/dom/xul/XULDocument.cpp @@ -1015,7 +1015,7 @@ XULDocument::AttributeChanged(nsIDocument* aDocument, if (ShouldPersistAttribute(aElement, aAttribute) && !persist.IsEmpty() && // XXXldb This should check that it's a token, not just a substring. persist.Find(nsDependentAtomString(aAttribute)) >= 0) { - nsContentUtils::AddScriptRunner(NS_NewRunnableMethodWithArgs + nsContentUtils::AddScriptRunner(NewRunnableMethod (this, &XULDocument::DoPersist, aElement, kNameSpaceID_None, aAttribute)); @@ -3135,7 +3135,7 @@ XULDocument::MaybeBroadcast() if (!nsContentUtils::IsSafeToRunScript()) { if (!mInDestructor) { nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &XULDocument::MaybeBroadcast)); + NewRunnableMethod(this, &XULDocument::MaybeBroadcast)); } return; } diff --git a/dom/xul/templates/nsXULTemplateBuilder.cpp b/dom/xul/templates/nsXULTemplateBuilder.cpp index 92285fb3c7..b46360bce2 100644 --- a/dom/xul/templates/nsXULTemplateBuilder.cpp +++ b/dom/xul/templates/nsXULTemplateBuilder.cpp @@ -1095,13 +1095,13 @@ nsXULTemplateBuilder::AttributeChanged(nsIDocument* aDocument, // beneath the element. if (aAttribute == nsGkAtoms::ref) nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &nsXULTemplateBuilder::RunnableRebuild)); + NewRunnableMethod(this, &nsXULTemplateBuilder::RunnableRebuild)); // Check for a change to the 'datasources' attribute. If so, setup // mDB by parsing the new value and rebuild. else if (aAttribute == nsGkAtoms::datasources) { nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &nsXULTemplateBuilder::RunnableLoadAndRebuild)); + NewRunnableMethod(this, &nsXULTemplateBuilder::RunnableLoadAndRebuild)); } } } @@ -1121,7 +1121,7 @@ nsXULTemplateBuilder::ContentRemoved(nsIDocument* aDocument, // Pass false to Uninit since content is going away anyway nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &nsXULTemplateBuilder::UninitFalse)); + NewRunnableMethod(this, &nsXULTemplateBuilder::UninitFalse)); MOZ_ASSERT(aDocument == mObservedDocument); StopObserving(); @@ -1160,7 +1160,7 @@ nsXULTemplateBuilder::NodeWillBeDestroyed(const nsINode* aNode) mCompDB = nullptr; nsContentUtils::AddScriptRunner( - NS_NewRunnableMethod(this, &nsXULTemplateBuilder::UninitTrue)); + NewRunnableMethod(this, &nsXULTemplateBuilder::UninitTrue)); } diff --git a/editor/libeditor/nsHTMLEditRules.cpp b/editor/libeditor/nsHTMLEditRules.cpp index 803d6710ca..55c0d77d72 100644 --- a/editor/libeditor/nsHTMLEditRules.cpp +++ b/editor/libeditor/nsHTMLEditRules.cpp @@ -8731,7 +8731,7 @@ nsHTMLEditRules::WillRelativeChangeZIndex(Selection* aSelection, NS_IMETHODIMP nsHTMLEditRules::DocumentModified() { - nsContentUtils::AddScriptRunner(NS_NewRunnableMethod(this, &nsHTMLEditRules::DocumentModifiedWorker)); + nsContentUtils::AddScriptRunner(NewRunnableMethod(this, &nsHTMLEditRules::DocumentModifiedWorker)); return NS_OK; } diff --git a/editor/libeditor/nsHTMLEditor.cpp b/editor/libeditor/nsHTMLEditor.cpp index 107b48ee5b..136ff4006c 100644 --- a/editor/libeditor/nsHTMLEditor.cpp +++ b/editor/libeditor/nsHTMLEditor.cpp @@ -3227,7 +3227,7 @@ nsHTMLEditor::DoContentInserted(nsIDocument* aDocument, nsIContent* aContainer, nsCOMPtr kungFuDeathGrip(this); if (ShouldReplaceRootElement()) { - nsContentUtils::AddScriptRunner(NS_NewRunnableMethod( + nsContentUtils::AddScriptRunner(NewRunnableMethod( this, &nsHTMLEditor::ResetRootElementAndEventTarget)); } // We don't need to handle our own modifications @@ -3273,7 +3273,7 @@ nsHTMLEditor::ContentRemoved(nsIDocument *aDocument, nsIContent* aContainer, nsCOMPtr kungFuDeathGrip(this); if (SameCOMIdentity(aChild, mRootElement)) { - nsContentUtils::AddScriptRunner(NS_NewRunnableMethod( + nsContentUtils::AddScriptRunner(NewRunnableMethod( this, &nsHTMLEditor::ResetRootElementAndEventTarget)); } // We don't need to handle our own modifications diff --git a/editor/txmgr/nsTransactionItem.cpp b/editor/txmgr/nsTransactionItem.cpp index 5ca1b56d2c..3317ca755b 100644 --- a/editor/txmgr/nsTransactionItem.cpp +++ b/editor/txmgr/nsTransactionItem.cpp @@ -237,7 +237,7 @@ nsTransactionItem::UndoChildren(nsTransactionManager *aTxMgr) if (NS_SUCCEEDED(result)) { item = mUndoStack->Pop(); - mRedoStack->Push(item); + mRedoStack->Push(item.forget()); } nsresult result2 = aTxMgr->DidUndoNotify(t, result); @@ -310,7 +310,7 @@ nsTransactionItem::RedoChildren(nsTransactionManager *aTxMgr) if (NS_SUCCEEDED(result)) { item = mRedoStack->Pop(); - mUndoStack->Push(item); + mUndoStack->Push(item.forget()); } nsresult result2 = aTxMgr->DidUndoNotify(t, result); diff --git a/editor/txmgr/nsTransactionManager.cpp b/editor/txmgr/nsTransactionManager.cpp index a879db0b35..ee32e35eb9 100644 --- a/editor/txmgr/nsTransactionManager.cpp +++ b/editor/txmgr/nsTransactionManager.cpp @@ -102,15 +102,13 @@ nsTransactionManager::UndoTransaction() // executing a transaction's DoTransaction() method! If this happens, // the UndoTransaction() request is ignored, and we return NS_ERROR_FAILURE. - RefPtr tx = mDoStack.Peek(); - - if (tx) { + if (!mDoStack.IsEmpty()) { return NS_ERROR_FAILURE; } // Peek at the top of the undo stack. Don't remove the transaction // until it has successfully completed. - tx = mUndoStack.Peek(); + RefPtr tx = mUndoStack.Peek(); // Bail if there's nothing on the stack. if (!tx) { @@ -135,7 +133,7 @@ nsTransactionManager::UndoTransaction() if (NS_SUCCEEDED(result)) { tx = mUndoStack.Pop(); - mRedoStack.Push(tx); + mRedoStack.Push(tx.forget()); } nsresult result2 = DidUndoNotify(t, result); @@ -155,15 +153,13 @@ nsTransactionManager::RedoTransaction() // executing a transaction's DoTransaction() method! If this happens, // the RedoTransaction() request is ignored, and we return NS_ERROR_FAILURE. - RefPtr tx = mDoStack.Peek(); - - if (tx) { + if (!mDoStack.IsEmpty()) { return NS_ERROR_FAILURE; } // Peek at the top of the redo stack. Don't remove the transaction // until it has successfully completed. - tx = mRedoStack.Peek(); + RefPtr tx = mRedoStack.Peek(); // Bail if there's nothing on the stack. if (!tx) { @@ -188,7 +184,7 @@ nsTransactionManager::RedoTransaction() if (NS_SUCCEEDED(result)) { tx = mRedoStack.Pop(); - mUndoStack.Push(tx); + mUndoStack.Push(tx.forget()); } nsresult result2 = DidRedoNotify(t, result); @@ -331,9 +327,7 @@ nsTransactionManager::SetMaxTransactionCount(int32_t aMaxCount) // SetMaxTransactionCount() request is ignored, and we return // NS_ERROR_FAILURE. - RefPtr tx = mDoStack.Peek(); - - if (tx) { + if (!mDoStack.IsEmpty()) { return NS_ERROR_FAILURE; } @@ -364,7 +358,7 @@ nsTransactionManager::SetMaxTransactionCount(int32_t aMaxCount) // the bottom of the stack and pop towards the top. while (numUndoItems > 0 && (numRedoItems + numUndoItems) > aMaxCount) { - tx = mUndoStack.PopBottom(); + RefPtr tx = mUndoStack.PopBottom(); if (!tx) { return NS_ERROR_FAILURE; @@ -377,7 +371,7 @@ nsTransactionManager::SetMaxTransactionCount(int32_t aMaxCount) // the bottom of the stack and pop towards the top. while (numRedoItems > 0 && (numRedoItems + numUndoItems) > aMaxCount) { - tx = mRedoStack.PopBottom(); + RefPtr tx = mRedoStack.PopBottom(); if (!tx) { return NS_ERROR_FAILURE; @@ -487,15 +481,11 @@ nsTransactionManager::BatchTopUndo() nsresult nsTransactionManager::RemoveTopUndo() { - RefPtr lastUndo; - - lastUndo = mUndoStack.Peek(); - if (!lastUndo) { + if (mUndoStack.IsEmpty()) { return NS_OK; } - lastUndo = mUndoStack.Pop(); - + RefPtr lastUndo = mUndoStack.Pop(); return NS_OK; } @@ -898,7 +888,7 @@ nsTransactionManager::EndTransaction(bool aAllowEmpty) // Push the transaction on the undo stack: - mUndoStack.Push(tx); + mUndoStack.Push(tx.forget()); return NS_OK; } diff --git a/editor/txmgr/nsTransactionStack.cpp b/editor/txmgr/nsTransactionStack.cpp index e75b7979ad..8cd23b5863 100644 --- a/editor/txmgr/nsTransactionStack.cpp +++ b/editor/txmgr/nsTransactionStack.cpp @@ -11,8 +11,16 @@ #include "nsTransactionStack.h" #include "nscore.h" -nsTransactionStack::nsTransactionStack(nsTransactionStack::Type aType) - : mType(aType) +class nsTransactionStackDeallocator : public nsDequeFunctor { + virtual void* operator() (void* aObject) { + RefPtr releaseMe = dont_AddRef(static_cast(aObject)); + return nullptr; + } +}; + +nsTransactionStack::nsTransactionStack(Type aType) + : nsDeque(new nsTransactionStackDeallocator()) + , mType(aType) { } @@ -22,72 +30,77 @@ nsTransactionStack::~nsTransactionStack() } void -nsTransactionStack::Push(nsTransactionItem *aTransaction) +nsTransactionStack::Push(nsTransactionItem* aTransactionItem) { - if (!aTransaction) { + if (!aTransactionItem) { return; } - // The stack's bottom is the front of the deque, and the top is the back. - mDeque.push_back(aTransaction); + RefPtr item(aTransactionItem); + Push(item.forget()); +} + +void +nsTransactionStack::Push(already_AddRefed aTransactionItem) +{ + RefPtr item(aTransactionItem); + if (!item) { + return; + } + + nsDeque::Push(item.forget().take()); } already_AddRefed nsTransactionStack::Pop() { - if (mDeque.empty()) { - return nullptr; - } - RefPtr ret = mDeque.back().forget(); - mDeque.pop_back(); - return ret.forget(); + RefPtr item = + dont_AddRef(static_cast(nsDeque::Pop())); + return item.forget(); } already_AddRefed nsTransactionStack::PopBottom() { - if (mDeque.empty()) { - return nullptr; - } - RefPtr ret = mDeque.front().forget(); - mDeque.pop_front(); - return ret.forget(); + RefPtr item = + dont_AddRef(static_cast(nsDeque::PopFront())); + return item.forget(); } already_AddRefed nsTransactionStack::Peek() { - if (mDeque.empty()) { - return nullptr; - } - RefPtr ret = mDeque.back(); - return ret.forget(); + RefPtr item = + static_cast(nsDeque::Peek()); + return item.forget(); } already_AddRefed nsTransactionStack::GetItem(int32_t aIndex) { - if (aIndex < 0 || aIndex >= static_cast(mDeque.size())) { + if (aIndex < 0 || aIndex >= static_cast(nsDeque::GetSize())) { return nullptr; } - RefPtr ret = mDeque[aIndex]; - return ret.forget(); + RefPtr item = + static_cast(nsDeque::ObjectAt(aIndex)); + return item.forget(); } void nsTransactionStack::Clear() { - while (!mDeque.empty()) { - RefPtr tx = mType == FOR_UNDO ? Pop() : PopBottom(); + while (GetSize() != 0) { + RefPtr item = + mType == FOR_UNDO ? Pop() : PopBottom(); } } void nsTransactionStack::DoTraverse(nsCycleCollectionTraversalCallback &cb) { - int32_t size = mDeque.size(); + int32_t size = GetSize(); for (int32_t i = 0; i < size; ++i) { - nsTransactionItem* item = mDeque[i]; + nsTransactionItem* item = static_cast(nsDeque::ObjectAt(i)); if (item) { NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "transaction stack mDeque[i]"); cb.NoteNativeChild(item, NS_CYCLE_COLLECTION_PARTICIPANT(nsTransactionItem)); diff --git a/editor/txmgr/nsTransactionStack.h b/editor/txmgr/nsTransactionStack.h index 2c56280954..7b211808cb 100644 --- a/editor/txmgr/nsTransactionStack.h +++ b/editor/txmgr/nsTransactionStack.h @@ -6,13 +6,13 @@ #ifndef nsTransactionStack_h__ #define nsTransactionStack_h__ -#include +#include "nsDeque.h" #include "nsAutoPtr.h" class nsCycleCollectionTraversalCallback; class nsTransactionItem; -class nsTransactionStack +class nsTransactionStack : private nsDeque { public: enum Type { FOR_UNDO, FOR_REDO }; @@ -21,18 +21,19 @@ public: ~nsTransactionStack(); void Push(nsTransactionItem *aTransactionItem); + void Push(already_AddRefed aTransactionItem); already_AddRefed Pop(); already_AddRefed PopBottom(); already_AddRefed Peek(); already_AddRefed GetItem(int32_t aIndex); void Clear(); - int32_t GetSize() { return mDeque.size(); } + int32_t GetSize() const { return static_cast(nsDeque::GetSize()); } + bool IsEmpty() const { return GetSize() == 0; } void DoUnlink() { Clear(); } void DoTraverse(nsCycleCollectionTraversalCallback &cb); private: - std::deque > mDeque; const Type mType; }; diff --git a/gfx/gl/AndroidSurfaceTexture.cpp b/gfx/gl/AndroidSurfaceTexture.cpp index 08d880c7ca..02aa2fc957 100644 --- a/gfx/gl/AndroidSurfaceTexture.cpp +++ b/gfx/gl/AndroidSurfaceTexture.cpp @@ -293,8 +293,7 @@ AndroidSurfaceTexture::NotifyFrameAvailable() // Proxy to main thread if we aren't on it if (!NS_IsMainThread()) { // Proxy to main thread - nsCOMPtr event = NS_NewRunnableMethod(this, &AndroidSurfaceTexture::NotifyFrameAvailable); - NS_DispatchToCurrentThread(event); + NS_DispatchToCurrentThread(NewRunnableMethod(this, &AndroidSurfaceTexture::NotifyFrameAvailable)); } else { mFrameAvailableCallback->Run(); } diff --git a/gfx/ipc/CompositorSession.cpp b/gfx/ipc/CompositorSession.cpp new file mode 100644 index 0000000000..a12f9ceee0 --- /dev/null +++ b/gfx/ipc/CompositorSession.cpp @@ -0,0 +1,122 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=99: */ +/* 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 "CompositorSession.h" +#include "mozilla/layers/CompositorBridgeChild.h" +#include "mozilla/layers/CompositorBridgeParent.h" +#include "base/process_util.h" + +namespace mozilla { +namespace layers { + +class InProcessCompositorSession final : public CompositorSession +{ +public: + InProcessCompositorSession( + widget::CompositorWidgetProxy* aWidgetProxy, + ClientLayerManager* aLayerManager, + CSSToLayoutDeviceScale aScale, + bool aUseAPZ, + bool aUseExternalSurfaceSize, + int aSurfaceWidth, int aSurfaceHeight); + + CompositorBridgeParent* GetInProcessBridge() const override; + void SetContentController(GeckoContentController* aController) override; + uint64_t RootLayerTreeId() const override; + APZCTreeManager* GetAPZCTreeManager() const override; + void Shutdown() override; + +private: + RefPtr mCompositorBridgeParent; +}; + +already_AddRefed +CompositorSession::CreateTopLevel(widget::CompositorWidgetProxy* aWidgetProxy, + ClientLayerManager* aLayerManager, + CSSToLayoutDeviceScale aScale, + bool aUseAPZ, + bool aUseExternalSurfaceSize, + int aSurfaceWidth, int aSurfaceHeight) +{ + RefPtr session = new InProcessCompositorSession( + aWidgetProxy, + aLayerManager, + aScale, + aUseAPZ, + aUseExternalSurfaceSize, + aSurfaceWidth, aSurfaceHeight); + return session.forget(); +} + +CompositorSession::CompositorSession() +{ +} + +CompositorSession::~CompositorSession() +{ +} + +CompositorBridgeChild* +CompositorSession::GetCompositorBridgeChild() +{ + return mCompositorBridgeChild; +} + +InProcessCompositorSession::InProcessCompositorSession(widget::CompositorWidgetProxy* aWidgetProxy, + ClientLayerManager* aLayerManager, + CSSToLayoutDeviceScale aScale, + bool aUseAPZ, + bool aUseExternalSurfaceSize, + int aSurfaceWidth, int aSurfaceHeight) +{ + mCompositorBridgeParent = new CompositorBridgeParent( + aWidgetProxy, + aScale, + aUseAPZ, + aUseExternalSurfaceSize, + aSurfaceWidth, + aSurfaceHeight); + mCompositorBridgeChild = new CompositorBridgeChild(aLayerManager); + mCompositorBridgeChild->OpenSameProcess(mCompositorBridgeParent); + mCompositorBridgeParent->SetOtherProcessId(base::GetCurrentProcId()); +} + +CompositorBridgeParent* +InProcessCompositorSession::GetInProcessBridge() const +{ + return mCompositorBridgeParent; +} + +void +InProcessCompositorSession::SetContentController(GeckoContentController* aController) +{ + mCompositorBridgeParent->SetControllerForLayerTree(RootLayerTreeId(), aController); +} + +uint64_t +InProcessCompositorSession::RootLayerTreeId() const +{ + return mCompositorBridgeParent->RootLayerTreeId(); +} + +APZCTreeManager* +InProcessCompositorSession::GetAPZCTreeManager() const +{ + return mCompositorBridgeParent->GetAPZCTreeManager(RootLayerTreeId()); +} + +void +InProcessCompositorSession::Shutdown() +{ + // XXX CompositorBridgeChild and CompositorBridgeParent might be re-created in + // ClientLayerManager destructor. See bug 1133426. + RefPtr compositorChild = mCompositorBridgeChild; + RefPtr compositorParent = mCompositorBridgeParent; + mCompositorBridgeChild->Destroy(); + mCompositorBridgeChild = nullptr; +} + +} // namespace layers +} // namespace mozilla diff --git a/gfx/ipc/CompositorSession.h b/gfx/ipc/CompositorSession.h new file mode 100644 index 0000000000..0e203349b0 --- /dev/null +++ b/gfx/ipc/CompositorSession.h @@ -0,0 +1,71 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=99: */ +/* 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 _include_mozilla_gfx_ipc_CompositorSession_h_ +#define _include_mozilla_gfx_ipc_CompositorSession_h_ + +#include "base/basictypes.h" +#include "Units.h" +#include "nsISupportsImpl.h" + +namespace mozilla { +namespace widget { +class CompositorWidgetProxy; +} // namespace widget +namespace layers { + +class GeckoContentController; +class APZCTreeManager; +class CompositorBridgeParent; +class CompositorBridgeChild; +class ClientLayerManager; + +// A CompositorSession provides access to a compositor without exposing whether +// or not it's in-process or out-of-process. +class CompositorSession +{ +public: + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorSession) + + static already_AddRefed CreateTopLevel( + widget::CompositorWidgetProxy* aWidgetProxy, + ClientLayerManager* aLayerManager, + CSSToLayoutDeviceScale aScale, + bool aUseAPZ, + bool aUseExternalSurfaceSize, + int aSurfaceWidth, int aSurfaceHeight); + + virtual void Shutdown() = 0; + + // This returns a CompositorBridgeParent if the compositor resides in the same process. + virtual CompositorBridgeParent* GetInProcessBridge() const = 0; + + // Set the GeckoContentController for the root of the layer tree. + virtual void SetContentController(GeckoContentController* aController) = 0; + + // Return the id of the root layer tree. + virtual uint64_t RootLayerTreeId() const = 0; + + // Return the Async Pan/Zoom Tree Manager for this compositor. + virtual APZCTreeManager* GetAPZCTreeManager() const = 0; + + // Return the child end of the compositor IPC bridge. + CompositorBridgeChild* GetCompositorBridgeChild(); + +protected: + CompositorSession(); + virtual ~CompositorSession(); + +protected: + RefPtr mCompositorBridgeChild; + +private: + DISALLOW_COPY_AND_ASSIGN(CompositorSession); +}; + +} // namespace layers +} // namespace mozilla + +#endif // _include_mozilla_gfx_ipc_CompositorSession_h_ diff --git a/gfx/ipc/moz.build b/gfx/ipc/moz.build index e3500a5b63..4598dcba47 100644 --- a/gfx/ipc/moz.build +++ b/gfx/ipc/moz.build @@ -13,6 +13,10 @@ EXPORTS.mozilla.gfx += [ 'SharedDIB.h', ] +EXPORTS.mozilla.layers += [ + 'CompositorSession.h', +] + if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': EXPORTS.mozilla.gfx += [ 'SharedDIBSurface.h', @@ -24,6 +28,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': ] UNIFIED_SOURCES += [ + 'CompositorSession.cpp', 'D3DMessageUtils.cpp', 'SharedDIB.cpp', ] diff --git a/gfx/layers/AtomicRefCountedWithFinalize.h b/gfx/layers/AtomicRefCountedWithFinalize.h index f6476106c6..793ab67b8c 100644 --- a/gfx/layers/AtomicRefCountedWithFinalize.h +++ b/gfx/layers/AtomicRefCountedWithFinalize.h @@ -68,9 +68,6 @@ public: template friend struct mozilla::RefPtrTraits; - template - friend struct ::RunnableMethodTraits; - template friend class ::mozilla::gl::RefSet; diff --git a/gfx/layers/Compositor.cpp b/gfx/layers/Compositor.cpp index 56ecb704f0..8969b04e97 100644 --- a/gfx/layers/Compositor.cpp +++ b/gfx/layers/Compositor.cpp @@ -7,6 +7,7 @@ #include "base/message_loop.h" // for MessageLoop #include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent #include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc +#include "mozilla/layers/CompositorThread.h" #include "mozilla/mozalloc.h" // for operator delete, etc #include "gfx2DGlue.h" #include "nsAppRunner.h" @@ -25,8 +26,8 @@ namespace layers { /* static */ void Compositor::AssertOnCompositorThread() { - MOZ_ASSERT(!CompositorBridgeParent::CompositorLoop() || - CompositorBridgeParent::CompositorLoop() == MessageLoop::current(), + MOZ_ASSERT(!CompositorThreadHolder::Loop() || + CompositorThreadHolder::Loop() == MessageLoop::current(), "Can only call this from the compositor thread!"); } @@ -412,7 +413,7 @@ Compositor::IsValid() const #if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17 void -Compositor::SetDispAcquireFence(Layer* aLayer, nsIWidget* aWidget) +Compositor::SetDispAcquireFence(Layer* aLayer) { // OpenGL does not provide ReleaseFence for rendering. // Instead use DispAcquireFence as layer buffer's ReleaseFence @@ -420,11 +421,10 @@ Compositor::SetDispAcquireFence(Layer* aLayer, nsIWidget* aWidget) // DispAcquireFence is DisplaySurface's AcquireFence. // AcquireFence will be signaled when a buffer's content is available. // See Bug 974152. - - if (!aLayer || !aWidget) { + if (!aLayer || !mWidget) { return; } - nsWindow* window = static_cast(aWidget); + nsWindow* window = static_cast(mWidget->RealWidget()); RefPtr fence = new FenceHandle::FdObj( window->GetScreen()->GetPrevDispAcquireFd()); mReleaseFenceHandle.Merge(FenceHandle(fence)); @@ -443,7 +443,7 @@ Compositor::GetReleaseFence() #else void -Compositor::SetDispAcquireFence(Layer* aLayer, nsIWidget* aWidget) +Compositor::SetDispAcquireFence(Layer* aLayer) { } diff --git a/gfx/layers/Compositor.h b/gfx/layers/Compositor.h index 8f033fcc17..574473eba6 100644 --- a/gfx/layers/Compositor.h +++ b/gfx/layers/Compositor.h @@ -389,7 +389,7 @@ public: */ virtual void EndFrame() = 0; - virtual void SetDispAcquireFence(Layer* aLayer, nsIWidget* aWidget); + virtual void SetDispAcquireFence(Layer* aLayer); virtual FenceHandle GetReleaseFence(); @@ -533,6 +533,9 @@ public: // frames and should not be used. void SetInvalid(); bool IsValid() const; + CompositorBridgeParent* GetCompositorBridgeParent() const { + return mParent; + } protected: void DrawDiagnosticsInternal(DiagnosticFlags aFlags, diff --git a/gfx/layers/apz/src/APZCTreeManager.cpp b/gfx/layers/apz/src/APZCTreeManager.cpp index 45efbc5e4d..7680d572be 100644 --- a/gfx/layers/apz/src/APZCTreeManager.cpp +++ b/gfx/layers/apz/src/APZCTreeManager.cpp @@ -649,8 +649,8 @@ APZCTreeManager::FlushApzRepaints(uint64_t aLayersId) const CompositorBridgeParent::LayerTreeState* state = CompositorBridgeParent::GetIndirectShadowTree(aLayersId); MOZ_ASSERT(state && state->mController); - NS_DispatchToMainThread(NS_NewRunnableMethod( - state->mController.get(), &GeckoContentController::NotifyFlushComplete)); + NS_DispatchToMainThread(NewRunnableMethod( + state->mController, &GeckoContentController::NotifyFlushComplete)); } nsEventStatus @@ -1345,8 +1345,7 @@ APZCTreeManager::ClearTree() // Ensure that no references to APZCs are alive in any lingering input // blocks. This breaks cycles from InputBlockState::mTargetApzc back to // the InputQueue. - APZThreadUtils::RunOnControllerThread(NewRunnableMethod( - mInputQueue.get(), &InputQueue::Clear)); + APZThreadUtils::RunOnControllerThread(NewRunnableMethod(mInputQueue, &InputQueue::Clear)); MutexAutoLock lock(mTreeLock); diff --git a/gfx/layers/apz/src/AsyncPanZoomController.cpp b/gfx/layers/apz/src/AsyncPanZoomController.cpp index 885a35298f..9f358aae11 100644 --- a/gfx/layers/apz/src/AsyncPanZoomController.cpp +++ b/gfx/layers/apz/src/AsyncPanZoomController.cpp @@ -516,9 +516,9 @@ public: // is this one, then the SetState(NOTHING) in UpdateAnimation will // stomp on the SetState(SNAP_BACK) it does. mDeferredTasks.AppendElement( - NewRunnableMethod(mOverscrollHandoffChain.get(), - &OverscrollHandoffChain::SnapBackOverscrolledApzc, - &mApzc)); + NewRunnableMethod(mOverscrollHandoffChain.get(), + &OverscrollHandoffChain::SnapBackOverscrolledApzc, + &mApzc)); return false; } @@ -568,11 +568,13 @@ public: // called after mMonitor is released. APZC_LOG("%p fling went into overscroll, handing off with velocity %s\n", &mApzc, Stringify(velocity).c_str()); mDeferredTasks.AppendElement( - NewRunnableMethod(&mApzc, - &AsyncPanZoomController::HandleFlingOverscroll, - velocity, - mOverscrollHandoffChain, - mScrolledApzc)); + NewRunnableMethod, + RefPtr>(&mApzc, + &AsyncPanZoomController::HandleFlingOverscroll, + velocity, + mOverscrollHandoffChain, + mScrolledApzc)); // If there is a remaining velocity on this APZC, continue this fling // as well. (This fling and the handed-off fling will run concurrently.) @@ -700,9 +702,7 @@ public: // The scroll snapping is done in a deferred task, otherwise the state // change to NOTHING caused by the overscroll animation ending would // clobber a possible state change to SMOOTH_SCROLL in ScrollSnap(). - mDeferredTasks.AppendElement( - NewRunnableMethod(&mApzc, - &AsyncPanZoomController::ScrollSnap)); + mDeferredTasks.AppendElement(NewRunnableMethod(&mApzc, &AsyncPanZoomController::ScrollSnap)); return false; } return true; @@ -819,9 +819,9 @@ public: // the lock ordering. Instead we schedule HandleSmoothScrollOverscroll() to be // called after mMonitor is released. mDeferredTasks.AppendElement( - NewRunnableMethod(&mApzc, - &AsyncPanZoomController::HandleSmoothScrollOverscroll, - velocity)); + NewRunnableMethod(&mApzc, + &AsyncPanZoomController::HandleSmoothScrollOverscroll, + velocity)); return false; } @@ -2180,11 +2180,14 @@ nsEventStatus AsyncPanZoomController::GenerateSingleTap(const ScreenIntPoint& aP // the single tap message before the corresponding touch-up. To avoid that we // schedule the singletap message to run on the next spin of the event loop. // See bug 965381 for the issue this was causing. - controller->PostDelayedTask( - NewRunnableMethod(controller.get(), &GeckoContentController::HandleSingleTap, - geckoScreenPoint, aModifiers, - GetGuid()), - 0); + RefPtr runnable = + NewRunnableMethod(controller, &GeckoContentController::HandleSingleTap, + geckoScreenPoint, aModifiers, + GetGuid()); + + controller->PostDelayedTask(runnable.forget(), 0); return nsEventStatus_eConsumeNoDefault; } } @@ -2992,7 +2995,7 @@ void AsyncPanZoomController::RequestContentRepaint() { // use the local variable to resolve the function overload. auto func = static_cast (&AsyncPanZoomController::RequestContentRepaint); - NS_DispatchToMainThread(NS_NewRunnableMethod(this, func)); + NS_DispatchToMainThread(NewRunnableMethod(this, func)); return; } @@ -3725,7 +3728,7 @@ void AsyncPanZoomController::ZoomToRect(CSSRect aRect, const uint32_t aFlags) { auto func = static_cast (&AsyncPanZoomController::RequestContentRepaint); NS_DispatchToMainThread( - NS_NewRunnableMethodWithArgs( + NewRunnableMethod( this, func, endZoomToMetrics, velocity)); } } diff --git a/gfx/layers/apz/src/GestureEventListener.cpp b/gfx/layers/apz/src/GestureEventListener.cpp index a655dc0e35..b81ddc10ef 100644 --- a/gfx/layers/apz/src/GestureEventListener.cpp +++ b/gfx/layers/apz/src/GestureEventListener.cpp @@ -498,7 +498,7 @@ void GestureEventListener::CancelLongTapTimeoutTask() void GestureEventListener::CreateLongTapTimeoutTask() { RefPtr task = - NewRunnableMethod(this, &GestureEventListener::HandleInputTimeoutLongTap); + NewCancelableRunnableMethod(this, &GestureEventListener::HandleInputTimeoutLongTap); mLongTapTimeoutTask = task; mAsyncPanZoomController->PostDelayedTask( @@ -525,8 +525,9 @@ void GestureEventListener::CreateMaxTapTimeoutTask() TouchBlockState* block = mAsyncPanZoomController->GetInputQueue()->CurrentTouchBlock(); RefPtr task = - NewRunnableMethod(this, &GestureEventListener::HandleInputTimeoutMaxTap, - block->IsDuringFastFling()); + NewCancelableRunnableMethod(this, + &GestureEventListener::HandleInputTimeoutMaxTap, + block->IsDuringFastFling()); mMaxTapTimeoutTask = task; mAsyncPanZoomController->PostDelayedTask( diff --git a/gfx/layers/apz/src/InputQueue.cpp b/gfx/layers/apz/src/InputQueue.cpp index 0909465d6a..c267b097b2 100644 --- a/gfx/layers/apz/src/InputQueue.cpp +++ b/gfx/layers/apz/src/InputQueue.cpp @@ -570,9 +570,10 @@ InputQueue::ScheduleMainThreadTimeout(const RefPtr& aTar CancelableBlockState* aBlock) { INPQ_LOG("scheduling main thread timeout for target %p\n", aTarget.get()); aBlock->StartContentResponseTimer(); - aTarget->PostDelayedTask( - NewRunnableMethod(this, &InputQueue::MainThreadTimeout, aBlock->GetBlockId()), - gfxPrefs::APZContentResponseTimeout()); + aTarget->PostDelayedTask(NewRunnableMethod(this, + &InputQueue::MainThreadTimeout, + aBlock->GetBlockId()), + gfxPrefs::APZContentResponseTimeout()); } void diff --git a/gfx/layers/apz/util/APZCCallbackHelper.cpp b/gfx/layers/apz/util/APZCCallbackHelper.cpp index 0d5298bf21..2cacf2d06d 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -690,7 +690,7 @@ public: } APZCCH_LOG("Got refresh, sending target APZCs for input block %" PRIu64 "\n", mInputBlockId); - SendLayersDependentApzcTargetConfirmation(mPresShell, mInputBlockId, mTargets); + SendLayersDependentApzcTargetConfirmation(mPresShell, mInputBlockId, Move(mTargets)); if (!mPresShell->RemovePostRefreshObserver(this)) { MOZ_ASSERT_UNREACHABLE("Unable to unregister post-refresh observer! Leaking it instead of leaving garbage registered"); @@ -721,7 +721,7 @@ SendSetTargetAPZCNotificationHelper(nsIWidget* aWidget, if (waitForRefresh) { APZCCH_LOG("At least one target got a new displayport, need to wait for refresh\n"); waitForRefresh = aShell->AddPostRefreshObserver( - new DisplayportSetListener(aShell, aInputBlockId, aTargets)); + new DisplayportSetListener(aShell, aInputBlockId, Move(aTargets))); } if (!waitForRefresh) { APZCCH_LOG("Sending target APZCs for input block %" PRIu64 "\n", aInputBlockId); @@ -772,7 +772,7 @@ APZCCallbackHelper::SendSetTargetAPZCNotification(nsIWidget* aWidget, aWidget, shell, aInputBlockId, - targets, + Move(targets), waitForRefresh); } } @@ -792,7 +792,7 @@ APZCCallbackHelper::SendSetAllowedTouchBehaviorNotification( widget::ContentHelper::GetAllowedTouchBehavior( aWidget, aEvent.mTouches[i]->mRefPoint)); } - aCallback(aInputBlockId, flags); + aCallback(aInputBlockId, Move(flags)); } void diff --git a/gfx/layers/apz/util/APZCCallbackHelper.h b/gfx/layers/apz/util/APZCCallbackHelper.h index aa9e90ade4..4aed50502c 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.h +++ b/gfx/layers/apz/util/APZCCallbackHelper.h @@ -141,9 +141,9 @@ public: /* Figure out the allowed touch behaviors of each touch point in |aEvent| * and send that information to the provided callback. */ static void SendSetAllowedTouchBehaviorNotification(nsIWidget* aWidget, - const WidgetTouchEvent& aEvent, - uint64_t aInputBlockId, - const SetAllowedTouchBehaviorCallback& aCallback); + const WidgetTouchEvent& aEvent, + uint64_t aInputBlockId, + const SetAllowedTouchBehaviorCallback& aCallback); /* Notify content of a mouse scroll testing event. */ static void NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent); diff --git a/gfx/layers/apz/util/ActiveElementManager.cpp b/gfx/layers/apz/util/ActiveElementManager.cpp index 436fa0436c..20d34aa2bb 100644 --- a/gfx/layers/apz/util/ActiveElementManager.cpp +++ b/gfx/layers/apz/util/ActiveElementManager.cpp @@ -94,8 +94,10 @@ ActiveElementManager::TriggerElementActivation() // bug properly should make this unnecessary. MOZ_ASSERT(mSetActiveTask == nullptr); - RefPtr task = NewRunnableMethod( - this, &ActiveElementManager::SetActiveTask, mTarget); + RefPtr task = + NewCancelableRunnableMethod>(this, + &ActiveElementManager::SetActiveTask, + mTarget); mSetActiveTask = task; MessageLoop::current()->PostDelayedTask(task.forget(), sActivationDelayMs); AEM_LOG("Scheduling mSetActiveTask %p\n", mSetActiveTask); diff --git a/gfx/layers/apz/util/ChromeProcessController.cpp b/gfx/layers/apz/util/ChromeProcessController.cpp index ee7aab2375..19ec6ac269 100644 --- a/gfx/layers/apz/util/ChromeProcessController.cpp +++ b/gfx/layers/apz/util/ChromeProcessController.cpp @@ -36,8 +36,7 @@ ChromeProcessController::ChromeProcessController(nsIWidget* aWidget, MOZ_ASSERT(aAPZEventState); MOZ_ASSERT(aAPZCTreeManager); - mUILoop->PostTask( - NewRunnableMethod(this, &ChromeProcessController::InitializeRoot)); + mUILoop->PostTask(NewRunnableMethod(this, &ChromeProcessController::InitializeRoot)); } ChromeProcessController::~ChromeProcessController() {} @@ -71,8 +70,7 @@ void ChromeProcessController::Destroy() { if (MessageLoop::current() != mUILoop) { - mUILoop->PostTask( - NewRunnableMethod(this, &ChromeProcessController::Destroy)); + mUILoop->PostTask(NewRunnableMethod(this, &ChromeProcessController::Destroy)); return; } @@ -121,9 +119,12 @@ ChromeProcessController::HandleDoubleTap(const mozilla::CSSPoint& aPoint, const ScrollableLayerGuid& aGuid) { if (MessageLoop::current() != mUILoop) { - mUILoop->PostTask( - NewRunnableMethod(this, &ChromeProcessController::HandleDoubleTap, - aPoint, aModifiers, aGuid)); + mUILoop->PostTask(NewRunnableMethod + (this, + &ChromeProcessController::HandleDoubleTap, + aPoint, aModifiers, aGuid)); return; } @@ -158,9 +159,12 @@ ChromeProcessController::HandleSingleTap(const CSSPoint& aPoint, const ScrollableLayerGuid& aGuid) { if (MessageLoop::current() != mUILoop) { - mUILoop->PostTask( - NewRunnableMethod(this, &ChromeProcessController::HandleSingleTap, - aPoint, aModifiers, aGuid)); + mUILoop->PostTask(NewRunnableMethod + (this, + &ChromeProcessController::HandleSingleTap, + aPoint, aModifiers, aGuid)); return; } @@ -173,9 +177,12 @@ ChromeProcessController::HandleLongTap(const mozilla::CSSPoint& aPoint, Modifier uint64_t aInputBlockId) { if (MessageLoop::current() != mUILoop) { - mUILoop->PostTask( - NewRunnableMethod(this, &ChromeProcessController::HandleLongTap, - aPoint, aModifiers, aGuid, aInputBlockId)); + mUILoop->PostTask(NewRunnableMethod + (this, &ChromeProcessController::HandleLongTap, + aPoint, aModifiers, aGuid, aInputBlockId)); return; } @@ -189,9 +196,11 @@ ChromeProcessController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid, int aArg) { if (MessageLoop::current() != mUILoop) { - mUILoop->PostTask( - NewRunnableMethod(this, &ChromeProcessController::NotifyAPZStateChange, - aGuid, aChange, aArg)); + mUILoop->PostTask(NewRunnableMethod + (this, &ChromeProcessController::NotifyAPZStateChange, + aGuid, aChange, aArg)); return; } @@ -202,8 +211,10 @@ void ChromeProcessController::NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& aScrollId, const nsString& aEvent) { if (MessageLoop::current() != mUILoop) { - mUILoop->PostTask( - NewRunnableMethod(this, &ChromeProcessController::NotifyMozMouseScrollEvent, aScrollId, aEvent)); + mUILoop->PostTask(NewRunnableMethod + (this, &ChromeProcessController::NotifyMozMouseScrollEvent, + aScrollId, aEvent)); return; } diff --git a/gfx/layers/composite/LayerManagerComposite.cpp b/gfx/layers/composite/LayerManagerComposite.cpp index a49450e015..c6c0de84ad 100644 --- a/gfx/layers/composite/LayerManagerComposite.cpp +++ b/gfx/layers/composite/LayerManagerComposite.cpp @@ -68,6 +68,7 @@ #endif #include "GeckoProfiler.h" #include "TextRenderer.h" // for TextRenderer +#include "mozilla/layers/CompositorBridgeParent.h" class gfxContext; @@ -944,7 +945,7 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi mCompositor->EndFrame(); // Call after EndFrame() - mCompositor->SetDispAcquireFence(mRoot, mCompositor->GetWidget()->RealWidget()); + mCompositor->SetDispAcquireFence(mRoot); } if (composer2D) { @@ -1547,7 +1548,10 @@ LayerComposite::SetLayerManager(LayerManagerComposite* aManager) bool LayerManagerComposite::AsyncPanZoomEnabled() const { - return mCompositor->GetWidget()->RealWidget()->AsyncPanZoomEnabled(); + if (CompositorBridgeParent* bridge = mCompositor->GetCompositorBridgeParent()) { + return bridge->AsyncPanZoomEnabled(); + } + return false; } nsIntRegion diff --git a/gfx/layers/composite/TextureHost.cpp b/gfx/layers/composite/TextureHost.cpp index c552cf1e14..0351d5b1a4 100644 --- a/gfx/layers/composite/TextureHost.cpp +++ b/gfx/layers/composite/TextureHost.cpp @@ -11,6 +11,7 @@ #include "mozilla/gfx/2D.h" // for DataSourceSurface, Factory #include "mozilla/ipc/Shmem.h" // for Shmem #include "mozilla/layers/CompositableTransactionParent.h" // for CompositableParentManager +#include "mozilla/layers/CompositorBridgeParent.h" #include "mozilla/layers/Compositor.h" // for Compositor #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc @@ -64,7 +65,7 @@ namespace layers { class TextureParent : public ParentActor { public: - explicit TextureParent(CompositableParentManager* aManager); + explicit TextureParent(ISurfaceAllocator* aAllocator); ~TextureParent(); @@ -82,26 +83,26 @@ public: virtual void Destroy() override; - CompositableParentManager* mCompositableManager; + ISurfaceAllocator* mSurfaceAllocator; RefPtr mWaitForClientRecycle; RefPtr mTextureHost; }; //////////////////////////////////////////////////////////////////////////////// PTextureParent* -TextureHost::CreateIPDLActor(CompositableParentManager* aManager, +TextureHost::CreateIPDLActor(ISurfaceAllocator* aAllocator, const SurfaceDescriptor& aSharedData, LayersBackend aLayersBackend, TextureFlags aFlags) { if (aSharedData.type() == SurfaceDescriptor::TSurfaceDescriptorBuffer && aSharedData.get_SurfaceDescriptorBuffer().data().type() == MemoryOrShmem::Tuintptr_t && - !aManager->IsSameProcess()) + !aAllocator->IsSameProcess()) { NS_ERROR("A client process is trying to peek at our address space using a MemoryTexture!"); return nullptr; } - TextureParent* actor = new TextureParent(aManager); + TextureParent* actor = new TextureParent(aAllocator); if (!actor->Init(aSharedData, aLayersBackend, aFlags)) { delete actor; return nullptr; @@ -891,8 +892,8 @@ size_t MemoryTextureHost::GetBufferSize() return std::numeric_limits::max(); } -TextureParent::TextureParent(CompositableParentManager* aCompositableManager) -: mCompositableManager(aCompositableManager) +TextureParent::TextureParent(ISurfaceAllocator* aSurfaceAllocator) +: mSurfaceAllocator(aSurfaceAllocator) { MOZ_COUNT_CTOR(TextureParent); } @@ -942,7 +943,7 @@ TextureParent::Init(const SurfaceDescriptor& aSharedData, const TextureFlags& aFlags) { mTextureHost = TextureHost::Create(aSharedData, - mCompositableManager, + mSurfaceAllocator, aBackend, aFlags); if (mTextureHost) { diff --git a/gfx/layers/composite/TextureHost.h b/gfx/layers/composite/TextureHost.h index ff43084203..80dd8eed0d 100644 --- a/gfx/layers/composite/TextureHost.h +++ b/gfx/layers/composite/TextureHost.h @@ -41,6 +41,7 @@ namespace layers { class BufferDescriptor; class Compositor; class CompositableParentManager; +class CompositorBridgeParent; class SurfaceDescriptor; class ISurfaceAllocator; class TextureHostOGL; @@ -478,7 +479,7 @@ public: * are for use with the managing IPDL protocols only (so that they can * implement AllocPTextureParent and DeallocPTextureParent). */ - static PTextureParent* CreateIPDLActor(CompositableParentManager* aManager, + static PTextureParent* CreateIPDLActor(ISurfaceAllocator* aAllocator, const SurfaceDescriptor& aSharedData, LayersBackend aLayersBackend, TextureFlags aFlags); diff --git a/gfx/layers/d3d11/CompositorD3D11.cpp b/gfx/layers/d3d11/CompositorD3D11.cpp index a9c4c922c0..af15685959 100644 --- a/gfx/layers/d3d11/CompositorD3D11.cpp +++ b/gfx/layers/d3d11/CompositorD3D11.cpp @@ -22,6 +22,7 @@ #include "gfxVR.h" #include "mozilla/gfx/StackArray.h" #include "mozilla/Services.h" +#include "mozilla/widget/WinCompositorWidgetProxy.h" #include "mozilla/EnumeratedArray.h" #include "mozilla/Telemetry.h" @@ -215,7 +216,7 @@ CompositorD3D11::Initialize() mFeatureLevel = mDevice->GetFeatureLevel(); - mHwnd = (HWND)mWidget->RealWidget()->GetNativeData(NS_NATIVE_WINDOW); + mHwnd = mWidget->AsWindowsProxy()->GetHwnd(); memset(&mVSConstants, 0, sizeof(VertexShaderConstants)); diff --git a/gfx/layers/d3d9/CompositorD3D9.cpp b/gfx/layers/d3d9/CompositorD3D9.cpp index 6977b0c99a..f8be57f216 100644 --- a/gfx/layers/d3d9/CompositorD3D9.cpp +++ b/gfx/layers/d3d9/CompositorD3D9.cpp @@ -17,6 +17,7 @@ #include "gfxPrefs.h" #include "gfxCrashReporterUtils.h" #include "mozilla/layers/CompositorBridgeParent.h" +#include "mozilla/widget/WinCompositorWidgetProxy.h" namespace mozilla { namespace layers { @@ -48,9 +49,7 @@ CompositorD3D9::Initialize() return false; } - mSwapChain = mDeviceManager-> - CreateSwapChain((HWND)mWidget->RealWidget()->GetNativeData(NS_NATIVE_WINDOW)); - + mSwapChain = mDeviceManager->CreateSwapChain(mWidget->AsWindowsProxy()->GetHwnd()); if (!mSwapChain) { return false; } @@ -593,8 +592,7 @@ CompositorD3D9::EnsureSwapChain() MOZ_ASSERT(mDeviceManager, "Don't call EnsureSwapChain without a device manager"); if (!mSwapChain) { - mSwapChain = mDeviceManager-> - CreateSwapChain((HWND)mWidget->RealWidget()->GetNativeData(NS_NATIVE_WINDOW)); + mSwapChain = mDeviceManager->CreateSwapChain(mWidget->AsWindowsProxy()->GetHwnd()); // We could not create a swap chain, return false if (!mSwapChain) { // Check the state of the device too diff --git a/gfx/layers/ipc/CompositorBridgeChild.cpp b/gfx/layers/ipc/CompositorBridgeChild.cpp index 7d71907ecc..b845728fe7 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.cpp +++ b/gfx/layers/ipc/CompositorBridgeChild.cpp @@ -6,6 +6,7 @@ #include "mozilla/layers/CompositorBridgeChild.h" #include "mozilla/layers/CompositorBridgeParent.h" +#include "mozilla/layers/CompositorThread.h" #include // for size_t #include "ClientLayerManager.h" // for ClientLayerManager #include "base/message_loop.h" // for MessageLoop @@ -112,6 +113,16 @@ CompositorBridgeChild::Destroy() // From now on we can't send any message message. MessageLoop::current()->PostTask( NewRunnableFunction(DeferredDestroyCompositor, mCompositorBridgeParent, selfRef)); + + const ManagedContainer& textures = ManagedPTextureChild(); + for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) { + RefPtr texture = TextureClient::AsTextureClient(iter.Get()->GetKey()); + + if (texture) { + texture->Destroy(); + } + } + } // static @@ -170,7 +181,7 @@ CompositorBridgeChild::OpenSameProcess(CompositorBridgeParent* aParent) mCompositorBridgeParent = aParent; mCanSend = Open(mCompositorBridgeParent->GetIPCChannel(), - CompositorBridgeParent::CompositorLoop(), + CompositorThreadHolder::Loop(), ipc::ChildSide); return mCanSend; } @@ -750,6 +761,21 @@ CompositorBridgeChild::SendUpdateVisibleRegion(VisibilityCounter aCounter, return PCompositorBridgeChild::SendUpdateVisibleRegion(aCounter, aGuid, aRegion); } +PTextureChild* +CompositorBridgeChild::AllocPTextureChild(const SurfaceDescriptor&, + const LayersBackend&, + const TextureFlags&, + const uint64_t&) +{ + return TextureClient::CreateIPDLActor(); +} + +bool +CompositorBridgeChild::DeallocPTextureChild(PTextureChild* actor) +{ + return TextureClient::DestroyIPDLActor(actor); +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/ipc/CompositorBridgeChild.h b/gfx/layers/ipc/CompositorBridgeChild.h index 0087aca420..7531772c95 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.h +++ b/gfx/layers/ipc/CompositorBridgeChild.h @@ -96,6 +96,13 @@ public: virtual bool RecvHideAllPlugins(const uintptr_t& aParentWidget) override; + virtual PTextureChild* AllocPTextureChild(const SurfaceDescriptor& aSharedData, + const LayersBackend& aLayersBackend, + const TextureFlags& aFlags, + const uint64_t& aId) override; + + virtual bool DeallocPTextureChild(PTextureChild* actor) override; + /** * Request that the parent tell us when graphics are ready on GPU. * When we get that message, we bounce it to the TabParent via diff --git a/gfx/layers/ipc/CompositorBridgeParent.cpp b/gfx/layers/ipc/CompositorBridgeParent.cpp index 8433079de4..752ba38133 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.cpp +++ b/gfx/layers/ipc/CompositorBridgeParent.cpp @@ -37,6 +37,7 @@ #include "mozilla/layers/Compositor.h" // for Compositor #include "mozilla/layers/CompositorLRU.h" // for CompositorLRU #include "mozilla/layers/CompositorOGL.h" // for CompositorOGL +#include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/CompositorTypes.h" #include "mozilla/layers/FrameUniformityData.h" #include "mozilla/layers/ImageBridgeParent.h" @@ -89,11 +90,6 @@ namespace mozilla { -namespace gfx { -// See VRManagerChild.cpp -void ReleaseVRManagerParentSingleton(); -} // namespace gfx - namespace layers { using namespace mozilla::ipc; @@ -154,99 +150,30 @@ CompositorBridgeParent::ForEachIndirectLayerTree(const Lambda& aCallback) * compositor */ typedef map CompositorMap; -static CompositorMap* sCompositorMap; +static StaticAutoPtr sCompositorMap; -static void CreateCompositorMap() +void +CompositorBridgeParent::Initialize() { + EnsureLayerTreeMapReady(); + MOZ_ASSERT(!sCompositorMap); sCompositorMap = new CompositorMap; } -static void DestroyCompositorMap() +void +CompositorBridgeParent::Shutdown() { MOZ_ASSERT(sCompositorMap); MOZ_ASSERT(sCompositorMap->empty()); - delete sCompositorMap; sCompositorMap = nullptr; } -// See ImageBridgeChild.cpp -void ReleaseImageBridgeParentSingleton(); - -CompositorThreadHolder::CompositorThreadHolder() - : mCompositorThread(CreateCompositorThread()) +void +CompositorBridgeParent::FinishShutdown() { - MOZ_ASSERT(NS_IsMainThread()); - MOZ_COUNT_CTOR(CompositorThreadHolder); -} - -CompositorThreadHolder::~CompositorThreadHolder() -{ - MOZ_ASSERT(NS_IsMainThread()); - - MOZ_COUNT_DTOR(CompositorThreadHolder); - - DestroyCompositorThread(mCompositorThread); -} - -static StaticRefPtr sCompositorThreadHolder; -static bool sFinishedCompositorShutDown = false; - -CompositorThreadHolder* GetCompositorThreadHolder() -{ - return sCompositorThreadHolder; -} - -/* static */ Thread* -CompositorThreadHolder::CreateCompositorThread() -{ - MOZ_ASSERT(NS_IsMainThread()); - - MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!"); - - Thread* compositorThread = new Thread("Compositor"); - - Thread::Options options; - /* Timeout values are powers-of-two to enable us get better data. - 128ms is chosen for transient hangs because 8Hz should be the minimally - acceptable goal for Compositor responsiveness (normal goal is 60Hz). */ - options.transient_hang_timeout = 128; // milliseconds - /* 2048ms is chosen for permanent hangs because it's longer than most - * Compositor hangs seen in the wild, but is short enough to not miss getting - * native hang stacks. */ - options.permanent_hang_timeout = 2048; // milliseconds -#if defined(_WIN32) - /* With d3d9 the compositor thread creates native ui, see DeviceManagerD3D9. As - * such the thread is a gui thread, and must process a windows message queue or - * risk deadlocks. Chromium message loop TYPE_UI does exactly what we need. */ - options.message_loop_type = MessageLoop::TYPE_UI; -#endif - - if (!compositorThread->StartWithOptions(options)) { - delete compositorThread; - return nullptr; - } - - EnsureLayerTreeMapReady(); - CreateCompositorMap(); - - return compositorThread; -} - -/* static */ void -CompositorThreadHolder::DestroyCompositorThread(Thread* aCompositorThread) -{ - MOZ_ASSERT(NS_IsMainThread()); - - MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet."); - - DestroyCompositorMap(); - delete aCompositorThread; - sFinishedCompositorShutDown = true; -} - -static Thread* CompositorThread() { - return sCompositorThreadHolder ? sCompositorThreadHolder->GetCompositorThread() : nullptr; + // TODO: this should be empty by now... + sIndirectLayerTrees.clear(); } static void SetThreadPriority() @@ -305,12 +232,14 @@ CompositorVsyncScheduler::Observer::Destroy() mOwner = nullptr; } -CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorBridgeParent* aCompositorBridgeParent, nsIWidget* aWidget) +CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorBridgeParent* aCompositorBridgeParent, + widget::CompositorWidgetProxy* aWidgetProxy) : mCompositorBridgeParent(aCompositorBridgeParent) , mLastCompose(TimeStamp::Now()) , mIsObservingVsync(false) , mNeedsComposite(0) , mVsyncNotificationsSkipped(0) + , mCompositorVsyncDispatcher(aWidgetProxy->GetCompositorVsyncDispatcher()) , mCurrentCompositeTaskMonitor("CurrentCompositeTaskMonitor") , mCurrentCompositeTask(nullptr) , mSetNeedsCompositeMonitor("SetNeedsCompositeMonitor") @@ -324,9 +253,7 @@ CompositorVsyncScheduler::CompositorVsyncScheduler(CompositorBridgeParent* aComp #endif { MOZ_ASSERT(NS_IsMainThread()); - MOZ_ASSERT(aWidget != nullptr); mVsyncObserver = new Observer(this); - mCompositorVsyncDispatcher = aWidget->GetCompositorVsyncDispatcher(); #ifdef MOZ_WIDGET_GONK GeckoTouchDispatcher::GetInstance()->SetCompositorVsyncScheduler(this); @@ -348,7 +275,6 @@ CompositorVsyncScheduler::~CompositorVsyncScheduler() MOZ_ASSERT(!mVsyncObserver); // The CompositorVsyncDispatcher is cleaned up before this in the nsBaseWidget, which stops vsync listeners mCompositorBridgeParent = nullptr; - mCompositorVsyncDispatcher = nullptr; } #ifdef MOZ_WIDGET_GONK @@ -362,7 +288,7 @@ CompositorVsyncScheduler::SetDisplay(bool aDisplayEnable) MOZ_ASSERT(NS_IsMainThread()); MonitorAutoLock lock(mSetDisplayMonitor); RefPtr task = - NewRunnableMethod(this, &CompositorVsyncScheduler::SetDisplay, aDisplayEnable); + NewCancelableRunnableMethod(this, &CompositorVsyncScheduler::SetDisplay, aDisplayEnable); mSetDisplayTask = task; ScheduleTask(task.forget(), 0); return; @@ -427,8 +353,8 @@ CompositorVsyncScheduler::PostCompositeTask(TimeStamp aCompositeTimestamp) MonitorAutoLock lock(mCurrentCompositeTaskMonitor); if (mCurrentCompositeTask == nullptr) { RefPtr task = - NewRunnableMethod(this, &CompositorVsyncScheduler::Composite, - aCompositeTimestamp); + NewCancelableRunnableMethod(this, &CompositorVsyncScheduler::Composite, + aCompositeTimestamp); mCurrentCompositeTask = task; ScheduleTask(task.forget(), 0); } @@ -481,7 +407,7 @@ CompositorVsyncScheduler::SetNeedsComposite() if (!CompositorBridgeParent::IsInCompositorThread()) { MonitorAutoLock lock(mSetNeedsCompositeMonitor); RefPtr task = - NewRunnableMethod(this, &CompositorVsyncScheduler::SetNeedsComposite); + NewCancelableRunnableMethod(this, &CompositorVsyncScheduler::SetNeedsComposite); mSetNeedsCompositeTask = task; ScheduleTask(task.forget(), 0); return; @@ -625,47 +551,13 @@ CompositorVsyncScheduler::DispatchVREvents(TimeStamp aVsyncTimestamp) vm->NotifyVsync(aVsyncTimestamp); } -void CompositorBridgeParent::StartUp() -{ - MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); - MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!"); - - sCompositorThreadHolder = new CompositorThreadHolder(); -} - -void CompositorBridgeParent::ShutDown() -{ - MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); - MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!"); - - ReleaseImageBridgeParentSingleton(); - ReleaseVRManagerParentSingleton(); - MediaSystemResourceService::Shutdown(); - - sCompositorThreadHolder = nullptr; - - // No locking is needed around sFinishedCompositorShutDown because it is only - // ever accessed on the main thread. - while (!sFinishedCompositorShutDown) { - NS_ProcessNextEvent(nullptr, true); - } - - // TODO: this should be empty by now... - sIndirectLayerTrees.clear(); -} - -MessageLoop* CompositorBridgeParent::CompositorLoop() -{ - return CompositorThread() ? CompositorThread()->message_loop() : nullptr; -} - void CompositorVsyncScheduler::ScheduleTask(already_AddRefed aTask, int aTime) { - MOZ_ASSERT(CompositorBridgeParent::CompositorLoop()); + MOZ_ASSERT(CompositorThreadHolder::Loop()); MOZ_ASSERT(aTime >= 0); - CompositorBridgeParent::CompositorLoop()->PostDelayedTask(Move(aTask), aTime); + CompositorThreadHolder::Loop()->PostDelayedTask(Move(aTask), aTime); } void @@ -684,6 +576,12 @@ CompositorVsyncScheduler::ComposeToTarget(gfx::DrawTarget* aTarget, const IntRec mCompositorBridgeParent->CompositeToTarget(aTarget, aRect); } +static inline MessageLoop* +CompositorLoop() +{ + return CompositorThreadHolder::Loop(); +} + CompositorBridgeParent::CompositorBridgeParent(widget::CompositorWidgetProxy* aWidget, CSSToLayoutDeviceScale aScale, bool aUseAPZ, @@ -701,7 +599,7 @@ CompositorBridgeParent::CompositorBridgeParent(widget::CompositorWidgetProxy* aW , mRootLayerTreeID(AllocateLayerTreeId()) , mOverrideComposeReadiness(false) , mForceCompositionTask(nullptr) - , mCompositorThreadHolder(sCompositorThreadHolder) + , mCompositorThreadHolder(CompositorThreadHolder::GetSingleton()) , mCompositorScheduler(nullptr) #if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) , mLastPluginUpdateLayerTreeId(0) @@ -713,6 +611,10 @@ CompositorBridgeParent::CompositorBridgeParent(widget::CompositorWidgetProxy* aW MOZ_ASSERT(CompositorThread(), "The compositor thread must be Initialized before instanciating a CompositorBridgeParent."); MOZ_COUNT_CTOR(CompositorBridgeParent); + + // Always run destructor on the main thread + SetMessageLoopToPostDestructionTo(MessageLoop::current()); + mCompositorID = 0; // FIXME: This holds on the the fact that right now the only thing that // can destroy this instance is initialized on the compositor thread after @@ -733,7 +635,7 @@ CompositorBridgeParent::CompositorBridgeParent(widget::CompositorWidgetProxy* aW mApzcTreeManager = new APZCTreeManager(); } - mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget->RealWidget()); + mCompositorScheduler = new CompositorVsyncScheduler(this, aWidget); LayerScope::SetPixelScale(aScale.scale); // mSelfRef is cleared in DeferredDestroy. @@ -756,6 +658,15 @@ CompositorBridgeParent::~CompositorBridgeParent() { MOZ_ASSERT(NS_IsMainThread()); MOZ_COUNT_DTOR(CompositorBridgeParent); + + InfallibleTArray textures; + ManagedPTextureParent(textures); + // We expect all textures to be destroyed by now. + MOZ_DIAGNOSTIC_ASSERT(textures.Length() == 0); + for (unsigned int i = 0; i < textures.Length(); ++i) { + RefPtr tex = TextureHost::AsTextureHost(textures[i]); + tex->DeallocateDeviceData(); + } } void @@ -981,7 +892,7 @@ CompositorBridgeParent::ActorDestroy(ActorDestroyReason why) // We must keep the compositor parent alive untill the code handling message // reception is finished on this thread. mSelfRef = this; - MessageLoop::current()->PostTask(NewRunnableMethod(this,&CompositorBridgeParent::DeferredDestroy)); + MessageLoop::current()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::DeferredDestroy)); } @@ -1113,7 +1024,10 @@ CompositorBridgeParent::ScheduleResumeOnCompositorThread(int width, int height) MonitorAutoLock lock(mResumeCompositionMonitor); MOZ_ASSERT(CompositorLoop()); - CompositorLoop()->PostTask(NewRunnableMethod(this, &CompositorBridgeParent::ResumeCompositionAndResize, width, height)); + CompositorLoop()->PostTask(NewRunnableMethod + (this, + &CompositorBridgeParent::ResumeCompositionAndResize, + width, height)); // Wait until the resume has actually been processed by the compositor thread lock.Wait(); @@ -1239,8 +1153,7 @@ CompositorBridgeParent::CompositeToTarget(DrawTarget* aTarget, const gfx::IntRec // to local pages, hide every plugin associated with the window. if (!hasRemoteContent && BrowserTabsRemoteAutostart() && mCachedPluginData.Length()) { - nsIWidget* widget = GetWidgetProxy()->RealWidget(); - Unused << SendHideAllPlugins(reinterpret_cast(widget)); + Unused << SendHideAllPlugins(GetWidgetProxy()->GetWidgetKey()); mCachedPluginData.Clear(); } #endif @@ -1365,7 +1278,8 @@ CompositorBridgeParent::ScheduleRotationOnCompositorThread(const TargetConfig& a if (mForceCompositionTask != nullptr) { mForceCompositionTask->Cancel(); } - RefPtr task = NewRunnableMethod(this, &CompositorBridgeParent::ForceComposition); + RefPtr task = + NewCancelableRunnableMethod(this, &CompositorBridgeParent::ForceComposition); mForceCompositionTask = task; ScheduleTask(task.forget(), gfxPrefs::OrientationSyncMillis()); } @@ -1865,7 +1779,7 @@ InsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp) CompositorBridgeParent::PostInsertVsyncProfilerMarker(TimeStamp aVsyncTimestamp) { // Called in the vsync thread - if (profiler_is_active() && sCompositorThreadHolder) { + if (profiler_is_active() && CompositorThreadHolder::IsActive()) { CompositorLoop()->PostTask( NewRunnableFunction(InsertVsyncProfilerMarker, aVsyncTimestamp)); } @@ -1895,11 +1809,12 @@ CompositorBridgeParent::RequestNotifyLayerTreeCleared(uint64_t aLayersId, Compos * hands off work to the CompositorBridgeParent it's associated with. */ class CrossProcessCompositorBridgeParent final : public PCompositorBridgeParent, - public ShadowLayersManager + public ShadowLayersManager, + public ISurfaceAllocator, + public ShmemAllocator { friend class CompositorBridgeParent; - NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CrossProcessCompositorBridgeParent) public: explicit CrossProcessCompositorBridgeParent(Transport* aTransport) : mTransport(aTransport) @@ -1908,6 +1823,8 @@ public: , mDestroyCalled(false) { MOZ_ASSERT(NS_IsMainThread()); + // Always run destructor on the main thread + SetMessageLoopToPostDestructionTo(MessageLoop::current()); } // IToplevelProtocol::CloneToplevel() @@ -2030,8 +1947,31 @@ public: TimeStamp& aCompositeStart, TimeStamp& aCompositeEnd); + virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData, + const LayersBackend& aLayersBackend, + const TextureFlags& aFlags, + const uint64_t& aId) override; + + virtual bool DeallocPTextureParent(PTextureParent* actor) override; + + virtual bool IsSameProcess() const override; + + virtual ShmemAllocator* AsShmemAllocator() override { return this; } + + virtual bool AllocShmem(size_t aSize, + mozilla::ipc::SharedMemory::SharedMemoryType aType, + mozilla::ipc::Shmem* aShmem) override; + + virtual bool AllocUnsafeShmem(size_t aSize, + mozilla::ipc::SharedMemory::SharedMemoryType aType, + mozilla::ipc::Shmem* aShmem) override; + + virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) override; + protected: - void OnChannelConnected(int32_t pid) override { mCompositorThreadHolder = sCompositorThreadHolder; } + void OnChannelConnected(int32_t pid) override { + mCompositorThreadHolder = CompositorThreadHolder::GetSingleton(); + } private: // Private destructor, to discourage deletion outside of Release(): virtual ~CrossProcessCompositorBridgeParent(); @@ -2106,11 +2046,12 @@ CompositorBridgeParent::ResetCompositor(const nsTArray& aBackendH { MonitorAutoLock lock(mResetCompositorMonitor); - CompositorLoop()->PostTask( - NewRunnableMethod(this, - &CompositorBridgeParent::ResetCompositorTask, - aBackendHints, - &newIdentifier)); + CompositorLoop()->PostTask(NewRunnableMethod + >, + Maybe*>(this, + &CompositorBridgeParent::ResetCompositorTask, + aBackendHints, + &newIdentifier)); mResetCompositorMonitor.Wait(); } @@ -2242,6 +2183,49 @@ CompositorBridgeParent::GetIndirectShadowTree(uint64_t aId) return &cit->second; } +PTextureParent* +CompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData, + const LayersBackend& aLayersBackend, + const TextureFlags& aFlags, + const uint64_t& aId) +{ + return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags); +} + +bool +CompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor) +{ + return TextureHost::DestroyIPDLActor(actor); +} + +bool +CompositorBridgeParent::AllocShmem(size_t aSize, + ipc::SharedMemory::SharedMemoryType aType, + ipc::Shmem* aShmem) +{ + return PCompositorBridgeParent::AllocShmem(aSize, aType, aShmem); +} + +bool +CompositorBridgeParent::AllocUnsafeShmem(size_t aSize, + ipc::SharedMemory::SharedMemoryType aType, + ipc::Shmem* aShmem) +{ + return PCompositorBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem); +} + +void +CompositorBridgeParent::DeallocShmem(ipc::Shmem& aShmem) +{ + PCompositorBridgeParent::DeallocShmem(aShmem); +} + +bool +CompositorBridgeParent::IsSameProcess() const +{ + return OtherPid() == base::GetCurrentProcId(); +} + bool CrossProcessCompositorBridgeParent::RecvNotifyHidden(const uint64_t& id) { @@ -2278,8 +2262,7 @@ CrossProcessCompositorBridgeParent::ActorDestroy(ActorDestroyReason aWhy) // We must keep this object alive untill the code handling message // reception is finished on this thread. - MessageLoop::current()->PostTask( - NewRunnableMethod(this, &CrossProcessCompositorBridgeParent::DeferredDestroy)); + MessageLoop::current()->PostTask(NewRunnableMethod(this, &CrossProcessCompositorBridgeParent::DeferredDestroy)); } PLayerTransactionParent* @@ -2469,8 +2452,7 @@ CompositorBridgeParent::UpdatePluginWindowState(uint64_t aId) return false; } - nsIWidget* widget = GetWidgetProxy()->RealWidget(); - uintptr_t parentWidget = reinterpret_cast(widget); + uintptr_t parentWidget = GetWidgetProxy()->GetWidgetKey(); // We will pass through here in cases where the previous shadow layer // tree contained visible plugins and the new tree does not. All we need @@ -2555,8 +2537,7 @@ CompositorBridgeParent::HideAllPluginWindows() return; } - nsIWidget* widget = GetWidgetProxy()->RealWidget(); - uintptr_t parentWidget = reinterpret_cast(widget); + uintptr_t parentWidget = GetWidgetProxy()->GetWidgetKey(); mDeferPluginWindows = true; mPluginWindowsHidden = true; @@ -2766,5 +2747,69 @@ CrossProcessCompositorBridgeParent::CloneToplevel( return nullptr; } +PTextureParent* +CrossProcessCompositorBridgeParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData, + const LayersBackend& aLayersBackend, + const TextureFlags& aFlags, + const uint64_t& aId) +{ + CompositorBridgeParent::LayerTreeState* state = nullptr; + + LayerTreeMap::iterator itr = sIndirectLayerTrees.find(aId); + if (sIndirectLayerTrees.end() != itr) { + state = &itr->second; + } + + TextureFlags flags = aFlags; + + if (!state || state->mPendingCompositorUpdates) { + // The compositor was recreated, and we're receiving layers updates for a + // a layer manager that will soon be discarded or invalidated. We can't + // return null because this will mess up deserialization later and we'll + // kill the content process. Instead, we signal that the underlying + // TextureHost should not attempt to access the compositor. + flags |= TextureFlags::INVALID_COMPOSITOR; + } else if (state->mLayerManager && state->mLayerManager->GetCompositor() && + aLayersBackend != state->mLayerManager->GetCompositor()->GetBackendType()) { + gfxDevCrash(gfx::LogReason::PAllocTextureBackendMismatch) << "Texture backend is wrong"; + } + + return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, aFlags); +} + +bool +CrossProcessCompositorBridgeParent::DeallocPTextureParent(PTextureParent* actor) +{ + return TextureHost::DestroyIPDLActor(actor); +} + +bool +CrossProcessCompositorBridgeParent::AllocShmem(size_t aSize, + ipc::SharedMemory::SharedMemoryType aType, + ipc::Shmem* aShmem) +{ + return PCompositorBridgeParent::AllocShmem(aSize, aType, aShmem); +} + +bool +CrossProcessCompositorBridgeParent::AllocUnsafeShmem(size_t aSize, + ipc::SharedMemory::SharedMemoryType aType, + ipc::Shmem* aShmem) +{ + return PCompositorBridgeParent::AllocUnsafeShmem(aSize, aType, aShmem); +} + +void +CrossProcessCompositorBridgeParent::DeallocShmem(ipc::Shmem& aShmem) +{ + PCompositorBridgeParent::DeallocShmem(aShmem); +} + +bool +CrossProcessCompositorBridgeParent::IsSameProcess() const +{ + return OtherPid() == base::GetCurrentProcId(); +} + } // namespace layers } // namespace mozilla diff --git a/gfx/layers/ipc/CompositorBridgeParent.h b/gfx/layers/ipc/CompositorBridgeParent.h index c355cc398a..151979aa6e 100644 --- a/gfx/layers/ipc/CompositorBridgeParent.h +++ b/gfx/layers/ipc/CompositorBridgeParent.h @@ -17,9 +17,6 @@ #include // for uint64_t #include "Layers.h" // for Layer -#include "base/basictypes.h" // for DISALLOW_EVIL_CONSTRUCTORS -#include "base/platform_thread.h" // for PlatformThreadId -#include "base/thread.h" // for Thread #include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2 #include "mozilla/Attributes.h" // for override #include "mozilla/Maybe.h" @@ -29,7 +26,9 @@ #include "mozilla/dom/ipc/IdType.h" #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/ipc/ProtocolUtils.h" +#include "mozilla/ipc/SharedMemory.h" #include "mozilla/layers/GeckoContentController.h" +#include "mozilla/layers/ISurfaceAllocator.h" // for ShmemAllocator #include "mozilla/layers/LayersMessages.h" // for TargetConfig #include "mozilla/layers/PCompositorBridgeParent.h" #include "mozilla/layers/ShadowLayersManager.h" // for ShadowLayersManager @@ -53,6 +52,7 @@ class DrawTarget; namespace ipc { class GeckoChildProcessHost; +class Shmem; } // namespace ipc namespace layers { @@ -65,6 +65,7 @@ class LayerManagerComposite; class LayerTransactionParent; class PAPZParent; class CrossProcessCompositorBridgeParent; +class CompositorThreadHolder; struct ScopedLayerTreeRegistration { @@ -78,28 +79,6 @@ private: uint64_t mLayersId; }; -class CompositorThreadHolder final -{ - NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorThreadHolder) - -public: - CompositorThreadHolder(); - - base::Thread* GetCompositorThread() const { - return mCompositorThread; - } - -private: - ~CompositorThreadHolder(); - - base::Thread* const mCompositorThread; - - static base::Thread* CreateCompositorThread(); - static void DestroyCompositorThread(base::Thread* aCompositorThread); - - friend class CompositorBridgeParent; -}; - /** * Manages the vsync (de)registration and tracking on behalf of the * compositor when it need to paint. @@ -110,7 +89,8 @@ class CompositorVsyncScheduler NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CompositorVsyncScheduler) public: - explicit CompositorVsyncScheduler(CompositorBridgeParent* aCompositorBridgeParent, nsIWidget* aWidget); + explicit CompositorVsyncScheduler(CompositorBridgeParent* aCompositorBridgeParent, + widget::CompositorWidgetProxy* aWidgetProxy); #ifdef MOZ_WIDGET_GONK // emulator-ics never trigger the display on/off, so compositor will always @@ -222,10 +202,12 @@ protected: }; class CompositorBridgeParent final : public PCompositorBridgeParent, - public ShadowLayersManager + public ShadowLayersManager, + public ISurfaceAllocator, + public ShmemAllocator { - NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorBridgeParent) friend class CompositorVsyncScheduler; + friend class CompositorThreadHolder; public: explicit CompositorBridgeParent(widget::CompositorWidgetProxy* aWidget, @@ -299,6 +281,26 @@ public: const nsTArray& aTargets) override; virtual AsyncCompositionManager* GetCompositionManager(LayerTransactionParent* aLayerTree) override { return mCompositionManager; } + virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData, + const LayersBackend& aLayersBackend, + const TextureFlags& aFlags, + const uint64_t& aId) override; + virtual bool DeallocPTextureParent(PTextureParent* actor) override; + + virtual bool IsSameProcess() const override; + + virtual ShmemAllocator* AsShmemAllocator() override { return this; } + + virtual bool AllocShmem(size_t aSize, + mozilla::ipc::SharedMemory::SharedMemoryType aType, + mozilla::ipc::Shmem* aShmem) override; + + virtual bool AllocUnsafeShmem(size_t aSize, + mozilla::ipc::SharedMemory::SharedMemoryType aType, + mozilla::ipc::Shmem* aShmem) override; + + virtual void DeallocShmem(mozilla::ipc::Shmem& aShmem) override; + /** * Request that the compositor be recreated due to a shared device reset. * This must be called on the main thread, and blocks until a task posted @@ -370,27 +372,6 @@ public: */ static CompositorBridgeParent* GetCompositor(uint64_t id); - /** - * Returns the compositor thread's message loop. - * - * This message loop is used by CompositorBridgeParent, ImageBridgeParent, - * and VRManagerParent - */ - static MessageLoop* CompositorLoop(); - - /** - * Creates the compositor thread and the global compositor map. - */ - static void StartUp(); - - /** - * Waits for all [CrossProcess]CompositorBridgeParent's to be gone, - * and destroys the compositor thread and global compositor map. - * - * Does not return until all of that has completed. - */ - static void ShutDown(); - /** * Allocate an ID that can be used to refer to a layer tree and * associated resources that live only on the compositor thread. @@ -516,6 +497,9 @@ public: dom::ContentParent* aContentParent, const dom::TabId& aTabId, dom::TabParent* aBrowserParent); + bool AsyncPanZoomEnabled() const { + return !!mApzcTreeManager; + } protected: // Protected destructor, to discourage deletion outside of Release(): @@ -556,7 +540,22 @@ protected: */ static CompositorBridgeParent* RemoveCompositor(uint64_t id); - /** + /** + * Creates the global compositor map. + */ + static void Initialize(); + + /** + * Destroys the compositor thread and global compositor map. + */ + static void Shutdown(); + + /** + * Finish the shutdown operation on the compositor thread. + */ + static void FinishShutdown(); + + /** * Return true if current state allows compositing, that is * finishing a layers transaction. */ diff --git a/gfx/layers/ipc/CompositorThread.cpp b/gfx/layers/ipc/CompositorThread.cpp new file mode 100644 index 0000000000..969ad9f691 --- /dev/null +++ b/gfx/layers/ipc/CompositorThread.cpp @@ -0,0 +1,146 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 sts=2 ts=8 et tw=99 : */ +/* 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 "CompositorThread.h" +#include "MainThreadUtils.h" +#include "nsThreadUtils.h" +#include "CompositorBridgeParent.h" +#include "mozilla/media/MediaSystemResourceService.h" + +namespace mozilla { + +namespace gfx { +// See VRManagerChild.cpp +void ReleaseVRManagerParentSingleton(); +} // namespace gfx + +namespace layers { + +static StaticRefPtr sCompositorThreadHolder; +static bool sFinishedCompositorShutDown = false; + +// See ImageBridgeChild.cpp +void ReleaseImageBridgeParentSingleton(); + +CompositorThreadHolder* GetCompositorThreadHolder() +{ + return sCompositorThreadHolder; +} + +base::Thread* +CompositorThread() +{ + return sCompositorThreadHolder + ? sCompositorThreadHolder->GetCompositorThread() + : nullptr; +} + +/* static */ MessageLoop* +CompositorThreadHolder::Loop() +{ + return CompositorThread() ? CompositorThread()->message_loop() : nullptr; +} + +CompositorThreadHolder* +CompositorThreadHolder::GetSingleton() +{ + return sCompositorThreadHolder; +} + +CompositorThreadHolder::CompositorThreadHolder() + : mCompositorThread(CreateCompositorThread()) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_COUNT_CTOR(CompositorThreadHolder); +} + +CompositorThreadHolder::~CompositorThreadHolder() +{ + MOZ_ASSERT(NS_IsMainThread()); + + MOZ_COUNT_DTOR(CompositorThreadHolder); + + DestroyCompositorThread(mCompositorThread); +} + +/* static */ void +CompositorThreadHolder::DestroyCompositorThread(base::Thread* aCompositorThread) +{ + MOZ_ASSERT(NS_IsMainThread()); + + MOZ_ASSERT(!sCompositorThreadHolder, "We shouldn't be destroying the compositor thread yet."); + + CompositorBridgeParent::Shutdown(); + delete aCompositorThread; + sFinishedCompositorShutDown = true; +} + +/* static */ base::Thread* +CompositorThreadHolder::CreateCompositorThread() +{ + MOZ_ASSERT(NS_IsMainThread()); + + MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!"); + + base::Thread* compositorThread = new base::Thread("Compositor"); + + base::Thread::Options options; + /* Timeout values are powers-of-two to enable us get better data. + 128ms is chosen for transient hangs because 8Hz should be the minimally + acceptable goal for Compositor responsiveness (normal goal is 60Hz). */ + options.transient_hang_timeout = 128; // milliseconds + /* 2048ms is chosen for permanent hangs because it's longer than most + * Compositor hangs seen in the wild, but is short enough to not miss getting + * native hang stacks. */ + options.permanent_hang_timeout = 2048; // milliseconds +#if defined(_WIN32) + /* With d3d9 the compositor thread creates native ui, see DeviceManagerD3D9. As + * such the thread is a gui thread, and must process a windows message queue or + * risk deadlocks. Chromium message loop TYPE_UI does exactly what we need. */ + options.message_loop_type = MessageLoop::TYPE_UI; +#endif + + if (!compositorThread->StartWithOptions(options)) { + delete compositorThread; + return nullptr; + } + + CompositorBridgeParent::Initialize(); + + return compositorThread; +} + +void +CompositorThreadHolder::Start() +{ + MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); + MOZ_ASSERT(!sCompositorThreadHolder, "The compositor thread has already been started!"); + + sCompositorThreadHolder = new CompositorThreadHolder(); +} + +void +CompositorThreadHolder::Shutdown() +{ + MOZ_ASSERT(NS_IsMainThread(), "Should be on the main Thread!"); + MOZ_ASSERT(sCompositorThreadHolder, "The compositor thread has already been shut down!"); + + ReleaseImageBridgeParentSingleton(); + gfx::ReleaseVRManagerParentSingleton(); + MediaSystemResourceService::Shutdown(); + + sCompositorThreadHolder = nullptr; + + // No locking is needed around sFinishedCompositorShutDown because it is only + // ever accessed on the main thread. + while (!sFinishedCompositorShutDown) { + NS_ProcessNextEvent(nullptr, true); + } + + CompositorBridgeParent::FinishShutdown(); +} + +} // namespace mozilla +} // namespace layers diff --git a/gfx/layers/ipc/CompositorThread.h b/gfx/layers/ipc/CompositorThread.h new file mode 100644 index 0000000000..7e0123a2ec --- /dev/null +++ b/gfx/layers/ipc/CompositorThread.h @@ -0,0 +1,65 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set sw=2 sts=2 ts=8 et tw=99 : */ +/* 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_layers_CompositorThread_h +#define mozilla_layers_CompositorThread_h + +#include "base/basictypes.h" // for DISALLOW_EVIL_CONSTRUCTORS +#include "base/platform_thread.h" // for PlatformThreadId +#include "base/thread.h" // for Thread +#include "base/message_loop.h" +#include "nsISupportsImpl.h" +#include "ThreadSafeRefcountingWithMainThreadDestruction.h" + +namespace mozilla { +namespace layers { + +class CompositorThreadHolder final +{ + NS_INLINE_DECL_THREADSAFE_REFCOUNTING_WITH_MAIN_THREAD_DESTRUCTION(CompositorThreadHolder) + +public: + CompositorThreadHolder(); + + base::Thread* GetCompositorThread() const { + return mCompositorThread; + } + + static CompositorThreadHolder* GetSingleton(); + + static bool IsActive() { + return !!GetSingleton(); + } + + /** + * Creates the compositor thread and the global compositor map. + */ + static void Start(); + + /* + * Waits for all [CrossProcess]CompositorBridgeParents to shutdown and + * releases compositor-thread owned resources. + */ + static void Shutdown(); + + static MessageLoop* Loop(); + +private: + ~CompositorThreadHolder(); + + base::Thread* const mCompositorThread; + + static base::Thread* CreateCompositorThread(); + static void DestroyCompositorThread(base::Thread* aCompositorThread); + + friend class CompositorBridgeParent; +}; + +base::Thread* CompositorThread(); + +} // namespace layers +} // namespace mozilla + +#endif // mozilla_layers_CompositorThread_h diff --git a/gfx/layers/ipc/ImageBridgeChild.cpp b/gfx/layers/ipc/ImageBridgeChild.cpp index eae77d0be3..89b834970d 100644 --- a/gfx/layers/ipc/ImageBridgeChild.cpp +++ b/gfx/layers/ipc/ImageBridgeChild.cpp @@ -24,7 +24,7 @@ #include "mozilla/media/MediaSystemResourceManager.h" // for MediaSystemResourceManager #include "mozilla/media/MediaSystemResourceManagerChild.h" // for MediaSystemResourceManagerChild #include "mozilla/layers/CompositableClient.h" // for CompositableChild, etc -#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent +#include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/ISurfaceAllocator.h" // for ISurfaceAllocator #include "mozilla/layers/ImageClient.h" // for ImageClient #include "mozilla/layers/LayersMessages.h" // for CompositableOperation @@ -842,7 +842,7 @@ bool ImageBridgeChild::StartUpOnThread(Thread* aThread) } sImageBridgeChildSingleton = new ImageBridgeChild(); sImageBridgeParentSingleton = new ImageBridgeParent( - CompositorBridgeParent::CompositorLoop(), nullptr, base::GetCurrentProcId()); + CompositorThreadHolder::Loop(), nullptr, base::GetCurrentProcId()); sImageBridgeChildSingleton->ConnectAsync(sImageBridgeParentSingleton); sImageBridgeChildSingleton->GetMessageLoop()->PostTask( NewRunnableFunction(CallSendImageBridgeThreadId, diff --git a/gfx/layers/ipc/ImageBridgeParent.cpp b/gfx/layers/ipc/ImageBridgeParent.cpp index a066389fb1..134337eecf 100644 --- a/gfx/layers/ipc/ImageBridgeParent.cpp +++ b/gfx/layers/ipc/ImageBridgeParent.cpp @@ -19,7 +19,6 @@ #include "mozilla/ipc/GeckoChildProcessHost.h" #include "mozilla/media/MediaSystemResourceManagerParent.h" // for MediaSystemResourceManagerParent #include "mozilla/layers/CompositableTransactionParent.h" -#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent #include "mozilla/layers/LayerManagerComposite.h" #include "mozilla/layers/LayersMessages.h" // for EditReply #include "mozilla/layers/LayersSurfaces.h" // for PGrallocBufferParent @@ -106,8 +105,7 @@ ImageBridgeParent::ActorDestroy(ActorDestroyReason aWhy) mSubprocess = nullptr; } - MessageLoop::current()->PostTask( - NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy)); + MessageLoop::current()->PostTask(NewRunnableMethod(this, &ImageBridgeParent::DeferredDestroy)); // It is very important that this method gets called at shutdown (be it a clean // or an abnormal shutdown), because DeferredDestroy is what clears mSelfRef. @@ -201,7 +199,7 @@ ConnectImageBridgeInParentProcess(ImageBridgeParent* aBridge, /*static*/ PImageBridgeParent* ImageBridgeParent::Create(Transport* aTransport, ProcessId aChildProcessId, GeckoChildProcessHost* aProcessHost) { - MessageLoop* loop = CompositorBridgeParent::CompositorLoop(); + MessageLoop* loop = CompositorThreadHolder::Loop(); RefPtr bridge = new ImageBridgeParent(loop, aTransport, aChildProcessId); if (aProcessHost) { diff --git a/gfx/layers/ipc/ImageBridgeParent.h b/gfx/layers/ipc/ImageBridgeParent.h index b0f3c286a5..875aa93887 100644 --- a/gfx/layers/ipc/ImageBridgeParent.h +++ b/gfx/layers/ipc/ImageBridgeParent.h @@ -14,7 +14,7 @@ #include "mozilla/Attributes.h" // for override #include "mozilla/ipc/ProtocolUtils.h" #include "mozilla/ipc/SharedMemory.h" // for SharedMemory, etc -#include "mozilla/layers/CompositorBridgeParent.h" +#include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/PImageBridgeParent.h" #include "nsAutoPtr.h" // for nsRefPtr #include "nsISupportsImpl.h" diff --git a/gfx/layers/ipc/LayerTransactionChild.cpp b/gfx/layers/ipc/LayerTransactionChild.cpp index ee2d3a3820..f197281dc4 100644 --- a/gfx/layers/ipc/LayerTransactionChild.cpp +++ b/gfx/layers/ipc/LayerTransactionChild.cpp @@ -37,15 +37,6 @@ LayerTransactionChild::Destroy() MOZ_ASSERT(0 == ManagedPLayerChild().Count(), "layers should have been cleaned up by now"); - const ManagedContainer& textures = ManagedPTextureChild(); - for (auto iter = textures.ConstIter(); !iter.Done(); iter.Next()) { - RefPtr texture = TextureClient::AsTextureClient(iter.Get()->GetKey()); - - if (texture) { - texture->Destroy(); - } - } - SendShutdown(); } @@ -127,20 +118,5 @@ LayerTransactionChild::ActorDestroy(ActorDestroyReason why) #endif } -PTextureChild* -LayerTransactionChild::AllocPTextureChild(const SurfaceDescriptor&, - const LayersBackend&, - const TextureFlags&) -{ - MOZ_ASSERT(!mDestroyed); - return TextureClient::CreateIPDLActor(); -} - -bool -LayerTransactionChild::DeallocPTextureChild(PTextureChild* actor) -{ - return TextureClient::DestroyIPDLActor(actor); -} - } // namespace layers } // namespace mozilla diff --git a/gfx/layers/ipc/LayerTransactionChild.h b/gfx/layers/ipc/LayerTransactionChild.h index 511f6e9ac1..b3cedab2a4 100644 --- a/gfx/layers/ipc/LayerTransactionChild.h +++ b/gfx/layers/ipc/LayerTransactionChild.h @@ -65,11 +65,6 @@ protected: virtual PCompositableChild* AllocPCompositableChild(const TextureInfo& aInfo) override; virtual bool DeallocPCompositableChild(PCompositableChild* actor) override; - virtual PTextureChild* AllocPTextureChild(const SurfaceDescriptor& aSharedData, - const LayersBackend& aLayersBackend, - const TextureFlags& aFlags) override; - virtual bool DeallocPTextureChild(PTextureChild* actor) override; - virtual bool RecvParentAsyncMessages(InfallibleTArray&& aMessages) override; diff --git a/gfx/layers/ipc/LayerTransactionParent.cpp b/gfx/layers/ipc/LayerTransactionParent.cpp index a448a8d4d3..404a06ed1e 100644 --- a/gfx/layers/ipc/LayerTransactionParent.cpp +++ b/gfx/layers/ipc/LayerTransactionParent.cpp @@ -177,14 +177,6 @@ LayerTransactionParent::Destroy() static_cast(iter.Get()->GetKey()); slp->Destroy(); } - InfallibleTArray textures; - ManagedPTextureParent(textures); - // We expect all textures to be destroyed by now. - MOZ_DIAGNOSTIC_ASSERT(textures.Length() == 0); - for (unsigned int i = 0; i < textures.Length(); ++i) { - RefPtr tex = TextureHost::AsTextureHost(textures[i]); - tex->DeallocateDeviceData(); - } mDestroyed = true; } @@ -960,33 +952,6 @@ LayerTransactionParent::DeallocPCompositableParent(PCompositableParent* aActor) return CompositableHost::DestroyIPDLActor(aActor); } -PTextureParent* -LayerTransactionParent::AllocPTextureParent(const SurfaceDescriptor& aSharedData, - const LayersBackend& aLayersBackend, - const TextureFlags& aFlags) -{ - TextureFlags flags = aFlags; - - if (mPendingCompositorUpdates) { - // The compositor was recreated, and we're receiving layers updates for a - // a layer manager that will soon be discarded or invalidated. We can't - // return null because this will mess up deserialization later and we'll - // kill the content process. Instead, we signal that the underlying - // TextureHost should not attempt to access the compositor. - flags |= TextureFlags::INVALID_COMPOSITOR; - } else if (aLayersBackend != mLayerManager->GetCompositor()->GetBackendType()) { - gfxDevCrash(gfx::LogReason::PAllocTextureBackendMismatch) << "Texture backend is wrong"; - } - - return TextureHost::CreateIPDLActor(this, aSharedData, aLayersBackend, flags); -} - -bool -LayerTransactionParent::DeallocPTextureParent(PTextureParent* actor) -{ - return TextureHost::DestroyIPDLActor(actor); -} - bool LayerTransactionParent::RecvChildAsyncMessages(InfallibleTArray&& aMessages) { diff --git a/gfx/layers/ipc/LayerTransactionParent.h b/gfx/layers/ipc/LayerTransactionParent.h index 353bf77743..ac2b76e033 100644 --- a/gfx/layers/ipc/LayerTransactionParent.h +++ b/gfx/layers/ipc/LayerTransactionParent.h @@ -159,11 +159,6 @@ protected: virtual PCompositableParent* AllocPCompositableParent(const TextureInfo& aInfo) override; virtual bool DeallocPCompositableParent(PCompositableParent* actor) override; - virtual PTextureParent* AllocPTextureParent(const SurfaceDescriptor& aSharedData, - const LayersBackend& aLayersBackend, - const TextureFlags& aFlags) override; - virtual bool DeallocPTextureParent(PTextureParent* actor) override; - virtual bool RecvChildAsyncMessages(InfallibleTArray&& aMessages) override; diff --git a/gfx/layers/ipc/PCompositorBridge.ipdl b/gfx/layers/ipc/PCompositorBridge.ipdl index ee18ea64a1..1fd80061f7 100644 --- a/gfx/layers/ipc/PCompositorBridge.ipdl +++ b/gfx/layers/ipc/PCompositorBridge.ipdl @@ -8,8 +8,11 @@ include LayersSurfaces; include LayersMessages; include protocol PBrowser; +include protocol PCompositable; +include protocol PImageContainer; include protocol PLayer; include protocol PLayerTransaction; +include protocol PTexture; include "mozilla/GfxMessageUtils.h"; using struct mozilla::null_t from "ipc/IPCMessageUtils.h"; @@ -28,6 +31,7 @@ using mozilla::LayoutDeviceIntRegion from "Units.h"; using mozilla::VisibilityCounter from "VisibilityIPC.h"; using class mozilla::TimeStamp from "mozilla/TimeStamp.h"; using class mozilla::layers::FrameUniformityData from "mozilla/layers/FrameUniformityData.h"; +using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h"; namespace mozilla { namespace layers { @@ -42,6 +46,7 @@ sync protocol PCompositorBridge { // A Compositor manages a single Layer Manager (PLayerTransaction) manages PLayerTransaction; + manages PTexture; child: // The child should invalidate retained layers. This is used for local @@ -187,6 +192,8 @@ parent: ScrollableLayerGuid guid, CSSIntRegion region); + async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags, uint64_t id); + child: // Send back Compositor Frame Metrics from APZCs so tiled layers can // update progressively. diff --git a/gfx/layers/ipc/PLayerTransaction.ipdl b/gfx/layers/ipc/PLayerTransaction.ipdl index d99febd3a1..580f68be15 100644 --- a/gfx/layers/ipc/PLayerTransaction.ipdl +++ b/gfx/layers/ipc/PLayerTransaction.ipdl @@ -17,7 +17,6 @@ include "mozilla/GfxMessageUtils.h"; using struct mozilla::layers::TextureInfo from "mozilla/layers/CompositorTypes.h"; using struct mozilla::void_t from "ipc/IPCMessageUtils.h"; -using mozilla::layers::TextureFlags from "mozilla/layers/CompositorTypes.h"; using class mozilla::layers::APZTestData from "mozilla/layers/APZTestData.h"; using mozilla::layers::FrameMetrics::ViewID from "FrameMetrics.h"; using struct mozilla::layers::ScrollableLayerGuid from "FrameMetrics.h"; @@ -43,7 +42,6 @@ sync protocol PLayerTransaction { manager PCompositorBridge; manages PLayer; manages PCompositable; - manages PTexture; child: async ParentAsyncMessages(AsyncParentMessageData[] aMessages); @@ -51,7 +49,6 @@ child: parent: async PLayer(); async PCompositable(TextureInfo aTextureInfo); - async PTexture(SurfaceDescriptor aSharedData, LayersBackend aBackend, TextureFlags aTextureFlags); // The isFirstPaint flag can be used to indicate that this is the first update // for a particular document. diff --git a/gfx/layers/ipc/PTexture.ipdl b/gfx/layers/ipc/PTexture.ipdl index b1b1893c21..a0ed795208 100644 --- a/gfx/layers/ipc/PTexture.ipdl +++ b/gfx/layers/ipc/PTexture.ipdl @@ -7,6 +7,7 @@ include LayersSurfaces; include protocol PLayerTransaction; +include protocol PCompositorBridge; include protocol PImageBridge; include "mozilla/GfxMessageUtils.h"; @@ -20,7 +21,7 @@ namespace layers { * PTexture is the IPDL glue between a TextureClient and a TextureHost. */ sync protocol PTexture { - manager PImageBridge or PLayerTransaction; + manager PImageBridge or PCompositorBridge; child: async __delete__(); diff --git a/gfx/layers/ipc/RemoteContentController.cpp b/gfx/layers/ipc/RemoteContentController.cpp index 180ca065e3..7756c6b741 100644 --- a/gfx/layers/ipc/RemoteContentController.cpp +++ b/gfx/layers/ipc/RemoteContentController.cpp @@ -58,9 +58,11 @@ RemoteContentController::HandleDoubleTap(const CSSPoint& aPoint, if (MessageLoop::current() != mUILoop) { // We have to send this message from the "UI thread" (main // thread). - mUILoop->PostTask( - NewRunnableMethod(this, &RemoteContentController::HandleDoubleTap, - aPoint, aModifiers, aGuid)); + mUILoop->PostTask(NewRunnableMethod(this, + &RemoteContentController::HandleDoubleTap, + aPoint, aModifiers, aGuid)); return; } if (CanSend()) { @@ -77,9 +79,11 @@ RemoteContentController::HandleSingleTap(const CSSPoint& aPoint, if (MessageLoop::current() != mUILoop) { // We have to send this message from the "UI thread" (main // thread). - mUILoop->PostTask( - NewRunnableMethod(this, &RemoteContentController::HandleSingleTap, - aPoint, aModifiers, aGuid)); + mUILoop->PostTask(NewRunnableMethod(this, + &RemoteContentController::HandleSingleTap, + aPoint, aModifiers, aGuid)); return; } @@ -110,9 +114,12 @@ RemoteContentController::HandleLongTap(const CSSPoint& aPoint, if (MessageLoop::current() != mUILoop) { // We have to send this message from the "UI thread" (main // thread). - mUILoop->PostTask( - NewRunnableMethod(this, &RemoteContentController::HandleLongTap, - aPoint, aModifiers, aGuid, aInputBlockId)); + mUILoop->PostTask(NewRunnableMethod(this, + &RemoteContentController::HandleLongTap, + aPoint, aModifiers, aGuid, aInputBlockId)); return; } if (CanSend()) { @@ -150,9 +157,11 @@ RemoteContentController::NotifyAPZStateChange(const ScrollableLayerGuid& aGuid, int aArg) { if (MessageLoop::current() != mUILoop) { - mUILoop->PostTask( - NewRunnableMethod(this, &RemoteContentController::NotifyAPZStateChange, - aGuid, aChange, aArg)); + mUILoop->PostTask(NewRunnableMethod(this, + &RemoteContentController::NotifyAPZStateChange, + aGuid, aChange, aArg)); return; } if (CanSend()) { @@ -165,9 +174,10 @@ RemoteContentController::NotifyMozMouseScrollEvent(const FrameMetrics::ViewID& a const nsString& aEvent) { if (MessageLoop::current() != mUILoop) { - mUILoop->PostTask( - NewRunnableMethod(this, &RemoteContentController::NotifyMozMouseScrollEvent, - aScrollId, aEvent)); + mUILoop->PostTask(NewRunnableMethod(this, + &RemoteContentController::NotifyMozMouseScrollEvent, + aScrollId, aEvent)); return; } @@ -217,9 +227,11 @@ RemoteContentController::RecvContentReceivedInputBlock(const ScrollableLayerGuid return false; } if (RefPtr apzcTreeManager = GetApzcTreeManager()) { - APZThreadUtils::RunOnControllerThread(NewRunnableMethod( - apzcTreeManager.get(), &APZCTreeManager::ContentReceivedInputBlock, - aInputBlockId, aPreventDefault)); + APZThreadUtils::RunOnControllerThread(NewRunnableMethod(apzcTreeManager, + &APZCTreeManager::ContentReceivedInputBlock, + aInputBlockId, aPreventDefault)); + } return true; } @@ -231,10 +243,11 @@ RemoteContentController::RecvStartScrollbarDrag(const AsyncDragMetrics& aDragMet ScrollableLayerGuid guid(mLayersId, aDragMetrics.mPresShellId, aDragMetrics.mViewId); - APZThreadUtils::RunOnControllerThread( - NewRunnableMethod(apzcTreeManager.get(), - &APZCTreeManager::StartScrollbarDrag, - guid, aDragMetrics)); + APZThreadUtils::RunOnControllerThread(NewRunnableMethod + (apzcTreeManager, + &APZCTreeManager::StartScrollbarDrag, + guid, aDragMetrics)); } return true; } @@ -254,9 +267,11 @@ RemoteContentController::RecvSetTargetAPZC(const uint64_t& aInputBlockId, // need a local var to disambiguate between the SetTargetAPZC overloads. void (APZCTreeManager::*setTargetApzcFunc)(uint64_t, const nsTArray&) = &APZCTreeManager::SetTargetAPZC; - APZThreadUtils::RunOnControllerThread(NewRunnableMethod( - apzcTreeManager.get(), setTargetApzcFunc, - aInputBlockId, aTargets)); + APZThreadUtils::RunOnControllerThread(NewRunnableMethod + >> + (apzcTreeManager, setTargetApzcFunc, aInputBlockId, aTargets)); + } return true; } @@ -266,9 +281,12 @@ RemoteContentController::RecvSetAllowedTouchBehavior(const uint64_t& aInputBlock nsTArray&& aFlags) { if (RefPtr apzcTreeManager = GetApzcTreeManager()) { - APZThreadUtils::RunOnControllerThread(NewRunnableMethod( - apzcTreeManager.get(), &APZCTreeManager::SetAllowedTouchBehavior, - aInputBlockId, Move(aFlags))); + APZThreadUtils::RunOnControllerThread(NewRunnableMethod + >> + (apzcTreeManager, + &APZCTreeManager::SetAllowedTouchBehavior, + aInputBlockId, Move(aFlags))); } return true; } diff --git a/gfx/layers/ipc/ShadowLayers.cpp b/gfx/layers/ipc/ShadowLayers.cpp index 7f9d40faf0..a24d4eccab 100644 --- a/gfx/layers/ipc/ShadowLayers.cpp +++ b/gfx/layers/ipc/ShadowLayers.cpp @@ -21,6 +21,7 @@ #include "mozilla/Assertions.h" // for MOZ_ASSERT, etc #include "mozilla/gfx/Point.h" // for IntSize #include "mozilla/layers/CompositableClient.h" // for CompositableClient, etc +#include "mozilla/layers/CompositorBridgeChild.h" #include "mozilla/layers/ImageDataSerializer.h" #include "mozilla/layers/LayersMessages.h" // for Edit, etc #include "mozilla/layers/LayersSurfaces.h" // for SurfaceDescriptor, etc @@ -1056,10 +1057,11 @@ ShadowLayerForwarder::CreateTexture(const SurfaceDescriptor& aSharedData, TextureFlags aFlags) { if (!HasShadowManager() || - !mShadowManager->IPCOpen()) { + !mShadowManager->IPCOpen() || + !mShadowManager->Manager()) { return nullptr; } - return mShadowManager->SendPTextureConstructor(aSharedData, aLayersBackend, aFlags); + return mShadowManager->Manager()->SendPTextureConstructor(aSharedData, aLayersBackend, aFlags, mShadowManager->GetId()); } diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index ba7c537326..4d796bfcdd 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -158,6 +158,7 @@ EXPORTS.mozilla.layers += [ 'ipc/CompositorBridgeChild.h', 'ipc/CompositorBridgeParent.h', 'ipc/CompositorLRU.h', + 'ipc/CompositorThread.h', 'ipc/FenceUtils.h', 'ipc/GonkNativeHandle.h', 'ipc/GonkNativeHandleUtils.h', @@ -338,6 +339,7 @@ UNIFIED_SOURCES += [ 'ipc/CompositorBridgeChild.cpp', 'ipc/CompositorBridgeParent.cpp', 'ipc/CompositorLRU.cpp', + 'ipc/CompositorThread.cpp', 'ipc/FenceUtils.cpp', 'ipc/ImageBridgeChild.cpp', 'ipc/ImageBridgeParent.cpp', diff --git a/gfx/thebes/SoftwareVsyncSource.cpp b/gfx/thebes/SoftwareVsyncSource.cpp index ccc6b59a14..d86ff9bbd2 100644 --- a/gfx/thebes/SoftwareVsyncSource.cpp +++ b/gfx/thebes/SoftwareVsyncSource.cpp @@ -1,4 +1,4 @@ -/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- +/* -*- Mode: C++; tab-width: 20; 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/. @@ -9,6 +9,8 @@ #include "gfxPlatform.h" #include "nsThreadUtils.h" +using namespace mozilla; + SoftwareVsyncSource::SoftwareVsyncSource() { MOZ_ASSERT(NS_IsMainThread()); @@ -128,14 +130,15 @@ SoftwareDisplay::ScheduleNextVsync(mozilla::TimeStamp aVsyncTimestamp) nextVsync = mozilla::TimeStamp::Now(); } - mCurrentVsyncTask = NewRunnableMethod(this, - &SoftwareDisplay::NotifyVsync, - nextVsync); + mCurrentVsyncTask = + NewCancelableRunnableMethod(this, + &SoftwareDisplay::NotifyVsync, + nextVsync); - RefPtr addrefedTask = mCurrentVsyncTask; + RefPtr addrefedTask = mCurrentVsyncTask; mVsyncThread->message_loop()->PostDelayedTask( - addrefedTask.forget(), - delay.ToMilliseconds()); + addrefedTask.forget(), + delay.ToMilliseconds()); } void diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index ce6b322e38..952b58847e 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -5,7 +5,7 @@ #include "mozilla/layers/AsyncTransactionTracker.h" // for AsyncTransactionTracker #include "mozilla/layers/CompositorBridgeChild.h" -#include "mozilla/layers/CompositorBridgeParent.h" +#include "mozilla/layers/CompositorThread.h" #include "mozilla/layers/ImageBridgeChild.h" #include "mozilla/layers/SharedBufferManagerChild.h" #include "mozilla/layers/ISurfaceAllocator.h" // for GfxMemoryImageReporter @@ -862,7 +862,7 @@ gfxPlatform::InitLayersIPC() if (XRE_IsParentProcess()) { - mozilla::layers::CompositorBridgeParent::StartUp(); + layers::CompositorThreadHolder::Start(); #ifdef MOZ_WIDGET_GONK SharedBufferManagerChild::StartUp(); #endif @@ -899,7 +899,7 @@ gfxPlatform::ShutdownLayersIPC() #endif // This has to happen after shutting down the child protocols. - layers::CompositorBridgeParent::ShutDown(); + layers::CompositorThreadHolder::Shutdown(); } else { // TODO: There are other kind of processes and we should make sure gfx // stuff is either not created there or shut down properly. diff --git a/gfx/thebes/gfxWindowsPlatform.cpp b/gfx/thebes/gfxWindowsPlatform.cpp index 606efc8174..705f013480 100644 --- a/gfx/thebes/gfxWindowsPlatform.cpp +++ b/gfx/thebes/gfxWindowsPlatform.cpp @@ -65,10 +65,10 @@ #include #include "d3dkmtQueryStatistics.h" +#include "base/thread.h" #include "SurfaceCache.h" #include "gfxPrefs.h" #include "gfxConfig.h" - #include "VsyncSource.h" #include "DriverCrashGuard.h" #include "gfxCrashReporterUtils.h" diff --git a/gfx/vr/ipc/VRManagerChild.cpp b/gfx/vr/ipc/VRManagerChild.cpp index c8476969de..cd4c21fb55 100644 --- a/gfx/vr/ipc/VRManagerChild.cpp +++ b/gfx/vr/ipc/VRManagerChild.cpp @@ -10,7 +10,7 @@ #include "VRDeviceProxy.h" #include "VRDeviceProxyOrientationFallBack.h" #include "mozilla/StaticPtr.h" -#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent +#include "mozilla/layers/CompositorThread.h" // for CompositorThread #include "mozilla/dom/Navigator.h" namespace mozilla { @@ -77,7 +77,7 @@ VRManagerChild::StartUpSameProcess() sVRManagerChildSingleton = new VRManagerChild(); sVRManagerParentSingleton = VRManagerParent::CreateSameProcess(); sVRManagerChildSingleton->Open(sVRManagerParentSingleton->GetIPCChannel(), - mozilla::layers::CompositorBridgeParent::CompositorLoop(), + mozilla::layers::CompositorThreadHolder::Loop(), mozilla::ipc::ChildSide); } } diff --git a/gfx/vr/ipc/VRManagerParent.cpp b/gfx/vr/ipc/VRManagerParent.cpp index b68baa817d..91d43cc788 100644 --- a/gfx/vr/ipc/VRManagerParent.cpp +++ b/gfx/vr/ipc/VRManagerParent.cpp @@ -10,18 +10,11 @@ #include "mozilla/ipc/ProtocolTypes.h" #include "mozilla/ipc/ProtocolUtils.h" // for IToplevelProtocol #include "mozilla/TimeStamp.h" // for TimeStamp -#include "mozilla/layers/CompositorBridgeParent.h" +#include "mozilla/layers/CompositorThread.h" #include "mozilla/unused.h" #include "VRManager.h" namespace mozilla { -namespace layers { - -// defined in CompositorBridgeParent.cpp -CompositorThreadHolder* GetCompositorThreadHolder(); - -} // namespace layers - namespace gfx { VRManagerParent::VRManagerParent(MessageLoop* aLoop, @@ -76,7 +69,7 @@ VRManagerParent::ConnectVRManagerInParentProcess(VRManagerParent* aVRManager, /*static*/ VRManagerParent* VRManagerParent::CreateCrossProcess(Transport* aTransport, ProcessId aChildProcessId) { - MessageLoop* loop = mozilla::layers::CompositorBridgeParent::CompositorLoop(); + MessageLoop* loop = mozilla::layers::CompositorThreadHolder::Loop(); RefPtr vmp = new VRManagerParent(loop, aTransport, aChildProcessId); vmp->mSelfRef = vmp; loop->PostTask(NewRunnableFunction(ConnectVRManagerInParentProcess, @@ -93,9 +86,9 @@ VRManagerParent::RegisterVRManagerInCompositorThread(VRManagerParent* aVRManager /*static*/ VRManagerParent* VRManagerParent::CreateSameProcess() { - MessageLoop* loop = mozilla::layers::CompositorBridgeParent::CompositorLoop(); + MessageLoop* loop = mozilla::layers::CompositorThreadHolder::Loop(); RefPtr vmp = new VRManagerParent(loop, nullptr, base::GetCurrentProcId()); - vmp->mCompositorThreadHolder = layers::GetCompositorThreadHolder(); + vmp->mCompositorThreadHolder = layers::CompositorThreadHolder::GetSingleton(); vmp->mSelfRef = vmp; loop->PostTask(NewRunnableFunction(RegisterVRManagerInCompositorThread, vmp.get())); return vmp.get(); @@ -112,8 +105,7 @@ void VRManagerParent::ActorDestroy(ActorDestroyReason why) { UnregisterFromManager(); - MessageLoop::current()->PostTask( - NewRunnableMethod(this, &VRManagerParent::DeferredDestroy)); + MessageLoop::current()->PostTask(NewRunnableMethod(this, &VRManagerParent::DeferredDestroy)); } mozilla::ipc::IToplevelProtocol* @@ -140,7 +132,7 @@ VRManagerParent::CloneToplevel(const InfallibleTArray runnable = - NS_NewRunnableMethod(aThisThread, &nsIThread::Shutdown); - NS_DispatchToMainThread(runnable); + NS_DispatchToMainThread(NewRunnableMethod(aThisThread, &nsIThread::Shutdown)); } /** diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index caf4f19663..b727b24dc3 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -440,9 +440,7 @@ RasterImage::OnSurfaceDiscarded() { MOZ_ASSERT(mProgressTracker); - nsCOMPtr runnable = - NS_NewRunnableMethod(mProgressTracker, &ProgressTracker::OnDiscard); - NS_DispatchToMainThread(runnable); + NS_DispatchToMainThread(NewRunnableMethod(mProgressTracker, &ProgressTracker::OnDiscard)); } //****************************************************************************** diff --git a/image/VectorImage.cpp b/image/VectorImage.cpp index 3f08dd4310..b8d8950433 100644 --- a/image/VectorImage.cpp +++ b/image/VectorImage.cpp @@ -1063,9 +1063,7 @@ VectorImage::OnSurfaceDiscarded() { MOZ_ASSERT(mProgressTracker); - nsCOMPtr runnable = - NS_NewRunnableMethod(mProgressTracker, &ProgressTracker::OnDiscard); - NS_DispatchToMainThread(runnable); + NS_DispatchToMainThread(NewRunnableMethod(mProgressTracker, &ProgressTracker::OnDiscard)); } //****************************************************************************** diff --git a/image/imgRequestProxy.cpp b/image/imgRequestProxy.cpp index b8fb700db9..ba3e3cf182 100644 --- a/image/imgRequestProxy.cpp +++ b/image/imgRequestProxy.cpp @@ -354,9 +354,7 @@ imgRequestProxy::CancelAndForgetObserver(nsresult aStatus) mIsInLoadGroup = oldIsInLoadGroup; if (mIsInLoadGroup) { - nsCOMPtr ev = - NS_NewRunnableMethod(this, &imgRequestProxy::DoRemoveFromLoadGroup); - NS_DispatchToCurrentThread(ev); + NS_DispatchToCurrentThread(NewRunnableMethod(this, &imgRequestProxy::DoRemoveFromLoadGroup)); } NullOutListener(); diff --git a/ipc/chromium/src/base/task.h b/ipc/chromium/src/base/task.h index b00451cf94..07787d64b1 100644 --- a/ipc/chromium/src/base/task.h +++ b/ipc/chromium/src/base/task.h @@ -303,16 +303,21 @@ class RunnableMethod : public mozilla::CancelableRunnable, Params params_; }; +namespace dont_add_new_uses_of_this { + +// Don't add new uses of this!!!! template -inline already_AddRefed +inline already_AddRefed NewRunnableMethod(T* object, Method method, Args&&... args) { typedef mozilla::Tuple::Type...> ArgsTuple; - RefPtr t = + RefPtr t = new RunnableMethod(object, method, mozilla::MakeTuple(mozilla::Forward(args)...)); return t.forget(); } +} // namespace dont_add_new_uses_of_this + // RunnableFunction and NewRunnableFunction implementation --------------------- template @@ -342,7 +347,7 @@ class RunnableFunction : public mozilla::CancelableRunnable { template inline already_AddRefed -NewRunnableFunction(Function function, Args&&... args) { +NewCancelableRunnableFunction(Function function, Args&&... args) { typedef mozilla::Tuple::Type...> ArgsTuple; RefPtr t = new RunnableFunction(function, @@ -350,4 +355,14 @@ NewRunnableFunction(Function function, Args&&... args) { return t.forget(); } +template +inline already_AddRefed +NewRunnableFunction(Function function, Args&&... args) { + typedef mozilla::Tuple::Type...> ArgsTuple; + RefPtr t = + new RunnableFunction(function, + mozilla::MakeTuple(mozilla::Forward(args)...)); + return t.forget(); +} + #endif // BASE_TASK_H_ diff --git a/ipc/glue/BackgroundImpl.cpp b/ipc/glue/BackgroundImpl.cpp index 3b7235613f..5a77e436dc 100644 --- a/ipc/glue/BackgroundImpl.cpp +++ b/ipc/glue/BackgroundImpl.cpp @@ -433,9 +433,8 @@ private: ChildImpl* actor; threadLocalInfo->mActor.forget(&actor); - nsCOMPtr releaser = - NS_NewNonOwningRunnableMethod(actor, &ChildImpl::Release); - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(releaser)); + MOZ_ALWAYS_SUCCEEDS( + NS_DispatchToMainThread(NewNonOwningRunnableMethod(actor, &ChildImpl::Release))); } } delete threadLocalInfo; @@ -1003,11 +1002,8 @@ ParentImpl::GetContentParent(PBackgroundParent* aBackgroundActor) // it for us. This is safe since we are guaranteed that our AddRef runnable // will run before the reference we hand out can be released, and the // ContentParent can't die as long as the existing reference is maintained. - nsCOMPtr runnable = - NS_NewNonOwningRunnableMethod(actor->mContent, &ContentParent::AddRef); - MOZ_ASSERT(runnable); - - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); + MOZ_ALWAYS_SUCCEEDS( + NS_DispatchToMainThread(NewNonOwningRunnableMethod(actor->mContent, &ContentParent::AddRef))); } return already_AddRefed(actor->mContent.get()); @@ -1271,11 +1267,8 @@ ParentImpl::Destroy() AssertIsInMainProcess(); - nsCOMPtr destroyRunnable = - NS_NewNonOwningRunnableMethod(this, &ParentImpl::MainThreadActorDestroy); - MOZ_ASSERT(destroyRunnable); - - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(destroyRunnable)); + MOZ_ALWAYS_SUCCEEDS( + NS_DispatchToMainThread(NewNonOwningRunnableMethod(this, &ParentImpl::MainThreadActorDestroy))); } void @@ -1363,11 +1356,9 @@ ParentImpl::ActorDestroy(ActorDestroyReason aWhy) // IPDL is about to call MessageChannel::Clear() on this thread! To avoid // racing with the main thread we must ensure that the MessageChannel lives // long enough to be cleared in this call stack. - nsCOMPtr destroyRunnable = - NS_NewNonOwningRunnableMethod(this, &ParentImpl::Destroy); - MOZ_ASSERT(destroyRunnable); - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToCurrentThread(destroyRunnable)); + MOZ_ALWAYS_SUCCEEDS( + NS_DispatchToCurrentThread(NewNonOwningRunnableMethod(this, &ParentImpl::Destroy))); } NS_IMPL_ISUPPORTS(ParentImpl::ShutdownObserver, nsIObserver) diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp index dce2d30ccd..0a2296c41d 100644 --- a/ipc/glue/GeckoChildProcessHost.cpp +++ b/ipc/glue/GeckoChildProcessHost.cpp @@ -81,13 +81,6 @@ ShouldHaveDirectoryService() return GeckoProcessType_Default == XRE_GetProcessType(); } -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(GeckoChildProcessHost* obj) { } - static void ReleaseCallee(GeckoChildProcessHost* obj) { } -}; - /*static*/ base::ChildPrivileges GeckoChildProcessHost::DefaultChildPrivileges() @@ -351,9 +344,10 @@ GeckoChildProcessHost::SyncLaunch(std::vector aExtraOpts, int aTime MessageLoop* ioLoop = XRE_GetIOMessageLoop(); NS_ASSERTION(MessageLoop::current() != ioLoop, "sync launch from the IO thread NYI"); - ioLoop->PostTask(NewRunnableMethod(this, - &GeckoChildProcessHost::RunPerformAsyncLaunch, - aExtraOpts, arch)); + ioLoop->PostTask(NewNonOwningRunnableMethod + , base::ProcessArchitecture> + (this, &GeckoChildProcessHost::RunPerformAsyncLaunch, + aExtraOpts, arch)); return WaitUntilConnected(aTimeoutMs); } @@ -365,9 +359,11 @@ GeckoChildProcessHost::AsyncLaunch(std::vector aExtraOpts, PrepareLaunch(); MessageLoop* ioLoop = XRE_GetIOMessageLoop(); - ioLoop->PostTask(NewRunnableMethod(this, - &GeckoChildProcessHost::RunPerformAsyncLaunch, - aExtraOpts, arch)); + + ioLoop->PostTask(NewNonOwningRunnableMethod + , base::ProcessArchitecture> + (this, &GeckoChildProcessHost::RunPerformAsyncLaunch, + aExtraOpts, arch)); // This may look like the sync launch wait, but we only delay as // long as it takes to create the channel. @@ -423,9 +419,10 @@ GeckoChildProcessHost::LaunchAndWaitForProcessHandle(StringVector aExtraOpts) PrepareLaunch(); MessageLoop* ioLoop = XRE_GetIOMessageLoop(); - ioLoop->PostTask(NewRunnableMethod(this, - &GeckoChildProcessHost::RunPerformAsyncLaunch, - aExtraOpts, base::GetCurrentProcessArchitecture())); + ioLoop->PostTask(NewNonOwningRunnableMethod + , base::ProcessArchitecture> + (this, &GeckoChildProcessHost::RunPerformAsyncLaunch, + aExtraOpts, base::GetCurrentProcessArchitecture())); MonitorAutoLock lock(mMonitor); while (mProcessState < PROCESS_CREATED) { diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 86a8f1ccdd..79e1c8cd43 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -101,13 +101,6 @@ using mozilla::dom::ScriptSettingsInitialized; using mozilla::MonitorAutoLock; using mozilla::MonitorAutoUnlock; -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::ipc::MessageChannel* obj) { } - static void ReleaseCallee(mozilla::ipc::MessageChannel* obj) { } -}; - #define IPC_ASSERT(_cond, ...) \ do { \ if (!(_cond)) \ @@ -502,13 +495,12 @@ MessageChannel::MessageChannel(MessageListener *aListener) mIsSyncWaitingOnNonMainThread = false; #endif - mDequeueOneTask = new RefCountedTask(NewRunnableMethod( - this, - &MessageChannel::OnMaybeDequeueOne)); + RefPtr runnable = + NewNonOwningCancelableRunnableMethod(this, &MessageChannel::OnMaybeDequeueOne); + mDequeueOneTask = new RefCountedTask(runnable.forget()); - mOnChannelConnectedTask = new RefCountedTask(NewRunnableMethod( - this, - &MessageChannel::DispatchOnChannelConnected)); + runnable = NewNonOwningCancelableRunnableMethod(this, &MessageChannel::DispatchOnChannelConnected); + mOnChannelConnectedTask = new RefCountedTask(runnable.forget()); #ifdef OS_WIN mEvent = CreateEventW(nullptr, TRUE, FALSE, nullptr); @@ -693,8 +685,10 @@ MessageChannel::Open(MessageChannel *aTargetChan, MessageLoop *aTargetLoop, Side MonitorAutoLock lock(*mMonitor); mChannelState = ChannelOpening; - aTargetLoop->PostTask( - NewRunnableMethod(aTargetChan, &MessageChannel::OnOpenAsSlave, this, oppSide)); + aTargetLoop->PostTask(NewNonOwningRunnableMethod + (aTargetChan, + &MessageChannel::OnOpenAsSlave, + this, oppSide)); while (ChannelOpening == mChannelState) mMonitor->Wait(); @@ -2100,7 +2094,7 @@ MessageChannel::OnNotifyMaybeChannelError() if (IsOnCxxStack()) { mChannelErrorTask = - NewRunnableMethod(this, &MessageChannel::OnNotifyMaybeChannelError); + NewNonOwningCancelableRunnableMethod(this, &MessageChannel::OnNotifyMaybeChannelError); RefPtr task = mChannelErrorTask; // 10 ms delay is completely arbitrary mWorkerLoop->PostDelayedTask(task.forget(), 10); @@ -2120,7 +2114,7 @@ MessageChannel::PostErrorNotifyTask() // This must be the last code that runs on this thread! mChannelErrorTask = - NewRunnableMethod(this, &MessageChannel::OnNotifyMaybeChannelError); + NewNonOwningCancelableRunnableMethod(this, &MessageChannel::OnNotifyMaybeChannelError); RefPtr task = mChannelErrorTask; mWorkerLoop->PostTask(task.forget()); } diff --git a/ipc/glue/MessageLink.cpp b/ipc/glue/MessageLink.cpp index 2288854615..1dc56687c9 100644 --- a/ipc/glue/MessageLink.cpp +++ b/ipc/glue/MessageLink.cpp @@ -31,13 +31,6 @@ extern "C" char* PrintJSStack(); using namespace mozilla; using namespace std; -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::ipc::ProcessLink* obj) { } - static void ReleaseCallee(mozilla::ipc::ProcessLink* obj) { } -}; - // We rely on invariants about the lifetime of the transport: // // - outlives this MessageChannel @@ -50,12 +43,6 @@ struct RunnableMethodTraits // Transport, because whatever task triggers its deletion only runs on // the IO thread, and only runs after this MessageChannel is done with // the Transport. -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::ipc::MessageChannel::Transport* obj) { } - static void ReleaseCallee(mozilla::ipc::MessageChannel::Transport* obj) { } -}; namespace mozilla { namespace ipc { @@ -131,14 +118,12 @@ ProcessLink::Open(mozilla::ipc::Transport* aTransport, MessageLoop *aIOLoop, Sid // Transport::Connect() has not been called. Call it so // we start polling our pipe and processing outgoing // messages. - mIOLoop->PostTask( - NewRunnableMethod(this, &ProcessLink::OnChannelOpened)); + mIOLoop->PostTask(NewNonOwningRunnableMethod(this, &ProcessLink::OnChannelOpened)); } else { // Transport::Connect() has already been called. Take // over the channel from the previous listener and process // any queued messages. - mIOLoop->PostTask( - NewRunnableMethod(this, &ProcessLink::OnTakeConnectedChannel)); + mIOLoop->PostTask(NewNonOwningRunnableMethod(this, &ProcessLink::OnTakeConnectedChannel)); } #ifdef MOZ_NUWA_PROCESS @@ -165,8 +150,7 @@ ProcessLink::EchoMessage(Message *msg) mChan->AssertWorkerThread(); mChan->mMonitor->AssertCurrentThreadOwns(); - mIOLoop->PostTask( - NewRunnableMethod(this, &ProcessLink::OnEchoMessage, msg)); + mIOLoop->PostTask(NewNonOwningRunnableMethod(this, &ProcessLink::OnEchoMessage, msg)); // OnEchoMessage takes ownership of |msg| } @@ -212,8 +196,7 @@ ProcessLink::SendMessage(Message *msg) #endif #endif - mIOLoop->PostTask( - NewRunnableMethod(mTransport, &Transport::Send, msg)); + mIOLoop->PostTask(NewNonOwningRunnableMethod(mTransport, &Transport::Send, msg)); } void @@ -222,7 +205,7 @@ ProcessLink::SendClose() mChan->AssertWorkerThread(); mChan->mMonitor->AssertCurrentThreadOwns(); - mIOLoop->PostTask(NewRunnableMethod(this, &ProcessLink::OnCloseChannel)); + mIOLoop->PostTask(NewNonOwningRunnableMethod(this, &ProcessLink::OnCloseChannel)); } ThreadLink::ThreadLink(MessageChannel *aChan, MessageChannel *aTargetChan) diff --git a/ipc/ipdl/test/cxx/IPDLUnitTests.h b/ipc/ipdl/test/cxx/IPDLUnitTests.h index bb50ecf5bf..544bc0ffb8 100644 --- a/ipc/ipdl/test/cxx/IPDLUnitTests.h +++ b/ipc/ipdl/test/cxx/IPDLUnitTests.h @@ -29,7 +29,7 @@ namespace _ipdltest { //----------------------------------------------------------------------------- // both processes -const char* const IPDLUnitTestName(); +const char* IPDLUnitTestName(); // NB: these are named like the similar functions in // xpcom/test/TestHarness.h. The names should nominally be kept in diff --git a/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp b/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp index ddeceaa1f9..23ced5c302 100644 --- a/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp +++ b/ipc/ipdl/test/cxx/IPDLUnitTests.template.cpp @@ -47,7 +47,7 @@ DeleteChildActor(); char* gIPDLUnitTestName = nullptr; -const char* const +const char* IPDLUnitTestName() { if (!gIPDLUnitTestName) { @@ -97,7 +97,7 @@ ${STRING_TO_ENUMS} } -const char* const +const char* IPDLUnitTestToString(IPDLUnitTestType aTest) { switch (aTest) { @@ -273,7 +273,7 @@ DeleteSubprocess(MessageLoop* uiLoop) { // pong to QuitXPCOM delete gSubprocess; - uiLoop->PostTask(FROM_HERE, NewRunnableFunction(QuitXPCOM)); + uiLoop->PostTask(NewRunnableFunction(QuitXPCOM)); } void @@ -281,7 +281,6 @@ DeferredParentShutdown() { // ping to DeleteSubprocess XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(DeleteSubprocess, MessageLoop::current())); } @@ -316,12 +315,12 @@ QuitParent() if (gChildThread) { gParentDone = true; MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableFunction(TryThreadedShutdown)); + NewRunnableFunction(TryThreadedShutdown)); } else { // defer "real" shutdown to avoid *Channel::Close() racing with the // deletion of the subprocess MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableFunction(DeferredParentShutdown)); + NewRunnableFunction(DeferredParentShutdown)); } } @@ -337,10 +336,10 @@ QuitChild() { if (gChildThread) { // Threaded-mode test gParentMessageLoop->PostTask( - FROM_HERE, NewRunnableFunction(ChildCompleted)); + NewRunnableFunction(ChildCompleted)); } else { // Process-mode test MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableFunction(ChildDie)); + NewRunnableFunction(ChildDie)); } } diff --git a/ipc/ipdl/test/cxx/TestActorPunning.cpp b/ipc/ipdl/test/cxx/TestActorPunning.cpp index 194a8f61c3..796a3b5d09 100644 --- a/ipc/ipdl/test/cxx/TestActorPunning.cpp +++ b/ipc/ipdl/test/cxx/TestActorPunning.cpp @@ -1,6 +1,7 @@ #include "TestActorPunning.h" #include "IPDLUnitTests.h" // fail etc. +#include "mozilla/unused.h" namespace mozilla { namespace _ipdltest { @@ -123,7 +124,7 @@ ParamTraits::Read(const Message* aMsg, void** aIter, paramType* aResult) { const char* ptr; int len; - aMsg->ReadData(aIter, &ptr, &len); + mozilla::Unused << aMsg->ReadData(aIter, &ptr, &len); return true; } diff --git a/ipc/ipdl/test/cxx/TestBridgeMain.cpp b/ipc/ipdl/test/cxx/TestBridgeMain.cpp index e68065d483..9856a43cf0 100644 --- a/ipc/ipdl/test/cxx/TestBridgeMain.cpp +++ b/ipc/ipdl/test/cxx/TestBridgeMain.cpp @@ -5,13 +5,6 @@ using namespace std; -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestBridgeMainSubChild* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestBridgeMainSubChild* obj) { } -}; - namespace mozilla { namespace _ipdltest { @@ -73,11 +66,9 @@ TestBridgeMainSubParent::ActorDestroy(ActorDestroyReason why) // which needs the top-level actor (this) to stay alive a little // longer so other things can be cleaned up. MessageLoop::current()->PostTask( - FROM_HERE, - new DeleteTask(this)); + do_AddRef(new DeleteTask(this))); XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, - new DeleteTask(mTransport)); + do_AddRef(new DeleteTask(mTransport))); } //----------------------------------------------------------------------------- @@ -118,8 +109,7 @@ TestBridgeMainChild::ActorDestroy(ActorDestroyReason why) fail("unexpected destruction!"); // NB: this is kosher because QuitChild() joins with the IO thread XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, - new DeleteTask(mSubprocess)); + do_AddRef(new DeleteTask(mSubprocess))); QuitChild(); } @@ -149,8 +139,7 @@ TestBridgeSubParent::ActorDestroy(ActorDestroyReason why) // which needs the top-level actor (this) to stay alive a little // longer so other things can be cleaned up. MessageLoop::current()->PostTask( - FROM_HERE, - new DeleteTask(this)); + do_AddRef(new DeleteTask(this))); } //----------------------------------------------------------------------------- @@ -207,8 +196,7 @@ TestBridgeMainSubChild::RecvHi() // Need to close the channel without message-processing frames on // the C++ stack MessageLoop::current()->PostTask( - FROM_HERE, - NewRunnableMethod(this, &TestBridgeMainSubChild::Close)); + NewNonOwningRunnableMethod(this, &TestBridgeMainSubChild::Close)); return true; } @@ -231,11 +219,9 @@ TestBridgeMainSubChild::ActorDestroy(ActorDestroyReason why) // which needs the top-level actor (this) to stay alive a little // longer so other things can be cleaned up. MessageLoop::current()->PostTask( - FROM_HERE, - new DeleteTask(this)); + do_AddRef(new DeleteTask(this))); XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, - new DeleteTask(mTransport)); + do_AddRef(new DeleteTask(mTransport))); } } // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestCancel.cpp b/ipc/ipdl/test/cxx/TestCancel.cpp index 160bdc71c8..8f983b3de8 100644 --- a/ipc/ipdl/test/cxx/TestCancel.cpp +++ b/ipc/ipdl/test/cxx/TestCancel.cpp @@ -2,13 +2,6 @@ #include "IPDLUnitTests.h" // fail etc. -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestCancelParent* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestCancelParent* obj) { } -}; - namespace mozilla { namespace _ipdltest { @@ -84,7 +77,7 @@ bool TestCancelParent::RecvDone() { MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableMethod(this, &TestCancelParent::Close)); + NewNonOwningRunnableMethod(this, &TestCancelParent::Close)); return true; } diff --git a/ipc/ipdl/test/cxx/TestCrashCleanup.cpp b/ipc/ipdl/test/cxx/TestCrashCleanup.cpp index 308e57395f..5a0fc339b1 100644 --- a/ipc/ipdl/test/cxx/TestCrashCleanup.cpp +++ b/ipc/ipdl/test/cxx/TestCrashCleanup.cpp @@ -44,7 +44,6 @@ void DeleteTheWorld() MutexAutoLock lock(mutex); XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(DeleteSubprocess, &mutex, &cvar)); cvar.Wait(); @@ -79,14 +78,14 @@ TestCrashCleanupParent::Main() { // NB: has to be enqueued before IO thread's error notification MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableFunction(DeleteTheWorld)); + NewRunnableFunction(DeleteTheWorld)); if (CallDIEDIEDIE()) fail("expected an error!"); Close(); - MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction(Done)); + MessageLoop::current()->PostTask(NewRunnableFunction(Done)); } diff --git a/ipc/ipdl/test/cxx/TestDemon.cpp b/ipc/ipdl/test/cxx/TestDemon.cpp index 38193dc8e5..c349aafbe8 100644 --- a/ipc/ipdl/test/cxx/TestDemon.cpp +++ b/ipc/ipdl/test/cxx/TestDemon.cpp @@ -14,20 +14,6 @@ #include #endif -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestDemonParent* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestDemonParent* obj) { } -}; - -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestDemonChild* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestDemonChild* obj) { } -}; - namespace mozilla { namespace _ipdltest { @@ -190,8 +176,7 @@ TestDemonParent::RunUnlimitedSequence() gFlushStack = false; DoAction(); - MessageLoop::current()->PostTask(FROM_HERE, - NewRunnableMethod(this, &TestDemonParent::RunUnlimitedSequence)); + MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(this, &TestDemonParent::RunUnlimitedSequence)); } void @@ -335,8 +320,7 @@ TestDemonChild::RunUnlimitedSequence() gFlushStack = false; DoAction(); - MessageLoop::current()->PostTask(FROM_HERE, - NewRunnableMethod(this, &TestDemonChild::RunUnlimitedSequence)); + MessageLoop::current()->PostTask(NewNonOwningRunnableMethod(this, &TestDemonChild::RunUnlimitedSequence)); } void diff --git a/ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp b/ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp index aa064b0d45..1efa8482e6 100644 --- a/ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp +++ b/ipc/ipdl/test/cxx/TestEndpointBridgeMain.cpp @@ -8,13 +8,6 @@ using namespace std; -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestEndpointBridgeMainSubChild* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestEndpointBridgeMainSubChild* obj) { } -}; - namespace mozilla { namespace _ipdltest { @@ -78,11 +71,9 @@ TestEndpointBridgeMainSubParent::ActorDestroy(ActorDestroyReason why) // which needs the top-level actor (this) to stay alive a little // longer so other things can be cleaned up. MessageLoop::current()->PostTask( - FROM_HERE, - new DeleteTask(this)); + do_AddRef(new DeleteTask(this))); XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, - new DeleteTask(GetTransport())); + do_AddRef(new DeleteTask(GetTransport()))); } //----------------------------------------------------------------------------- @@ -126,8 +117,7 @@ TestEndpointBridgeMainChild::ActorDestroy(ActorDestroyReason why) } // NB: this is kosher because QuitChild() joins with the IO thread XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, - new DeleteTask(mSubprocess)); + do_AddRef(new DeleteTask(mSubprocess))); QuitChild(); } @@ -174,8 +164,7 @@ TestEndpointBridgeSubParent::ActorDestroy(ActorDestroyReason why) // which needs the top-level actor (this) to stay alive a little // longer so other things can be cleaned up. MessageLoop::current()->PostTask( - FROM_HERE, - new DeleteTask(this)); + do_AddRef(new DeleteTask(this))); } //----------------------------------------------------------------------------- @@ -238,8 +227,7 @@ TestEndpointBridgeMainSubChild::RecvHi() // Need to close the channel without message-processing frames on // the C++ stack MessageLoop::current()->PostTask( - FROM_HERE, - NewRunnableMethod(this, &TestEndpointBridgeMainSubChild::Close)); + NewNonOwningRunnableMethod(this, &TestEndpointBridgeMainSubChild::Close)); return true; } @@ -263,11 +251,9 @@ TestEndpointBridgeMainSubChild::ActorDestroy(ActorDestroyReason why) // which needs the top-level actor (this) to stay alive a little // longer so other things can be cleaned up. MessageLoop::current()->PostTask( - FROM_HERE, - new DeleteTask(this)); + do_AddRef(new DeleteTask(this))); XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, - new DeleteTask(GetTransport())); + do_AddRef(new DeleteTask(GetTransport()))); } } // namespace mozilla diff --git a/ipc/ipdl/test/cxx/TestEndpointOpens.cpp b/ipc/ipdl/test/cxx/TestEndpointOpens.cpp index 76e87846ba..27966b2676 100644 --- a/ipc/ipdl/test/cxx/TestEndpointOpens.cpp +++ b/ipc/ipdl/test/cxx/TestEndpointOpens.cpp @@ -7,20 +7,6 @@ #include "IPDLUnitTests.h" // fail etc. -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestEndpointOpensChild* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestEndpointOpensChild* obj) { } -}; - -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest2::TestEndpointOpensOpenedChild* obj) { } - static void ReleaseCallee(mozilla::_ipdltest2::TestEndpointOpensOpenedChild* obj) { } -}; - using namespace mozilla::ipc; using base::ProcessHandle; @@ -85,7 +71,6 @@ TestEndpointOpensParent::RecvStartSubprotocol( TestEndpointOpensOpenedParent* a = new TestEndpointOpensOpenedParent(); gParentThread->message_loop()->PostTask( - FROM_HERE, NewRunnableFunction(OpenParent, a, mozilla::Move(endpoint))); return true; @@ -134,8 +119,7 @@ ShutdownTestEndpointOpensOpenedParent(TestEndpointOpensOpenedParent* parent, // Now delete the transport, which has to happen after the // top-level actor is deleted. XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, - new DeleteTask(transport)); + do_AddRef(new DeleteTask(transport))); } void @@ -151,7 +135,6 @@ TestEndpointOpensOpenedParent::ActorDestroy(ActorDestroyReason why) // which needs the top-level actor (this) to stay alive a little // longer so other things can be cleaned up. gParentThread->message_loop()->PostTask( - FROM_HERE, NewRunnableFunction(ShutdownTestEndpointOpensOpenedParent, this, GetTransport())); } @@ -208,7 +191,6 @@ TestEndpointOpensChild::RecvStart() TestEndpointOpensOpenedChild* a = new TestEndpointOpensOpenedChild(); gChildThread->message_loop()->PostTask( - FROM_HERE, NewRunnableFunction(OpenChild, a, mozilla::Move(child))); if (!SendStartSubprotocol(parent)) { @@ -248,8 +230,7 @@ TestEndpointOpensOpenedChild::RecvHi() // Need to close the channel without message-processing frames on // the C++ stack MessageLoop::current()->PostTask( - FROM_HERE, - NewRunnableMethod(this, &TestEndpointOpensOpenedChild::Close)); + NewNonOwningRunnableMethod(this, &TestEndpointOpensOpenedChild::Close)); return true; } @@ -271,13 +252,11 @@ ShutdownTestEndpointOpensOpenedChild(TestEndpointOpensOpenedChild* child, // Now delete the transport, which has to happen after the // top-level actor is deleted. XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, - new DeleteTask(transport)); + do_AddRef(new DeleteTask(transport))); // Kick off main-thread shutdown. gMainThread->PostTask( - FROM_HERE, - NewRunnableMethod(gOpensChild, &TestEndpointOpensChild::Close)); + NewNonOwningRunnableMethod(gOpensChild, &TestEndpointOpensChild::Close)); } void @@ -294,7 +273,6 @@ TestEndpointOpensOpenedChild::ActorDestroy(ActorDestroyReason why) // longer so other things can be cleaned up. Defer shutdown to // let cleanup finish. gChildThread->message_loop()->PostTask( - FROM_HERE, NewRunnableFunction(ShutdownTestEndpointOpensOpenedChild, this, GetTransport())); } diff --git a/ipc/ipdl/test/cxx/TestHangs.cpp b/ipc/ipdl/test/cxx/TestHangs.cpp index ef80e02e15..b96823aee3 100644 --- a/ipc/ipdl/test/cxx/TestHangs.cpp +++ b/ipc/ipdl/test/cxx/TestHangs.cpp @@ -6,13 +6,6 @@ using base::KillProcess; -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestHangsParent* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestHangsParent* obj) { } -}; - namespace mozilla { namespace _ipdltest { @@ -82,7 +75,7 @@ TestHangsParent::ShouldContinueFromReplyTimeout() // reply should be here; we'll post a task to shut things down. // This must be after OnMaybeDequeueOne() in the event queue. MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableMethod(this, &TestHangsParent::CleanUp)); + NewNonOwningRunnableMethod(this, &TestHangsParent::CleanUp)); GetIPCChannel()->CloseWithTimeout(); diff --git a/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp index 238b040d17..748f1c5e65 100644 --- a/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp +++ b/ipc/ipdl/test/cxx/TestInterruptErrorCleanup.cpp @@ -44,7 +44,6 @@ void DeleteTheWorld() MutexAutoLock lock(mutex); XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(DeleteSubprocess, &mutex, &cvar)); cvar.Wait(); @@ -101,7 +100,7 @@ TestInterruptErrorCleanupParent::Main() // errors/crashes. MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableFunction(DeleteTheWorld)); + NewRunnableFunction(DeleteTheWorld)); // it's a failure if this *succeeds* if (CallError()) @@ -118,7 +117,7 @@ TestInterruptErrorCleanupParent::Main() // notification enqueued by AsyncChannel, because that event is // enqueued within the same mutex that ends up signaling the // wakeup-on-error of |CallError()| above - MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction(Done)); + MessageLoop::current()->PostTask(NewRunnableFunction(Done)); } void diff --git a/ipc/ipdl/test/cxx/TestInterruptRaces.cpp b/ipc/ipdl/test/cxx/TestInterruptRaces.cpp index a5a566777a..6986506bb8 100644 --- a/ipc/ipdl/test/cxx/TestInterruptRaces.cpp +++ b/ipc/ipdl/test/cxx/TestInterruptRaces.cpp @@ -4,14 +4,6 @@ using mozilla::ipc::MessageChannel; -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestInterruptRacesParent* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestInterruptRacesParent* obj) { } -}; - - namespace mozilla { namespace _ipdltest { @@ -36,8 +28,7 @@ bool TestInterruptRacesParent::RecvStartRace() { MessageLoop::current()->PostTask( - FROM_HERE, - NewRunnableMethod(this, &TestInterruptRacesParent::OnRaceTime)); + NewNonOwningRunnableMethod(this, &TestInterruptRacesParent::OnRaceTime)); return true; } @@ -53,8 +44,7 @@ TestInterruptRacesParent::OnRaceTime() mHasReply = true; MessageLoop::current()->PostTask( - FROM_HERE, - NewRunnableMethod(this, &TestInterruptRacesParent::Test2)); + NewNonOwningRunnableMethod(this, &TestInterruptRacesParent::Test2)); } bool @@ -81,8 +71,7 @@ TestInterruptRacesParent::Test2() puts(" passed"); MessageLoop::current()->PostTask( - FROM_HERE, - NewRunnableMethod(this, &TestInterruptRacesParent::Test3)); + NewNonOwningRunnableMethod(this, &TestInterruptRacesParent::Test3)); } bool diff --git a/ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp b/ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp index 7f18c4c687..9f766798ab 100644 --- a/ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp +++ b/ipc/ipdl/test/cxx/TestInterruptShutdownRace.cpp @@ -3,14 +3,6 @@ #include "IPDLUnitTests.h" // fail etc. #include "IPDLUnitTestSubprocess.h" -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestInterruptShutdownRaceParent* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestInterruptShutdownRaceParent* obj) { } -}; - - namespace mozilla { namespace _ipdltest { @@ -59,9 +51,8 @@ TestInterruptShutdownRaceParent::RecvStartDeath() // this will be ordered before the OnMaybeDequeueOne event of // Orphan in the queue MessageLoop::current()->PostTask( - FROM_HERE, - NewRunnableMethod(this, - &TestInterruptShutdownRaceParent::StartShuttingDown)); + NewNonOwningRunnableMethod(this, + &TestInterruptShutdownRaceParent::StartShuttingDown)); return true; } @@ -82,12 +73,10 @@ TestInterruptShutdownRaceParent::StartShuttingDown() delete static_cast(gParentActor); gParentActor = nullptr; - XRE_GetIOMessageLoop()->PostTask(FROM_HERE, - NewRunnableFunction(DeleteSubprocess)); + XRE_GetIOMessageLoop()->PostTask(NewRunnableFunction(DeleteSubprocess)); // this is ordered after the OnMaybeDequeueOne event in the queue - MessageLoop::current()->PostTask(FROM_HERE, - NewRunnableFunction(Done)); + MessageLoop::current()->PostTask(NewRunnableFunction(Done)); // |this| has been deleted, be mindful } diff --git a/ipc/ipdl/test/cxx/TestNestedLoops.cpp b/ipc/ipdl/test/cxx/TestNestedLoops.cpp index 689ab3b71c..0e0ba496de 100644 --- a/ipc/ipdl/test/cxx/TestNestedLoops.cpp +++ b/ipc/ipdl/test/cxx/TestNestedLoops.cpp @@ -6,13 +6,6 @@ #include "IPDLUnitTests.h" // fail etc. -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestNestedLoopsParent* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestNestedLoopsParent* obj) { } -}; - namespace mozilla { namespace _ipdltest { @@ -53,8 +46,7 @@ TestNestedLoopsParent::RecvNonce() // to the inherent race condition in this test, then this event // must be ordered after it in the queue MessageLoop::current()->PostTask( - FROM_HERE, - NewRunnableMethod(this, &TestNestedLoopsParent::BreakNestedLoop)); + NewNonOwningRunnableMethod(this, &TestNestedLoopsParent::BreakNestedLoop)); // sigh ... spin for a while to let the reply to R arrive puts(" (sleeping to wait for reply to R ... sorry)"); diff --git a/ipc/ipdl/test/cxx/TestOpens.cpp b/ipc/ipdl/test/cxx/TestOpens.cpp index 3895f71fa8..0f6ea07793 100644 --- a/ipc/ipdl/test/cxx/TestOpens.cpp +++ b/ipc/ipdl/test/cxx/TestOpens.cpp @@ -4,20 +4,6 @@ #include "IPDLUnitTests.h" // fail etc. -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestOpensChild* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestOpensChild* obj) { } -}; - -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest2::TestOpensOpenedChild* obj) { } - static void ReleaseCallee(mozilla::_ipdltest2::TestOpensOpenedChild* obj) { } -}; - using namespace mozilla::ipc; using base::ProcessHandle; @@ -78,7 +64,6 @@ TestOpensParent::AllocPTestOpensOpenedParent(Transport* transport, TestOpensOpenedParent* a = new TestOpensOpenedParent(transport); gParentThread->message_loop()->PostTask( - FROM_HERE, NewRunnableFunction(OpenParent, a, transport, otherPid)); return a; @@ -126,8 +111,7 @@ ShutdownTestOpensOpenedParent(TestOpensOpenedParent* parent, // Now delete the transport, which has to happen after the // top-level actor is deleted. XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, - new DeleteTask(transport)); + do_AddRef(new DeleteTask(transport))); } void @@ -142,7 +126,6 @@ TestOpensOpenedParent::ActorDestroy(ActorDestroyReason why) // which needs the top-level actor (this) to stay alive a little // longer so other things can be cleaned up. gParentThread->message_loop()->PostTask( - FROM_HERE, NewRunnableFunction(ShutdownTestOpensOpenedParent, this, mTransport)); } @@ -197,7 +180,6 @@ TestOpensChild::AllocPTestOpensOpenedChild(Transport* transport, TestOpensOpenedChild* a = new TestOpensOpenedChild(transport); gChildThread->message_loop()->PostTask( - FROM_HERE, NewRunnableFunction(OpenChild, a, transport, otherPid)); return a; @@ -229,8 +211,7 @@ TestOpensOpenedChild::RecvHi() // Need to close the channel without message-processing frames on // the C++ stack MessageLoop::current()->PostTask( - FROM_HERE, - NewRunnableMethod(this, &TestOpensOpenedChild::Close)); + NewNonOwningRunnableMethod(this, &TestOpensOpenedChild::Close)); return true; } @@ -252,13 +233,11 @@ ShutdownTestOpensOpenedChild(TestOpensOpenedChild* child, // Now delete the transport, which has to happen after the // top-level actor is deleted. XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, - new DeleteTask(transport)); + do_AddRef(new DeleteTask(transport))); // Kick off main-thread shutdown. gMainThread->PostTask( - FROM_HERE, - NewRunnableMethod(gOpensChild, &TestOpensChild::Close)); + NewNonOwningRunnableMethod(gOpensChild, &TestOpensChild::Close)); } void @@ -274,7 +253,6 @@ TestOpensOpenedChild::ActorDestroy(ActorDestroyReason why) // longer so other things can be cleaned up. Defer shutdown to // let cleanup finish. gChildThread->message_loop()->PostTask( - FROM_HERE, NewRunnableFunction(ShutdownTestOpensOpenedChild, this, mTransport)); } diff --git a/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp b/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp index 2ad3a74958..7402f30d3a 100644 --- a/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp +++ b/ipc/ipdl/test/cxx/TestRaceDeadlock.cpp @@ -6,6 +6,7 @@ using namespace mozilla::ipc; typedef mozilla::ipc::MessageChannel::Message Message; +typedef mozilla::ipc::MessageChannel::MessageInfo MessageInfo; namespace mozilla { namespace _ipdltest { diff --git a/ipc/ipdl/test/cxx/TestRaceDeferral.cpp b/ipc/ipdl/test/cxx/TestRaceDeferral.cpp index 2b88fc87b8..b62d0e2f3c 100644 --- a/ipc/ipdl/test/cxx/TestRaceDeferral.cpp +++ b/ipc/ipdl/test/cxx/TestRaceDeferral.cpp @@ -4,6 +4,7 @@ using namespace mozilla::ipc; typedef mozilla::ipc::MessageChannel::Message Message; +typedef mozilla::ipc::MessageChannel::MessageInfo MessageInfo; namespace mozilla { namespace _ipdltest { diff --git a/ipc/ipdl/test/cxx/TestStackHooks.cpp b/ipc/ipdl/test/cxx/TestStackHooks.cpp index b65833727e..0f6e93e368 100644 --- a/ipc/ipdl/test/cxx/TestStackHooks.cpp +++ b/ipc/ipdl/test/cxx/TestStackHooks.cpp @@ -81,8 +81,7 @@ TestStackHooksChild::RecvStart() // kick off tests from a runnable so that we can start with // MessageChannel code on the C++ stack - MessageLoop::current()->PostTask(FROM_HERE, - NewRunnableFunction(RunTestsFn)); + MessageLoop::current()->PostTask(NewRunnableFunction(RunTestsFn)); return true; } diff --git a/ipc/ipdl/test/cxx/TestSyncHang.cpp b/ipc/ipdl/test/cxx/TestSyncHang.cpp index 2035ac5320..830aa3fb74 100644 --- a/ipc/ipdl/test/cxx/TestSyncHang.cpp +++ b/ipc/ipdl/test/cxx/TestSyncHang.cpp @@ -35,7 +35,6 @@ DeferredSyncHangParentShutdown() { // ping to DeleteSubprocess XRE_GetIOMessageLoop()->PostTask( - FROM_HERE, NewRunnableFunction(DeleteSyncHangSubprocess, MessageLoop::current())); } @@ -49,8 +48,7 @@ TestSyncHangParent::Main() if (launched) fail("Calling SyncLaunch with an invalid path should return false"); - MessageLoop::current()->PostTask( - FROM_HERE, NewRunnableFunction(DeferredSyncHangParentShutdown)); + MessageLoop::current()->PostTask(NewRunnableFunction(DeferredSyncHangParentShutdown)); Close(); } diff --git a/ipc/ipdl/test/cxx/TestUrgency.cpp b/ipc/ipdl/test/cxx/TestUrgency.cpp index a18105ff3b..b9b05bceaf 100644 --- a/ipc/ipdl/test/cxx/TestUrgency.cpp +++ b/ipc/ipdl/test/cxx/TestUrgency.cpp @@ -7,13 +7,6 @@ #include #endif -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestUrgencyParent* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestUrgencyParent* obj) { } -}; - namespace mozilla { namespace _ipdltest { diff --git a/ipc/ipdl/test/cxx/TestUrgentHangs.cpp b/ipc/ipdl/test/cxx/TestUrgentHangs.cpp index f2ca7839a2..b798ae18d9 100644 --- a/ipc/ipdl/test/cxx/TestUrgentHangs.cpp +++ b/ipc/ipdl/test/cxx/TestUrgentHangs.cpp @@ -11,13 +11,6 @@ #include #endif -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(mozilla::_ipdltest::TestUrgentHangsParent* obj) { } - static void ReleaseCallee(mozilla::_ipdltest::TestUrgentHangsParent* obj) { } -}; - namespace mozilla { namespace _ipdltest { @@ -56,8 +49,7 @@ TestUrgentHangsParent::Main() // Do a second round of testing once the reply to Test2 comes back. MessageLoop::current()->PostDelayedTask( - FROM_HERE, - NewRunnableMethod(this, &TestUrgentHangsParent::SecondStage), + NewNonOwningRunnableMethod(this, &TestUrgentHangsParent::SecondStage), 3000); } @@ -75,8 +67,7 @@ TestUrgentHangsParent::SecondStage() fail("sending Test4_1"); MessageLoop::current()->PostDelayedTask( - FROM_HERE, - NewRunnableMethod(this, &TestUrgentHangsParent::ThirdStage), + NewNonOwningRunnableMethod(this, &TestUrgentHangsParent::ThirdStage), 3000); } @@ -99,8 +90,7 @@ TestUrgentHangsParent::ThirdStage() // Close the channel after the child finishes its work in RecvTest5. MessageLoop::current()->PostDelayedTask( - FROM_HERE, - NewRunnableMethod(this, &TestUrgentHangsParent::Close), + NewNonOwningRunnableMethod(this, &TestUrgentHangsParent::Close), 3000); } diff --git a/js/public/Proxy.h b/js/public/Proxy.h index 9470b70e8d..42c3b9e407 100644 --- a/js/public/Proxy.h +++ b/js/public/Proxy.h @@ -272,7 +272,7 @@ class JS_FRIEND_API(BaseProxyHandler) /* Non-standard but conceptual kin to {g,s}etPrototype, so these live here. */ virtual bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, - MutableHandleObject protop) const; + MutableHandleObject protop) const = 0; virtual bool setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const; virtual bool preventExtensions(JSContext* cx, HandleObject proxy, diff --git a/js/src/builtin/MapObject.cpp b/js/src/builtin/MapObject.cpp index 522340f323..71aa3ea86d 100644 --- a/js/src/builtin/MapObject.cpp +++ b/js/src/builtin/MapObject.cpp @@ -232,7 +232,7 @@ MapIteratorObject::createResultPair(JSContext* cx) if (!resultPairObj) return nullptr; - Rooted proto(cx, resultPairObj->getTaggedProto()); + Rooted proto(cx, resultPairObj->taggedProto()); ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, resultPairObj->getClass(), proto); if (!group) return nullptr; diff --git a/js/src/builtin/Object.cpp b/js/src/builtin/Object.cpp index b59913789a..c1a47c0dc6 100644 --- a/js/src/builtin/Object.cpp +++ b/js/src/builtin/Object.cpp @@ -612,7 +612,7 @@ js::ObjectCreateImpl(JSContext* cx, HandleObject proto, NewObjectKind newKind, PlainObject* js::ObjectCreateWithTemplate(JSContext* cx, HandlePlainObject templateObj) { - RootedObject proto(cx, templateObj->getProto()); + RootedObject proto(cx, templateObj->staticPrototype()); RootedObjectGroup group(cx, templateObj->group()); return ObjectCreateImpl(cx, proto, GenericObject, group); } diff --git a/js/src/builtin/RegExp.cpp b/js/src/builtin/RegExp.cpp index 5ec36bed24..effda51c0d 100644 --- a/js/src/builtin/RegExp.cpp +++ b/js/src/builtin/RegExp.cpp @@ -1609,12 +1609,12 @@ js::RegExpInstanceOptimizableRaw(JSContext* cx, JSObject* rx, JSObject* proto, u return true; } - if (rx->hasLazyPrototype()) { + if (!rx->hasStaticPrototype()) { *result = false; return true; } - if (rx->getTaggedProto().toObjectOrNull() != proto) { + if (rx->staticPrototype() != proto) { *result = false; return true; } diff --git a/js/src/builtin/TypedObject.cpp b/js/src/builtin/TypedObject.cpp index 95539441de..a5db65d521 100644 --- a/js/src/builtin/TypedObject.cpp +++ b/js/src/builtin/TypedObject.cpp @@ -1679,7 +1679,7 @@ TypedObject::obj_lookupProperty(JSContext* cx, HandleObject obj, HandleId id, return true; } - RootedObject proto(cx, obj->getProto()); + RootedObject proto(cx, obj->staticPrototype()); if (!proto) { objp.set(nullptr); propp.set(nullptr); @@ -1751,7 +1751,7 @@ TypedObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id, bool* } } - RootedObject proto(cx, obj->getProto()); + RootedObject proto(cx, obj->staticPrototype()); if (!proto) { *foundp = false; return true; @@ -1808,7 +1808,7 @@ TypedObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue receiv } } - RootedObject proto(cx, obj->getProto()); + RootedObject proto(cx, obj->staticPrototype()); if (!proto) { vp.setUndefined(); return true; @@ -1836,7 +1836,7 @@ TypedObject::obj_getElement(JSContext* cx, HandleObject obj, HandleValue receive return obj_getArrayElement(cx, typedObj, descr, index, vp); } - RootedObject proto(cx, obj->getProto()); + RootedObject proto(cx, obj->staticPrototype()); if (!proto) { vp.setUndefined(); return true; @@ -2019,7 +2019,7 @@ TypedObject::obj_deleteProperty(JSContext* cx, HandleObject obj, HandleId id, Ob if (IsOwnId(cx, obj, id)) return ReportPropertyError(cx, JSMSG_CANT_DELETE, id); - RootedObject proto(cx, obj->getProto()); + RootedObject proto(cx, obj->staticPrototype()); if (!proto) return result.succeed(); diff --git a/js/src/builtin/TypedObject.h b/js/src/builtin/TypedObject.h index 1e9dbee7b8..49ef86436c 100644 --- a/js/src/builtin/TypedObject.h +++ b/js/src/builtin/TypedObject.h @@ -530,7 +530,8 @@ class TypedObject : public JSObject public: TypedProto& typedProto() const { - return getProto()->as(); + // Typed objects' prototypes can't be modified. + return staticPrototype()->as(); } TypeDescr& typeDescr() const { diff --git a/js/src/jit/BaselineIC.cpp b/js/src/jit/BaselineIC.cpp index 95b81d5ad6..4d7e0621ec 100644 --- a/js/src/jit/BaselineIC.cpp +++ b/js/src/jit/BaselineIC.cpp @@ -785,12 +785,14 @@ IsCacheableSetPropAddSlot(JSContext* cx, JSObject* obj, Shape* oldShape, size_t chainDepth = 0; // Walk up the object prototype chain and ensure that all prototypes are // native, and that all prototypes have no setter defined on the property. - for (JSObject* proto = obj->getProto(); proto; proto = proto->getProto()) { + for (JSObject* proto = obj->staticPrototype(); proto; proto = proto->staticPrototype()) { chainDepth++; // if prototype is non-native, don't optimize if (!proto->isNative()) return false; + MOZ_ASSERT(proto->hasStaticPrototype()); + // if prototype defines this property in a non-plain way, don't optimize Shape* protoShape = proto->as().lookup(cx, id); if (protoShape && !protoShape->hasDefaultSetter()) @@ -2360,13 +2362,13 @@ SetElemAddHasSameShapes(ICSetElem_DenseOrUnboxedArrayAdd* stub, JSObject* obj) if (obj->maybeShape() != nstub->shape(0)) return false; - JSObject* proto = obj->getProto(); + JSObject* proto = obj->staticPrototype(); for (size_t i = 0; i < stub->protoChainDepth(); i++) { if (!proto->isNative()) return false; if (proto->as().lastProperty() != nstub->shape(i + 1)) return false; - proto = obj->getProto(); + proto = obj->staticPrototype(); if (!proto) { if (i != stub->protoChainDepth() - 1) return false; @@ -2487,12 +2489,12 @@ CanOptimizeDenseOrUnboxedArraySetElem(JSObject* obj, uint32_t index, // Scan the prototype and shape chain to make sure that this is not the case. if (obj->isIndexed()) return false; - JSObject* curObj = obj->getProto(); + JSObject* curObj = obj->staticPrototype(); while (curObj) { ++*protoDepthOut; if (!curObj->isNative() || curObj->isIndexed()) return false; - curObj = curObj->getProto(); + curObj = curObj->staticPrototype(); } if (*protoDepthOut > ICSetElem_DenseOrUnboxedArrayAdd::MAX_PROTO_CHAIN_DEPTH) @@ -3706,7 +3708,7 @@ TryAttachGlobalNameValueStub(JSContext* cx, HandleScript script, jsbytecode* pc, if (current == globalLexical) { current = &globalLexical->global(); } else { - JSObject* proto = current->getProto(); + JSObject* proto = current->staticPrototype(); if (!proto || !proto->is()) return true; current = &proto->as(); @@ -3781,7 +3783,7 @@ TryAttachGlobalNameAccessorStub(JSContext* cx, HandleScript script, jsbytecode* shape = current->lookup(cx, id); if (shape) break; - JSObject* proto = current->getProto(); + JSObject* proto = current->staticPrototype(); if (!proto || !proto->is()) return true; current = &proto->as(); @@ -7770,12 +7772,14 @@ TryAttachInstanceOfStub(JSContext* cx, BaselineFrame* frame, ICInstanceOf_Fallba // clobber it. if (!js::FunctionHasDefaultHasInstance(fun, cx->wellKnownSymbols())) return true; + // Refuse to optimize any function whose [[Prototype]] isn't // Function.prototype. - if (fun->hasLazyPrototype() || fun->hasUncacheableProto()) + if (!fun->hasStaticPrototype() || fun->hasUncacheableProto()) return true; + Value funProto = cx->global()->getPrototype(JSProto_Function); - if (funProto.isObject() && fun->getProto() != &funProto.toObject()) + if (funProto.isObject() && fun->staticPrototype() != &funProto.toObject()) return true; Shape* shape = fun->lookupPure(cx->names().prototype); diff --git a/js/src/jit/CacheIR.cpp b/js/src/jit/CacheIR.cpp index c376dd5456..075f4b0eae 100644 --- a/js/src/jit/CacheIR.cpp +++ b/js/src/jit/CacheIR.cpp @@ -137,12 +137,10 @@ GeneratePrototypeGuards(CacheIRWriter& writer, JSObject* obj, JSObject* holder, if (obj->hasUncacheableProto()) { // If the shape does not imply the proto, emit an explicit proto guard. - writer.guardProto(objId, obj->getProto()); + writer.guardProto(objId, obj->staticPrototype()); } - JSObject* pobj = IsCacheableDOMProxy(obj) - ? obj->getTaggedProto().toObjectOrNull() - : obj->getProto(); + JSObject* pobj = obj->staticPrototype(); if (!pobj) return; @@ -151,12 +149,12 @@ GeneratePrototypeGuards(CacheIRWriter& writer, JSObject* obj, JSObject* holder, ObjOperandId protoId = writer.loadObject(pobj); if (pobj->isSingleton()) { // Singletons can have their group's |proto| mutated directly. - writer.guardProto(protoId, pobj->getProto()); + writer.guardProto(protoId, pobj->staticPrototype()); } else { writer.guardGroup(protoId, pobj->group()); } } - pobj = pobj->getProto(); + pobj = pobj->staticPrototype(); } } @@ -199,12 +197,12 @@ EmitReadSlotResult(CacheIRWriter& writer, JSObject* obj, JSObject* holder, // The property does not exist. Guard on everything in the prototype // chain. This is guaranteed to see only Native objects because of // CanAttachNativeGetProp(). - JSObject* proto = obj->getTaggedProto().toObjectOrNull(); + JSObject* proto = obj->taggedProto().toObjectOrNull(); ObjOperandId lastObjId = objId; while (proto) { ObjOperandId protoId = writer.loadProto(lastObjId); writer.guardShape(protoId, proto->as().lastProperty()); - proto = proto->getProto(); + proto = proto->staticPrototype(); lastObjId = protoId; } } diff --git a/js/src/jit/IonBuilder.cpp b/js/src/jit/IonBuilder.cpp index c514cc6546..08c2abb906 100644 --- a/js/src/jit/IonBuilder.cpp +++ b/js/src/jit/IonBuilder.cpp @@ -6281,7 +6281,7 @@ IonBuilder::createThisScriptedSingleton(JSFunction* target, MDefinition* callee) return nullptr; if (!templateObject->is() && !templateObject->is()) return nullptr; - if (templateObject->getProto() != proto) + if (templateObject->staticPrototype() != proto) return nullptr; TypeSet::ObjectKey* templateObjectKey = TypeSet::ObjectKey::get(templateObject->group()); @@ -6328,7 +6328,7 @@ IonBuilder::createThisScriptedBaseline(MDefinition* callee) return nullptr; JSObject* proto = checkNurseryObject(&protov.toObject()); - if (proto != templateObject->getProto()) + if (proto != templateObject->staticPrototype()) return nullptr; TypeSet::ObjectKey* templateObjectKey = TypeSet::ObjectKey::get(templateObject->group()); @@ -8116,7 +8116,7 @@ IonBuilder::testSingletonProperty(JSObject* obj, jsid id) if (ObjectHasExtraOwnProperty(compartment, objKey, id)) return nullptr; - obj = checkNurseryObject(obj->getProto()); + obj = checkNurseryObject(obj->staticPrototype()); } return nullptr; @@ -13826,23 +13826,26 @@ IonBuilder::jsop_instanceof() if (!rhsObject || !rhsObject->is() || rhsObject->isBoundFunction()) break; - // Refuse to optimize anything whose [[Prototype]] isn't Function.prototype + // Refuse to optimize anything whose [[Prototype]] isn't Function.prototype // since we can't guarantee that it uses the default @@hasInstance method. - if (rhsObject->hasUncacheableProto() || rhsObject->hasLazyPrototype()) + if (rhsObject->hasUncacheableProto() || !rhsObject->hasStaticPrototype()) break; + Value funProto = script()->global().getPrototype(JSProto_Function); - if (!funProto.isObject() || rhsObject->getProto() != &funProto.toObject()) + if (!funProto.isObject() || rhsObject->staticPrototype() != &funProto.toObject()) break; + // If the user has supplied their own @@hasInstance method we shouldn't // clobber it. JSFunction* fun = &rhsObject->as(); const WellKnownSymbols* symbols = &compartment->runtime()->wellKnownSymbols(); if (!js::FunctionHasDefaultHasInstance(fun, *symbols)) break; + // Ensure that we will bail if the @@hasInstance property or [[Prototype]] // change. TypeSet::ObjectKey* rhsKey = TypeSet::ObjectKey::get(rhsObject); - if (!rhsKey->hasStableClassAndProto(constraints())) + if (!rhsKey->hasStableClassAndProto(constraints())) break; if (rhsKey->unknownProperties()) diff --git a/js/src/jit/IonCaches.cpp b/js/src/jit/IonCaches.cpp index 44f2a40027..4d07234733 100644 --- a/js/src/jit/IonCaches.cpp +++ b/js/src/jit/IonCaches.cpp @@ -422,12 +422,10 @@ GeneratePrototypeGuards(JSContext* cx, IonScript* ion, MacroAssembler& masm, JSO // use objectReg in the rest of this function. masm.loadPtr(Address(objectReg, JSObject::offsetOfGroup()), scratchReg); Address proto(scratchReg, ObjectGroup::offsetOfProto()); - masm.branchPtr(Assembler::NotEqual, proto, ImmGCPtr(obj->getProto()), failures); + masm.branchPtr(Assembler::NotEqual, proto, ImmGCPtr(obj->staticPrototype()), failures); } - JSObject* pobj = IsCacheableDOMProxy(obj) - ? obj->getTaggedProto().toObjectOrNull() - : obj->getProto(); + JSObject* pobj = obj->staticPrototype(); if (!pobj) return; while (pobj != holder) { @@ -438,12 +436,14 @@ GeneratePrototypeGuards(JSContext* cx, IonScript* ion, MacroAssembler& masm, JSO // Singletons can have their group's |proto| mutated directly. masm.loadPtr(groupAddr, scratchReg); Address protoAddr(scratchReg, ObjectGroup::offsetOfProto()); - masm.branchPtr(Assembler::NotEqual, protoAddr, ImmGCPtr(pobj->getProto()), failures); + masm.branchPtr(Assembler::NotEqual, protoAddr, ImmGCPtr(pobj->staticPrototype()), + failures); } else { masm.branchPtr(Assembler::NotEqual, groupAddr, ImmGCPtr(pobj->group()), failures); } } - pobj = pobj->getProto(); + + pobj = pobj->staticPrototype(); } } @@ -459,7 +459,7 @@ jit::IsCacheableProtoChainForIonOrCacheIR(JSObject* obj, JSObject* holder) * chain and must check for null proto. The prototype chain can be * altered during the lookupProperty call. */ - JSObject* proto = obj->getProto(); + JSObject* proto = obj->staticPrototype(); if (!proto || !proto->isNative()) return false; obj = proto; @@ -500,7 +500,7 @@ IsCacheableNoProperty(JSObject* obj, JSObject* holder, Shape* shape, jsbytecode* while (obj2) { if (!obj2->isNative()) return false; - obj2 = obj2->getProto(); + obj2 = obj2->staticPrototype(); } // The pc is nullptr if the cache is idempotent. We cannot share missing @@ -819,19 +819,20 @@ GenerateReadSlot(JSContext* cx, IonScript* ion, MacroAssembler& masm, } else { // The property does not exist. Guard on everything in the // prototype chain. - JSObject* proto = obj->getTaggedProto().toObjectOrNull(); + JSObject* proto = obj->staticPrototype(); Register lastReg = object; MOZ_ASSERT(scratchReg != object); while (proto) { masm.loadObjProto(lastReg, scratchReg); // Guard the shape of the current prototype. + MOZ_ASSERT(proto->hasStaticPrototype()); masm.branchPtr(Assembler::NotEqual, Address(scratchReg, JSObject::offsetOfShape()), ImmGCPtr(proto->as().lastProperty()), &prototypeFailures); - proto = proto->getProto(); + proto = proto->staticPrototype(); lastReg = scratchReg; } @@ -1803,7 +1804,7 @@ GetPropertyIC::tryAttachDOMProxyUnshadowed(JSContext* cx, HandleScript outerScri MOZ_ASSERT(monitoredResult()); MOZ_ASSERT(output().hasValue()); - RootedObject checkObj(cx, obj->getTaggedProto().toObjectOrNull()); + RootedObject checkObj(cx, obj->staticPrototype()); RootedNativeObject holder(cx); RootedShape shape(cx); @@ -2920,7 +2921,7 @@ IsCacheableDOMProxyUnshadowedSetterCall(JSContext* cx, HandleObject obj, HandleI { MOZ_ASSERT(IsCacheableDOMProxy(obj)); - RootedObject checkObj(cx, obj->getTaggedProto().toObjectOrNull()); + RootedObject checkObj(cx, obj->staticPrototype()); if (!checkObj) return false; @@ -3043,7 +3044,7 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att CheckTypeSetForWrite(masm, obj, newShape->propid(), tempReg, value, failures); // Guard shapes along prototype chain. - JSObject* proto = obj->getProto(); + JSObject* proto = obj->staticPrototype(); Register protoReg = tempReg; bool first = true; while (proto) { @@ -3056,7 +3057,7 @@ GenerateAddSlot(JSContext* cx, MacroAssembler& masm, IonCache::StubAttacher& att // Ensure that its shape matches. masm.branchTestObjShape(Assembler::NotEqual, protoReg, protoShape, failures); - proto = proto->getProto(); + proto = proto->staticPrototype(); } // Call a stub to (re)allocate dynamic slots, if necessary. @@ -3262,7 +3263,7 @@ PrototypeChainShadowsPropertyAdd(JSContext* cx, JSObject* obj, jsid id) // Walk up the object prototype chain and ensure that all prototypes // are native, and that all prototypes have no getter or setter // defined on the property - for (JSObject* proto = obj->getProto(); proto; proto = proto->getProto()) { + for (JSObject* proto = obj->staticPrototype(); proto; proto = proto->staticPrototype()) { // If prototype is non-native, don't optimize if (!proto->isNative()) return true; @@ -3863,7 +3864,7 @@ GetPropertyIC::canAttachDenseElementHole(JSObject* obj, HandleValue idval, Typed if (ClassCanHaveExtraProperties(obj->getClass())) return false; - JSObject* proto = obj->getProto(); + JSObject* proto = obj->staticPrototype(); if (!proto) break; @@ -3899,10 +3900,10 @@ GenerateDenseElementHole(JSContext* cx, MacroAssembler& masm, IonCache::StubAtta if (obj->hasUncacheableProto()) { masm.loadPtr(Address(object, JSObject::offsetOfGroup()), scratchReg); Address proto(scratchReg, ObjectGroup::offsetOfProto()); - masm.branchPtr(Assembler::NotEqual, proto, ImmGCPtr(obj->getProto()), &failures); + masm.branchPtr(Assembler::NotEqual, proto, ImmGCPtr(obj->staticPrototype()), &failures); } - JSObject* pobj = obj->getProto(); + JSObject* pobj = obj->staticPrototype(); while (pobj) { MOZ_ASSERT(pobj->as().lastProperty()); @@ -3928,7 +3929,7 @@ GenerateDenseElementHole(JSContext* cx, MacroAssembler& masm, IonCache::StubAtta Address initLength(scratchReg, ObjectElements::offsetOfInitializedLength()); masm.branch32(Assembler::NotEqual, initLength, Imm32(0), &failures); - pobj = pobj->getProto(); + pobj = pobj->staticPrototype(); } // Ensure the index is an int32 value. @@ -4332,7 +4333,7 @@ IsDenseElementSetInlineable(JSObject* obj, const Value& idval, ConstantOrRegiste // Scan the prototype and shape chain to make sure that this is not the case. JSObject* curObj = obj; while (curObj) { - // Ensure object is native. + // Ensure object is native. (This guarantees static prototype below.) if (!curObj->isNative()) return false; @@ -4340,7 +4341,7 @@ IsDenseElementSetInlineable(JSObject* obj, const Value& idval, ConstantOrRegiste if (curObj->isIndexed()) return false; - curObj = curObj->getProto(); + curObj = curObj->staticPrototype(); } *checkTypeset = false; diff --git a/js/src/jit/MCallOptimize.cpp b/js/src/jit/MCallOptimize.cpp index cc14918de5..61ca20fb1d 100644 --- a/js/src/jit/MCallOptimize.cpp +++ b/js/src/jit/MCallOptimize.cpp @@ -2057,7 +2057,7 @@ IonBuilder::inlineObjectCreate(CallInfo& callInfo) // Ensure the argument matches the template object's prototype. MDefinition* arg = callInfo.getArg(0); - if (JSObject* proto = templateObject->getProto()) { + if (JSObject* proto = templateObject->staticPrototype()) { if (IsInsideNursery(proto)) return InliningStatus_NotInlined; diff --git a/js/src/jit/MIR.cpp b/js/src/jit/MIR.cpp index f5be1cc1c6..ad222d3cd0 100644 --- a/js/src/jit/MIR.cpp +++ b/js/src/jit/MIR.cpp @@ -5633,7 +5633,7 @@ jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx, if (key->isSingleton()) obj = key->singleton(); else - obj = key->proto().isLazy() ? nullptr : key->proto().toObjectOrNull(); + obj = key->proto().isDynamic() ? nullptr : key->proto().toObjectOrNull(); while (obj) { if (!obj->getClass()->isNative()) @@ -5657,7 +5657,7 @@ jit::PropertyReadNeedsTypeBarrier(JSContext* propertycx, } } - obj = obj->getProto(); + obj = obj->staticPrototype(); } } @@ -5845,7 +5845,7 @@ PrototypeHasIndexedProperty(IonBuilder* builder, JSObject* obj) HeapTypeSetKey index = key->property(JSID_VOID); if (index.nonData(builder->constraints()) || index.isOwnProperty(builder->constraints())) return true; - obj = obj->getProto(); + obj = obj->staticPrototype(); } while (obj); return false; diff --git a/js/src/jit/SharedIC.cpp b/js/src/jit/SharedIC.cpp index 6df746b7c5..004881102d 100644 --- a/js/src/jit/SharedIC.cpp +++ b/js/src/jit/SharedIC.cpp @@ -2172,7 +2172,7 @@ JSObject* GetDOMProxyProto(JSObject* obj) { MOZ_ASSERT(IsCacheableDOMProxy(obj)); - return obj->getTaggedProto().toObjectOrNull(); + return obj->staticPrototype(); } // Look up a property's shape on an object, being careful never to do any effectful @@ -2243,30 +2243,25 @@ IsCacheableProtoChain(JSObject* obj, JSObject* holder, bool isDOMProxy) } } - // Don't handle objects which require a prototype guard. This should - // be uncommon so handling it is likely not worth the complexity. - if (obj->hasUncacheableProto()) - return false; - JSObject* cur = obj; while (cur != holder) { // We cannot assume that we find the holder object on the prototype // chain and must check for null proto. The prototype chain can be // altered during the lookupProperty call. - JSObject* proto; - if (isDOMProxy && cur == obj) - proto = cur->getTaggedProto().toObjectOrNull(); - else - proto = cur->getProto(); + MOZ_ASSERT(!cur->hasDynamicPrototype()); - if (!proto || !proto->isNative()) + // Don't handle objects which require a prototype guard. This should + // be uncommon so handling it is likely not worth the complexity. + if (cur->hasUncacheableProto()) return false; - if (proto->hasUncacheableProto()) + JSObject* proto = cur->staticPrototype(); + if (!proto || !proto->isNative()) return false; cur = proto; } + return true; } @@ -2638,7 +2633,7 @@ CheckHasNoSuchProperty(JSContext* cx, JSObject* obj, PropertyName* name, return false; } - JSObject* proto = curObj->getTaggedProto().toObjectOrNull(); + JSObject* proto = curObj->staticPrototype(); if (!proto) break; @@ -3057,13 +3052,15 @@ ICGetPropNativeCompiler::generateStubCode(MacroAssembler& masm) bool GetProtoShapes(JSObject* obj, size_t protoChainDepth, MutableHandle shapes) { - JSObject* curProto = obj->getProto(); + JSObject* curProto = obj->staticPrototype(); for (size_t i = 0; i < protoChainDepth; i++) { if (!shapes.append(curProto->as().lastProperty())) return false; - curProto = curProto->getProto(); + curProto = curProto->staticPrototype(); } - MOZ_ASSERT(!curProto); + + MOZ_ASSERT(!curProto, + "longer prototype chain encountered than this stub permits!"); return true; } diff --git a/js/src/jsapi.cpp b/js/src/jsapi.cpp index 623d978e3d..38859652cf 100644 --- a/js/src/jsapi.cpp +++ b/js/src/jsapi.cpp @@ -1133,7 +1133,7 @@ JS_MayResolveStandardClass(const JSAtomState& names, jsid id, JSObject* maybeObj // The global object's resolve hook is special: JS_ResolveStandardClass // initializes the prototype chain lazily. Only attempt to optimize here // if we know the prototype chain has been initialized. - if (!maybeObj || !maybeObj->getProto()) + if (!maybeObj || !maybeObj->staticPrototype()) return true; if (!JSID_IS_ATOM(id)) diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 961121ddcd..2cfe230f96 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -4904,9 +4904,9 @@ GetSymbolDescription(HandleSymbol symbol); macro(replace) \ macro(search) \ macro(species) \ + macro(hasInstance) \ macro(split) \ macro(toPrimitive) \ - macro(hasInstance) \ macro(unscopables) enum class SymbolCode : uint32_t { diff --git a/js/src/jsarray.cpp b/js/src/jsarray.cpp index b7124d016b..5c101e5527 100644 --- a/js/src/jsarray.cpp +++ b/js/src/jsarray.cpp @@ -828,26 +828,33 @@ ObjectMayHaveExtraIndexedOwnProperties(JSObject* obj) obj->getClass(), INT_TO_JSID(0), obj); } +/* + * Whether obj may have indexed properties anywhere besides its dense + * elements. This includes other indexed properties in its shape hierarchy, and + * indexed properties or elements along its prototype chain. + */ bool js::ObjectMayHaveExtraIndexedProperties(JSObject* obj) { - /* - * Whether obj may have indexed properties anywhere besides its dense - * elements. This includes other indexed properties in its shape hierarchy, - * and indexed properties or elements along its prototype chain. - */ + MOZ_ASSERT_IF(obj->hasDynamicPrototype(), !obj->isNative()); if (ObjectMayHaveExtraIndexedOwnProperties(obj)) return true; - while ((obj = obj->getProto()) != nullptr) { + do { + MOZ_ASSERT(obj->hasStaticPrototype(), + "dynamic-prototype objects must be non-native, ergo must " + "have failed ObjectMayHaveExtraIndexedOwnProperties"); + + obj = obj->staticPrototype(); + if (!obj) + return false; // no extra indexed properties found + if (ObjectMayHaveExtraIndexedOwnProperties(obj)) return true; if (GetAnyBoxedOrUnboxedInitializedLength(obj) != 0) return true; - } - - return false; + } while (true); } static bool @@ -2700,7 +2707,7 @@ GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj, uint32_t begin, uin do { if (!pobj->isNative() || pobj->getClass()->getResolve() || pobj->getOpsLookupProperty()) return true; - } while ((pobj = pobj->getProto())); + } while ((pobj = pobj->staticPrototype())); // Collect indexed property names. pobj = obj; @@ -2745,7 +2752,7 @@ GetIndexedPropertiesInRange(JSContext* cx, HandleObject obj, uint32_t begin, uin return false; } } - } while ((pobj = pobj->getProto())); + } while ((pobj = pobj->staticPrototype())); // Sort the indexes. Vector tmp(cx); @@ -3609,7 +3616,7 @@ NewArrayTryReuseGroup(JSContext* cx, JSObject* obj, size_t length, if (!obj->is() && !obj->is()) return NewArray(cx, length, nullptr, newKind); - if (obj->getProto() != cx->global()->maybeGetArrayPrototype()) + if (obj->staticPrototype() != cx->global()->maybeGetArrayPrototype()) return NewArray(cx, length, nullptr, newKind); RootedObjectGroup group(cx, obj->getGroup(cx)); diff --git a/js/src/jscompartment.cpp b/js/src/jscompartment.cpp index ab163983cf..3a4574f26e 100644 --- a/js/src/jscompartment.cpp +++ b/js/src/jscompartment.cpp @@ -453,7 +453,7 @@ JSCompartment::wrap(JSContext* cx, MutableHandleObject obj, HandleObject existin RootedObject existing(cx, existingArg); if (existing) { // Is it possible to reuse |existing|? - if (!existing->getTaggedProto().isLazy() || + if (existing->hasStaticPrototype() || // Note: Class asserted above, so all that's left to check is callability existing->isCallable() || obj->isCallable()) diff --git a/js/src/jsfriendapi.cpp b/js/src/jsfriendapi.cpp index 493161e37a..4af361c57c 100644 --- a/js/src/jsfriendapi.cpp +++ b/js/src/jsfriendapi.cpp @@ -353,8 +353,7 @@ JS_FRIEND_API(JSObject*) js::GetPrototypeNoProxy(JSObject* obj) { MOZ_ASSERT(!obj->is()); - MOZ_ASSERT(!obj->getTaggedProto().isLazy()); - return obj->getTaggedProto().toObjectOrNull(); + return obj->staticPrototype(); } JS_FRIEND_API(void) @@ -501,6 +500,13 @@ js::GetObjectProto(JSContext* cx, JS::Handle obj, JS::MutableHandlehasStaticPrototype()); + return obj->staticPrototype(); +} + JS_FRIEND_API(bool) js::GetOriginalEval(JSContext* cx, HandleObject scope, MutableHandleObject eval) { diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 53a616ceb3..501446706e 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -681,6 +681,9 @@ FunctionHasNativeReserved(JSObject* fun); JS_FRIEND_API(bool) GetObjectProto(JSContext* cx, JS::HandleObject obj, JS::MutableHandleObject proto); +extern JS_FRIEND_API(JSObject*) +GetStaticPrototype(JSObject* obj); + JS_FRIEND_API(bool) GetOriginalEval(JSContext* cx, JS::HandleObject scope, JS::MutableHandleObject eval); diff --git a/js/src/jsfun.cpp b/js/src/jsfun.cpp index 862f6af626..14157ccf47 100644 --- a/js/src/jsfun.cpp +++ b/js/src/jsfun.cpp @@ -693,7 +693,6 @@ js::fun_symbolHasInstance(JSContext* cx, unsigned argc, Value* vp) /* * ES6 (4-25-16) 7.3.19 OrdinaryHasInstance */ - bool js::OrdinaryHasInstance(JSContext* cx, HandleObject objArg, MutableHandleValue v, bool* bp) { @@ -1164,20 +1163,6 @@ js::FunctionToString(JSContext* cx, HandleFunction fun, bool lambdaParen) return out.finishString(); } -bool -js::FunctionHasDefaultHasInstance(JSFunction* fun, const WellKnownSymbols& symbols) -{ - jsid id = SYMBOL_TO_JSID(symbols.hasInstance); - Shape* shape = fun->lookupPure(id); - if (shape) { - if (!shape->hasSlot() || !shape->hasDefaultGetter()) - return false; - const Value hasInstance = fun->as().getSlot(shape->slot()); - return IsNativeFunction(hasInstance, js::fun_symbolHasInstance); - } - return true; -} - JSString* fun_toStringHelper(JSContext* cx, HandleObject obj, unsigned indent) { @@ -1196,6 +1181,20 @@ fun_toStringHelper(JSContext* cx, HandleObject obj, unsigned indent) return FunctionToString(cx, fun, indent != JS_DONT_PRETTY_PRINT); } +bool +js::FunctionHasDefaultHasInstance(JSFunction* fun, const WellKnownSymbols& symbols) +{ + jsid id = SYMBOL_TO_JSID(symbols.hasInstance); + Shape* shape = fun->lookupPure(id); + if (shape) { + if (!shape->hasSlot() || !shape->hasDefaultGetter()) + return false; + const Value hasInstance = fun->as().getSlot(shape->slot()); + return IsNativeFunction(hasInstance, js::fun_symbolHasInstance); + } + return true; +} + bool js::fun_toString(JSContext* cx, unsigned argc, Value* vp) { @@ -2107,7 +2106,7 @@ js::CloneFunctionReuseScript(JSContext* cx, HandleFunction fun, HandleObject par * Clone the function, reusing its script. We can use the same group as * the original function provided that its prototype is correct. */ - if (fun->getProto() == clone->getProto()) + if (fun->staticPrototype() == clone->staticPrototype()) clone->setGroup(fun->group()); return clone; } @@ -2260,8 +2259,8 @@ js::ReportIncompatibleMethod(JSContext* cx, CallReceiver call, const Class* clas if (thisv.isObject()) { MOZ_ASSERT(thisv.toObject().getClass() != clasp || !thisv.toObject().isNative() || - !thisv.toObject().getProto() || - thisv.toObject().getProto()->getClass() != clasp); + !thisv.toObject().staticPrototype() || + thisv.toObject().staticPrototype()->getClass() != clasp); } else if (thisv.isString()) { MOZ_ASSERT(clasp != &StringObject::class_); } else if (thisv.isNumber()) { diff --git a/js/src/jsiter.cpp b/js/src/jsiter.cpp index 3bb8aada2f..962b06b74b 100644 --- a/js/src/jsiter.cpp +++ b/js/src/jsiter.cpp @@ -111,8 +111,10 @@ Enumerate(JSContext* cx, HandleObject pobj, jsid id, // It's not necessary to add properties to the hash table at the end of // the prototype chain, but custom enumeration behaviors might return // duplicated properties, so always add in such cases. - if ((pobj->is() || pobj->getProto() || pobj->getOpsEnumerate()) && !ht->add(p, id)) - return false; + if (pobj->is() || pobj->staticPrototype() || pobj->getOpsEnumerate()) { + if (!ht->add(p, id)) + return false; + } } // Symbol-keyed properties and nonenumerable properties are skipped unless @@ -701,7 +703,11 @@ VectorToKeyIterator(JSContext* cx, HandleObject obj, unsigned flags, AutoIdVecto size_t ind = 0; do { ni->guard_array[ind++].init(ReceiverGuard(pobj)); - pobj = pobj->getProto(); + + // The one caller of this method that passes |numGuards > 0|, does + // so only if the entire chain consists of cacheable objects (that + // necessarily have static prototypes). + pobj = pobj->staticPrototype(); } while (pobj); MOZ_ASSERT(ind == numGuards); } @@ -843,10 +849,10 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleOb CanCompareIterableObjectToCache(obj) && ReceiverGuard(obj) == lastni->guard_array[0]) { - JSObject* proto = obj->getProto(); + JSObject* proto = obj->staticPrototype(); if (CanCompareIterableObjectToCache(proto) && ReceiverGuard(proto) == lastni->guard_array[1] && - !proto->getProto()) + !proto->staticPrototype()) { objp.set(last); UpdateNativeIterator(lastni, obj); @@ -856,12 +862,9 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleOb } } - /* - * The iterator object for JSITER_ENUMERATE never escapes, so we - * don't care for the proper parent/proto to be set. This also - * allows us to re-use a previous iterator object that is not - * currently active. - */ + // The iterator object for JSITER_ENUMERATE never escapes, so we don't + // care that the "proper" prototype is set. This also lets us reuse an + // old, inactive iterator object. { JSObject* pobj = obj; do { @@ -869,11 +872,13 @@ js::GetIterator(JSContext* cx, HandleObject obj, unsigned flags, MutableHandleOb guards.clear(); goto miss; } + ReceiverGuard guard(pobj); key = (key + (key << 16)) ^ guard.hash(); if (!guards.append(guard)) return false; - pobj = pobj->getProto(); + + pobj = pobj->staticPrototype(); } while (pobj); } diff --git a/js/src/jsobj.cpp b/js/src/jsobj.cpp index 0c2d7940ec..9c4c82e2cb 100644 --- a/js/src/jsobj.cpp +++ b/js/src/jsobj.cpp @@ -501,7 +501,7 @@ js::SetIntegrityLevel(JSContext* cx, HandleObject obj, IntegrityLevel level) // generic path below then any non-empty object will be converted to // dictionary mode. RootedShape last(cx, EmptyShape::getInitialShape(cx, nobj->getClass(), - nobj->getTaggedProto(), + nobj->taggedProto(), nobj->numFixedSlots(), nobj->lastProperty()->getObjectFlags())); if (!last) @@ -689,7 +689,7 @@ NewObjectCache::fillProto(EntryIndex entry, const Class* clasp, js::TaggedProto gc::AllocKind kind, NativeObject* obj) { MOZ_ASSERT_IF(proto.isObject(), !proto.toObject()->is()); - MOZ_ASSERT(obj->getTaggedProto() == proto); + MOZ_ASSERT(obj->taggedProto() == proto); return fill(entry, clasp, proto.raw(), kind, obj); } @@ -914,7 +914,7 @@ CreateThisForFunctionWithGroup(JSContext* cx, HandleObjectGroup group, return nullptr; if (newKind == SingletonObject) { - Rooted proto(cx, TaggedProto(templateObject->getProto())); + Rooted proto(cx, TaggedProto(templateObject->staticPrototype())); if (!res->splicePrototype(cx, &PlainObject::class_, proto)) return nullptr; } else { @@ -1341,13 +1341,13 @@ InitializePropertiesFromCompatibleNativeObject(JSContext* cx, MOZ_ASSERT(!src->hasPrivate()); RootedShape shape(cx); - if (src->getProto() == dst->getProto()) { + if (src->staticPrototype() == dst->staticPrototype()) { shape = src->lastProperty(); } else { // We need to generate a new shape for dst that has dst's proto but all // the property information from src. Note that we asserted above that // dst's object flags are 0. - shape = EmptyShape::getInitialShape(cx, dst->getClass(), dst->getTaggedProto(), + shape = EmptyShape::getInitialShape(cx, dst->getClass(), dst->taggedProto(), dst->numFixedSlots(), 0); if (!shape) return false; @@ -1943,7 +1943,7 @@ js::SetClassAndProto(JSContext* cx, HandleObject obj, MOZ_ASSERT(obj == oldproto); break; } - oldproto = oldproto->getProto(); + oldproto = oldproto->staticPrototype(); } if (proto.isObject() && !proto.toObject()->setDelegate(cx)) @@ -1993,7 +1993,7 @@ JSObject::changeToSingleton(JSContext* cx, HandleObject obj) MarkObjectGroupUnknownProperties(cx, obj->group()); ObjectGroup* group = ObjectGroup::lazySingletonGroup(cx, obj->getClass(), - obj->getTaggedProto()); + obj->taggedProto()); if (!group) return false; @@ -2295,7 +2295,7 @@ js::LookupPropertyPure(ExclusiveContext* cx, JSObject* obj, jsid id, JSObject** return true; } - obj = obj->getProto(); + obj = obj->staticPrototype(); } while (obj); *objp = nullptr; @@ -2498,13 +2498,11 @@ bool js::GetPrototypeIfOrdinary(JSContext* cx, HandleObject obj, bool* isOrdinary, MutableHandleObject protop) { - if (obj->getTaggedProto().isLazy()) { - MOZ_ASSERT(obj->is()); + if (obj->is()) return js::Proxy::getPrototypeIfOrdinary(cx, obj, isOrdinary, protop); - } *isOrdinary = true; - protop.set(obj->getTaggedProto().toObjectOrNull()); + protop.set(obj->staticPrototype()); return true; } @@ -2527,19 +2525,15 @@ JS_ImmutablePrototypesEnabled() bool js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::ObjectOpResult& result) { - /* - * If |obj| has a "lazy" [[Prototype]], it is 1) a proxy 2) whose handler's - * {get,set}Prototype and setImmutablePrototype methods mediate access to - * |obj.[[Prototype]]|. The Proxy subsystem is responsible for responding - * to such attempts. - */ - if (obj->hasLazyPrototype()) { + // The proxy trap subsystem fully handles prototype-setting for proxies + // with dynamic [[Prototype]]s. + if (obj->hasDynamicPrototype()) { MOZ_ASSERT(obj->is()); return Proxy::setPrototype(cx, obj, proto, result); } /* Disallow mutation of immutable [[Prototype]]s. */ - if (obj->nonLazyPrototypeIsImmutable() && ImmutablePrototypesEnabled) + if (obj->staticPrototypeIsImmutable() && ImmutablePrototypesEnabled) return result.fail(JSMSG_CANT_SET_PROTO); /* @@ -2576,7 +2570,7 @@ js::SetPrototype(JSContext* cx, HandleObject obj, HandleObject proto, JS::Object * ES6 9.1.2 step 3-4 if |obj.[[Prototype]]| has SameValue as |proto| return true. * Since the values in question are objects, we can just compare pointers. */ - if (proto == obj->getProto()) + if (proto == obj->staticPrototype()) return result.succeed(); /* ES6 9.1.2 step 5 forbids changing [[Prototype]] if not [[Extensible]]. */ @@ -2786,7 +2780,7 @@ js::DefineElement(ExclusiveContext* cx, HandleObject obj, uint32_t index, Handle bool js::SetImmutablePrototype(ExclusiveContext* cx, HandleObject obj, bool* succeeded) { - if (obj->hasLazyPrototype()) { + if (obj->hasDynamicPrototype()) { if (!cx->shouldBeJSContext()) return false; return Proxy::setImmutablePrototype(cx->asJSContext(), obj, succeeded); @@ -3471,7 +3465,8 @@ JSObject::dump() if (obj->hasUncacheableProto()) fprintf(stderr, " has_uncacheable_proto"); if (obj->hadElementsAccess()) fprintf(stderr, " had_elements_access"); if (obj->wasNewScriptCleared()) fprintf(stderr, " new_script_cleared"); - if (!obj->hasLazyPrototype() && obj->nonLazyPrototypeIsImmutable()) fprintf(stderr, " immutable_prototype"); + if (obj->hasStaticPrototype() && obj->staticPrototypeIsImmutable()) + fprintf(stderr, " immutable_prototype"); if (obj->isNative()) { NativeObject* nobj = &obj->as(); @@ -3497,9 +3492,9 @@ JSObject::dump() } fprintf(stderr, "proto "); - TaggedProto proto = obj->getTaggedProto(); - if (proto.isLazy()) - fprintf(stderr, ""); + TaggedProto proto = obj->taggedProto(); + if (proto.isDynamic()) + fprintf(stderr, ""); else dumpValue(ObjectOrNullValue(proto.toObjectOrNull())); fputc('\n', stderr); diff --git a/js/src/jsobj.h b/js/src/jsobj.h index 845681ad9d..bbaf785b7e 100644 --- a/js/src/jsobj.h +++ b/js/src/jsobj.h @@ -265,6 +265,9 @@ class JSObject : public js::gc::Cell // hasUncacheableProto flag. inline bool hasUncacheableProto() const; bool setUncacheableProto(js::ExclusiveContext* cx) { + MOZ_ASSERT(hasStaticPrototype(), + "uncacheability as a concept is only applicable to static " + "(not dynamically-computed) prototypes"); return setFlags(cx, js::BaseShape::UNCACHEABLE_PROTO, GENERATE_SHAPE); } @@ -355,20 +358,26 @@ class JSObject : public js::gc::Cell } /* - * We allow the prototype of an object to be lazily computed if the object - * is a proxy. In the lazy case, we store (JSObject*)0x1 in the proto field - * of the object's group. We offer three ways of getting the prototype: + * We permit proxies to dynamically compute their prototype if desired. + * (Not all proxies will so desire: in particular, most DOM proxies can + * track their prototype with a single, nullable JSObject*.) If a proxy + * so desires, we store (JSObject*)0x1 in the proto field of the object's + * group. * - * 1. obj->getProto() returns the prototype, but asserts if obj is a proxy - * with a relevant getPrototype() handler. - * 2. obj->getTaggedProto() returns a TaggedProto, which can be tested to + * We offer three ways to get an object's prototype: + * + * 1. obj->staticPrototype() returns the prototype, but it asserts if obj + * is a proxy, and the proxy has opted to dynamically compute its + * prototype using a getPrototype() handler. + * 2. obj->taggedProto() returns a TaggedProto, which can be tested to * check if the proto is an object, nullptr, or lazily computed. * 3. js::GetPrototype(cx, obj, &proto) computes the proto of an object. - * If obj is a proxy and the proto is lazy, this code may allocate or - * GC in order to compute the proto. Currently, it will not run JS code. + * If obj is a proxy with dynamically-computed prototype, this code may + * perform arbitrary behavior (allocation, GC, run JS) while computing + * the proto. */ - js::TaggedProto getTaggedProto() const { + js::TaggedProto taggedProto() const { return group_->proto(); } @@ -376,37 +385,34 @@ class JSObject : public js::gc::Cell bool uninlinedIsProxy() const; - JSObject* getProto() const { - MOZ_ASSERT(!hasLazyPrototype()); - return getTaggedProto().toObjectOrNull(); + JSObject* staticPrototype() const { + MOZ_ASSERT(hasStaticPrototype()); + return taggedProto().toObjectOrNull(); } - // Normal objects and a subset of proxies have uninteresting [[Prototype]]. - // For such objects the [[Prototype]] is just a value returned when needed - // for accesses, or modified in response to requests. These objects store - // the [[Prototype]] directly within |obj->type_|. - // - // Proxies that don't have such a simple [[Prototype]] instead have a - // "lazy" [[Prototype]]. Accessing the [[Prototype]] of such an object - // requires going through the proxy handler {get,set}Prototype and - // setImmutablePrototype methods. This is most commonly useful for proxies - // that are wrappers around other objects. If the [[Prototype]] of the - // underlying object changes, the [[Prototype]] of the wrapper must also - // simultaneously change. We implement this by having the handler methods - // simply delegate to the wrapped object, forwarding its response to the - // caller. - // - // This method returns true if this object has a non-simple [[Prototype]] - // as described above, or false otherwise. - bool hasLazyPrototype() const { - bool lazy = getTaggedProto().isLazy(); - MOZ_ASSERT_IF(lazy, uninlinedIsProxy()); - return lazy; + // Normal objects and a subset of proxies have an uninteresting, static + // (albeit perhaps mutable) [[Prototype]]. For such objects the + // [[Prototype]] is just a value returned when needed for accesses, or + // modified in response to requests. These objects store the + // [[Prototype]] directly within |obj->group_|. + bool hasStaticPrototype() const { + return !hasDynamicPrototype(); } - // True iff this object's [[Prototype]] is immutable. Must not be called - // on proxies with lazy [[Prototype]]! - inline bool nonLazyPrototypeIsImmutable() const; + // The remaining proxies have a [[Prototype]] requiring dynamic computation + // for every access, going through the proxy handler {get,set}Prototype and + // setImmutablePrototype methods. (Wrappers particularly use this to keep + // the wrapper/wrappee [[Prototype]]s consistent.) + bool hasDynamicPrototype() const { + bool dynamic = taggedProto().isDynamic(); + MOZ_ASSERT_IF(dynamic, uninlinedIsProxy()); + MOZ_ASSERT_IF(dynamic, !isNative()); + return dynamic; + } + + // True iff this object's [[Prototype]] is immutable. Must be called only + // on objects with a static [[Prototype]]! + inline bool staticPrototypeIsImmutable() const; inline void setGroup(js::ObjectGroup* group); diff --git a/js/src/jsobjinlines.h b/js/src/jsobjinlines.h index c607349ee7..a38bdc9375 100644 --- a/js/src/jsobjinlines.h +++ b/js/src/jsobjinlines.h @@ -117,7 +117,7 @@ JSObject::setSingleton(js::ExclusiveContext* cx, js::HandleObject obj) MOZ_ASSERT_IF(cx->isJSContext(), !IsInsideNursery(obj)); js::ObjectGroup* group = js::ObjectGroup::lazySingletonGroup(cx, obj->getClass(), - obj->getTaggedProto()); + obj->taggedProto()); if (!group) return false; @@ -152,13 +152,13 @@ JSObject::setGroup(js::ObjectGroup* group) inline bool js::GetPrototype(JSContext* cx, js::HandleObject obj, js::MutableHandleObject protop) { - if (obj->getTaggedProto().isLazy()) { + if (obj->hasDynamicPrototype()) { MOZ_ASSERT(obj->is()); return js::Proxy::getPrototype(cx, obj, protop); - } else { - protop.set(obj->getTaggedProto().toObjectOrNull()); - return true; } + + protop.set(obj->taggedProto().toObjectOrNull()); + return true; } inline bool @@ -487,9 +487,9 @@ JSObject::isIndexed() const } inline bool -JSObject::nonLazyPrototypeIsImmutable() const +JSObject::staticPrototypeIsImmutable() const { - MOZ_ASSERT(!hasLazyPrototype()); + MOZ_ASSERT(hasStaticPrototype()); return hasAllFlags(js::BaseShape::IMMUTABLE_PROTOTYPE); } @@ -564,7 +564,7 @@ ClassMethodIsNative(JSContext* cx, NativeObject* obj, const Class* clasp, jsid m Value v; if (!HasDataProperty(cx, obj, methodid, &v)) { - JSObject* proto = obj->getProto(); + JSObject* proto = obj->staticPrototype(); if (!proto || proto->getClass() != clasp || !HasDataProperty(cx, &proto->as(), methodid, &v)) return false; } @@ -585,7 +585,7 @@ HasObjectValueOf(JSObject* obj, JSContext* cx) Value v; while (!HasDataProperty(cx, &obj->as(), valueOf, &v)) { - obj = obj->getProto(); + obj = obj->staticPrototype(); if (!obj || obj->is() || !obj->isNative()) return false; } diff --git a/js/src/proxy/BaseProxyHandler.cpp b/js/src/proxy/BaseProxyHandler.cpp index ec0d392fd6..2d47bf4efa 100644 --- a/js/src/proxy/BaseProxyHandler.cpp +++ b/js/src/proxy/BaseProxyHandler.cpp @@ -396,14 +396,14 @@ BaseProxyHandler::weakmapKeyDelegate(JSObject* proxy) const bool BaseProxyHandler::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const { - MOZ_CRASH("must override getPrototype with lazy prototype"); + MOZ_CRASH("must override getPrototype with dynamic prototype"); } bool BaseProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) const { - // Disallow sets of protos on proxies with lazy protos, but no hook. + // Disallow sets of protos on proxies with dynamic prototypes but no hook. // This keeps us away from the footgun of having the first proto set opt // you out of having dynamic protos altogether. JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_CANT_SET_PROTO_OF, @@ -411,13 +411,6 @@ BaseProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObject p return false; } -bool -BaseProxyHandler::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, - MutableHandleObject protop) const -{ - MOZ_CRASH("must override getPrototypeIfOrdinary with lazy prototype"); -} - bool BaseProxyHandler::setImmutablePrototype(JSContext* cx, HandleObject proxy, bool* succeeded) const { diff --git a/js/src/proxy/Proxy.cpp b/js/src/proxy/Proxy.cpp index ba5f52bdf9..56e1a661f1 100644 --- a/js/src/proxy/Proxy.cpp +++ b/js/src/proxy/Proxy.cpp @@ -183,7 +183,7 @@ js::AppendUnique(JSContext* cx, AutoIdVector& base, AutoIdVector& others) /* static */ bool Proxy::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject proto) { - MOZ_ASSERT(proxy->hasLazyPrototype()); + MOZ_ASSERT(proxy->hasDynamicPrototype()); JS_CHECK_RECURSION(cx, return false); return proxy->as().handler()->getPrototype(cx, proxy, proto); } @@ -191,7 +191,7 @@ Proxy::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject proto /* static */ bool Proxy::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, ObjectOpResult& result) { - MOZ_ASSERT(proxy->hasLazyPrototype()); + MOZ_ASSERT(proxy->hasDynamicPrototype()); JS_CHECK_RECURSION(cx, return false); return proxy->as().handler()->setPrototype(cx, proxy, proto, result); } @@ -200,7 +200,6 @@ Proxy::setPrototype(JSContext* cx, HandleObject proxy, HandleObject proto, Objec Proxy::getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, MutableHandleObject proto) { - MOZ_ASSERT(proxy->hasLazyPrototype()); JS_CHECK_RECURSION(cx, return false); return proxy->as().handler()->getPrototypeIfOrdinary(cx, proxy, isOrdinary, proto); @@ -782,7 +781,7 @@ ProxyObject::renew(JSContext* cx, const BaseProxyHandler* handler, Value priv) MOZ_ASSERT_IF(IsCrossCompartmentWrapper(this), IsDeadProxyObject(this)); MOZ_ASSERT(getClass() == &ProxyObject::proxyClass); MOZ_ASSERT(!IsWindowProxy(this)); - MOZ_ASSERT(hasLazyPrototype()); + MOZ_ASSERT(hasDynamicPrototype()); setHandler(handler); setCrossCompartmentPrivate(priv); diff --git a/js/src/tests/ecma_6/Function/has-instance-jitted.js b/js/src/tests/ecma_6/Function/has-instance-jitted.js new file mode 100644 index 0000000000..a2d33abc7f --- /dev/null +++ b/js/src/tests/ecma_6/Function/has-instance-jitted.js @@ -0,0 +1,96 @@ +const OriginalHasInstance = Function.prototype[Symbol.hasInstance]; + +// Ensure that folding doesn't impact user defined @@hasInstance methods. +{ + function Test() { + this.x = 1; + } + + Object.defineProperty(Test, Symbol.hasInstance, + {writable: true, value: () => false}); + + function x(t) { + return t instanceof Test; + } + + function y() { + let t = new Test; + let b = true; + for (let i = 0; i < 10; i++) { + b = b && x(t); + } + return b; + } + + + function z() { + let f = 0; + let t = 0; + for (let i = 0; i < 100; i++) + assertEq(y(), false); + } + + z(); +} + +// Ensure that the jitting does not clobber user defined @@hasInstance methods. +{ + function a() { + function b() {}; + b.__proto__ = a.prototype; + return b; + }; + let c = new a(); + + let t = 0; + let f = 0; + let e = 0; + for (let i = 0; i < 40000; i++) { + if (i == 20000) + Object.defineProperty(a.prototype, Symbol.hasInstance, + {writable: true, value: () => true}); + if (i == 30000) + Object.setPrototypeOf(c, Function.prototype); + + if (1 instanceof c) { + t++; + } else { + f++; + } + } + + assertEq(t, 10000); + assertEq(f, 30000); +} + +{ + function a() {}; + function b() {}; + Object.defineProperty(a, Symbol.hasInstance, {writable: true, value: () => true}); + assertEq(b instanceof a, true); + for (let _ of Array(10000)) + assertEq(b instanceof a, true); +} + +{ + function a(){}; + function b(){}; + function c(){}; + function d(){}; + function e(){}; + Object.defineProperty(a, Symbol.hasInstance, {value: () => true }); + Object.defineProperty(b, Symbol.hasInstance, {value: () => true }); + Object.defineProperty(c, Symbol.hasInstance, {value: () => true }); + Object.defineProperty(d, Symbol.hasInstance, {value: () => true }); + let funcs = [a, b, c, d]; + for (let f of funcs) + assertEq(e instanceof f, true); + + for (let _ of Array(10001)) { + for (let f of funcs) + assertEq(e instanceof f, true); + } +} + +if (typeof reportCompare === "function") + reportCompare(true, true); diff --git a/js/src/tests/ecma_6/Symbol/well-known.js b/js/src/tests/ecma_6/Symbol/well-known.js index 5bad0256be..8c5de12796 100644 --- a/js/src/tests/ecma_6/Symbol/well-known.js +++ b/js/src/tests/ecma_6/Symbol/well-known.js @@ -8,6 +8,7 @@ var names = [ "replace", "search", "species", + "hasInstance", "split", "toPrimitive", "unscopables" diff --git a/js/src/vm/Interpreter.cpp b/js/src/vm/Interpreter.cpp index 3b7ee831c3..79c5df1925 100644 --- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -782,11 +782,7 @@ js::HasInstance(JSContext* cx, HandleObject obj, HandleValue v, bool* bp) RootedValue local(cx, v); if (JSHasInstanceOp hasInstance = clasp->getHasInstance()) return hasInstance(cx, obj, &local, bp); - - RootedValue val(cx, ObjectValue(*obj)); - ReportValueError(cx, JSMSG_BAD_INSTANCEOF_RHS, - JSDVG_SEARCH_STACK, val, nullptr); - return false; + return js::InstanceOfOperator(cx, obj, &local, bp); } static inline bool @@ -3401,7 +3397,8 @@ CASE(JSOP_LAMBDA) JSObject* obj = Lambda(cx, fun, REGS.fp()->scopeChain()); if (!obj) goto error; - MOZ_ASSERT(obj->getProto()); + + MOZ_ASSERT(obj->staticPrototype()); PUSH_OBJECT(*obj); } END_CASE(JSOP_LAMBDA) @@ -3414,7 +3411,8 @@ CASE(JSOP_LAMBDA_ARROW) JSObject* obj = LambdaArrow(cx, fun, REGS.fp()->scopeChain(), newTarget); if (!obj) goto error; - MOZ_ASSERT(obj->getProto()); + + MOZ_ASSERT(obj->staticPrototype()); REGS.sp[-1].setObject(*obj); } END_CASE(JSOP_LAMBDA_ARROW) diff --git a/js/src/vm/NativeObject-inl.h b/js/src/vm/NativeObject-inl.h index 177256834f..05d82b8b92 100644 --- a/js/src/vm/NativeObject-inl.h +++ b/js/src/vm/NativeObject-inl.h @@ -566,7 +566,7 @@ LookupPropertyInline(ExclusiveContext* cx, return true; } - typename MaybeRooted::RootType proto(cx, current->getProto()); + typename MaybeRooted::RootType proto(cx, current->staticPrototype()); if (!proto) break; diff --git a/js/src/vm/NativeObject.cpp b/js/src/vm/NativeObject.cpp index 84c5110b1f..d9d7ec1bec 100644 --- a/js/src/vm/NativeObject.cpp +++ b/js/src/vm/NativeObject.cpp @@ -1086,7 +1086,7 @@ PurgeProtoChain(ExclusiveContext* cx, JSObject* objArg, HandleId id) if (shape) return obj->as().shadowingShapeChange(cx, *shape); - obj = obj->getProto(); + obj = obj->staticPrototype(); } return true; @@ -1105,7 +1105,7 @@ PurgeScopeChainHelper(ExclusiveContext* cx, HandleObject objArg, HandleId id) if (JSID_IS_INT(id)) return true; - if (!PurgeProtoChain(cx, obj->getProto(), id)) + if (!PurgeProtoChain(cx, obj->staticPrototype(), id)) return false; /* @@ -1646,7 +1646,7 @@ js::NativeHasProperty(JSContext* cx, HandleNativeObject obj, HandleId id, bool* // What they all have in common is we do not want to keep walking // the prototype chain, and always claim that the property // doesn't exist. - RootedObject proto(cx, done ? nullptr : pobj->getProto()); + RootedObject proto(cx, done ? nullptr : pobj->staticPrototype()); // Step 8. if (!proto) { @@ -2018,7 +2018,7 @@ NativeGetPropertyInline(JSContext* cx, // being resolved. // What they all have in common is we do not want to keep walking // the prototype chain. - RootedObject proto(cx, done ? nullptr : pobj->getProto()); + RootedObject proto(cx, done ? nullptr : pobj->staticPrototype()); // Step 4.c. The spec algorithm simply returns undefined if proto is // null, but see the comment on GetNonexistentProperty. @@ -2228,9 +2228,10 @@ js::SetPropertyOnProto(JSContext* cx, HandleObject obj, HandleId id, HandleValue { MOZ_ASSERT(!obj->is()); - RootedObject proto(cx, obj->getProto()); + RootedObject proto(cx, obj->staticPrototype()); if (proto) return SetProperty(cx, proto, id, v, receiver, result); + return SetPropertyByDefining(cx, id, v, receiver, result); } @@ -2404,7 +2405,7 @@ js::NativeSetProperty(JSContext* cx, HandleNativeObject obj, HandleId id, Handle // being resolved. // What they all have in common is we do not want to keep walking // the prototype chain. - RootedObject proto(cx, done ? nullptr : pobj->getProto()); + RootedObject proto(cx, done ? nullptr : pobj->staticPrototype()); if (!proto) { // Step 4.d.i (and step 5). return SetNonexistentProperty(cx, id, v, receiver, qualified, result); diff --git a/js/src/vm/ObjectGroup.cpp b/js/src/vm/ObjectGroup.cpp index 6200fd4c52..2c2788f2d9 100644 --- a/js/src/vm/ObjectGroup.cpp +++ b/js/src/vm/ObjectGroup.cpp @@ -260,7 +260,7 @@ JSObject::shouldSplicePrototype(JSContext* cx) * object if their __proto__ had previously been set to null, as this * will change the prototype for all other objects with the same type. */ - if (getProto() != nullptr) + if (staticPrototype() != nullptr) return false; return isSingleton(); } @@ -320,7 +320,7 @@ JSObject::makeLazyGroup(JSContext* cx, HandleObject obj) if (obj->is() && obj->as().length() > INT32_MAX) initialFlags |= OBJECT_FLAG_LENGTH_OVERFLOW; - Rooted proto(cx, obj->getTaggedProto()); + Rooted proto(cx, obj->taggedProto()); ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, obj->getClass(), proto, initialFlags); if (!group) @@ -488,7 +488,7 @@ ObjectGroup::defaultNewGroup(ExclusiveContext* cx, const Class* clasp, } ObjectGroupFlags initialFlags = 0; - if (proto.isLazy() || (proto.isObject() && proto.toObject()->isNewGroupUnknown())) + if (proto.isDynamic() || (proto.isObject() && proto.toObject()->isNewGroupUnknown())) initialFlags = OBJECT_FLAG_DYNAMIC_MASK; Rooted protoRoot(cx, proto); @@ -1208,7 +1208,7 @@ ObjectGroup::newPlainObject(ExclusiveContext* cx, IdValuePair* properties, size_ // default (which will have unknown properties) so that the group we // just created will be collected by the GC. if (obj->slotSpan() != nproperties) { - ObjectGroup* group = defaultNewGroup(cx, obj->getClass(), obj->getTaggedProto()); + ObjectGroup* group = defaultNewGroup(cx, obj->getClass(), obj->taggedProto()); if (!group) return nullptr; obj->setGroup(group); diff --git a/js/src/vm/ObjectGroup.h b/js/src/vm/ObjectGroup.h index 9c5dd39f3d..82befe49c4 100644 --- a/js/src/vm/ObjectGroup.h +++ b/js/src/vm/ObjectGroup.h @@ -99,6 +99,10 @@ class ObjectGroup : public gc::TenuredCell clasp_ = clasp; } + bool hasDynamicPrototype() const { + return proto_.isDynamic(); + } + const HeapPtr& proto() const { return proto_; } diff --git a/js/src/vm/PIC.cpp b/js/src/vm/PIC.cpp index 86da0b9e79..587a80cd0d 100644 --- a/js/src/vm/PIC.cpp +++ b/js/src/vm/PIC.cpp @@ -181,14 +181,7 @@ bool js::ForOfPIC::Chain::isOptimizableArray(JSObject* obj) { MOZ_ASSERT(obj->is()); - - // Ensure object's prototype is the actual Array.prototype - if (!obj->getTaggedProto().isObject()) - return false; - if (obj->getTaggedProto().toObject() != arrayProto_) - return false; - - return true; + return obj->staticPrototype() == arrayProto_; } bool diff --git a/js/src/vm/RegExpObject.cpp b/js/src/vm/RegExpObject.cpp index 9b7f42c5e4..c15fcccbe9 100644 --- a/js/src/vm/RegExpObject.cpp +++ b/js/src/vm/RegExpObject.cpp @@ -849,7 +849,7 @@ RegExpCompartment::createMatchResultTemplateObject(JSContext* cx) return matchResultTemplateObject_; // = nullptr // Create a new group for the template. - Rooted proto(cx, templateObject->getTaggedProto()); + Rooted proto(cx, templateObject->taggedProto()); ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, templateObject->getClass(), proto); if (!group) return matchResultTemplateObject_; // = nullptr diff --git a/js/src/vm/ScopeObject.cpp b/js/src/vm/ScopeObject.cpp index 19ae97f5b7..6dc765b374 100644 --- a/js/src/vm/ScopeObject.cpp +++ b/js/src/vm/ScopeObject.cpp @@ -2003,6 +2003,12 @@ class DebugScopeProxy : public BaseProxyHandler return isFunctionScope(scope) && !scope.as().callee().hasLexicalThis(); } + bool getPrototypeIfOrdinary(JSContext* cx, HandleObject proxy, bool* isOrdinary, + MutableHandleObject protop) const override + { + MOZ_CRASH("shouldn't be possible to access the prototype chain of a DebugScopeProxy"); + } + bool preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const override { diff --git a/js/src/vm/ScopeObject.h b/js/src/vm/ScopeObject.h index d41eb8f0b3..b2e1bcfab9 100644 --- a/js/src/vm/ScopeObject.h +++ b/js/src/vm/ScopeObject.h @@ -897,7 +897,7 @@ class NestedScopeObject : public ScopeObject public: // Return the static scope corresponding to this scope chain object. inline NestedStaticScope* staticScope() { - return &getProto()->as(); + return &staticPrototype()->as(); } void initEnclosingScope(JSObject* obj) { @@ -927,7 +927,7 @@ class DynamicWithObject : public NestedScopeObject WithKind kind = SyntacticWith); StaticWithScope& staticWith() const { - return getProto()->as(); + return staticPrototype()->as(); } /* Return the 'o' in 'with (o)'. */ @@ -1007,7 +1007,7 @@ class ClonedBlockObject : public NestedScopeObject public: /* The static block from which this block was cloned. */ StaticBlockScope& staticBlock() const { - return getProto()->as(); + return staticPrototype()->as(); } /* Assuming 'put' has been called, return the value of the ith let var. */ @@ -1387,7 +1387,7 @@ template<> inline bool JSObject::is() const { - return hasClass(&js::ClonedBlockObject::class_) && !getProto(); + return hasClass(&js::ClonedBlockObject::class_) && !staticPrototype(); } template<> @@ -1411,7 +1411,7 @@ template<> inline bool JSObject::is() const { - return hasClass(&js::ClonedBlockObject::class_) && !!getProto(); + return hasClass(&js::ClonedBlockObject::class_) && staticPrototype(); } template<> diff --git a/js/src/vm/SelfHosting.cpp b/js/src/vm/SelfHosting.cpp index 40bcb7df59..3678f89768 100644 --- a/js/src/vm/SelfHosting.cpp +++ b/js/src/vm/SelfHosting.cpp @@ -479,7 +479,7 @@ intrinsic_FinishBoundFunctionInit(JSContext* cx, unsigned argc, Value* vp) if (!GetPrototype(cx, targetObj, &proto)) return false; - if (bound->getProto() != proto) { + if (bound->staticPrototype() != proto) { if (!SetPrototype(cx, bound, proto)) return false; } diff --git a/js/src/vm/Shape-inl.h b/js/src/vm/Shape-inl.h index 92e0b9f54a..e44459f110 100644 --- a/js/src/vm/Shape-inl.h +++ b/js/src/vm/Shape-inl.h @@ -134,7 +134,7 @@ EmptyShape::ensureInitialCustomShape(ExclusiveContext* cx, HandlegetProto()); + RootedObject proto(cx, obj->staticPrototype()); EmptyShape::insertInitialShape(cx, shape, proto); return true; } diff --git a/js/src/vm/Shape.cpp b/js/src/vm/Shape.cpp index be919c5c91..50b2bbf031 100644 --- a/js/src/vm/Shape.cpp +++ b/js/src/vm/Shape.cpp @@ -1194,7 +1194,7 @@ JSObject::setFlags(ExclusiveContext* cx, BaseShape::Flag flags, GenerateShape ge if (!existingShape) return false; - Shape* newShape = Shape::setObjectFlags(cx, flags, self->getTaggedProto(), existingShape); + Shape* newShape = Shape::setObjectFlags(cx, flags, self->taggedProto(), existingShape); if (!newShape) return false; diff --git a/js/src/vm/TaggedProto.cpp b/js/src/vm/TaggedProto.cpp index a7c79aff27..bde4a50576 100644 --- a/js/src/vm/TaggedProto.cpp +++ b/js/src/vm/TaggedProto.cpp @@ -49,7 +49,7 @@ js::TaggedProto::hashCode() const uint64_t js::TaggedProto::uniqueId() const { - if (isLazy()) + if (isDynamic()) return uint64_t(1); JSObject* obj = toObjectOrNull(); if (!obj) diff --git a/js/src/vm/TaggedProto.h b/js/src/vm/TaggedProto.h index 675b21ddac..cad3248221 100644 --- a/js/src/vm/TaggedProto.h +++ b/js/src/vm/TaggedProto.h @@ -24,7 +24,7 @@ class TaggedProto uintptr_t toWord() const { return uintptr_t(proto); } - bool isLazy() const { + bool isDynamic() const { return proto == LazyProto; } bool isObject() const { @@ -83,7 +83,7 @@ class TaggedProtoOperations public: uintptr_t toWord() const { return value().toWord(); } - inline bool isLazy() const { return value().isLazy(); } + inline bool isDynamic() const { return value().isDynamic(); } inline bool isObject() const { return value().isObject(); } inline JSObject* toObject() const { return value().toObject(); } inline JSObject* toObjectOrNull() const { return value().toObjectOrNull(); } diff --git a/js/src/vm/TraceLoggingGraph.cpp b/js/src/vm/TraceLoggingGraph.cpp index 262d16a5bf..88cfbb8f7c 100644 --- a/js/src/vm/TraceLoggingGraph.cpp +++ b/js/src/vm/TraceLoggingGraph.cpp @@ -6,6 +6,13 @@ #include "vm/TraceLoggingGraph.h" +#ifdef XP_WIN +#include +#define getpid _getpid +#else +#include +#endif + #include "mozilla/Endian.h" #include "jsstr.h" @@ -28,12 +35,23 @@ TraceLoggerGraphState* traceLoggerGraphState = nullptr; bool TraceLoggerGraphState::init() { - out = fopen(TRACE_LOG_DIR "tl-data.json", "w"); + pid_ = (uint32_t) getpid(); + + char filename[sizeof TRACE_LOG_DIR "tl-data.4294967295.json"]; + sprintf(filename, TRACE_LOG_DIR "tl-data.%u.json", pid_); + out = fopen(filename, "w"); if (!out) return false; fprintf(out, "["); + // Write the last tl-data.*.json file to tl-data.json. + // In most cases that is the wanted file. + if (FILE* last = fopen(TRACE_LOG_DIR "tl-data.json", "w")) { + fprintf(last, "\"tl-data.%u.json\"", pid_); + fclose(last); + } + #ifdef DEBUG initialized = true; #endif @@ -73,9 +91,9 @@ TraceLoggerGraphState::nextLoggerId() } } - int written = fprintf(out, "{\"tree\":\"tl-tree.%d.tl\", \"events\":\"tl-event.%d.tl\", " - "\"dict\":\"tl-dict.%d.json\", \"treeFormat\":\"64,64,31,1,32\"}", - numLoggers, numLoggers, numLoggers); + int written = fprintf(out, "{\"tree\":\"tl-tree.%u.%d.tl\", \"events\":\"tl-event.%u.%d.tl\", " + "\"dict\":\"tl-dict.%u.%d.json\", \"treeFormat\":\"64,64,31,1,32\"}", + pid_, numLoggers, pid_, numLoggers, pid_, numLoggers); if (written < 0) { fprintf(stderr, "TraceLogging: Error while writing.\n"); return uint32_t(-1); @@ -134,16 +152,18 @@ TraceLoggerGraph::init(uint64_t startTimestamp) return false; } - char dictFilename[sizeof TRACE_LOG_DIR "tl-dict.100.json"]; - sprintf(dictFilename, TRACE_LOG_DIR "tl-dict.%d.json", loggerId); + uint32_t pid = traceLoggerGraphState->pid(); + + char dictFilename[sizeof TRACE_LOG_DIR "tl-dict.4294967295.100.json"]; + sprintf(dictFilename, TRACE_LOG_DIR "tl-dict.%u.%d.json", pid, loggerId); dictFile = fopen(dictFilename, "w"); if (!dictFile) { failed = true; return false; } - char treeFilename[sizeof TRACE_LOG_DIR "tl-tree.100.tl"]; - sprintf(treeFilename, TRACE_LOG_DIR "tl-tree.%d.tl", loggerId); + char treeFilename[sizeof TRACE_LOG_DIR "tl-tree.4294967295.100.tl"]; + sprintf(treeFilename, TRACE_LOG_DIR "tl-tree.%u.%d.tl", pid, loggerId); treeFile = fopen(treeFilename, "w+b"); if (!treeFile) { fclose(dictFile); @@ -152,8 +172,8 @@ TraceLoggerGraph::init(uint64_t startTimestamp) return false; } - char eventFilename[sizeof TRACE_LOG_DIR "tl-event.100.tl"]; - sprintf(eventFilename, TRACE_LOG_DIR "tl-event.%d.tl", loggerId); + char eventFilename[sizeof TRACE_LOG_DIR "tl-event.4294967295.100.tl"]; + sprintf(eventFilename, TRACE_LOG_DIR "tl-event.%u.%d.tl", pid, loggerId); eventFile = fopen(eventFilename, "wb"); if (!eventFile) { fclose(dictFile); @@ -570,3 +590,5 @@ TraceLoggerGraph::addTextId(uint32_t id, const char* text) if (!js::FileEscapedString(dictFile, text, strlen(text), '"')) failed = true; } + +#undef getpid diff --git a/js/src/vm/TraceLoggingGraph.h b/js/src/vm/TraceLoggingGraph.h index f9147531f5..a1430e215f 100644 --- a/js/src/vm/TraceLoggingGraph.h +++ b/js/src/vm/TraceLoggingGraph.h @@ -68,6 +68,7 @@ void DestroyTraceLoggerGraphState(); class TraceLoggerGraphState { uint32_t numLoggers; + uint32_t pid_; // File pointer to the "tl-data.json" file. (Explained above). FILE* out; @@ -81,8 +82,9 @@ class TraceLoggerGraphState public: TraceLoggerGraphState() - : numLoggers(0) - , out(nullptr) + : numLoggers(0), + pid_(0), + out(nullptr) #ifdef DEBUG , initialized(false) #endif @@ -92,6 +94,7 @@ class TraceLoggerGraphState ~TraceLoggerGraphState(); uint32_t nextLoggerId(); + uint32_t pid() { return pid_; } }; class TraceLoggerGraph diff --git a/js/src/vm/TypeInference.cpp b/js/src/vm/TypeInference.cpp index 7995ee1d7c..558955392f 100644 --- a/js/src/vm/TypeInference.cpp +++ b/js/src/vm/TypeInference.cpp @@ -1215,7 +1215,7 @@ TypeSet::ObjectKey::clasp() TaggedProto TypeSet::ObjectKey::proto() { - return isGroup() ? group()->proto() : singleton()->getTaggedProto(); + return isGroup() ? group()->proto() : singleton()->taggedProto(); } TypeNewScript* @@ -2422,7 +2422,7 @@ TemporaryTypeSet::getCommonPrototype(CompilerConstraintList* constraints, JSObje TaggedProto nproto = key->proto(); if (isFirst) { - if (nproto.isLazy()) + if (nproto.isDynamic()) return false; *proto = nproto.toObjectOrNull(); isFirst = false; @@ -2486,7 +2486,7 @@ PrototypeHasIndexedProperty(CompilerConstraintList* constraints, JSObject* obj) HeapTypeSetKey index = key->property(JSID_VOID); if (index.nonData(constraints) || index.isOwnProperty(constraints)) return true; - obj = obj->getProto(); + obj = obj->staticPrototype(); } while (obj); return false; @@ -3052,8 +3052,11 @@ ObjectGroup::print() TaggedProto tagged(proto()); fprintf(stderr, "%s : %s", TypeSet::ObjectGroupString(this), - tagged.isObject() ? TypeSet::TypeString(TypeSet::ObjectType(tagged.toObject())) - : (tagged.isLazy() ? "(lazy)" : "(null)")); + tagged.isObject() + ? TypeSet::TypeString(TypeSet::ObjectType(tagged.toObject())) + : tagged.isDynamic() + ? "(dynamic)" + : "(null)"); if (unknownProperties()) { fprintf(stderr, " unknown"); @@ -3164,7 +3167,7 @@ js::AddClearDefiniteGetterSetterForPrototypeChain(JSContext* cx, ObjectGroup* gr return false; if (!protoTypes->addConstraint(cx, cx->typeLifoAlloc().new_(group))) return false; - proto = proto->getProto(); + proto = proto->staticPrototype(); } return true; } @@ -3364,7 +3367,7 @@ JSFunction::setTypeForScriptedFunction(ExclusiveContext* cx, HandleFunction fun, if (!setSingleton(cx, fun)) return false; } else { - RootedObject funProto(cx, fun->getProto()); + RootedObject funProto(cx, fun->staticPrototype()); Rooted taggedProto(cx, TaggedProto(funProto)); ObjectGroup* group = ObjectGroupCompartment::makeGroup(cx, &JSFunction::class_, taggedProto); @@ -3661,9 +3664,7 @@ ChangeObjectFixedSlotCount(JSContext* cx, PlainObject* obj, gc::AllocKind allocK { MOZ_ASSERT(OnlyHasDataProperties(obj->lastProperty())); - Shape* newShape = ReshapeForAllocKind(cx, obj->lastProperty(), - obj->getTaggedProto(), - allocKind); + Shape* newShape = ReshapeForAllocKind(cx, obj->lastProperty(), obj->taggedProto(), allocKind); if (!newShape) return false; diff --git a/js/src/vm/UnboxedObject.cpp b/js/src/vm/UnboxedObject.cpp index bf6e492589..0fb869f58f 100644 --- a/js/src/vm/UnboxedObject.cpp +++ b/js/src/vm/UnboxedObject.cpp @@ -727,7 +727,7 @@ UnboxedPlainObject::obj_lookupProperty(JSContext* cx, HandleObject obj, return true; } - RootedObject proto(cx, obj->getProto()); + RootedObject proto(cx, obj->staticPrototype()); if (!proto) { objp.set(nullptr); propp.set(nullptr); @@ -778,7 +778,7 @@ UnboxedPlainObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id return true; } - RootedObject proto(cx, obj->getProto()); + RootedObject proto(cx, obj->staticPrototype()); if (!proto) { *foundp = false; return true; @@ -805,7 +805,7 @@ UnboxedPlainObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue } } - RootedObject proto(cx, obj->getProto()); + RootedObject proto(cx, obj->staticPrototype()); if (!proto) { vp.setUndefined(); return true; @@ -1428,7 +1428,7 @@ UnboxedArrayObject::obj_lookupProperty(JSContext* cx, HandleObject obj, return true; } - RootedObject proto(cx, obj->getProto()); + RootedObject proto(cx, obj->staticPrototype()); if (!proto) { objp.set(nullptr); propp.set(nullptr); @@ -1479,7 +1479,7 @@ UnboxedArrayObject::obj_hasProperty(JSContext* cx, HandleObject obj, HandleId id return true; } - RootedObject proto(cx, obj->getProto()); + RootedObject proto(cx, obj->staticPrototype()); if (!proto) { *foundp = false; return true; @@ -1500,7 +1500,7 @@ UnboxedArrayObject::obj_getProperty(JSContext* cx, HandleObject obj, HandleValue return true; } - RootedObject proto(cx, obj->getProto()); + RootedObject proto(cx, obj->staticPrototype()); if (!proto) { vp.setUndefined(); return true; diff --git a/js/xpconnect/tests/chrome/test_xrayToJS.xul b/js/xpconnect/tests/chrome/test_xrayToJS.xul index d3366b31d0..c3d4e920df 100644 --- a/js/xpconnect/tests/chrome/test_xrayToJS.xul +++ b/js/xpconnect/tests/chrome/test_xrayToJS.xul @@ -214,7 +214,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 gPrototypeProperties['Function'] = ["constructor", "toSource", "toString", "apply", "call", "bind", - "isGenerator", "length", "name", "arguments", "caller"]; + "isGenerator", "length", "name", "arguments", "caller", Symbol.hasInstance]; gConstructorProperties['Function'] = constructorProps([]) gPrototypeProperties['RegExp'] = @@ -579,7 +579,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=933681 trickyArray[1] = "hi"; is(trickyArray.length, 0, "Length remains non-writable"); is(trickyArray[1], undefined, "Frozen length forbids new properties"); - + is(trickyArray instanceof iwin.Array, true, "instanceof should work across xray wrappers."); testTrickyObject(trickyArray); testArrayIterators(new iwin.Array(1, 1, 2, 3, 5), [1, 1, 2, 3, 5]); diff --git a/layout/base/ZoomConstraintsClient.cpp b/layout/base/ZoomConstraintsClient.cpp index e2a4e53921..f660f81b48 100644 --- a/layout/base/ZoomConstraintsClient.cpp +++ b/layout/base/ZoomConstraintsClient.cpp @@ -152,7 +152,7 @@ ZoomConstraintsClient::Observe(nsISupports* aSubject, const char* aTopic, const // We need to run this later because all the pref change listeners need // to execute before we can be guaranteed that gfxPrefs::ForceUserScalable() // returns the updated value. - NS_DispatchToMainThread(NS_NewRunnableMethod( + NS_DispatchToMainThread(NewRunnableMethod( this, &ZoomConstraintsClient::RefreshZoomConstraints)); } return NS_OK; diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 4013147e8d..2450b6d8eb 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -1588,7 +1588,7 @@ nsPresContext::ThemeChanged() sThemeChanged = true; nsCOMPtr ev = - NS_NewRunnableMethod(this, &nsPresContext::ThemeChangedInternal); + NewRunnableMethod(this, &nsPresContext::ThemeChangedInternal); if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) { mPendingThemeChanged = true; } @@ -1647,7 +1647,7 @@ nsPresContext::SysColorChanged() if (!mPendingSysColorChanged) { sLookAndFeelChanged = true; nsCOMPtr ev = - NS_NewRunnableMethod(this, &nsPresContext::SysColorChangedInternal); + NewRunnableMethod(this, &nsPresContext::SysColorChangedInternal); if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) { mPendingSysColorChanged = true; } @@ -1682,7 +1682,7 @@ nsPresContext::UIResolutionChanged() { if (!mPendingUIResolutionChanged) { nsCOMPtr ev = - NS_NewRunnableMethod(this, &nsPresContext::UIResolutionChangedInternal); + NewRunnableMethod(this, &nsPresContext::UIResolutionChangedInternal); if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) { mPendingUIResolutionChanged = true; } @@ -1935,7 +1935,7 @@ nsPresContext::PostMediaFeatureValuesChangedEvent() // need to track whether it's been added). if (!mPendingMediaFeatureValuesChanged) { nsCOMPtr ev = - NS_NewRunnableMethod(this, &nsPresContext::HandleMediaFeatureValuesChangedEvent); + NewRunnableMethod(this, &nsPresContext::HandleMediaFeatureValuesChangedEvent); if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) { mPendingMediaFeatureValuesChanged = true; mDocument->SetNeedStyleFlush(); @@ -2127,7 +2127,7 @@ nsPresContext::RebuildCounterStyles() mDocument->SetNeedStyleFlush(); if (!mPostedFlushCounterStyles) { nsCOMPtr ev = - NS_NewRunnableMethod(this, &nsPresContext::HandleRebuildCounterStyles); + NewRunnableMethod(this, &nsPresContext::HandleRebuildCounterStyles); if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) { mPostedFlushCounterStyles = true; } diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 0e52a84592..af76663136 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1912,7 +1912,7 @@ PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight) } } else { RefPtr > resizeEvent = - NS_NewRunnableMethod(this, &PresShell::FireResizeEvent); + NewRunnableMethod(this, &PresShell::FireResizeEvent); if (NS_SUCCEEDED(NS_DispatchToCurrentThread(resizeEvent))) { mResizeEvent = resizeEvent; mDocument->SetNeedStyleFlush(); @@ -6097,7 +6097,7 @@ PresShell::ScheduleApproximateFrameVisibilityUpdateNow() } RefPtr > ev = - NS_NewRunnableMethod(this, &PresShell::UpdateApproximateFrameVisibility); + NewRunnableMethod(this, &PresShell::UpdateApproximateFrameVisibility); if (NS_SUCCEEDED(NS_DispatchToCurrentThread(ev))) { mUpdateApproximateFrameVisibilityEvent = ev; } @@ -6380,7 +6380,7 @@ PresShell::Paint(nsView* aViewToPaint, // since this is happening during a paint and updating the visible // regions triggers a recomposite. RefPtr> event = - NS_NewRunnableMethod(this, &PresShell::NotifyCompositorOfVisibleRegionsChange); + NewRunnableMethod(this, &PresShell::NotifyCompositorOfVisibleRegionsChange); if (NS_SUCCEEDED(NS_DispatchToMainThread(event))) { mNotifyCompositorOfVisibleRegionsChangeEvent = event; } diff --git a/layout/base/nsRefreshDriver.cpp b/layout/base/nsRefreshDriver.cpp index 473e8c0df3..786373fdf8 100644 --- a/layout/base/nsRefreshDriver.cpp +++ b/layout/base/nsRefreshDriver.cpp @@ -419,9 +419,9 @@ private: } nsCOMPtr vsyncEvent = - NS_NewRunnableMethodWithArg(this, - &RefreshDriverVsyncObserver::TickRefreshDriver, - aVsyncTimestamp); + NewRunnableMethod(this, + &RefreshDriverVsyncObserver::TickRefreshDriver, + aVsyncTimestamp); NS_DispatchToMainThread(vsyncEvent); } else { RefPtr kungFuDeathGrip(this); @@ -1962,7 +1962,7 @@ nsRefreshDriver::Thaw() // updates our mMostRecentRefresh, but the DoRefresh call won't run // and notify our observers until we get back to the event loop. // Thus MostRecentRefresh() will lie between now and the DoRefresh. - NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, &nsRefreshDriver::DoRefresh)); + NS_DispatchToCurrentThread(NewRunnableMethod(this, &nsRefreshDriver::DoRefresh)); EnsureTimerStarted(); } } diff --git a/layout/build/nsLayoutStatics.cpp b/layout/build/nsLayoutStatics.cpp index 39de78771e..deb19b944c 100644 --- a/layout/build/nsLayoutStatics.cpp +++ b/layout/build/nsLayoutStatics.cpp @@ -134,6 +134,7 @@ using namespace mozilla::system; #include "MediaDecoder.h" #include "mozilla/layers/CompositorLRU.h" #include "mozilla/dom/devicestorage/DeviceStorageStatics.h" +#include "mozilla/ServoBindings.h" #include "mozilla/StaticPresData.h" #ifdef MOZ_B2G_BT @@ -326,6 +327,10 @@ nsLayoutStatics::Initialize() mozilla::dom::WebCryptoThreadPool::Initialize(); +#ifdef MOZ_STYLO + Servo_Initialize(); +#endif + return NS_OK; } diff --git a/layout/ipc/VsyncParent.cpp b/layout/ipc/VsyncParent.cpp index 9fdb8511d6..6de114f603 100644 --- a/layout/ipc/VsyncParent.cpp +++ b/layout/ipc/VsyncParent.cpp @@ -50,9 +50,9 @@ VsyncParent::NotifyVsync(TimeStamp aTimeStamp) // Called on hardware vsync thread. We should post to current ipc thread. MOZ_ASSERT(!IsOnBackgroundThread()); nsCOMPtr vsyncEvent = - NS_NewRunnableMethodWithArg(this, - &VsyncParent::DispatchVsyncEvent, - aTimeStamp); + NewRunnableMethod(this, + &VsyncParent::DispatchVsyncEvent, + aTimeStamp); MOZ_ALWAYS_SUCCEEDS(mBackgroundThread->Dispatch(vsyncEvent, NS_DISPATCH_NORMAL)); return true; } diff --git a/layout/style/FontFaceSet.cpp b/layout/style/FontFaceSet.cpp index fc71698570..5650b053a2 100644 --- a/layout/style/FontFaceSet.cpp +++ b/layout/style/FontFaceSet.cpp @@ -1473,7 +1473,7 @@ FontFaceSet::OnFontFaceStatusChanged(FontFace* aFontFace) if (!mDelayedLoadCheck) { mDelayedLoadCheck = true; nsCOMPtr checkTask = - NS_NewRunnableMethod(this, &FontFaceSet::CheckLoadingFinishedAfterDelay); + NewRunnableMethod(this, &FontFaceSet::CheckLoadingFinishedAfterDelay); NS_DispatchToMainThread(checkTask); } } diff --git a/layout/style/ServoBindings.cpp b/layout/style/ServoBindings.cpp index f34583f3ff..b9c1cbd03d 100644 --- a/layout/style/ServoBindings.cpp +++ b/layout/style/ServoBindings.cpp @@ -296,6 +296,13 @@ Servo_ReleaseComputedValues(ServoComputedValues*) "non-MOZ_STYLO build"); } +void +Servo_Initialize() +{ + MOZ_CRASH("stylo: shouldn't be calling Servo_Initialize in a " + "non-MOZ_STYLO build"); +} + void Servo_RestyleDocument(RawGeckoDocument* doc, RawServoStyleSet* set) { diff --git a/layout/style/ServoBindings.h b/layout/style/ServoBindings.h index a96ac15851..1ceb01ad34 100644 --- a/layout/style/ServoBindings.h +++ b/layout/style/ServoBindings.h @@ -93,7 +93,10 @@ ServoComputedValues* Servo_GetComputedValuesForPseudoElement(ServoComputedValues void Servo_AddRefComputedValues(ServoComputedValues*); void Servo_ReleaseComputedValues(ServoComputedValues*); -// Servo API. +// Initialize Servo components. Should be called exactly once at startup. +void Servo_Initialize(); + +// Restyle the given document. void Servo_RestyleDocument(RawGeckoDocument* doc, RawServoStyleSet* set); // Style-struct management. diff --git a/layout/xul/tree/nsTreeColumns.cpp b/layout/xul/tree/nsTreeColumns.cpp index 45e5a8adaf..911cae0956 100644 --- a/layout/xul/tree/nsTreeColumns.cpp +++ b/layout/xul/tree/nsTreeColumns.cpp @@ -606,12 +606,6 @@ nsTreeColumns::NamedGetter(const nsAString& aId, bool& aFound) return nullptr; } -bool -nsTreeColumns::NameIsEnumerable(const nsAString& aName) -{ - return true; -} - nsTreeColumn* nsTreeColumns::GetNamedColumn(const nsAString& aId) { @@ -627,7 +621,7 @@ nsTreeColumns::GetNamedColumn(const nsAString& aId, nsITreeColumn** _retval) } void -nsTreeColumns::GetSupportedNames(unsigned, nsTArray& aNames) +nsTreeColumns::GetSupportedNames(nsTArray& aNames) { for (nsTreeColumn* currCol = mFirstColumn; currCol; currCol = currCol->GetNext()) { aNames.AppendElement(currCol->GetId()); diff --git a/layout/xul/tree/nsTreeColumns.h b/layout/xul/tree/nsTreeColumns.h index 54fed19663..3cbc4db085 100644 --- a/layout/xul/tree/nsTreeColumns.h +++ b/layout/xul/tree/nsTreeColumns.h @@ -186,9 +186,8 @@ public: nsTreeColumn* IndexedGetter(uint32_t aIndex, bool& aFound); nsTreeColumn* GetColumnAt(uint32_t aIndex); nsTreeColumn* NamedGetter(const nsAString& aId, bool& aFound); - bool NameIsEnumerable(const nsAString& aName); nsTreeColumn* GetNamedColumn(const nsAString& aId); - void GetSupportedNames(unsigned, nsTArray& aNames); + void GetSupportedNames(nsTArray& aNames); // Uses XPCOM InvalidateColumns(). // Uses XPCOM RestoreNaturalOrder(). diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp index c262fab714..618858ae46 100644 --- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp +++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp @@ -192,7 +192,7 @@ public: ++mLength; // Atomic nsCOMPtr runnable = - NS_NewRunnableMethodWithArgs, bool>( + NewRunnableMethod, bool>( this, &VideoFrameConverter::ProcessVideoFrame, aChunk.mFrame.GetImage(), forceBlack); mTaskQueue->Dispatch(runnable.forget()); diff --git a/modules/libjar/nsJARChannel.cpp b/modules/libjar/nsJARChannel.cpp index 8060d70891..e6b1e5f849 100644 --- a/modules/libjar/nsJARChannel.cpp +++ b/modules/libjar/nsJARChannel.cpp @@ -1223,11 +1223,10 @@ nsJARChannel::OnDataAvailable(nsIRequest *req, nsISupports *ctx, if (NS_IsMainThread()) { FireOnProgress(offset + count); } else { - nsCOMPtr runnable = - NS_NewRunnableMethodWithArg(this, - &nsJARChannel::FireOnProgress, - offset + count); - NS_DispatchToMainThread(runnable); + NS_DispatchToMainThread(NewRunnableMethod + (this, + &nsJARChannel::FireOnProgress, + offset + count)); } } diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 90e819190d..c87597a56c 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -548,8 +548,6 @@ pref("media.encoder.omx.enabled", true); // Whether to autostart a media element with an |autoplay| attribute pref("media.autoplay.enabled", true); -// Whether to autostart a media element with an autoplaying script event -pref("media.autoplay.allowscripted", true); // The default number of decoded video frames that are enqueued in // MediaDecoderReader's mVideoQueue. diff --git a/netwerk/base/BackgroundFileSaver.cpp b/netwerk/base/BackgroundFileSaver.cpp index 87d5691bf6..1e27ccd35f 100644 --- a/netwerk/base/BackgroundFileSaver.cpp +++ b/netwerk/base/BackgroundFileSaver.cpp @@ -323,11 +323,9 @@ BackgroundFileSaver::GetWorkerThreadAttention(bool aShouldInterruptCopy) if (!mAsyncCopyContext) { // Copy is not in progress, post an event to handle the change manually. - nsCOMPtr event = - NS_NewRunnableMethod(this, &BackgroundFileSaver::ProcessAttention); - NS_ENSURE_TRUE(event, NS_ERROR_FAILURE); - - rv = mWorkerThread->Dispatch(event, NS_DISPATCH_NORMAL); + rv = mWorkerThread->Dispatch(NewRunnableMethod(this, + &BackgroundFileSaver::ProcessAttention), + NS_DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); } else if (aShouldInterruptCopy) { // Interrupt the copy. The copy will be resumed, if needed, by the @@ -745,10 +743,9 @@ BackgroundFileSaver::CheckCompletion() } // Post an event to notify that the operation completed. - nsCOMPtr event = - NS_NewRunnableMethod(this, &BackgroundFileSaver::NotifySaveComplete); - if (!event || - NS_FAILED(mControlThread->Dispatch(event, NS_DISPATCH_NORMAL))) { + if (NS_FAILED(mControlThread->Dispatch(NewRunnableMethod(this, + &BackgroundFileSaver::NotifySaveComplete), + NS_DISPATCH_NORMAL))) { NS_WARNING("Unable to post completion event to the control thread."); } @@ -1142,10 +1139,9 @@ BackgroundFileSaverStreamListener::AsyncCopyProgressCallback(void *aClosure, self->mReceivedTooMuchData = false; // Post an event to verify if the request should be resumed. - nsCOMPtr event = NS_NewRunnableMethod(self, - &BackgroundFileSaverStreamListener::NotifySuspendOrResume); - if (!event || NS_FAILED(self->mControlThread->Dispatch(event, - NS_DISPATCH_NORMAL))) { + if (NS_FAILED(self->mControlThread->Dispatch(NewRunnableMethod(self, + &BackgroundFileSaverStreamListener::NotifySuspendOrResume), + NS_DISPATCH_NORMAL))) { NS_WARNING("Unable to post resume event to the control thread."); } } diff --git a/netwerk/base/Dashboard.cpp b/netwerk/base/Dashboard.cpp index cf180dc1eb..d084f75a1f 100644 --- a/netwerk/base/Dashboard.cpp +++ b/netwerk/base/Dashboard.cpp @@ -175,10 +175,9 @@ ConnectionData::OnTransportStatus(nsITransport *aTransport, nsresult aStatus, } GetErrorString(aStatus, mStatus); - nsCOMPtr event = - NS_NewRunnableMethodWithArg > - (mDashboard, &Dashboard::GetConnectionStatus, this); - mThread->Dispatch(event, NS_DISPATCH_NORMAL); + mThread->Dispatch(NewRunnableMethod> + (mDashboard, &Dashboard::GetConnectionStatus, this), + NS_DISPATCH_NORMAL); return NS_OK; } @@ -197,10 +196,9 @@ ConnectionData::Notify(nsITimer *aTimer) mTimer = nullptr; mStatus.AssignLiteral(MOZ_UTF16("NS_ERROR_NET_TIMEOUT")); - nsCOMPtr event = - NS_NewRunnableMethodWithArg > - (mDashboard, &Dashboard::GetConnectionStatus, this); - mThread->Dispatch(event, NS_DISPATCH_NORMAL); + mThread->Dispatch(NewRunnableMethod> + (mDashboard, &Dashboard::GetConnectionStatus, this), + NS_DISPATCH_NORMAL); return NS_OK; } @@ -287,10 +285,9 @@ LookupHelper::OnLookupComplete(nsICancelable *aRequest, mStatus = aStatus; RefPtr arg = new LookupArgument(aRecord, this); - nsCOMPtr event = - NS_NewRunnableMethodWithArg >( - this, &LookupHelper::ConstructAnswer, arg); - mThread->Dispatch(event, NS_DISPATCH_NORMAL); + mThread->Dispatch(NewRunnableMethod> + (this, &LookupHelper::ConstructAnswer, arg), + NS_DISPATCH_NORMAL); return NS_OK; } @@ -354,10 +351,9 @@ Dashboard::RequestSockets(NetDashboardCallback *aCallback) socketData->mCallback = new nsMainThreadPtrHolder(aCallback, true); socketData->mThread = NS_GetCurrentThread(); - nsCOMPtr event = - NS_NewRunnableMethodWithArg > - (this, &Dashboard::GetSocketsDispatch, socketData); - gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL); + gSocketTransportService->Dispatch(NewRunnableMethod> + (this, &Dashboard::GetSocketsDispatch, socketData), + NS_DISPATCH_NORMAL); return NS_OK; } @@ -370,10 +366,9 @@ Dashboard::GetSocketsDispatch(SocketData *aSocketData) socketData->mTotalSent = gSocketTransportService->GetSentBytes(); socketData->mTotalRecv = gSocketTransportService->GetReceivedBytes(); } - nsCOMPtr event = - NS_NewRunnableMethodWithArg > - (this, &Dashboard::GetSockets, socketData); - socketData->mThread->Dispatch(event, NS_DISPATCH_NORMAL); + socketData->mThread->Dispatch(NewRunnableMethod> + (this, &Dashboard::GetSockets, socketData), + NS_DISPATCH_NORMAL); return NS_OK; } @@ -426,10 +421,9 @@ Dashboard::RequestHttpConnections(NetDashboardCallback *aCallback) new nsMainThreadPtrHolder(aCallback, true); httpData->mThread = NS_GetCurrentThread(); - nsCOMPtr event = - NS_NewRunnableMethodWithArg > - (this, &Dashboard::GetHttpDispatch, httpData); - gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL); + gSocketTransportService->Dispatch(NewRunnableMethod> + (this, &Dashboard::GetHttpDispatch, httpData), + NS_DISPATCH_NORMAL); return NS_OK; } @@ -438,10 +432,9 @@ Dashboard::GetHttpDispatch(HttpData *aHttpData) { RefPtr httpData = aHttpData; HttpInfo::GetHttpConnectionData(&httpData->mData); - nsCOMPtr event = - NS_NewRunnableMethodWithArg > - (this, &Dashboard::GetHttpConnections, httpData); - httpData->mThread->Dispatch(event, NS_DISPATCH_NORMAL); + httpData->mThread->Dispatch(NewRunnableMethod> + (this, &Dashboard::GetHttpConnections, httpData), + NS_DISPATCH_NORMAL); return NS_OK; } @@ -604,10 +597,9 @@ Dashboard::RequestWebsocketConnections(NetDashboardCallback *aCallback) new nsMainThreadPtrHolder(aCallback, true); wsRequest->mThread = NS_GetCurrentThread(); - nsCOMPtr event = - NS_NewRunnableMethodWithArg > - (this, &Dashboard::GetWebSocketConnections, wsRequest); - wsRequest->mThread->Dispatch(event, NS_DISPATCH_NORMAL); + wsRequest->mThread->Dispatch(NewRunnableMethod> + (this, &Dashboard::GetWebSocketConnections, wsRequest), + NS_DISPATCH_NORMAL); return NS_OK; } @@ -666,10 +658,9 @@ Dashboard::RequestDNSInfo(NetDashboardCallback *aCallback) } } - nsCOMPtr event = - NS_NewRunnableMethodWithArg > - (this, &Dashboard::GetDnsInfoDispatch, dnsData); - gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL); + gSocketTransportService->Dispatch(NewRunnableMethod> + (this, &Dashboard::GetDnsInfoDispatch, dnsData), + NS_DISPATCH_NORMAL); return NS_OK; } @@ -680,10 +671,9 @@ Dashboard::GetDnsInfoDispatch(DnsData *aDnsData) if (mDnsService) { mDnsService->GetDNSCacheEntries(&dnsData->mData); } - nsCOMPtr event = - NS_NewRunnableMethodWithArg > - (this, &Dashboard::GetDNSCacheEntries, dnsData); - dnsData->mThread->Dispatch(event, NS_DISPATCH_NORMAL); + dnsData->mThread->Dispatch(NewRunnableMethod> + (this, &Dashboard::GetDNSCacheEntries, dnsData), + NS_DISPATCH_NORMAL); return NS_OK; } @@ -810,10 +800,9 @@ Dashboard::RequestConnection(const nsACString& aHost, uint32_t aPort, rv = TestNewConnection(connectionData); if (NS_FAILED(rv)) { mozilla::net::GetErrorString(rv, connectionData->mStatus); - nsCOMPtr event = - NS_NewRunnableMethodWithArg > - (this, &Dashboard::GetConnectionStatus, connectionData); - connectionData->mThread->Dispatch(event, NS_DISPATCH_NORMAL); + connectionData->mThread->Dispatch(NewRunnableMethod> + (this, &Dashboard::GetConnectionStatus, connectionData), + NS_DISPATCH_NORMAL); return rv; } diff --git a/netwerk/base/OfflineObserver.cpp b/netwerk/base/OfflineObserver.cpp index 1cdc838ea7..286173e98e 100644 --- a/netwerk/base/OfflineObserver.cpp +++ b/netwerk/base/OfflineObserver.cpp @@ -21,9 +21,8 @@ OfflineObserver::RegisterOfflineObserver() if (NS_IsMainThread()) { RegisterOfflineObserverMainThread(); } else { - nsCOMPtr event = - NS_NewRunnableMethod(this, &OfflineObserver::RegisterOfflineObserverMainThread); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(NewRunnableMethod(this, + &OfflineObserver::RegisterOfflineObserverMainThread)); } } @@ -33,9 +32,8 @@ OfflineObserver::RemoveOfflineObserver() if (NS_IsMainThread()) { RemoveOfflineObserverMainThread(); } else { - nsCOMPtr event = - NS_NewRunnableMethod(this, &OfflineObserver::RemoveOfflineObserverMainThread); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(NewRunnableMethod(this, + &OfflineObserver::RemoveOfflineObserverMainThread)); } } diff --git a/netwerk/base/Tickler.cpp b/netwerk/base/Tickler.cpp index 5d42440dca..a705104ba3 100644 --- a/netwerk/base/Tickler.cpp +++ b/netwerk/base/Tickler.cpp @@ -130,7 +130,7 @@ void Tickler::Tickle() void Tickler::PostCheckTickler() { mLock.AssertCurrentThreadOwns(); - mThread->Dispatch(NS_NewRunnableMethod(this, &Tickler::CheckTickler), + mThread->Dispatch(NewRunnableMethod(this, &Tickler::CheckTickler), NS_DISPATCH_NORMAL); return; } @@ -146,7 +146,7 @@ void Tickler::MaybeStartTickler() mLock.AssertCurrentThreadOwns(); if (!NS_IsMainThread()) { NS_DispatchToMainThread( - NS_NewRunnableMethod(this, &Tickler::MaybeStartTicklerUnlocked)); + NewRunnableMethod(this, &Tickler::MaybeStartTicklerUnlocked)); return; } diff --git a/netwerk/base/nsAsyncStreamCopier.cpp b/netwerk/base/nsAsyncStreamCopier.cpp index 331dcc65a9..0a1473a9fe 100644 --- a/netwerk/base/nsAsyncStreamCopier.cpp +++ b/netwerk/base/nsAsyncStreamCopier.cpp @@ -44,8 +44,9 @@ public: return NS_OK; } - nsCOMPtr event = NS_NewRunnableMethod(mCopier, &nsAsyncStreamCopier::AsyncCopyInternal); - rv = mTarget->Dispatch(event, NS_DISPATCH_NORMAL); + rv = mTarget->Dispatch(NewRunnableMethod(mCopier, + &nsAsyncStreamCopier::AsyncCopyInternal), + NS_DISPATCH_NORMAL); MOZ_ASSERT(NS_SUCCEEDED(rv)); if (NS_FAILED(rv)) { diff --git a/netwerk/base/nsInputStreamPump.cpp b/netwerk/base/nsInputStreamPump.cpp index 1096c10f01..998961c1e7 100644 --- a/netwerk/base/nsInputStreamPump.cpp +++ b/netwerk/base/nsInputStreamPump.cpp @@ -679,7 +679,7 @@ nsInputStreamPump::OnStateStop() MOZ_ASSERT(NS_IsMainThread(), "OnStateStop should only be called on the main thread."); nsresult rv = NS_DispatchToMainThread( - NS_NewRunnableMethod(this, &nsInputStreamPump::CallOnStateStop)); + NewRunnableMethod(this, &nsInputStreamPump::CallOnStateStop)); NS_ENSURE_SUCCESS(rv, STATE_IDLE); return STATE_IDLE; } diff --git a/netwerk/base/nsPACMan.cpp b/netwerk/base/nsPACMan.cpp index 59ec94f851..b5a3bcd9f5 100644 --- a/netwerk/base/nsPACMan.cpp +++ b/netwerk/base/nsPACMan.cpp @@ -414,10 +414,8 @@ nsPACMan::LoadPACFromURI(const nsCString &spec) // queries the enter between now and when we actually load the PAC file. if (!mLoadPending) { - nsCOMPtr event = - NS_NewRunnableMethod(this, &nsPACMan::StartLoading); nsresult rv; - if (NS_FAILED(rv = NS_DispatchToCurrentThread(event))) + if (NS_FAILED(rv = NS_DispatchToCurrentThread(NewRunnableMethod(this, &nsPACMan::StartLoading)))) return rv; mLoadPending = true; } @@ -783,9 +781,9 @@ nsPACMan::Init(nsISystemProxySettings *systemProxySettings) if (NS_FAILED(rv)) return rv; - nsCOMPtr event = NS_NewRunnableMethod(this, &nsPACMan::NamePACThread); // don't check return value as it is not a big deal for this to fail. - mPACThread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); + mPACThread->Dispatch(NewRunnableMethod(this, &nsPACMan::NamePACThread), + nsIEventTarget::DISPATCH_NORMAL); return NS_OK; } diff --git a/netwerk/base/nsServerSocket.cpp b/netwerk/base/nsServerSocket.cpp index 3822448263..a074bc7e0e 100644 --- a/netwerk/base/nsServerSocket.cpp +++ b/netwerk/base/nsServerSocket.cpp @@ -30,10 +30,7 @@ typedef void (nsServerSocket:: *nsServerSocketFunc)(void); static nsresult PostEvent(nsServerSocket *s, nsServerSocketFunc func) { - nsCOMPtr ev = NS_NewRunnableMethod(s, func); - if (!ev) - return NS_ERROR_OUT_OF_MEMORY; - + nsCOMPtr ev = NewRunnableMethod(s, func); if (!gSocketTransportService) return NS_ERROR_FAILURE; @@ -129,7 +126,7 @@ nsServerSocket::TryAttach() if (!gSocketTransportService->CanAttachSocket()) { nsCOMPtr event = - NS_NewRunnableMethod(this, &nsServerSocket::OnMsgAttach); + NewRunnableMethod(this, &nsServerSocket::OnMsgAttach); if (!event) return NS_ERROR_OUT_OF_MEMORY; diff --git a/netwerk/base/nsSocketTransportService2.cpp b/netwerk/base/nsSocketTransportService2.cpp index 64185a12bb..39cc577f67 100644 --- a/netwerk/base/nsSocketTransportService2.cpp +++ b/netwerk/base/nsSocketTransportService2.cpp @@ -886,7 +886,7 @@ nsSocketTransportService::Run() mRawThread->HasPendingEvents(&pendingEvents); if (pendingEvents) { if (!mServingPendingQueue) { - nsresult rv = Dispatch(NS_NewRunnableMethod(this, + nsresult rv = Dispatch(NewRunnableMethod(this, &nsSocketTransportService::MarkTheLastElementOfPendingQueue), nsIEventTarget::DISPATCH_NORMAL); if (NS_FAILED(rv)) { @@ -1181,7 +1181,7 @@ nsSocketTransportService::OnKeepaliveEnabledPrefChange() // Dispatch to socket thread if we're not executing there. if (PR_GetCurrentThread() != gSocketThread) { gSocketTransportService->Dispatch( - NS_NewRunnableMethod( + NewRunnableMethod( this, &nsSocketTransportService::OnKeepaliveEnabledPrefChange), NS_DISPATCH_NORMAL); return; @@ -1233,8 +1233,8 @@ nsSocketTransportService::Observe(nsISupports *subject, if (!strcmp(topic, "last-pb-context-exited")) { nsCOMPtr ev = - NS_NewRunnableMethod(this, - &nsSocketTransportService::ClosePrivateConnections); + NewRunnableMethod(this, + &nsSocketTransportService::ClosePrivateConnections); nsresult rv = Dispatch(ev, nsIEventTarget::DISPATCH_NORMAL); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/netwerk/base/nsUDPSocket.cpp b/netwerk/base/nsUDPSocket.cpp index bdd0934e08..06b9fd8e9b 100644 --- a/netwerk/base/nsUDPSocket.cpp +++ b/netwerk/base/nsUDPSocket.cpp @@ -47,12 +47,10 @@ typedef void (nsUDPSocket:: *nsUDPSocketFunc)(void); static nsresult PostEvent(nsUDPSocket *s, nsUDPSocketFunc func) { - nsCOMPtr ev = NS_NewRunnableMethod(s, func); - if (!gSocketTransportService) return NS_ERROR_FAILURE; - return gSocketTransportService->Dispatch(ev, NS_DISPATCH_NORMAL); + return gSocketTransportService->Dispatch(NewRunnableMethod(s, func), NS_DISPATCH_NORMAL); } static nsresult @@ -346,7 +344,7 @@ nsUDPSocket::TryAttach() if (!gSocketTransportService->CanAttachSocket()) { nsCOMPtr event = - NS_NewRunnableMethod(this, &nsUDPSocket::OnMsgAttach); + NewRunnableMethod(this, &nsUDPSocket::OnMsgAttach); nsresult rv = gSocketTransportService->NotifyWhenCanAttachSocket(event); if (NS_FAILED(rv)) diff --git a/netwerk/cache/nsCacheService.cpp b/netwerk/cache/nsCacheService.cpp index c29457c8ef..081984ab91 100644 --- a/netwerk/cache/nsCacheService.cpp +++ b/netwerk/cache/nsCacheService.cpp @@ -1522,8 +1522,8 @@ nsresult nsCacheService::EvictEntriesInternal(nsCacheStoragePolicy storagePolicy if (storagePolicy == nsICache::STORE_ANYWHERE) { // if not called on main thread, dispatch the notification to the main thread to notify observers if (!NS_IsMainThread()) { - nsCOMPtr event = NS_NewRunnableMethod(this, - &nsCacheService::FireClearNetworkCacheStoredAnywhereNotification); + nsCOMPtr event = NewRunnableMethod(this, + &nsCacheService::FireClearNetworkCacheStoredAnywhereNotification); NS_DispatchToMainThread(event); } else { // else you're already on main thread - notify observers diff --git a/netwerk/cache2/CacheEntry.cpp b/netwerk/cache2/CacheEntry.cpp index 92179e200d..fda6111850 100644 --- a/netwerk/cache2/CacheEntry.cpp +++ b/netwerk/cache2/CacheEntry.cpp @@ -650,10 +650,9 @@ bool CacheEntry::InvokeCallbacks(bool aReadOnly) if (NS_SUCCEEDED(rv) && !onCheckThread) { // Redispatch to the target thread - RefPtr > event = - NS_NewRunnableMethod(this, &CacheEntry::InvokeCallbacksLock); - - rv = mCallbacks[i].mTargetThread->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); + rv = mCallbacks[i].mTargetThread->Dispatch(NewRunnableMethod(this, + &CacheEntry::InvokeCallbacksLock), + nsIEventTarget::DISPATCH_NORMAL); if (NS_SUCCEEDED(rv)) { LOG((" re-dispatching to target thread")); return false; @@ -1721,9 +1720,7 @@ void CacheEntry::BackgroundOp(uint32_t aOperations, bool aForceAsync) // Because CacheFile::Set*() are not thread-safe to use (uses WeakReference that // is not thread-safe) we must post to the main thread... - RefPtr > event = - NS_NewRunnableMethodWithArg(this, &CacheEntry::StoreFrecency, mFrecency); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(NewRunnableMethod(this, &CacheEntry::StoreFrecency, mFrecency)); } if (aOperations & Ops::REGISTER) { diff --git a/netwerk/cache2/CacheFileChunk.cpp b/netwerk/cache2/CacheFileChunk.cpp index 4b090a846d..51dff37052 100644 --- a/netwerk/cache2/CacheFileChunk.cpp +++ b/netwerk/cache2/CacheFileChunk.cpp @@ -54,9 +54,7 @@ CacheFileChunk::DispatchRelease() return false; } - RefPtr > event = - NS_NewNonOwningRunnableMethod(this, &CacheFileChunk::Release); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(NewNonOwningRunnableMethod(this, &CacheFileChunk::Release)); return true; } diff --git a/netwerk/cache2/CacheFileContextEvictor.cpp b/netwerk/cache2/CacheFileContextEvictor.cpp index b92dcacf7d..79966927c3 100644 --- a/netwerk/cache2/CacheFileContextEvictor.cpp +++ b/netwerk/cache2/CacheFileContextEvictor.cpp @@ -522,7 +522,7 @@ CacheFileContextEvictor::StartEvicting() } nsCOMPtr ev; - ev = NS_NewRunnableMethod(this, &CacheFileContextEvictor::EvictEntries); + ev = NewRunnableMethod(this, &CacheFileContextEvictor::EvictEntries); RefPtr ioThread = CacheFileIOManager::IOThread(); diff --git a/netwerk/cache2/CacheFileIOManager.cpp b/netwerk/cache2/CacheFileIOManager.cpp index 5461aae69d..6d18939acd 100644 --- a/netwerk/cache2/CacheFileIOManager.cpp +++ b/netwerk/cache2/CacheFileIOManager.cpp @@ -67,9 +67,10 @@ CacheFileHandle::DispatchRelease() return false; } - RefPtr > event = - NS_NewNonOwningRunnableMethod(this, &CacheFileHandle::Release); - nsresult rv = ioTarget->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); + nsresult rv = + ioTarget->Dispatch(NewNonOwningRunnableMethod(this, + &CacheFileHandle::Release), + nsIEventTarget::DISPATCH_NORMAL); if (NS_FAILED(rv)) { return false; } @@ -2635,8 +2636,8 @@ CacheFileIOManager::EvictIfOverLimit() } nsCOMPtr ev; - ev = NS_NewRunnableMethod(ioMan, - &CacheFileIOManager::EvictIfOverLimitInternal); + ev = NewRunnableMethod(ioMan, + &CacheFileIOManager::EvictIfOverLimitInternal); rv = ioMan->mIOThread->Dispatch(ev, CacheIOThread::EVICT); NS_ENSURE_SUCCESS(rv, rv); @@ -2696,8 +2697,8 @@ CacheFileIOManager::EvictIfOverLimitInternal() cacheUsage, cacheLimit)); nsCOMPtr ev; - ev = NS_NewRunnableMethod(this, - &CacheFileIOManager::OverLimitEvictionInternal); + ev = NewRunnableMethod(this, + &CacheFileIOManager::OverLimitEvictionInternal); rv = mIOThread->Dispatch(ev, CacheIOThread::EVICT); NS_ENSURE_SUCCESS(rv, rv); @@ -2836,7 +2837,7 @@ CacheFileIOManager::EvictAll() } nsCOMPtr ev; - ev = NS_NewRunnableMethod(ioMan, &CacheFileIOManager::EvictAllInternal); + ev = NewRunnableMethod(ioMan, &CacheFileIOManager::EvictAllInternal); rv = ioMan->mIOThread->DispatchAfterPendingOpens(ev); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -2954,7 +2955,7 @@ CacheFileIOManager::EvictByContext(nsILoadContextInfo *aLoadContextInfo, bool aP } nsCOMPtr ev; - ev = NS_NewRunnableMethodWithArgs, bool> + ev = NewRunnableMethod, bool> (ioMan, &CacheFileIOManager::EvictByContextInternal, aLoadContextInfo, aPinned); rv = ioMan->mIOThread->DispatchAfterPendingOpens(ev); @@ -3073,7 +3074,7 @@ CacheFileIOManager::CacheIndexStateChanged() // We have to re-distatch even if we are on IO thread to prevent reentering // the lock in CacheIndex nsCOMPtr ev; - ev = NS_NewRunnableMethod( + ev = NewRunnableMethod( gInstance, &CacheFileIOManager::CacheIndexStateChangedInternal); nsCOMPtr ioTarget = IOTarget(); @@ -3248,8 +3249,8 @@ CacheFileIOManager::StartRemovingTrash() } nsCOMPtr ev; - ev = NS_NewRunnableMethod(this, - &CacheFileIOManager::RemoveTrashInternal); + ev = NewRunnableMethod(this, + &CacheFileIOManager::RemoveTrashInternal); rv = mIOThread->Dispatch(ev, CacheIOThread::EVICT); NS_ENSURE_SUCCESS(rv, rv); diff --git a/netwerk/cache2/CacheIndex.cpp b/netwerk/cache2/CacheIndex.cpp index d0cc250e09..d40687c417 100644 --- a/netwerk/cache2/CacheIndex.cpp +++ b/netwerk/cache2/CacheIndex.cpp @@ -346,7 +346,7 @@ CacheIndex::PreShutdown() } nsCOMPtr event; - event = NS_NewRunnableMethod(index, &CacheIndex::PreShutdownInternal); + event = NewRunnableMethod(index, &CacheIndex::PreShutdownInternal); RefPtr ioThread = CacheFileIOManager::IOThread(); MOZ_ASSERT(ioThread); diff --git a/netwerk/cache2/CacheObserver.cpp b/netwerk/cache2/CacheObserver.cpp index 6e452cec2f..ce6c360143 100644 --- a/netwerk/cache2/CacheObserver.cpp +++ b/netwerk/cache2/CacheObserver.cpp @@ -317,7 +317,7 @@ CacheObserver::SetDiskCacheCapacity(uint32_t aCapacity) sSelf->StoreDiskCacheCapacity(); } else { nsCOMPtr event = - NS_NewRunnableMethod(sSelf, &CacheObserver::StoreDiskCacheCapacity); + NewRunnableMethod(sSelf, &CacheObserver::StoreDiskCacheCapacity); NS_DispatchToMainThread(event); } } diff --git a/netwerk/cache2/CacheStorageService.cpp b/netwerk/cache2/CacheStorageService.cpp index a71d76ab12..44ce98eb5c 100644 --- a/netwerk/cache2/CacheStorageService.cpp +++ b/netwerk/cache2/CacheStorageService.cpp @@ -143,7 +143,7 @@ void CacheStorageService::Shutdown() mShutdown = true; nsCOMPtr event = - NS_NewRunnableMethod(this, &CacheStorageService::ShutdownBackground); + NewRunnableMethod(this, &CacheStorageService::ShutdownBackground); Dispatch(event); mozilla::MutexAutoLock lock(mLock); @@ -1208,7 +1208,7 @@ CacheStorageService::OnMemoryConsumptionChange(CacheMemoryConsumer* aConsumer, // Dispatch as a priority task, we want to set the purge timer // ASAP to prevent vain redispatch of this event. nsCOMPtr event = - NS_NewRunnableMethod(this, &CacheStorageService::SchedulePurgeOverMemoryLimit); + NewRunnableMethod(this, &CacheStorageService::SchedulePurgeOverMemoryLimit); cacheIOTarget->Dispatch(event, nsIEventTarget::DISPATCH_NORMAL); } @@ -1248,7 +1248,7 @@ CacheStorageService::Notify(nsITimer* aTimer) mPurgeTimer = nullptr; nsCOMPtr event = - NS_NewRunnableMethod(this, &CacheStorageService::PurgeOverMemoryLimit); + NewRunnableMethod(this, &CacheStorageService::PurgeOverMemoryLimit); Dispatch(event); } diff --git a/netwerk/dns/DNSRequestChild.cpp b/netwerk/dns/DNSRequestChild.cpp index 44b27eb8fe..431fc8fbe6 100644 --- a/netwerk/dns/DNSRequestChild.cpp +++ b/netwerk/dns/DNSRequestChild.cpp @@ -207,7 +207,7 @@ DNSRequestChild::StartRequest() // we can only do IPDL on the main thread if (!NS_IsMainThread()) { NS_DispatchToMainThread( - NS_NewRunnableMethod(this, &DNSRequestChild::StartRequest)); + NewRunnableMethod(this, &DNSRequestChild::StartRequest)); return; } @@ -260,7 +260,7 @@ DNSRequestChild::RecvLookupCompleted(const DNSRequestResponse& reply) CallOnLookupComplete(); } else { nsCOMPtr event = - NS_NewRunnableMethod(this, &DNSRequestChild::CallOnLookupComplete); + NewRunnableMethod(this, &DNSRequestChild::CallOnLookupComplete); mTarget->Dispatch(event, NS_DISPATCH_NORMAL); } diff --git a/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp index 5b205f925b..d66c3f571d 100644 --- a/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp +++ b/netwerk/dns/mdns/libmdns/MDNSResponderOperator.cpp @@ -74,9 +74,8 @@ public: PR_Close(mFD); mFD = nullptr; - nsCOMPtr ev = - NS_NewRunnableMethod(this, &ServiceWatcher::Deallocate); - mThread->Dispatch(ev, NS_DISPATCH_NORMAL); + mThread->Dispatch(NewRunnableMethod(this, &ServiceWatcher::Deallocate), + NS_DISPATCH_NORMAL); } virtual void IsLocal(bool *aIsLocal) override { *aIsLocal = true; } @@ -154,8 +153,8 @@ private: nsresult PostEvent(void(ServiceWatcher::*func)(void)) { - nsCOMPtr ev = NS_NewRunnableMethod(this, func); - return gSocketTransportService->Dispatch(ev, NS_DISPATCH_NORMAL); + return gSocketTransportService->Dispatch(NewRunnableMethod(this, func), + NS_DISPATCH_NORMAL); } void OnMsgClose() @@ -219,7 +218,7 @@ private: // if (!gSocketTransportService->CanAttachSocket()) { nsCOMPtr event = - NS_NewRunnableMethod(this, &ServiceWatcher::OnMsgAttach); + NewRunnableMethod(this, &ServiceWatcher::OnMsgAttach); nsresult rv = gSocketTransportService->NotifyWhenCanAttachSocket(event); if (NS_FAILED(rv)) { diff --git a/netwerk/ipc/ChannelEventQueue.cpp b/netwerk/ipc/ChannelEventQueue.cpp index d0511e2d61..ae55ebd032 100644 --- a/netwerk/ipc/ChannelEventQueue.cpp +++ b/netwerk/ipc/ChannelEventQueue.cpp @@ -67,13 +67,13 @@ ChannelEventQueue::Resume() } if (!--mSuspendCount) { - RefPtr > event = - NS_NewRunnableMethod(this, &ChannelEventQueue::CompleteResume); + RefPtr event = + NewRunnableMethod(this, &ChannelEventQueue::CompleteResume); if (mTargetThread) { - mTargetThread->Dispatch(event, NS_DISPATCH_NORMAL); + mTargetThread->Dispatch(event.forget(), NS_DISPATCH_NORMAL); } else { MOZ_RELEASE_ASSERT(NS_IsMainThread()); - NS_WARN_IF(NS_FAILED(NS_DispatchToCurrentThread(event))); + NS_WARN_IF(NS_FAILED(NS_DispatchToCurrentThread(event.forget()))); } } } diff --git a/netwerk/protocol/about/nsAboutCache.cpp b/netwerk/protocol/about/nsAboutCache.cpp index 31f4a02c82..2ab2e719d5 100644 --- a/netwerk/protocol/about/nsAboutCache.cpp +++ b/netwerk/protocol/about/nsAboutCache.cpp @@ -179,9 +179,7 @@ nsAboutCache::VisitNextStorage() // from visitor callback. The cache v1 service doesn't like it. // TODO - mayhemer, bug 913828, remove this dispatch and call // directly. - nsCOMPtr event = - NS_NewRunnableMethod(this, &nsAboutCache::FireVisitStorage); - return NS_DispatchToMainThread(event); + return NS_DispatchToMainThread(mozilla::NewRunnableMethod(this, &nsAboutCache::FireVisitStorage)); } void diff --git a/netwerk/protocol/file/nsFileChannel.cpp b/netwerk/protocol/file/nsFileChannel.cpp index 8368161a01..38b59af4b6 100644 --- a/netwerk/protocol/file/nsFileChannel.cpp +++ b/netwerk/protocol/file/nsFileChannel.cpp @@ -232,7 +232,7 @@ nsFileUploadContentStream::AsyncWait(nsIInputStreamCallback *callback, if (IsNonBlocking()) { nsCOMPtr callback = - NS_NewRunnableMethod(this, &nsFileUploadContentStream::OnCopyComplete); + NewRunnableMethod(this, &nsFileUploadContentStream::OnCopyComplete); mCopyEvent->Dispatch(callback, mSink, target); } diff --git a/netwerk/protocol/ftp/FTPChannelParent.cpp b/netwerk/protocol/ftp/FTPChannelParent.cpp index cd2013c602..fbe3addde2 100644 --- a/netwerk/protocol/ftp/FTPChannelParent.cpp +++ b/netwerk/protocol/ftp/FTPChannelParent.cpp @@ -740,7 +740,7 @@ FTPChannelParent::DivertTo(nsIStreamListener *aListener) // Call OnStartRequest and SendDivertMessages asynchronously to avoid // reentering client context. NS_DispatchToCurrentThread( - NS_NewRunnableMethod(this, &FTPChannelParent::StartDiversion)); + NewRunnableMethod(this, &FTPChannelParent::StartDiversion)); return; } diff --git a/netwerk/protocol/http/HttpBaseChannel.cpp b/netwerk/protocol/http/HttpBaseChannel.cpp index 372a221ce8..f1e0ba5661 100644 --- a/netwerk/protocol/http/HttpBaseChannel.cpp +++ b/netwerk/protocol/http/HttpBaseChannel.cpp @@ -676,7 +676,7 @@ void CopyComplete(void* aClosure, nsresult aStatus) { // Called on the STS thread by NS_AsyncCopy auto channel = static_cast(aClosure); - nsCOMPtr runnable = NS_NewRunnableMethodWithArg( + nsCOMPtr runnable = NewRunnableMethod( channel, &HttpBaseChannel::EnsureUploadStreamIsCloneableComplete, aStatus); NS_DispatchToMainThread(runnable.forget()); } diff --git a/netwerk/protocol/http/HttpBaseChannel.h b/netwerk/protocol/http/HttpBaseChannel.h index f0b1ee6b98..094129f03e 100644 --- a/netwerk/protocol/http/HttpBaseChannel.h +++ b/netwerk/protocol/http/HttpBaseChannel.h @@ -582,11 +582,11 @@ inline void HttpAsyncAborter::HandleAsyncAbort() template nsresult HttpAsyncAborter::AsyncCall(void (T::*funcPtr)(), - nsRunnableMethod **retval) + nsRunnableMethod **retval) { nsresult rv; - RefPtr > event = NS_NewRunnableMethod(mThis, funcPtr); + RefPtr> event = NewRunnableMethod(mThis, funcPtr); rv = NS_DispatchToCurrentThread(event); if (NS_SUCCEEDED(rv) && retval) { *retval = event; diff --git a/netwerk/protocol/http/HttpChannelParent.cpp b/netwerk/protocol/http/HttpChannelParent.cpp index 43dfdd48f4..84663d4bd2 100644 --- a/netwerk/protocol/http/HttpChannelParent.cpp +++ b/netwerk/protocol/http/HttpChannelParent.cpp @@ -1435,7 +1435,7 @@ HttpChannelParent::DivertTo(nsIStreamListener *aListener) // Call OnStartRequest and SendDivertMessages asynchronously to avoid // reentering client context. NS_DispatchToCurrentThread( - NS_NewRunnableMethod(this, &HttpChannelParent::StartDiversion)); + NewRunnableMethod(this, &HttpChannelParent::StartDiversion)); return; } diff --git a/netwerk/protocol/http/PackagedAppVerifier.cpp b/netwerk/protocol/http/PackagedAppVerifier.cpp index 9ab90d8e7e..7bc4a49df0 100644 --- a/netwerk/protocol/http/PackagedAppVerifier.cpp +++ b/netwerk/protocol/http/PackagedAppVerifier.cpp @@ -248,13 +248,13 @@ PackagedAppVerifier::FireVerifiedEvent(bool aForManifest, bool aSuccess) nsCOMPtr r; if (aForManifest) { - r = NS_NewRunnableMethodWithArgs(this, - &PackagedAppVerifier::OnManifestVerified, - aSuccess); + r = NewRunnableMethod(this, + &PackagedAppVerifier::OnManifestVerified, + aSuccess); } else { - r = NS_NewRunnableMethodWithArgs(this, - &PackagedAppVerifier::OnResourceVerified, - aSuccess); + r = NewRunnableMethod(this, + &PackagedAppVerifier::OnResourceVerified, + aSuccess); } NS_DispatchToMainThread(r); diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index d9c2c7748c..a92e4c460c 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -2108,8 +2108,8 @@ nsHttpHandler::Observe(nsISupports *subject, if (mConnMgr) { if (gSocketTransportService) { nsCOMPtr event = - NS_NewRunnableMethod(mConnMgr, - &nsHttpConnectionMgr::ClearConnectionHistory); + NewRunnableMethod(mConnMgr, + &nsHttpConnectionMgr::ClearConnectionHistory); gSocketTransportService->Dispatch(event, NS_DISPATCH_NORMAL); } mConnMgr->ClearAltServiceMappings(); diff --git a/netwerk/protocol/websocket/WebSocketChannel.cpp b/netwerk/protocol/websocket/WebSocketChannel.cpp index ea25ec73cd..775556bd90 100644 --- a/netwerk/protocol/websocket/WebSocketChannel.cpp +++ b/netwerk/protocol/websocket/WebSocketChannel.cpp @@ -1248,7 +1248,7 @@ WebSocketChannel::Observe(nsISupports *subject, // Next we check mDataStarted, which we need to do on mTargetThread. if (!IsOnTargetThread()) { mTargetThread->Dispatch( - NS_NewRunnableMethod(this, &WebSocketChannel::OnNetworkChanged), + NewRunnableMethod(this, &WebSocketChannel::OnNetworkChanged), NS_DISPATCH_NORMAL); } else { OnNetworkChanged(); @@ -1272,7 +1272,7 @@ WebSocketChannel::OnNetworkChanged() } return mSocketThread->Dispatch( - NS_NewRunnableMethod(this, &WebSocketChannel::OnNetworkChanged), + NewRunnableMethod(this, &WebSocketChannel::OnNetworkChanged), NS_DISPATCH_NORMAL); } @@ -1359,7 +1359,7 @@ WebSocketChannel::BeginOpen(bool aCalledFromAdmissionManager) // When called from nsWSAdmissionManager post an event to avoid potential // re-entering of nsWSAdmissionManager and its lock. NS_DispatchToMainThread( - NS_NewRunnableMethod(this, &WebSocketChannel::BeginOpenInternal), + NewRunnableMethod(this, &WebSocketChannel::BeginOpenInternal), NS_DISPATCH_NORMAL); } else { BeginOpenInternal(); @@ -2836,7 +2836,7 @@ WebSocketChannel::StartWebsocketData() if (!IsOnTargetThread()) { return mTargetThread->Dispatch( - NS_NewRunnableMethod(this, &WebSocketChannel::StartWebsocketData), + NewRunnableMethod(this, &WebSocketChannel::StartWebsocketData), NS_DISPATCH_NORMAL); } @@ -2859,15 +2859,15 @@ WebSocketChannel::StartWebsocketData() LOG(("WebSocketChannel::StartWebsocketData mSocketIn->AsyncWait() failed " "with error 0x%08x", rv)); return mSocketThread->Dispatch( - NS_NewRunnableMethodWithArgs(this, - &WebSocketChannel::AbortSession, - rv), + NewRunnableMethod(this, + &WebSocketChannel::AbortSession, + rv), NS_DISPATCH_NORMAL); } if (mPingInterval) { rv = mSocketThread->Dispatch( - NS_NewRunnableMethod(this, &WebSocketChannel::StartPinging), + NewRunnableMethod(this, &WebSocketChannel::StartPinging), NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) { LOG(("WebSocketChannel::StartWebsocketData Could not start pinging, " diff --git a/netwerk/protocol/websocket/WebSocketChannelChild.cpp b/netwerk/protocol/websocket/WebSocketChannelChild.cpp index d98167db75..b88a4698aa 100644 --- a/netwerk/protocol/websocket/WebSocketChannelChild.cpp +++ b/netwerk/protocol/websocket/WebSocketChannelChild.cpp @@ -107,9 +107,9 @@ WebSocketChannelChild::MaybeReleaseIPCObject() } if (!NS_IsMainThread()) { - nsCOMPtr runnable = - NS_NewRunnableMethod(this, &WebSocketChannelChild::MaybeReleaseIPCObject); - MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(runnable)); + MOZ_ALWAYS_SUCCEEDS( + NS_DispatchToMainThread(NewRunnableMethod(this, + &WebSocketChannelChild::MaybeReleaseIPCObject))); return; } diff --git a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp index c73bf4287d..7f1a431317 100644 --- a/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp +++ b/netwerk/protocol/wyciwyg/nsWyciwygChannel.cpp @@ -700,7 +700,7 @@ nsWyciwygChannel::OnCacheEntryAvailable(nsICacheEntry *aCacheEntry, if (!aNew) { // Since OnCacheEntryAvailable can be called directly from AsyncOpen // we must dispatch. - NS_DispatchToCurrentThread(NS_NewRunnableMethod( + NS_DispatchToCurrentThread(mozilla::NewRunnableMethod( this, &nsWyciwygChannel::NotifyListener)); } } diff --git a/parser/html/nsHtml5TreeOpExecutor.cpp b/parser/html/nsHtml5TreeOpExecutor.cpp index d3d8c8e34a..3a260e6ebb 100644 --- a/parser/html/nsHtml5TreeOpExecutor.cpp +++ b/parser/html/nsHtml5TreeOpExecutor.cpp @@ -233,11 +233,8 @@ nsHtml5TreeOpExecutor::MarkAsBroken(nsresult aReason) // works out so that we get to terminate and clean up the parser from // a safer point. if (mParser) { // can mParser ever be null here? - nsCOMPtr terminator = - NS_NewRunnableMethod(GetParser(), &nsHtml5Parser::Terminate); - if (NS_FAILED(NS_DispatchToMainThread(terminator))) { - NS_WARNING("failed to dispatch executor flush event"); - } + MOZ_ALWAYS_SUCCEEDS( + NS_DispatchToMainThread(NewRunnableMethod(GetParser(), &nsHtml5Parser::Terminate))); } return aReason; } diff --git a/security/apps/AppSignatureVerification.cpp b/security/apps/AppSignatureVerification.cpp index fdfd18d424..38dbb69414 100644 --- a/security/apps/AppSignatureVerification.cpp +++ b/security/apps/AppSignatureVerification.cpp @@ -12,6 +12,7 @@ #include "ScopedNSSTypes.h" #include "base64.h" #include "certdb.h" +#include "mozilla/Casting.h" #include "mozilla/Logging.h" #include "mozilla/RefPtr.h" #include "mozilla/UniquePtr.h" @@ -622,7 +623,7 @@ ParseMF(const char* filebuf, nsIZipReader * zip, struct VerifyCertificateContext { AppTrustedRoot trustedRoot; - ScopedCERTCertList& builtChain; + UniqueCERTCertList& builtChain; }; nsresult @@ -633,7 +634,7 @@ VerifyCertificate(CERTCertificate* signerCert, void* voidContext, void* pinArg) return NS_ERROR_INVALID_ARG; } const VerifyCertificateContext& context = - *reinterpret_cast(voidContext); + *static_cast(voidContext); AppTrustDomain trustDomain(context.builtChain, pinArg); if (trustDomain.SetTrustedRoot(context.trustedRoot) != SECSuccess) { @@ -682,7 +683,7 @@ VerifyCertificate(CERTCertificate* signerCert, void* voidContext, void* pinArg) nsresult VerifySignature(AppTrustedRoot trustedRoot, const SECItem& buffer, const SECItem& detachedDigest, - /*out*/ ScopedCERTCertList& builtChain) + /*out*/ UniqueCERTCertList& builtChain) { // Currently, this function is only called within the CalculateResult() method // of CryptoTasks. As such, NSS should not be shut down at this point and the @@ -742,7 +743,7 @@ OpenSignedAppFile(AppTrustedRoot aTrustedRoot, nsIFile* aJarFile, } sigBuffer.type = siBuffer; - ScopedCERTCertList builtChain; + UniqueCERTCertList builtChain; rv = VerifySignature(aTrustedRoot, sigBuffer, sfCalculatedDigest.get(), builtChain); if (NS_FAILED(rv)) { @@ -916,14 +917,14 @@ VerifySignedManifest(AppTrustedRoot aTrustedRoot, // Calculate SHA1 digest of the base64 encoded string Digest doubleDigest; rv = doubleDigest.DigestBuf(SEC_OID_SHA1, - reinterpret_cast(base64EncDigest.get()), + BitwiseCast(base64EncDigest.get()), strlen(base64EncDigest.get())); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } // Verify the manifest signature (signed digest of the base64 encoded string) - ScopedCERTCertList builtChain; + UniqueCERTCertList builtChain; rv = VerifySignature(aTrustedRoot, signatureBuffer, doubleDigest.get(), builtChain); if (NS_FAILED(rv)) { @@ -1422,7 +1423,7 @@ VerifySignedDirectory(AppTrustedRoot aTrustedRoot, } sigBuffer.type = siBuffer; - ScopedCERTCertList builtChain; + UniqueCERTCertList builtChain; rv = VerifySignature(aTrustedRoot, sigBuffer, sfCalculatedDigest.get(), builtChain); if (NS_FAILED(rv)) { diff --git a/security/apps/AppTrustDomain.cpp b/security/apps/AppTrustDomain.cpp index 4f6bc68ff2..bc4e7689a0 100644 --- a/security/apps/AppTrustDomain.cpp +++ b/security/apps/AppTrustDomain.cpp @@ -5,17 +5,18 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "AppTrustDomain.h" -#include "certdb.h" -#include "pkix/pkixnss.h" -#include "mozilla/ArrayUtils.h" #include "MainThreadUtils.h" +#include "certdb.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/Casting.h" #include "mozilla/Preferences.h" #include "nsComponentManagerUtils.h" #include "nsIFile.h" #include "nsIFileStreams.h" #include "nsIX509CertDB.h" -#include "nsNetUtil.h" #include "nsNSSCertificate.h" +#include "nsNetUtil.h" +#include "pkix/pkixnss.h" #include "prerror.h" #include "secerr.h" @@ -49,7 +50,7 @@ StaticMutex AppTrustDomain::sMutex; UniquePtr AppTrustDomain::sDevImportedDERData; unsigned int AppTrustDomain::sDevImportedDERLen = 0; -AppTrustDomain::AppTrustDomain(ScopedCERTCertList& certChain, void* pinArg) +AppTrustDomain::AppTrustDomain(UniqueCERTCertList& certChain, void* pinArg) : mCertChain(certChain) , mPinArg(pinArg) , mMinRSABits(DEFAULT_MIN_RSA_BITS) @@ -152,7 +153,8 @@ AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot) } MOZ_ASSERT(length == sDevImportedDERLen); - sDevImportedDERData.reset(reinterpret_cast(data.release())); + sDevImportedDERData.reset( + BitwiseCast(data.release())); } trustedDER.data = sDevImportedDERData.get(); @@ -194,7 +196,7 @@ AppTrustDomain::FindIssuer(Input encodedIssuerName, IssuerChecker& checker, // message, passing each one to checker.Check. SECItem encodedIssuerNameSECItem = UnsafeMapInputToSECItem(encodedIssuerName); - ScopedCERTCertList + UniqueCERTCertList candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(), &encodedIssuerNameSECItem, 0, false)); diff --git a/security/apps/AppTrustDomain.h b/security/apps/AppTrustDomain.h index 29a9ac20bb..6410a78ee7 100644 --- a/security/apps/AppTrustDomain.h +++ b/security/apps/AppTrustDomain.h @@ -4,8 +4,8 @@ * 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_psm_AppsTrustDomain_h -#define mozilla_psm_AppsTrustDomain_h +#ifndef AppTrustDomain_h +#define AppTrustDomain_h #include "pkix/pkixtypes.h" #include "mozilla/StaticMutex.h" @@ -21,7 +21,7 @@ class AppTrustDomain final : public mozilla::pkix::TrustDomain public: typedef mozilla::pkix::Result Result; - AppTrustDomain(ScopedCERTCertList&, void* pinArg); + AppTrustDomain(UniqueCERTCertList& certChain, void* pinArg); SECStatus SetTrustedRoot(AppTrustedRoot trustedRoot); @@ -67,7 +67,7 @@ public: size_t digestBufLen) override; private: - /*out*/ ScopedCERTCertList& mCertChain; + /*out*/ UniqueCERTCertList& mCertChain; void* mPinArg; // non-owning! UniqueCERTCertificate mTrustedRoot; unsigned int mMinRSABits; @@ -79,4 +79,4 @@ private: } } // namespace mozilla::psm -#endif // mozilla_psm_AppsTrustDomain_h +#endif // AppTrustDomain_h diff --git a/security/certverifier/CertVerifier.cpp b/security/certverifier/CertVerifier.cpp index 0f229bc598..a34232a418 100644 --- a/security/certverifier/CertVerifier.cpp +++ b/security/certverifier/CertVerifier.cpp @@ -61,7 +61,7 @@ InitCertVerifierLog() } Result -IsCertChainRootBuiltInRoot(CERTCertList* chain, bool& result) +IsCertChainRootBuiltInRoot(const UniqueCERTCertList& chain, bool& result) { if (!chain || CERT_LIST_EMPTY(chain)) { return Result::FATAL_ERROR_LIBRARY_FAILURE; @@ -181,7 +181,7 @@ static const unsigned int MIN_RSA_BITS_WEAK = 1024; SECStatus CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage, Time time, void* pinArg, const char* hostname, - /*out*/ ScopedCERTCertList& builtChain, + /*out*/ UniqueCERTCertList& builtChain, /*optional*/ const Flags flags, /*optional*/ const SECItem* stapledOCSPResponseSECItem, /*optional out*/ SECOidTag* evOidPolicy, @@ -650,7 +650,7 @@ CertVerifier::VerifySSLServerCert(const UniqueCERTCertificate& peerCert, Time time, /*optional*/ void* pinarg, const char* hostname, - /*out*/ ScopedCERTCertList& builtChain, + /*out*/ UniqueCERTCertList& builtChain, /*optional*/ bool saveIntermediatesInPermanentDatabase, /*optional*/ Flags flags, /*optional out*/ SECOidTag* evOidPolicy, diff --git a/security/certverifier/CertVerifier.h b/security/certverifier/CertVerifier.h index 7a73d28e2e..fabc11bf51 100644 --- a/security/certverifier/CertVerifier.h +++ b/security/certverifier/CertVerifier.h @@ -4,8 +4,8 @@ * 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_psm__CertVerifier_h -#define mozilla_psm__CertVerifier_h +#ifndef CertVerifier_h +#define CertVerifier_h #include "BRNameMatchingPolicy.h" #include "OCSPCache.h" @@ -74,7 +74,7 @@ public: mozilla::pkix::Time time, void* pinArg, const char* hostname, - /*out*/ ScopedCERTCertList& builtChain, + /*out*/ UniqueCERTCertList& builtChain, Flags flags = 0, /*optional in*/ const SECItem* stapledOCSPResponse = nullptr, /*optional out*/ SECOidTag* evOidPolicy = nullptr, @@ -89,7 +89,7 @@ public: mozilla::pkix::Time time, /*optional*/ void* pinarg, const char* hostname, - /*out*/ ScopedCERTCertList& builtChain, + /*out*/ UniqueCERTCertList& builtChain, /*optional*/ bool saveIntermediatesInPermanentDatabase = false, /*optional*/ Flags flags = 0, /*optional out*/ SECOidTag* evOidPolicy = nullptr, @@ -154,4 +154,4 @@ mozilla::pkix::Result CertListContainsExpectedKeys( } } // namespace mozilla::psm -#endif // mozilla_psm__CertVerifier_h +#endif // CertVerifier_h diff --git a/security/certverifier/NSSCertDBTrustDomain.cpp b/security/certverifier/NSSCertDBTrustDomain.cpp index e99df42989..0674948881 100644 --- a/security/certverifier/NSSCertDBTrustDomain.cpp +++ b/security/certverifier/NSSCertDBTrustDomain.cpp @@ -9,25 +9,26 @@ #include #include "ExtendedValidation.h" +#include "NSSErrorsService.h" #include "OCSPRequestor.h" #include "OCSPVerificationTrustDomain.h" -#include "certdb.h" +#include "PublicKeyPinningService.h" #include "cert.h" +#include "certdb.h" +#include "mozilla/Casting.h" #include "mozilla/UniquePtr.h" +#include "mozilla/unused.h" #include "nsNSSCertificate.h" #include "nsThreadUtils.h" -#include "nss.h" -#include "NSSErrorsService.h" #include "nsServiceManagerUtils.h" +#include "nss.h" #include "pk11pub.h" +#include "pkix/Result.h" #include "pkix/pkix.h" #include "pkix/pkixnss.h" -#include "pkix/Result.h" #include "prerror.h" #include "prmem.h" #include "prprf.h" -#include "PublicKeyPinningService.h" -#include "ScopedNSSTypes.h" #include "secerr.h" #include "CNNICHashWhitelist.inc" @@ -53,7 +54,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType, unsigned int minRSABits, ValidityCheckingMode validityCheckingMode, CertVerifier::SHA1Mode sha1Mode, - ScopedCERTCertList& builtChain, + UniqueCERTCertList& builtChain, /*optional*/ PinningTelemetryInfo* pinningTelemetryInfo, /*optional*/ const char* hostname) : mCertDBTrustType(certDBTrustType) @@ -77,7 +78,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType, // If useRoots is true, we only use root certificates in the candidate list. // If useRoots is false, we only use non-root certificates in the list. static Result -FindIssuerInner(ScopedCERTCertList& candidates, bool useRoots, +FindIssuerInner(const UniqueCERTCertList& candidates, bool useRoots, Input encodedIssuerName, TrustDomain::IssuerChecker& checker, /*out*/ bool& keepGoing) { @@ -137,7 +138,7 @@ NSSCertDBTrustDomain::FindIssuer(Input encodedIssuerName, // TODO: NSS seems to be ambiguous between "no potential issuers found" and // "there was an error trying to retrieve the potential issuers." SECItem encodedIssuerNameItem = UnsafeMapInputToSECItem(encodedIssuerName); - ScopedCERTCertList + UniqueCERTCertList candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(), &encodedIssuerNameItem, 0, false)); @@ -736,7 +737,7 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time) MOZ_LOG(gCertVerifierLog, LogLevel::Debug, ("NSSCertDBTrustDomain: IsChainValid")); - ScopedCERTCertList certList; + UniqueCERTCertList certList; SECStatus srv = ConstructCERTCertListFromReversedDERArray(certArray, certList); if (srv != SECSuccess) { @@ -777,7 +778,7 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time) return Result::FATAL_ERROR_LIBRARY_FAILURE; } const uint8_t* certHash( - reinterpret_cast(digest.get().data)); + BitwiseCast(digest.get().data)); size_t certHashLen = digest.get().len; size_t unused; if (!mozilla::BinarySearchIf(WhitelistedCNNICHashes, 0, @@ -814,7 +815,7 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time) } } - mBuiltChain = certList.forget(); + mBuiltChain = Move(certList); return Success; } @@ -1023,16 +1024,16 @@ LoadLoadableRoots(/*optional*/ const char* dir, const char* modNameUTF8) int modType; SECMOD_DeleteModule(modNameUTF8, &modType); - UniquePtr - pkcs11ModuleSpec(PR_smprintf("name=\"%s\" library=\"%s\"", modNameUTF8, - escapedFullLibraryPath.get()), - PR_smprintf_free); - if (!pkcs11ModuleSpec) { + nsAutoCString pkcs11ModuleSpec; + pkcs11ModuleSpec.AppendPrintf("name=\"%s\" library=\"%s\"", modNameUTF8, + escapedFullLibraryPath.get()); + if (pkcs11ModuleSpec.IsEmpty()) { return SECFailure; } - UniqueSECMODModule rootsModule(SECMOD_LoadUserModule(pkcs11ModuleSpec.get(), - nullptr, false)); + UniqueSECMODModule rootsModule( + SECMOD_LoadUserModule(const_cast(pkcs11ModuleSpec.get()), nullptr, + false)); if (!rootsModule) { return SECFailure; } @@ -1056,69 +1057,69 @@ UnloadLoadableRoots(const char* modNameUTF8) } } -char* -DefaultServerNicknameForCert(CERTCertificate* cert) +nsresult +DefaultServerNicknameForCert(const CERTCertificate* cert, + /*out*/ nsCString& nickname) { - char* nickname = nullptr; - int count; - bool conflict; - char* servername = nullptr; + MOZ_ASSERT(cert); + NS_ENSURE_ARG_POINTER(cert); - servername = CERT_GetCommonName(&cert->subject); - if (!servername) { - // Certs without common names are strange, but they do exist... - // Let's try to use another string for the nickname - servername = CERT_GetOrgUnitName(&cert->subject); - if (!servername) { - servername = CERT_GetOrgName(&cert->subject); - if (!servername) { - servername = CERT_GetLocalityName(&cert->subject); - if (!servername) { - servername = CERT_GetStateName(&cert->subject); - if (!servername) { - servername = CERT_GetCountryName(&cert->subject); - if (!servername) { - // We tried hard, there is nothing more we can do. - // A cert without any names doesn't really make sense. - return nullptr; - } - } - } - } - } + UniquePORTString baseName(CERT_GetCommonName(&cert->subject)); + if (!baseName) { + baseName = UniquePORTString(CERT_GetOrgUnitName(&cert->subject)); + } + if (!baseName) { + baseName = UniquePORTString(CERT_GetOrgName(&cert->subject)); + } + if (!baseName) { + baseName = UniquePORTString(CERT_GetLocalityName(&cert->subject)); + } + if (!baseName) { + baseName = UniquePORTString(CERT_GetStateName(&cert->subject)); + } + if (!baseName) { + baseName = UniquePORTString(CERT_GetCountryName(&cert->subject)); + } + if (!baseName) { + return NS_ERROR_FAILURE; } - count = 1; - while (1) { - if (count == 1) { - nickname = PR_smprintf("%s", servername); + // This function is only used in contexts where a failure to find a suitable + // nickname does not block the overall task from succeeding. + // As such, we use an arbitrary limit to prevent this nickname searching + // process from taking forever. + static const uint32_t ARBITRARY_LIMIT = 500; + for (uint32_t count = 1; count < ARBITRARY_LIMIT; count++) { + nickname = baseName.get(); + if (count != 1) { + nickname.AppendPrintf(" #%u", count); } - else { - nickname = PR_smprintf("%s #%d", servername, count); - } - if (!nickname) { - break; + if (nickname.IsEmpty()) { + return NS_ERROR_FAILURE; } - conflict = SEC_CertNicknameConflict(nickname, &cert->derSubject, - cert->dbhandle); + bool conflict = SEC_CertNicknameConflict(nickname.get(), &cert->derSubject, + cert->dbhandle); if (!conflict) { - break; + return NS_OK; } - PR_Free(nickname); - count++; } - PR_FREEIF(servername); - return nickname; + + return NS_ERROR_FAILURE; } void -SaveIntermediateCerts(const ScopedCERTCertList& certList) +SaveIntermediateCerts(const UniqueCERTCertList& certList) { if (!certList) { return; } + UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); + if (!slot) { + return; + } + bool isEndEntity = true; for (CERTCertListNode* node = CERT_LIST_HEAD(certList); !CERT_LIST_END(node, certList); @@ -1140,15 +1141,19 @@ SaveIntermediateCerts(const ScopedCERTCertList& certList) } // We have found a signer cert that we want to remember. - char* nickname = DefaultServerNicknameForCert(node->cert); - if (nickname && *nickname) { - ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); - if (slot) { - PK11_ImportCert(slot.get(), node->cert, CK_INVALID_HANDLE, - nickname, false); - } + nsAutoCString nickname; + nsresult rv = DefaultServerNicknameForCert(node->cert, nickname); + if (NS_FAILED(rv)) { + continue; } - PR_FREEIF(nickname); + + // Saving valid intermediate certs to the database is a compatibility hack + // to work around unknown issuer errors for incorrectly configured servers + // that fail to send the necessary intermediate certs. As such, we ignore + // the return value of PK11_ImportCert(), since it doesn't really matter if + // it fails. + Unused << PK11_ImportCert(slot.get(), node->cert, CK_INVALID_HANDLE, + nickname.get(), false); } } diff --git a/security/certverifier/NSSCertDBTrustDomain.h b/security/certverifier/NSSCertDBTrustDomain.h index 298f6de78e..f34f22229a 100644 --- a/security/certverifier/NSSCertDBTrustDomain.h +++ b/security/certverifier/NSSCertDBTrustDomain.h @@ -4,11 +4,13 @@ * 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_psm__NSSCertDBTrustDomain_h -#define mozilla_psm__NSSCertDBTrustDomain_h +#ifndef NSSCertDBTrustDomain_h +#define NSSCertDBTrustDomain_h #include "CertVerifier.h" +#include "ScopedNSSTypes.h" #include "nsICertBlocklist.h" +#include "nsString.h" #include "pkix/pkixtypes.h" #include "secmodt.h" @@ -36,10 +38,10 @@ SECStatus LoadLoadableRoots(/*optional*/ const char* dir, void UnloadLoadableRoots(const char* modNameUTF8); -// Caller must free the result with PR_Free -char* DefaultServerNicknameForCert(CERTCertificate* cert); +nsresult DefaultServerNicknameForCert(const CERTCertificate* cert, + /*out*/ nsCString& nickname); -void SaveIntermediateCerts(const ScopedCERTCertList& certList); +void SaveIntermediateCerts(const UniqueCERTCertList& certList); class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain { @@ -63,7 +65,7 @@ public: unsigned int minRSABits, ValidityCheckingMode validityCheckingMode, CertVerifier::SHA1Mode sha1Mode, - ScopedCERTCertList& builtChain, + UniqueCERTCertList& builtChain, /*optional*/ PinningTelemetryInfo* pinningTelemetryInfo = nullptr, /*optional*/ const char* hostname = nullptr); @@ -149,7 +151,7 @@ private: const unsigned int mMinRSABits; ValidityCheckingMode mValidityCheckingMode; CertVerifier::SHA1Mode mSHA1Mode; - ScopedCERTCertList& mBuiltChain; // non-owning + UniqueCERTCertList& mBuiltChain; // non-owning PinningTelemetryInfo* mPinningTelemetryInfo; const char* mHostname; // non-owning - only used for pinning checks nsCOMPtr mCertBlocklist; @@ -158,4 +160,4 @@ private: } } // namespace mozilla::psm -#endif // mozilla_psm__NSSCertDBTrustDomain_h +#endif // NSSCertDBTrustDomain_h diff --git a/security/certverifier/OCSPRequestor.cpp b/security/certverifier/OCSPRequestor.cpp index b19b476f39..36cf6db3fe 100644 --- a/security/certverifier/OCSPRequestor.cpp +++ b/security/certverifier/OCSPRequestor.cpp @@ -10,6 +10,7 @@ #include "ScopedNSSTypes.h" #include "mozilla/Base64.h" +#include "mozilla/Casting.h" #include "nsIURLParser.h" #include "nsNSSCallbacks.h" #include "nsNetCID.h" @@ -49,7 +50,8 @@ AppendEscapedBase64Item(const SECItem* encodedRequest, nsACString& path) { nsresult rv; nsDependentCSubstring requestAsSubstring( - reinterpret_cast(encodedRequest->data), encodedRequest->len); + BitwiseCast(encodedRequest->data), + encodedRequest->len); nsCString base64Request; rv = Base64Encode(requestAsSubstring, base64Request); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -140,14 +142,13 @@ DoOCSPRequest(const UniquePLArenaPool& arena, const char* url, hostname(url + authorityPos + hostnamePos, static_cast(hostnameLen)); - SEC_HTTP_SERVER_SESSION serverSessionPtr = nullptr; + nsNSSHttpServerSession* serverSessionPtr = nullptr; Result rv = nsNSSHttpInterface::createSessionFcn( hostname.BeginReading(), static_cast(port), &serverSessionPtr); if (rv != Success) { return rv; } - UniqueHTTPServerSession serverSession( - reinterpret_cast(serverSessionPtr)); + UniqueHTTPServerSession serverSession(serverSessionPtr); nsAutoCString path; if (pathLen > 0) { @@ -170,19 +171,19 @@ DoOCSPRequest(const UniquePLArenaPool& arena, const char* url, } } - SEC_HTTP_REQUEST_SESSION requestSessionPtr; + nsNSSHttpRequestSession* requestSessionPtr; rv = nsNSSHttpInterface::createFcn(serverSession.get(), "http", path.get(), method.get(), timeout, &requestSessionPtr); if (rv != Success) { return rv; } - UniqueHTTPRequestSession requestSession( - reinterpret_cast(requestSessionPtr)); + UniqueHTTPRequestSession requestSession(requestSessionPtr); if (!useGET) { rv = nsNSSHttpInterface::setPostDataFcn( - requestSession.get(), reinterpret_cast(encodedRequest->data), + requestSession.get(), + BitwiseCast(encodedRequest->data), encodedRequest->len, "application/ocsp-request"); if (rv != Success) { return rv; diff --git a/security/manager/ssl/CSTrustDomain.cpp b/security/manager/ssl/CSTrustDomain.cpp index 3c18340f7b..e2f334a776 100644 --- a/security/manager/ssl/CSTrustDomain.cpp +++ b/security/manager/ssl/CSTrustDomain.cpp @@ -20,7 +20,7 @@ namespace mozilla { namespace psm { static LazyLogModule gTrustDomainPRLog("CSTrustDomain"); #define CSTrust_LOG(args) MOZ_LOG(gTrustDomainPRLog, LogLevel::Debug, args) -CSTrustDomain::CSTrustDomain(ScopedCERTCertList& certChain) +CSTrustDomain::CSTrustDomain(UniqueCERTCertList& certChain) : mCertChain(certChain) , mCertBlocklist(do_GetService(NS_CERTBLOCKLIST_CONTRACTID)) { diff --git a/security/manager/ssl/CSTrustDomain.h b/security/manager/ssl/CSTrustDomain.h index 66f846a6d0..2627b17210 100644 --- a/security/manager/ssl/CSTrustDomain.h +++ b/security/manager/ssl/CSTrustDomain.h @@ -22,7 +22,7 @@ class CSTrustDomain final : public mozilla::pkix::TrustDomain public: typedef mozilla::pkix::Result Result; - explicit CSTrustDomain(ScopedCERTCertList& certChain); + explicit CSTrustDomain(UniqueCERTCertList& certChain); virtual Result GetCertTrust( mozilla::pkix::EndEntityOrCA endEntityOrCA, @@ -66,7 +66,7 @@ public: size_t digestBufLen) override; private: - /*out*/ ScopedCERTCertList& mCertChain; + /*out*/ UniqueCERTCertList& mCertChain; nsCOMPtr mCertBlocklist; }; diff --git a/security/manager/ssl/CertBlocklist.cpp b/security/manager/ssl/CertBlocklist.cpp index 163fe7955f..066497127b 100644 --- a/security/manager/ssl/CertBlocklist.cpp +++ b/security/manager/ssl/CertBlocklist.cpp @@ -5,7 +5,10 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "CertBlocklist.h" + #include "mozilla/Base64.h" +#include "mozilla/Casting.h" +#include "mozilla/Logging.h" #include "mozilla/Preferences.h" #include "mozilla/unused.h" #include "nsAppDirectoryServiceDefs.h" @@ -21,7 +24,6 @@ #include "nsTHashtable.h" #include "nsThreadUtils.h" #include "pkix/Input.h" -#include "mozilla/Logging.h" #include "prtime.h" NS_IMPL_ISUPPORTS(CertBlocklist, nsICertBlocklist) @@ -82,9 +84,9 @@ CertBlocklistItem::~CertBlocklistItem() nsresult CertBlocklistItem::ToBase64(nsACString& b64DNOut, nsACString& b64OtherOut) { - nsDependentCSubstring DNString(reinterpret_cast(mDNData), + nsDependentCSubstring DNString(BitwiseCast(mDNData), mDNLength); - nsDependentCSubstring otherString(reinterpret_cast(mOtherData), + nsDependentCSubstring otherString(BitwiseCast(mOtherData), mOtherLength); nsresult rv = Base64Encode(DNString, b64DNOut); if (NS_FAILED(rv)) { @@ -344,25 +346,24 @@ CertBlocklist::AddRevokedCertInternal(const nsACString& aEncodedDN, CertBlocklistItemState aItemState, MutexAutoLock& /*proofOfLock*/) { - nsCString decodedDN; - nsCString decodedOther; - - nsresult rv = Base64Decode(aEncodedDN, decodedDN); - if (NS_FAILED(rv)) { - return rv; - } - rv = Base64Decode(aEncodedOther, decodedOther); - if (NS_FAILED(rv)) { - return rv; - } - - CertBlocklistItem item(reinterpret_cast(decodedDN.get()), - decodedDN.Length(), - reinterpret_cast(decodedOther.get()), - decodedOther.Length(), - aMechanism); + nsCString decodedDN; + nsCString decodedOther; + nsresult rv = Base64Decode(aEncodedDN, decodedDN); + if (NS_FAILED(rv)) { + return rv; + } + rv = Base64Decode(aEncodedOther, decodedOther); + if (NS_FAILED(rv)) { + return rv; + } + CertBlocklistItem item( + BitwiseCast(decodedDN.get()), + decodedDN.Length(), + BitwiseCast(decodedOther.get()), + decodedOther.Length(), + aMechanism); if (aItemState == CertNewFromBlocklist) { // We want SaveEntries to be a no-op if no new entries are added. @@ -584,8 +585,7 @@ CertBlocklist::IsCertRevoked(const uint8_t* aIssuer, return rv; } - rv = crypto->Update(reinterpret_cast(aPubKey), - aPubKeyLength); + rv = crypto->Update(aPubKey, aPubKeyLength); if (NS_FAILED(rv)) { return rv; } @@ -596,11 +596,12 @@ CertBlocklist::IsCertRevoked(const uint8_t* aIssuer, return rv; } - CertBlocklistItem subjectPubKey(aSubject, - static_cast(aSubjectLength), - reinterpret_cast(hashString.get()), - hashString.Length(), - BlockBySubjectAndPubKey); + CertBlocklistItem subjectPubKey( + aSubject, + static_cast(aSubjectLength), + BitwiseCast(hashString.get()), + hashString.Length(), + BlockBySubjectAndPubKey); rv = subjectPubKey.ToBase64(encDN, encOther); if (NS_FAILED(rv)) { @@ -649,7 +650,7 @@ void CertBlocklist::PreferenceChanged(const char* aPref, void* aClosure) { - CertBlocklist* blocklist = reinterpret_cast(aClosure); + auto blocklist = static_cast(aClosure); MutexAutoLock lock(blocklist->mMutex); MOZ_LOG(gCertBlockPRLog, LogLevel::Warning, diff --git a/security/manager/ssl/ContentSignatureVerifier.cpp b/security/manager/ssl/ContentSignatureVerifier.cpp index 3cc6586211..a693f72ce7 100644 --- a/security/manager/ssl/ContentSignatureVerifier.cpp +++ b/security/manager/ssl/ContentSignatureVerifier.cpp @@ -7,18 +7,19 @@ #include "ContentSignatureVerifier.h" #include "BRNameMatchingPolicy.h" +#include "SharedCertVerifier.h" #include "cryptohi.h" #include "keyhi.h" +#include "mozilla/Casting.h" #include "nsCOMPtr.h" #include "nsNSSComponent.h" -#include "nssb64.h" +#include "nsSecurityHeaderParser.h" #include "nsWhitespaceTokenizer.h" #include "nsXPCOMStrings.h" +#include "nssb64.h" #include "pkix/pkix.h" #include "pkix/pkixtypes.h" #include "secerr.h" -#include "SharedCertVerifier.h" -#include "nsSecurityHeaderParser.h" NS_IMPL_ISUPPORTS(ContentSignatureVerifier, nsIContentSignatureVerifier) @@ -146,8 +147,7 @@ ContentSignatureVerifier::CreateContext(const nsACString& aData, return NS_ERROR_ALREADY_INITIALIZED; } - ScopedCERTCertList certCertList(CERT_NewCertList()); - + UniqueCERTCertList certCertList(CERT_NewCertList()); if (!certCertList) { return NS_ERROR_OUT_OF_MEMORY; } @@ -166,7 +166,7 @@ ContentSignatureVerifier::CreateContext(const nsACString& aData, Input certDER; Result result = - certDER.Init(reinterpret_cast(certSecItem->data), + certDER.Init(BitwiseCast(certSecItem->data), certSecItem->len); if (result != Success) { return NS_ERROR_FAILURE; diff --git a/security/manager/ssl/DataStorage.cpp b/security/manager/ssl/DataStorage.cpp index 72c9717a85..2059bb5f8d 100644 --- a/security/manager/ssl/DataStorage.cpp +++ b/security/manager/ssl/DataStorage.cpp @@ -193,9 +193,9 @@ DataStorage::Reader::~Reader() // This is for tests. nsCOMPtr job = - NS_NewRunnableMethodWithArg(mDataStorage, - &DataStorage::NotifyObservers, - "data-storage-ready"); + NewRunnableMethod(mDataStorage, + &DataStorage::NotifyObservers, + "data-storage-ready"); nsresult rv = NS_DispatchToMainThread(job, NS_DISPATCH_NORMAL); Unused << NS_WARN_IF(NS_FAILED(rv)); } @@ -686,9 +686,9 @@ DataStorage::Writer::Run() // Observed by tests. nsCOMPtr job = - NS_NewRunnableMethodWithArg(mDataStorage, - &DataStorage::NotifyObservers, - "data-storage-written"); + NewRunnableMethod(mDataStorage, + &DataStorage::NotifyObservers, + "data-storage-written"); rv = NS_DispatchToMainThread(job, NS_DISPATCH_NORMAL); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -777,7 +777,7 @@ DataStorage::AsyncSetTimer(const MutexAutoLock& /*aProofOfLock*/) mPendingWrite = true; nsCOMPtr job = - NS_NewRunnableMethod(this, &DataStorage::SetTimer); + NewRunnableMethod(this, &DataStorage::SetTimer); nsresult rv = mWorkerThread->Dispatch(job, NS_DISPATCH_NORMAL); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; @@ -827,7 +827,7 @@ DataStorage::DispatchShutdownTimer(const MutexAutoLock& /*aProofOfLock*/) MOZ_ASSERT(XRE_IsParentProcess()); nsCOMPtr job = - NS_NewRunnableMethod(this, &DataStorage::ShutdownTimer); + NewRunnableMethod(this, &DataStorage::ShutdownTimer); nsresult rv = mWorkerThread->Dispatch(job, NS_DISPATCH_NORMAL); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; diff --git a/security/manager/ssl/LocalCertService.cpp b/security/manager/ssl/LocalCertService.cpp index 578009780b..7908b0374f 100644 --- a/security/manager/ssl/LocalCertService.cpp +++ b/security/manager/ssl/LocalCertService.cpp @@ -4,10 +4,12 @@ #include "LocalCertService.h" +#include "CryptoTask.h" +#include "ScopedNSSTypes.h" +#include "cert.h" +#include "mozilla/Casting.h" #include "mozilla/ModuleUtils.h" #include "mozilla/RefPtr.h" -#include "cert.h" -#include "CryptoTask.h" #include "nsIPK11Token.h" #include "nsIPK11TokenDB.h" #include "nsIX509Cert.h" @@ -18,7 +20,6 @@ #include "nsServiceManagerUtils.h" #include "nsString.h" #include "pk11pub.h" -#include "ScopedNSSTypes.h" namespace mozilla { @@ -109,7 +110,7 @@ private: nsresult rv; // Get the key slot for generation later - ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); if (!slot) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } @@ -141,12 +142,12 @@ private: memcpy(keyParams.data + 2, curveOidData->oid.data, curveOidData->oid.len); // Generate cert key pair - ScopedSECKEYPrivateKey privateKey; ScopedSECKEYPublicKey publicKey; SECKEYPublicKey* tempPublicKey; - privateKey = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN, &keyParams, - &tempPublicKey, true /* token */, - true /* sensitive */, nullptr); + UniqueSECKEYPrivateKey privateKey( + PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &keyParams, + &tempPublicKey, true /* token */, + true /* sensitive */, nullptr)); if (!privateKey) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } @@ -181,10 +182,9 @@ private: // Generate random serial unsigned long serial; // This serial in principle could collide, but it's unlikely - rv = MapSECStatus( - PK11_GenerateRandomOnSlot(slot, - reinterpret_cast(&serial), - sizeof(serial))); + rv = MapSECStatus(PK11_GenerateRandomOnSlot( + slot.get(), BitwiseCast(&serial), + sizeof(serial))); if (NS_FAILED(rv)) { return rv; } @@ -224,7 +224,7 @@ private: } rv = MapSECStatus( SEC_DerSignData(arena, &cert->derCert, certDER->data, certDER->len, - privateKey, + privateKey.get(), SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE)); if (NS_FAILED(rv)) { return rv; @@ -239,7 +239,7 @@ private: } // Save the cert in the DB - rv = MapSECStatus(PK11_ImportCert(slot, certFromDER, CK_INVALID_HANDLE, + rv = MapSECStatus(PK11_ImportCert(slot.get(), certFromDER, CK_INVALID_HANDLE, mNickname.get(), false /* unused */)); if (NS_FAILED(rv)) { return rv; @@ -368,21 +368,21 @@ LocalCertService::LoginToKeySlot() nsresult rv; // Get access to key slot - ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); if (!slot) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // If no user password yet, set it an empty one - if (PK11_NeedUserInit(slot)) { - rv = MapSECStatus(PK11_InitPin(slot, "", "")); + if (PK11_NeedUserInit(slot.get())) { + rv = MapSECStatus(PK11_InitPin(slot.get(), "", "")); if (NS_FAILED(rv)) { return rv; } } // If user has a password set, prompt to login - if (PK11_NeedLogin(slot) && !PK11_IsLoggedIn(slot, nullptr)) { + if (PK11_NeedLogin(slot.get()) && !PK11_IsLoggedIn(slot.get(), nullptr)) { // Switching to XPCOM to get the UI prompt that PSM owns nsCOMPtr tokenDB = do_GetService(NS_PK11TOKENDB_CONTRACTID); @@ -452,20 +452,21 @@ LocalCertService::GetLoginPromptRequired(bool* aRequired) nsresult rv; // Get access to key slot - ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); if (!slot) { return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } // If no user password yet, set it an empty one - if (PK11_NeedUserInit(slot)) { - rv = MapSECStatus(PK11_InitPin(slot, "", "")); + if (PK11_NeedUserInit(slot.get())) { + rv = MapSECStatus(PK11_InitPin(slot.get(), "", "")); if (NS_FAILED(rv)) { return rv; } } - *aRequired = PK11_NeedLogin(slot) && !PK11_IsLoggedIn(slot, nullptr); + *aRequired = PK11_NeedLogin(slot.get()) && + !PK11_IsLoggedIn(slot.get(), nullptr); return NS_OK; } diff --git a/security/manager/ssl/PSMContentListener.cpp b/security/manager/ssl/PSMContentListener.cpp index bc6c4c98ec..5ea6ae0b07 100644 --- a/security/manager/ssl/PSMContentListener.cpp +++ b/security/manager/ssl/PSMContentListener.cpp @@ -152,7 +152,7 @@ PSMContentStreamListener::OnStopRequest(nsIRequest* request, // Because importing the cert can spin the event loop (via alerts), we can't // do it here. Do it off the event loop instead. nsCOMPtr r = - NS_NewRunnableMethod(this, &PSMContentStreamListener::ImportCertificate); + NewRunnableMethod(this, &PSMContentStreamListener::ImportCertificate); MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(r)); return NS_OK; @@ -182,17 +182,20 @@ PSMContentStreamListener::ImportCertificate() switch (mType) { case X509_CA_CERT: - certdb->ImportCertificates(reinterpret_cast(mByteData.BeginWriting()), + certdb->ImportCertificates(BitwiseCast( + mByteData.BeginWriting()), mByteData.Length(), mType, ctx); break; case X509_USER_CERT: - certdb->ImportUserCertificate(reinterpret_cast(mByteData.BeginWriting()), + certdb->ImportUserCertificate(BitwiseCast( + mByteData.BeginWriting()), mByteData.Length(), ctx); break; case X509_EMAIL_CERT: - certdb->ImportEmailCertificate(reinterpret_cast(mByteData.BeginWriting()), + certdb->ImportEmailCertificate(BitwiseCast( + mByteData.BeginWriting()), mByteData.Length(), ctx); break; diff --git a/security/manager/ssl/PublicKeyPinningService.cpp b/security/manager/ssl/PublicKeyPinningService.cpp index d9098f1768..1f34c880b6 100644 --- a/security/manager/ssl/PublicKeyPinningService.cpp +++ b/security/manager/ssl/PublicKeyPinningService.cpp @@ -4,16 +4,16 @@ #include "PublicKeyPinningService.h" +#include "RootCertificateTelemetryUtils.h" #include "mozilla/Base64.h" +#include "mozilla/Casting.h" +#include "mozilla/Logging.h" #include "mozilla/Telemetry.h" #include "nsISiteSecurityService.h" #include "nsServiceManagerUtils.h" #include "nsSiteSecurityService.h" #include "nssb64.h" #include "pkix/pkixtypes.h" -#include "mozilla/Logging.h" -#include "RootCertificateTelemetryUtils.h" -#include "ScopedNSSTypes.h" #include "seccomon.h" #include "sechash.h" @@ -40,7 +40,7 @@ GetBase64HashSPKI(const CERTCertificate* cert, nsACString& hashSPKIDigest) return rv; } return Base64Encode(nsDependentCSubstring( - reinterpret_cast(digest.get().data), + BitwiseCast(digest.get().data), digest.get().len), hashSPKIDigest); } @@ -98,7 +98,8 @@ EvalCert(const CERTCertificate* cert, const StaticFingerprints* fingerprints, * dynamicFingerprints array, or to false otherwise. */ static nsresult -EvalChain(const CERTCertList* certList, const StaticFingerprints* fingerprints, +EvalChain(const UniqueCERTCertList& certList, + const StaticFingerprints* fingerprints, const nsTArray* dynamicFingerprints, /*out*/ bool& certListIntersectsPinset) { @@ -135,16 +136,15 @@ EvalChain(const CERTCertList* certList, const StaticFingerprints* fingerprints, Comparator for the is public key pinned host. */ static int -TransportSecurityPreloadCompare(const void *key, const void *entry) { - const char *keyStr = reinterpret_cast(key); - const TransportSecurityPreload *preloadEntry = - reinterpret_cast(entry); +TransportSecurityPreloadCompare(const void* key, const void* entry) { + auto keyStr = static_cast(key); + auto preloadEntry = static_cast(entry); return strcmp(keyStr, preloadEntry->mHost); } nsresult -PublicKeyPinningService::ChainMatchesPinset(const CERTCertList* certList, +PublicKeyPinningService::ChainMatchesPinset(const UniqueCERTCertList& certList, const nsTArray& aSHA256keys, /*out*/ bool& chainMatchesPinset) { @@ -231,7 +231,7 @@ FindPinningInformation(const char* hostname, mozilla::pkix::Time time, // subject public key info data in the list and the most relevant non-expired // pinset for the host or there is no pinning information for the host. static nsresult -CheckPinsForHostname(const CERTCertList* certList, const char* hostname, +CheckPinsForHostname(const UniqueCERTCertList& certList, const char* hostname, bool enforceTestMode, mozilla::pkix::Time time, /*out*/ bool& chainHasValidPins, /*optional out*/ PinningTelemetryInfo* pinningTelemetryInfo) @@ -318,7 +318,7 @@ CheckPinsForHostname(const CERTCertList* certList, const char* hostname, } nsresult -PublicKeyPinningService::ChainHasValidPins(const CERTCertList* certList, +PublicKeyPinningService::ChainHasValidPins(const UniqueCERTCertList& certList, const char* hostname, mozilla::pkix::Time time, bool enforceTestMode, diff --git a/security/manager/ssl/PublicKeyPinningService.h b/security/manager/ssl/PublicKeyPinningService.h index 601f624e58..f42376b527 100644 --- a/security/manager/ssl/PublicKeyPinningService.h +++ b/security/manager/ssl/PublicKeyPinningService.h @@ -5,8 +5,9 @@ #ifndef PublicKeyPinningService_h #define PublicKeyPinningService_h -#include "cert.h" #include "CertVerifier.h" +#include "ScopedNSSTypes.h" +#include "cert.h" #include "nsString.h" #include "nsTArray.h" #include "pkix/Time.h" @@ -26,7 +27,7 @@ public: * Note: if an alt name is a wildcard, it won't necessarily find a pinset * that would otherwise be valid for it */ - static nsresult ChainHasValidPins(const CERTCertList* certList, + static nsresult ChainHasValidPins(const UniqueCERTCertList& certList, const char* hostname, mozilla::pkix::Time time, bool enforceTestMode, @@ -37,7 +38,7 @@ public: * certificate list and the pins specified in the aSHA256keys array. * Values passed in are assumed to be in base64 encoded form. */ - static nsresult ChainMatchesPinset(const CERTCertList* certList, + static nsresult ChainMatchesPinset(const UniqueCERTCertList& certList, const nsTArray& aSHA256keys, /*out*/ bool& chainMatchesPinset); @@ -61,4 +62,4 @@ public: }} // namespace mozilla::psm -#endif // PublicKeyPinningServiceService_h +#endif // PublicKeyPinningService_h diff --git a/security/manager/ssl/RootCertificateTelemetryUtils.cpp b/security/manager/ssl/RootCertificateTelemetryUtils.cpp index e97b6acbb3..3f9ea3eb62 100644 --- a/security/manager/ssl/RootCertificateTelemetryUtils.cpp +++ b/security/manager/ssl/RootCertificateTelemetryUtils.cpp @@ -58,9 +58,9 @@ RootCABinNumber(const SECItem* cert) digest.get().data[0], digest.get().data[1], digest.get().data[2], digest.get().data[3])); if (mozilla::BinarySearchIf(ROOT_TABLE, 0, ArrayLength(ROOT_TABLE), - BinaryHashSearchArrayComparator( - reinterpret_cast(digest.get().data), digest.get().len), - &idx)) { + BinaryHashSearchArrayComparator(static_cast(digest.get().data), + digest.get().len), + &idx)) { MOZ_LOG(gPublicKeyPinningTelemetryLog, LogLevel::Debug, ("pkpinTelem: Telemetry index was %lu, bin is %d\n", diff --git a/security/manager/ssl/SSLServerCertVerification.cpp b/security/manager/ssl/SSLServerCertVerification.cpp index c2b74c546a..2b4302299a 100644 --- a/security/manager/ssl/SSLServerCertVerification.cpp +++ b/security/manager/ssl/SSLServerCertVerification.cpp @@ -107,6 +107,7 @@ #include "SharedSSLState.h" #include "cert.h" #include "mozilla/Assertions.h" +#include "mozilla/Casting.h" #include "mozilla/Mutex.h" #include "mozilla/Telemetry.h" #include "mozilla/UniquePtr.h" @@ -734,7 +735,7 @@ public: const void* fdForLogging, nsNSSSocketInfo* infoObject, const UniqueCERTCertificate& serverCert, - ScopedCERTCertList& peerCertChain, + const UniqueCERTCertList& peerCertChain, SECItem* stapledOCSPResponse, uint32_t providerFlags, Time time, @@ -747,7 +748,7 @@ private: const void* fdForLogging, nsNSSSocketInfo* infoObject, const UniqueCERTCertificate& cert, - CERTCertList* peerCertChain, + UniqueCERTCertList peerCertChain, SECItem* stapledOCSPResponse, uint32_t providerFlags, Time time, @@ -756,7 +757,7 @@ private: const void* const mFdForLogging; const RefPtr mInfoObject; const UniqueCERTCertificate mCert; - ScopedCERTCertList mPeerCertChain; + UniqueCERTCertList mPeerCertChain; const uint32_t mProviderFlags; const Time mTime; const PRTime mPRTime; @@ -767,13 +768,13 @@ private: SSLServerCertVerificationJob::SSLServerCertVerificationJob( const RefPtr& certVerifier, const void* fdForLogging, nsNSSSocketInfo* infoObject, const UniqueCERTCertificate& cert, - CERTCertList* peerCertChain, SECItem* stapledOCSPResponse, + UniqueCERTCertList peerCertChain, SECItem* stapledOCSPResponse, uint32_t providerFlags, Time time, PRTime prtime) : mCertVerifier(certVerifier) , mFdForLogging(fdForLogging) , mInfoObject(infoObject) , mCert(CERT_DupCertificate(cert.get())) - , mPeerCertChain(peerCertChain) + , mPeerCertChain(Move(peerCertChain)) , mProviderFlags(providerFlags) , mTime(time) , mPRTime(prtime) @@ -893,7 +894,7 @@ TryMatchingWildcardSubjectAltName(const char* commonName, // certList consists of a validated certificate chain. The end-entity // certificate is first and the root (trust anchor) is last. void -GatherBaselineRequirementsTelemetry(const ScopedCERTCertList& certList) +GatherBaselineRequirementsTelemetry(const UniqueCERTCertList& certList) { CERTCertListNode* endEntityNode = CERT_LIST_HEAD(certList); CERTCertListNode* rootNode = CERT_LIST_TAIL(certList); @@ -963,7 +964,8 @@ GatherBaselineRequirementsTelemetry(const ScopedCERTCertList& certList) do { nsAutoCString altName; if (currentName->type == certDNSName) { - altName.Assign(reinterpret_cast(currentName->name.other.data), + altName.Assign(BitwiseCast( + currentName->name.other.data), currentName->name.other.len); nsDependentCString altNameWithoutWildcard(altName, 0); if (StringBeginsWith(altNameWithoutWildcard, NS_LITERAL_CSTRING("*."))) { @@ -1058,7 +1060,7 @@ GatherBaselineRequirementsTelemetry(const ScopedCERTCertList& certList) // Gather telemetry on whether the end-entity cert for a server has the // required TLS Server Authentication EKU, or any others void -GatherEKUTelemetry(const ScopedCERTCertList& certList) +GatherEKUTelemetry(const UniqueCERTCertList& certList) { CERTCertListNode* endEntityNode = CERT_LIST_HEAD(certList); CERTCertListNode* rootNode = CERT_LIST_TAIL(certList); @@ -1140,7 +1142,7 @@ GatherEKUTelemetry(const ScopedCERTCertList& certList) // If the root is a built-in root, then the telemetry makes a count // by root. Roots that are not built-in are counted in one bin. void -GatherRootCATelemetry(const ScopedCERTCertList& certList) +GatherRootCATelemetry(const UniqueCERTCertList& certList) { CERTCertListNode* rootNode = CERT_LIST_TAIL(certList); PR_ASSERT(rootNode); @@ -1166,7 +1168,7 @@ const uint64_t ONE_YEAR_IN_WEEKS = 52; // Gathers telemetry on the certificate lifetimes we observe in the wild void -GatherEndEntityTelemetry(const ScopedCERTCertList& certList) +GatherEndEntityTelemetry(const UniqueCERTCertList& certList) { CERTCertListNode* endEntityNode = CERT_LIST_HEAD(certList); PR_ASSERT(endEntityNode); @@ -1207,7 +1209,7 @@ GatherEndEntityTelemetry(const ScopedCERTCertList& certList) // There are various things that we want to measure about certificate // chains that we accept. This is a single entry point for all of them. void -GatherSuccessfulValidationTelemetry(const ScopedCERTCertList& certList) +GatherSuccessfulValidationTelemetry(const UniqueCERTCertList& certList) { GatherBaselineRequirementsTelemetry(certList); GatherEKUTelemetry(certList); @@ -1215,11 +1217,12 @@ GatherSuccessfulValidationTelemetry(const ScopedCERTCertList& certList) GatherEndEntityTelemetry(certList); } +// Note: Takes ownership of |peerCertChain| if SECSuccess is not returned. SECStatus AuthCertificate(CertVerifier& certVerifier, nsNSSSocketInfo* infoObject, const UniqueCERTCertificate& cert, - ScopedCERTCertList& peerCertChain, + UniqueCERTCertList& peerCertChain, SECItem* stapledOCSPResponse, uint32_t providerFlags, Time time) @@ -1235,7 +1238,7 @@ AuthCertificate(CertVerifier& certVerifier, !(providerFlags & nsISocketProvider::NO_PERMANENT_STORAGE); SECOidTag evOidPolicy; - ScopedCERTCertList certList; + UniqueCERTCertList certList; CertVerifier::OCSPStaplingStatus ocspStaplingStatus = CertVerifier::OCSP_STAPLING_NEVER_CHECKED; KeySizeStatus keySizeStatus = KeySizeStatus::NeverChecked; @@ -1342,9 +1345,8 @@ AuthCertificate(CertVerifier& certVerifier, if (rv != SECSuccess) { // Certificate validation failed; store the peer certificate chain on - // infoObject so it can be used for error reporting. Note: infoObject - // indirectly takes ownership of peerCertChain. - infoObject->SetFailedCertChain(peerCertChain); + // infoObject so it can be used for error reporting. + infoObject->SetFailedCertChain(Move(peerCertChain)); PR_SetError(savedErrorCode, 0); } @@ -1357,7 +1359,7 @@ SSLServerCertVerificationJob::Dispatch( const void* fdForLogging, nsNSSSocketInfo* infoObject, const UniqueCERTCertificate& serverCert, - ScopedCERTCertList& peerCertChain, + const UniqueCERTCertList& peerCertChain, SECItem* stapledOCSPResponse, uint32_t providerFlags, Time time, @@ -1375,11 +1377,16 @@ SSLServerCertVerificationJob::Dispatch( // We can safely skip checking if NSS has already shut down here since we're // in the middle of verifying a certificate. nsNSSShutDownPreventionLock lock; - CERTCertList* peerCertChainCopy = nsNSSCertList::DupCertList(peerCertChain, lock); + UniqueCERTCertList peerCertChainCopy = + nsNSSCertList::DupCertList(peerCertChain, lock); + if (!peerCertChainCopy) { + PR_SetError(SEC_ERROR_NO_MEMORY, 0); + return SECFailure; + } RefPtr job( new SSLServerCertVerificationJob(certVerifier, fdForLogging, infoObject, - serverCert, peerCertChainCopy, + serverCert, Move(peerCertChainCopy), stapledOCSPResponse, providerFlags, time, prtime)); @@ -1433,6 +1440,8 @@ SSLServerCertVerificationJob::Run() SECStatus rv = AuthCertificate(*mCertVerifier, mInfoObject, mCert, mPeerCertChain, mStapledOCSPResponse, mProviderFlags, mTime); + MOZ_ASSERT(mPeerCertChain || rv != SECSuccess, + "AuthCertificate() should take ownership of chain on failure"); if (rv == SECSuccess) { uint32_t interval = (uint32_t) ((TimeStamp::Now() - mJobStartTime).ToMilliseconds()); RefPtr restart( @@ -1533,7 +1542,11 @@ AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer) } // Get the peer certificate chain for error reporting - ScopedCERTCertList peerCertChain(SSL_PeerCertificateChain(fd)); + UniqueCERTCertList peerCertChain(SSL_PeerCertificateChain(fd)); + if (!peerCertChain) { + PR_SetError(PR_INVALID_STATE_ERROR, 0); + return SECFailure; + } socketInfo->SetFullHandshake(); @@ -1601,6 +1614,8 @@ AuthCertificateHook(void* arg, PRFileDesc* fd, PRBool checkSig, PRBool isServer) SECStatus rv = AuthCertificate(*certVerifier, socketInfo, serverCert, peerCertChain, stapledOCSPResponse, providerFlags, now); + MOZ_ASSERT(peerCertChain || rv != SECSuccess, + "AuthCertificate() should take ownership of chain on failure"); if (rv == SECSuccess) { Telemetry::Accumulate(Telemetry::SSL_CERT_ERROR_OVERRIDES, 1); return SECSuccess; diff --git a/security/manager/ssl/ScopedNSSTypes.h b/security/manager/ssl/ScopedNSSTypes.h index 2917c8eeee..ac02ed672b 100644 --- a/security/manager/ssl/ScopedNSSTypes.h +++ b/security/manager/ssl/ScopedNSSTypes.h @@ -16,6 +16,7 @@ #include "cms.h" #include "cryptohi.h" #include "keyhi.h" +#include "mozilla/Casting.h" #include "mozilla/Likely.h" #include "mozilla/Scoped.h" #include "mozilla/UniquePtr.h" @@ -37,21 +38,23 @@ namespace mozilla { +// Deprecated: Use something like |mozilla::BitwiseCast(p)| +// instead. // It is very common to cast between char* and uint8_t* when doing crypto stuff. // Here, we provide more type-safe wrappers around reinterpret_cast so you don't // shoot yourself in the foot by reinterpret_casting completely unrelated types. -inline char * -char_ptr_cast(uint8_t * p) { return reinterpret_cast(p); } +inline char* +char_ptr_cast(uint8_t* p) { return BitwiseCast(p); } -inline const char * -char_ptr_cast(const uint8_t * p) { return reinterpret_cast(p); } +inline const char* +char_ptr_cast(const uint8_t* p) { return BitwiseCast(p); } -inline uint8_t * -uint8_t_ptr_cast(char * p) { return reinterpret_cast(p); } +inline uint8_t* +uint8_t_ptr_cast(char* p) { return BitwiseCast(p); } -inline const uint8_t * -uint8_t_ptr_cast(const char * p) { return reinterpret_cast(p); } +inline const uint8_t* +uint8_t_ptr_cast(const char* p) { return BitwiseCast(p); } // NSPR APIs use PRStatus/PR_GetError and NSS APIs use SECStatus/PR_GetError to // report success/failure. This function makes it more convenient and *safer* @@ -86,9 +89,6 @@ MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTCertificateList, MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTCertificateRequest, CERTCertificateRequest, CERT_DestroyCertificateRequest) -MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTCertList, - CERTCertList, - CERT_DestroyCertList) MOZ_TYPE_SPECIFIC_SCOPED_POINTER_TEMPLATE(ScopedCERTName, CERTName, CERT_DestroyName) diff --git a/security/manager/ssl/TransportSecurityInfo.cpp b/security/manager/ssl/TransportSecurityInfo.cpp index 58476bf5cc..215f3628c6 100644 --- a/security/manager/ssl/TransportSecurityInfo.cpp +++ b/security/manager/ssl/TransportSecurityInfo.cpp @@ -6,29 +6,30 @@ #include "TransportSecurityInfo.h" -#include "pkix/pkixtypes.h" -#include "nsNSSComponent.h" -#include "nsIWebProgressListener.h" -#include "nsNSSCertificate.h" -#include "nsIX509CertValidity.h" -#include "nsIDateTimeFormat.h" +#include "PSMRunnable.h" +#include "mozilla/Casting.h" +#include "nsComponentManagerUtils.h" +#include "nsIArray.h" #include "nsICertOverrideService.h" +#include "nsIDateTimeFormat.h" #include "nsIObjectInputStream.h" #include "nsIObjectOutputStream.h" +#include "nsIWebProgressListener.h" +#include "nsIX509CertValidity.h" #include "nsNSSCertHelper.h" -#include "nsIArray.h" -#include "nsComponentManagerUtils.h" +#include "nsNSSCertificate.h" +#include "nsNSSComponent.h" #include "nsReadableUtils.h" #include "nsServiceManagerUtils.h" #include "nsXULAppAPI.h" -#include "PSMRunnable.h" #include "mozilla/net/DNS.h" +#include "pkix/pkixtypes.h" #include "secerr.h" //#define DEBUG_SSL_VERBOSE //Enable this define to get minimal //reports when doing SSL read/write - + //#define DUMP_BUFFER //Enable this define along with //DEBUG_SSL_VERBOSE to dump SSL //read/write buffer to a log. @@ -422,7 +423,7 @@ TransportSecurityInfo::Read(nsIObjectInputStream* stream) if (NS_FAILED(rv)) { return rv; } - mSSLStatus = reinterpret_cast(supports.get()); + mSSLStatus = BitwiseCast(supports.get()); nsCOMPtr failedCertChainSupports; rv = NS_ReadOptionalObject(stream, true, getter_AddRefs(failedCertChainSupports)); @@ -651,9 +652,9 @@ GetSubjectAltNames(CERTCertificate* nssCert, nsString& allNames) switch (current->type) { case certDNSName: { - nsDependentCSubstring nameFromCert(reinterpret_cast - (current->name.other.data), - current->name.other.len); + nsDependentCSubstring nameFromCert(BitwiseCast( + current->name.other.data), + current->name.other.len); // dNSName fields are defined as type IA5String and thus should // be limited to ASCII characters. if (IsASCII(nameFromCert)) { @@ -1079,16 +1080,15 @@ TransportSecurityInfo::GetFailedCertChain(nsIX509CertList** _result) } nsresult -TransportSecurityInfo::SetFailedCertChain(ScopedCERTCertList& certList) +TransportSecurityInfo::SetFailedCertChain(UniqueCERTCertList certList) { nsNSSShutDownPreventionLock lock; if (isAlreadyShutDown()) { return NS_ERROR_NOT_AVAILABLE; } - nsCOMPtr comCertList; // nsNSSCertList takes ownership of certList - mFailedCertChain = new nsNSSCertList(certList, lock); + mFailedCertChain = new nsNSSCertList(Move(certList), lock); return NS_OK; } diff --git a/security/manager/ssl/TransportSecurityInfo.h b/security/manager/ssl/TransportSecurityInfo.h index 1f6e1f8416..2910167f17 100644 --- a/security/manager/ssl/TransportSecurityInfo.h +++ b/security/manager/ssl/TransportSecurityInfo.h @@ -4,8 +4,8 @@ * 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_PSM_TRANSPORTSECURITYINFO_H -#define _MOZILLA_PSM_TRANSPORTSECURITYINFO_H +#ifndef TransportSecurityInfo_h +#define TransportSecurityInfo_h #include "ScopedNSSTypes.h" #include "certt.h" @@ -70,13 +70,13 @@ public: void SetCanceled(PRErrorCode errorCode, ::mozilla::psm::SSLErrorMessageType errorMessageType); - + /* Set SSL Status values */ nsresult SetSSLStatus(nsSSLStatus *aSSLStatus); nsSSLStatus* SSLStatus() { return mSSLStatus; } void SetStatusErrorBits(nsNSSCertificate* cert, uint32_t collected_errors); - nsresult SetFailedCertChain(ScopedCERTCertList& certList); + nsresult SetFailedCertChain(UniqueCERTCertList certList); private: mutable ::mozilla::Mutex mMutex; @@ -161,4 +161,4 @@ private: { 0x16786594, 0x0296, 0x4471, \ { 0x80, 0x96, 0x8f, 0x84, 0x49, 0x7c, 0xa4, 0x28 } } -#endif /* _MOZILLA_PSM_TRANSPORTSECURITYINFO_H */ +#endif // TransportSecurityInfo_h diff --git a/security/manager/ssl/nsCertOverrideService.cpp b/security/manager/ssl/nsCertOverrideService.cpp index ee8031e4af..ca1844c673 100644 --- a/security/manager/ssl/nsCertOverrideService.cpp +++ b/security/manager/ssl/nsCertOverrideService.cpp @@ -371,27 +371,24 @@ nsCertOverrideService::RememberValidityOverride(const nsACString& aHostName, return NS_ERROR_FAILURE; } - char* nickname = DefaultServerNicknameForCert(nsscert.get()); - if (!aTemporary && nickname && *nickname) - { - ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + nsAutoCString nickname; + nsresult rv = DefaultServerNicknameForCert(nsscert.get(), nickname); + if (!aTemporary && NS_SUCCEEDED(rv)) { + UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); if (!slot) { - PR_Free(nickname); return NS_ERROR_FAILURE; } - - SECStatus srv = PK11_ImportCert(slot, nsscert.get(), CK_INVALID_HANDLE, - nickname, false); + + SECStatus srv = PK11_ImportCert(slot.get(), nsscert.get(), CK_INVALID_HANDLE, + nickname.get(), false); if (srv != SECSuccess) { - PR_Free(nickname); return NS_ERROR_FAILURE; } } - PR_FREEIF(nickname); nsAutoCString fpStr; - nsresult rv = GetCertFingerprintByOidTag(nsscert.get(), - mOidTagForStoringNewHashes, fpStr); + rv = GetCertFingerprintByOidTag(nsscert.get(), mOidTagForStoringNewHashes, + fpStr); if (NS_FAILED(rv)) return rv; diff --git a/security/manager/ssl/nsCertPicker.cpp b/security/manager/ssl/nsCertPicker.cpp index 987e374293..7cb04416e2 100644 --- a/security/manager/ssl/nsCertPicker.cpp +++ b/security/manager/ssl/nsCertPicker.cpp @@ -64,14 +64,13 @@ NS_IMETHODIMP nsCertPicker::PickByUsage(nsIInterfaceRequestor *ctx, { // Iterate over all certs. This assures that user is logged in to all hardware tokens. nsCOMPtr ctx = new PipUIContext(); - ScopedCERTCertList allcerts(PK11_ListCerts(PK11CertListUnique, ctx)); + UniqueCERTCertList allcerts(PK11_ListCerts(PK11CertListUnique, ctx)); } /* find all user certs that are valid for the specified usage */ /* note that we are allowing expired certs in this list */ - - ScopedCERTCertList certList( - CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), + UniqueCERTCertList certList( + CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), (SECCertUsage)certUsage, !allowDuplicateNicknames, !allowInvalid, @@ -106,8 +105,7 @@ NS_IMETHODIMP nsCertPicker::PickByUsage(nsIInterfaceRequestor *ctx, } } - UniqueCERTCertNicknames nicknames( - getNSSCertNicknamesFromCertList(certList.get())); + UniqueCERTCertNicknames nicknames(getNSSCertNicknamesFromCertList(certList)); if (!nicknames) { return NS_ERROR_NOT_AVAILABLE; } diff --git a/security/manager/ssl/nsCertTree.cpp b/security/manager/ssl/nsCertTree.cpp index 2729be2696..25aa04a2c3 100644 --- a/security/manager/ssl/nsCertTree.cpp +++ b/security/manager/ssl/nsCertTree.cpp @@ -182,10 +182,10 @@ nsCertTree::FreeCertArray() mDispInfo.Clear(); } -CompareCacheHashEntry * -nsCertTree::getCacheEntry(void *cache, void *aCert) +CompareCacheHashEntry* +nsCertTree::getCacheEntry(void* cache, void* aCert) { - PLDHashTable &aCompareCache = *reinterpret_cast(cache); + PLDHashTable& aCompareCache = *static_cast(cache); auto entryPtr = static_cast (aCompareCache.Add(aCert, fallible)); return entryPtr ? entryPtr->entry : nullptr; @@ -584,7 +584,7 @@ nsCertTree::GetCertsByType(uint32_t aType, { nsNSSShutDownPreventionLock locker; nsCOMPtr cxt = new PipUIContext(); - ScopedCERTCertList certList(PK11_ListCerts(PK11CertListUnique, cxt)); + UniqueCERTCertList certList(PK11_ListCerts(PK11CertListUnique, cxt)); return GetCertsByTypeFromCertList(certList.get(), aType, aCertCmpFn, aCertCmpFnArg); } @@ -605,7 +605,7 @@ nsCertTree::GetCertsByTypeFromCache(nsIX509CertList *aCache, // more encapsulated types that handled NSS shutdown themselves, we wouldn't // be having these kinds of problems. nsNSSShutDownPreventionLock locker; - CERTCertList *certList = reinterpret_cast(aCache->GetRawCertList()); + CERTCertList* certList = aCache->GetRawCertList(); if (!certList) return NS_ERROR_FAILURE; return GetCertsByTypeFromCertList(certList, aType, aCertCmpFn, aCertCmpFnArg); diff --git a/security/manager/ssl/nsDataSignatureVerifier.cpp b/security/manager/ssl/nsDataSignatureVerifier.cpp index b2dc945e30..b62d09490e 100644 --- a/security/manager/ssl/nsDataSignatureVerifier.cpp +++ b/security/manager/ssl/nsDataSignatureVerifier.cpp @@ -7,6 +7,7 @@ #include "cms.h" #include "cryptohi.h" #include "keyhi.h" +#include "mozilla/Casting.h" #include "mozilla/unused.h" #include "nsCOMPtr.h" #include "nsNSSComponent.h" @@ -108,7 +109,8 @@ nsDataSignatureVerifier::VerifyData(const nsACString& aData, // Perform the final verification DER_ConvertBitString(&(sigData.signature)); srv = VFY_VerifyDataWithAlgorithmID( - reinterpret_cast(PromiseFlatCString(aData).get()), + BitwiseCast( + PromiseFlatCString(aData).get()), aData.Length(), publicKey.get(), &(sigData.signature), &(sigData.signatureAlgorithm), nullptr, nullptr); @@ -160,7 +162,7 @@ VerifyCMSDetachedSignatureIncludingCertificate( // signedData is non-owning NSSCMSSignedData* signedData = - reinterpret_cast(NSS_CMSContentInfo_GetContent(cinfo)); + static_cast(NSS_CMSContentInfo_GetContent(cinfo)); if (!signedData) { return NS_ERROR_CMS_VERIFY_NO_CONTENT_INFO; } @@ -242,7 +244,7 @@ namespace { struct VerifyCertificateContext { nsCOMPtr signingCert; - ScopedCERTCertList builtChain; + UniqueCERTCertList builtChain; }; static nsresult @@ -254,7 +256,7 @@ VerifyCertificate(CERTCertificate* cert, void* voidContext, void* pinArg) } VerifyCertificateContext* context = - reinterpret_cast(voidContext); + static_cast(voidContext); nsCOMPtr xpcomCert(nsNSSCertificate::Create(cert)); if (!xpcomCert) { @@ -304,7 +306,7 @@ nsDataSignatureVerifier::VerifySignature(const char* aRSABuf, SECItem buffer = { siBuffer, - reinterpret_cast(const_cast(aRSABuf)), + BitwiseCast(aRSABuf), aRSABufLen }; diff --git a/security/manager/ssl/nsIX509CertList.idl b/security/manager/ssl/nsIX509CertList.idl index e0be66fb68..63f1c5e384 100644 --- a/security/manager/ssl/nsIX509CertList.idl +++ b/security/manager/ssl/nsIX509CertList.idl @@ -7,16 +7,23 @@ interface nsISimpleEnumerator; interface nsIX509Cert; +%{C++ +typedef struct CERTCertListStr CERTCertList; +%} +[ptr] native CERTCertListPtr(CERTCertList); + [scriptable, uuid(ae74cda5-cd2f-473f-96f5-f0b7fff62c68)] interface nsIX509CertList : nsISupports { void addCert(in nsIX509Cert cert); void deleteCert(in nsIX509Cert cert); nsISimpleEnumerator getEnumerator(); - /* getRawCertList MUST be called only from functions where - * the nssShutdownPreventionLock has been adquired. + /** + * Returns the raw, backing cert list. + * Must be called only from functions where an nsNSSShutDownPreventionLock + * has been acquired. */ - [notxpcom, noscript] voidPtr getRawCertList(); + [notxpcom, noscript] CERTCertListPtr getRawCertList(); /** * Test whether two certificate list instances represent the same diff --git a/security/manager/ssl/nsKeyModule.cpp b/security/manager/ssl/nsKeyModule.cpp index 6b0f80ac45..7c5fcf5c98 100644 --- a/security/manager/ssl/nsKeyModule.cpp +++ b/security/manager/ssl/nsKeyModule.cpp @@ -137,7 +137,7 @@ nsKeyObjectFactory::KeyFromString(int16_t aAlgorithm, const nsACString& aKey, keyItem.data = (unsigned char*)flatKey.get(); keyItem.len = flatKey.Length(); - ScopedPK11SlotInfo slot(PK11_GetBestSlot(cipherMech, nullptr)); + UniquePK11SlotInfo slot(PK11_GetBestSlot(cipherMech, nullptr)); if (!slot) { return NS_ERROR_FAILURE; } diff --git a/security/manager/ssl/nsNSSCallbacks.cpp b/security/manager/ssl/nsNSSCallbacks.cpp index 62241c1abe..986665eb27 100644 --- a/security/manager/ssl/nsNSSCallbacks.cpp +++ b/security/manager/ssl/nsNSSCallbacks.cpp @@ -6,6 +6,8 @@ #include "nsNSSCallbacks.h" +#include "mozilla/ArrayUtils.h" +#include "mozilla/Casting.h" #include "mozilla/TimeStamp.h" #include "nsContentUtils.h" #include "nsICertOverrideService.h" @@ -176,7 +178,7 @@ struct nsCancelHTTPDownloadEvent : Runnable { Result nsNSSHttpServerSession::createSessionFcn(const char* host, uint16_t portnum, - SEC_HTTP_SERVER_SESSION* pSession) + /*out*/ nsNSSHttpServerSession** pSession) { if (!host || !pSession) { return Result::FATAL_ERROR_INVALID_ARGS; @@ -195,23 +197,18 @@ nsNSSHttpServerSession::createSessionFcn(const char* host, } Result -nsNSSHttpRequestSession::createFcn(SEC_HTTP_SERVER_SESSION session, +nsNSSHttpRequestSession::createFcn(const nsNSSHttpServerSession* session, const char* http_protocol_variant, const char* path_and_query_string, const char* http_request_method, const PRIntervalTime timeout, - SEC_HTTP_REQUEST_SESSION* pRequest) + /*out*/ nsNSSHttpRequestSession** pRequest) { if (!session || !http_protocol_variant || !path_and_query_string || !http_request_method || !pRequest) { return Result::FATAL_ERROR_INVALID_ARGS; } - nsNSSHttpServerSession* hss = static_cast(session); - if (!hss) { - return Result::FATAL_ERROR_INVALID_ARGS; - } - nsNSSHttpRequestSession* rs = new nsNSSHttpRequestSession; if (!rs) { return Result::FATAL_ERROR_NO_MEMORY; @@ -228,14 +225,14 @@ nsNSSHttpRequestSession::createFcn(SEC_HTTP_SERVER_SESSION session, rs->mURL.Assign(http_protocol_variant); rs->mURL.AppendLiteral("://"); - rs->mURL.Append(hss->mHost); + rs->mURL.Append(session->mHost); rs->mURL.Append(':'); - rs->mURL.AppendInt(hss->mPort); + rs->mURL.AppendInt(session->mPort); rs->mURL.Append(path_and_query_string); rs->mRequestMethod = http_request_method; - *pRequest = (void*)rs; + *pRequest = rs; return Success; } @@ -830,16 +827,17 @@ PreliminaryHandshakeDone(PRFileDesc* fd) unsigned char npnbuf[256]; unsigned int npnlen; - if (SSL_GetNextProto(fd, &state, npnbuf, &npnlen, 256) == SECSuccess) { + if (SSL_GetNextProto(fd, &state, npnbuf, &npnlen, + AssertedCast(ArrayLength(npnbuf))) + == SECSuccess) { if (state == SSL_NEXT_PROTO_NEGOTIATED || state == SSL_NEXT_PROTO_SELECTED) { - infoObject->SetNegotiatedNPN(reinterpret_cast(npnbuf), npnlen); - } - else { + infoObject->SetNegotiatedNPN(BitwiseCast(npnbuf), + npnlen); + } else { infoObject->SetNegotiatedNPN(nullptr, 0); } - } - else { + } else { infoObject->SetNegotiatedNPN(nullptr, 0); } diff --git a/security/manager/ssl/nsNSSCallbacks.h b/security/manager/ssl/nsNSSCallbacks.h index 8ec6f95d1d..6c123098ae 100644 --- a/security/manager/ssl/nsNSSCallbacks.h +++ b/security/manager/ssl/nsNSSCallbacks.h @@ -84,7 +84,7 @@ public: static Result createSessionFcn(const char* host, uint16_t portnum, - SEC_HTTP_SERVER_SESSION* pSession); + /*out*/ nsNSSHttpServerSession** pSession); }; class nsNSSHttpRequestSession @@ -95,12 +95,12 @@ protected: public: typedef mozilla::pkix::Result Result; - static Result createFcn(SEC_HTTP_SERVER_SESSION session, + static Result createFcn(const nsNSSHttpServerSession* session, const char* httpProtocolVariant, const char* pathAndQueryString, const char* httpRequestMethod, const PRIntervalTime timeout, - SEC_HTTP_REQUEST_SESSION* pRequest); + /*out*/ nsNSSHttpRequestSession** pRequest); Result setPostDataFcn(const char* httpData, const uint32_t httpDataLen, @@ -147,17 +147,17 @@ public: static Result createSessionFcn(const char* host, uint16_t portnum, - SEC_HTTP_SERVER_SESSION* pSession) + /*out*/ nsNSSHttpServerSession** pSession) { return nsNSSHttpServerSession::createSessionFcn(host, portnum, pSession); } - static Result createFcn(SEC_HTTP_SERVER_SESSION session, + static Result createFcn(const nsNSSHttpServerSession* session, const char* httpProtocolVariant, const char* pathAndQueryString, const char* httpRequestMethod, const PRIntervalTime timeout, - SEC_HTTP_REQUEST_SESSION* pRequest) + /*out*/ nsNSSHttpRequestSession** pRequest) { return nsNSSHttpRequestSession::createFcn(session, httpProtocolVariant, pathAndQueryString, @@ -165,16 +165,15 @@ public: pRequest); } - static Result setPostDataFcn(SEC_HTTP_REQUEST_SESSION request, + static Result setPostDataFcn(nsNSSHttpRequestSession* request, const char* httpData, const uint32_t httpDataLen, const char* httpContentType) { - return static_cast(request) - ->setPostDataFcn(httpData, httpDataLen, httpContentType); + return request->setPostDataFcn(httpData, httpDataLen, httpContentType); } - static Result trySendAndReceiveFcn(SEC_HTTP_REQUEST_SESSION request, + static Result trySendAndReceiveFcn(nsNSSHttpRequestSession* request, PRPollDesc** pPollDesc, uint16_t* httpResponseCode, const char** httpResponseContentType, @@ -182,10 +181,10 @@ public: const char** httpResponseData, uint32_t* httpResponseDataLen) { - return static_cast(request) - ->trySendAndReceiveFcn(pPollDesc, httpResponseCode, - httpResponseContentType, httpResponseHeaders, - httpResponseData, httpResponseDataLen); + return request->trySendAndReceiveFcn(pPollDesc, httpResponseCode, + httpResponseContentType, + httpResponseHeaders, + httpResponseData, httpResponseDataLen); } }; diff --git a/security/manager/ssl/nsNSSCertHelper.cpp b/security/manager/ssl/nsNSSCertHelper.cpp index 50bfde108d..5da7b7a7c5 100644 --- a/security/manager/ssl/nsNSSCertHelper.cpp +++ b/security/manager/ssl/nsNSSCertHelper.cpp @@ -6,7 +6,7 @@ #include -#include "ScopedNSSTypes.h" +#include "mozilla/Casting.h" #include "mozilla/net/DNS.h" #include "mozilla/Snprintf.h" #include "mozilla/UniquePtr.h" @@ -102,7 +102,7 @@ ProcessVersion(SECItem* versionItem, nsINSSComponent* nssComponent, if (versionItem->len != 1) { return NS_ERROR_FAILURE; } - version = *reinterpret_cast(versionItem->data); + version = *BitwiseCast(versionItem->data); } else { // If there is no version present in the cert, then RFC 5280 says we // default to v1 (0). @@ -2065,8 +2065,8 @@ getCertType(CERTCertificate *cert) return nsIX509Cert::UNKNOWN_CERT; } -CERTCertNicknames * -getNSSCertNicknamesFromCertList(CERTCertList *certList) +CERTCertNicknames* +getNSSCertNicknamesFromCertList(const UniqueCERTCertList& certList) { static NS_DEFINE_CID(kNSSComponentCID, NS_NSSCOMPONENT_CID); @@ -2091,10 +2091,9 @@ getNSSCertNicknamesFromCertList(CERTCertList *certList) NS_ConvertUTF16toUTF8 aUtf8ExpiredString(expiredStringLeadingSpace); NS_ConvertUTF16toUTF8 aUtf8NotYetValidString(notYetValidStringLeadingSpace); - return CERT_NicknameStringsFromCertList(certList, + return CERT_NicknameStringsFromCertList(certList.get(), const_cast(aUtf8ExpiredString.get()), const_cast(aUtf8NotYetValidString.get())); - } nsresult diff --git a/security/manager/ssl/nsNSSCertHelper.h b/security/manager/ssl/nsNSSCertHelper.h index 3f30ad7ccf..1c84ea05c8 100644 --- a/security/manager/ssl/nsNSSCertHelper.h +++ b/security/manager/ssl/nsNSSCertHelper.h @@ -2,25 +2,26 @@ * 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 _NSNSSCERTHELPER_H_ -#define _NSNSSCERTHELPER_H_ +#ifndef nsNSSCertHelper_h +#define nsNSSCertHelper_h #ifndef INET6_ADDRSTRLEN #define INET6_ADDRSTRLEN 46 #endif +#include "ScopedNSSTypes.h" #include "certt.h" #include "nsString.h" uint32_t getCertType(CERTCertificate *cert); -CERTCertNicknames * -getNSSCertNicknamesFromCertList(CERTCertList *certList); +CERTCertNicknames* +getNSSCertNicknamesFromCertList(const mozilla::UniqueCERTCertList& certList); nsresult GetCertFingerprintByOidTag(CERTCertificate* nsscert, SECOidTag aOidTag, nsCString &fp); -#endif +#endif // nsNSSCertHelper_h diff --git a/security/manager/ssl/nsNSSCertificate.cpp b/security/manager/ssl/nsNSSCertificate.cpp index 1ccc243ab7..843b50db12 100644 --- a/security/manager/ssl/nsNSSCertificate.cpp +++ b/security/manager/ssl/nsNSSCertificate.cpp @@ -10,6 +10,7 @@ #include "NSSCertDBTrustDomain.h" #include "certdb.h" #include "mozilla/Base64.h" +#include "mozilla/Casting.h" #include "mozilla/unused.h" #include "nsArray.h" #include "nsCOMPtr.h" @@ -532,12 +533,14 @@ nsNSSCertificate::GetDbKey(const UniqueCERTCertificate& cert, nsACString& aDbKey const char leadingZeroes[] = {0, 0, 0, 0, 0, 0, 0, 0}; buf.Append(leadingZeroes, sizeof(leadingZeroes)); uint32_t serialNumberLen = htonl(cert->serialNumber.len); - buf.Append(reinterpret_cast(&serialNumberLen), sizeof(uint32_t)); + buf.Append(BitwiseCast(&serialNumberLen), + sizeof(uint32_t)); uint32_t issuerLen = htonl(cert->derIssuer.len); - buf.Append(reinterpret_cast(&issuerLen), sizeof(uint32_t)); - buf.Append(reinterpret_cast(cert->serialNumber.data), + buf.Append(BitwiseCast(&issuerLen), + sizeof(uint32_t)); + buf.Append(BitwiseCast(cert->serialNumber.data), cert->serialNumber.len); - buf.Append(reinterpret_cast(cert->derIssuer.data), + buf.Append(BitwiseCast(cert->derIssuer.data), cert->derIssuer.len); return Base64Encode(buf, aDbKey); @@ -841,10 +844,10 @@ nsNSSCertificate::GetChain(nsIArray** _rvChain) mozilla::pkix::Time now(mozilla::pkix::Now()); - ScopedCERTCertList nssChain; RefPtr certVerifier(GetDefaultCertVerifier()); NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); + UniqueCERTCertList nssChain; // We want to test all usages, but we start with server because most of the // time Firefox users care about server certs. if (certVerifier->VerifyCert(mCert.get(), certificateUsageSSLServer, now, @@ -884,16 +887,15 @@ nsNSSCertificate::GetChain(nsIArray** _rvChain) } if (!nssChain) { - // There is not verified path for the chain, howeever we still want to + // There is not verified path for the chain, however we still want to // present to the user as much of a possible chain as possible, in the case // where there was a problem with the cert or the issuers. MOZ_LOG(gPIPNSSLog, LogLevel::Debug, ("pipnss: getchain :CertVerify failed to get chain for '%s'\n", mCert->nickname)); - nssChain = CERT_GetCertChainFromCert(mCert.get(), PR_Now(), - certUsageSSLClient); - } - + nssChain = UniqueCERTCertList( + CERT_GetCertChainFromCert(mCert.get(), PR_Now(), certUsageSSLClient)); + } if (!nssChain) { return NS_ERROR_FAILURE; } @@ -1102,7 +1104,7 @@ nsNSSCertificate::GetSha256SubjectPublicKeyInfoDigest(nsACString& aSha256SPKIDig return rv; } rv = Base64Encode(nsDependentCSubstring( - reinterpret_cast (digest.get().data), + BitwiseCast(digest.get().data), digest.get().len), aSha256SPKIDigest); if (NS_WARN_IF(NS_FAILED(rv))) { @@ -1405,7 +1407,7 @@ nsNSSCertificate::hasValidEVOidTag(SECOidTag& resultOidTag, bool& validEV) uint32_t flags = mozilla::psm::CertVerifier::FLAG_LOCAL_ONLY | mozilla::psm::CertVerifier::FLAG_MUST_BE_EV; - ScopedCERTCertList unusedBuiltChain; + UniqueCERTCertList unusedBuiltChain; SECStatus rv = certVerifier->VerifyCert(mCert.get(), certificateUsageSSLServer, mozilla::pkix::Now(), nullptr /* XXX pinarg */, @@ -1479,9 +1481,9 @@ namespace mozilla { SECStatus ConstructCERTCertListFromReversedDERArray( const mozilla::pkix::DERArray& certArray, - /*out*/ ScopedCERTCertList& certList) + /*out*/ UniqueCERTCertList& certList) { - certList = CERT_NewCertList(); + certList = UniqueCERTCertList(CERT_NewCertList()); if (!certList) { return SECFailure; } @@ -1519,19 +1521,19 @@ NS_IMPL_ISUPPORTS_CI(nsNSSCertList, nsIX509CertList, nsISerializable) -nsNSSCertList::nsNSSCertList(ScopedCERTCertList& certList, +nsNSSCertList::nsNSSCertList(UniqueCERTCertList certList, const nsNSSShutDownPreventionLock& proofOfLock) { if (certList) { - mCertList = certList.forget(); + mCertList = Move(certList); } else { - mCertList = CERT_NewCertList(); + mCertList = UniqueCERTCertList(CERT_NewCertList()); } } nsNSSCertList::nsNSSCertList() { - mCertList = CERT_NewCertList(); + mCertList = UniqueCERTCertList(CERT_NewCertList()); } nsNSSCertList::~nsNSSCertList() @@ -1551,9 +1553,7 @@ void nsNSSCertList::virtualDestroyNSSReference() void nsNSSCertList::destructorSafeDestroyNSSReference() { - if (mCertList) { - mCertList = nullptr; - } + mCertList = nullptr; } NS_IMETHODIMP @@ -1612,30 +1612,37 @@ nsNSSCertList::DeleteCert(nsIX509Cert* aCert) return NS_OK; // XXX Should we fail if we couldn't find it? } -CERTCertList* -nsNSSCertList::DupCertList(CERTCertList* aCertList, +UniqueCERTCertList +nsNSSCertList::DupCertList(const UniqueCERTCertList& certList, const nsNSSShutDownPreventionLock& /*proofOfLock*/) { - if (!aCertList) { + if (!certList) { return nullptr; } - CERTCertList* newList = CERT_NewCertList(); - + UniqueCERTCertList newList(CERT_NewCertList()); if (!newList) { return nullptr; } - CERTCertListNode* node; - for (node = CERT_LIST_HEAD(aCertList); !CERT_LIST_END(node, aCertList); - node = CERT_LIST_NEXT(node)) { - CERTCertificate* cert = CERT_DupCertificate(node->cert); - CERT_AddCertToListTail(newList, cert); + for (CERTCertListNode* node = CERT_LIST_HEAD(certList); + !CERT_LIST_END(node, certList); + node = CERT_LIST_NEXT(node)) { + UniqueCERTCertificate cert(CERT_DupCertificate(node->cert)); + if (!cert) { + return nullptr; + } + + if (CERT_AddCertToListTail(newList.get(), cert.get()) != SECSuccess) { + return nullptr; + } + + Unused << cert.release(); // Ownership transferred to the cert list. } return newList; } -void* +CERTCertList* nsNSSCertList::GetRawCertList() { // This function should only be called after acquiring a @@ -1740,8 +1747,13 @@ nsNSSCertList::GetEnumerator(nsISimpleEnumerator** _retval) if (isAlreadyShutDown()) { return NS_ERROR_NOT_AVAILABLE; } + + if (!mCertList) { + return NS_ERROR_FAILURE; + } + nsCOMPtr enumerator = - new nsNSSCertListEnumerator(mCertList.get(), locker); + new nsNSSCertListEnumerator(mCertList, locker); enumerator.forget(_retval); return NS_OK; @@ -1811,8 +1823,10 @@ nsNSSCertList::Equals(nsIX509CertList* other, bool* result) NS_IMPL_ISUPPORTS(nsNSSCertListEnumerator, nsISimpleEnumerator) nsNSSCertListEnumerator::nsNSSCertListEnumerator( - CERTCertList* certList, const nsNSSShutDownPreventionLock& proofOfLock) + const UniqueCERTCertList& certList, + const nsNSSShutDownPreventionLock& proofOfLock) { + MOZ_ASSERT(certList); mCertList = nsNSSCertList::DupCertList(certList, proofOfLock); } @@ -1833,9 +1847,7 @@ void nsNSSCertListEnumerator::virtualDestroyNSSReference() void nsNSSCertListEnumerator::destructorSafeDestroyNSSReference() { - if (mCertList) { - mCertList = nullptr; - } + mCertList = nullptr; } NS_IMETHODIMP diff --git a/security/manager/ssl/nsNSSCertificate.h b/security/manager/ssl/nsNSSCertificate.h index c31c636b34..0cecf05f93 100644 --- a/security/manager/ssl/nsNSSCertificate.h +++ b/security/manager/ssl/nsNSSCertificate.h @@ -3,20 +3,20 @@ * 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 _NS_NSSCERTIFICATE_H_ -#define _NS_NSSCERTIFICATE_H_ +#ifndef nsNSSCertificate_h +#define nsNSSCertificate_h +#include "ScopedNSSTypes.h" +#include "certt.h" +#include "nsCOMPtr.h" +#include "nsIASN1Object.h" +#include "nsIClassInfo.h" +#include "nsISerializable.h" +#include "nsISimpleEnumerator.h" #include "nsIX509Cert.h" #include "nsIX509CertDB.h" #include "nsIX509CertList.h" -#include "nsIASN1Object.h" -#include "nsCOMPtr.h" #include "nsNSSShutDown.h" -#include "nsISimpleEnumerator.h" -#include "nsISerializable.h" -#include "nsIClassInfo.h" -#include "ScopedNSSTypes.h" -#include "certt.h" namespace mozilla { namespace pkix { class DERArray; } } @@ -84,7 +84,7 @@ namespace mozilla { SECStatus ConstructCERTCertListFromReversedDERArray( const mozilla::pkix::DERArray& certArray, - /*out*/ mozilla::ScopedCERTCertList& certList); + /*out*/ mozilla::UniqueCERTCertList& certList); } // namespace mozilla @@ -98,20 +98,21 @@ public: NS_DECL_NSISERIALIZABLE // certList is adopted - nsNSSCertList(mozilla::ScopedCERTCertList& certList, + nsNSSCertList(mozilla::UniqueCERTCertList certList, const nsNSSShutDownPreventionLock& proofOfLock); nsNSSCertList(); - static CERTCertList* DupCertList(CERTCertList* aCertList, - const nsNSSShutDownPreventionLock& - proofOfLock); + static mozilla::UniqueCERTCertList DupCertList( + const mozilla::UniqueCERTCertList& certList, + const nsNSSShutDownPreventionLock& proofOfLock); + private: virtual ~nsNSSCertList(); virtual void virtualDestroyNSSReference() override; void destructorSafeDestroyNSSReference(); - mozilla::ScopedCERTCertList mCertList; + mozilla::UniqueCERTCertList mCertList; nsNSSCertList(const nsNSSCertList&) = delete; void operator=(const nsNSSCertList&) = delete; @@ -124,14 +125,14 @@ public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSISIMPLEENUMERATOR - nsNSSCertListEnumerator(CERTCertList* certList, + nsNSSCertListEnumerator(const mozilla::UniqueCERTCertList& certList, const nsNSSShutDownPreventionLock& proofOfLock); private: virtual ~nsNSSCertListEnumerator(); virtual void virtualDestroyNSSReference() override; void destructorSafeDestroyNSSReference(); - mozilla::ScopedCERTCertList mCertList; + mozilla::UniqueCERTCertList mCertList; nsNSSCertListEnumerator(const nsNSSCertListEnumerator&) = delete; void operator=(const nsNSSCertListEnumerator&) = delete; @@ -144,4 +145,4 @@ private: { 0xbb, 0x20, 0x89, 0x85, 0xa6, 0x32, 0xdf, 0x05 } \ } -#endif // _NS_NSSCERTIFICATE_H_ +#endif // nsNSSCertificate_h diff --git a/security/manager/ssl/nsNSSCertificateDB.cpp b/security/manager/ssl/nsNSSCertificateDB.cpp index ff129c489c..36ce2f2735 100644 --- a/security/manager/ssl/nsNSSCertificateDB.cpp +++ b/security/manager/ssl/nsNSSCertificateDB.cpp @@ -9,6 +9,7 @@ #include "NSSCertDBTrustDomain.h" #include "SharedSSLState.h" #include "mozilla/Base64.h" +#include "mozilla/Casting.h" #include "mozilla/unused.h" #include "nsArray.h" #include "nsArrayUtils.h" @@ -65,14 +66,14 @@ attemptToLogInWithDefaultPassword() // change certificate trust to pass on all platforms. TODO(bug 978120): Do // proper testing and/or implement a better solution so that we are confident // that this does the correct thing outside of xpcshell tests too. - ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); if (!slot) { return MapSECStatus(SECFailure); } - if (PK11_NeedUserInit(slot)) { + if (PK11_NeedUserInit(slot.get())) { // Ignore the return value. Presumably PK11_InitPin will fail if the user // has a non-default password. - (void) PK11_InitPin(slot, nullptr, nullptr); + Unused << PK11_InitPin(slot.get(), nullptr, nullptr); } #endif @@ -179,24 +180,28 @@ nsNSSCertificateDB::FindCertByDBKey(const char* aDBKey, return NS_ERROR_ILLEGAL_INPUT; } const char* reader = decoded.BeginReading(); - uint64_t zeroes = *reinterpret_cast(reader); + uint64_t zeroes = *BitwiseCast(reader); if (zeroes != 0) { return NS_ERROR_ILLEGAL_INPUT; } reader += sizeof(uint64_t); - uint32_t serialNumberLen = ntohl(*reinterpret_cast(reader)); + // Note: We surround the ntohl() argument with parentheses to stop the macro + // from thinking two arguments were passed. + uint32_t serialNumberLen = ntohl( + (*BitwiseCast(reader))); reader += sizeof(uint32_t); - uint32_t issuerLen = ntohl(*reinterpret_cast(reader)); + uint32_t issuerLen = ntohl( + (*BitwiseCast(reader))); reader += sizeof(uint32_t); if (decoded.Length() != 16ULL + serialNumberLen + issuerLen) { return NS_ERROR_ILLEGAL_INPUT; } CERTIssuerAndSN issuerSN; issuerSN.serialNumber.len = serialNumberLen; - issuerSN.serialNumber.data = (unsigned char*)reader; + issuerSN.serialNumber.data = BitwiseCast(reader); reader += serialNumberLen; issuerSN.derIssuer.len = issuerLen; - issuerSN.derIssuer.data = (unsigned char*)reader; + issuerSN.derIssuer.data = BitwiseCast(reader); reader += issuerLen; MOZ_ASSERT(reader == decoded.EndReading()); @@ -237,8 +242,7 @@ nsNSSCertificateDB::getCertsFromPackage(const UniquePLArenaPool& arena, uint8_t* data, uint32_t length, const nsNSSShutDownPreventionLock& /*proofOfLock*/) { - CERTDERCerts* collectArgs = - (CERTDERCerts*)PORT_ArenaZAlloc(arena.get(), sizeof(CERTDERCerts)); + CERTDERCerts* collectArgs = PORT_ArenaZNew(arena.get(), CERTDERCerts); if (!collectArgs) { return nullptr; } @@ -465,9 +469,8 @@ nsNSSCertificateDB::ImportCertificates(uint8_t* data, uint32_t length, // Now let's create some certs to work with for (int i = 0; i < certCollection->numcerts; i++) { SECItem* currItem = &certCollection->rawCerts[i]; - nsCOMPtr cert = - nsNSSCertificate::ConstructFromDER(reinterpret_cast(currItem->data), - currItem->len); + nsCOMPtr cert = nsNSSCertificate::ConstructFromDER( + BitwiseCast(currItem->data), currItem->len); if (!cert) { return NS_ERROR_FAILURE; } @@ -554,7 +557,7 @@ ImportCertsIntoTempStorage(int numcerts, SECItem* certs, } static SECStatus -ImportCertsIntoPermanentStorage(const ScopedCERTCertList& certChain, +ImportCertsIntoPermanentStorage(const UniqueCERTCertList& certChain, const SECCertUsage usage, const bool caOnly) { int chainLen = 0; @@ -630,7 +633,7 @@ nsNSSCertificateDB::ImportEmailCertificate(uint8_t* data, uint32_t length, continue; } - ScopedCERTCertList certChain; + UniqueCERTCertList certChain; SECStatus srv = certVerifier->VerifyCert(node->cert, certificateUsageEmailRecipient, mozilla::pkix::Now(), ctx, @@ -686,7 +689,7 @@ nsNSSCertificateDB::ImportValidCACertsInList(const UniqueCERTCertList& filteredC for (CERTCertListNode* node = CERT_LIST_HEAD(filteredCerts.get()); !CERT_LIST_END(node, filteredCerts.get()); node = CERT_LIST_NEXT(node)) { - ScopedCERTCertList certChain; + UniqueCERTCertList certChain; SECStatus rv = certVerifier->VerifyCert(node->cert, certificateUsageVerifyCA, mozilla::pkix::Now(), ctx, @@ -1009,7 +1012,7 @@ nsNSSCertificateDB::ImportCertsFromFile(nsIFile* aFile, uint32_t aType) return NS_ERROR_FAILURE; } -NS_IMETHODIMP +NS_IMETHODIMP nsNSSCertificateDB::ImportPKCS12File(nsISupports* aToken, nsIFile* aFile) { nsNSSShutDownPreventionLock locker; @@ -1026,12 +1029,11 @@ nsNSSCertificateDB::ImportPKCS12File(nsISupports* aToken, nsIFile* aFile) return blob.ImportFromFile(aFile); } -NS_IMETHODIMP +NS_IMETHODIMP nsNSSCertificateDB::ExportPKCS12File(nsISupports* aToken, nsIFile* aFile, uint32_t count, nsIX509Cert** certs) - //const char16_t **aCertNames) { nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) { @@ -1043,16 +1045,15 @@ nsNSSCertificateDB::ExportPKCS12File(nsISupports* aToken, if (count == 0) return NS_OK; nsCOMPtr localRef; if (!aToken) { - ScopedPK11SlotInfo keySlot(PK11_GetInternalKeySlot()); - NS_ASSERTION(keySlot,"Failed to get the internal key slot"); - localRef = new nsPK11Token(keySlot); - } - else { + UniquePK11SlotInfo keySlot(PK11_GetInternalKeySlot()); + if (!keySlot) { + return NS_ERROR_FAILURE; + } + localRef = new nsPK11Token(keySlot.get()); + } else { localRef = do_QueryInterface(aToken); } blob.SetToken(localRef); - //blob.LoadCerts(aCertNames, count); - //return blob.ExportToFile(aFile); return blob.ExportToFile(aFile, certs, count); } @@ -1142,7 +1143,7 @@ nsNSSCertificateDB::FindCertByEmailAddress(const char* aEmailAddress, RefPtr certVerifier(GetDefaultCertVerifier()); NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); - ScopedCERTCertList certlist( + UniqueCERTCertList certlist( PK11_FindCertsFromEmailAddress(aEmailAddress, nullptr)); if (!certlist) return NS_ERROR_FAILURE; @@ -1159,7 +1160,7 @@ nsNSSCertificateDB::FindCertByEmailAddress(const char* aEmailAddress, !CERT_LIST_END(node, certlist); node = CERT_LIST_NEXT(node)) { - ScopedCERTCertList unusedCertChain; + UniqueCERTCertList unusedCertChain; SECStatus srv = certVerifier->VerifyCert(node->cert, certificateUsageEmailRecipient, mozilla::pkix::Now(), @@ -1291,13 +1292,9 @@ nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert, NS_ConvertUTF16toUTF8 nickFmt(tmpNickFmt); nsAutoCString baseName; - char *temp_nn = PR_smprintf(nickFmt.get(), username.get(), caname.get()); - if (!temp_nn) { + baseName.AppendPrintf(nickFmt.get(), username.get(), caname.get()); + if (baseName.IsEmpty()) { return; - } else { - baseName = temp_nn; - PR_smprintf_free(temp_nn); - temp_nn = nullptr; } nickname = baseName; @@ -1307,49 +1304,43 @@ nsNSSCertificateDB::get_default_nickname(CERTCertificate *cert, * then we need to check for nicknames that already exist on the smart * card. */ - ScopedPK11SlotInfo slot(PK11_KeyForCertExists(cert, &keyHandle, ctx)); + UniquePK11SlotInfo slot(PK11_KeyForCertExists(cert, &keyHandle, ctx)); if (!slot) return; - if (!PK11_IsInternal(slot)) { - char *tmp = PR_smprintf("%s:%s", PK11_GetTokenName(slot), baseName.get()); - if (!tmp) { + if (!PK11_IsInternal(slot.get())) { + nsAutoCString tmp; + tmp.AppendPrintf("%s:%s", PK11_GetTokenName(slot.get()), baseName.get()); + if (tmp.IsEmpty()) { nickname.Truncate(); return; } baseName = tmp; - PR_smprintf_free(tmp); - nickname = baseName; } int count = 1; while (true) { if ( count > 1 ) { - char *tmp = PR_smprintf("%s #%d", baseName.get(), count); - if (!tmp) { + nsAutoCString tmp; + tmp.AppendPrintf("%s #%d", baseName.get(), count); + if (tmp.IsEmpty()) { nickname.Truncate(); return; } nickname = tmp; - PR_smprintf_free(tmp); } UniqueCERTCertificate dummycert; - if (PK11_IsInternal(slot)) { + if (PK11_IsInternal(slot.get())) { /* look up the nickname to make sure it isn't in use already */ dummycert.reset(CERT_FindCertByNickname(defaultcertdb, nickname.get())); } else { - /* - * Check the cert against others that already live on the smart - * card. - */ + // Check the cert against others that already live on the smart card. dummycert.reset(PK11_FindCertFromNickname(nickname.get(), ctx)); if (dummycert) { - /* - * Make sure the subject names are different. - */ + // Make sure the subject names are different. if (CERT_CompareName(&cert->subject, &dummycert->subject) == SECEqual) { /* @@ -1471,15 +1462,15 @@ nsNSSCertificateDB::GetCerts(nsIX509CertList **_retval) nsNSSShutDownPreventionLock locker; if (isAlreadyShutDown()) { return NS_ERROR_NOT_AVAILABLE; - } + } nsCOMPtr ctx = new PipUIContext(); nsCOMPtr nssCertList; - ScopedCERTCertList certList(PK11_ListCerts(PK11CertListUnique, ctx)); + UniqueCERTCertList certList(PK11_ListCerts(PK11CertListUnique, ctx)); // nsNSSCertList 1) adopts certList, and 2) handles the nullptr case fine. // (returns an empty list) - nssCertList = new nsNSSCertList(certList, locker); + nssCertList = new nsNSSCertList(Move(certList), locker); nssCertList.forget(_retval); return NS_OK; @@ -1517,7 +1508,7 @@ VerifyCertAtTime(nsIX509Cert* aCert, RefPtr certVerifier(GetDefaultCertVerifier()); NS_ENSURE_TRUE(certVerifier, NS_ERROR_FAILURE); - ScopedCERTCertList resultChain; + UniqueCERTCertList resultChain; SECOidTag evOidPolicy; SECStatus srv; @@ -1545,7 +1536,7 @@ VerifyCertAtTime(nsIX509Cert* aCert, nsCOMPtr nssCertList; // This adopts the list - nssCertList = new nsNSSCertList(resultChain, locker); + nssCertList = new nsNSSCertList(Move(resultChain), locker); NS_ENSURE_TRUE(nssCertList, NS_ERROR_FAILURE); if (srv == SECSuccess) { diff --git a/security/manager/ssl/nsNSSCertificateDB.h b/security/manager/ssl/nsNSSCertificateDB.h index 4258a153bf..23502460a3 100644 --- a/security/manager/ssl/nsNSSCertificateDB.h +++ b/security/manager/ssl/nsNSSCertificateDB.h @@ -5,13 +5,14 @@ #ifndef nsNSSCertificateDB_h #define nsNSSCertificateDB_h +#include "ScopedNSSTypes.h" #include "certt.h" #include "mozilla/Mutex.h" #include "mozilla/RefPtr.h" #include "mozilla/UniquePtr.h" #include "nsIX509CertDB.h" #include "nsNSSShutDown.h" -#include "ScopedNSSTypes.h" +#include "nsString.h" class nsCString; class nsIArray; diff --git a/security/manager/ssl/nsNSSCertificateFakeTransport.cpp b/security/manager/ssl/nsNSSCertificateFakeTransport.cpp index 81863c7c6e..45f0f9d6d8 100644 --- a/security/manager/ssl/nsNSSCertificateFakeTransport.cpp +++ b/security/manager/ssl/nsNSSCertificateFakeTransport.cpp @@ -425,7 +425,7 @@ nsNSSCertListFakeTransport::DeleteCert(nsIX509Cert* aCert) return NS_ERROR_NOT_IMPLEMENTED; } -void* +CERTCertList* nsNSSCertListFakeTransport::GetRawCertList() { NS_NOTREACHED("Unimplemented on content process"); diff --git a/security/manager/ssl/nsNSSComponent.cpp b/security/manager/ssl/nsNSSComponent.cpp index 44a5316a34..641e540d66 100644 --- a/security/manager/ssl/nsNSSComponent.cpp +++ b/security/manager/ssl/nsNSSComponent.cpp @@ -12,6 +12,7 @@ #include "SharedSSLState.h" #include "cert.h" #include "certdb.h" +#include "mozilla/Casting.h" #include "mozilla/Preferences.h" #include "mozilla/PublicSSL.h" #include "mozilla/Services.h" @@ -440,7 +441,7 @@ GetUserSid(nsAString& sidString) return false; } char sid_buffer[SECURITY_MAX_SID_SIZE]; - SID* sid = reinterpret_cast(sid_buffer); + SID* sid = BitwiseCast(sid_buffer); DWORD cbSid = MOZ_ARRAY_LENGTH(sid_buffer); SID_NAME_USE eUse; // There doesn't appear to be a defined maximum length for the domain name diff --git a/security/manager/ssl/nsNSSIOLayer.cpp b/security/manager/ssl/nsNSSIOLayer.cpp index 3240ab21a7..0e2f68e337 100644 --- a/security/manager/ssl/nsNSSIOLayer.cpp +++ b/security/manager/ssl/nsNSSIOLayer.cpp @@ -413,7 +413,7 @@ nsNSSSocketInfo::IsAcceptableForHost(const nsACString& hostname, bool* _retval) } nsAutoCString hostnameFlat(PromiseFlatCString(hostname)); CertVerifier::Flags flags = CertVerifier::FLAG_LOCAL_ONLY; - ScopedCERTCertList unusedBuiltChain; + UniqueCERTCertList unusedBuiltChain; SECStatus rv = certVerifier->VerifySSLServerCert(nssCert, nullptr, mozilla::pkix::Now(), nullptr, hostnameFlat.get(), @@ -505,7 +505,7 @@ nsNSSSocketInfo::SetNPNList(nsTArray& protocolArray) if (SSL_SetNextProtoNego( mFd, - reinterpret_cast(npnList.get()), + BitwiseCast(npnList.get()), npnList.Length()) != SECSuccess) return NS_ERROR_FAILURE; @@ -2005,7 +2005,7 @@ nsNSS_SSLGetClientAuthData(void* arg, PRFileDesc* socket, } RefPtr info( - reinterpret_cast(socket->higher->secret)); + BitwiseCast(socket->higher->secret)); UniqueCERTCertificate serverCert(SSL_PeerCertificate(socket)); if (!serverCert) { @@ -2057,7 +2057,7 @@ ClientAuthDataRunnable::RunOnTargetThread() char** caNameStrings; UniqueCERTCertificate cert; UniqueSECKEYPrivateKey privKey; - ScopedCERTCertList certList; + UniqueCERTCertList certList; CERTCertListNode* node; UniqueCERTCertNicknames nicknames; int keyError = 0; // used for private key retrieval error @@ -2110,9 +2110,9 @@ ClientAuthDataRunnable::RunOnTargetThread() // automatically find the right cert // find all user certs that are valid and for SSL - certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), - certUsageSSLClient, false, - true, wincx); + certList.reset(CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), + certUsageSSLClient, false, true, + wincx)); if (!certList) { goto noCert; } @@ -2202,7 +2202,7 @@ ClientAuthDataRunnable::RunOnTargetThread() getter_AddRefs(found_cert)); if (NS_SUCCEEDED(find_rv) && found_cert) { nsNSSCertificate* obj_cert = - reinterpret_cast(found_cert.get()); + BitwiseCast(found_cert.get()); if (obj_cert) { cert.reset(obj_cert->GetCert()); } @@ -2224,9 +2224,9 @@ ClientAuthDataRunnable::RunOnTargetThread() // find all user certs that are for SSL // note that we are allowing expired certs in this list - certList = CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), - certUsageSSLClient, false, - false, wincx); + certList.reset(CERT_FindUserCertsByUsage(CERT_GetDefaultCertDB(), + certUsageSSLClient, false, + false, wincx)); if (!certList) { goto noCert; } @@ -2257,7 +2257,7 @@ ClientAuthDataRunnable::RunOnTargetThread() goto noCert; } - nicknames.reset(getNSSCertNicknamesFromCertList(certList.get())); + nicknames.reset(getNSSCertNicknamesFromCertList(certList)); if (!nicknames) { goto loser; diff --git a/security/manager/ssl/nsNSSShutDown.cpp b/security/manager/ssl/nsNSSShutDown.cpp index 27f8d0bc12..adcbadcef1 100644 --- a/security/manager/ssl/nsNSSShutDown.cpp +++ b/security/manager/ssl/nsNSSShutDown.cpp @@ -2,6 +2,7 @@ * 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/Casting.h" #include "nsNSSShutDown.h" #include "nsCOMPtr.h" @@ -114,8 +115,8 @@ nsresult nsNSSShutDownList::doPK11Logout() !iter.Done(); iter.Next()) { auto entry = static_cast(iter.Get()); - nsOnPK11LogoutCancelObject *pklco = - reinterpret_cast(entry->obj); + nsOnPK11LogoutCancelObject* pklco = + BitwiseCast(entry->obj); if (pklco) { pklco->logout(); } diff --git a/security/manager/ssl/nsNSSU2FToken.cpp b/security/manager/ssl/nsNSSU2FToken.cpp index 63c1eaf85d..7fd5d36ae0 100644 --- a/security/manager/ssl/nsNSSU2FToken.cpp +++ b/security/manager/ssl/nsNSSU2FToken.cpp @@ -7,6 +7,7 @@ #include "nsNSSU2FToken.h" #include "CryptoBuffer.h" +#include "mozilla/Casting.h" #include "nsNSSComponent.h" #include "pk11pub.h" #include "prerror.h" @@ -83,7 +84,7 @@ nsNSSU2FToken::destructorSafeDestroyNSSReference() } static PK11SymKey* -GetSymKeyByNickname(PK11SlotInfo* aSlot, +GetSymKeyByNickname(const UniquePK11SlotInfo& aSlot, nsCString aNickname, const nsNSSShutDownPreventionLock&) { @@ -91,13 +92,13 @@ GetSymKeyByNickname(PK11SlotInfo* aSlot, ("Searching for a symmetric key named %s", aNickname.get())); PK11SymKey* keyList; - keyList = PK11_ListFixedKeysInSlot(aSlot, const_cast(aNickname.get()), + keyList = PK11_ListFixedKeysInSlot(aSlot.get(), + const_cast(aNickname.get()), /* wincx */ nullptr); while (keyList) { ScopedPK11SymKey freeKey(keyList); - UniquePtr - freeKeyName(PK11_GetSymKeyNickname(freeKey), PORT_Free); + UniquePORTString freeKeyName(PK11_GetSymKeyNickname(freeKey.get())); if (aNickname == freeKeyName.get()) { MOZ_LOG(gNSSTokenLog, LogLevel::Debug, ("Symmetric key found!")); @@ -112,7 +113,7 @@ GetSymKeyByNickname(PK11SlotInfo* aSlot, } static nsresult -GenEcKeypair(PK11SlotInfo* aSlot, ScopedSECKEYPrivateKey& aPrivKey, +GenEcKeypair(const UniquePK11SlotInfo& aSlot, ScopedSECKEYPrivateKey& aPrivKey, ScopedSECKEYPublicKey& aPubKey, const nsNSSShutDownPreventionLock&) { UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); @@ -130,7 +131,7 @@ GenEcKeypair(PK11SlotInfo* aSlot, ScopedSECKEYPrivateKey& aPrivKey, CK_MECHANISM_TYPE mechanism = CKM_EC_KEY_PAIR_GEN; SECKEYPublicKey* pubKeyRaw; - aPrivKey = PK11_GenerateKeyPair(aSlot, mechanism, keyParams, &pubKeyRaw, + aPrivKey = PK11_GenerateKeyPair(aSlot.get(), mechanism, keyParams, &pubKeyRaw, /* ephemeral */ PR_FALSE, PR_FALSE, /* wincx */ nullptr); aPubKey = pubKeyRaw; @@ -147,7 +148,7 @@ GenEcKeypair(PK11SlotInfo* aSlot, ScopedSECKEYPrivateKey& aPrivKey, } nsresult -nsNSSU2FToken::GetOrCreateWrappingKey(PK11SlotInfo* aSlot, +nsNSSU2FToken::GetOrCreateWrappingKey(const UniquePK11SlotInfo& aSlot, const nsNSSShutDownPreventionLock& locker) { // Search for an existing wrapping key. If we find it, @@ -164,7 +165,7 @@ nsNSSU2FToken::GetOrCreateWrappingKey(PK11SlotInfo* aSlot, // We did not find an existing wrapping key, so we generate one in the // persistent database (e.g, Token). - mWrappingKey = PK11_TokenKeyGenWithFlags(aSlot, CKM_AES_KEY_GEN, + mWrappingKey = PK11_TokenKeyGenWithFlags(aSlot.get(), CKM_AES_KEY_GEN, /* default params */ nullptr, kWrappingKeyByteLen, /* empty keyid */ nullptr, @@ -194,7 +195,7 @@ nsNSSU2FToken::GetOrCreateWrappingKey(PK11SlotInfo* aSlot, } static nsresult -GetAttestationCertificate(PK11SlotInfo* aSlot, +GetAttestationCertificate(const UniquePK11SlotInfo& aSlot, ScopedSECKEYPrivateKey& aAttestPrivKey, ScopedCERTCertificate& aAttestCert, const nsNSSShutDownPreventionLock& locker) @@ -245,8 +246,10 @@ GetAttestationCertificate(PK11SlotInfo* aSlot, } unsigned long serial; - unsigned char* serialBytes = reinterpret_cast(&serial); - SECStatus srv = PK11_GenerateRandomOnSlot(aSlot, serialBytes, sizeof(serial)); + unsigned char* serialBytes = + mozilla::BitwiseCast(&serial); + SECStatus srv = PK11_GenerateRandomOnSlot(aSlot.get(), serialBytes, + sizeof(serial)); if (srv != SECSuccess) { MOZ_LOG(gNSSTokenLog, LogLevel::Warning, ("Failed to gen serial, NSS error #%d", PORT_GetError())); @@ -320,11 +323,11 @@ nsNSSU2FToken::Init() return NS_ERROR_NOT_AVAILABLE; } - ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); MOZ_ASSERT(slot.get()); // Search for an existing wrapping key, or create one. - nsresult rv = GetOrCreateWrappingKey(slot.get(), locker); + nsresult rv = GetOrCreateWrappingKey(slot, locker); if (NS_WARN_IF(NS_FAILED(rv))) { return rv; } @@ -337,7 +340,7 @@ nsNSSU2FToken::Init() // Convert a Private Key object into an opaque key handle, using AES Key Wrap // and aWrappingKey to convert aPrivKey. static SECItem* -KeyHandleFromPrivateKey(PK11SlotInfo* aSlot, +KeyHandleFromPrivateKey(const UniquePK11SlotInfo& aSlot, PK11SymKey* aWrappingKey, SECKEYPrivateKey* aPrivKey, const nsNSSShutDownPreventionLock&) @@ -354,7 +357,7 @@ KeyHandleFromPrivateKey(PK11SlotInfo* aSlot, ScopedSECItem param(PK11_ParamFromIV(CKM_NSS_AES_KEY_WRAP_PAD, /* default IV */ nullptr )); - SECStatus srv = PK11_WrapPrivKey(aSlot, aWrappingKey, aPrivKey, + SECStatus srv = PK11_WrapPrivKey(aSlot.get(), aWrappingKey, aPrivKey, CKM_NSS_AES_KEY_WRAP_PAD, param, wrappedKey.get(), /* wincx */ nullptr); if (srv != SECSuccess) { @@ -369,7 +372,8 @@ KeyHandleFromPrivateKey(PK11SlotInfo* aSlot, // Convert an opaque key handle aKeyHandle back into a Private Key object, using // aWrappingKey and the AES Key Wrap algorithm. static SECKEYPrivateKey* -PrivateKeyFromKeyHandle(PK11SlotInfo* aSlot, PK11SymKey* aWrappingKey, +PrivateKeyFromKeyHandle(const UniquePK11SlotInfo& aSlot, + PK11SymKey* aWrappingKey, uint8_t* aKeyHandle, uint32_t aKeyHandleLen, const nsNSSShutDownPreventionLock&) { @@ -385,7 +389,7 @@ PrivateKeyFromKeyHandle(PK11SlotInfo* aSlot, PK11SymKey* aWrappingKey, int usageCount = 1; SECKEYPrivateKey* unwrappedKey; - unwrappedKey = PK11_UnwrapPrivKey(aSlot, aWrappingKey, + unwrappedKey = PK11_UnwrapPrivKey(aSlot.get(), aWrappingKey, CKM_NSS_AES_KEY_WRAP_PAD, param, &keyHandleItem, /* no nickname */ nullptr, @@ -437,11 +441,11 @@ nsNSSU2FToken::IsRegistered(uint8_t* aKeyHandle, uint32_t aKeyHandleLen, return NS_ERROR_FAILURE; } - ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + UniquePK11SlotInfo slot(PK11_GetInternalSlot()); MOZ_ASSERT(slot.get()); // Decode the key handle - ScopedSECKEYPrivateKey privKey(PrivateKeyFromKeyHandle(slot.get(), + UniqueSECKEYPrivateKey privKey(PrivateKeyFromKeyHandle(slot, mWrappingKey.get(), aKeyHandle, aKeyHandleLen, @@ -500,13 +504,13 @@ nsNSSU2FToken::Register(uint8_t* aApplication, // We should already have a wrapping key MOZ_ASSERT(mWrappingKey); - ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + UniquePK11SlotInfo slot(PK11_GetInternalSlot()); MOZ_ASSERT(slot.get()); // Construct a one-time-use Attestation Certificate ScopedSECKEYPrivateKey attestPrivKey; ScopedCERTCertificate attestCert; - nsresult rv = GetAttestationCertificate(slot.get(), attestPrivKey, attestCert, + nsresult rv = GetAttestationCertificate(slot, attestPrivKey, attestCert, locker); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; @@ -517,14 +521,13 @@ nsNSSU2FToken::Register(uint8_t* aApplication, // Generate a new keypair; the private will be wrapped into a Key Handle ScopedSECKEYPrivateKey privKey; ScopedSECKEYPublicKey pubKey; - rv = GenEcKeypair(slot.get(), privKey, pubKey, locker); + rv = GenEcKeypair(slot, privKey, pubKey, locker); if (NS_WARN_IF(NS_FAILED(rv))) { return NS_ERROR_FAILURE; } // The key handle will be the result of keywrap(privKey, key=mWrappingKey) - ScopedSECItem keyHandleItem(KeyHandleFromPrivateKey(slot.get(), - mWrappingKey.get(), + UniqueSECItem keyHandleItem(KeyHandleFromPrivateKey(slot, mWrappingKey.get(), privKey.get(), locker)); if (!keyHandleItem.get()) { @@ -628,7 +631,7 @@ nsNSSU2FToken::Sign(uint8_t* aApplication, uint32_t aApplicationLen, MOZ_ASSERT(mWrappingKey); - ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + UniquePK11SlotInfo slot(PK11_GetInternalSlot()); MOZ_ASSERT(slot.get()); if ((aChallengeLen != kParamLen) || (aApplicationLen != kParamLen)) { @@ -640,7 +643,7 @@ nsNSSU2FToken::Sign(uint8_t* aApplication, uint32_t aApplicationLen, } // Decode the key handle - ScopedSECKEYPrivateKey privKey(PrivateKeyFromKeyHandle(slot.get(), + UniqueSECKEYPrivateKey privKey(PrivateKeyFromKeyHandle(slot, mWrappingKey.get(), aKeyHandle, aKeyHandleLen, diff --git a/security/manager/ssl/nsNSSU2FToken.h b/security/manager/ssl/nsNSSU2FToken.h index d725b0da10..814aa99fc3 100644 --- a/security/manager/ssl/nsNSSU2FToken.h +++ b/security/manager/ssl/nsNSSU2FToken.h @@ -36,7 +36,7 @@ private: static const nsString mVersion; ~nsNSSU2FToken(); - nsresult GetOrCreateWrappingKey(PK11SlotInfo* aSlot, + nsresult GetOrCreateWrappingKey(const mozilla::UniquePK11SlotInfo& aSlot, const nsNSSShutDownPreventionLock&); }; diff --git a/security/manager/ssl/nsNTLMAuthModule.cpp b/security/manager/ssl/nsNTLMAuthModule.cpp index 8ef2223711..e095a51af9 100644 --- a/security/manager/ssl/nsNTLMAuthModule.cpp +++ b/security/manager/ssl/nsNTLMAuthModule.cpp @@ -7,7 +7,9 @@ #include +#include "ScopedNSSTypes.h" #include "md4.h" +#include "mozilla/Casting.h" #include "mozilla/CheckedInt.h" #include "mozilla/Endian.h" #include "mozilla/Likely.h" @@ -15,16 +17,15 @@ #include "mozilla/Snprintf.h" #include "nsCOMPtr.h" #include "nsComponentManagerUtils.h" -#include "nsICryptoHash.h" #include "nsICryptoHMAC.h" +#include "nsICryptoHash.h" #include "nsIKeyModule.h" #include "nsKeyModule.h" +#include "nsNSSShutDown.h" #include "nsNativeCharsetUtils.h" #include "nsNetCID.h" -#include "nsNSSShutDown.h" #include "nsUnicharUtils.h" #include "pk11pub.h" -#include "mozilla/Logging.h" #include "prsystem.h" static bool sNTLMv1Forced = false; @@ -449,7 +450,7 @@ ParseType2Msg(const void *inBuf, uint32_t inLen, Type2Msg *msg) if (inLen < NTLM_TYPE2_HEADER_LEN) return NS_ERROR_UNEXPECTED; - const uint8_t *cursor = reinterpret_cast(inBuf); + auto cursor = static_cast(inBuf); // verify NTLMSSP signature if (memcmp(cursor, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)) != 0) @@ -476,7 +477,7 @@ ParseType2Msg(const void *inBuf, uint32_t inLen, Type2Msg *msg) // integer overflow checking. if (MOZ_LIKELY(targetEnd.isValid() && targetEnd.value() <= inLen)) { msg->targetLen = targetLen; - msg->target = reinterpret_cast(inBuf) + offset; + msg->target = static_cast(inBuf) + offset; } else { // Do not error out, for (conservative) backward compatibility. msg->targetLen = 0; @@ -491,8 +492,9 @@ ParseType2Msg(const void *inBuf, uint32_t inLen, Type2Msg *msg) cursor += sizeof(msg->challenge); LOG(("NTLM type 2 message:\n")); - LogBuf("target", reinterpret_cast (msg->target), msg->targetLen); - LogBuf("flags", reinterpret_cast (&msg->flags), 4); + LogBuf("target", msg->target, msg->targetLen); + LogBuf("flags", + mozilla::BitwiseCast(&msg->flags), 4); LogFlags(msg->flags); LogBuf("challenge", msg->challenge, sizeof(msg->challenge)); @@ -512,7 +514,7 @@ ParseType2Msg(const void *inBuf, uint32_t inLen, Type2Msg *msg) // integer overflow checking. if (MOZ_LIKELY(targetInfoEnd.isValid() && targetInfoEnd.value() <= inLen)) { msg->targetInfoLen = targetInfoLen; - msg->targetInfo = reinterpret_cast(inBuf) + offset; + msg->targetInfo = static_cast(inBuf) + offset; } else { NS_ERROR("failed to get NTLMv2 target info"); return NS_ERROR_UNEXPECTED; @@ -570,7 +572,8 @@ GenerateType3Msg(const nsString &domain, ucsDomainBuf = domain; domainPtr = ucsDomainBuf.get(); domainLen = ucsDomainBuf.Length() * 2; - WriteUnicodeLE((void *) domainPtr, reinterpret_cast (domainPtr), + WriteUnicodeLE(const_cast(domainPtr), + static_cast(domainPtr), ucsDomainBuf.Length()); #else domainPtr = domain.get(); @@ -593,7 +596,8 @@ GenerateType3Msg(const nsString &domain, ucsUserBuf = username; userPtr = ucsUserBuf.get(); userLen = ucsUserBuf.Length() * 2; - WriteUnicodeLE((void *) userPtr, reinterpret_cast (userPtr), + WriteUnicodeLE(const_cast(userPtr), + static_cast(userPtr), ucsUserBuf.Length()); #else userPtr = username.get(); @@ -623,7 +627,8 @@ GenerateType3Msg(const nsString &domain, hostPtr = ucsHostBuf.get(); hostLen = ucsHostBuf.Length() * 2; #ifdef IS_BIG_ENDIAN - WriteUnicodeLE((void *) hostPtr, reinterpret_cast (hostPtr), + WriteUnicodeLE(const_cast(hostPtr), + static_cast(hostPtr), ucsHostBuf.Length()); #endif } @@ -669,19 +674,22 @@ GenerateType3Msg(const nsString &domain, userUpperPtr = ucsUserUpperBuf.get(); userUpperLen = ucsUserUpperBuf.Length() * 2; #ifdef IS_BIG_ENDIAN - WriteUnicodeLE((void *) userUpperPtr, reinterpret_cast (userUpperPtr), + WriteUnicodeLE(const_cast(userUpperPtr), + static_cast(userUpperPtr), ucsUserUpperBuf.Length()); #endif ToUpperCase(domain, ucsDomainUpperBuf); domainUpperPtr = ucsDomainUpperBuf.get(); domainUpperLen = ucsDomainUpperBuf.Length() * 2; #ifdef IS_BIG_ENDIAN - WriteUnicodeLE((void *) domainUpperPtr, reinterpret_cast (domainUpperPtr), + WriteUnicodeLE(const_cast(domainUpperPtr), + static_cast(domainUpperPtr), ucsDomainUpperBuf.Length()); #endif NTLM_Hash(password, ntlmHash); - ntlmHashStr = nsAutoCString(reinterpret_cast(ntlmHash), NTLM_HASH_LEN); + ntlmHashStr = nsAutoCString( + mozilla::BitwiseCast(ntlmHash), NTLM_HASH_LEN); nsCOMPtr keyFactory = do_CreateInstance(NS_KEYMODULEOBJECTFACTORY_CONTRACTID, &rv); @@ -710,11 +718,12 @@ GenerateType3Msg(const nsString &domain, if (NS_FAILED(rv)) { return rv; } - rv = hasher->Update(reinterpret_cast (userUpperPtr), userUpperLen); + rv = hasher->Update(static_cast(userUpperPtr), userUpperLen); if (NS_FAILED(rv)) { return rv; } - rv = hasher->Update(reinterpret_cast (domainUpperPtr), domainUpperLen); + rv = hasher->Update(static_cast(domainUpperPtr), + domainUpperLen); if (NS_FAILED(rv)) { return rv; } @@ -786,7 +795,7 @@ GenerateType3Msg(const nsString &domain, if (NS_FAILED(rv)) { return rv; } - rv = hasher->Update(reinterpret_cast (msg.targetInfo), msg.targetInfoLen); + rv = hasher->Update(msg.targetInfo, msg.targetInfoLen); if (NS_FAILED(rv)) { return rv; } @@ -809,7 +818,6 @@ GenerateType3Msg(const nsString &domain, } else if (msg.flags & NTLM_NegotiateNTLM2Key) { // compute NTLM2 session response nsCString sessionHashString; - const uint8_t *sessionHash; PK11_GenerateRandom(lmResp, NTLM_CHAL_LEN); memset(lmResp + NTLM_CHAL_LEN, 0, LM_RESP_LEN - NTLM_CHAL_LEN); @@ -836,7 +844,8 @@ GenerateType3Msg(const nsString &domain, return rv; } - sessionHash = reinterpret_cast (sessionHashString.get()); + auto sessionHash = mozilla::BitwiseCast( + sessionHashString.get()); LogBuf("NTLM2 effective key: ", sessionHash, 8); @@ -890,7 +899,7 @@ GenerateType3Msg(const nsString &domain, return NS_ERROR_UNEXPECTED; } cursor = WriteSecBuf(cursor, LM_RESP_LEN, offset.value()); - memcpy((uint8_t *) *outBuf + offset.value(), lmResp, LM_RESP_LEN); + memcpy(static_cast(*outBuf) + offset.value(), lmResp, LM_RESP_LEN); // 20 : NTLM or NTLMv2 response sec buf offset += LM_RESP_LEN; @@ -900,26 +909,30 @@ GenerateType3Msg(const nsString &domain, } cursor = WriteSecBuf(cursor, ntlmRespLen.value(), offset.value()); if (ntlmv2) { - memcpy(reinterpret_cast (*outBuf) + offset.value(), ntlmv2Resp, NTLMv2_RESP_LEN); + memcpy(static_cast(*outBuf) + offset.value(), ntlmv2Resp, + NTLMv2_RESP_LEN); offset += NTLMv2_RESP_LEN; if (!offset.isValid()) { NS_ERROR("failed preparing to write NTLM response: integer overflow?!?"); return NS_ERROR_UNEXPECTED; } - memcpy(reinterpret_cast (*outBuf) + offset.value(), ntlmv2_blob1, NTLMv2_BLOB1_LEN); + memcpy(static_cast(*outBuf) + offset.value(), ntlmv2_blob1, + NTLMv2_BLOB1_LEN); offset += NTLMv2_BLOB1_LEN; if (!offset.isValid()) { NS_ERROR("failed preparing to write NTLM response: integer overflow?!?"); return NS_ERROR_UNEXPECTED; } - memcpy(reinterpret_cast (*outBuf) + offset.value(), msg.targetInfo, msg.targetInfoLen); + memcpy(static_cast(*outBuf) + offset.value(), msg.targetInfo, + msg.targetInfoLen); } else { - memcpy(reinterpret_cast (*outBuf) + offset.value(), ntlmResp, NTLM_RESP_LEN); + memcpy(static_cast(*outBuf) + offset.value(), ntlmResp, + NTLM_RESP_LEN); } // 28 : domain name sec buf offset = NTLM_TYPE3_HEADER_LEN; cursor = WriteSecBuf(cursor, domainLen, offset.value()); - memcpy((uint8_t *) *outBuf + offset.value(), domainPtr, domainLen); + memcpy(static_cast(*outBuf) + offset.value(), domainPtr, domainLen); // 36 : user name sec buf offset += domainLen; @@ -928,7 +941,7 @@ GenerateType3Msg(const nsString &domain, return NS_ERROR_UNEXPECTED; } cursor = WriteSecBuf(cursor, userLen, offset.value()); - memcpy(reinterpret_cast (*outBuf) + offset.value(), userPtr, userLen); + memcpy(static_cast(*outBuf) + offset.value(), userPtr, userLen); // 44 : workstation (host) name sec buf offset += userLen; @@ -937,7 +950,7 @@ GenerateType3Msg(const nsString &domain, return NS_ERROR_UNEXPECTED; } cursor = WriteSecBuf(cursor, hostLen, offset.value()); - memcpy(reinterpret_cast (*outBuf) + offset.value(), hostPtr, hostLen); + memcpy(static_cast(*outBuf) + offset.value(), hostPtr, hostLen); // 52 : session key sec buf (not used) cursor = WriteSecBuf(cursor, 0, 0); @@ -1091,14 +1104,13 @@ static void des_encrypt(const uint8_t *key, const uint8_t *src, uint8_t *hash) { CK_MECHANISM_TYPE cipherMech = CKM_DES_ECB; - PK11SlotInfo *slot = nullptr; PK11SymKey *symkey = nullptr; PK11Context *ctxt = nullptr; SECItem keyItem, *param = nullptr; SECStatus rv; unsigned int n; - - slot = PK11_GetBestSlot(cipherMech, nullptr); + + mozilla::UniquePK11SlotInfo slot(PK11_GetBestSlot(cipherMech, nullptr)); if (!slot) { NS_ERROR("no slot"); @@ -1107,7 +1119,7 @@ des_encrypt(const uint8_t *key, const uint8_t *src, uint8_t *hash) keyItem.data = (uint8_t *) key; keyItem.len = 8; - symkey = PK11_ImportSymKey(slot, cipherMech, + symkey = PK11_ImportSymKey(slot.get(), cipherMech, PK11_OriginUnwrap, CKA_ENCRYPT, &keyItem, nullptr); if (!symkey) @@ -1150,6 +1162,4 @@ done: PK11_FreeSymKey(symkey); if (param) SECITEM_FreeItem(param, true); - if (slot) - PK11_FreeSlot(slot); } diff --git a/security/manager/ssl/nsPK11TokenDB.cpp b/security/manager/ssl/nsPK11TokenDB.cpp index 1190d3ee62..061682804c 100644 --- a/security/manager/ssl/nsPK11TokenDB.cpp +++ b/security/manager/ssl/nsPK11TokenDB.cpp @@ -5,6 +5,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsPK11TokenDB.h" +#include "mozilla/Casting.h" #include "mozilla/unused.h" #include "nsIMutableArray.h" #include "nsISupports.h" @@ -46,7 +47,7 @@ nsPK11Token::refreshTokenInfo(const nsNSSShutDownPreventionLock& /*proofOfLock*/ } // Set the Label field - const char* ccLabel = reinterpret_cast(tokInfo.label); + const char* ccLabel = mozilla::BitwiseCast(tokInfo.label); const nsACString& cLabel = Substring( ccLabel, ccLabel + PL_strnlen(ccLabel, sizeof(tokInfo.label))); @@ -54,7 +55,8 @@ nsPK11Token::refreshTokenInfo(const nsNSSShutDownPreventionLock& /*proofOfLock*/ mTokenLabel.Trim(" ", false, true); // Set the Manufacturer field - const char* ccManID = reinterpret_cast(tokInfo.manufacturerID); + const char* ccManID = + mozilla::BitwiseCast(tokInfo.manufacturerID); const nsACString& cManID = Substring( ccManID, ccManID + PL_strnlen(ccManID, sizeof(tokInfo.manufacturerID))); @@ -72,7 +74,8 @@ nsPK11Token::refreshTokenInfo(const nsNSSShutDownPreventionLock& /*proofOfLock*/ mTokenFWVersion.AppendInt(tokInfo.firmwareVersion.minor); // Set the Serial Number field - const char* ccSerial = reinterpret_cast(tokInfo.serialNumber); + const char* ccSerial = + mozilla::BitwiseCast(tokInfo.serialNumber); const nsACString& cSerial = Substring( ccSerial, ccSerial + PL_strnlen(ccSerial, sizeof(tokInfo.serialNumber))); diff --git a/security/manager/ssl/nsPKCS11Slot.cpp b/security/manager/ssl/nsPKCS11Slot.cpp index a0da2c2239..bced1531f2 100644 --- a/security/manager/ssl/nsPKCS11Slot.cpp +++ b/security/manager/ssl/nsPKCS11Slot.cpp @@ -4,6 +4,7 @@ #include "nsPKCS11Slot.h" +#include "mozilla/Casting.h" #include "mozilla/Logging.h" #include "mozilla/Telemetry.h" #include "mozilla/unused.h" @@ -41,7 +42,8 @@ nsPKCS11Slot::refreshSlotInfo(const nsNSSShutDownPreventionLock& /*proofOfLock*/ } // Set the Description field - const char* ccDesc = reinterpret_cast(slotInfo.slotDescription); + const char* ccDesc = + mozilla::BitwiseCast(slotInfo.slotDescription); const nsACString& cDesc = Substring( ccDesc, ccDesc + PL_strnlen(ccDesc, sizeof(slotInfo.slotDescription))); @@ -49,7 +51,8 @@ nsPKCS11Slot::refreshSlotInfo(const nsNSSShutDownPreventionLock& /*proofOfLock*/ mSlotDesc.Trim(" ", false, true); // Set the Manufacturer field - const char* ccManID = reinterpret_cast(slotInfo.manufacturerID); + const char* ccManID = + mozilla::BitwiseCast(slotInfo.manufacturerID); const nsACString& cManID = Substring( ccManID, ccManID + PL_strnlen(ccManID, sizeof(slotInfo.manufacturerID))); diff --git a/security/manager/ssl/nsPKCS12Blob.cpp b/security/manager/ssl/nsPKCS12Blob.cpp index f856e20866..3273c35ea1 100644 --- a/security/manager/ssl/nsPKCS12Blob.cpp +++ b/security/manager/ssl/nsPKCS12Blob.cpp @@ -5,7 +5,9 @@ #include "nsPKCS12Blob.h" #include "ScopedNSSTypes.h" +#include "mozilla/Casting.h" #include "nsCRT.h" +#include "nsCRTGlue.h" #include "nsDirectoryServiceDefs.h" #include "nsICertificateDialogs.h" #include "nsIDirectoryService.h" @@ -15,7 +17,6 @@ #include "nsNSSCertificate.h" #include "nsNSSComponent.h" #include "nsNSSHelper.h" -#include "nsNSSHelper.h" #include "nsNSSShutDown.h" #include "nsNetUtil.h" #include "nsPK11TokenDB.h" @@ -146,10 +147,10 @@ nsPKCS12Blob::ImportFromFileHelper(nsIFile *file, SEC_PKCS12DecoderContext *dcx = nullptr; SECItem unicodePw; - PK11SlotInfo *slot=nullptr; + UniquePK11SlotInfo slot; nsXPIDLString tokenName; unicodePw.data = nullptr; - + aWantRetry = rr_do_not_retry; if (aImportMode == im_try_zero_length_secitem) @@ -166,11 +167,11 @@ nsPKCS12Blob::ImportFromFileHelper(nsIFile *file, return NS_OK; } } - + mToken->GetTokenName(getter_Copies(tokenName)); { NS_ConvertUTF16toUTF8 tokenNameCString(tokenName); - slot = PK11_FindSlotByName(tokenNameCString.get()); + slot = UniquePK11SlotInfo(PK11_FindSlotByName(tokenNameCString.get())); } if (!slot) { srv = SECFailure; @@ -178,7 +179,7 @@ nsPKCS12Blob::ImportFromFileHelper(nsIFile *file, } // initialize the decoder - dcx = SEC_PKCS12DecoderStart(&unicodePw, slot, nullptr, + dcx = SEC_PKCS12DecoderStart(&unicodePw, slot.get(), nullptr, digest_open, digest_close, digest_read, digest_write, this); @@ -228,11 +229,9 @@ finish: { handleError(PIP_PKCS12_NSS_ERROR); } - } else if (NS_FAILED(rv)) { + } else if (NS_FAILED(rv)) { handleError(PIP_PKCS12_RESTORE_FAILED); } - if (slot) - PK11_FreeSlot(slot); // finish the decoder if (dcx) SEC_PKCS12DecoderFinish(dcx); @@ -413,22 +412,17 @@ finish: // // For the NSS PKCS#12 library, must convert PRUnichars (shorts) to // a buffer of octets. Must handle byte order correctly. -// TODO: Is there a mozilla way to do this? In the string lib? -void +nsresult nsPKCS12Blob::unicodeToItem(const char16_t *uni, SECItem *item) { - int len = 0; - while (uni[len++] != 0); - SECITEM_AllocItem(nullptr, item, sizeof(char16_t) * len); -#ifdef IS_LITTLE_ENDIAN - int i = 0; - for (i=0; idata[2*i ] = (unsigned char )(uni[i] << 8); - item->data[2*i+1] = (unsigned char )(uni[i]); + uint32_t len = NS_strlen(uni) + 1; + if (!SECITEM_AllocItem(nullptr, item, sizeof(char16_t) * len)) { + return NS_ERROR_OUT_OF_MEMORY; } -#else - memcpy(item->data, uni, item->len); -#endif + + mozilla::NativeEndian::copyAndSwapToBigEndian(item->data, uni, len); + + return NS_OK; } // newPKCS12FilePassword @@ -448,8 +442,7 @@ nsPKCS12Blob::newPKCS12FilePassword(SECItem *unicodePw) bool pressedOK; rv = certDialogs->SetPKCS12FilePassword(mUIContext, password, &pressedOK); if (NS_FAILED(rv) || !pressedOK) return rv; - unicodeToItem(password.get(), unicodePw); - return NS_OK; + return unicodeToItem(password.get(), unicodePw); } // getPKCS12FilePassword @@ -469,8 +462,7 @@ nsPKCS12Blob::getPKCS12FilePassword(SECItem *unicodePw) bool pressedOK; rv = certDialogs->GetPKCS12FilePassword(mUIContext, password, &pressedOK); if (NS_FAILED(rv) || !pressedOK) return rv; - unicodeToItem(password.get(), unicodePw); - return NS_OK; + return unicodeToItem(password.get(), unicodePw); } // inputToDecoder @@ -522,9 +514,9 @@ nsPKCS12Blob::inputToDecoder(SEC_PKCS12DecoderContext *dcx, nsIFile *file) SECStatus nsPKCS12Blob::digest_open(void *arg, PRBool reading) { - nsPKCS12Blob *cx = reinterpret_cast(arg); + auto cx = static_cast(arg); NS_ENSURE_TRUE(cx, SECFailure); - + if (reading) { NS_ENSURE_TRUE(cx->mDigest, SECFailure); @@ -557,17 +549,17 @@ nsPKCS12Blob::digest_open(void *arg, PRBool reading) SECStatus nsPKCS12Blob::digest_close(void *arg, PRBool remove_it) { - nsPKCS12Blob *cx = reinterpret_cast(arg); + auto cx = static_cast(arg); NS_ENSURE_TRUE(cx, SECFailure); delete cx->mDigestIterator; cx->mDigestIterator = nullptr; - if (remove_it) { + if (remove_it) { delete cx->mDigest; cx->mDigest = nullptr; } - + return SECSuccess; } @@ -576,7 +568,7 @@ nsPKCS12Blob::digest_close(void *arg, PRBool remove_it) int nsPKCS12Blob::digest_read(void *arg, unsigned char *buf, unsigned long len) { - nsPKCS12Blob *cx = reinterpret_cast(arg); + auto cx = static_cast(arg); NS_ENSURE_TRUE(cx, SECFailure); NS_ENSURE_TRUE(cx->mDigest, SECFailure); @@ -584,13 +576,13 @@ nsPKCS12Blob::digest_read(void *arg, unsigned char *buf, unsigned long len) NS_ENSURE_TRUE(cx->mDigestIterator, SECFailure); unsigned long available = cx->mDigestIterator->size_forward(); - + if (len > available) len = available; memcpy(buf, cx->mDigestIterator->get(), len); cx->mDigestIterator->advance(len); - + return len; } @@ -599,16 +591,16 @@ nsPKCS12Blob::digest_read(void *arg, unsigned char *buf, unsigned long len) int nsPKCS12Blob::digest_write(void *arg, unsigned char *buf, unsigned long len) { - nsPKCS12Blob *cx = reinterpret_cast(arg); + auto cx = static_cast(arg); NS_ENSURE_TRUE(cx, SECFailure); NS_ENSURE_TRUE(cx->mDigest, SECFailure); // make sure we are in write mode, read iterator has not yet been allocated NS_ENSURE_FALSE(cx->mDigestIterator, SECFailure); - - cx->mDigest->Append(reinterpret_cast(buf), - static_cast(len)); - + + cx->mDigest->Append(BitwiseCast(buf), + static_cast(len)); + return len; } @@ -654,10 +646,9 @@ nsPKCS12Blob::nickname_collision(SECItem *oldNick, PRBool *cancel, void *wincx) // without a corresponding cert. // XXX If a user imports *many* certs without the 'friendly name' // attribute, then this may take a long time. :( + nickname = nickFromPropC; if (count > 1) { - nickname.Adopt(PR_smprintf("%s #%d", nickFromPropC.get(), count)); - } else { - nickname = nickFromPropC; + nickname.AppendPrintf(" #%d", count); } CERTCertificate *cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), const_cast(nickname.get())); diff --git a/security/manager/ssl/nsPKCS12Blob.h b/security/manager/ssl/nsPKCS12Blob.h index 58eca08b20..d717a328a1 100644 --- a/security/manager/ssl/nsPKCS12Blob.h +++ b/security/manager/ssl/nsPKCS12Blob.h @@ -54,7 +54,7 @@ private: nsresult getPKCS12FilePassword(SECItem *); nsresult newPKCS12FilePassword(SECItem *); nsresult inputToDecoder(SEC_PKCS12DecoderContext *, nsIFile *); - void unicodeToItem(const char16_t *, SECItem *); + nsresult unicodeToItem(const char16_t *, SECItem *); void handleError(int myerr = 0); // RetryReason and ImportMode are used when importing a PKCS12 file. diff --git a/security/manager/ssl/nsRandomGenerator.cpp b/security/manager/ssl/nsRandomGenerator.cpp index 3672924515..ceda7fbd77 100644 --- a/security/manager/ssl/nsRandomGenerator.cpp +++ b/security/manager/ssl/nsRandomGenerator.cpp @@ -4,6 +4,7 @@ #include "nsRandomGenerator.h" +#include "ScopedNSSTypes.h" #include "nsNSSComponent.h" #include "pk11pub.h" #include "prerror.h" @@ -23,7 +24,7 @@ nsRandomGenerator::GenerateRandomBytes(uint32_t aLength, return NS_ERROR_NOT_AVAILABLE; } - mozilla::ScopedPK11SlotInfo slot(PK11_GetInternalSlot()); + mozilla::UniquePK11SlotInfo slot(PK11_GetInternalSlot()); if (!slot) { return NS_ERROR_FAILURE; } @@ -33,8 +34,7 @@ nsRandomGenerator::GenerateRandomBytes(uint32_t aLength, return NS_ERROR_OUT_OF_MEMORY; } - SECStatus srv = PK11_GenerateRandomOnSlot(slot, buf, aLength); - + SECStatus srv = PK11_GenerateRandomOnSlot(slot.get(), buf, aLength); if (srv != SECSuccess) { NS_Free(buf); return NS_ERROR_FAILURE; diff --git a/security/manager/ssl/nsSiteSecurityService.cpp b/security/manager/ssl/nsSiteSecurityService.cpp index f9282c6812..b1088ed06f 100644 --- a/security/manager/ssl/nsSiteSecurityService.cpp +++ b/security/manager/ssl/nsSiteSecurityService.cpp @@ -706,7 +706,7 @@ nsSiteSecurityService::ProcessPKPHeader(nsIURI* aSourceURI, NS_ENSURE_TRUE(nssCert, NS_ERROR_FAILURE); mozilla::pkix::Time now(mozilla::pkix::Now()); - ScopedCERTCertList certList; + UniqueCERTCertList certList; RefPtr certVerifier(GetDefaultCertVerifier()); NS_ENSURE_TRUE(certVerifier, NS_ERROR_UNEXPECTED); if (certVerifier->VerifySSLServerCert(nssCert, nullptr, // stapled ocsp diff --git a/security/manager/ssl/nsSmartCardMonitor.cpp b/security/manager/ssl/nsSmartCardMonitor.cpp index da13f289b5..ace537dd05 100644 --- a/security/manager/ssl/nsSmartCardMonitor.cpp +++ b/security/manager/ssl/nsSmartCardMonitor.cpp @@ -1,14 +1,16 @@ /* 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 "nspr.h" +#include "nsSmartCardMonitor.h" + +#include "ScopedNSSTypes.h" #include "mozilla/Services.h" #include "mozilla/unused.h" #include "nsIObserverService.h" #include "nsServiceManagerUtils.h" -#include "nsSmartCardMonitor.h" #include "nsThreadUtils.h" +#include "nspr.h" #include "pk11func.h" using namespace mozilla; @@ -318,7 +320,6 @@ SmartCardMonitoringThread::SendEvent(const nsAString& eventType, // void SmartCardMonitoringThread::Execute() { - PK11SlotInfo* slot; const char* tokenName; // @@ -339,17 +340,18 @@ void SmartCardMonitoringThread::Execute() // loop starts.. do { - slot = SECMOD_WaitForAnyTokenEvent(mModule, 0, PR_SecondsToInterval(1)); + UniquePK11SlotInfo slot( + SECMOD_WaitForAnyTokenEvent(mModule, 0, PR_SecondsToInterval(1))); if (!slot) { break; } // now we have a potential insertion or removal event, see if the slot // is present to determine which it is... - if (PK11_IsPresent(slot)) { + if (PK11_IsPresent(slot.get())) { // insertion - CK_SLOT_ID slotID = PK11_GetSlotID(slot); - uint32_t series = PK11_GetSlotSeries(slot); + CK_SLOT_ID slotID = PK11_GetSlotID(slot.get()); + uint32_t series = PK11_GetSlotSeries(slot.get()); // skip spurious insertion events... if (series != GetTokenSeries(slotID)) { @@ -359,14 +361,14 @@ void SmartCardMonitoringThread::Execute() if (tokenName) { SendEvent(NS_LITERAL_STRING("smartcard-remove"), tokenName); } - tokenName = PK11_GetTokenName(slot); + tokenName = PK11_GetTokenName(slot.get()); // save the token name and series SetTokenName(slotID, tokenName, series); SendEvent(NS_LITERAL_STRING("smartcard-insert"), tokenName); } } else { // retrieve token name - CK_SLOT_ID slotID = PK11_GetSlotID(slot); + CK_SLOT_ID slotID = PK11_GetSlotID(slot.get()); tokenName = GetTokenName(slotID); // if there's not a token name, then the software isn't expecting // a (or another) remove event. @@ -376,8 +378,6 @@ void SmartCardMonitoringThread::Execute() SetTokenName(slotID, nullptr, 0); } } - PK11_FreeSlot(slot); - } while (1); } diff --git a/security/manager/ssl/nsUsageArrayHelper.cpp b/security/manager/ssl/nsUsageArrayHelper.cpp index 5576065021..124303ceaf 100644 --- a/security/manager/ssl/nsUsageArrayHelper.cpp +++ b/security/manager/ssl/nsUsageArrayHelper.cpp @@ -4,6 +4,7 @@ #include "nsUsageArrayHelper.h" +#include "ScopedNSSTypes.h" #include "mozilla/Assertions.h" #include "nsCOMPtr.h" #include "nsComponentManagerUtils.h" @@ -103,7 +104,7 @@ nsUsageArrayHelper::check(uint32_t previousCheckResult, MOZ_CRASH("unknown cert usage passed to check()"); } - ScopedCERTCertList unusedBuiltChain; + UniqueCERTCertList unusedBuiltChain; SECStatus rv = certVerifier->VerifyCert(mCert, aCertUsage, time, nullptr /*XXX:wincx*/, nullptr /*hostname*/, diff --git a/security/manager/ssl/tests/compiled/TestMD4.cpp b/security/manager/ssl/tests/compiled/TestMD4.cpp index 8c82cc8adb..69d4bd83aa 100644 --- a/security/manager/ssl/tests/compiled/TestMD4.cpp +++ b/security/manager/ssl/tests/compiled/TestMD4.cpp @@ -6,6 +6,7 @@ #include "TestHarness.h" #include "md4.h" +#include "mozilla/Casting.h" // The md4 implementation isn't built as a separate library. This is the easiest // way to expose the symbols necessary to test the implementation. @@ -52,7 +53,8 @@ TestMD4() for (size_t i = 0; i < MOZ_ARRAY_LENGTH(rfc1320_test_values); i++) { uint8_t md4_result[16]; - md4sum(reinterpret_cast(rfc1320_test_values[i].data), + md4sum(mozilla::BitwiseCast( + rfc1320_test_values[i].data), strlen(rfc1320_test_values[i].data), md4_result); if (memcmp(md4_result, rfc1320_test_values[i].md4, 16) != 0) { fail("MD4 comparison test value #%d from RFC1320 failed", i + 1); diff --git a/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp b/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp index c524b185b7..5adad52b6c 100644 --- a/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp +++ b/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp @@ -7,6 +7,7 @@ #include "CertVerifier.h" #include "OCSPCache.h" #include "gtest/gtest.h" +#include "mozilla/Casting.h" #include "mozilla/Snprintf.h" #include "nss.h" #include "pkix/pkixtypes.h" @@ -22,6 +23,9 @@ template inline Input LiteralInput(const char(&valueString)[N]) { + // Ideally we would use mozilla::BitwiseCast() here rather than + // reinterpret_cast for better type checking, but the |N - 1| part trips + // static asserts. return Input(reinterpret_cast(valueString)); } @@ -85,7 +89,8 @@ TEST_F(OCSPCacheTest, TestVariousGets) SCOPED_TRACE(""); for (int i = 0; i < MaxCacheEntries; i++) { uint8_t serialBuf[8]; - snprintf(reinterpret_cast(serialBuf), sizeof(serialBuf), "%04d", i); + snprintf(mozilla::BitwiseCast(serialBuf), sizeof(serialBuf), + "%04d", i); Input fakeSerial; ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4)); Time timeIn(now); @@ -134,7 +139,8 @@ TEST_F(OCSPCacheTest, TestEviction) // we cause the least recently used entry to be evicted. for (int i = 0; i < MaxCacheEntries + 1; i++) { uint8_t serialBuf[8]; - snprintf(reinterpret_cast(serialBuf), sizeof(serialBuf), "%04d", i); + snprintf(mozilla::BitwiseCast(serialBuf), sizeof(serialBuf), + "%04d", i); Input fakeSerial; ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4)); Time timeIn(now); @@ -159,7 +165,8 @@ TEST_F(OCSPCacheTest, TestNoEvictionForRevokedResponses) // we cause the least recently used entry that isn't revoked to be evicted. for (int i = 1; i < MaxCacheEntries + 1; i++) { uint8_t serialBuf[8]; - snprintf(reinterpret_cast(serialBuf), sizeof(serialBuf), "%04d", i); + snprintf(mozilla::BitwiseCast(serialBuf), sizeof(serialBuf), + "%04d", i); Input fakeSerial; ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4)); Time timeIn(now); @@ -185,7 +192,8 @@ TEST_F(OCSPCacheTest, TestEverythingIsRevoked) // Fill up the cache with revoked responses. for (int i = 0; i < MaxCacheEntries; i++) { uint8_t serialBuf[8]; - snprintf(reinterpret_cast(serialBuf), sizeof(serialBuf), "%04d", i); + snprintf(mozilla::BitwiseCast(serialBuf), sizeof(serialBuf), + "%04d", i); Input fakeSerial; ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4)); Time timeIn(now); diff --git a/security/manager/ssl/tests/unit/test_certDB_import/cert_from_windows.pfx b/security/manager/ssl/tests/unit/test_certDB_import/cert_from_windows.pfx new file mode 100644 index 0000000000..e969d672d7 Binary files /dev/null and b/security/manager/ssl/tests/unit/test_certDB_import/cert_from_windows.pfx differ diff --git a/security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js b/security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js new file mode 100644 index 0000000000..56e17855a2 --- /dev/null +++ b/security/manager/ssl/tests/unit/test_certDB_import_pkcs12.js @@ -0,0 +1,92 @@ +// -*- indent-tabs-mode: nil; js-indent-level: 2 -*- +// Any copyright is dedicated to the Public Domain. +// http://creativecommons.org/publicdomain/zero/1.0/ +"use strict"; + +// Tests import PKCS12 file by nsIX509CertDB. + +do_get_profile(); + +const gCertDB = Cc["@mozilla.org/security/x509certdb;1"] + .getService(Ci.nsIX509CertDB); + +const CERT_COMMON_NAME = "test_cert_from_windows"; +const TEST_CERT_PASSWORD = "黒い"; + +let gGetPKCS12Password = false; + +// Mock implementation of nsICertificateDialogs. +const gCertificateDialogs = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsICertificateDialogs]), + + getPKCS12FilePassword: (ctx, password) => { + ok(!gGetPKCS12Password, + "getPKCS12FilePassword should be called only once."); + + password.value = TEST_CERT_PASSWORD; + do_print("getPKCS12FilePassword() is called"); + gGetPKCS12Password = true; + return true; + }, +}; + +const gPrompt = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIPrompt]), + alert: (title, text) => { + do_print("alert('" + text + "')"); + }, +}; + +const gPromptFactory = { + QueryInterface: XPCOMUtils.generateQI([Ci.nsIPromptFactory]), + getPrompt: (aWindow, aIID) => gPrompt, +}; + +function doesCertExist(commonName) { + let allCerts = gCertDB.getCerts(); + let enumerator = allCerts.getEnumerator(); + while (enumerator.hasMoreElements()) { + let cert = enumerator.getNext().QueryInterface(Ci.nsIX509Cert); + if (cert.isBuiltInRoot) { + continue; + } + if (cert.commonName == commonName) { + return true; + } + } + + return false; +} + +function testImportPKCS12Cert() { + ok(!doesCertExist(CERT_COMMON_NAME), + "Cert should not be in the database before import"); + + // Import and check for success. + let certFile = do_get_file("test_certDB_import/cert_from_windows.pfx"); + gCertDB.importPKCS12File(null, certFile); + + ok(gGetPKCS12Password, "PKCS12 password should be asked"); + + ok(doesCertExist(CERT_COMMON_NAME), + "Cert should now be found in the database"); +} + +function run_test() { + // We have to set a password and login before we attempt to import anything. + loginToDBWithDefaultPassword(); + + let certificateDialogsCID = + MockRegistrar.register("@mozilla.org/nsCertificateDialogs;1", + gCertificateDialogs); + let promptFactoryCID = + MockRegistrar.register("@mozilla.org/prompter;1", gPromptFactory); + + do_register_cleanup(() => { + MockRegistrar.unregister(certificateDialogsCID); + MockRegistrar.unregister(promptFactoryCID); + }); + + // Import PKCS12 file with utf-8 password + testImportPKCS12Cert(); +} diff --git a/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.cpp b/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.cpp index 5816eed38e..1701e54ddb 100644 --- a/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.cpp +++ b/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.cpp @@ -8,7 +8,6 @@ #include #include -#include "ScopedNSSTypes.h" #include "base64.h" #include "mozilla/Move.h" #include "mozilla/Snprintf.h" @@ -130,7 +129,7 @@ AddKeyFromFile(const char* basePath, const char* filename) unsigned int binLength; UniquePORTString bin( - reinterpret_cast(ATOB_AsciiToData(base64, &binLength))); + BitwiseCast(ATOB_AsciiToData(base64, &binLength))); if (!bin || binLength == 0) { PrintPRError("ATOB_AsciiToData failed"); return SECFailure; @@ -141,21 +140,21 @@ AddKeyFromFile(const char* basePath, const char* filename) return SECFailure; } PORT_Memcpy(secitem->data, bin.get(), binLength); - ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); if (!slot) { PrintPRError("PK11_GetInternalKeySlot failed"); return SECFailure; } - if (PK11_NeedUserInit(slot)) { - if (PK11_InitPin(slot, nullptr, nullptr) != SECSuccess) { + if (PK11_NeedUserInit(slot.get())) { + if (PK11_InitPin(slot.get(), nullptr, nullptr) != SECSuccess) { PrintPRError("PK11_InitPin failed"); return SECFailure; } } SECKEYPrivateKey* privateKey; - if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot, secitem, nullptr, nullptr, - true, false, KU_ALL, - &privateKey, nullptr) + if (PK11_ImportDERPrivateKeyInfoAndReturnKey(slot.get(), secitem.get(), + nullptr, nullptr, true, false, + KU_ALL, &privateKey, nullptr) != SECSuccess) { PrintPRError("PK11_ImportDERPrivateKeyInfoAndReturnKey failed"); return SECFailure; @@ -198,7 +197,7 @@ AddCertificateFromFile(const char* basePath, const char* filename) PrintPRError("CERT_NewTempCertificate failed"); return SECFailure; } - ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); if (!slot) { PrintPRError("PK11_GetInternalKeySlot failed"); return SECFailure; @@ -448,7 +447,7 @@ ConfigSecureServerWithNamedCert(PRFileDesc* fd, const char* certName, certList->arena = arena.release(); // We also have to manually copy the certificates we care about to the // list, because there aren't any utility functions for that either. - certList->certs = reinterpret_cast( + certList->certs = static_cast( PORT_ArenaAlloc(certList->arena, 2 * sizeof(SECItem))); if (SECITEM_CopyItem(certList->arena, certList->certs, &cert->derCert) != SECSuccess) { @@ -463,7 +462,11 @@ ConfigSecureServerWithNamedCert(PRFileDesc* fd, const char* certName, certList->len = 2; } - ScopedPK11SlotInfo slot(PK11_GetInternalKeySlot()); + UniquePK11SlotInfo slot(PK11_GetInternalKeySlot()); + if (!slot) { + PrintPRError("PK11_GetInternalKeySlot failed"); + return SECFailure; + } UniqueSECKEYPrivateKey key( PK11_FindKeyByDERCert(slot.get(), cert.get(), nullptr)); if (!key) { diff --git a/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.h b/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.h index eff86ca38b..f1dc1569a2 100644 --- a/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.h +++ b/security/manager/ssl/tests/unit/tlsserver/lib/TLSServer.h @@ -14,8 +14,10 @@ // it will connect to a specified port and issue a simple HTTP request. #include -#include "prio.h" + #include "ScopedNSSTypes.h" +#include "mozilla/Casting.h" +#include "prio.h" #include "secerr.h" #include "ssl.h" @@ -63,7 +65,7 @@ GetHostForSNI(const SECItem *aSrvNameArr, uint32_t aSrvNameArrSize, for (uint32_t i = 0; i < aSrvNameArrSize; i++) { for (const Host *host = hosts; host->mHostName; ++host) { SECItem hostName; - hostName.data = reinterpret_cast(const_cast(host->mHostName)); + hostName.data = BitwiseCast(host->mHostName); hostName.len = strlen(host->mHostName); if (SECITEM_ItemsAreEqual(&hostName, &aSrvNameArr[i])) { if (gDebugLevel >= DEBUG_VERBOSE) { diff --git a/security/manager/ssl/tests/unit/xpcshell.ini b/security/manager/ssl/tests/unit/xpcshell.ini index 7e697d3931..76856729e9 100644 --- a/security/manager/ssl/tests/unit/xpcshell.ini +++ b/security/manager/ssl/tests/unit/xpcshell.ini @@ -72,6 +72,7 @@ run-sequentially = hardcoded ports [test_cert_trust.js] [test_cert_version.js] [test_certDB_import.js] +[test_certDB_import_pkcs12.js] [test_certviewer_invalid_oids.js] skip-if = toolkit == 'android' || buildapp == 'b2g' [test_constructX509FromBase64.js] diff --git a/storage/mozStorageConnection.cpp b/storage/mozStorageConnection.cpp index 64825f11ff..95ff936436 100644 --- a/storage/mozStorageConnection.cpp +++ b/storage/mozStorageConnection.cpp @@ -367,7 +367,7 @@ public: MOZ_ASSERT(onAsyncThread); #endif // DEBUG - nsCOMPtr event = NS_NewRunnableMethodWithArg> + nsCOMPtr event = NewRunnableMethod> (mConnection, &Connection::shutdownAsyncThread, mAsyncExecutionThread); (void)NS_DispatchToMainThread(event); diff --git a/storage/mozStorageService.cpp b/storage/mozStorageService.cpp index ee38a096d6..7ba2e4ad10 100644 --- a/storage/mozStorageService.cpp +++ b/storage/mozStorageService.cpp @@ -383,7 +383,7 @@ Service::minimizeMemory() // We are on the wrong thread, the query should be executed on the // opener thread, so we must dispatch to it. nsCOMPtr event = - NS_NewRunnableMethodWithArg( + NewRunnableMethod( conn, &Connection::ExecuteSimpleSQL, shrinkPragma); conn->threadOpenedOn->Dispatch(event, NS_DISPATCH_NORMAL); } @@ -702,7 +702,7 @@ public: : mConnection->initialize(); if (NS_FAILED(rv)) { nsCOMPtr closeRunnable = - NS_NewRunnableMethodWithArg( + NewRunnableMethod( mConnection.get(), &Connection::AsyncClose, nullptr); diff --git a/testing/web-platform/meta/MANIFEST.json b/testing/web-platform/meta/MANIFEST.json index 3f57a399e8..55b29d4336 100644 --- a/testing/web-platform/meta/MANIFEST.json +++ b/testing/web-platform/meta/MANIFEST.json @@ -22447,6 +22447,12 @@ "url": "/XMLHttpRequest/open-url-multi-window-6.htm" } ], + "html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html": [ + { + "path": "html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html", + "url": "/html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html" + } + ], "html/semantics/document-metadata/the-base-element/base_about_blank.html": [ { "path": "html/semantics/document-metadata/the-base-element/base_about_blank.html", diff --git a/testing/web-platform/tests/html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html b/testing/web-platform/tests/html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html new file mode 100644 index 0000000000..f72ed1eaf2 --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-location-interface/allow_prototype_cycle_through_location.sub.html @@ -0,0 +1,197 @@ + + + + + + Location objects' custom [[GetPrototypeOf]] trap permit [[Prototype]] chain cycles to be created through them + + + + + + + + + +
+ +
+ + + + + + + diff --git a/testing/web-platform/tests/html/browsers/history/the-location-interface/cross_origin_joined_frame.sub.html b/testing/web-platform/tests/html/browsers/history/the-location-interface/cross_origin_joined_frame.sub.html new file mode 100644 index 0000000000..a3ffdd005a --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-location-interface/cross_origin_joined_frame.sub.html @@ -0,0 +1,15 @@ + + + + + Cross-origin subframe for Location cyclic [[Prototype]] test + + + + + +

Cross-origin iframe with joined document.domain

+ + diff --git a/testing/web-platform/tests/html/browsers/history/the-location-interface/same_origin_frame.html b/testing/web-platform/tests/html/browsers/history/the-location-interface/same_origin_frame.html new file mode 100644 index 0000000000..953e696b2a --- /dev/null +++ b/testing/web-platform/tests/html/browsers/history/the-location-interface/same_origin_frame.html @@ -0,0 +1,12 @@ + + + + + Same-origin subframe for Location cyclic [[Prototype]] test + + + + +

Same-origin iframe

+ + diff --git a/toolkit/components/filewatcher/NativeFileWatcherWin.cpp b/toolkit/components/filewatcher/NativeFileWatcherWin.cpp index ac9a7654d0..21385b03bf 100644 --- a/toolkit/components/filewatcher/NativeFileWatcherWin.cpp +++ b/toolkit/components/filewatcher/NativeFileWatcherWin.cpp @@ -1311,7 +1311,7 @@ NativeFileWatcherService::AddPath(const nsAString& aPathToWatch, nsMainThreadPtrHandle successCallbackHandle( new nsMainThreadPtrHolder(aOnSuccess)); - // Wrap the path and the callbacks in order to pass them using NS_NewRunnableMethodWithArg. + // Wrap the path and the callbacks in order to pass them using NewRunnableMethod. UniquePtr wrappedCallbacks( new PathRunnablesParametersWrapper( aPathToWatch, @@ -1322,7 +1322,7 @@ NativeFileWatcherService::AddPath(const nsAString& aPathToWatch, // Since this function does a bit of I/O stuff , run it in the IO thread. nsresult rv = mIOThread->Dispatch( - NS_NewRunnableMethodWithArg( + NewRunnableMethod( static_cast(mWorkerIORunnable.get()), &NativeFileWatcherIOTask::AddPathRunnableMethod, wrappedCallbacks.get()), @@ -1381,7 +1381,7 @@ NativeFileWatcherService::RemovePath(const nsAString& aPathToRemove, nsMainThreadPtrHandle successCallbackHandle( new nsMainThreadPtrHolder(aOnSuccess)); - // Wrap the path and the callbacks in order to pass them using NS_NewRunnableMethodWithArg. + // Wrap the path and the callbacks in order to pass them using NewRunnableMethod. UniquePtr wrappedCallbacks( new PathRunnablesParametersWrapper( aPathToRemove, @@ -1392,7 +1392,7 @@ NativeFileWatcherService::RemovePath(const nsAString& aPathToRemove, // Since this function does a bit of I/O stuff, run it in the IO thread. nsresult rv = mIOThread->Dispatch( - NS_NewRunnableMethodWithArg( + NewRunnableMethod( static_cast(mWorkerIORunnable.get()), &NativeFileWatcherIOTask::RemovePathRunnableMethod, wrappedCallbacks.get()), @@ -1441,7 +1441,7 @@ NativeFileWatcherService::Uninit() // in the IO thread. nsresult rv = ioThread->Dispatch( - NS_NewRunnableMethod( + NewRunnableMethod( static_cast(mWorkerIORunnable.get()), &NativeFileWatcherIOTask::DeactivateRunnableMethod), nsIEventTarget::DISPATCH_NORMAL); diff --git a/toolkit/components/places/History.cpp b/toolkit/components/places/History.cpp index a3c2f77acf..73c3309721 100644 --- a/toolkit/components/places/History.cpp +++ b/toolkit/components/places/History.cpp @@ -504,9 +504,7 @@ public: RefPtr cb = new VisitedQuery(aURI, callback, true); NS_ENSURE_TRUE(cb, NS_ERROR_OUT_OF_MEMORY); // As per IHistory contract, we must notify asynchronously. - nsCOMPtr event = - NS_NewRunnableMethod(cb, &VisitedQuery::NotifyVisitedStatus); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(NewRunnableMethod(cb, &VisitedQuery::NotifyVisitedStatus)); return NS_OK; } diff --git a/toolkit/components/satchel/nsFormFillController.cpp b/toolkit/components/satchel/nsFormFillController.cpp index 7fd8f6a6a2..f68c17eb04 100644 --- a/toolkit/components/satchel/nsFormFillController.cpp +++ b/toolkit/components/satchel/nsFormFillController.cpp @@ -119,7 +119,7 @@ nsFormFillController::AttributeChanged(nsIDocument* aDocument, // to avoid ending up in an endless loop due to re-registering our // mutation observer (which would notify us again for *this* event). nsCOMPtr event = - NS_NewRunnableMethodWithArg> + mozilla::NewRunnableMethod> (this, &nsFormFillController::MaybeStartControllingInput, focusedInput); NS_DispatchToCurrentThread(event); } diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index 46a6876c7e..b5d4012f67 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -1748,7 +1748,7 @@ public: ReadLastShutdownDuration(mShutdownTimeFilename); mTelemetry->ReadLateWritesStacks(mProfileDir); nsCOMPtr e = - NS_NewRunnableMethod(this, &nsFetchTelemetryData::MainThread); + NewRunnableMethod(this, &nsFetchTelemetryData::MainThread); NS_ENSURE_STATE(e); NS_DispatchToMainThread(e); return NS_OK; diff --git a/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp b/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp index 96fdfea720..f0be4f2000 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierProxies.cpp @@ -9,6 +9,7 @@ #include "mozilla/SyncRunnable.h" using namespace mozilla::safebrowsing; +using mozilla::NewRunnableMethod; static nsresult DispatchToWorkerThread(nsIRunnable* r) @@ -113,8 +114,8 @@ NS_IMETHODIMP UrlClassifierDBServiceWorkerProxy::FinishStream() { nsCOMPtr r = - NS_NewRunnableMethod(mTarget, - &nsIUrlClassifierDBServiceWorker::FinishStream); + NewRunnableMethod(mTarget, + &nsIUrlClassifierDBServiceWorker::FinishStream); return DispatchToWorkerThread(r); } @@ -147,8 +148,8 @@ NS_IMETHODIMP UrlClassifierDBServiceWorkerProxy::FinishUpdate() { nsCOMPtr r = - NS_NewRunnableMethod(mTarget, - &nsIUrlClassifierDBServiceWorker::FinishUpdate); + NewRunnableMethod(mTarget, + &nsIUrlClassifierDBServiceWorker::FinishUpdate); return DispatchToWorkerThread(r); } @@ -156,8 +157,8 @@ NS_IMETHODIMP UrlClassifierDBServiceWorkerProxy::CancelUpdate() { nsCOMPtr r = - NS_NewRunnableMethod(mTarget, - &nsIUrlClassifierDBServiceWorker::CancelUpdate); + NewRunnableMethod(mTarget, + &nsIUrlClassifierDBServiceWorker::CancelUpdate); return DispatchToWorkerThread(r); } @@ -165,8 +166,8 @@ NS_IMETHODIMP UrlClassifierDBServiceWorkerProxy::ResetDatabase() { nsCOMPtr r = - NS_NewRunnableMethod(mTarget, - &nsIUrlClassifierDBServiceWorker::ResetDatabase); + NewRunnableMethod(mTarget, + &nsIUrlClassifierDBServiceWorker::ResetDatabase); return DispatchToWorkerThread(r); } @@ -174,8 +175,8 @@ NS_IMETHODIMP UrlClassifierDBServiceWorkerProxy::OpenDb() { nsCOMPtr r = - NS_NewRunnableMethod(mTarget, - &nsIUrlClassifierDBServiceWorker::OpenDb); + NewRunnableMethod(mTarget, + &nsIUrlClassifierDBServiceWorker::OpenDb); return DispatchToWorkerThread(r); } @@ -183,8 +184,8 @@ NS_IMETHODIMP UrlClassifierDBServiceWorkerProxy::CloseDb() { nsCOMPtr r = - NS_NewRunnableMethod(mTarget, - &nsIUrlClassifierDBServiceWorker::CloseDb); + NewRunnableMethod(mTarget, + &nsIUrlClassifierDBServiceWorker::CloseDb); return DispatchToWorkerThread(r); } diff --git a/toolkit/content/tests/browser/browser_mediaPlayback_suspended.js b/toolkit/content/tests/browser/browser_mediaPlayback_suspended.js new file mode 100644 index 0000000000..6e659fe73b --- /dev/null +++ b/toolkit/content/tests/browser/browser_mediaPlayback_suspended.js @@ -0,0 +1,164 @@ +const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_mediaPlayback2.html"; + +var SuspendedType = { + NONE_SUSPENDED : 0, + SUSPENDED_PAUSE : 1, + SUSPENDED_BLOCK : 2, + SUSPENDED_PAUSE_DISPOSABLE : 3 +}; + +function wait_for_event(browser, event) { + return BrowserTestUtils.waitForEvent(browser, event, false, (event) => { + is(event.originalTarget, browser, "Event must be dispatched to correct browser."); + return true; + }); +} + +function check_audio_suspended(suspendedType) { + var list = content.document.getElementsByTagName('audio'); + if (list.length != 1) { + ok(false, "There should be only one audio element in page!") + } + + var audio = list[0]; + is(audio.computedSuspended, suspendedType, + "The suspended state of MediaElement is correct."); +} + +function check_audio_pause_state(expectedPauseState) { + var list = content.document.getElementsByTagName('audio'); + if (list.length != 1) { + ok(false, "There should be only one audio element in page!") + } + + var audio = list[0]; + if (expectedPauseState) { + is(audio.paused, true, "Audio is paused correctly."); + } else { + is(audio.paused, false, "Audio is resumed correctly."); + } +} + +function* suspended_pause(url, browser) { + info("### Start test for suspended-pause ###"); + browser.loadURI(url); + + info("- page should have playing audio -"); + yield wait_for_event(browser, "DOMAudioPlaybackStarted"); + + info("- the suspended state of audio should be non-suspened -"); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_audio_suspended); + + info("- pause playing audio -"); + browser.pauseMedia(false /* non-disposable */); + yield ContentTask.spawn(browser, true /* expect for pause */, + check_audio_pause_state); + yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE, + check_audio_suspended); + + info("- resume paused audio -"); + browser.resumeMedia(); + yield ContentTask.spawn(browser, false /* expect for playing */, + check_audio_pause_state); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_audio_suspended); +} + +function* suspended_pause_disposable(url, browser) { + info("### Start test for suspended-pause-disposable ###"); + browser.loadURI(url); + + info("- page should have playing audio -"); + yield wait_for_event(browser, "DOMAudioPlaybackStarted"); + + info("- the suspended state of audio should be non-suspened -"); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_audio_suspended); + + info("- pause playing audio -"); + browser.pauseMedia(true /* disposable */); + yield ContentTask.spawn(browser, true /* expect for pause */, + check_audio_pause_state); + yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE_DISPOSABLE, + check_audio_suspended); + + info("- resume paused audio -"); + browser.resumeMedia(); + yield ContentTask.spawn(browser, false /* expect for playing */, + check_audio_pause_state); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_audio_suspended); +} + +function* suspended_stop_disposable(url, browser) { + info("### Start test for suspended-stop-disposable ###"); + browser.loadURI(url); + + info("- page should have playing audio -"); + yield wait_for_event(browser, "DOMAudioPlaybackStarted"); + + info("- the suspended state of audio should be non-suspened -"); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_audio_suspended); + + info("- stop playing audio -"); + browser.stopMedia(); + yield wait_for_event(browser, "DOMAudioPlaybackStopped"); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_audio_suspended); +} + +function* suspended_block(url, browser) { + info("### Start test for suspended-block ###"); + browser.loadURI(url); + + info("- page should have playing audio -"); + yield wait_for_event(browser, "DOMAudioPlaybackStarted"); + + info("- block playing audio -"); + browser.blockMedia(); + yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_BLOCK, + check_audio_suspended); + + info("- resume blocked audio -"); + browser.resumeMedia(); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_audio_suspended); +} + +add_task(function* setup_test_preference() { + yield new Promise(resolve => { + SpecialPowers.pushPrefEnv({"set": [ + ["media.useAudioChannelService.testing", true] + ]}, resolve); + }); +}); + +add_task(function* test_suspended_pause() { + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: "about:blank" + }, suspended_pause.bind(this, PAGE)); +}); + +add_task(function* test_suspended_pause_disposable() { + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: "about:blank" + }, suspended_pause_disposable.bind(this, PAGE)); +}); + +add_task(function* test_suspended_stop_disposable() { + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: "about:blank" + }, suspended_stop_disposable.bind(this, PAGE)); +}); + +add_task(function* test_suspended_block() { + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: "about:blank" + }, suspended_block.bind(this, PAGE)); +}); diff --git a/toolkit/content/tests/browser/browser_mediaPlayback_suspended_multipleAudio.js b/toolkit/content/tests/browser/browser_mediaPlayback_suspended_multipleAudio.js new file mode 100644 index 0000000000..9da63b385f --- /dev/null +++ b/toolkit/content/tests/browser/browser_mediaPlayback_suspended_multipleAudio.js @@ -0,0 +1,305 @@ +const PAGE = "https://example.com/browser/toolkit/content/tests/browser/file_multipleAudio.html"; + +var SuspendedType = { + NONE_SUSPENDED : 0, + SUSPENDED_PAUSE : 1, + SUSPENDED_BLOCK : 2, + SUSPENDED_PAUSE_DISPOSABLE : 3 +}; + +function wait_for_event(browser, event) { + return BrowserTestUtils.waitForEvent(browser, event, false, (event) => { + is(event.originalTarget, browser, "Event must be dispatched to correct browser."); + return true; + }); +} + +function check_all_audio_suspended(suspendedType) { + var autoPlay = content.document.getElementById('autoplay'); + var nonAutoPlay = content.document.getElementById('nonautoplay'); + if (!autoPlay || !nonAutoPlay) { + ok(false, "Can't get the audio element!"); + } + + is(autoPlay.computedSuspended, suspendedType, + "The suspeded state of autoplay audio is correct."); + is(nonAutoPlay.computedSuspended, suspendedType, + "The suspeded state of non-autoplay audio is correct."); +} + +function check_autoplay_audio_suspended(suspendedType) { + var autoPlay = content.document.getElementById('autoplay'); + if (!autoPlay) { + ok(false, "Can't get the audio element!"); + } + + is(autoPlay.computedSuspended, suspendedType, + "The suspeded state of autoplay audio is correct."); +} + +function check_nonautoplay_audio_suspended(suspendedType) { + var nonAutoPlay = content.document.getElementById('nonautoplay'); + if (!nonAutoPlay) { + ok(false, "Can't get the audio element!"); + } + + is(nonAutoPlay.computedSuspended, suspendedType, + "The suspeded state of non-autoplay audio is correct."); +} + +function check_autoplay_audio_pause_state(expectedPauseState) { + var autoPlay = content.document.getElementById('autoplay'); + if (!autoPlay) { + ok(false, "Can't get the audio element!"); + } + + if (expectedPauseState) { + is(autoPlay.paused, true, "Audio is paused correctly."); + } else { + is(autoPlay.paused, false, "Audio is resumed correctly."); + } +} + +function play_nonautoplay_audio_should_be_paused() { + var nonAutoPlay = content.document.getElementById('nonautoplay'); + if (!nonAutoPlay) { + ok(false, "Can't get the audio element!"); + } + + nonAutoPlay.play(); + return new Promise(resolve => { + nonAutoPlay.onpause = function () { + nonAutoPlay.onpause = null; + is(nonAutoPlay.ended, false, "Audio can't be playback."); + resolve(); + } + }); +} + +function all_audio_onresume() { + var autoPlay = content.document.getElementById('autoplay'); + var nonAutoPlay = content.document.getElementById('nonautoplay'); + if (!autoPlay || !nonAutoPlay) { + ok(false, "Can't get the audio element!"); + } + + is(autoPlay.paused, false, "Autoplay audio is resumed."); + is(nonAutoPlay.paused, false, "Non-AutoPlay audio is resumed."); +} + +function all_audio_onpause() { + var autoPlay = content.document.getElementById('autoplay'); + var nonAutoPlay = content.document.getElementById('nonautoplay'); + if (!autoPlay || !nonAutoPlay) { + ok(false, "Can't get the audio element!"); + } + + is(autoPlay.paused, true, "Autoplay audio is paused."); + is(nonAutoPlay.paused, true, "Non-AutoPlay audio is paused."); +} + +function play_nonautoplay_audio_should_play_until_ended() { + var nonAutoPlay = content.document.getElementById('nonautoplay'); + if (!nonAutoPlay) { + ok(false, "Can't get the audio element!"); + } + + nonAutoPlay.play(); + return new Promise(resolve => { + nonAutoPlay.onended = function () { + nonAutoPlay.onended = null; + ok(true, "Audio can be playback until ended."); + resolve(); + } + }); +} + +function no_audio_resumed() { + var autoPlay = content.document.getElementById('autoplay'); + var nonAutoPlay = content.document.getElementById('nonautoplay'); + if (!autoPlay || !nonAutoPlay) { + ok(false, "Can't get the audio element!"); + } + + is(autoPlay.paused && nonAutoPlay.paused, true, "No audio was resumed."); +} + +function play_nonautoplay_audio_should_be_blocked(suspendedType) { + var nonAutoPlay = content.document.getElementById('nonautoplay'); + if (!nonAutoPlay) { + ok(false, "Can't get the audio element!"); + } + + nonAutoPlay.play(); + return new Promise(resolve => { + nonAutoPlay.onplay = function () { + nonAutoPlay.onplay = null; + is(nonAutoPlay.computedSuspended, suspendedType, + "The suspeded state of non-autoplay audio is correct."); + resolve(); + } + }); +} + +function* suspended_pause(url, browser) { + info("### Start test for suspended-pause ###"); + browser.loadURI(url); + + info("- page should have playing audio -"); + yield wait_for_event(browser, "DOMAudioPlaybackStarted"); + + info("- the default suspended state of all audio should be non-suspened-"); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_all_audio_suspended); + + info("- pause all audio in the page -"); + browser.pauseMedia(false /* non-disposable */); + yield ContentTask.spawn(browser, true /* expect for pause */, + check_autoplay_audio_pause_state); + yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE, + check_autoplay_audio_suspended); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_nonautoplay_audio_suspended); + + info("- no audio can be playback during suspended-paused -"); + yield ContentTask.spawn(browser, null, + play_nonautoplay_audio_should_be_paused); + yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE, + check_nonautoplay_audio_suspended); + + info("- both audio should be resumed at the same time -"); + browser.resumeMedia(); + yield ContentTask.spawn(browser, null, + all_audio_onresume); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_all_audio_suspended); + + info("- both audio should be paused at the same time -"); + browser.pauseMedia(false /* non-disposable */); + yield ContentTask.spawn(browser, null, all_audio_onpause); +} + +function* suspended_pause_disposable(url, browser) { + info("### Start test for suspended-pause-disposable ###"); + browser.loadURI(url); + + info("- page should have playing audio -"); + yield wait_for_event(browser, "DOMAudioPlaybackStarted"); + + info("- the default suspended state of all audio should be non-suspened -"); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_all_audio_suspended); + + info("- only pause playing audio in the page -"); + browser.pauseMedia(true /* non-disposable */); + yield ContentTask.spawn(browser, true /* expect for pause */, + check_autoplay_audio_pause_state); + yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_PAUSE_DISPOSABLE, + check_autoplay_audio_suspended); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_nonautoplay_audio_suspended); + + info("- new playing audio should be playback correctly -"); + yield ContentTask.spawn(browser, null, + play_nonautoplay_audio_should_play_until_ended); + + info("- should only resume one audio -"); + browser.resumeMedia(); + yield ContentTask.spawn(browser, false /* expect for playing */, + check_autoplay_audio_pause_state); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_all_audio_suspended); +} + +function* suspended_stop_disposable(url, browser) { + info("### Start test for suspended-stop-disposable ###"); + browser.loadURI(url); + + info("- page should have playing audio -"); + yield wait_for_event(browser, "DOMAudioPlaybackStarted"); + + info("- the default suspended state of all audio should be non-suspened -"); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_all_audio_suspended); + + info("- only stop playing audio in the page -"); + browser.stopMedia(); + yield ContentTask.spawn(browser, true /* expect for pause */, + check_autoplay_audio_pause_state); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_all_audio_suspended); + + info("- new playing audio should be playback correctly -"); + yield ContentTask.spawn(browser, null, + play_nonautoplay_audio_should_play_until_ended); + + info("- no any audio can be resumed by page -"); + browser.resumeMedia(); + yield ContentTask.spawn(browser, null, no_audio_resumed); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_all_audio_suspended); +} + +function* suspended_block(url, browser) { + info("### Start test for suspended-block ###"); + browser.loadURI(url); + + info("- page should have playing audio -"); + yield wait_for_event(browser, "DOMAudioPlaybackStarted"); + + info("- the default suspended state of all audio should be non-suspened-"); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_all_audio_suspended); + + info("- block autoplay audio -"); + browser.blockMedia(); + yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_BLOCK, + check_autoplay_audio_suspended); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_nonautoplay_audio_suspended); + + info("- no audio can be playback during suspended-block -"); + yield ContentTask.spawn(browser, SuspendedType.SUSPENDED_BLOCK, + play_nonautoplay_audio_should_be_blocked); + + info("- both audio should be resumed at the same time -"); + browser.resumeMedia(); + yield ContentTask.spawn(browser, SuspendedType.NONE_SUSPENDED, + check_all_audio_suspended); +} + +add_task(function* setup_test_preference() { + yield new Promise(resolve => { + SpecialPowers.pushPrefEnv({"set": [ + ["media.useAudioChannelService.testing", true] + ]}, resolve); + }); +}); + +add_task(function* test_suspended_pause() { + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: "about:blank" + }, suspended_pause.bind(this, PAGE)); +}); + +add_task(function* test_suspended_pause_disposable() { + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: "about:blank" + }, suspended_pause_disposable.bind(this, PAGE)); +}); + +add_task(function* test_suspended_stop_disposable() { + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: "about:blank" + }, suspended_stop_disposable.bind(this, PAGE)); +}); + +add_task(function* test_suspended_block() { + yield BrowserTestUtils.withNewTab({ + gBrowser, + url: "about:blank" + }, suspended_block.bind(this, PAGE)); +}); diff --git a/toolkit/content/tests/browser/file_multipleAudio.html b/toolkit/content/tests/browser/file_multipleAudio.html new file mode 100644 index 0000000000..fb860aac19 --- /dev/null +++ b/toolkit/content/tests/browser/file_multipleAudio.html @@ -0,0 +1,7 @@ + + + + + + diff --git a/toolkit/content/tests/widgets/audio.ogg b/toolkit/content/tests/widgets/audio.ogg index 7e6ef77ec4..a553c23e73 100644 Binary files a/toolkit/content/tests/widgets/audio.ogg and b/toolkit/content/tests/widgets/audio.ogg differ diff --git a/toolkit/xre/nsEmbedFunctions.cpp b/toolkit/xre/nsEmbedFunctions.cpp index 1416f3b038..aa86cd8a0c 100644 --- a/toolkit/xre/nsEmbedFunctions.cpp +++ b/toolkit/xre/nsEmbedFunctions.cpp @@ -802,13 +802,6 @@ XRE_RunAppShell() return appShell->Run(); } -template<> -struct RunnableMethodTraits -{ - static void RetainCallee(ContentChild* obj) { } - static void ReleaseCallee(ContentChild* obj) { } -}; - void XRE_ShutdownChildProcess() { diff --git a/toolkit/xre/nsUpdateDriver.cpp b/toolkit/xre/nsUpdateDriver.cpp index 83002ca022..cc8b87ef63 100644 --- a/toolkit/xre/nsUpdateDriver.cpp +++ b/toolkit/xre/nsUpdateDriver.cpp @@ -1204,8 +1204,8 @@ nsUpdateProcessor::ProcessUpdate(nsIUpdate* aUpdate) #endif MOZ_ASSERT(NS_IsMainThread(), "not main thread"); - return NS_NewThread(getter_AddRefs(mProcessWatcher), - NS_NewRunnableMethod(this, &nsUpdateProcessor::StartStagedUpdate)); + nsCOMPtr r = NewRunnableMethod(this, &nsUpdateProcessor::StartStagedUpdate); + return NS_NewThread(getter_AddRefs(mProcessWatcher), r); } @@ -1229,13 +1229,13 @@ nsUpdateProcessor::StartStagedUpdate() if (mUpdaterPID) { // Track the state of the updater process while it is staging an update. - rv = NS_DispatchToCurrentThread(NS_NewRunnableMethod(this, &nsUpdateProcessor::WaitForProcess)); + rv = NS_DispatchToCurrentThread(NewRunnableMethod(this, &nsUpdateProcessor::WaitForProcess)); NS_ENSURE_SUCCESS_VOID(rv); } else { // Failed to launch the updater process for some reason. // We need to shutdown the current thread as there isn't anything more for // us to do... - rv = NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsUpdateProcessor::ShutdownWatcherThread)); + rv = NS_DispatchToMainThread(NewRunnableMethod(this, &nsUpdateProcessor::ShutdownWatcherThread)); NS_ENSURE_SUCCESS_VOID(rv); } } @@ -1253,7 +1253,7 @@ nsUpdateProcessor::WaitForProcess() { MOZ_ASSERT(!NS_IsMainThread(), "main thread"); ::WaitForProcess(mUpdaterPID); - NS_DispatchToMainThread(NS_NewRunnableMethod(this, &nsUpdateProcessor::UpdateDone)); + NS_DispatchToMainThread(NewRunnableMethod(this, &nsUpdateProcessor::UpdateDone)); } void diff --git a/uriloader/prefetch/nsOfflineCacheUpdate.cpp b/uriloader/prefetch/nsOfflineCacheUpdate.cpp index 1598520a30..ad1e88c04a 100644 --- a/uriloader/prefetch/nsOfflineCacheUpdate.cpp +++ b/uriloader/prefetch/nsOfflineCacheUpdate.cpp @@ -1736,10 +1736,8 @@ nsOfflineCacheUpdate::Begin() mItemsInProgress = 0; if (mState == STATE_CANCELLED) { - RefPtr > errorNotification = - NS_NewRunnableMethod(this, - &nsOfflineCacheUpdate::AsyncFinishWithError); - nsresult rv = NS_DispatchToMainThread(errorNotification); + nsresult rv = NS_DispatchToMainThread(NewRunnableMethod(this, + &nsOfflineCacheUpdate::AsyncFinishWithError)); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; diff --git a/widget/CompositorWidgetProxy.cpp b/widget/CompositorWidgetProxy.cpp index a4594a2b70..3d58854ce3 100644 --- a/widget/CompositorWidgetProxy.cpp +++ b/widget/CompositorWidgetProxy.cpp @@ -5,6 +5,7 @@ #include "CompositorWidgetProxy.h" #include "GLConsts.h" #include "nsBaseWidget.h" +#include "VsyncDispatcher.h" namespace mozilla { namespace widget { @@ -69,18 +70,12 @@ CompositorWidgetProxyWrapper::CompositorWidgetProxyWrapper(nsBaseWidget* aWidget bool CompositorWidgetProxyWrapper::PreRender(layers::LayerManagerComposite* aManager) { - if (!mWidget) { - return false; - } return mWidget->PreRender(aManager); } void CompositorWidgetProxyWrapper::PostRender(layers::LayerManagerComposite* aManager) { - if (!mWidget) { - return; - } mWidget->PostRender(aManager); } @@ -88,9 +83,6 @@ void CompositorWidgetProxyWrapper::DrawWindowUnderlay(layers::LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) { - if (!mWidget) { - return; - } mWidget->DrawWindowUnderlay(aManager, aRect); } @@ -98,18 +90,12 @@ void CompositorWidgetProxyWrapper::DrawWindowOverlay(layers::LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) { - if (!mWidget) { - return; - } mWidget->DrawWindowOverlay(aManager, aRect); } already_AddRefed CompositorWidgetProxyWrapper::StartRemoteDrawing() { - if (!mWidget) { - return nullptr; - } return mWidget->StartRemoteDrawing(); } @@ -117,18 +103,12 @@ already_AddRefed CompositorWidgetProxyWrapper::StartRemoteDrawingInRegion(LayoutDeviceIntRegion& aInvalidRegion, layers::BufferMode* aBufferMode) { - if (!mWidget) { - return nullptr; - } return mWidget->StartRemoteDrawingInRegion(aInvalidRegion, aBufferMode); } void CompositorWidgetProxyWrapper::EndRemoteDrawing() { - if (!mWidget) { - return; - } mWidget->EndRemoteDrawing(); } @@ -136,71 +116,63 @@ void CompositorWidgetProxyWrapper::EndRemoteDrawingInRegion(gfx::DrawTarget* aDrawTarget, LayoutDeviceIntRegion& aInvalidRegion) { - if (!mWidget) { - return; - } mWidget->EndRemoteDrawingInRegion(aDrawTarget, aInvalidRegion); } void CompositorWidgetProxyWrapper::CleanupRemoteDrawing() { - if (mWidget) { - mWidget->CleanupRemoteDrawing(); - } - CompositorWidgetProxy::CleanupRemoteDrawing(); + mWidget->CleanupRemoteDrawing(); } void CompositorWidgetProxyWrapper::CleanupWindowEffects() { - if (!mWidget) { - return; - } mWidget->CleanupWindowEffects(); } bool CompositorWidgetProxyWrapper::InitCompositor(layers::Compositor* aCompositor) { - if (!mWidget) { - return false; - } return mWidget->InitCompositor(aCompositor); } LayoutDeviceIntSize CompositorWidgetProxyWrapper::GetClientSize() { - if (!mWidget) { - return LayoutDeviceIntSize(); - } return mWidget->GetClientSize(); } uint32_t CompositorWidgetProxyWrapper::GetGLFrameBufferFormat() { - if (!mWidget) { - return CompositorWidgetProxy::GetGLFrameBufferFormat(); - } return mWidget->GetGLFrameBufferFormat(); } layers::Composer2D* CompositorWidgetProxyWrapper::GetComposer2D() { - if (!mWidget) { - return nullptr; - } return mWidget->GetComposer2D(); } +uintptr_t +CompositorWidgetProxyWrapper::GetWidgetKey() +{ + return reinterpret_cast(mWidget); +} + nsIWidget* CompositorWidgetProxyWrapper::RealWidget() { return mWidget; } +already_AddRefed +CompositorWidgetProxyWrapper::GetCompositorVsyncDispatcher() +{ + RefPtr cvd = mWidget->GetCompositorVsyncDispatcher(); + return cvd.forget(); +} + } // namespace widget } // namespace mozilla diff --git a/widget/CompositorWidgetProxy.h b/widget/CompositorWidgetProxy.h index eb5eea4073..225a03a4f4 100644 --- a/widget/CompositorWidgetProxy.h +++ b/widget/CompositorWidgetProxy.h @@ -15,6 +15,7 @@ class nsIWidget; class nsBaseWidget; namespace mozilla { +class CompositorVsyncDispatcher; namespace layers { class Compositor; class LayerManagerComposite; @@ -26,6 +27,8 @@ class DrawTarget; } // namespace gfx namespace widget { +class WinCompositorWidgetProxy; + /** * Access to a widget from the compositor is restricted to these methods. */ @@ -162,6 +165,19 @@ public: */ virtual void CleanupRemoteDrawing(); + /** + * Return a key that can represent the widget object round-trip across the + * CompositorBridge channel. This only needs to be implemented on GTK and + * Windows. + * + * The key must be the nsIWidget pointer cast to a uintptr_t. See + * CompositorBridgeChild::RecvHideAllPlugins and + * CompositorBridgeParent::SendHideAllPlugins. + */ + virtual uintptr_t GetWidgetKey() { + return 0; + } + /** * Create a backbuffer for the software compositor. */ @@ -170,6 +186,15 @@ public: const LayoutDeviceIntRect& aRect, const LayoutDeviceIntRect& aClearRect); + /** + * Return a compositor vsync dispatcher for this widget. + */ + virtual already_AddRefed GetCompositorVsyncDispatcher() = 0; + + virtual WinCompositorWidgetProxy* AsWindowsProxy() { + return nullptr; + } + protected: virtual ~CompositorWidgetProxy(); @@ -204,6 +229,8 @@ public: virtual LayoutDeviceIntSize GetClientSize() override; virtual uint32_t GetGLFrameBufferFormat() override; virtual layers::Composer2D* GetComposer2D() override; + virtual already_AddRefed GetCompositorVsyncDispatcher() override; + virtual uintptr_t GetWidgetKey() override; // If you can override this method, inherit from CompositorWidgetProxy instead. nsIWidget* RealWidget() override; diff --git a/widget/ScreenProxy.cpp b/widget/ScreenProxy.cpp index cf774a6e9a..5257eb68ab 100644 --- a/widget/ScreenProxy.cpp +++ b/widget/ScreenProxy.cpp @@ -174,9 +174,7 @@ ScreenProxy::InvalidateCacheOnNextTick() mCacheWillInvalidate = true; - nsCOMPtr r = - NS_NewRunnableMethod(this, &ScreenProxy::InvalidateCache); - nsContentUtils::RunInStableState(r.forget()); + nsContentUtils::RunInStableState(NewRunnableMethod(this, &ScreenProxy::InvalidateCache)); } void diff --git a/widget/VsyncDispatcher.cpp b/widget/VsyncDispatcher.cpp index b57c71136d..04ad7410b1 100644 --- a/widget/VsyncDispatcher.cpp +++ b/widget/VsyncDispatcher.cpp @@ -89,7 +89,7 @@ CompositorVsyncDispatcher::SetCompositorVsyncObserver(VsyncObserver* aVsyncObser } bool observeVsync = aVsyncObserver != nullptr; - nsCOMPtr vsyncControl = NS_NewRunnableMethodWithArg(this, + nsCOMPtr vsyncControl = NewRunnableMethod(this, &CompositorVsyncDispatcher::ObserveVsync, observeVsync); NS_DispatchToMainThread(vsyncControl); @@ -180,9 +180,8 @@ void RefreshTimerVsyncDispatcher::UpdateVsyncStatus() { if (!NS_IsMainThread()) { - nsCOMPtr vsyncControl = NS_NewRunnableMethod(this, - &RefreshTimerVsyncDispatcher::UpdateVsyncStatus); - NS_DispatchToMainThread(vsyncControl); + NS_DispatchToMainThread(NewRunnableMethod(this, + &RefreshTimerVsyncDispatcher::UpdateVsyncStatus)); return; } diff --git a/widget/gonk/nsWindow.cpp b/widget/gonk/nsWindow.cpp index c2b43fc0bc..526d6fd551 100644 --- a/widget/gonk/nsWindow.cpp +++ b/widget/gonk/nsWindow.cpp @@ -44,6 +44,7 @@ #include "mozilla/layers/APZCTreeManager.h" #include "mozilla/layers/APZThreadUtils.h" #include "mozilla/layers/CompositorBridgeParent.h" +#include "mozilla/layers/CompositorSession.h" #include "mozilla/TouchEvents.h" #include "HwcComposer2D.h" @@ -697,10 +698,10 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager, } CreateCompositor(); - if (mCompositorBridgeParent) { - mScreen->SetCompositorBridgeParent(mCompositorBridgeParent); + if (RefPtr bridge = GetCompositorBridgeParent()) { + mScreen->SetCompositorBridgeParent(bridge); if (mScreen->IsPrimaryScreen()) { - mComposer2D->SetCompositorBridgeParent(mCompositorBridgeParent); + mComposer2D->SetCompositorBridgeParent(bridge); } } MOZ_ASSERT(mLayerManager); @@ -710,7 +711,7 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager, void nsWindow::DestroyCompositor() { - if (mCompositorBridgeParent) { + if (RefPtr bridge = GetCompositorBridgeParent()) { mScreen->SetCompositorBridgeParent(nullptr); if (mScreen->IsPrimaryScreen()) { // Unset CompositorBridgeParent @@ -720,12 +721,6 @@ nsWindow::DestroyCompositor() nsBaseWidget::DestroyCompositor(); } -CompositorBridgeParent* -nsWindow::NewCompositorBridgeParent(int aSurfaceWidth, int aSurfaceHeight) -{ - return new CompositorBridgeParent(this, true, aSurfaceWidth, aSurfaceHeight); -} - void nsWindow::BringToTop() { @@ -799,3 +794,9 @@ nsWindow::GetComposer2D() return mComposer2D; } + +CompositorBridgeParent* +nsWindow::GetCompositorBridgeParent() const +{ + return mCompositorSession ? mCompositorSession->GetInProcessBridge() : nullptr; +} diff --git a/widget/gonk/nsWindow.h b/widget/gonk/nsWindow.h index 74cecc66b6..3460d15458 100644 --- a/widget/gonk/nsWindow.h +++ b/widget/gonk/nsWindow.h @@ -117,8 +117,6 @@ public: bool* aAllowRetaining = nullptr); virtual void DestroyCompositor(); - virtual CompositorBridgeParent* NewCompositorBridgeParent(int aSurfaceWidth, int aSurfaceHeight); - NS_IMETHOD_(void) SetInputContext(const InputContext& aContext, const InputContextAction& aAction); NS_IMETHOD_(InputContext) GetInputContext(); @@ -148,6 +146,11 @@ protected: // event (like a keypress or mouse click). void UserActivity(); + bool UseExternalCompositingSurface() const override { + return true; + } + CompositorBridgeParent* GetCompositorBridgeParent() const; + private: // This is used by SynthesizeNativeTouchPoint to maintain state between // multiple synthesized points diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index e3e21bc16e..50bce28d60 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -2144,7 +2144,7 @@ nsWindow::OnExposeEvent(cairo_t *cr) ? static_cast(GetLayerManager()) : nullptr; - if (clientLayers && mCompositorBridgeParent) { + if (clientLayers && mCompositorSession) { // We need to paint to the screen even if nothing changed, since if we // don't have a compositing window manager, our pixels could be stale. clientLayers->SetNeedsComposite(true); @@ -2169,9 +2169,9 @@ nsWindow::OnExposeEvent(cairo_t *cr) return FALSE; } - if (clientLayers && mCompositorBridgeParent && clientLayers->NeedsComposite()) { - mCompositorBridgeParent->ScheduleRenderOnCompositorThread(); - clientLayers->SetNeedsComposite(false); + if (clientLayers && clientLayers->NeedsComposite()) { + clientLayers->Composite(); + clientLayers->SetNeedsComposite(false); } LOGDRAW(("sending expose event [%p] %p 0x%lx (rects follow):\n", @@ -2473,9 +2473,7 @@ nsWindow::OnSizeAllocate(GtkAllocation *aAllocation) // GtkWindow callers of gtk_widget_size_allocate expect the signal // handlers to return sometime in the near future. mNeedsDispatchResized = true; - nsCOMPtr r = - NS_NewRunnableMethod(this, &nsWindow::MaybeDispatchResized); - NS_DispatchToCurrentThread(r.forget()); + NS_DispatchToCurrentThread(NewRunnableMethod(this, &nsWindow::MaybeDispatchResized)); } void @@ -4628,8 +4626,12 @@ nsWindow::GrabPointer(guint32 aTime) LOG(("GrabPointer: pointer grab failed: %i\n", retval)); // A failed grab indicates that another app has grabbed the pointer. // Check for rollup now, because, without the grab, we likely won't - // get subsequent button press events. - CheckForRollup(0, 0, false, true); + // get subsequent button press events. Do this with an event so that + // popups don't rollup while potentially adjusting the grab for + // this popup. + nsCOMPtr event = + NewRunnableMethod(this, &nsWindow::CheckForRollupDuringGrab); + NS_DispatchToCurrentThread(event.forget()); } } diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h index 6155930818..415c224b61 100644 --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -416,6 +416,11 @@ private: bool DispatchContentCommandEvent(mozilla::EventMessage aMsg); bool CheckForRollup(gdouble aMouseX, gdouble aMouseY, bool aIsWheel, bool aAlwaysRollup); + void CheckForRollupDuringGrab() + { + CheckForRollup(0, 0, false, true); + } + bool GetDragInfo(mozilla::WidgetMouseEvent* aMouseEvent, GdkWindow** aWindow, gint* aButton, gint* aRootX, gint* aRootY); diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index ed5865644f..2a1997d267 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -70,6 +70,7 @@ #include "nsAccessibilityService.h" #endif #include "gfxConfig.h" +#include "mozilla/layers/CompositorSession.h" #ifdef DEBUG #include "nsIObserver.h" @@ -271,8 +272,8 @@ void nsBaseWidget::DestroyCompositor() // XXX CompositorBridgeChild and CompositorBridgeParent might be re-created in // ClientLayerManager destructor. See bug 1133426. RefPtr compositorChild = mCompositorBridgeChild; - RefPtr compositorParent = mCompositorBridgeParent; - mCompositorBridgeChild->Destroy(); + RefPtr compositorSession = mCompositorSession; + mCompositorSession->Shutdown(); mCompositorBridgeChild = nullptr; } @@ -296,7 +297,7 @@ void nsBaseWidget::DestroyLayerManager() void nsBaseWidget::OnRenderingDeviceReset() { - if (!mLayerManager || !mCompositorBridgeParent) { + if (!mLayerManager || !mCompositorSession) { return; } @@ -316,9 +317,14 @@ nsBaseWidget::OnRenderingDeviceReset() return; } + RefPtr parent = mCompositorSession->GetInProcessBridge(); + if (!parent) { + return; + } + // Recreate the compositor. TextureFactoryIdentifier identifier; - if (!mCompositorBridgeParent->ResetCompositor(backendHints, &identifier)) { + if (!parent->ResetCompositor(backendHints, &identifier)) { // No action was taken, so we don't have to do anything. return; } @@ -939,20 +945,6 @@ nsBaseWidget::UseAPZ() (WindowType() == eWindowType_toplevel || WindowType() == eWindowType_child)); } -CompositorBridgeParent* -nsBaseWidget::NewCompositorBridgeParent(int aSurfaceWidth, - int aSurfaceHeight) -{ - if (!mCompositorWidgetProxy) { - mCompositorWidgetProxy = NewCompositorWidgetProxy(); - } - return new CompositorBridgeParent(mCompositorWidgetProxy, - GetDefaultScale(), - UseAPZ(), - false, - aSurfaceWidth, aSurfaceHeight); -} - void nsBaseWidget::CreateCompositor() { LayoutDeviceIntRect rect; @@ -983,9 +975,11 @@ void nsBaseWidget::ConfigureAPZCTreeManager() bool aPreventDefault) { MOZ_ASSERT(NS_IsMainThread()); - APZThreadUtils::RunOnControllerThread(NewRunnableMethod( - treeManager.get(), &APZCTreeManager::ContentReceivedInputBlock, - aInputBlockId, aPreventDefault)); + APZThreadUtils::RunOnControllerThread(NewRunnableMethod + (treeManager, + &APZCTreeManager::ContentReceivedInputBlock, + aInputBlockId, + aPreventDefault)); }); mAPZEventState = new APZEventState(this, mozilla::Move(callback)); @@ -993,15 +987,16 @@ void nsBaseWidget::ConfigureAPZCTreeManager() const nsTArray& aFlags) { MOZ_ASSERT(NS_IsMainThread()); - APZThreadUtils::RunOnControllerThread(NewRunnableMethod( - treeManager.get(), &APZCTreeManager::SetAllowedTouchBehavior, - aInputBlockId, aFlags)); + APZThreadUtils::RunOnControllerThread(NewRunnableMethod + >>(treeManager, + &APZCTreeManager::SetAllowedTouchBehavior, + aInputBlockId, aFlags)); }; mRootContentController = CreateRootContentController(); if (mRootContentController) { - uint64_t rootLayerTreeId = mCompositorBridgeParent->RootLayerTreeId(); - CompositorBridgeParent::SetControllerForLayerTree(rootLayerTreeId, mRootContentController); + mCompositorSession->SetContentController(mRootContentController); } // When APZ is enabled, we can actually enable raw touch events because we @@ -1026,8 +1021,10 @@ nsBaseWidget::SetConfirmedTargetAPZC(uint64_t aInputBlockId, // Need to specifically bind this since it's overloaded. void (APZCTreeManager::*setTargetApzcFunc)(uint64_t, const nsTArray&) = &APZCTreeManager::SetTargetAPZC; - APZThreadUtils::RunOnControllerThread(NewRunnableMethod( - mAPZC.get(), setTargetApzcFunc, aInputBlockId, aTargets)); + APZThreadUtils::RunOnControllerThread(NewRunnableMethod + >>(mAPZC, + setTargetApzcFunc, + aInputBlockId, aTargets)); } void @@ -1035,7 +1032,7 @@ nsBaseWidget::UpdateZoomConstraints(const uint32_t& aPresShellId, const FrameMetrics::ViewID& aViewId, const Maybe& aConstraints) { - if (!mCompositorBridgeParent || !mAPZC) { + if (!mCompositorSession || !mAPZC) { if (mInitialZoomConstraints) { MOZ_ASSERT(mInitialZoomConstraints->mPresShellID == aPresShellId); MOZ_ASSERT(mInitialZoomConstraints->mViewID == aViewId); @@ -1051,7 +1048,7 @@ nsBaseWidget::UpdateZoomConstraints(const uint32_t& aPresShellId, } return; } - uint64_t layersId = mCompositorBridgeParent->RootLayerTreeId(); + uint64_t layersId = mCompositorSession->RootLayerTreeId(); mAPZC->UpdateZoomConstraints(ScrollableLayerGuid(layersId, aPresShellId, aViewId), aConstraints); } @@ -1076,7 +1073,7 @@ nsBaseWidget::ProcessUntransformedAPZEvent(WidgetInputEvent* aEvent, // event. If the event is instead targeted to an APZC in the child process, // the transform will be applied in the child process before dispatching // the event there (see e.g. TabChild::RecvRealTouchEvent()). - if (aGuid.mLayersId == mCompositorBridgeParent->RootLayerTreeId()) { + if (aGuid.mLayersId == mCompositorSession->RootLayerTreeId()) { APZCCallbackHelper::ApplyCallbackTransform(*aEvent, aGuid, GetDefaultScale()); } @@ -1263,7 +1260,7 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight) MOZ_ASSERT(gfxPlatform::UsesOffMainThreadCompositing(), "This function assumes OMTC"); - MOZ_ASSERT(!mCompositorBridgeParent && !mCompositorBridgeChild, + MOZ_ASSERT(!mCompositorSession && !mCompositorBridgeChild, "Should have properly cleaned up the previous PCompositor pair beforehand"); if (mCompositorBridgeChild) { @@ -1280,16 +1277,23 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight) } CreateCompositorVsyncDispatcher(); - mCompositorBridgeParent = NewCompositorBridgeParent(aWidth, aHeight); + + if (!mCompositorWidgetProxy) { + mCompositorWidgetProxy = NewCompositorWidgetProxy(); + } + RefPtr lm = new ClientLayerManager(this); - mCompositorBridgeChild = new CompositorBridgeChild(lm); - mCompositorBridgeChild->OpenSameProcess(mCompositorBridgeParent); - // Make sure the parent knows it is same process. - mCompositorBridgeParent->SetOtherProcessId(base::GetCurrentProcId()); + mCompositorSession = CompositorSession::CreateTopLevel( + mCompositorWidgetProxy, + lm, + GetDefaultScale(), + UseAPZ(), + UseExternalCompositingSurface(), + aWidth, aHeight); + mCompositorBridgeChild = mCompositorSession->GetCompositorBridgeChild(); - uint64_t rootLayerTreeId = mCompositorBridgeParent->RootLayerTreeId(); - mAPZC = CompositorBridgeParent::GetAPZCTreeManager(rootLayerTreeId); + mAPZC = mCompositorSession->GetAPZCTreeManager(); if (mAPZC) { ConfigureAPZCTreeManager(); } @@ -1325,7 +1329,7 @@ void nsBaseWidget::CreateCompositor(int aWidth, int aHeight) DestroyCompositor(); mLayerManager = nullptr; mCompositorBridgeChild = nullptr; - mCompositorBridgeParent = nullptr; + mCompositorSession = nullptr; mCompositorVsyncDispatcher = nullptr; return; } @@ -1859,10 +1863,10 @@ nsBaseWidget::ZoomToRect(const uint32_t& aPresShellId, const CSSRect& aRect, const uint32_t& aFlags) { - if (!mCompositorBridgeParent || !mAPZC) { + if (!mCompositorSession || !mAPZC) { return; } - uint64_t layerId = mCompositorBridgeParent->RootLayerTreeId(); + uint64_t layerId = mCompositorSession->RootLayerTreeId(); mAPZC->ZoomToRect(ScrollableLayerGuid(layerId, aPresShellId, aViewId), aRect, aFlags); } @@ -1908,13 +1912,15 @@ nsBaseWidget::StartAsyncScrollbarDrag(const AsyncDragMetrics& aDragMetrics) return; } - MOZ_ASSERT(XRE_IsParentProcess() && mCompositorBridgeParent); + MOZ_ASSERT(XRE_IsParentProcess() && mCompositorSession); - int layersId = mCompositorBridgeParent->RootLayerTreeId();; + int layersId = mCompositorSession->RootLayerTreeId();; ScrollableLayerGuid guid(layersId, aDragMetrics.mPresShellId, aDragMetrics.mViewId); - APZThreadUtils::RunOnControllerThread( - NewRunnableMethod(mAPZC.get(), &APZCTreeManager::StartScrollbarDrag, guid, aDragMetrics)); + APZThreadUtils::RunOnControllerThread(NewRunnableMethod + (mAPZC, + &APZCTreeManager::StartScrollbarDrag, + guid, aDragMetrics)); } nsresult diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h index b8442c1a4e..88a35598f9 100644 --- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -28,6 +28,7 @@ class nsAutoRollup; class gfxContext; namespace mozilla { +class CompositorVsyncDispatcher; #ifdef ACCESSIBILITY namespace a11y { class Accessible; @@ -45,6 +46,7 @@ class CompositorBridgeParent; class APZCTreeManager; class GeckoContentController; class APZEventState; +class CompositorSession; struct ScrollableLayerGuid; } // namespace layers @@ -111,6 +113,7 @@ protected: typedef mozilla::CSSRect CSSRect; typedef mozilla::ScreenRotation ScreenRotation; typedef mozilla::widget::CompositorWidgetProxy CompositorWidgetProxy; + typedef mozilla::layers::CompositorSession CompositorSession; virtual ~nsBaseWidget(); @@ -162,9 +165,8 @@ public: LayerManagerPersistence aPersistence = LAYER_MANAGER_CURRENT, bool* aAllowRetaining = nullptr) override; - CompositorVsyncDispatcher* GetCompositorVsyncDispatcher() override; + mozilla::CompositorVsyncDispatcher* GetCompositorVsyncDispatcher(); void CreateCompositorVsyncDispatcher(); - virtual CompositorBridgeParent* NewCompositorBridgeParent(int aSurfaceWidth, int aSurfaceHeight); virtual void CreateCompositor(); virtual void CreateCompositor(int aWidth, int aHeight); virtual void PrepareWindowEffects() override {} @@ -529,6 +531,11 @@ protected: bool UseAPZ(); protected: + // Returns whether compositing should use an external surface size. + virtual bool UseExternalCompositingSurface() const { + return false; + } + /** * Starts the OMTC compositor destruction sequence. * @@ -547,8 +554,8 @@ protected: nsIWidgetListener* mAttachedWidgetListener; nsIWidgetListener* mPreviouslyAttachedWidgetListener; RefPtr mLayerManager; + RefPtr mCompositorSession; RefPtr mCompositorBridgeChild; - RefPtr mCompositorBridgeParent; RefPtr mCompositorVsyncDispatcher; RefPtr mAPZC; RefPtr mRootContentController; diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 85e4210793..a90f2d2933 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -42,7 +42,6 @@ class nsIRunnable; class nsIKeyEventInPluginCallback; namespace mozilla { -class CompositorVsyncDispatcher; namespace dom { class TabChild; } // namespace dom @@ -347,7 +346,6 @@ class nsIWidget : public nsISupports typedef mozilla::widget::TextEventDispatcher TextEventDispatcher; typedef mozilla::widget::TextEventDispatcherListener TextEventDispatcherListener; - typedef mozilla::CompositorVsyncDispatcher CompositorVsyncDispatcher; typedef mozilla::LayoutDeviceIntMargin LayoutDeviceIntMargin; typedef mozilla::LayoutDeviceIntPoint LayoutDeviceIntPoint; typedef mozilla::LayoutDeviceIntRect LayoutDeviceIntRect; @@ -557,11 +555,6 @@ class nsIWidget : public nsISupports */ virtual mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() = 0; - /** - * Returns the CompositorVsyncDispatcher associated with this widget - */ - virtual CompositorVsyncDispatcher* GetCompositorVsyncDispatcher() = 0; - /** * Return the default scale factor for the window. This is the * default number of device pixels per CSS pixel to use. This should diff --git a/widget/nsScreenManagerProxy.cpp b/widget/nsScreenManagerProxy.cpp index 18661451b4..a4448b2566 100644 --- a/widget/nsScreenManagerProxy.cpp +++ b/widget/nsScreenManagerProxy.cpp @@ -199,9 +199,7 @@ nsScreenManagerProxy::InvalidateCacheOnNextTick() mCacheWillInvalidate = true; - nsCOMPtr r = - NS_NewRunnableMethod(this, &nsScreenManagerProxy::InvalidateCache); - nsContentUtils::RunInStableState(r.forget()); + nsContentUtils::RunInStableState(NewRunnableMethod(this, &nsScreenManagerProxy::InvalidateCache)); } void diff --git a/widget/qt/nsWindow.h b/widget/qt/nsWindow.h index 3943018b28..53a7b20ff5 100644 --- a/widget/qt/nsWindow.h +++ b/widget/qt/nsWindow.h @@ -312,7 +312,7 @@ private: void DispatchMotionToMainThread() { if (!mTimerStarted) { nsCOMPtr event = - NS_NewRunnableMethod(this, &nsWindow::ProcessMotionEvent); + mozilla::NewRunnableMethod(this, &nsWindow::ProcessMotionEvent); NS_DispatchToMainThread(event); mTimerStarted = true; } diff --git a/widget/windows/AudioSession.cpp b/widget/windows/AudioSession.cpp index 3d4b0f2f67..418a98b8ed 100644 --- a/widget/windows/AudioSession.cpp +++ b/widget/windows/AudioSession.cpp @@ -408,7 +408,7 @@ AudioSession::OnSessionDisconnected(AudioSessionDisconnectReason aReason) // Run our code asynchronously. Per MSDN we can't do anything interesting // in this callback. nsCOMPtr runnable = - NS_NewRunnableMethod(this, &AudioSession::OnSessionDisconnectedInternal); + NewRunnableMethod(this, &AudioSession::OnSessionDisconnectedInternal); NS_DispatchToMainThread(runnable); return S_OK; } diff --git a/widget/windows/LSPAnnotator.cpp b/widget/windows/LSPAnnotator.cpp index bbe55563e5..de4a40d2ac 100644 --- a/widget/windows/LSPAnnotator.cpp +++ b/widget/windows/LSPAnnotator.cpp @@ -145,7 +145,7 @@ LSPAnnotationGatherer::Run() } mString = str; - NS_DispatchToMainThread(NS_NewRunnableMethod(this, &LSPAnnotationGatherer::Annotate)); + NS_DispatchToMainThread(NewRunnableMethod(this, &LSPAnnotationGatherer::Annotate)); return NS_OK; } diff --git a/widget/windows/WinCompositorWidgetProxy.cpp b/widget/windows/WinCompositorWidgetProxy.cpp new file mode 100644 index 0000000000..3d4b48be20 --- /dev/null +++ b/widget/windows/WinCompositorWidgetProxy.cpp @@ -0,0 +1,255 @@ +/* -*- 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 "WinCompositorWidgetProxy.h" +#include "nsWindow.h" +#include "VsyncDispatcher.h" +#include "mozilla/gfx/Point.h" + +namespace mozilla { +namespace widget { + +using namespace mozilla::gfx; + +WinCompositorWidgetProxy::WinCompositorWidgetProxy(nsWindow* aWindow) + : mWindow(aWindow), + mWidgetKey(reinterpret_cast(aWindow)), + mWnd(reinterpret_cast(aWindow->GetNativeData(NS_NATIVE_WINDOW))), + mTransparencyMode(aWindow->GetTransparencyMode()), + mMemoryDC(nullptr), + mCompositeDC(nullptr) +{ + MOZ_ASSERT(aWindow); + MOZ_ASSERT(!aWindow->Destroyed()); + MOZ_ASSERT(mWnd && ::IsWindow(mWnd)); +} + +void +WinCompositorWidgetProxy::OnDestroyWindow() +{ + mTransparentSurface = nullptr; + mMemoryDC = nullptr; +} + +bool +WinCompositorWidgetProxy::PreRender(layers::LayerManagerComposite* aManager) +{ + // This can block waiting for WM_SETTEXT to finish + // Using PreRender is unnecessarily pessimistic because + // we technically only need to block during the present call + // not all of compositor rendering + mPresentLock.Enter(); + return true; +} + +void +WinCompositorWidgetProxy::PostRender(layers::LayerManagerComposite* aManager) +{ + mPresentLock.Leave(); +} + +nsIWidget* +WinCompositorWidgetProxy::RealWidget() +{ + return mWindow; +} + +LayoutDeviceIntSize +WinCompositorWidgetProxy::GetClientSize() +{ + RECT r; + if (!::GetClientRect(mWnd, &r)) { + return LayoutDeviceIntSize(); + } + return LayoutDeviceIntSize( + r.right - r.left, + r.bottom - r.top); +} + +already_AddRefed +WinCompositorWidgetProxy::StartRemoteDrawing() +{ + MOZ_ASSERT(!mCompositeDC); + + RefPtr surf; + if (mTransparencyMode == eTransparencyTransparent) { + surf = EnsureTransparentSurface(); + } + + // Must call this after EnsureTransparentSurface(), since it could update + // the DC. + HDC dc = GetWindowSurface(); + if (!surf) { + if (!dc) { + return nullptr; + } + uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 : + gfxWindowsSurface::FLAG_IS_TRANSPARENT; + surf = new gfxWindowsSurface(dc, flags); + } + + IntSize size = surf->GetSize(); + if (size.width <= 0 || size.height <= 0) { + if (dc) { + FreeWindowSurface(dc); + } + return nullptr; + } + + MOZ_ASSERT(!mCompositeDC); + mCompositeDC = dc; + + return mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(surf->CairoSurface(), size); +} + +void +WinCompositorWidgetProxy::EndRemoteDrawing() +{ + if (mTransparencyMode == eTransparencyTransparent) { + MOZ_ASSERT(mTransparentSurface); + RedrawTransparentWindow(); + } + if (mCompositeDC) { + FreeWindowSurface(mCompositeDC); + } + mCompositeDC = nullptr; +} + +already_AddRefed +WinCompositorWidgetProxy::GetCompositorVsyncDispatcher() +{ + RefPtr cvd = mWindow->GetCompositorVsyncDispatcher(); + return cvd.forget(); +} + +uintptr_t +WinCompositorWidgetProxy::GetWidgetKey() +{ + return mWidgetKey; +} + +void +WinCompositorWidgetProxy::EnterPresentLock() +{ + mPresentLock.Enter(); +} + +void +WinCompositorWidgetProxy::LeavePresentLock() +{ + mPresentLock.Leave(); +} + +RefPtr +WinCompositorWidgetProxy::EnsureTransparentSurface() +{ + MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent); + + if (!mTransparentSurface) { + LayoutDeviceIntSize size = GetClientSize(); + CreateTransparentSurface(size.width, size.height); + } + + RefPtr surface = mTransparentSurface; + return surface.forget(); +} + +void +WinCompositorWidgetProxy::CreateTransparentSurface(int32_t aWidth, int32_t aHeight) +{ + MOZ_ASSERT(!mTransparentSurface && !mMemoryDC); + RefPtr surface = + new gfxWindowsSurface(IntSize(aWidth, aHeight), SurfaceFormat::A8R8G8B8_UINT32); + mTransparentSurface = surface; + mMemoryDC = surface->GetDC(); +} + +void +WinCompositorWidgetProxy::UpdateTransparency(nsTransparencyMode aMode) +{ + if (mTransparencyMode == aMode) { + return; + } + + mTransparencyMode = aMode; + mTransparentSurface = nullptr; + mMemoryDC = nullptr; + + if (mTransparencyMode == eTransparencyTransparent) { + EnsureTransparentSurface(); + } +} + +void +WinCompositorWidgetProxy::ClearTransparentWindow() +{ + if (!mTransparentSurface) { + return; + } + + IntSize size = mTransparentSurface->GetSize(); + RefPtr drawTarget = gfxPlatform::GetPlatform()-> + CreateDrawTargetForSurface(mTransparentSurface, size); + drawTarget->ClearRect(Rect(0, 0, size.width, size.height)); + RedrawTransparentWindow(); +} + +void +WinCompositorWidgetProxy::ResizeTransparentWindow(int32_t aNewWidth, int32_t aNewHeight) +{ + MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent); + + if (mTransparentSurface && + mTransparentSurface->GetSize() == IntSize(aNewWidth, aNewHeight)) + { + return; + } + + // Destroy the old surface. + mTransparentSurface = nullptr; + mMemoryDC = nullptr; + + CreateTransparentSurface(aNewWidth, aNewHeight); +} + +bool +WinCompositorWidgetProxy::RedrawTransparentWindow() +{ + MOZ_ASSERT(mTransparencyMode == eTransparencyTransparent); + + LayoutDeviceIntSize size = GetClientSize(); + + ::GdiFlush(); + + BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; + SIZE winSize = { size.width, size.height }; + POINT srcPos = { 0, 0 }; + HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true); + RECT winRect; + ::GetWindowRect(hWnd, &winRect); + + // perform the alpha blend + return !!::UpdateLayeredWindow( + hWnd, nullptr, (POINT*)&winRect, &winSize, mMemoryDC, + &srcPos, 0, &bf, ULW_ALPHA); +} + +HDC +WinCompositorWidgetProxy::GetWindowSurface() +{ + return eTransparencyTransparent == mTransparencyMode + ? mMemoryDC + : ::GetDC(mWnd); +} + +void +WinCompositorWidgetProxy::FreeWindowSurface(HDC dc) +{ + if (eTransparencyTransparent != mTransparencyMode) + ::ReleaseDC(mWnd, dc); +} + +} // namespace widget +} // namespace mozilla diff --git a/widget/windows/WinCompositorWidgetProxy.h b/widget/windows/WinCompositorWidgetProxy.h new file mode 100644 index 0000000000..bf65ca46c0 --- /dev/null +++ b/widget/windows/WinCompositorWidgetProxy.h @@ -0,0 +1,83 @@ +/* -*- 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/. */ + +#ifndef _widget_windows_WinCompositorWidget_h__ +#define _widget_windows_WinCompositorWidget_h__ + +#include "CompositorWidgetProxy.h" +#include "mozilla/gfx/CriticalSection.h" + +class nsWindow; + +namespace mozilla { +namespace widget { + +// This is the Windows-specific implementation of CompositorWidgetProxy. For +// the most part it only requires an HWND, however it maintains extra state +// for transparent windows, as well as for synchronizing WM_SETTEXT messages +// with the compositor. +class WinCompositorWidgetProxy : public CompositorWidgetProxy +{ +public: + WinCompositorWidgetProxy(nsWindow* aWindow); + + bool PreRender(layers::LayerManagerComposite*) override; + void PostRender(layers::LayerManagerComposite*) override; + already_AddRefed StartRemoteDrawing() override; + void EndRemoteDrawing() override; + LayoutDeviceIntSize GetClientSize() override; + already_AddRefed GetCompositorVsyncDispatcher() override; + uintptr_t GetWidgetKey() override; + nsIWidget* RealWidget() override; + WinCompositorWidgetProxy* AsWindowsProxy() override { + return this; + } + + // Callbacks for nsWindow. + void EnterPresentLock(); + void LeavePresentLock(); + void OnDestroyWindow(); + + // Transparency handling. + void UpdateTransparency(nsTransparencyMode aMode); + void ClearTransparentWindow(); + bool RedrawTransparentWindow(); + + // Update the bounds of the transparent surface. + void ResizeTransparentWindow(int32_t aNewWidth, int32_t aNewHeight); + + // Ensure that a transparent surface exists, then return it. + RefPtr EnsureTransparentSurface(); + + HDC GetTransparentDC() const { + return mMemoryDC; + } + HWND GetHwnd() const { + return mWnd; + } + +private: + HDC GetWindowSurface(); + void FreeWindowSurface(HDC dc); + + void CreateTransparentSurface(int32_t aWidth, int32_t aHeight); + +private: + nsWindow* mWindow; + uintptr_t mWidgetKey; + HWND mWnd; + gfx::CriticalSection mPresentLock; + + // Transparency handling. + nsTransparencyMode mTransparencyMode; + RefPtr mTransparentSurface; + HDC mMemoryDC; + HDC mCompositeDC; +}; + +} // namespace widget +} // namespace mozilla + +#endif // _widget_windows_WinCompositorWidget_h__ diff --git a/widget/windows/WinTextEventDispatcherListener.cpp b/widget/windows/WinTextEventDispatcherListener.cpp index 7ea20f59e2..156c7a79b1 100644 --- a/widget/windows/WinTextEventDispatcherListener.cpp +++ b/widget/windows/WinTextEventDispatcherListener.cpp @@ -8,6 +8,7 @@ #include "mozilla/widget/IMEData.h" #include "nsWindow.h" #include "WinIMEHandler.h" +#include "WinTextEventDispatcherListener.h" namespace mozilla { namespace widget { diff --git a/widget/windows/moz.build b/widget/windows/moz.build index 1da3a5b3d8..a6e4d90807 100644 --- a/widget/windows/moz.build +++ b/widget/windows/moz.build @@ -14,6 +14,7 @@ EXPORTS += [ EXPORTS.mozilla.widget += [ 'AudioSession.h', + 'WinCompositorWidgetProxy.h', 'WinMessages.h', 'WinModifierKeyState.h', 'WinNativeEventData.h', @@ -54,6 +55,7 @@ UNIFIED_SOURCES += [ 'TaskbarTabPreview.cpp', 'TaskbarWindowPreview.cpp', 'WidgetTraceEvent.cpp', + 'WinCompositorWidgetProxy.cpp', 'WindowHook.cpp', 'WinIMEHandler.cpp', 'WinTaskbar.cpp', diff --git a/widget/windows/nsWindow.cpp b/widget/windows/nsWindow.cpp index c65c90cc48..0b7c367ef9 100644 --- a/widget/windows/nsWindow.cpp +++ b/widget/windows/nsWindow.cpp @@ -55,6 +55,7 @@ **************************************************************/ #include "gfx2DGlue.h" +#include "gfxEnv.h" #include "gfxPlatform.h" #include "gfxPrefs.h" #include "mozilla/MathAlgorithms.h" @@ -140,6 +141,7 @@ #include "nsIFrame.h" #include "nsThemeConstants.h" #include "gfxConfig.h" +#include "WinCompositorWidgetProxy.h" #include "nsIGfxInfo.h" #include "nsUXThemeConstants.h" @@ -392,7 +394,6 @@ nsWindow::nsWindow() : nsWindowBase() mIconBig = nullptr; mWnd = nullptr; mPaintDC = nullptr; - mCompositeDC = nullptr; mPrevWndProc = nullptr; mNativeDragTarget = nullptr; mInDtor = false; @@ -427,8 +428,6 @@ nsWindow::nsWindow() : nsWindowBase() mCachedHitTestTime = TimeStamp::Now(); mCachedHitTestResult = 0; #ifdef MOZ_XUL - mTransparentSurface = nullptr; - mMemoryDC = nullptr; mTransparencyMode = eTransparencyOpaque; memset(&mGlassMargins, 0, sizeof mGlassMargins); #endif @@ -1299,7 +1298,9 @@ NS_METHOD nsWindow::Show(bool bState) // Clear contents to avoid ghosting of old content if we display // this window again. if (wasVisible && mTransparencyMode == eTransparencyTransparent) { - ClearTranslucentWindow(); + if (RefPtr proxy = GetCompositorWidgetProxy()) { + proxy->ClearTransparentWindow(); + } } if (mWindowType != eWindowType_dialog) { ::ShowWindow(mWnd, SW_HIDE); @@ -1555,10 +1556,11 @@ NS_METHOD nsWindow::Resize(double aWidth, double aHeight, bool aRepaint) return NS_OK; } -#ifdef MOZ_XUL - if (eTransparencyTransparent == mTransparencyMode) - ResizeTranslucentWindow(width, height); -#endif + if (mTransparencyMode == eTransparencyTransparent) { + if (RefPtr proxy = GetCompositorWidgetProxy()) { + proxy->ResizeTransparentWindow(width, height); + } + } // Set cached value for lightweight and printing mBounds.width = width; @@ -1613,10 +1615,11 @@ NS_METHOD nsWindow::Resize(double aX, double aY, double aWidth, double aHeight, return NS_OK; } -#ifdef MOZ_XUL - if (eTransparencyTransparent == mTransparencyMode) - ResizeTranslucentWindow(width, height); -#endif + if (eTransparencyTransparent == mTransparencyMode) { + if (RefPtr proxy = GetCompositorWidgetProxy()) { + proxy->ResizeTransparentWindow(width, height); + } + } // Set cached value for lightweight and printing mBounds.x = x; @@ -3023,27 +3026,6 @@ nsWindow::MakeFullScreen(bool aFullScreen, nsIScreen* aTargetScreen) return rv; } -HDC nsWindow::GetWindowSurface() -{ -#ifdef MOZ_XUL - return eTransparencyTransparent == mTransparencyMode - ? mMemoryDC - : ::GetDC(mWnd); -#else - return ::GetDC(mWnd); -#endif -} - -void nsWindow::FreeWindowSurface(HDC dc) -{ -#ifdef MOZ_XUL - if (eTransparencyTransparent != mTransparencyMode) - ::ReleaseDC(mWnd, dc); -#else - ::ReleaseDC(mWnd, dc); -#endif -} - /************************************************************** * * SECTION: Native data storage @@ -3464,7 +3446,14 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager, } if (!mLayerManager) { - MOZ_ASSERT(!mCompositorBridgeParent && !mCompositorBridgeChild); + MOZ_ASSERT(!mCompositorSession && !mCompositorBridgeChild); + + // Ensure we have a widget proxy even if we're not using the compositor, + // since that's where we handle transparent windows. + if (!mCompositorWidgetProxy) { + mCompositorWidgetProxy = new WinCompositorWidgetProxy(this); + } + mLayerManager = CreateBasicLayerManager(); } @@ -3525,57 +3514,16 @@ nsWindow::OnDefaultButtonLoaded(const LayoutDeviceIntRect& aButtonRect) return NS_OK; } -already_AddRefed -nsWindow::StartRemoteDrawing() +mozilla::widget::CompositorWidgetProxy* +nsWindow::NewCompositorWidgetProxy() { - MOZ_ASSERT(!mCompositeDC); - HDC dc = GetWindowSurface(); - RefPtr surf; - - if (mTransparencyMode == eTransparencyTransparent) { - if (!mTransparentSurface) { - SetupTranslucentWindowMemoryBitmap(mTransparencyMode); - } - if (mTransparentSurface) { - surf = mTransparentSurface; - } - } - - if (!surf) { - if (!dc) { - return nullptr; - } - uint32_t flags = (mTransparencyMode == eTransparencyOpaque) ? 0 : - gfxWindowsSurface::FLAG_IS_TRANSPARENT; - surf = new gfxWindowsSurface(dc, flags); - } - - mozilla::gfx::IntSize size(surf->GetSize().width, surf->GetSize().height); - if (size.width <= 0 || size.height <= 0) { - if (dc) { - FreeWindowSurface(dc); - } - return nullptr; - } - - MOZ_ASSERT(!mCompositeDC); - mCompositeDC = dc; - - return mozilla::gfx::Factory::CreateDrawTargetForCairoSurface(surf->CairoSurface(), size); + return new WinCompositorWidgetProxy(this); } -void -nsWindow::EndRemoteDrawing() +mozilla::widget::WinCompositorWidgetProxy* +nsWindow::GetCompositorWidgetProxy() { - if (mTransparencyMode == eTransparencyTransparent) { - MOZ_ASSERT(gfxWindowsPlatform::GetPlatform()->IsDirect2DBackend() - || mTransparentSurface); - UpdateTranslucentWindow(); - } - if (mCompositeDC) { - FreeWindowSurface(mCompositeDC); - } - mCompositeDC = nullptr; + return mCompositorWidgetProxy ? mCompositorWidgetProxy->AsWindowsProxy() : nullptr; } void @@ -4786,13 +4734,18 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam, // // To do this we take mPresentLock in nsWindow::PreRender and // if that lock is taken we wait before doing WM_SETTEXT - mPresentLock.Enter(); + RefPtr proxy = GetCompositorWidgetProxy(); + if (proxy) { + proxy->EnterPresentLock(); + } DWORD style = GetWindowLong(mWnd, GWL_STYLE); SetWindowLong(mWnd, GWL_STYLE, style & ~WS_VISIBLE); *aRetValue = CallWindowProcW(GetPrevWindowProc(), mWnd, msg, wParam, lParam); SetWindowLong(mWnd, GWL_STYLE, style); - mPresentLock.Leave(); + if (proxy) { + proxy->LeavePresentLock(); + } return true; } @@ -4808,6 +4761,13 @@ nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam, if (!mCustomNonClient) break; + // There is a case that rendered result is not kept. Bug 1237617 + if (wParam == TRUE && + !gfxEnv::DisableForcePresent() && + gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled()) { + NS_DispatchToMainThread(NewRunnableMethod(this, &nsWindow::ForcePresent)); + } + // let the dwm handle nc painting on glass // Never allow native painting if we are on fullscreen if(mSizeMode != nsSizeMode_Fullscreen && @@ -6037,10 +5997,11 @@ void nsWindow::OnWindowPosChanged(WINDOWPOS* wp) newHeight = r.bottom - r.top; nsIntRect rect(wp->x, wp->y, newWidth, newHeight); -#ifdef MOZ_XUL - if (eTransparencyTransparent == mTransparencyMode) - ResizeTranslucentWindow(newWidth, newHeight); -#endif + if (eTransparencyTransparent == mTransparencyMode) { + if (RefPtr proxy = GetCompositorWidgetProxy()) { + proxy->ResizeTransparentWindow(newWidth, newHeight); + } + } if (newWidth > mLastSize.width) { @@ -6558,11 +6519,9 @@ void nsWindow::OnDestroy() if (mCursor == -1) SetCursor(eCursor_standard); -#ifdef MOZ_XUL - // Reset transparency - if (eTransparencyTransparent == mTransparencyMode) - SetupTranslucentWindowMemoryBitmap(eTransparencyOpaque); -#endif + if (RefPtr proxy = GetCompositorWidgetProxy()) { + proxy->OnDestroyWindow(); + } // Finalize panning feedback to possibly restore window displacement mGesture.PanFeedbackFinalize(mWnd, true); @@ -6845,17 +6804,6 @@ nsWindow::GetAccessible() #ifdef MOZ_XUL -void nsWindow::ResizeTranslucentWindow(int32_t aNewWidth, int32_t aNewHeight, bool force) -{ - if (!force && aNewWidth == mBounds.width && aNewHeight == mBounds.height) - return; - - RefPtr newSurface = - new gfxWindowsSurface(IntSize(aNewWidth, aNewHeight), SurfaceFormat::A8R8G8B8_UINT32); - mTransparentSurface = newSurface; - mMemoryDC = newSurface->GetDC(); -} - void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode) { if (aMode == mTransparencyMode) @@ -6907,57 +6855,12 @@ void nsWindow::SetWindowTranslucencyInner(nsTransparencyMode aMode) memset(&mGlassMargins, 0, sizeof mGlassMargins); mTransparencyMode = aMode; - SetupTranslucentWindowMemoryBitmap(aMode); + if (RefPtr proxy = GetCompositorWidgetProxy()) { + proxy->UpdateTransparency(aMode); + } UpdateGlass(); } -void nsWindow::SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode) -{ - if (eTransparencyTransparent == aMode) { - ResizeTranslucentWindow(mBounds.width, mBounds.height, true); - } else { - mTransparentSurface = nullptr; - mMemoryDC = nullptr; - } -} - -void nsWindow::ClearTranslucentWindow() -{ - if (mTransparentSurface) { - IntSize size = mTransparentSurface->GetSize(); - RefPtr drawTarget = gfxPlatform::GetPlatform()-> - CreateDrawTargetForSurface(mTransparentSurface, size); - drawTarget->ClearRect(Rect(0, 0, size.width, size.height)); - UpdateTranslucentWindow(); - } -} - -nsresult nsWindow::UpdateTranslucentWindow() -{ - if (mBounds.IsEmpty()) - return NS_OK; - - ::GdiFlush(); - - BLENDFUNCTION bf = { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA }; - SIZE winSize = { mBounds.width, mBounds.height }; - POINT srcPos = { 0, 0 }; - HWND hWnd = WinUtils::GetTopLevelHWND(mWnd, true); - RECT winRect; - ::GetWindowRect(hWnd, &winRect); - - // perform the alpha blend - bool updateSuccesful = - ::UpdateLayeredWindow(hWnd, nullptr, (POINT*)&winRect, &winSize, mMemoryDC, - &srcPos, 0, &bf, ULW_ALPHA); - - if (!updateSuccesful) { - return NS_ERROR_FAILURE; - } - - return NS_OK; -} - #endif //MOZ_XUL /************************************************************** @@ -7597,21 +7500,6 @@ void nsWindow::PickerClosed() } } -bool nsWindow::PreRender(LayerManagerComposite*) -{ - // This can block waiting for WM_SETTEXT to finish - // Using PreRender is unnecessarily pessimistic because - // we technically only need to block during the present call - // not all of compositor rendering - mPresentLock.Enter(); - return true; -} - -void nsWindow::PostRender(LayerManagerComposite*) -{ - mPresentLock.Leave(); -} - bool nsWindow::ComputeShouldAccelerate() { diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h index 5791450db6..fba0209130 100644 --- a/widget/windows/nsWindow.h +++ b/widget/windows/nsWindow.h @@ -25,7 +25,6 @@ #include "nsITimer.h" #include "nsRegion.h" #include "mozilla/EventForwards.h" -#include "mozilla/gfx/CriticalSection.h" #include "mozilla/MouseEvents.h" #include "mozilla/TimeStamp.h" #include "nsMargin.h" @@ -59,6 +58,7 @@ namespace mozilla { namespace widget { class NativeKey; struct MSGResult; +class WinCompositorWidgetProxy; } // namespace widget } // namespacw mozilla; @@ -206,8 +206,6 @@ public: NS_IMETHOD GetNonClientMargins(LayoutDeviceIntMargin& aMargins) override; NS_IMETHOD SetNonClientMargins(LayoutDeviceIntMargin& aMargins) override; void SetDrawsInTitlebar(bool aState) override; - already_AddRefed StartRemoteDrawing() override; - virtual void EndRemoteDrawing() override; virtual void UpdateWindowDraggingRegion(const LayoutDeviceIntRegion& aRegion) override; virtual void UpdateThemeGeometries(const nsTArray& aThemeGeometries) override; @@ -310,6 +308,8 @@ public: const mozilla::NativeEventData& aKeyEventData, nsIKeyEventInPluginCallback* aCallback) override; + mozilla::widget::CompositorWidgetProxy* NewCompositorWidgetProxy() override; + protected: virtual ~nsWindow(); @@ -454,17 +454,10 @@ protected: private: void SetWindowTranslucencyInner(nsTransparencyMode aMode); nsTransparencyMode GetWindowTranslucencyInner() const { return mTransparencyMode; } - void ResizeTranslucentWindow(int32_t aNewWidth, int32_t aNewHeight, bool force = false); - nsresult UpdateTranslucentWindow(); - void ClearTranslucentWindow(); - void SetupTranslucentWindowMemoryBitmap(nsTransparencyMode aMode); void UpdateGlass(); protected: #endif // MOZ_XUL - HDC GetWindowSurface(); - void FreeWindowSurface(HDC dc); - static bool IsAsyncResponseEvent(UINT aMsg, LRESULT& aResult); void IPCWindowProcHandler(UINT& msg, WPARAM& wParam, LPARAM& lParam); @@ -481,8 +474,7 @@ protected: void ClearCachedResources(); nsIWidgetListener* GetPaintListener(); - virtual bool PreRender(LayerManagerComposite*) override; - virtual void PostRender(LayerManagerComposite*) override; + mozilla::widget::WinCompositorWidgetProxy* GetCompositorWidgetProxy(); protected: nsCOMPtr mParent; @@ -578,15 +570,11 @@ protected: // Graphics HDC mPaintDC; // only set during painting - HDC mCompositeDC; // only set during StartRemoteDrawing LayoutDeviceIntRect mLastPaintBounds; // Transparency #ifdef MOZ_XUL - // Use layered windows to support full 256 level alpha translucency - RefPtr mTransparentSurface; - HDC mMemoryDC; nsTransparencyMode mTransparencyMode; nsIntRegion mPossiblyTransparentRegion; MARGINS mGlassMargins; @@ -620,8 +608,6 @@ protected: static bool sNeedsToInitMouseWheelSettings; static void InitMouseWheelScrollData(); - mozilla::gfx::CriticalSection mPresentLock; - double mSizeConstraintsScale; // scale in effect when setting constraints }; diff --git a/widget/windows/nsWindowGfx.cpp b/widget/windows/nsWindowGfx.cpp index 96dc80b869..fe4cfb3b0b 100644 --- a/widget/windows/nsWindowGfx.cpp +++ b/widget/windows/nsWindowGfx.cpp @@ -215,12 +215,10 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) ClientLayerManager *clientLayerManager = GetLayerManager()->AsClientLayerManager(); - if (clientLayerManager && mCompositorBridgeParent && - !mBounds.IsEqualEdges(mLastPaintBounds)) - { + if (clientLayerManager && !mBounds.IsEqualEdges(mLastPaintBounds)) { // Do an early async composite so that we at least have something on the // screen in the right place, even if the content is out of date. - mCompositorBridgeParent->ScheduleRenderOnCompositorThread(); + clientLayerManager->Composite(); } mLastPaintBounds = mBounds; @@ -238,7 +236,8 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) ::BeginPaint(mWnd, &ps); ::EndPaint(mWnd, &ps); - aDC = mMemoryDC; + // We're guaranteed to have a widget proxy since we called GetLayerManager(). + aDC = GetCompositorWidgetProxy()->GetTransparentDC(); } #endif @@ -266,7 +265,7 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) #endif nsIntRegion region = GetRegionToPaint(forceRepaint, ps, hDC); - if (clientLayerManager && mCompositorBridgeParent) { + if (clientLayerManager) { // We need to paint to the screen even if nothing changed, since if we // don't have a compositing window manager, our pixels could be stale. clientLayerManager->SetNeedsComposite(true); @@ -283,8 +282,8 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) return false; } - if (clientLayerManager && mCompositorBridgeParent && clientLayerManager->NeedsComposite()) { - mCompositorBridgeParent->ScheduleRenderOnCompositorThread(); + if (clientLayerManager && clientLayerManager->NeedsComposite()) { + clientLayerManager->Composite(); clientLayerManager->SetNeedsComposite(false); } @@ -310,10 +309,7 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) #if defined(MOZ_XUL) // don't support transparency for non-GDI rendering, for now if (eTransparencyTransparent == mTransparencyMode) { - if (mTransparentSurface == nullptr) { - SetupTranslucentWindowMemoryBitmap(mTransparencyMode); - } - targetSurface = mTransparentSurface; + targetSurface = GetCompositorWidgetProxy()->EnsureTransparentSurface(); } #endif @@ -378,7 +374,7 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) // Data from offscreen drawing surface was copied to memory bitmap of transparent // bitmap. Now it can be read from memory bitmap to apply alpha channel and after // that displayed on the screen. - UpdateTranslucentWindow(); + GetCompositorWidgetProxy()->RedrawTransparentWindow(); } #endif } @@ -389,7 +385,7 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) this, LayoutDeviceIntRegion::FromUnknownRegion(region)); if (!gfxEnv::DisableForcePresent() /*&& gfxWindowsPlatform::GetPlatform()->DwmCompositionEnabled()*/) { nsCOMPtr event = - NS_NewRunnableMethod(this, &nsWindow::ForcePresent); + NewRunnableMethod(this, &nsWindow::ForcePresent); NS_DispatchToMainThread(event); } } diff --git a/xpcom/base/nsDumpUtils.cpp b/xpcom/base/nsDumpUtils.cpp index b9d9eb4f5c..33dceb47c6 100644 --- a/xpcom/base/nsDumpUtils.cpp +++ b/xpcom/base/nsDumpUtils.cpp @@ -74,8 +74,7 @@ FdWatcher::Init() nsCOMPtr os = services::GetObserverService(); os->AddObserver(this, "xpcom-shutdown", /* ownsWeak = */ false); - XRE_GetIOMessageLoop()->PostTask( - NewRunnableMethod(this, &FdWatcher::StartWatching)); + XRE_GetIOMessageLoop()->PostTask(NewRunnableMethod(this, &FdWatcher::StartWatching)); } // Implementations may call this function multiple times if they ensure that diff --git a/xpcom/base/nsDumpUtils.h b/xpcom/base/nsDumpUtils.h index 46951f59f8..12a99da18d 100644 --- a/xpcom/base/nsDumpUtils.h +++ b/xpcom/base/nsDumpUtils.h @@ -89,8 +89,7 @@ public: MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(!strcmp(aTopic, "xpcom-shutdown")); - XRE_GetIOMessageLoop()->PostTask( - NewRunnableMethod(this, &FdWatcher::StopWatching)); + XRE_GetIOMessageLoop()->PostTask(mozilla::NewRunnableMethod(this, &FdWatcher::StopWatching)); return NS_OK; } diff --git a/xpcom/base/nsMemoryReporterManager.cpp b/xpcom/base/nsMemoryReporterManager.cpp index c48c18a59c..026c73c0e2 100644 --- a/xpcom/base/nsMemoryReporterManager.cpp +++ b/xpcom/base/nsMemoryReporterManager.cpp @@ -1696,8 +1696,9 @@ nsMemoryReporterManager::GetReportsExtended( aDMDDumpIdent); if (aMinimize) { - rv = MinimizeMemoryUsage(NS_NewRunnableMethod( - this, &nsMemoryReporterManager::StartGettingReports)); + nsCOMPtr callback = + NewRunnableMethod(this, &nsMemoryReporterManager::StartGettingReports); + rv = MinimizeMemoryUsage(callback); } else { rv = StartGettingReports(); } diff --git a/xpcom/ds/nsObserverService.cpp b/xpcom/ds/nsObserverService.cpp index 42bcff58be..455764811e 100644 --- a/xpcom/ds/nsObserverService.cpp +++ b/xpcom/ds/nsObserverService.cpp @@ -200,9 +200,7 @@ nsObserverService::Create(nsISupports* aOuter, const nsIID& aIID, // The memory reporter can not be immediately registered here because // the nsMemoryReporterManager may attempt to get the nsObserverService // during initialization, causing a recursive GetService. - RefPtr> registerRunnable = - NS_NewRunnableMethod(os, &nsObserverService::RegisterReporter); - NS_DispatchToCurrentThread(registerRunnable); + NS_DispatchToCurrentThread(NewRunnableMethod(os, &nsObserverService::RegisterReporter)); return os->QueryInterface(aIID, aInstancePtr); } diff --git a/xpcom/glue/nsThreadUtils.h b/xpcom/glue/nsThreadUtils.h index b9bb171ab1..0cf96b6219 100644 --- a/xpcom/glue/nsThreadUtils.h +++ b/xpcom/glue/nsThreadUtils.h @@ -283,8 +283,11 @@ nsRunnableFunction* NS_NewRunnableFunction(const Function& aFunction) // with nsRevocableEventPtr. template -class nsRunnableMethod : public mozilla::Runnable + bool Owning = true, + bool Cancelable = false> +class nsRunnableMethod : public mozilla::Conditional::Type { public: virtual void Revoke() = 0; @@ -328,31 +331,60 @@ struct nsRunnableMethodReceiver void Revoke() { mObj = nullptr; } }; -template struct nsRunnableMethodTraits; +template struct nsRunnableMethodTraits; -template -struct nsRunnableMethodTraits +template +struct nsRunnableMethodTraits { typedef C class_type; typedef R return_type; - typedef nsRunnableMethod base_type; + typedef nsRunnableMethod base_type; + static const bool can_cancel = Cancelable; +}; + +template +struct nsRunnableMethodTraits +{ + typedef const C class_type; + typedef R return_type; + typedef nsRunnableMethod base_type; + static const bool can_cancel = Cancelable; }; #ifdef NS_HAVE_STDCALL -template -struct nsRunnableMethodTraits +template +struct nsRunnableMethodTraits { typedef C class_type; typedef R return_type; - typedef nsRunnableMethod base_type; + typedef nsRunnableMethod base_type; + static const bool can_cancel = Cancelable; }; -template -struct nsRunnableMethodTraits +template +struct nsRunnableMethodTraits { typedef C class_type; typedef R return_type; - typedef nsRunnableMethod base_type; + typedef nsRunnableMethod base_type; + static const bool can_cancel = Cancelable; +}; +template +struct nsRunnableMethodTraits +{ + typedef const C class_type; + typedef R return_type; + typedef nsRunnableMethod base_type; + static const bool can_cancel = Cancelable; +}; + +template +struct nsRunnableMethodTraits +{ + typedef const C class_type; + typedef R return_type; + typedef nsRunnableMethod base_type; + static const bool can_cancel = Cancelable; }; #endif @@ -683,11 +715,11 @@ struct nsRunnableMethodArguments } }; -template +template class nsRunnableMethodImpl - : public nsRunnableMethodTraits::base_type + : public nsRunnableMethodTraits::base_type { - typedef typename nsRunnableMethodTraits::class_type + typedef typename nsRunnableMethodTraits::class_type ClassType; nsRunnableMethodReceiver mReceiver; Method mMethod; @@ -710,70 +742,102 @@ public: } return NS_OK; } + nsresult Cancel() { + static_assert(Cancelable, "Don't use me!"); + Revoke(); + return NS_OK; + } void Revoke() { mReceiver.Revoke(); } }; // Use this template function like so: // // nsCOMPtr event = -// NS_NewRunnableMethod(myObject, &MyClass::HandleEvent); +// mozilla::NewRunnableMethod(myObject, &MyClass::HandleEvent); // NS_DispatchToCurrentThread(event); // // Statically enforced constraints: // - myObject must be of (or implicitly convertible to) type MyClass // - MyClass must defined AddRef and Release methods // + +namespace mozilla { + template -typename nsRunnableMethodTraits::base_type* -NS_NewRunnableMethod(PtrType aPtr, Method aMethod) +already_AddRefed::base_type> +NewRunnableMethod(PtrType aPtr, Method aMethod) { - return new nsRunnableMethodImpl(aPtr, aMethod); + return do_AddRef(new nsRunnableMethodImpl(aPtr, aMethod)); } template -typename nsRunnableMethodTraits::base_type* -NS_NewNonOwningRunnableMethod(PtrType&& aPtr, Method aMethod) +already_AddRefed::base_type> +NewCancelableRunnableMethod(PtrType aPtr, Method aMethod) { - return new nsRunnableMethodImpl(aPtr, aMethod); + return do_AddRef(new nsRunnableMethodImpl(aPtr, aMethod)); } -// Similar to NS_NewRunnableMethod. Call like so: -// nsCOMPtr event = -// NS_NewRunnableMethodWithArg(myObject, &MyClass::HandleEvent, myArg); -// 'Type' is the stored type for the argument, see ParameterStorage for details. -template -typename nsRunnableMethodTraits::base_type* -NS_NewRunnableMethodWithArg(PtrType&& aPtr, Method aMethod, Arg&& aArg) +template +already_AddRefed::base_type> +NewNonOwningRunnableMethod(PtrType&& aPtr, Method aMethod) { - return new nsRunnableMethodImpl( - aPtr, aMethod, mozilla::Forward(aArg)); + return do_AddRef(new nsRunnableMethodImpl(aPtr, aMethod)); } -// Similar to NS_NewRunnableMethod. Call like so: +template +already_AddRefed::base_type> +NewNonOwningCancelableRunnableMethod(PtrType&& aPtr, Method aMethod) +{ + return do_AddRef(new nsRunnableMethodImpl(aPtr, aMethod)); +} + +// Similar to NewRunnableMethod. Call like so: // nsCOMPtr event = -// NS_NewRunnableMethodWithArg(myObject, &MyClass::HandleEvent, myArg1,...); +// NewRunnableMethod(myObject, &MyClass::HandleEvent, myArg1,...); // 'Types' are the stored type for each argument, see ParameterStorage for details. template -typename nsRunnableMethodTraits::base_type* -NS_NewRunnableMethodWithArgs(PtrType&& aPtr, Method aMethod, Args&&... aArgs) +already_AddRefed::base_type> +NewRunnableMethod(PtrType&& aPtr, Method aMethod, Args&&... aArgs) { static_assert(sizeof...(Storages) == sizeof...(Args), " size should be equal to number of arguments"); - return new nsRunnableMethodImpl( - aPtr, aMethod, mozilla::Forward(aArgs)...); + return do_AddRef(new nsRunnableMethodImpl( + aPtr, aMethod, mozilla::Forward(aArgs)...)); } template -typename nsRunnableMethodTraits::base_type* -NS_NewNonOwningRunnableMethodWithArgs(PtrType&& aPtr, Method aMethod, - Args&&... aArgs) +already_AddRefed::base_type> +NewNonOwningRunnableMethod(PtrType&& aPtr, Method aMethod, Args&&... aArgs) { static_assert(sizeof...(Storages) == sizeof...(Args), " size should be equal to number of arguments"); - return new nsRunnableMethodImpl( - aPtr, aMethod, mozilla::Forward(aArgs)...); + return do_AddRef(new nsRunnableMethodImpl( + aPtr, aMethod, mozilla::Forward(aArgs)...)); } +template +already_AddRefed::base_type> +NewCancelableRunnableMethod(PtrType&& aPtr, Method aMethod, Args&&... aArgs) +{ + static_assert(sizeof...(Storages) == sizeof...(Args), + " size should be equal to number of arguments"); + return do_AddRef(new nsRunnableMethodImpl( + aPtr, aMethod, mozilla::Forward(aArgs)...)); +} + +template +already_AddRefed::base_type> +NewNonOwningCancelableRunnableMethod(PtrType&& aPtr, Method aMethod, + Args&&... aArgs) +{ + static_assert(sizeof...(Storages) == sizeof...(Args), + " size should be equal to number of arguments"); + return do_AddRef(new nsRunnableMethodImpl( + aPtr, aMethod, mozilla::Forward(aArgs)...)); +} + +} // namespace mozilla + #endif // XPCOM_GLUE_AVOID_NSPR // This class is designed to be used when you have an event class E that has a @@ -837,6 +901,16 @@ public: return *this; } + const nsRevocableEventPtr& operator=(already_AddRefed aEvent) + { + RefPtr event = aEvent; + if (mEvent != event) { + Revoke(); + mEvent = event.forget(); + } + return *this; + } + void Revoke() { if (mEvent) { diff --git a/xpcom/glue/tests/gtest/TestThreadUtils.cpp b/xpcom/glue/tests/gtest/TestThreadUtils.cpp index ac4b9ef0d8..728bae612a 100644 --- a/xpcom/glue/tests/gtest/TestThreadUtils.cpp +++ b/xpcom/glue/tests/gtest/TestThreadUtils.cpp @@ -290,18 +290,18 @@ TEST(ThreadUtils, main) // Test legacy functions. nsCOMPtr r1 = - NS_NewRunnableMethod(rpt, &ThreadUtilsObject::Test0); + NewRunnableMethod(rpt, &ThreadUtilsObject::Test0); r1->Run(); EXPECT_EQ(count += 1, rpt->mCount); - r1 = NS_NewRunnableMethodWithArg(rpt, &ThreadUtilsObject::Test1i, 11); + r1 = NewRunnableMethod(rpt, &ThreadUtilsObject::Test1i, 11); r1->Run(); EXPECT_EQ(count += 2, rpt->mCount); EXPECT_EQ(11, rpt->mA0); // Test variadic function with simple POD arguments. - r1 = NS_NewRunnableMethodWithArgs(rpt, &ThreadUtilsObject::Test0); + r1 = NewRunnableMethod(rpt, &ThreadUtilsObject::Test0); r1->Run(); EXPECT_EQ(count += 1, rpt->mCount); @@ -314,19 +314,19 @@ TEST(ThreadUtils, main) StoreCopyPassByValue>::value, "detail::ParameterStorage>::Type should be StoreCopyPassByValue"); - r1 = NS_NewRunnableMethodWithArgs(rpt, &ThreadUtilsObject::Test1i, 12); + r1 = NewRunnableMethod(rpt, &ThreadUtilsObject::Test1i, 12); r1->Run(); EXPECT_EQ(count += 2, rpt->mCount); EXPECT_EQ(12, rpt->mA0); - r1 = NS_NewRunnableMethodWithArgs( + r1 = NewRunnableMethod( rpt, &ThreadUtilsObject::Test2i, 21, 22); r1->Run(); EXPECT_EQ(count += 3, rpt->mCount); EXPECT_EQ(21, rpt->mA0); EXPECT_EQ(22, rpt->mA1); - r1 = NS_NewRunnableMethodWithArgs( + r1 = NewRunnableMethod( rpt, &ThreadUtilsObject::Test3i, 31, 32, 33); r1->Run(); EXPECT_EQ(count += 4, rpt->mCount); @@ -334,7 +334,7 @@ TEST(ThreadUtils, main) EXPECT_EQ(32, rpt->mA1); EXPECT_EQ(33, rpt->mA2); - r1 = NS_NewRunnableMethodWithArgs( + r1 = NewRunnableMethod( rpt, &ThreadUtilsObject::Test4i, 41, 42, 43, 44); r1->Run(); EXPECT_EQ(count += 5, rpt->mCount); @@ -347,7 +347,7 @@ TEST(ThreadUtils, main) // Passing a short to make sure forwarding works with an inexact type match. short int si = 11; - r1 = NS_NewRunnableMethodWithArgs(rpt, &ThreadUtilsObject::Test1i, si); + r1 = NewRunnableMethod(rpt, &ThreadUtilsObject::Test1i, si); r1->Run(); EXPECT_EQ(count += 2, rpt->mCount); EXPECT_EQ(si, rpt->mA0); @@ -373,7 +373,7 @@ TEST(ThreadUtils, main) "detail::ParameterStorage::Type::passed_type should be int*"); { int i = 12; - r1 = NS_NewRunnableMethodWithArgs(rpt, &ThreadUtilsObject::Test1pi, &i); + r1 = NewRunnableMethod(rpt, &ThreadUtilsObject::Test1pi, &i); r1->Run(); EXPECT_EQ(count += 2, rpt->mCount); EXPECT_EQ(i, rpt->mA0); @@ -400,7 +400,7 @@ TEST(ThreadUtils, main) "detail::ParameterStorage::Type::passed_type should be const int*"); { int i = 1201; - r1 = NS_NewRunnableMethodWithArgs(rpt, &ThreadUtilsObject::Test1pci, &i); + r1 = NewRunnableMethod(rpt, &ThreadUtilsObject::Test1pci, &i); r1->Run(); EXPECT_EQ(count += 2, rpt->mCount); EXPECT_EQ(i, rpt->mA0); @@ -415,7 +415,7 @@ TEST(ThreadUtils, main) "StoreCopyPassByPtr::passed_type should be int*"); { int i = 1202; - r1 = NS_NewRunnableMethodWithArgs>( + r1 = NewRunnableMethod>( rpt, &ThreadUtilsObject::Test1pi, i); r1->Run(); EXPECT_EQ(count += 2, rpt->mCount); @@ -431,7 +431,7 @@ TEST(ThreadUtils, main) "StoreCopyPassByConstPtr::passed_type should be const int*"); { int i = 1203; - r1 = NS_NewRunnableMethodWithArgs>( + r1 = NewRunnableMethod>( rpt, &ThreadUtilsObject::Test1pci, i); r1->Run(); EXPECT_EQ(count += 2, rpt->mCount); @@ -491,7 +491,7 @@ TEST(ThreadUtils, main) "ParameterStorage::Type::passed_type should be int&"); { int i = 13; - r1 = NS_NewRunnableMethodWithArgs(rpt, &ThreadUtilsObject::Test1ri, i); + r1 = NewRunnableMethod(rpt, &ThreadUtilsObject::Test1ri, i); r1->Run(); EXPECT_EQ(count += 2, rpt->mCount); EXPECT_EQ(i, rpt->mA0); @@ -512,7 +512,7 @@ TEST(ThreadUtils, main) "ParameterStorage::Type::passed_type should be int&&"); { int i = 14; - r1 = NS_NewRunnableMethodWithArgs( + r1 = NewRunnableMethod( rpt, &ThreadUtilsObject::Test1rri, mozilla::Move(i)); } r1->Run(); @@ -534,7 +534,7 @@ TEST(ThreadUtils, main) "ParameterStorage&&>::Type::passed_type should be UniquePtr&&"); { mozilla::UniquePtr upi; - r1 = NS_NewRunnableMethodWithArgs&&>( + r1 = NewRunnableMethod&&>( rpt, &ThreadUtilsObject::Test1upi, mozilla::Move(upi)); } r1->Run(); @@ -557,7 +557,7 @@ TEST(ThreadUtils, main) "ParameterStorage>>::Type::passed_type should be UniquePtr&&"); { mozilla::UniquePtr upi; - r1 = NS_NewRunnableMethodWithArgs + r1 = NewRunnableMethod >>( rpt, &ThreadUtilsObject::Test1upi, mozilla::Move(upi)); } @@ -568,7 +568,7 @@ TEST(ThreadUtils, main) // Unique pointer as xvalue. { mozilla::UniquePtr upi = mozilla::MakeUnique(1); - r1 = NS_NewRunnableMethodWithArgs&&>( + r1 = NewRunnableMethod&&>( rpt, &ThreadUtilsObject::Test1upi, mozilla::Move(upi)); } r1->Run(); @@ -577,7 +577,7 @@ TEST(ThreadUtils, main) { mozilla::UniquePtr upi = mozilla::MakeUnique(1); - r1 = NS_NewRunnableMethodWithArgs + r1 = NewRunnableMethod >> (rpt, &ThreadUtilsObject::Test1upi, mozilla::Move(upi)); } @@ -586,7 +586,7 @@ TEST(ThreadUtils, main) EXPECT_EQ(1, rpt->mA0); // Unique pointer as prvalue. - r1 = NS_NewRunnableMethodWithArgs&&>( + r1 = NewRunnableMethod&&>( rpt, &ThreadUtilsObject::Test1upi, mozilla::MakeUnique(2)); r1->Run(); EXPECT_EQ(count += 2, rpt->mCount); @@ -595,7 +595,7 @@ TEST(ThreadUtils, main) // Unique pointer as lvalue to lref. { mozilla::UniquePtr upi; - r1 = NS_NewRunnableMethodWithArgs&>( + r1 = NewRunnableMethod&>( rpt, &ThreadUtilsObject::Test1rupi, upi); // Passed as lref, so Run() must be called while local upi is still alive! r1->Run(); @@ -614,8 +614,8 @@ TEST(ThreadUtils, main) Spy s(10); EXPECT_EQ(1, gConstructions); EXPECT_EQ(1, gAlive); - if (gDebug) { printf("%d - r2 = NS_NewRunnableMethodWithArgs>(&TestByValue, s)\n", __LINE__); } - r2 = NS_NewRunnableMethodWithArgs>( + if (gDebug) { printf("%d - r2 = NewRunnableMethod>(&TestByValue, s)\n", __LINE__); } + r2 = NewRunnableMethod>( rpt, &ThreadUtilsObject::TestByValue, s); EXPECT_EQ(2, gAlive); EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction. @@ -641,9 +641,9 @@ TEST(ThreadUtils, main) Spy::ClearAll(); if (gDebug) { printf("%d - Test: Store copy from prvalue, pass by value\n", __LINE__); } { - if (gDebug) { printf("%d - r3 = NS_NewRunnableMethodWithArgs>(&TestByValue, Spy(11))\n", __LINE__); } + if (gDebug) { printf("%d - r3 = NewRunnableMethod>(&TestByValue, Spy(11))\n", __LINE__); } nsCOMPtr r3 = - NS_NewRunnableMethodWithArgs>( + NewRunnableMethod>( rpt, &ThreadUtilsObject::TestByValue, Spy(11)); EXPECT_EQ(1, gAlive); EXPECT_EQ(1, gConstructions); @@ -670,7 +670,7 @@ TEST(ThreadUtils, main) EXPECT_EQ(1, gConstructions); EXPECT_EQ(1, gAlive); Spy::ClearActions(); - r4 = NS_NewRunnableMethodWithArgs>( + r4 = NewRunnableMethod>( rpt, &ThreadUtilsObject::TestByValue, mozilla::Move(s)); EXPECT_LE(1, gMoveConstructions); EXPECT_EQ(1, gAlive); @@ -701,8 +701,8 @@ TEST(ThreadUtils, main) Spy s(20); EXPECT_EQ(1, gConstructions); EXPECT_EQ(1, gAlive); - if (gDebug) { printf("%d - r5 = NS_NewRunnableMethodWithArgs>(&TestByConstLRef, s)\n", __LINE__); } - r5 = NS_NewRunnableMethodWithArgs>( + if (gDebug) { printf("%d - r5 = NewRunnableMethod>(&TestByConstLRef, s)\n", __LINE__); } + r5 = NewRunnableMethod>( rpt, &ThreadUtilsObject::TestByConstLRef, s); EXPECT_EQ(2, gAlive); EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction. @@ -728,9 +728,9 @@ TEST(ThreadUtils, main) Spy::ClearAll(); if (gDebug) { printf("%d - Test: Store copy from prvalue, pass by const lvalue ref\n", __LINE__); } { - if (gDebug) { printf("%d - r6 = NS_NewRunnableMethodWithArgs>(&TestByConstLRef, Spy(21))\n", __LINE__); } + if (gDebug) { printf("%d - r6 = NewRunnableMethod>(&TestByConstLRef, Spy(21))\n", __LINE__); } nsCOMPtr r6 = - NS_NewRunnableMethodWithArgs>( + NewRunnableMethod>( rpt, &ThreadUtilsObject::TestByConstLRef, Spy(21)); EXPECT_EQ(1, gAlive); EXPECT_EQ(1, gConstructions); @@ -758,8 +758,8 @@ TEST(ThreadUtils, main) Spy s(30); EXPECT_EQ(1, gConstructions); EXPECT_EQ(1, gAlive); - if (gDebug) { printf("%d - r7 = NS_NewRunnableMethodWithArgs>(&TestByRRef, s)\n", __LINE__); } - r7 = NS_NewRunnableMethodWithArgs>( + if (gDebug) { printf("%d - r7 = NewRunnableMethod>(&TestByRRef, s)\n", __LINE__); } + r7 = NewRunnableMethod>( rpt, &ThreadUtilsObject::TestByRRef, s); EXPECT_EQ(2, gAlive); EXPECT_LE(1, gCopyConstructions); // At least 1 copy-construction. @@ -786,9 +786,9 @@ TEST(ThreadUtils, main) Spy::ClearAll(); if (gDebug) { printf("%d - Test: Store copy from prvalue, pass by rvalue ref\n", __LINE__); } { - if (gDebug) { printf("%d - r8 = NS_NewRunnableMethodWithArgs>(&TestByRRef, Spy(31))\n", __LINE__); } + if (gDebug) { printf("%d - r8 = NewRunnableMethod>(&TestByRRef, Spy(31))\n", __LINE__); } nsCOMPtr r8 = - NS_NewRunnableMethodWithArgs>( + NewRunnableMethod>( rpt, &ThreadUtilsObject::TestByRRef, Spy(31)); EXPECT_EQ(1, gAlive); EXPECT_EQ(1, gConstructions); @@ -816,9 +816,9 @@ TEST(ThreadUtils, main) EXPECT_EQ(1, gConstructions); EXPECT_EQ(1, gAlive); Spy::ClearActions(); - if (gDebug) { printf("%d - r9 = NS_NewRunnableMethodWithArgs(&TestByLRef, s)\n", __LINE__); } + if (gDebug) { printf("%d - r9 = NewRunnableMethod(&TestByLRef, s)\n", __LINE__); } nsCOMPtr r9 = - NS_NewRunnableMethodWithArgs( + NewRunnableMethod( rpt, &ThreadUtilsObject::TestByLRef, s); EXPECT_EQ(0, gAllConstructions); EXPECT_EQ(0, gDestructions); @@ -849,8 +849,8 @@ TEST(ThreadUtils, main) ptr = s.get(); EXPECT_EQ(1, gConstructions); EXPECT_EQ(1, gAlive); - if (gDebug) { printf("%d - r10 = NS_NewRunnableMethodWithArgs>(&TestByRRef, s.get())\n", __LINE__); } - r10 = NS_NewRunnableMethodWithArgs>( + if (gDebug) { printf("%d - r10 = NewRunnableMethod>(&TestByRRef, s.get())\n", __LINE__); } + r10 = NewRunnableMethod>( rpt, &ThreadUtilsObject::TestByPointer, s.get()); EXPECT_LE(0, gAllConstructions); EXPECT_EQ(1, gAlive); @@ -882,9 +882,9 @@ TEST(ThreadUtils, main) EXPECT_EQ(1, gConstructions); EXPECT_EQ(1, gAlive); Spy::ClearActions(); - if (gDebug) { printf("%d - r11 = NS_NewRunnableMethodWithArgs(&TestByPointer, s)\n", __LINE__); } + if (gDebug) { printf("%d - r11 = NewRunnableMethod(&TestByPointer, s)\n", __LINE__); } nsCOMPtr r11 = - NS_NewRunnableMethodWithArgs( + NewRunnableMethod( rpt, &ThreadUtilsObject::TestByPointer, &s); EXPECT_EQ(0, gAllConstructions); EXPECT_EQ(0, gDestructions); @@ -912,9 +912,9 @@ TEST(ThreadUtils, main) EXPECT_EQ(1, gConstructions); EXPECT_EQ(1, gAlive); Spy::ClearActions(); - if (gDebug) { printf("%d - r12 = NS_NewRunnableMethodWithArgs(&TestByPointer, s)\n", __LINE__); } + if (gDebug) { printf("%d - r12 = NewRunnableMethod(&TestByPointer, s)\n", __LINE__); } nsCOMPtr r12 = - NS_NewRunnableMethodWithArgs( + NewRunnableMethod( rpt, &ThreadUtilsObject::TestByPointerToConst, &s); EXPECT_EQ(0, gAllConstructions); EXPECT_EQ(0, gDestructions); diff --git a/xpcom/tests/TestThreadUtils.cpp b/xpcom/tests/TestThreadUtils.cpp index e26f9d6821..5219338275 100644 --- a/xpcom/tests/TestThreadUtils.cpp +++ b/xpcom/tests/TestThreadUtils.cpp @@ -5,8 +5,11 @@ #include "TestHarness.h" #include "nsThreadUtils.h" +using namespace mozilla; + enum { TEST_CALL_VOID_ARG_VOID_RETURN, + TEST_CALL_VOID_ARG_VOID_RETURN_CONST, TEST_CALL_VOID_ARG_NONVOID_RETURN, TEST_CALL_NONVOID_ARG_VOID_RETURN, TEST_CALL_NONVOID_ARG_NONVOID_RETURN, @@ -63,6 +66,9 @@ public: void DoBar1(void) { gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN] = true; } + void DoBar1Const(void) const { + gRunnableExecuted[TEST_CALL_VOID_ARG_VOID_RETURN_CONST] = true; + } nsresult DoBar2(void) { gRunnableExecuted[TEST_CALL_VOID_ARG_NONVOID_RETURN] = true; return NS_OK; @@ -120,6 +126,7 @@ int main(int argc, char** argv) { RefPtr foo = new nsFoo(); RefPtr bar = new nsBar(); + RefPtr constBar = bar; // This pointer will be freed at the end of the block // Do not dereference this pointer in the runnable method! @@ -128,23 +135,24 @@ int main(int argc, char** argv) // Read only string. Dereferencing in runnable method to check this works. char* message = (char*)"Test message"; - NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar1)); - NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar2)); - NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< RefPtr > + NS_DispatchToMainThread(NewRunnableMethod(bar, &nsBar::DoBar1)); + NS_DispatchToMainThread(NewRunnableMethod(constBar, &nsBar::DoBar1Const)); + NS_DispatchToMainThread(NewRunnableMethod(bar, &nsBar::DoBar2)); + NS_DispatchToMainThread(NewRunnableMethod> (bar, &nsBar::DoBar3, foo)); - NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< RefPtr > + NS_DispatchToMainThread(NewRunnableMethod> (bar, &nsBar::DoBar4, foo)); - NS_DispatchToMainThread(NS_NewRunnableMethodWithArg(bar, &nsBar::DoBar5, rawFoo)); - NS_DispatchToMainThread(NS_NewRunnableMethodWithArg(bar, &nsBar::DoBar6, message)); + NS_DispatchToMainThread(NewRunnableMethod(bar, &nsBar::DoBar5, rawFoo)); + NS_DispatchToMainThread(NewRunnableMethod(bar, &nsBar::DoBar6, message)); #ifdef HAVE_STDCALL - NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar1std)); - NS_DispatchToMainThread(NS_NewRunnableMethod(bar, &nsBar::DoBar2std)); - NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< RefPtr > + NS_DispatchToMainThread(NewRunnableMethod(bar, &nsBar::DoBar1std)); + NS_DispatchToMainThread(NewRunnableMethod(bar, &nsBar::DoBar2std)); + NS_DispatchToMainThread(NewRunnableMethod> (bar, &nsBar::DoBar3std, foo)); - NS_DispatchToMainThread(NS_NewRunnableMethodWithArg< RefPtr > + NS_DispatchToMainThread(NewRunnableMethod> (bar, &nsBar::DoBar4std, foo)); - NS_DispatchToMainThread(NS_NewRunnableMethodWithArg(bar, &nsBar::DoBar5std, rawFoo)); - NS_DispatchToMainThread(NS_NewRunnableMethodWithArg(bar, &nsBar::DoBar6std, message)); + NS_DispatchToMainThread(NewRunnableMethod(bar, &nsBar::DoBar5std, rawFoo)); + NS_DispatchToMainThread(NewRunnableMethod(bar, &nsBar::DoBar6std, message)); #endif } diff --git a/xpcom/threads/AbstractThread.cpp b/xpcom/threads/AbstractThread.cpp index 1aa8b4bd4d..a337efd9d4 100644 --- a/xpcom/threads/AbstractThread.cpp +++ b/xpcom/threads/AbstractThread.cpp @@ -88,7 +88,7 @@ public: if (!mTailDispatcher.isSome()) { mTailDispatcher.emplace(/* aIsTailDispatcher = */ true); - nsCOMPtr event = NS_NewRunnableMethod(this, &XPCOMThreadWrapper::FireTailDispatcher); + nsCOMPtr event = NewRunnableMethod(this, &XPCOMThreadWrapper::FireTailDispatcher); nsContentUtils::RunInStableState(event.forget()); } @@ -105,11 +105,19 @@ private: bool AbstractThread::RequiresTailDispatch(AbstractThread* aThread) const { + MOZ_ASSERT(aThread); // We require tail dispatch if both the source and destination // threads support it. return SupportsTailDispatch() && aThread->SupportsTailDispatch(); } +bool +AbstractThread::RequiresTailDispatchFromCurrentThread() const +{ + AbstractThread* current = GetCurrent(); + return current && RequiresTailDispatch(current); +} + AbstractThread* AbstractThread::MainThread() { diff --git a/xpcom/threads/AbstractThread.h b/xpcom/threads/AbstractThread.h index 7607ffd106..c3938ee29b 100644 --- a/xpcom/threads/AbstractThread.h +++ b/xpcom/threads/AbstractThread.h @@ -72,6 +72,7 @@ public: // Returns true if this thread requires all dispatches originating from // aThread go through the tail dispatcher. bool RequiresTailDispatch(AbstractThread* aThread) const; + bool RequiresTailDispatchFromCurrentThread() const; virtual TaskQueue* AsTaskQueue() { MOZ_CRASH("Not a task queue!"); } virtual nsIThread* AsXPCOMThread() { MOZ_CRASH("Not an XPCOM thread!"); } diff --git a/xpcom/threads/LazyIdleThread.cpp b/xpcom/threads/LazyIdleThread.cpp index 43d8857aa1..535a48a8e4 100644 --- a/xpcom/threads/LazyIdleThread.cpp +++ b/xpcom/threads/LazyIdleThread.cpp @@ -163,7 +163,7 @@ LazyIdleThread::EnsureThread() } nsCOMPtr runnable = - NS_NewRunnableMethod(this, &LazyIdleThread::InitThread); + NewRunnableMethod(this, &LazyIdleThread::InitThread); if (NS_WARN_IF(!runnable)) { return NS_ERROR_UNEXPECTED; } @@ -291,7 +291,7 @@ LazyIdleThread::ShutdownThread() #endif nsCOMPtr runnable = - NS_NewRunnableMethod(this, &LazyIdleThread::CleanupThread); + NewRunnableMethod(this, &LazyIdleThread::CleanupThread); if (NS_WARN_IF(!runnable)) { return NS_ERROR_UNEXPECTED; } @@ -368,7 +368,7 @@ LazyIdleThread::Release() mRefCnt = 1; nsCOMPtr runnable = - NS_NewNonOwningRunnableMethod(this, &LazyIdleThread::SelfDestruct); + NewNonOwningRunnableMethod(this, &LazyIdleThread::SelfDestruct); NS_WARN_IF_FALSE(runnable, "Couldn't make runnable!"); if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) { @@ -561,7 +561,7 @@ LazyIdleThread::AfterProcessNextEvent(nsIThreadInternal* /* aThread */, if (shouldNotifyIdle) { nsCOMPtr runnable = - NS_NewRunnableMethod(this, &LazyIdleThread::ScheduleTimer); + NewRunnableMethod(this, &LazyIdleThread::ScheduleTimer); if (NS_WARN_IF(!runnable)) { return NS_ERROR_UNEXPECTED; } diff --git a/xpcom/threads/MozPromise.h b/xpcom/threads/MozPromise.h index 5e317312d2..21813b304b 100644 --- a/xpcom/threads/MozPromise.h +++ b/xpcom/threads/MozPromise.h @@ -792,7 +792,7 @@ public: // Provide a Monitor that should always be held when accessing this instance. void SetMonitor(Monitor* aMonitor) { mMonitor = aMonitor; } - bool IsEmpty() + bool IsEmpty() const { if (mMonitor) { mMonitor->AssertCurrentThreadOwns(); diff --git a/xpcom/threads/SharedThreadPool.cpp b/xpcom/threads/SharedThreadPool.cpp index 4944e6fc68..004a352135 100644 --- a/xpcom/threads/SharedThreadPool.cpp +++ b/xpcom/threads/SharedThreadPool.cpp @@ -141,10 +141,9 @@ NS_IMETHODIMP_(MozExternalRefCountType) SharedThreadPool::Release(void) MOZ_ASSERT(!sPools->Get(mName)); // Dispatch an event to the main thread to call Shutdown() on - // the nsIThreadPool. The Runnable here will add a refcount to the pool, + // the nsIThreadPool. The Runnable here will add a refcount to the pool, // and when the Runnable releases the nsIThreadPool it will be deleted. - nsCOMPtr r = NS_NewRunnableMethod(mPool, &nsIThreadPool::Shutdown); - NS_DispatchToMainThread(r); + NS_DispatchToMainThread(NewRunnableMethod(mPool, &nsIThreadPool::Shutdown)); // Stabilize refcount, so that if something in the dtor QIs, it won't explode. mRefCnt = 1; diff --git a/xpcom/threads/StateMirroring.h b/xpcom/threads/StateMirroring.h index bcb65fea38..d004b6983a 100644 --- a/xpcom/threads/StateMirroring.h +++ b/xpcom/threads/StateMirroring.h @@ -152,9 +152,9 @@ private: { MIRROR_LOG("%s [%p] Disconnecting all mirrors", mName, this); for (size_t i = 0; i < mMirrors.Length(); ++i) { - nsCOMPtr r = - NS_NewRunnableMethod(mMirrors[i], &AbstractMirror::NotifyDisconnected); - mMirrors[i]->OwnerThread()->Dispatch(r.forget(), AbstractThread::DontAssertDispatchSuccess); + mMirrors[i]->OwnerThread()->Dispatch(NewRunnableMethod(mMirrors[i], + &AbstractMirror::NotifyDisconnected), + AbstractThread::DontAssertDispatchSuccess); } mMirrors.Clear(); } @@ -191,8 +191,7 @@ private: // we can avoid sending multiple updates, and possibly avoid sending any // updates at all if the value ends up where it started. if (!alreadyNotifying) { - nsCOMPtr r = NS_NewRunnableMethod(this, &Impl::DoNotify); - AbstractThread::DispatchDirectTask(r.forget()); + AbstractThread::DispatchDirectTask(NewRunnableMethod(this, &Impl::DoNotify)); } } @@ -223,9 +222,7 @@ private: already_AddRefed MakeNotifier(AbstractMirror* aMirror) { - nsCOMPtr r = - NS_NewRunnableMethodWithArg(aMirror, &AbstractMirror::UpdateValue, mValue); - return r.forget(); + return NewRunnableMethod(aMirror, &AbstractMirror::UpdateValue, mValue);; } T mValue; @@ -328,7 +325,7 @@ private: MOZ_ASSERT(!IsConnected()); MOZ_ASSERT(OwnerThread()->RequiresTailDispatch(aCanonical->OwnerThread()), "Can't get coherency without tail dispatch"); - nsCOMPtr r = NS_NewRunnableMethodWithArg>> + nsCOMPtr r = NewRunnableMethod>> (aCanonical, &AbstractCanonical::AddMirror, this); aCanonical->OwnerThread()->Dispatch(r.forget(), AbstractThread::DontAssertDispatchSuccess); mCanonical = aCanonical; @@ -343,7 +340,7 @@ private: } MIRROR_LOG("%s [%p] Disconnecting from %p", mName, this, mCanonical.get()); - nsCOMPtr r = NS_NewRunnableMethodWithArg>> + nsCOMPtr r = NewRunnableMethod>> (mCanonical, &AbstractCanonical::RemoveMirror, this); mCanonical->OwnerThread()->Dispatch(r.forget(), AbstractThread::DontAssertDispatchSuccess); mCanonical = nullptr; diff --git a/xpcom/threads/StateWatching.h b/xpcom/threads/StateWatching.h index 3ad8c21840..a5543120b6 100644 --- a/xpcom/threads/StateWatching.h +++ b/xpcom/threads/StateWatching.h @@ -255,8 +255,7 @@ private: mStrongRef = mOwner; // Hold the owner alive while notifying. // Queue up our notification jobs to run in a stable state. - nsCOMPtr r = NS_NewRunnableMethod(this, &PerCallbackWatcher::DoNotify); - mOwnerThread->TailDispatcher().AddDirectTask(r.forget()); + mOwnerThread->TailDispatcher().AddDirectTask(NewRunnableMethod(this, &PerCallbackWatcher::DoNotify)); } bool CallbackMethodIs(CallbackMethod aMethod) const diff --git a/xpcom/threads/SyncRunnable.h b/xpcom/threads/SyncRunnable.h index 9c493d9dcc..7b77dcd8a5 100644 --- a/xpcom/threads/SyncRunnable.h +++ b/xpcom/threads/SyncRunnable.h @@ -8,6 +8,7 @@ #define mozilla_SyncRunnable_h #include "nsThreadUtils.h" +#include "mozilla/AbstractThread.h" #include "mozilla/Monitor.h" namespace mozilla { @@ -61,6 +62,24 @@ public: } } + void DispatchToThread(AbstractThread* aThread, bool aForceDispatch = false) + { + if (!aForceDispatch && aThread->IsCurrentThreadIn()) { + mRunnable->Run(); + return; + } + + // Check we don't have tail dispatching here. Otherwise we will deadlock + // ourself when spinning the loop below. + MOZ_ASSERT(!aThread->RequiresTailDispatchFromCurrentThread()); + + aThread->Dispatch(RefPtr(this).forget()); + mozilla::MonitorAutoLock lock(mMonitor); + while (!mDone) { + lock.Wait(); + } + } + static void DispatchToThread(nsIEventTarget* aThread, nsIRunnable* aRunnable, bool aForceDispatch = false) @@ -69,6 +88,14 @@ public: s->DispatchToThread(aThread, aForceDispatch); } + static void DispatchToThread(AbstractThread* aThread, + nsIRunnable* aRunnable, + bool aForceDispatch = false) + { + RefPtr s(new SyncRunnable(aRunnable)); + s->DispatchToThread(aThread, aForceDispatch); + } + protected: NS_IMETHODIMP Run() { diff --git a/xpcom/threads/nsProcessCommon.cpp b/xpcom/threads/nsProcessCommon.cpp index cc2938f635..90585f3267 100644 --- a/xpcom/threads/nsProcessCommon.cpp +++ b/xpcom/threads/nsProcessCommon.cpp @@ -301,9 +301,7 @@ nsProcess::Monitor(void* aArg) if (NS_IsMainThread()) { process->ProcessComplete(); } else { - nsCOMPtr event = - NS_NewRunnableMethod(process, &nsProcess::ProcessComplete); - NS_DispatchToMainThread(event); + NS_DispatchToMainThread(NewRunnableMethod(process, &nsProcess::ProcessComplete)); } } diff --git a/xpcom/threads/nsThreadPool.cpp b/xpcom/threads/nsThreadPool.cpp index 8be613d578..0b4ac6047a 100644 --- a/xpcom/threads/nsThreadPool.cpp +++ b/xpcom/threads/nsThreadPool.cpp @@ -146,9 +146,8 @@ nsThreadPool::ShutdownThread(nsIThread* aThread) // shutdown requires this thread have an event loop (and it may not, see bug // 10204784). The simplest way to cover all cases is to asynchronously // shutdown aThread from the main thread. - nsCOMPtr r = NS_NewRunnableMethod(aThread, - &nsIThread::AsyncShutdown); - NS_DispatchToMainThread(r); + NS_DispatchToMainThread(NewRunnableMethod(aThread, + &nsIThread::AsyncShutdown)); } NS_IMETHODIMP