BackgroundVideoDecodingPermissionObserver.cpp (5211B)
1 /* vim:set ts=2 sw=2 sts=2 et cindent: */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #include "BackgroundVideoDecodingPermissionObserver.h" 7 8 #include "MediaDecoder.h" 9 #include "mozilla/AsyncEventDispatcher.h" 10 #include "mozilla/Services.h" 11 #include "mozilla/StaticPrefs_media.h" 12 #include "mozilla/dom/BrowsingContext.h" 13 #include "mozilla/dom/Document.h" 14 #include "nsContentUtils.h" 15 #include "nsIObserverService.h" 16 17 namespace mozilla { 18 19 BackgroundVideoDecodingPermissionObserver:: 20 BackgroundVideoDecodingPermissionObserver(MediaDecoder* aDecoder) 21 : mDecoder(aDecoder), mIsRegisteredForEvent(false) { 22 MOZ_ASSERT(mDecoder); 23 } 24 25 NS_IMETHODIMP 26 BackgroundVideoDecodingPermissionObserver::Observe(nsISupports* aSubject, 27 const char* aTopic, 28 const char16_t* aData) { 29 if (!StaticPrefs::media_resume_background_video_on_tabhover()) { 30 return NS_OK; 31 } 32 33 if (!IsValidEventSender(aSubject)) { 34 return NS_OK; 35 } 36 37 if (strcmp(aTopic, "unselected-tab-hover") == 0) { 38 bool allowed = !NS_strcmp(aData, u"true"); 39 mDecoder->SetIsBackgroundVideoDecodingAllowed(allowed); 40 } 41 return NS_OK; 42 } 43 44 void BackgroundVideoDecodingPermissionObserver::RegisterEvent() { 45 MOZ_ASSERT(!mIsRegisteredForEvent); 46 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); 47 if (observerService) { 48 observerService->AddObserver(this, "unselected-tab-hover", false); 49 mIsRegisteredForEvent = true; 50 if (nsContentUtils::IsInStableOrMetaStableState()) { 51 // Events shall not be fired synchronously to prevent anything visible 52 // from the scripts while we are in stable state. 53 if (nsCOMPtr<dom::Document> doc = GetOwnerDoc()) { 54 doc->Dispatch(NewRunnableMethod( 55 "BackgroundVideoDecodingPermissionObserver::EnableEvent", this, 56 &BackgroundVideoDecodingPermissionObserver::EnableEvent)); 57 } 58 } else { 59 EnableEvent(); 60 } 61 } 62 } 63 64 void BackgroundVideoDecodingPermissionObserver::UnregisterEvent() { 65 MOZ_ASSERT(mIsRegisteredForEvent); 66 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService(); 67 if (observerService) { 68 observerService->RemoveObserver(this, "unselected-tab-hover"); 69 mIsRegisteredForEvent = false; 70 mDecoder->SetIsBackgroundVideoDecodingAllowed(false); 71 if (nsContentUtils::IsInStableOrMetaStableState()) { 72 // Events shall not be fired synchronously to prevent anything visible 73 // from the scripts while we are in stable state. 74 if (nsCOMPtr<dom::Document> doc = GetOwnerDoc()) { 75 doc->Dispatch(NewRunnableMethod( 76 "BackgroundVideoDecodingPermissionObserver::DisableEvent", this, 77 &BackgroundVideoDecodingPermissionObserver::DisableEvent)); 78 } 79 } else { 80 DisableEvent(); 81 } 82 } 83 } 84 85 BackgroundVideoDecodingPermissionObserver:: 86 ~BackgroundVideoDecodingPermissionObserver() { 87 MOZ_ASSERT(!mIsRegisteredForEvent); 88 } 89 90 void BackgroundVideoDecodingPermissionObserver::EnableEvent() const { 91 // If we can't get document or outer window, then you can't reach the chrome 92 // <browser> either, so we don't need want to dispatch the event. 93 dom::Document* doc = GetOwnerDoc(); 94 if (!doc || !doc->GetWindow()) { 95 return; 96 } 97 98 RefPtr<AsyncEventDispatcher> asyncDispatcher = 99 new AsyncEventDispatcher(doc, u"UnselectedTabHover:Enable"_ns, 100 CanBubble::eYes, ChromeOnlyDispatch::eYes); 101 asyncDispatcher->PostDOMEvent(); 102 } 103 104 void BackgroundVideoDecodingPermissionObserver::DisableEvent() const { 105 // If we can't get document or outer window, then you can't reach the chrome 106 // <browser> either, so we don't need want to dispatch the event. 107 dom::Document* doc = GetOwnerDoc(); 108 if (!doc || !doc->GetWindow()) { 109 return; 110 } 111 112 RefPtr<AsyncEventDispatcher> asyncDispatcher = 113 new AsyncEventDispatcher(doc, u"UnselectedTabHover:Disable"_ns, 114 CanBubble::eYes, ChromeOnlyDispatch::eYes); 115 asyncDispatcher->PostDOMEvent(); 116 } 117 118 dom::BrowsingContext* BackgroundVideoDecodingPermissionObserver::GetOwnerBC() 119 const { 120 dom::Document* doc = GetOwnerDoc(); 121 return doc ? doc->GetBrowsingContext() : nullptr; 122 } 123 124 dom::Document* BackgroundVideoDecodingPermissionObserver::GetOwnerDoc() const { 125 if (!mDecoder->GetOwner()) { 126 return nullptr; 127 } 128 129 return mDecoder->GetOwner()->GetDocument(); 130 } 131 132 bool BackgroundVideoDecodingPermissionObserver::IsValidEventSender( 133 nsISupports* aSubject) const { 134 nsCOMPtr<nsPIDOMWindowInner> senderInner(do_QueryInterface(aSubject)); 135 if (!senderInner) { 136 return false; 137 } 138 139 RefPtr<dom::BrowsingContext> senderBC = senderInner->GetBrowsingContext(); 140 if (!senderBC) { 141 return false; 142 } 143 // Valid sender should be in the same browsing context tree as where owner is. 144 return GetOwnerBC() ? GetOwnerBC()->Top() == senderBC->Top() : false; 145 } 146 147 NS_IMPL_ISUPPORTS(BackgroundVideoDecodingPermissionObserver, nsIObserver) 148 149 } // namespace mozilla