MediaMetadata.cpp (4944B)
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "mozilla/dom/MediaMetadata.h" 8 9 #include "mozilla/dom/Document.h" 10 #include "mozilla/dom/MediaSessionBinding.h" 11 #include "mozilla/dom/ScriptSettings.h" 12 #include "mozilla/dom/ToJSValue.h" 13 #include "nsNetUtil.h" 14 15 namespace mozilla::dom { 16 17 // Only needed for refcounted objects. 18 NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(MediaMetadata, mParent) 19 NS_IMPL_CYCLE_COLLECTING_ADDREF(MediaMetadata) 20 NS_IMPL_CYCLE_COLLECTING_RELEASE(MediaMetadata) 21 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(MediaMetadata) 22 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 23 NS_INTERFACE_MAP_ENTRY(nsISupports) 24 NS_INTERFACE_MAP_END 25 26 MediaMetadata::MediaMetadata(nsIGlobalObject* aParent, const nsString& aTitle, 27 const nsString& aArtist, const nsString& aAlbum) 28 : MediaMetadataBase(aTitle, aArtist, aAlbum), mParent(aParent) { 29 MOZ_ASSERT(mParent); 30 } 31 32 nsIGlobalObject* MediaMetadata::GetParentObject() const { return mParent; } 33 34 JSObject* MediaMetadata::WrapObject(JSContext* aCx, 35 JS::Handle<JSObject*> aGivenProto) { 36 return MediaMetadata_Binding::Wrap(aCx, this, aGivenProto); 37 } 38 39 already_AddRefed<MediaMetadata> MediaMetadata::Constructor( 40 const GlobalObject& aGlobal, const MediaMetadataInit& aInit, 41 ErrorResult& aRv) { 42 nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(aGlobal.GetAsSupports()); 43 if (!global) { 44 aRv.Throw(NS_ERROR_FAILURE); 45 return nullptr; 46 } 47 48 RefPtr<MediaMetadata> mediaMetadata = 49 new MediaMetadata(global, aInit.mTitle, aInit.mArtist, aInit.mAlbum); 50 mediaMetadata->SetArtworkInternal(aInit.mArtwork, aRv); 51 return aRv.Failed() ? nullptr : mediaMetadata.forget(); 52 } 53 54 void MediaMetadata::GetTitle(nsString& aRetVal) const { aRetVal = mTitle; } 55 56 void MediaMetadata::SetTitle(const nsAString& aTitle) { mTitle = aTitle; } 57 58 void MediaMetadata::GetArtist(nsString& aRetVal) const { aRetVal = mArtist; } 59 60 void MediaMetadata::SetArtist(const nsAString& aArtist) { mArtist = aArtist; } 61 62 void MediaMetadata::GetAlbum(nsString& aRetVal) const { aRetVal = mAlbum; } 63 64 void MediaMetadata::SetAlbum(const nsAString& aAlbum) { mAlbum = aAlbum; } 65 66 void MediaMetadata::GetArtwork(JSContext* aCx, nsTArray<JSObject*>& aRetVal, 67 ErrorResult& aRv) const { 68 // Convert the MediaImages to JS Objects 69 if (!aRetVal.SetCapacity(mArtwork.Length(), fallible)) { 70 aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 71 return; 72 } 73 74 for (size_t i = 0; i < mArtwork.Length(); ++i) { 75 JS::Rooted<JS::Value> value(aCx); 76 if (!ToJSValue(aCx, mArtwork[i], &value)) { 77 aRv.NoteJSContextException(aCx); 78 return; 79 } 80 81 JS::Rooted<JSObject*> object(aCx, &value.toObject()); 82 if (!JS_FreezeObject(aCx, object)) { 83 aRv.NoteJSContextException(aCx); 84 return; 85 } 86 87 aRetVal.AppendElement(object); 88 } 89 } 90 91 void MediaMetadata::SetArtwork(JSContext* aCx, 92 const Sequence<JSObject*>& aArtwork, 93 ErrorResult& aRv) { 94 // Convert the JS Objects to MediaImages 95 Sequence<MediaImage> artwork; 96 if (!artwork.SetCapacity(aArtwork.Length(), fallible)) { 97 aRv.Throw(NS_ERROR_OUT_OF_MEMORY); 98 return; 99 } 100 101 for (JSObject* object : aArtwork) { 102 JS::Rooted<JS::Value> value(aCx, JS::ObjectValue(*object)); 103 104 MediaImage* image = artwork.AppendElement(fallible); 105 MOZ_ASSERT(image, "The capacity is preallocated"); 106 if (!image->Init(aCx, value)) { 107 aRv.NoteJSContextException(aCx); 108 return; 109 } 110 } 111 112 SetArtworkInternal(artwork, aRv); 113 }; 114 115 static nsIURI* GetEntryBaseURL() { 116 nsCOMPtr<Document> doc = GetEntryDocument(); 117 return doc ? doc->GetDocBaseURI() : nullptr; 118 } 119 120 // `aURL` is an inout parameter. 121 static nsresult ResolveURL(nsString& aURL, nsIURI* aBaseURI) { 122 nsCOMPtr<nsIURI> uri; 123 nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, 124 /* UTF-8 for charset */ nullptr, aBaseURI); 125 if (NS_FAILED(rv)) { 126 return rv; 127 } 128 129 nsAutoCString spec; 130 rv = uri->GetSpec(spec); 131 if (NS_FAILED(rv)) { 132 return rv; 133 } 134 135 CopyUTF8toUTF16(spec, aURL); 136 return NS_OK; 137 } 138 139 void MediaMetadata::SetArtworkInternal(const Sequence<MediaImage>& aArtwork, 140 ErrorResult& aRv) { 141 nsTArray<MediaImage> artwork; 142 artwork.Assign(aArtwork); 143 144 nsCOMPtr<nsIURI> baseURI = GetEntryBaseURL(); 145 for (MediaImage& image : artwork) { 146 nsresult rv = ResolveURL(image.mSrc, baseURI); 147 if (NS_WARN_IF(NS_FAILED(rv))) { 148 aRv.ThrowTypeError<MSG_INVALID_URL>(NS_ConvertUTF16toUTF8(image.mSrc)); 149 return; 150 } 151 } 152 mArtwork = std::move(artwork); 153 } 154 155 } // namespace mozilla::dom