/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
NS_IMETHODIMP
ScreenOrientation::LockOrientationTask::Run() { if (!mPromise) { return NS_OK;
}
if (!mDocument) {
mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); return NS_OK;
}
nsCOMPtr<nsPIDOMWindowInner> owner = mScreenOrientation->GetOwnerWindow(); if (!owner || !owner->IsFullyActive()) {
mPromise->MaybeRejectWithAbortError("The document is not fully active."); return NS_OK;
}
// Step to lock the orientation as defined in the spec. if (mDocument->GetOrientationPendingPromise() != mPromise) { // The document's pending promise is not associated with this task // to lock orientation. There has since been another request to // lock orientation, thus we don't need to do anything. Old promise // should be been rejected. return NS_OK;
}
if (mDocument->Hidden()) { // Active orientation lock is not the document's orientation lock.
mPromise->MaybeResolveWithUndefined();
mDocument->ClearOrientationPendingPromise(); return NS_OK;
}
BrowsingContext* bc = mDocument->GetBrowsingContext(); if (!bc) {
mPromise->MaybeResolveWithUndefined();
mDocument->ClearOrientationPendingPromise(); return NS_OK;
}
OrientationType previousOrientationType = bc->GetCurrentOrientationType();
mScreenOrientation->LockDeviceOrientation(mOrientationLock, mIsFullscreen)
->Then(
GetCurrentSerialEventTarget(), __func__,
[self = RefPtr{this}, previousOrientationType]( const GenericNonExclusivePromise::ResolveOrRejectValue& aValue) { if (self->mPromise->State() != Promise::PromiseState::Pending) { // mPromise is already resolved or rejected by // DispatchChangeEventAndResolvePromise() or // AbortInProcessOrientationPromises(). return;
}
if (!self->mDocument) {
self->mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); return;
}
if (self->mDocument->GetOrientationPendingPromise() !=
self->mPromise) { // mPromise is old promise now and document has new promise by // later `orientation.lock` call. Old promise is already rejected // by AbortInProcessOrientationPromises() return;
} if (aValue.IsResolve()) { // LockDeviceOrientation won't change orientation, so change // event isn't fired. if (BrowsingContext* bc = self->mDocument->GetBrowsingContext()) {
OrientationType currentOrientationType =
bc->GetCurrentOrientationType(); if ((previousOrientationType == currentOrientationType &&
self->OrientationLockContains(currentOrientationType)) ||
(self->mOrientationLock ==
hal::ScreenOrientation::Default &&
bc->GetCurrentOrientationAngle() == 0)) { // Orientation lock will not cause an orientation change, so // we need to manually resolve the promise here.
self->mPromise->MaybeResolveWithUndefined();
self->mDocument->ClearOrientationPendingPromise();
}
} return;
}
self->mPromise->MaybeReject(aValue.RejectValue());
self->mDocument->ClearOrientationPendingPromise();
});
switch (aOrientation) { case OrientationLockType::Any:
orientation = hal::ScreenOrientation::PortraitPrimary |
hal::ScreenOrientation::PortraitSecondary |
hal::ScreenOrientation::LandscapePrimary |
hal::ScreenOrientation::LandscapeSecondary; break; case OrientationLockType::Natural:
orientation |= hal::ScreenOrientation::Default; break; case OrientationLockType::Landscape:
orientation = hal::ScreenOrientation::LandscapePrimary |
hal::ScreenOrientation::LandscapeSecondary; break; case OrientationLockType::Portrait:
orientation = hal::ScreenOrientation::PortraitPrimary |
hal::ScreenOrientation::PortraitSecondary; break; case OrientationLockType::Portrait_primary:
orientation = hal::ScreenOrientation::PortraitPrimary; break; case OrientationLockType::Portrait_secondary:
orientation = hal::ScreenOrientation::PortraitSecondary; break; case OrientationLockType::Landscape_primary:
orientation = hal::ScreenOrientation::LandscapePrimary; break; case OrientationLockType::Landscape_secondary:
orientation = hal::ScreenOrientation::LandscapeSecondary; break; default:
NS_WARNING("Unexpected orientation type");
aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr;
}
return LockInternal(orientation, aRv);
}
// Wait for document entered fullscreen. class FullscreenWaitListener final : public nsIDOMEventListener { private:
~FullscreenWaitListener() = default;
public:
FullscreenWaitListener() = default;
NS_DECL_ISUPPORTS
// When we have pending fullscreen request, we will wait for the completion or // cancel of it.
RefPtr<GenericPromise> Promise(Document* aDocument) { if (aDocument->Fullscreen()) { return GenericPromise::CreateAndResolve(true, __func__);
}
if (NS_FAILED(InstallEventListener(aDocument))) { return GenericPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
}
already_AddRefed<Promise> ScreenOrientation::LockInternal(
hal::ScreenOrientation aOrientation, ErrorResult& aRv) { // Steps to apply an orientation lock as defined in spec.
// Step 1. // Let document be this's relevant global object's associated Document.
nsCOMPtr<nsIGlobalObject> go = do_QueryInterface(owner);
MOZ_ASSERT(go);
RefPtr<Promise> p = Promise::Create(go, aRv); if (NS_WARN_IF(aRv.Failed())) { return nullptr;
}
if (!owner->IsFullyActive()) {
p->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR); return p.forget();
}
// Step 3. // If document has the sandboxed orientation lock browsing context flag set, // or doesn't meet the pre-lock conditions, or locking would be a security // risk, return a promise rejected with a "SecurityError" DOMException and // abort these steps.
// Step 4. // If the user agent does not support locking the screen orientation to // orientation, return a promise rejected with a "NotSupportedError" // DOMException and abort these steps.
#if !defined(MOZ_WIDGET_ANDROID) && !defined(XP_WIN) // User agent does not support locking the screen orientation.
p->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return p.forget(); #else // Bypass locking screen orientation if preference is false if (!StaticPrefs::dom_screenorientation_allow_lock()) {
p->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR); return p.forget();
}
RefPtr<BrowsingContext> bc = docShell->GetBrowsingContext();
bc = bc ? bc->Top() : nullptr; if (!bc) {
aRv.Throw(NS_ERROR_UNEXPECTED); return nullptr;
}
bc->SetOrientationLock(aOrientation, aRv); if (aRv.Failed()) { return nullptr;
}
if (!doc->SetOrientationPendingPromise(p)) {
p->MaybeReject(NS_ERROR_DOM_SECURITY_ERR); return p.forget();
}
if (perm == LOCK_ALLOWED || doc->Fullscreen()) {
nsCOMPtr<nsIRunnable> lockOrientationTask = new LockOrientationTask( this, p, aOrientation, doc, perm == FULLSCREEN_LOCK_ALLOWED);
aRv = NS_DispatchToMainThread(lockOrientationTask); if (NS_WARN_IF(aRv.Failed())) { return nullptr;
}
return p.forget();
}
MOZ_ASSERT(perm == FULLSCREEN_LOCK_ALLOWED);
// Full screen state is pending. We have to wait for the completion.
RefPtr<FullscreenWaitListener> listener = new FullscreenWaitListener();
RefPtr<Promise> promise = p;
listener->Promise(doc)->Then(
GetMainThreadSerialEventTarget(), __func__,
[self = RefPtr{this}, promise = std::move(promise), aOrientation,
document =
RefPtr{doc}](const GenericPromise::ResolveOrRejectValue& aValue) { if (aValue.IsResolve()) {
nsCOMPtr<nsIRunnable> lockOrientationTask = new LockOrientationTask(
self, promise, aOrientation, document, true);
nsresult rv = NS_DispatchToMainThread(lockOrientationTask); if (NS_SUCCEEDED(rv)) { return;
}
} // Pending full screen request is canceled or causes an error. if (document->GetOrientationPendingPromise() != promise) { // The document's pending promise is not associated with // this promise. return;
} // pre-lock conditions aren't matched.
promise->MaybeReject(NS_ERROR_DOM_SECURITY_ERR);
document->ClearOrientationPendingPromise();
});
nsCOMPtr<EventTarget> target = GetOwnerWindow()->GetDoc(); // We need to register a listener so we learn when we leave fullscreen // and when we will have to unlock the screen. // This needs to be done before LockScreenOrientation call to make sure // the locking can be unlocked. if (aIsFullscreen && !target) { return GenericNonExclusivePromise::CreateAndReject(NS_ERROR_DOM_ABORT_ERR,
__func__);
}
// We are fullscreen and lock has been accepted. if (aIsFullscreen) { if (!mFullscreenListener) {
mFullscreenListener = new FullscreenEventListener();
}
// Sandboxed without "allow-orientation-lock" if (aCheckSandbox && doc->GetSandboxFlags() & SANDBOXED_ORIENTATION_LOCK) { return LOCK_DENIED;
}
if (Preferences::GetBool( "dom.screenorientation.testing.non_fullscreen_lock_allow", false)) { return LOCK_ALLOWED;
}
// Other content must be fullscreen in order to lock orientation. return doc->Fullscreen() || doc->HasPendingFullscreenRequests()
? FULLSCREEN_LOCK_ALLOWED
: LOCK_DENIED;
}
BrowsingContext* bc = doc->GetBrowsingContext(); if (!bc) { return;
}
hal::ScreenOrientation orientation = mScreen->GetOrientationType(); if (orientation != hal::ScreenOrientation::PortraitPrimary &&
orientation != hal::ScreenOrientation::PortraitSecondary &&
orientation != hal::ScreenOrientation::LandscapePrimary &&
orientation != hal::ScreenOrientation::LandscapeSecondary) { // The platform may notify of some other values from // an orientation lock, but we only care about real // changes to screen orientation which result in one of // the values we care about. return;
}
NS_IMETHODIMP
ScreenOrientation::VisibleEventListener::HandleEvent(Event* aEvent) { // Document may have become visible, if the page is visible, run the steps // following the "now visible algorithm" as specified.
MOZ_ASSERT(aEvent->GetCurrentTarget());
nsCOMPtr<nsINode> eventTargetNode =
nsINode::FromEventTarget(aEvent->GetCurrentTarget()); if (!eventTargetNode || !eventTargetNode->IsDocument() ||
eventTargetNode->AsDocument()->Hidden()) { return NS_OK;
}
// We have to make sure that the event we got is the event sent when // fullscreen is disabled because we could get one when fullscreen // got enabled if the lock call is done at the same moment. if (doc->Fullscreen()) { return NS_OK;
}
BrowsingContext* bc = doc->GetBrowsingContext();
bc = bc ? bc->Top() : nullptr; if (bc) {
bc->SetOrientationLock(hal::ScreenOrientation::None, IgnoreErrors());
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.