diff options
Diffstat (limited to 'dom/media/utils/MediaElementEventRunners.cpp')
-rw-r--r-- | dom/media/utils/MediaElementEventRunners.cpp | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/dom/media/utils/MediaElementEventRunners.cpp b/dom/media/utils/MediaElementEventRunners.cpp new file mode 100644 index 0000000000..57be04528c --- /dev/null +++ b/dom/media/utils/MediaElementEventRunners.cpp @@ -0,0 +1,140 @@ +/* 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 "MediaElementEventRunners.h" + +#include "mozilla/dom/HTMLMediaElement.h" + +extern mozilla::LazyLogModule gMediaElementEventsLog; +#define LOG_EVENT(type, msg) MOZ_LOG(gMediaElementEventsLog, type, msg) + +namespace mozilla::dom { + +nsMediaEventRunner::nsMediaEventRunner(const nsAString& aName, + HTMLMediaElement* aElement, + const nsAString& aEventName) + : mElement(aElement), + mName(aName), + mEventName(aEventName), + mLoadID(mElement->GetCurrentLoadID()) {} + +bool nsMediaEventRunner::IsCancelled() { + return !mElement || mElement->GetCurrentLoadID() != mLoadID; +} + +nsresult nsMediaEventRunner::DispatchEvent(const nsAString& aName) { + return mElement ? mElement->DispatchEvent(aName) : NS_OK; +} + +NS_IMPL_CYCLE_COLLECTION(nsMediaEventRunner, mElement) +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsMediaEventRunner) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsMediaEventRunner) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsMediaEventRunner) + NS_INTERFACE_MAP_ENTRY(nsINamed) + NS_INTERFACE_MAP_ENTRY(nsIRunnable) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRunnable) +NS_INTERFACE_MAP_END + +NS_IMETHODIMP nsAsyncEventRunner::Run() { + // Silently cancel if our load has been cancelled or element has been CCed. + return IsCancelled() ? NS_OK : DispatchEvent(mEventName); +} + +nsResolveOrRejectPendingPlayPromisesRunner:: + nsResolveOrRejectPendingPlayPromisesRunner( + HTMLMediaElement* aElement, nsTArray<RefPtr<PlayPromise>>&& aPromises, + nsresult aError) + : nsMediaEventRunner(u"nsResolveOrRejectPendingPlayPromisesRunner"_ns, + aElement), + mPromises(std::move(aPromises)), + mError(aError) { + mElement->mPendingPlayPromisesRunners.AppendElement(this); +} + +void nsResolveOrRejectPendingPlayPromisesRunner::ResolveOrReject() { + if (NS_SUCCEEDED(mError)) { + PlayPromise::ResolvePromisesWithUndefined(mPromises); + } else { + PlayPromise::RejectPromises(mPromises, mError); + } +} + +NS_IMETHODIMP nsResolveOrRejectPendingPlayPromisesRunner::Run() { + if (!IsCancelled()) { + ResolveOrReject(); + } + + mElement->mPendingPlayPromisesRunners.RemoveElement(this); + return NS_OK; +} + +NS_IMETHODIMP nsNotifyAboutPlayingRunner::Run() { + if (!IsCancelled()) { + DispatchEvent(u"playing"_ns); + } + return nsResolveOrRejectPendingPlayPromisesRunner::Run(); +} + +NS_IMPL_CYCLE_COLLECTION_INHERITED(nsResolveOrRejectPendingPlayPromisesRunner, + nsMediaEventRunner, mPromises) +NS_IMPL_ADDREF_INHERITED(nsResolveOrRejectPendingPlayPromisesRunner, + nsMediaEventRunner) +NS_IMPL_RELEASE_INHERITED(nsResolveOrRejectPendingPlayPromisesRunner, + nsMediaEventRunner) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION( + nsResolveOrRejectPendingPlayPromisesRunner) +NS_INTERFACE_MAP_END_INHERITING(nsMediaEventRunner) + +NS_IMETHODIMP nsSourceErrorEventRunner::Run() { + // Silently cancel if our load has been cancelled. + if (IsCancelled()) { + return NS_OK; + } + LOG_EVENT(LogLevel::Debug, + ("%p Dispatching simple event source error", mElement.get())); + return nsContentUtils::DispatchTrustedEvent(mElement->OwnerDoc(), mSource, + u"error"_ns, CanBubble::eNo, + Cancelable::eNo); +} + +NS_IMPL_CYCLE_COLLECTION_INHERITED(nsSourceErrorEventRunner, nsMediaEventRunner, + mSource) +NS_IMPL_ADDREF_INHERITED(nsSourceErrorEventRunner, nsMediaEventRunner) +NS_IMPL_RELEASE_INHERITED(nsSourceErrorEventRunner, nsMediaEventRunner) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsSourceErrorEventRunner) +NS_INTERFACE_MAP_END_INHERITING(nsMediaEventRunner) + +NS_IMETHODIMP nsTimeupdateRunner::Run() { + if (IsCancelled() || !ShouldDispatchTimeupdate()) { + return NS_OK; + } + // After dispatching `timeupdate`, if the timeupdate event listener takes lots + // of time then we end up spending all time handling just timeupdate events. + // The spec is vague in this situation, so we choose to update time after we + // dispatch the event in order to solve that issue. + nsresult rv = DispatchEvent(mEventName); + if (NS_WARN_IF(NS_FAILED(rv))) { + LOG_EVENT(LogLevel::Debug, + ("%p Failed to dispatch 'timeupdate'", mElement.get())); + } else { + mElement->UpdateLastTimeupdateDispatchTime(); + } + return rv; +} + +bool nsTimeupdateRunner::ShouldDispatchTimeupdate() const { + if (mIsMandatory) { + return true; + } + + // If the main thread is busy, tasks may be delayed and dispatched at + // unexpected times. Ensure we don't dispatch `timeupdate` more often + // than once per `TIMEUPDATE_MS`. + const TimeStamp& lastTime = mElement->LastTimeupdateDispatchTime(); + return lastTime.IsNull() || TimeStamp::Now() - lastTime > + TimeDuration::FromMilliseconds(TIMEUPDATE_MS); +} + +#undef LOG_EVENT +} // namespace mozilla::dom |