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