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/StaticPrefs_media.h"
10 #include "MediaDecoder.h"
11 #include "nsContentUtils.h"
12 #include "mozilla/dom/Document.h"
13
14 namespace mozilla {
15
16 BackgroundVideoDecodingPermissionObserver::
BackgroundVideoDecodingPermissionObserver(MediaDecoder * aDecoder)17 BackgroundVideoDecodingPermissionObserver(MediaDecoder* aDecoder)
18 : mDecoder(aDecoder), mIsRegisteredForEvent(false) {
19 MOZ_ASSERT(mDecoder);
20 }
21
22 NS_IMETHODIMP
Observe(nsISupports * aSubject,const char * aTopic,const char16_t * aData)23 BackgroundVideoDecodingPermissionObserver::Observe(nsISupports* aSubject,
24 const char* aTopic,
25 const char16_t* aData) {
26 if (!StaticPrefs::media_resume_bkgnd_video_on_tabhover()) {
27 return NS_OK;
28 }
29
30 if (!IsValidEventSender(aSubject)) {
31 return NS_OK;
32 }
33
34 if (strcmp(aTopic, "unselected-tab-hover") == 0) {
35 bool allowed = !NS_strcmp(aData, u"true");
36 mDecoder->SetIsBackgroundVideoDecodingAllowed(allowed);
37 }
38 return NS_OK;
39 }
40
RegisterEvent()41 void BackgroundVideoDecodingPermissionObserver::RegisterEvent() {
42 MOZ_ASSERT(!mIsRegisteredForEvent);
43 nsCOMPtr<nsIObserverService> observerService = services::GetObserverService();
44 if (observerService) {
45 observerService->AddObserver(this, "unselected-tab-hover", false);
46 mIsRegisteredForEvent = true;
47 if (nsContentUtils::IsInStableOrMetaStableState()) {
48 // Events shall not be fired synchronously to prevent anything visible
49 // from the scripts while we are in stable state.
50 if (nsCOMPtr<dom::Document> doc = GetOwnerDoc()) {
51 doc->Dispatch(
52 TaskCategory::Other,
53 NewRunnableMethod(
54 "BackgroundVideoDecodingPermissionObserver::"
55 "EnableEvent",
56 this, &BackgroundVideoDecodingPermissionObserver::EnableEvent));
57 }
58 } else {
59 EnableEvent();
60 }
61 }
62 }
63
UnregisterEvent()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(
76 TaskCategory::Other,
77 NewRunnableMethod(
78 "BackgroundVideoDecodingPermissionObserver::"
79 "DisableEvent",
80 this,
81 &BackgroundVideoDecodingPermissionObserver::DisableEvent));
82 }
83 } else {
84 DisableEvent();
85 }
86 }
87 }
88
89 BackgroundVideoDecodingPermissionObserver::
~BackgroundVideoDecodingPermissionObserver()90 ~BackgroundVideoDecodingPermissionObserver() {
91 MOZ_ASSERT(!mIsRegisteredForEvent);
92 }
93
EnableEvent() const94 void BackgroundVideoDecodingPermissionObserver::EnableEvent() const {
95 dom::Document* doc = GetOwnerDoc();
96 if (!doc) {
97 return;
98 }
99
100 nsCOMPtr<nsPIDOMWindowOuter> ownerTop = GetOwnerWindow();
101 if (!ownerTop) {
102 return;
103 }
104
105 RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
106 doc, NS_LITERAL_STRING("UnselectedTabHover:Enable"), CanBubble::eYes,
107 ChromeOnlyDispatch::eYes);
108 asyncDispatcher->PostDOMEvent();
109 }
110
DisableEvent() const111 void BackgroundVideoDecodingPermissionObserver::DisableEvent() const {
112 dom::Document* doc = GetOwnerDoc();
113 if (!doc) {
114 return;
115 }
116
117 nsCOMPtr<nsPIDOMWindowOuter> ownerTop = GetOwnerWindow();
118 if (!ownerTop) {
119 return;
120 }
121
122 RefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(
123 doc, NS_LITERAL_STRING("UnselectedTabHover:Disable"), CanBubble::eYes,
124 ChromeOnlyDispatch::eYes);
125 asyncDispatcher->PostDOMEvent();
126 }
127
128 already_AddRefed<nsPIDOMWindowOuter>
GetOwnerWindow() const129 BackgroundVideoDecodingPermissionObserver::GetOwnerWindow() const {
130 dom::Document* doc = GetOwnerDoc();
131 if (!doc) {
132 return nullptr;
133 }
134
135 nsCOMPtr<nsPIDOMWindowInner> innerWin = doc->GetInnerWindow();
136 if (!innerWin) {
137 return nullptr;
138 }
139
140 nsCOMPtr<nsPIDOMWindowOuter> outerWin = innerWin->GetOuterWindow();
141 if (!outerWin) {
142 return nullptr;
143 }
144
145 nsCOMPtr<nsPIDOMWindowOuter> topWin = outerWin->GetInProcessTop();
146 return topWin.forget();
147 }
148
GetOwnerDoc() const149 dom::Document* BackgroundVideoDecodingPermissionObserver::GetOwnerDoc() const {
150 if (!mDecoder->GetOwner()) {
151 return nullptr;
152 }
153
154 return mDecoder->GetOwner()->GetDocument();
155 }
156
IsValidEventSender(nsISupports * aSubject) const157 bool BackgroundVideoDecodingPermissionObserver::IsValidEventSender(
158 nsISupports* aSubject) const {
159 nsCOMPtr<nsPIDOMWindowInner> senderInner(do_QueryInterface(aSubject));
160 if (!senderInner) {
161 return false;
162 }
163
164 nsCOMPtr<nsPIDOMWindowOuter> senderOuter = senderInner->GetOuterWindow();
165 if (!senderOuter) {
166 return false;
167 }
168
169 nsCOMPtr<nsPIDOMWindowOuter> senderTop = senderOuter->GetInProcessTop();
170 if (!senderTop) {
171 return false;
172 }
173
174 nsCOMPtr<nsPIDOMWindowOuter> ownerTop = GetOwnerWindow();
175 if (!ownerTop) {
176 return false;
177 }
178
179 return ownerTop == senderTop;
180 }
181
182 NS_IMPL_ISUPPORTS(BackgroundVideoDecodingPermissionObserver, nsIObserver)
183
184 } // namespace mozilla
185