/src/mozilla-central/dom/base/ScreenOrientation.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=2 et sw=2 tw=80: */ |
3 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
4 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
5 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
6 | | |
7 | | #include "ScreenOrientation.h" |
8 | | #include "nsIDeviceSensors.h" |
9 | | #include "nsIDocShell.h" |
10 | | #include "nsIDocument.h" |
11 | | #include "nsGlobalWindow.h" |
12 | | #include "nsSandboxFlags.h" |
13 | | #include "nsScreen.h" |
14 | | |
15 | | #include "mozilla/DOMEventTargetHelper.h" |
16 | | #include "mozilla/Hal.h" |
17 | | #include "mozilla/Preferences.h" |
18 | | |
19 | | #include "mozilla/dom/Event.h" |
20 | | #include "mozilla/dom/Promise.h" |
21 | | #include "nsContentUtils.h" |
22 | | |
23 | | using namespace mozilla; |
24 | | using namespace mozilla::dom; |
25 | | |
26 | | NS_IMPL_CYCLE_COLLECTION_INHERITED(ScreenOrientation, |
27 | | DOMEventTargetHelper, |
28 | | mScreen); |
29 | | |
30 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScreenOrientation) |
31 | 0 | NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) |
32 | | |
33 | | NS_IMPL_ADDREF_INHERITED(ScreenOrientation, DOMEventTargetHelper) |
34 | | NS_IMPL_RELEASE_INHERITED(ScreenOrientation, DOMEventTargetHelper) |
35 | | |
36 | | static OrientationType |
37 | | InternalOrientationToType(hal::ScreenOrientation aOrientation) |
38 | 0 | { |
39 | 0 | switch (aOrientation) { |
40 | 0 | case hal::eScreenOrientation_PortraitPrimary: |
41 | 0 | return OrientationType::Portrait_primary; |
42 | 0 | case hal::eScreenOrientation_PortraitSecondary: |
43 | 0 | return OrientationType::Portrait_secondary; |
44 | 0 | case hal::eScreenOrientation_LandscapePrimary: |
45 | 0 | return OrientationType::Landscape_primary; |
46 | 0 | case hal::eScreenOrientation_LandscapeSecondary: |
47 | 0 | return OrientationType::Landscape_secondary; |
48 | 0 | default: |
49 | 0 | MOZ_CRASH("Bad aOrientation value"); |
50 | 0 | } |
51 | 0 | } |
52 | | |
53 | | static hal::ScreenOrientation |
54 | | OrientationTypeToInternal(OrientationType aOrientation) |
55 | 0 | { |
56 | 0 | switch (aOrientation) { |
57 | 0 | case OrientationType::Portrait_primary: |
58 | 0 | return hal::eScreenOrientation_PortraitPrimary; |
59 | 0 | case OrientationType::Portrait_secondary: |
60 | 0 | return hal::eScreenOrientation_PortraitSecondary; |
61 | 0 | case OrientationType::Landscape_primary: |
62 | 0 | return hal::eScreenOrientation_LandscapePrimary; |
63 | 0 | case OrientationType::Landscape_secondary: |
64 | 0 | return hal::eScreenOrientation_LandscapeSecondary; |
65 | 0 | default: |
66 | 0 | MOZ_CRASH("Bad aOrientation value"); |
67 | 0 | } |
68 | 0 | } |
69 | | |
70 | | ScreenOrientation::ScreenOrientation(nsPIDOMWindowInner* aWindow, nsScreen* aScreen) |
71 | | : DOMEventTargetHelper(aWindow), mScreen(aScreen) |
72 | 0 | { |
73 | 0 | MOZ_ASSERT(aWindow); |
74 | 0 | MOZ_ASSERT(aScreen); |
75 | 0 |
|
76 | 0 | hal::RegisterScreenConfigurationObserver(this); |
77 | 0 |
|
78 | 0 | hal::ScreenConfiguration config; |
79 | 0 | hal::GetCurrentScreenConfiguration(&config); |
80 | 0 | mType = InternalOrientationToType(config.orientation()); |
81 | 0 | mAngle = config.angle(); |
82 | 0 |
|
83 | 0 | nsIDocument* doc = GetResponsibleDocument(); |
84 | 0 | if (doc) { |
85 | 0 | doc->SetCurrentOrientation(mType, mAngle); |
86 | 0 | } |
87 | 0 | } |
88 | | |
89 | | ScreenOrientation::~ScreenOrientation() |
90 | 0 | { |
91 | 0 | hal::UnregisterScreenConfigurationObserver(this); |
92 | 0 | MOZ_ASSERT(!mFullscreenListener); |
93 | 0 | } |
94 | | |
95 | | class ScreenOrientation::FullscreenEventListener final : public nsIDOMEventListener |
96 | | { |
97 | | ~FullscreenEventListener() = default; |
98 | | public: |
99 | 0 | FullscreenEventListener() = default; |
100 | | |
101 | | NS_DECL_ISUPPORTS |
102 | | NS_DECL_NSIDOMEVENTLISTENER |
103 | | }; |
104 | | |
105 | | class ScreenOrientation::VisibleEventListener final : public nsIDOMEventListener |
106 | | { |
107 | 0 | ~VisibleEventListener() {} |
108 | | public: |
109 | 0 | VisibleEventListener() {} |
110 | | |
111 | | NS_DECL_ISUPPORTS |
112 | | NS_DECL_NSIDOMEVENTLISTENER |
113 | | }; |
114 | | |
115 | | class ScreenOrientation::LockOrientationTask final : public nsIRunnable |
116 | | { |
117 | | ~LockOrientationTask(); |
118 | | public: |
119 | | NS_DECL_ISUPPORTS |
120 | | NS_DECL_NSIRUNNABLE |
121 | | |
122 | | LockOrientationTask(ScreenOrientation* aScreenOrientation, |
123 | | Promise* aPromise, |
124 | | hal::ScreenOrientation aOrientationLock, |
125 | | nsIDocument* aDocument, |
126 | | bool aIsFullscreen); |
127 | | protected: |
128 | | bool OrientationLockContains(OrientationType aOrientationType); |
129 | | |
130 | | RefPtr<ScreenOrientation> mScreenOrientation; |
131 | | RefPtr<Promise> mPromise; |
132 | | hal::ScreenOrientation mOrientationLock; |
133 | | nsCOMPtr<nsIDocument> mDocument; |
134 | | bool mIsFullscreen; |
135 | | }; |
136 | | |
137 | | NS_IMPL_ISUPPORTS(ScreenOrientation::LockOrientationTask, nsIRunnable) |
138 | | |
139 | | ScreenOrientation::LockOrientationTask::LockOrientationTask( |
140 | | ScreenOrientation* aScreenOrientation, Promise* aPromise, |
141 | | hal::ScreenOrientation aOrientationLock, |
142 | | nsIDocument* aDocument, bool aIsFullscreen) |
143 | | : mScreenOrientation(aScreenOrientation), mPromise(aPromise), |
144 | | mOrientationLock(aOrientationLock), mDocument(aDocument), |
145 | | mIsFullscreen(aIsFullscreen) |
146 | 0 | { |
147 | 0 | MOZ_ASSERT(aScreenOrientation); |
148 | 0 | MOZ_ASSERT(aPromise); |
149 | 0 | MOZ_ASSERT(aDocument); |
150 | 0 | } |
151 | | |
152 | | ScreenOrientation::LockOrientationTask::~LockOrientationTask() |
153 | 0 | { |
154 | 0 | } |
155 | | |
156 | | bool |
157 | | ScreenOrientation::LockOrientationTask::OrientationLockContains( |
158 | | OrientationType aOrientationType) |
159 | 0 | { |
160 | 0 | return mOrientationLock & OrientationTypeToInternal(aOrientationType); |
161 | 0 | } |
162 | | |
163 | | NS_IMETHODIMP |
164 | | ScreenOrientation::LockOrientationTask::Run() |
165 | 0 | { |
166 | 0 | // Step to lock the orientation as defined in the spec. |
167 | 0 |
|
168 | 0 | if (mDocument->GetOrientationPendingPromise() != mPromise) { |
169 | 0 | // The document's pending promise is not associated with this task |
170 | 0 | // to lock orientation. There has since been another request to |
171 | 0 | // lock orientation, thus we don't need to do anything. Old promise |
172 | 0 | // should be been rejected. |
173 | 0 | return NS_OK; |
174 | 0 | } |
175 | 0 | |
176 | 0 | if (mDocument->Hidden()) { |
177 | 0 | // Active orientation lock is not the document's orientation lock. |
178 | 0 | mPromise->MaybeResolveWithUndefined(); |
179 | 0 | mDocument->SetOrientationPendingPromise(nullptr); |
180 | 0 | return NS_OK; |
181 | 0 | } |
182 | 0 | |
183 | 0 | if (mOrientationLock == hal::eScreenOrientation_None) { |
184 | 0 | mScreenOrientation->UnlockDeviceOrientation(); |
185 | 0 | mPromise->MaybeResolveWithUndefined(); |
186 | 0 | mDocument->SetOrientationPendingPromise(nullptr); |
187 | 0 | return NS_OK; |
188 | 0 | } |
189 | 0 | |
190 | 0 | ErrorResult rv; |
191 | 0 | bool result = mScreenOrientation->LockDeviceOrientation(mOrientationLock, |
192 | 0 | mIsFullscreen, rv); |
193 | 0 | if (NS_WARN_IF(rv.Failed())) { |
194 | 0 | return rv.StealNSResult(); |
195 | 0 | } |
196 | 0 | |
197 | 0 | if (NS_WARN_IF(!result)) { |
198 | 0 | mPromise->MaybeReject(NS_ERROR_UNEXPECTED); |
199 | 0 | mDocument->SetOrientationPendingPromise(nullptr); |
200 | 0 | return NS_OK; |
201 | 0 | } |
202 | 0 | |
203 | 0 | if (OrientationLockContains(mDocument->CurrentOrientationType()) || |
204 | 0 | (mOrientationLock == hal::eScreenOrientation_Default && |
205 | 0 | mDocument->CurrentOrientationAngle() == 0)) { |
206 | 0 | // Orientation lock will not cause an orientation change. |
207 | 0 | mPromise->MaybeResolveWithUndefined(); |
208 | 0 | mDocument->SetOrientationPendingPromise(nullptr); |
209 | 0 | } |
210 | 0 |
|
211 | 0 | return NS_OK; |
212 | 0 | } |
213 | | |
214 | | already_AddRefed<Promise> |
215 | | ScreenOrientation::Lock(OrientationLockType aOrientation, ErrorResult& aRv) |
216 | 0 | { |
217 | 0 | hal::ScreenOrientation orientation = hal::eScreenOrientation_None; |
218 | 0 |
|
219 | 0 | switch (aOrientation) { |
220 | 0 | case OrientationLockType::Any: |
221 | 0 | orientation = hal::eScreenOrientation_PortraitPrimary | |
222 | 0 | hal::eScreenOrientation_PortraitSecondary | |
223 | 0 | hal::eScreenOrientation_LandscapePrimary | |
224 | 0 | hal::eScreenOrientation_LandscapeSecondary; |
225 | 0 | break; |
226 | 0 | case OrientationLockType::Natural: |
227 | 0 | orientation |= hal::eScreenOrientation_Default; |
228 | 0 | break; |
229 | 0 | case OrientationLockType::Landscape: |
230 | 0 | orientation = hal::eScreenOrientation_LandscapePrimary | |
231 | 0 | hal::eScreenOrientation_LandscapeSecondary; |
232 | 0 | break; |
233 | 0 | case OrientationLockType::Portrait: |
234 | 0 | orientation = hal::eScreenOrientation_PortraitPrimary | |
235 | 0 | hal::eScreenOrientation_PortraitSecondary; |
236 | 0 | break; |
237 | 0 | case OrientationLockType::Portrait_primary: |
238 | 0 | orientation = hal::eScreenOrientation_PortraitPrimary; |
239 | 0 | break; |
240 | 0 | case OrientationLockType::Portrait_secondary: |
241 | 0 | orientation = hal::eScreenOrientation_PortraitSecondary; |
242 | 0 | break; |
243 | 0 | case OrientationLockType::Landscape_primary: |
244 | 0 | orientation = hal::eScreenOrientation_LandscapePrimary; |
245 | 0 | break; |
246 | 0 | case OrientationLockType::Landscape_secondary: |
247 | 0 | orientation = hal::eScreenOrientation_LandscapeSecondary; |
248 | 0 | break; |
249 | 0 | default: |
250 | 0 | NS_WARNING("Unexpected orientation type"); |
251 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
252 | 0 | return nullptr; |
253 | 0 | } |
254 | 0 |
|
255 | 0 | return LockInternal(orientation, aRv); |
256 | 0 | } |
257 | | |
258 | | static inline void |
259 | | AbortOrientationPromises(nsIDocShell* aDocShell) |
260 | 0 | { |
261 | 0 | MOZ_ASSERT(aDocShell); |
262 | 0 |
|
263 | 0 | nsIDocument* doc = aDocShell->GetDocument(); |
264 | 0 | if (doc) { |
265 | 0 | Promise* promise = doc->GetOrientationPendingPromise(); |
266 | 0 | if (promise) { |
267 | 0 | promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); |
268 | 0 | doc->SetOrientationPendingPromise(nullptr); |
269 | 0 | } |
270 | 0 | } |
271 | 0 |
|
272 | 0 | int32_t childCount; |
273 | 0 | aDocShell->GetChildCount(&childCount); |
274 | 0 | for (int32_t i = 0; i < childCount; i++) { |
275 | 0 | nsCOMPtr<nsIDocShellTreeItem> child; |
276 | 0 | if (NS_SUCCEEDED(aDocShell->GetChildAt(i, getter_AddRefs(child)))) { |
277 | 0 | nsCOMPtr<nsIDocShell> childShell(do_QueryInterface(child)); |
278 | 0 | if (childShell) { |
279 | 0 | AbortOrientationPromises(childShell); |
280 | 0 | } |
281 | 0 | } |
282 | 0 | } |
283 | 0 | } |
284 | | |
285 | | already_AddRefed<Promise> |
286 | | ScreenOrientation::LockInternal(hal::ScreenOrientation aOrientation, |
287 | | ErrorResult& aRv) |
288 | 0 | { |
289 | 0 | // Steps to apply an orientation lock as defined in spec. |
290 | 0 |
|
291 | 0 | nsIDocument* doc = GetResponsibleDocument(); |
292 | 0 | if (NS_WARN_IF(!doc)) { |
293 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
294 | 0 | return nullptr; |
295 | 0 | } |
296 | 0 | |
297 | 0 | nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner(); |
298 | 0 | if (NS_WARN_IF(!owner)) { |
299 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
300 | 0 | return nullptr; |
301 | 0 | } |
302 | 0 | |
303 | 0 | nsCOMPtr<nsIDocShell> docShell = owner->GetDocShell(); |
304 | 0 | if (NS_WARN_IF(!docShell)) { |
305 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
306 | 0 | return nullptr; |
307 | 0 | } |
308 | 0 | |
309 | 0 | nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(owner); |
310 | 0 | MOZ_ASSERT(go); |
311 | 0 | RefPtr<Promise> p = Promise::Create(go, aRv); |
312 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
313 | 0 | return nullptr; |
314 | 0 | } |
315 | 0 | |
316 | 0 | #if !defined(MOZ_WIDGET_ANDROID) |
317 | 0 | // User agent does not support locking the screen orientation. |
318 | 0 | p->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR); |
319 | 0 | return p.forget(); |
320 | | #else |
321 | | LockPermission perm = GetLockOrientationPermission(true); |
322 | | if (perm == LOCK_DENIED) { |
323 | | p->MaybeReject(NS_ERROR_DOM_SECURITY_ERR); |
324 | | return p.forget(); |
325 | | } |
326 | | |
327 | | nsCOMPtr<nsIDocShellTreeItem> root; |
328 | | docShell->GetSameTypeRootTreeItem(getter_AddRefs(root)); |
329 | | nsCOMPtr<nsIDocShell> rootShell(do_QueryInterface(root)); |
330 | | if (!rootShell) { |
331 | | aRv.Throw(NS_ERROR_UNEXPECTED); |
332 | | return nullptr; |
333 | | } |
334 | | |
335 | | rootShell->SetOrientationLock(aOrientation); |
336 | | AbortOrientationPromises(rootShell); |
337 | | |
338 | | doc->SetOrientationPendingPromise(p); |
339 | | |
340 | | nsCOMPtr<nsIRunnable> lockOrientationTask = |
341 | | new LockOrientationTask(this, p, aOrientation, doc, |
342 | | perm == FULLSCREEN_LOCK_ALLOWED); |
343 | | aRv = NS_DispatchToMainThread(lockOrientationTask); |
344 | | if (NS_WARN_IF(aRv.Failed())) { |
345 | | return nullptr; |
346 | | } |
347 | | |
348 | | return p.forget(); |
349 | | #endif |
350 | | } |
351 | | |
352 | | bool |
353 | | ScreenOrientation::LockDeviceOrientation(hal::ScreenOrientation aOrientation, |
354 | | bool aIsFullscreen, ErrorResult& aRv) |
355 | 0 | { |
356 | 0 | if (!GetOwner()) { |
357 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
358 | 0 | return false; |
359 | 0 | } |
360 | 0 | |
361 | 0 | nsCOMPtr<EventTarget> target = do_QueryInterface(GetOwner()->GetDoc()); |
362 | 0 | // We need to register a listener so we learn when we leave fullscreen |
363 | 0 | // and when we will have to unlock the screen. |
364 | 0 | // This needs to be done before LockScreenOrientation call to make sure |
365 | 0 | // the locking can be unlocked. |
366 | 0 | if (aIsFullscreen && !target) { |
367 | 0 | return false; |
368 | 0 | } |
369 | 0 | |
370 | 0 | if (NS_WARN_IF(!hal::LockScreenOrientation(aOrientation))) { |
371 | 0 | return false; |
372 | 0 | } |
373 | 0 | |
374 | 0 | // We are fullscreen and lock has been accepted. |
375 | 0 | if (aIsFullscreen) { |
376 | 0 | if (!mFullscreenListener) { |
377 | 0 | mFullscreenListener = new FullscreenEventListener(); |
378 | 0 | } |
379 | 0 |
|
380 | 0 | aRv = target->AddSystemEventListener(NS_LITERAL_STRING("fullscreenchange"), |
381 | 0 | mFullscreenListener, /* useCapture = */ true); |
382 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
383 | 0 | return false; |
384 | 0 | } |
385 | 0 | } |
386 | 0 | |
387 | 0 | return true; |
388 | 0 | } |
389 | | |
390 | | void |
391 | | ScreenOrientation::Unlock(ErrorResult& aRv) |
392 | 0 | { |
393 | 0 | RefPtr<Promise> p = LockInternal(hal::eScreenOrientation_None, aRv); |
394 | 0 | } |
395 | | |
396 | | void |
397 | | ScreenOrientation::UnlockDeviceOrientation() |
398 | 0 | { |
399 | 0 | hal::UnlockScreenOrientation(); |
400 | 0 |
|
401 | 0 | if (!mFullscreenListener || !GetOwner()) { |
402 | 0 | mFullscreenListener = nullptr; |
403 | 0 | return; |
404 | 0 | } |
405 | 0 | |
406 | 0 | // Remove event listener in case of fullscreen lock. |
407 | 0 | nsCOMPtr<EventTarget> target = do_QueryInterface(GetOwner()->GetDoc()); |
408 | 0 | if (target) { |
409 | 0 | target->RemoveSystemEventListener(NS_LITERAL_STRING("fullscreenchange"), |
410 | 0 | mFullscreenListener, |
411 | 0 | /* useCapture */ true); |
412 | 0 | } |
413 | 0 |
|
414 | 0 | mFullscreenListener = nullptr; |
415 | 0 | } |
416 | | |
417 | | OrientationType |
418 | | ScreenOrientation::DeviceType(CallerType aCallerType) const |
419 | 0 | { |
420 | 0 | return nsContentUtils::ResistFingerprinting(aCallerType) ? |
421 | 0 | OrientationType::Landscape_primary : mType; |
422 | 0 | } |
423 | | |
424 | | uint16_t |
425 | | ScreenOrientation::DeviceAngle(CallerType aCallerType) const |
426 | 0 | { |
427 | 0 | return nsContentUtils::ResistFingerprinting(aCallerType) ? 0 : mAngle; |
428 | 0 | } |
429 | | |
430 | | OrientationType |
431 | | ScreenOrientation::GetType(CallerType aCallerType, ErrorResult& aRv) const |
432 | 0 | { |
433 | 0 | if (nsContentUtils::ResistFingerprinting(aCallerType)) { |
434 | 0 | return OrientationType::Landscape_primary; |
435 | 0 | } |
436 | 0 | |
437 | 0 | nsIDocument* doc = GetResponsibleDocument(); |
438 | 0 | if (!doc) { |
439 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
440 | 0 | return OrientationType::Portrait_primary; |
441 | 0 | } |
442 | 0 | |
443 | 0 | return doc->CurrentOrientationType(); |
444 | 0 | } |
445 | | |
446 | | uint16_t |
447 | | ScreenOrientation::GetAngle(CallerType aCallerType, ErrorResult& aRv) const |
448 | 0 | { |
449 | 0 | if (nsContentUtils::ResistFingerprinting(aCallerType)) { |
450 | 0 | return 0; |
451 | 0 | } |
452 | 0 | |
453 | 0 | nsIDocument* doc = GetResponsibleDocument(); |
454 | 0 | if (!doc) { |
455 | 0 | aRv.Throw(NS_ERROR_UNEXPECTED); |
456 | 0 | return 0; |
457 | 0 | } |
458 | 0 | |
459 | 0 | return doc->CurrentOrientationAngle(); |
460 | 0 | } |
461 | | |
462 | | ScreenOrientation::LockPermission |
463 | | ScreenOrientation::GetLockOrientationPermission(bool aCheckSandbox) const |
464 | 0 | { |
465 | 0 | nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner(); |
466 | 0 | if (!owner) { |
467 | 0 | return LOCK_DENIED; |
468 | 0 | } |
469 | 0 | |
470 | 0 | // Chrome can always lock the screen orientation. |
471 | 0 | nsIDocShell* docShell = owner->GetDocShell(); |
472 | 0 | if (docShell && docShell->ItemType() == nsIDocShellTreeItem::typeChrome) { |
473 | 0 | return LOCK_ALLOWED; |
474 | 0 | } |
475 | 0 | |
476 | 0 | nsCOMPtr<nsIDocument> doc = owner->GetDoc(); |
477 | 0 | if (!doc || doc->Hidden()) { |
478 | 0 | return LOCK_DENIED; |
479 | 0 | } |
480 | 0 | |
481 | 0 | // Sandboxed without "allow-orientation-lock" |
482 | 0 | if (aCheckSandbox && doc->GetSandboxFlags() & SANDBOXED_ORIENTATION_LOCK) { |
483 | 0 | return LOCK_DENIED; |
484 | 0 | } |
485 | 0 | |
486 | 0 | if (Preferences::GetBool("dom.screenorientation.testing.non_fullscreen_lock_allow", |
487 | 0 | false)) { |
488 | 0 | return LOCK_ALLOWED; |
489 | 0 | } |
490 | 0 | |
491 | 0 | // Other content must be fullscreen in order to lock orientation. |
492 | 0 | return doc->Fullscreen() ? FULLSCREEN_LOCK_ALLOWED : LOCK_DENIED; |
493 | 0 | } |
494 | | |
495 | | nsIDocument* |
496 | | ScreenOrientation::GetResponsibleDocument() const |
497 | 0 | { |
498 | 0 | nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner(); |
499 | 0 | if (!owner) { |
500 | 0 | return nullptr; |
501 | 0 | } |
502 | 0 | |
503 | 0 | return owner->GetDoc(); |
504 | 0 | } |
505 | | |
506 | | void |
507 | | ScreenOrientation::Notify(const hal::ScreenConfiguration& aConfiguration) |
508 | 0 | { |
509 | 0 | if (ShouldResistFingerprinting()) { |
510 | 0 | return; |
511 | 0 | } |
512 | 0 | |
513 | 0 | nsIDocument* doc = GetResponsibleDocument(); |
514 | 0 | if (!doc) { |
515 | 0 | return; |
516 | 0 | } |
517 | 0 | |
518 | 0 | hal::ScreenOrientation orientation = aConfiguration.orientation(); |
519 | 0 | if (orientation != hal::eScreenOrientation_PortraitPrimary && |
520 | 0 | orientation != hal::eScreenOrientation_PortraitSecondary && |
521 | 0 | orientation != hal::eScreenOrientation_LandscapePrimary && |
522 | 0 | orientation != hal::eScreenOrientation_LandscapeSecondary) { |
523 | 0 | // The platform may notify of some other values from |
524 | 0 | // an orientation lock, but we only care about real |
525 | 0 | // changes to screen orientation which result in one of |
526 | 0 | // the values we care about. |
527 | 0 | return; |
528 | 0 | } |
529 | 0 | |
530 | 0 | OrientationType previousOrientation = mType; |
531 | 0 | mAngle = aConfiguration.angle(); |
532 | 0 | mType = InternalOrientationToType(orientation); |
533 | 0 |
|
534 | 0 | DebugOnly<nsresult> rv; |
535 | 0 | if (mScreen && mType != previousOrientation) { |
536 | 0 | // Use of mozorientationchange is deprecated. |
537 | 0 | rv = mScreen->DispatchTrustedEvent(NS_LITERAL_STRING("mozorientationchange")); |
538 | 0 | NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "DispatchTrustedEvent failed"); |
539 | 0 | } |
540 | 0 |
|
541 | 0 | if (doc->Hidden() && !mVisibleListener) { |
542 | 0 | mVisibleListener = new VisibleEventListener(); |
543 | 0 | rv = doc->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), |
544 | 0 | mVisibleListener, /* useCapture = */ true); |
545 | 0 | NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "AddSystemEventListener failed"); |
546 | 0 | return; |
547 | 0 | } |
548 | 0 |
|
549 | 0 | if (mType != doc->CurrentOrientationType()) { |
550 | 0 | doc->SetCurrentOrientation(mType, mAngle); |
551 | 0 |
|
552 | 0 | Promise* pendingPromise = doc->GetOrientationPendingPromise(); |
553 | 0 | if (pendingPromise) { |
554 | 0 | pendingPromise->MaybeResolveWithUndefined(); |
555 | 0 | doc->SetOrientationPendingPromise(nullptr); |
556 | 0 | } |
557 | 0 |
|
558 | 0 | nsCOMPtr<nsIRunnable> runnable = |
559 | 0 | NewRunnableMethod("dom::ScreenOrientation::DispatchChangeEvent", |
560 | 0 | this, |
561 | 0 | &ScreenOrientation::DispatchChangeEvent); |
562 | 0 | rv = NS_DispatchToMainThread(runnable); |
563 | 0 | NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "NS_DispatchToMainThread failed"); |
564 | 0 | } |
565 | 0 | } |
566 | | |
567 | | void |
568 | | ScreenOrientation::UpdateActiveOrientationLock( |
569 | | hal::ScreenOrientation aOrientation) |
570 | 0 | { |
571 | 0 | if (aOrientation == hal::eScreenOrientation_None) { |
572 | 0 | hal::UnlockScreenOrientation(); |
573 | 0 | } else { |
574 | 0 | DebugOnly<bool> ok = hal::LockScreenOrientation(aOrientation); |
575 | 0 | NS_WARNING_ASSERTION(ok, "hal::LockScreenOrientation failed"); |
576 | 0 | } |
577 | 0 | } |
578 | | |
579 | | void |
580 | | ScreenOrientation::DispatchChangeEvent() |
581 | 0 | { |
582 | 0 | DebugOnly<nsresult> rv = DispatchTrustedEvent(NS_LITERAL_STRING("change")); |
583 | 0 | NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "DispatchTrustedEvent failed"); |
584 | 0 | } |
585 | | |
586 | | JSObject* |
587 | | ScreenOrientation::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
588 | 0 | { |
589 | 0 | return ScreenOrientation_Binding::Wrap(aCx, this, aGivenProto); |
590 | 0 | } |
591 | | |
592 | | bool |
593 | | ScreenOrientation::ShouldResistFingerprinting() const |
594 | 0 | { |
595 | 0 | bool resist = false; |
596 | 0 | if (nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner()) { |
597 | 0 | resist = nsContentUtils::ShouldResistFingerprinting(owner->GetDocShell()); |
598 | 0 | } |
599 | 0 | return resist; |
600 | 0 | } |
601 | | |
602 | | NS_IMPL_ISUPPORTS(ScreenOrientation::VisibleEventListener, nsIDOMEventListener) |
603 | | |
604 | | NS_IMETHODIMP |
605 | | ScreenOrientation::VisibleEventListener::HandleEvent(Event* aEvent) |
606 | 0 | { |
607 | 0 | // Document may have become visible, if the page is visible, run the steps |
608 | 0 | // following the "now visible algorithm" as specified. |
609 | 0 | nsCOMPtr<EventTarget> target = aEvent->GetCurrentTarget(); |
610 | 0 | MOZ_ASSERT(target); |
611 | 0 |
|
612 | 0 | nsCOMPtr<nsIDocument> doc = do_QueryInterface(target); |
613 | 0 | if (!doc || doc->Hidden()) { |
614 | 0 | return NS_OK; |
615 | 0 | } |
616 | 0 | |
617 | 0 | auto* win = nsGlobalWindowInner::Cast(doc->GetInnerWindow()); |
618 | 0 | if (!win) { |
619 | 0 | return NS_OK; |
620 | 0 | } |
621 | 0 | |
622 | 0 | ErrorResult rv; |
623 | 0 | nsScreen* screen = win->GetScreen(rv); |
624 | 0 | if (NS_WARN_IF(rv.Failed())) { |
625 | 0 | return rv.StealNSResult(); |
626 | 0 | } |
627 | 0 | |
628 | 0 | MOZ_ASSERT(screen); |
629 | 0 | ScreenOrientation* orientation = screen->Orientation(); |
630 | 0 | MOZ_ASSERT(orientation); |
631 | 0 |
|
632 | 0 | target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), |
633 | 0 | this, true); |
634 | 0 |
|
635 | 0 | if (doc->CurrentOrientationType() != orientation->DeviceType(CallerType::System)) { |
636 | 0 | doc->SetCurrentOrientation(orientation->DeviceType(CallerType::System), |
637 | 0 | orientation->DeviceAngle(CallerType::System)); |
638 | 0 |
|
639 | 0 | Promise* pendingPromise = doc->GetOrientationPendingPromise(); |
640 | 0 | if (pendingPromise) { |
641 | 0 | pendingPromise->MaybeResolveWithUndefined(); |
642 | 0 | doc->SetOrientationPendingPromise(nullptr); |
643 | 0 | } |
644 | 0 |
|
645 | 0 | nsCOMPtr<nsIRunnable> runnable = |
646 | 0 | NewRunnableMethod("dom::ScreenOrientation::DispatchChangeEvent", |
647 | 0 | orientation, |
648 | 0 | &ScreenOrientation::DispatchChangeEvent); |
649 | 0 | rv = NS_DispatchToMainThread(runnable); |
650 | 0 | if (NS_WARN_IF(rv.Failed())) { |
651 | 0 | return rv.StealNSResult(); |
652 | 0 | } |
653 | 0 | } |
654 | 0 | |
655 | 0 | return NS_OK; |
656 | 0 | } |
657 | | |
658 | | NS_IMPL_ISUPPORTS(ScreenOrientation::FullscreenEventListener, nsIDOMEventListener) |
659 | | |
660 | | NS_IMETHODIMP |
661 | | ScreenOrientation::FullscreenEventListener::HandleEvent(Event* aEvent) |
662 | 0 | { |
663 | | #ifdef DEBUG |
664 | | nsAutoString eventType; |
665 | | aEvent->GetType(eventType); |
666 | | |
667 | | MOZ_ASSERT(eventType.EqualsLiteral("fullscreenchange")); |
668 | | #endif |
669 | |
|
670 | 0 | nsCOMPtr<EventTarget> target = aEvent->GetCurrentTarget(); |
671 | 0 | MOZ_ASSERT(target); |
672 | 0 |
|
673 | 0 | nsCOMPtr<nsIDocument> doc = do_QueryInterface(target); |
674 | 0 | MOZ_ASSERT(doc); |
675 | 0 |
|
676 | 0 | // We have to make sure that the event we got is the event sent when |
677 | 0 | // fullscreen is disabled because we could get one when fullscreen |
678 | 0 | // got enabled if the lock call is done at the same moment. |
679 | 0 | if (doc->Fullscreen()) { |
680 | 0 | return NS_OK; |
681 | 0 | } |
682 | 0 | |
683 | 0 | hal::UnlockScreenOrientation(); |
684 | 0 |
|
685 | 0 | target->RemoveSystemEventListener(NS_LITERAL_STRING("fullscreenchange"), |
686 | 0 | this, true); |
687 | 0 | return NS_OK; |
688 | 0 | } |