tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 6dc346b92490dcac3b401a34ad7a346febc75193
parent 01d56417ef9c72252ffe694010c2d7cf96adb2b9
Author: Tom Schuster <tschuster@mozilla.com>
Date:   Mon, 10 Nov 2025 11:36:56 +0000

Bug 1944033 - Load MediaSession artwork in the child. r=media-playback-reviewers,aosmond

Differential Revision: https://phabricator.services.mozilla.com/D271045

Diffstat:
Mdom/media/mediasession/MediaMetadata.cpp | 49+++++++++++++++++++++++++++++++++++++++++++++++++
Mdom/media/mediasession/MediaMetadata.h | 19+++++++++++++++----
Mdom/media/mediasession/MediaSession.cpp | 28++++++++++++++++++++++------
Mdom/media/mediasession/MediaSession.h | 3+++
Mdom/media/mediasession/MediaSessionIPCUtils.h | 15+++++++++++++++
5 files changed, 104 insertions(+), 10 deletions(-)

diff --git a/dom/media/mediasession/MediaMetadata.cpp b/dom/media/mediasession/MediaMetadata.cpp @@ -10,6 +10,7 @@ #include "mozilla/dom/MediaSessionBinding.h" #include "mozilla/dom/ScriptSettings.h" #include "mozilla/dom/ToJSValue.h" +#include "mozilla/image/FetchDecodedImage.h" #include "nsNetUtil.h" namespace mozilla::dom { @@ -120,6 +121,54 @@ void MediaMetadata::SetArtwork(JSContext* aCx, SetArtworkInternal(artwork, aRv); }; +RefPtr<MediaMetadataBasePromise> MediaMetadata::FetchArtwork( + const MediaMetadataBase& aMetadata, nsIPrincipal* aPrincipal, + const size_t aIndex) { + if (!aPrincipal || aIndex >= aMetadata.mArtwork.Length()) { + // No image loaded successfully or no principal, but still resolve without + // any image data. + return MediaMetadataBasePromise::CreateAndResolve(aMetadata, __func__); + } + + nsCOMPtr<nsIURI> uri; + if (NS_WARN_IF(NS_FAILED( + NS_NewURI(getter_AddRefs(uri), aMetadata.mArtwork[aIndex].mSrc)))) { + return FetchArtwork(aMetadata, aPrincipal, aIndex + 1); + } + + return image::FetchDecodedImage(uri, gfx::IntSize{}, aPrincipal) + ->Then( + GetCurrentSerialEventTarget(), __func__, + [metadata = aMetadata, principal = RefPtr{aPrincipal}, + aIndex](already_AddRefed<imgIContainer> aImage) { + nsCOMPtr<imgIContainer> image(std::move(aImage)); + // The promise should only be resolved for decoded images, so using + // FLAG_SYNC_DECODE is just a precaution. + if (RefPtr<mozilla::gfx::SourceSurface> surface = + image->GetFrame(imgIContainer::FRAME_FIRST, + imgIContainer::FLAG_SYNC_DECODE | + imgIContainer::FLAG_ASYNC_NOTIFY)) { + if (RefPtr<mozilla::gfx::DataSourceSurface> dataSurface = + surface->GetDataSurface()) { + MediaMetadataBase data(metadata); + data.mArtwork[aIndex].mDataSurface = dataSurface; + return MediaMetadataBasePromise::CreateAndResolve(data, + __func__); + } + } + return FetchArtwork(metadata, principal, aIndex + 1); + }, + [metadata = aMetadata, principal = RefPtr{aPrincipal}, + aIndex](nsresult aStatus) { + return FetchArtwork(metadata, principal, aIndex + 1); + }); +} + +RefPtr<MediaMetadataBasePromise> MediaMetadata::LoadMetadataArtwork() { + // TODO: Track Promise? + return FetchArtwork(*this, mParent->PrincipalOrNull(), 0); +} + static nsIURI* GetEntryBaseURL() { nsCOMPtr<Document> doc = GetEntryDocument(); return doc ? doc->GetDocBaseURI() : nullptr; diff --git a/dom/media/mediasession/MediaMetadata.h b/dom/media/mediasession/MediaMetadata.h @@ -10,6 +10,7 @@ #include "js/TypeDecls.h" #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/MediaSessionBinding.h" +#include "mozilla/gfx/2D.h" #include "nsCycleCollectionParticipant.h" #include "nsWrapperCache.h" @@ -31,6 +32,9 @@ class MediaImageData { nsString mSizes; nsString mSrc; nsString mType; + // Maybe null, only the first valid artwork is fetched by + // MediaMetadata::FetchArtwork. + RefPtr<mozilla::gfx::DataSourceSurface> mDataSurface; }; class MediaMetadataBase { @@ -49,6 +53,9 @@ class MediaMetadataBase { CopyableTArray<MediaImageData> mArtwork; }; +using MediaMetadataBasePromise = + mozilla::MozPromise<MediaMetadataBase, nsresult, true>; + class MediaMetadata final : public nsISupports, public nsWrapperCache, private MediaMetadataBase { @@ -85,10 +92,10 @@ class MediaMetadata final : public nsISupports, void SetArtwork(JSContext* aCx, const Sequence<JSObject*>& aArtwork, ErrorResult& aRv); - // This would expose MediaMetadataBase's members as public, so use this method - // carefully. Now we only use this when we want to update the metadata to the - // media session controller in the chrome process. - MediaMetadataBase* AsMetadataBase() { return this; } + // This function will always resolve successfully, even when no artwork was + // loaded. + // At most, it returns one decoded image of the artwork. + RefPtr<MediaMetadataBasePromise> LoadMetadataArtwork(); private: MediaMetadata(nsIGlobalObject* aParent, const nsString& aTitle, @@ -101,6 +108,10 @@ class MediaMetadata final : public nsISupports, void SetArtworkInternal(const Sequence<MediaImage>& aArtwork, ErrorResult& aRv); + static RefPtr<MediaMetadataBasePromise> FetchArtwork( + const MediaMetadataBase& aMetadata, nsIPrincipal* aPrincipal, + const size_t aIndex); + nsCOMPtr<nsIGlobalObject> mParent; }; diff --git a/dom/media/mediasession/MediaSession.cpp b/dom/media/mediasession/MediaSession.cpp @@ -87,6 +87,7 @@ void MediaSession::Shutdown() { if (mParent) { SetMediaSessionDocStatus(SessionDocStatus::eInactive); } + mMetadataRequest.DisconnectIfExists(); } void MediaSession::NotifyOwnerDocumentActivityChanged() { @@ -315,13 +316,28 @@ void MediaSession::NotifyMetadataUpdated() { RefPtr<BrowsingContext> currentBC = GetParentObject()->GetBrowsingContext(); MOZ_ASSERT(currentBC, "Update session metadata after context destroyed!"); - Maybe<MediaMetadataBase> metadata; - if (GetMetadata()) { - metadata.emplace(*(GetMetadata()->AsMetadataBase())); - } - if (RefPtr<IMediaInfoUpdater> updater = ContentMediaAgent::Get(currentBC)) { - updater->UpdateMetadata(currentBC->Id(), metadata); + if (!mMediaMetadata) { + if (RefPtr<IMediaInfoUpdater> updater = ContentMediaAgent::Get(currentBC)) { + updater->UpdateMetadata(currentBC->Id(), Nothing()); + } + return; } + + mMetadataRequest.DisconnectIfExists(); + + mMediaMetadata->LoadMetadataArtwork()->Then( + GetCurrentSerialEventTarget(), __func__, + [self = RefPtr{this}, currentBC](MediaMetadataBase&& aMetadata) { + if (RefPtr<IMediaInfoUpdater> updater = + ContentMediaAgent::Get(currentBC)) { + updater->UpdateMetadata(currentBC->Id(), Some(aMetadata)); + } + + self->mMetadataRequest.Complete(); + }, + [](nsresult rv) { + MOZ_ASSERT_UNREACHABLE("LoadMetadataArtwork should always resolve"); + })->Track(mMetadataRequest); } void MediaSession::NotifyEnableSupportedAction(MediaSessionAction aAction) { diff --git a/dom/media/mediasession/MediaSession.h b/dom/media/mediasession/MediaSession.h @@ -131,6 +131,9 @@ class MediaSession final : public nsIDocumentActivity, public nsWrapperCache { Maybe<PositionState> mPositionState; RefPtr<Document> mDoc; SessionDocStatus mSessionDocState = SessionDocStatus::eInactive; + + MozPromiseRequestHolder<mozilla::dom::MediaMetadataBasePromise> + mMetadataRequest; }; } // namespace dom diff --git a/dom/media/mediasession/MediaSessionIPCUtils.h b/dom/media/mediasession/MediaSessionIPCUtils.h @@ -11,6 +11,7 @@ #include "mozilla/dom/BindingIPCUtils.h" #include "mozilla/dom/MediaSession.h" #include "mozilla/dom/MediaSessionBinding.h" +#include "nsContentUtils.h" namespace mozilla { namespace dom { @@ -30,6 +31,12 @@ struct ParamTraits<mozilla::dom::MediaImageData> { WriteParam(aWriter, aParam.mSizes); WriteParam(aWriter, aParam.mSrc); WriteParam(aWriter, aParam.mType); + + mozilla::Maybe<mozilla::dom::IPCImage> image; + if (aParam.mDataSurface) { + image = nsContentUtils::SurfaceToIPCImage(*aParam.mDataSurface); + } + WriteParam(aWriter, std::move(image)); } static bool Read(MessageReader* aReader, paramType* aResult) { @@ -38,6 +45,14 @@ struct ParamTraits<mozilla::dom::MediaImageData> { !ReadParam(aReader, &(aResult->mType))) { return false; } + + mozilla::Maybe<mozilla::dom::IPCImage> image; + if (!ReadParam(aReader, &image)) { + return false; + } + if (image) { + aResult->mDataSurface = nsContentUtils::IPCImageToSurface(*image); + } return true; } };