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