Bug 1943650 - Command-line --help output misformatted after --dbus-service. r=emilio
[gecko.git] / dom / media / autoplay / GVAutoplayPermissionRequest.cpp
bloba1ce1018af71225084ee9abc2b2893311b5044b8
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "GVAutoplayPermissionRequest.h"
7 #include "mozilla/Logging.h"
8 #include "mozilla/StaticPrefs_media.h"
9 #include "mozilla/dom/HTMLMediaElement.h"
10 #include "nsGlobalWindowInner.h"
12 mozilla::LazyLogModule gGVAutoplayRequestLog("GVAutoplay");
14 namespace mozilla::dom {
16 using RType = GVAutoplayRequestType;
17 using RStatus = GVAutoplayRequestStatus;
19 // avoid redefined macro in unified build
20 #undef REQUEST_LOG
21 #define REQUEST_LOG(msg, ...) \
22 if (MOZ_LOG_TEST(gGVAutoplayRequestLog, mozilla::LogLevel::Debug)) { \
23 MOZ_LOG(gGVAutoplayRequestLog, LogLevel::Debug, \
24 ("Request=%p, Type=%s, " msg, this, \
25 EnumValueToString(this->mType), ##__VA_ARGS__)); \
28 #undef LOG
29 #define LOG(msg, ...) \
30 MOZ_LOG(gGVAutoplayRequestLog, LogLevel::Debug, (msg, ##__VA_ARGS__))
32 static RStatus GetRequestStatus(BrowsingContext* aContext, RType aType) {
33 MOZ_ASSERT(aContext);
34 AssertIsOnMainThread();
35 return aType == RType::eAUDIBLE
36 ? aContext->GetGVAudibleAutoplayRequestStatus()
37 : aContext->GetGVInaudibleAutoplayRequestStatus();
40 // This is copied from the value of `media.geckoview.autoplay.request.testing`.
41 enum class TestRequest : uint32_t {
42 ePromptAsNormal = 0,
43 eAllowAll = 1,
44 eDenyAll = 2,
45 eAllowAudible = 3,
46 eDenyAudible = 4,
47 eAllowInAudible = 5,
48 eDenyInAudible = 6,
49 eLeaveAllPending = 7,
52 NS_IMPL_CYCLE_COLLECTION_INHERITED(GVAutoplayPermissionRequest,
53 ContentPermissionRequestBase)
55 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(GVAutoplayPermissionRequest,
56 ContentPermissionRequestBase)
58 /* static */
59 void GVAutoplayPermissionRequest::CreateRequest(nsGlobalWindowInner* aWindow,
60 BrowsingContext* aContext,
61 GVAutoplayRequestType aType) {
62 RefPtr<GVAutoplayPermissionRequest> request =
63 new GVAutoplayPermissionRequest(aWindow, aContext, aType);
64 request->SetRequestStatus(RStatus::ePENDING);
65 const TestRequest testingPref = static_cast<TestRequest>(
66 StaticPrefs::media_geckoview_autoplay_request_testing());
67 if (testingPref != TestRequest::ePromptAsNormal) {
68 LOG("Create testing request, tesing value=%u",
69 static_cast<uint32_t>(testingPref));
70 if (testingPref == TestRequest::eAllowAll ||
71 (testingPref == TestRequest::eAllowAudible &&
72 aType == RType::eAUDIBLE) ||
73 (testingPref == TestRequest::eAllowInAudible &&
74 aType == RType::eINAUDIBLE)) {
75 request->Allow(JS::UndefinedHandleValue);
76 } else if (testingPref == TestRequest::eDenyAll ||
77 (testingPref == TestRequest::eDenyAudible &&
78 aType == RType::eAUDIBLE) ||
79 (testingPref == TestRequest::eDenyInAudible &&
80 aType == RType::eINAUDIBLE)) {
81 request->Cancel();
83 } else {
84 LOG("Dispatch async request");
85 request->RequestDelayedTask(
86 aWindow->SerialEventTarget(),
87 GVAutoplayPermissionRequest::DelayedTaskType::Request);
91 GVAutoplayPermissionRequest::GVAutoplayPermissionRequest(
92 nsGlobalWindowInner* aWindow, BrowsingContext* aContext, RType aType)
93 : ContentPermissionRequestBase(aWindow->GetPrincipal(), aWindow,
94 ""_ns, // No testing pref used in this class
95 aType == RType::eAUDIBLE
96 ? "autoplay-media-audible"_ns
97 : "autoplay-media-inaudible"_ns),
98 mType(aType),
99 mContext(aContext) {
100 MOZ_ASSERT(mContext);
101 REQUEST_LOG("Request created");
104 GVAutoplayPermissionRequest::~GVAutoplayPermissionRequest() {
105 REQUEST_LOG("Request destroyed");
106 // If user doesn't response to the request before it gets destroyed (ex.
107 // request dismissed, tab closed, naviagation to a new page), then we should
108 // treat it as a denial.
109 if (mContext) {
110 Cancel();
114 void GVAutoplayPermissionRequest::SetRequestStatus(RStatus aStatus) {
115 REQUEST_LOG("SetRequestStatus, new status=%s", EnumValueToString(aStatus));
116 MOZ_ASSERT(mContext);
117 AssertIsOnMainThread();
118 if (mType == RType::eAUDIBLE) {
119 // Return value of setting synced field should be checked. See bug 1656492.
120 Unused << mContext->SetGVAudibleAutoplayRequestStatus(aStatus);
121 } else {
122 // Return value of setting synced field should be checked. See bug 1656492.
123 Unused << mContext->SetGVInaudibleAutoplayRequestStatus(aStatus);
127 NS_IMETHODIMP
128 GVAutoplayPermissionRequest::Cancel() {
129 MOZ_ASSERT(mContext, "Do not call 'Cancel()' twice!");
130 // As the process of replying of the request is an async task, the status
131 // might have be reset at the time we get the result from parent process.
132 // Ex. if the page got closed or naviagated immediately after user replied to
133 // the request. Therefore, the status should be either `pending` or `unknown`.
134 const RStatus status = GetRequestStatus(mContext, mType);
135 REQUEST_LOG("Cancel, current status=%s", EnumValueToString(status));
136 MOZ_ASSERT(status == RStatus::ePENDING || status == RStatus::eUNKNOWN);
137 if ((status == RStatus::ePENDING) && !mContext->IsDiscarded()) {
138 SetRequestStatus(RStatus::eDENIED);
140 mContext = nullptr;
141 return NS_OK;
144 NS_IMETHODIMP
145 GVAutoplayPermissionRequest::Allow(JS::Handle<JS::Value> aChoices) {
146 MOZ_ASSERT(mContext, "Do not call 'Allow()' twice!");
147 // As the process of replying of the request is an async task, the status
148 // might have be reset at the time we get the result from parent process.
149 // Ex. if the page got closed or naviagated immediately after user replied to
150 // the request. Therefore, the status should be either `pending` or `unknown`.
151 const RStatus status = GetRequestStatus(mContext, mType);
152 REQUEST_LOG("Allow, current status=%s", EnumValueToString(status));
153 MOZ_ASSERT(status == RStatus::ePENDING || status == RStatus::eUNKNOWN);
154 if (status == RStatus::ePENDING) {
155 SetRequestStatus(RStatus::eALLOWED);
157 mContext = nullptr;
158 return NS_OK;
161 /* static */
162 void GVAutoplayPermissionRequestor::AskForPermissionIfNeeded(
163 nsPIDOMWindowInner* aWindow) {
164 LOG("Requestor, AskForPermissionIfNeeded");
165 if (!aWindow) {
166 return;
169 // The request is used for content permission, so it's no need to create a
170 // content request in parent process if we're in e10s.
171 if (XRE_IsE10sParentProcess()) {
172 return;
175 if (!StaticPrefs::media_geckoview_autoplay_request()) {
176 return;
179 LOG("Requestor, check status to decide if we need to create the new request");
180 // The request status is stored in top-level browsing context only.
181 RefPtr<BrowsingContext> context = aWindow->GetBrowsingContext()->Top();
182 if (!HasEverAskForRequest(context, RType::eAUDIBLE)) {
183 CreateAsyncRequest(aWindow, context, RType::eAUDIBLE);
185 if (!HasEverAskForRequest(context, RType::eINAUDIBLE)) {
186 CreateAsyncRequest(aWindow, context, RType::eINAUDIBLE);
190 /* static */
191 bool GVAutoplayPermissionRequestor::HasEverAskForRequest(
192 BrowsingContext* aContext, RType aType) {
193 return GetRequestStatus(aContext, aType) != RStatus::eUNKNOWN;
196 /* static */
197 void GVAutoplayPermissionRequestor::CreateAsyncRequest(
198 nsPIDOMWindowInner* aWindow, BrowsingContext* aContext,
199 GVAutoplayRequestType aType) {
200 nsGlobalWindowInner* innerWindow = nsGlobalWindowInner::Cast(aWindow);
201 if (!innerWindow || !innerWindow->GetPrincipal()) {
202 return;
205 GVAutoplayPermissionRequest::CreateRequest(innerWindow, aContext, aType);
208 } // namespace mozilla::dom