diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp index ff04e25362..a2e24483a1 100644 --- a/docshell/base/nsDocShell.cpp +++ b/docshell/base/nsDocShell.cpp @@ -16,6 +16,7 @@ #include "mozilla/dom/Element.h" #include "mozilla/dom/TabChild.h" #include "mozilla/dom/ProfileTimelineMarkerBinding.h" +#include "mozilla/dom/ScreenOrientation.h" #include "mozilla/dom/ToJSValue.h" #include "mozilla/dom/workers/ServiceWorkerManager.h" #include "mozilla/EventStateManager.h" @@ -757,6 +758,7 @@ nsDocShell::nsDocShell() , mLoadedTransIndex(-1) , mSandboxFlags(0) , mFullscreenAllowed(CHECK_ATTRIBUTES) + , mOrientationLock(eScreenOrientation_None) , mCreated(false) , mAllowSubframes(true) , mAllowPlugins(true) @@ -2560,6 +2562,18 @@ nsDocShell::SetFullscreenAllowed(bool aFullscreenAllowed) return NS_OK; } +ScreenOrientationInternal +nsDocShell::OrientationLock() +{ + return mOrientationLock; +} + +void +nsDocShell::SetOrientationLock(ScreenOrientationInternal aOrientationLock) +{ + mOrientationLock = aOrientationLock; +} + NS_IMETHODIMP nsDocShell::GetMayEnableCharacterEncodingMenu( bool* aMayEnableCharacterEncodingMenu) @@ -6065,6 +6079,16 @@ nsDocShell::SetIsActive(bool aIsActive) if (mScriptGlobal) { mScriptGlobal->SetIsBackground(!aIsActive); if (nsCOMPtr doc = mScriptGlobal->GetExtantDoc()) { + if (aIsActive) { + nsCOMPtr parent; + GetSameTypeParent(getter_AddRefs(parent)); + if (!parent) { + // We only care about the top-level browsing context. + uint16_t orientation = OrientationLock(); + ScreenOrientation::UpdateActiveOrientationLock(orientation); + } + } + doc->PostVisibilityUpdateEvent(); } } @@ -10270,6 +10294,22 @@ nsDocShell::InternalLoad2(nsIURI* aURI, mTiming->NotifyUnloadAccepted(mCurrentURI); } + // Whenever a top-level browsing context is navigated, the user agent MUST + // lock the orientation of the document to the document's default + // orientation. We don't explicitly check for a top-level browsing context + // here because orientation is only set on top-level browsing contexts. + if (OrientationLock() != eScreenOrientation_None) { +#ifdef DEBUG + nsCOMPtr parent; + GetSameTypeParent(getter_AddRefs(parent)); + MOZ_ASSERT(!parent); +#endif + SetOrientationLock(eScreenOrientation_None); + if (mIsActive) { + ScreenOrientation::UpdateActiveOrientationLock(eScreenOrientation_None); + } + } + // Check for saving the presentation here, before calling Stop(). // This is necessary so that we can catch any pending requests. // Since the new request has not been created yet, we pass null for the diff --git a/docshell/base/nsDocShell.h b/docshell/base/nsDocShell.h index 0fc5be6ddf..3fbcd654d9 100644 --- a/docshell/base/nsDocShell.h +++ b/docshell/base/nsDocShell.h @@ -62,6 +62,7 @@ namespace mozilla { namespace dom { class EventTarget; +typedef uint32_t ScreenOrientationInternal; } // namespace dom } // namespace mozilla @@ -879,6 +880,10 @@ protected: }; FullscreenAllowedState mFullscreenAllowed; + // The orientation lock as described by + // https://w3c.github.io/screen-orientation/ + mozilla::dom::ScreenOrientationInternal mOrientationLock; + // Cached value of the "browser.xul.error_pages.enabled" preference. static bool sUseErrorPages; diff --git a/docshell/base/nsIDocShell.idl b/docshell/base/nsIDocShell.idl index 6513268031..2816a1878e 100644 --- a/docshell/base/nsIDocShell.idl +++ b/docshell/base/nsIDocShell.idl @@ -46,7 +46,7 @@ interface nsITabParent; typedef unsigned long nsLoadFlags; -[scriptable, builtinclass, uuid(97471054-0BC8-4A57-BBFE-6C255BCBBB67)] +[scriptable, builtinclass, uuid(35a26f70-dbb9-450d-b634-cd0bbb9b8e13)] interface nsIDocShell : nsIDocShellTreeItem { /** @@ -920,6 +920,9 @@ interface nsIDocShell : nsIDocShellTreeItem void setFullscreenAllowed(in boolean allowed); + [notxpcom] uint32_t orientationLock(); + [notxpcom] void setOrientationLock(in uint32_t orientationLock); + [noscript, infallible] attribute boolean affectPrivateSessionLifetime; /** diff --git a/dom/base/ScreenOrientation.cpp b/dom/base/ScreenOrientation.cpp new file mode 100644 index 0000000000..ca24ca57fa --- /dev/null +++ b/dom/base/ScreenOrientation.cpp @@ -0,0 +1,645 @@ +/* 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/. */ + +#include "ScreenOrientation.h" +#include "nsIDeviceSensors.h" +#include "nsSandboxFlags.h" +#include "nsScreen.h" + +using namespace mozilla::dom; + +NS_IMPL_CYCLE_COLLECTION_INHERITED(ScreenOrientation, + DOMEventTargetHelper, + mScreen); + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ScreenOrientation) +NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) + +NS_IMPL_ADDREF_INHERITED(ScreenOrientation, DOMEventTargetHelper) +NS_IMPL_RELEASE_INHERITED(ScreenOrientation, DOMEventTargetHelper) + +static OrientationType +InternalOrientationToType(ScreenOrientationInternal aOrientation) +{ + switch (aOrientation) { + case eScreenOrientation_PortraitPrimary: + return OrientationType::Portrait_primary; + case eScreenOrientation_PortraitSecondary: + return OrientationType::Portrait_secondary; + case eScreenOrientation_LandscapePrimary: + return OrientationType::Landscape_primary; + case eScreenOrientation_LandscapeSecondary: + return OrientationType::Landscape_secondary; + default: + MOZ_CRASH("Bad aOrientation value"); + } +} + +static ScreenOrientationInternal +OrientationTypeToInternal(OrientationType aOrientation) +{ + switch (aOrientation) { + case OrientationType::Portrait_primary: + return eScreenOrientation_PortraitPrimary; + case OrientationType::Portrait_secondary: + return eScreenOrientation_PortraitSecondary; + case OrientationType::Landscape_primary: + return eScreenOrientation_LandscapePrimary; + case OrientationType::Landscape_secondary: + return eScreenOrientation_LandscapeSecondary; + default: + MOZ_CRASH("Bad aOrientation value"); + } +} + +ScreenOrientation::ScreenOrientation(nsPIDOMWindow* aWindow, nsScreen* aScreen) + : DOMEventTargetHelper(aWindow), mScreen(aScreen) +{ + MOZ_ASSERT(aWindow); + MOZ_ASSERT(aScreen); + + hal::RegisterScreenConfigurationObserver(this); + + hal::ScreenConfiguration config; + hal::GetCurrentScreenConfiguration(&config); + mType = InternalOrientationToType(config.orientation()); + mAngle = config.angle(); + + nsIDocument* doc = GetResponsibleDocument(); + if (doc) { + doc->SetCurrentOrientation(mType, mAngle); + } +} + +ScreenOrientation::~ScreenOrientation() +{ + hal::UnregisterScreenConfigurationObserver(this); + MOZ_ASSERT(!mFullScreenListener); +} + +class ScreenOrientation::FullScreenEventListener final : public nsIDOMEventListener +{ + ~FullScreenEventListener() {} +public: + FullScreenEventListener() {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIDOMEVENTLISTENER +}; + +class ScreenOrientation::VisibleEventListener final : public nsIDOMEventListener +{ + ~VisibleEventListener() {} +public: + VisibleEventListener() {} + + NS_DECL_ISUPPORTS + NS_DECL_NSIDOMEVENTLISTENER +}; + +class ScreenOrientation::LockOrientationTask final : public nsIRunnable +{ + ~LockOrientationTask(); +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIRUNNABLE + + LockOrientationTask(ScreenOrientation* aScreenOrientation, + Promise* aPromise, + ScreenOrientationInternal aOrientationLock, + nsIDocument* aDocument, + bool aIsFullScreen); +protected: + bool OrientationLockContains(OrientationType aOrientationType); + + nsRefPtr mScreenOrientation; + nsRefPtr mPromise; + ScreenOrientationInternal mOrientationLock; + nsCOMPtr mDocument; + bool mIsFullScreen; +}; + +NS_IMPL_ISUPPORTS(ScreenOrientation::LockOrientationTask, nsIRunnable) + +ScreenOrientation::LockOrientationTask::LockOrientationTask( + ScreenOrientation* aScreenOrientation, Promise* aPromise, + ScreenOrientationInternal aOrientationLock, + nsIDocument* aDocument, bool aIsFullScreen) + : mScreenOrientation(aScreenOrientation), mPromise(aPromise), + mOrientationLock(aOrientationLock), mDocument(aDocument), + mIsFullScreen(aIsFullScreen) +{ + MOZ_ASSERT(aScreenOrientation); + MOZ_ASSERT(aPromise); + MOZ_ASSERT(aDocument); +} + +ScreenOrientation::LockOrientationTask::~LockOrientationTask() +{ +} + +bool +ScreenOrientation::LockOrientationTask::OrientationLockContains( + OrientationType aOrientationType) +{ + return mOrientationLock & OrientationTypeToInternal(aOrientationType); +} + +NS_IMETHODIMP +ScreenOrientation::LockOrientationTask::Run() +{ + // 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->MaybeResolve(JS::UndefinedHandleValue); + mDocument->SetOrientationPendingPromise(nullptr); + return NS_OK; + } + + if (mOrientationLock == eScreenOrientation_None) { + mScreenOrientation->UnlockDeviceOrientation(); + mPromise->MaybeResolve(JS::UndefinedHandleValue); + mDocument->SetOrientationPendingPromise(nullptr); + return NS_OK; + } + + ErrorResult rv; + bool result = mScreenOrientation->LockDeviceOrientation(mOrientationLock, + mIsFullScreen, rv); + if (NS_WARN_IF(rv.Failed())) { + return rv.StealNSResult(); + } + + if (NS_WARN_IF(!result)) { + mPromise->MaybeReject(NS_ERROR_UNEXPECTED); + mDocument->SetOrientationPendingPromise(nullptr); + return NS_OK; + } + + if (OrientationLockContains(mDocument->CurrentOrientationType()) || + (mOrientationLock == eScreenOrientation_Default && + mDocument->CurrentOrientationAngle() == 0)) { + // Orientation lock will not cause an orientation change. + mPromise->MaybeResolve(JS::UndefinedHandleValue); + mDocument->SetOrientationPendingPromise(nullptr); + } + + return NS_OK; +} + +already_AddRefed +ScreenOrientation::Lock(OrientationLockType aOrientation, ErrorResult& aRv) +{ + ScreenOrientationInternal orientation = eScreenOrientation_None; + + switch (aOrientation) { + case OrientationLockType::Any: + orientation = eScreenOrientation_PortraitPrimary | + eScreenOrientation_PortraitSecondary | + eScreenOrientation_LandscapePrimary | + eScreenOrientation_LandscapeSecondary; + break; + case OrientationLockType::Natural: + orientation |= eScreenOrientation_Default; + break; + case OrientationLockType::Landscape: + orientation = eScreenOrientation_LandscapePrimary | + eScreenOrientation_LandscapeSecondary; + break; + case OrientationLockType::Portrait: + orientation = eScreenOrientation_PortraitPrimary | + eScreenOrientation_PortraitSecondary; + break; + case OrientationLockType::Portrait_primary: + orientation = eScreenOrientation_PortraitPrimary; + break; + case OrientationLockType::Portrait_secondary: + orientation = eScreenOrientation_PortraitSecondary; + break; + case OrientationLockType::Landscape_primary: + orientation = eScreenOrientation_LandscapePrimary; + break; + case OrientationLockType::Landscape_secondary: + orientation = eScreenOrientation_LandscapeSecondary; + break; + default: + NS_WARNING("Unexpected orientation type"); + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + return LockInternal(orientation, aRv); +} + +static inline void +AbortOrientationPromises(nsIDocShell* aDocShell) +{ + MOZ_ASSERT(aDocShell); + + nsIDocument* doc = aDocShell->GetDocument(); + if (doc) { + Promise* promise = doc->GetOrientationPendingPromise(); + if (promise) { + promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); + doc->SetOrientationPendingPromise(nullptr); + } + } + + int32_t childCount; + aDocShell->GetChildCount(&childCount); + for (int32_t i = 0; i < childCount; i++) { + nsCOMPtr child; + if (NS_SUCCEEDED(aDocShell->GetChildAt(i, getter_AddRefs(child)))) { + nsCOMPtr childShell(do_QueryInterface(child)); + if (childShell) { + AbortOrientationPromises(childShell); + } + } + } +} + +already_AddRefed +ScreenOrientation::LockInternal(ScreenOrientationInternal aOrientation, ErrorResult& aRv) +{ + // Steps to apply an orientation lock as defined in spec. + + nsIDocument* doc = GetResponsibleDocument(); + if (NS_WARN_IF(!doc)) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + nsCOMPtr owner = GetOwner(); + if (NS_WARN_IF(!owner)) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + nsCOMPtr docShell = owner->GetDocShell(); + if (NS_WARN_IF(!docShell)) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + nsCOMPtr go = do_QueryInterface(owner); + MOZ_ASSERT(go); + nsRefPtr p = Promise::Create(go, aRv); + if (NS_WARN_IF(aRv.Failed())) { + return nullptr; + } + +#if !defined(MOZ_WIDGET_ANDROID) && !defined(MOZ_WIDGET_GONK) + // User agent does not support locking the screen orientation. + p->MaybeReject(NS_ERROR_DOM_NOT_SUPPORTED_ERR); + return p.forget(); +#else + LockPermission perm = GetLockOrientationPermission(true); + if (perm == LOCK_DENIED) { + p->MaybeReject(NS_ERROR_DOM_SECURITY_ERR); + return p.forget(); + } + + nsCOMPtr root; + docShell->GetSameTypeRootTreeItem(getter_AddRefs(root)); + nsCOMPtr rootShell(do_QueryInterface(root)); + if (!rootShell) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return nullptr; + } + + rootShell->SetOrientationLock(aOrientation); + AbortOrientationPromises(rootShell); + + doc->SetOrientationPendingPromise(p); + + nsCOMPtr 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(); +#endif +} + +bool +ScreenOrientation::LockDeviceOrientation(ScreenOrientationInternal aOrientation, + bool aIsFullScreen, ErrorResult& aRv) +{ + nsCOMPtr target = do_QueryInterface(GetOwner()->GetDoc()); + // We need to register a listener so we learn when we leave full-screen + // 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 false; + } + + if (NS_WARN_IF(!hal::LockScreenOrientation(aOrientation))) { + return false; + } + + // We are fullscreen and lock has been accepted. + if (aIsFullScreen && !mFullScreenListener) { + mFullScreenListener = new FullScreenEventListener(); + aRv = target->AddSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"), + mFullScreenListener, /* useCapture = */ true); + if (NS_WARN_IF(aRv.Failed())) { + return false; + } + } + + return true; +} + +void +ScreenOrientation::Unlock(ErrorResult& aRv) +{ + nsRefPtr p = LockInternal(eScreenOrientation_None, aRv); +} + +void +ScreenOrientation::UnlockDeviceOrientation() +{ + hal::UnlockScreenOrientation(); + + if (!mFullScreenListener) { + return; + } + + // Remove event listener in case of fullscreen lock. + nsCOMPtr target = do_QueryInterface(GetOwner()->GetDoc()); + if (target) { + nsresult rv = target->RemoveSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"), + mFullScreenListener, /* useCapture */ true); + NS_WARN_IF(NS_FAILED(rv)); + } + + mFullScreenListener = nullptr; +} + +OrientationType +ScreenOrientation::DeviceType() const +{ + return mType; +} + +uint16_t +ScreenOrientation::DeviceAngle() const +{ + return mAngle; +} + +OrientationType +ScreenOrientation::GetType(ErrorResult& aRv) const +{ + nsIDocument* doc = GetResponsibleDocument(); + if (!doc) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return OrientationType::Portrait_primary; + } + + return doc->CurrentOrientationType(); +} + +uint16_t +ScreenOrientation::GetAngle(ErrorResult& aRv) const +{ + nsIDocument* doc = GetResponsibleDocument(); + if (!doc) { + aRv.Throw(NS_ERROR_UNEXPECTED); + return 0; + } + + return doc->CurrentOrientationAngle(); +} + +ScreenOrientation::LockPermission +ScreenOrientation::GetLockOrientationPermission(bool aCheckSandbox) const +{ + nsCOMPtr owner = GetOwner(); + if (!owner) { + return LOCK_DENIED; + } + + // Chrome can always lock the screen orientation. + nsIDocShell* docShell = owner->GetDocShell(); + if (docShell && docShell->ItemType() == nsIDocShellTreeItem::typeChrome) { + return LOCK_ALLOWED; + } + + nsCOMPtr doc = owner->GetDoc(); + if (!doc || doc->Hidden()) { + return LOCK_DENIED; + } + + // Sandboxed without "allow-orientation-lock" + if (aCheckSandbox && doc->GetSandboxFlags() & SANDBOXED_ORIENTATION_LOCK) { + return LOCK_DENIED; + } + + // Apps can always lock the screen orientation. + if (doc->NodePrincipal()->GetAppStatus() >= + nsIPrincipal::APP_STATUS_INSTALLED) { + return LOCK_ALLOWED; + } + + if (Preferences::GetBool("dom.screenorientation.testing.non_fullscreen_lock_allow", + false)) { + return LOCK_ALLOWED; + } + + // Other content must be full-screen in order to lock orientation. + return doc->MozFullScreen() ? FULLSCREEN_LOCK_ALLOWED : LOCK_DENIED; +} + +nsIDocument* +ScreenOrientation::GetResponsibleDocument() const +{ + nsCOMPtr owner = GetOwner(); + if (!owner) { + return nullptr; + } + + return owner->GetDoc(); +} + +void +ScreenOrientation::Notify(const hal::ScreenConfiguration& aConfiguration) +{ + nsIDocument* doc = GetResponsibleDocument(); + if (!doc) { + return; + } + + ScreenOrientationInternal orientation = aConfiguration.orientation(); + if (orientation != eScreenOrientation_PortraitPrimary && + orientation != eScreenOrientation_PortraitSecondary && + orientation != eScreenOrientation_LandscapePrimary && + orientation != eScreenOrientation_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; + } + + OrientationType previousOrientation = mType; + mAngle = aConfiguration.angle(); + mType = InternalOrientationToType(orientation); + + nsresult rv; + if (mScreen && mType != previousOrientation) { + // Use of mozorientationchange is deprecated. + rv = mScreen->DispatchTrustedEvent(NS_LITERAL_STRING("mozorientationchange")); + NS_WARN_IF(NS_FAILED(rv)); + } + + if (doc->Hidden() && !mVisibleListener) { + mVisibleListener = new VisibleEventListener(); + rv = doc->AddSystemEventListener(NS_LITERAL_STRING("visibilitychange"), + mVisibleListener, /* useCapture = */ true); + NS_WARN_IF(NS_FAILED(rv)); + return; + } + + if (mType != doc->CurrentOrientationType()) { + doc->SetCurrentOrientation(mType, mAngle); + + Promise* pendingPromise = doc->GetOrientationPendingPromise(); + if (pendingPromise) { + pendingPromise->MaybeResolve(JS::UndefinedHandleValue); + doc->SetOrientationPendingPromise(nullptr); + } + + nsCOMPtr runnable = NS_NewRunnableMethod(this, + &ScreenOrientation::DispatchChangeEvent); + rv = NS_DispatchToMainThread(runnable); + NS_WARN_IF(NS_FAILED(rv)); + } +} + +void +ScreenOrientation::UpdateActiveOrientationLock(ScreenOrientationInternal aOrientation) +{ + if (aOrientation == eScreenOrientation_None) { + hal::UnlockScreenOrientation(); + } else { + hal::LockScreenOrientation(aOrientation); + } +} + +void +ScreenOrientation::DispatchChangeEvent() +{ + nsresult rv = DispatchTrustedEvent(NS_LITERAL_STRING("change")); + NS_WARN_IF(NS_FAILED(rv)); +} + +JSObject* +ScreenOrientation::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return ScreenOrientationBinding::Wrap(aCx, this, aGivenProto); +} + +NS_IMPL_ISUPPORTS(ScreenOrientation::VisibleEventListener, nsIDOMEventListener) + +NS_IMETHODIMP +ScreenOrientation::VisibleEventListener::HandleEvent(nsIDOMEvent* aEvent) +{ + // Document may have become visible, if the page is visible, run the steps + // following the "now visible algorithm" as specified. + nsCOMPtr target = aEvent->InternalDOMEvent()->GetCurrentTarget(); + MOZ_ASSERT(target); + + nsCOMPtr doc = do_QueryInterface(target); + if (!doc || doc->Hidden()) { + return NS_OK; + } + + nsGlobalWindow* win = static_cast(doc->GetInnerWindow()); + if (!win) { + return NS_OK; + } + + ErrorResult rv; + nsScreen* screen = win->GetScreen(rv); + if (NS_WARN_IF(rv.Failed())) { + return rv.StealNSResult(); + } + + MOZ_ASSERT(screen); + ScreenOrientation* orientation = screen->Orientation(); + MOZ_ASSERT(orientation); + + rv = target->RemoveSystemEventListener(NS_LITERAL_STRING("visibilitychange"), + this, true); + if (NS_WARN_IF(rv.Failed())) { + return rv.StealNSResult(); + } + + if (doc->CurrentOrientationType() != orientation->DeviceType()) { + doc->SetCurrentOrientation(orientation->DeviceType(), orientation->DeviceAngle()); + + Promise* pendingPromise = doc->GetOrientationPendingPromise(); + if (pendingPromise) { + pendingPromise->MaybeResolve(JS::UndefinedHandleValue); + doc->SetOrientationPendingPromise(nullptr); + } + + nsCOMPtr runnable = NS_NewRunnableMethod(orientation, + &ScreenOrientation::DispatchChangeEvent); + rv = NS_DispatchToMainThread(runnable); + if (NS_WARN_IF(rv.Failed())) { + return rv.StealNSResult(); + } + } + + return NS_OK; +} + +NS_IMPL_ISUPPORTS(ScreenOrientation::FullScreenEventListener, nsIDOMEventListener) + +NS_IMETHODIMP +ScreenOrientation::FullScreenEventListener::HandleEvent(nsIDOMEvent* aEvent) +{ +#ifdef DEBUG + nsAutoString eventType; + aEvent->GetType(eventType); + + MOZ_ASSERT(eventType.EqualsLiteral("mozfullscreenchange")); +#endif + + nsCOMPtr target = aEvent->InternalDOMEvent()->GetCurrentTarget(); + MOZ_ASSERT(target); + + nsCOMPtr doc = do_QueryInterface(target); + MOZ_ASSERT(doc); + + // 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->MozFullScreen()) { + return NS_OK; + } + + hal::UnlockScreenOrientation(); + + nsresult rv = target->RemoveSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"), + this, true); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} diff --git a/dom/base/ScreenOrientation.h b/dom/base/ScreenOrientation.h index ca2cdca5b1..796cb9a9bd 100644 --- a/dom/base/ScreenOrientation.h +++ b/dom/base/ScreenOrientation.h @@ -7,9 +7,16 @@ #ifndef mozilla_dom_ScreenOrientation_h #define mozilla_dom_ScreenOrientation_h +#include "mozilla/DOMEventTargetHelper.h" +#include "mozilla/dom/ScreenOrientationBinding.h" +#include "mozilla/HalScreenConfiguration.h" + +class nsScreen; + namespace mozilla { namespace dom { +class Promise; // Make sure that any change to ScreenOrientationInternal values are // also made in mobile/android/base/GeckoScreenOrientation.java typedef uint32_t ScreenOrientationInternal; @@ -23,6 +30,90 @@ static const ScreenOrientationInternal eScreenOrientation_LandscapeSecondary = 1 //it could be PortraitPrimary or LandscapePrimary depends on display resolution static const ScreenOrientationInternal eScreenOrientation_Default = 1u << 4; +class ScreenOrientation final : public DOMEventTargetHelper, + public mozilla::hal::ScreenConfigurationObserver +{ + // nsScreen has deprecated API that shares implementation. + friend class ::nsScreen; + +public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ScreenOrientation, mozilla::DOMEventTargetHelper) + NS_REALLY_FORWARD_NSIDOMEVENTTARGET(mozilla::DOMEventTargetHelper) + + IMPL_EVENT_HANDLER(change) + + ScreenOrientation(nsPIDOMWindow* aWindow, nsScreen* aScreen); + + already_AddRefed Lock(OrientationLockType aOrientation, + ErrorResult& aRv); + + void Unlock(ErrorResult& aRv); + + // DeviceType and DeviceAngle gets the current type and angle of the device. + OrientationType DeviceType() const; + uint16_t DeviceAngle() const; + + // GetType and GetAngle gets the type and angle of the responsible document + // (as defined in specification). + OrientationType GetType(ErrorResult& aRv) const; + uint16_t GetAngle(ErrorResult& aRv) const; + + virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; + + void Notify(const mozilla::hal::ScreenConfiguration& aConfiguration) override; + + static void UpdateActiveOrientationLock(ScreenOrientationInternal aOrientation); + +private: + virtual ~ScreenOrientation(); + + // Listener to unlock orientation if we leave fullscreen. + class FullScreenEventListener; + + // Listener to update document's orienation lock when document becomes + // visible. + class VisibleEventListener; + + // Task to run step to lock orientation as defined in specification. + class LockOrientationTask; + + enum LockPermission { + LOCK_DENIED, + FULLSCREEN_LOCK_ALLOWED, + LOCK_ALLOWED + }; + + // This method calls into the HAL to lock the device and sets + // up listeners for full screen change. + bool LockDeviceOrientation(ScreenOrientationInternal aOrientation, + bool aIsFullscreen, ErrorResult& aRv); + + // This method calls in to the HAL to unlock the device and removes + // full screen change listener. + void UnlockDeviceOrientation(); + + // This method performs the same function as |Lock| except it takes + // a ScreenOrientationInternal argument instead of an OrientationType. + // This method exists in order to share implementation with nsScreen that + // uses ScreenOrientationInternal. + already_AddRefed LockInternal(ScreenOrientationInternal aOrientation, + ErrorResult& aRv); + + void DispatchChangeEvent(); + + LockPermission GetLockOrientationPermission(bool aCheckSandbox) const; + + // Gets the responsible document as defined in the spec. + nsIDocument* GetResponsibleDocument() const; + + nsRefPtr mScreen; + nsRefPtr mFullScreenListener; + nsRefPtr mVisibleListener; + OrientationType mType; + uint16_t mAngle; +}; + } // namespace dom } // namespace mozilla diff --git a/dom/base/StructuredCloneHelper.cpp b/dom/base/StructuredCloneHelper.cpp index 20583cbee5..1ba82f186d 100644 --- a/dom/base/StructuredCloneHelper.cpp +++ b/dom/base/StructuredCloneHelper.cpp @@ -7,11 +7,18 @@ #include "StructuredCloneHelper.h" #include "ImageContainer.h" +#include "mozilla/AutoRestore.h" #include "mozilla/dom/BlobBinding.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/FileList.h" #include "mozilla/dom/FileListBinding.h" #include "mozilla/dom/ImageBitmap.h" #include "mozilla/dom/ImageBitmapBinding.h" +#include "mozilla/dom/MessagePort.h" +#include "mozilla/dom/MessagePortBinding.h" +#include "mozilla/dom/PMessagePort.h" #include "mozilla/dom/StructuredCloneTags.h" +#include "mozilla/dom/ToJSValue.h" namespace mozilla { namespace dom { diff --git a/dom/base/StructuredCloneHelper.h b/dom/base/StructuredCloneHelper.h index b8e97e99df..0c72104e66 100644 --- a/dom/base/StructuredCloneHelper.h +++ b/dom/base/StructuredCloneHelper.h @@ -12,6 +12,7 @@ #include "nsTArray.h" namespace mozilla { +class ErrorResult; namespace layers { class Image; } diff --git a/dom/base/moz.build b/dom/base/moz.build index 2925843e6f..7d084d2168 100644 --- a/dom/base/moz.build +++ b/dom/base/moz.build @@ -333,6 +333,7 @@ UNIFIED_SOURCES += [ 'ProcessGlobal.cpp', 'ResponsiveImageSelector.cpp', 'SameProcessMessageQueue.cpp', + 'ScreenOrientation.cpp', 'ScriptSettings.cpp', 'ShadowRoot.cpp', 'StructuredCloneHelper.cpp', diff --git a/dom/base/nsAttrValue.h b/dom/base/nsAttrValue.h index 66c1b0c47f..c1dee8b7a1 100644 --- a/dom/base/nsAttrValue.h +++ b/dom/base/nsAttrValue.h @@ -25,6 +25,9 @@ #include "mozilla/MemoryReporting.h" #include "mozilla/dom/BindingDeclarations.h" +// Undefine LoadImage to prevent naming conflict with Windows. +#undef LoadImage + class nsAString; class nsIDocument; class nsStyledElementNotElementCSSInlineStyle; diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index 70549e7442..7ddfde0aac 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -1341,6 +1341,7 @@ nsContentUtils::ParseSandboxAttributeToFlags(const nsAttrValue* sandboxAttr) | SANDBOXED_SCRIPTS | SANDBOXED_AUTOMATIC_FEATURES | SANDBOXED_POINTER_LOCK + | SANDBOXED_ORIENTATION_LOCK | SANDBOXED_DOMAIN; // Macro for updating the flag according to the keywords @@ -1352,6 +1353,7 @@ nsContentUtils::ParseSandboxAttributeToFlags(const nsAttrValue* sandboxAttr) IF_KEYWORD(allowscripts, SANDBOXED_SCRIPTS | SANDBOXED_AUTOMATIC_FEATURES) IF_KEYWORD(allowtopnavigation, SANDBOXED_TOPLEVEL_NAVIGATION) IF_KEYWORD(allowpointerlock, SANDBOXED_POINTER_LOCK) + IF_KEYWORD(alloworientationlock, SANDBOXED_ORIENTATION_LOCK) IF_KEYWORD(allowpopups, SANDBOXED_AUXILIARY_NAVIGATION) return out; diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 1d54f18908..70024fb526 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -38,6 +38,7 @@ #include "nsQueryObject.h" #include "nsDOMClassInfo.h" #include "mozilla/Services.h" +#include "nsScreen.h" #include "mozilla/AsyncEventDispatcher.h" #include "mozilla/BasicEvents.h" @@ -1922,6 +1923,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFirstBaseNodeWithHref) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDOMImplementation) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageMaps) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOrientationPendingPromise) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOriginalDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCachedEncoder) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mStateObjectCached) @@ -2022,6 +2024,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK(mChildrenCollection) NS_IMPL_CYCLE_COLLECTION_UNLINK(mRegistry) NS_IMPL_CYCLE_COLLECTION_UNLINK(mMasterDocument) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mOrientationPendingPromise) NS_IMPL_CYCLE_COLLECTION_UNLINK(mImportManager) NS_IMPL_CYCLE_COLLECTION_UNLINK(mSubImportLinks) NS_IMPL_CYCLE_COLLECTION_UNLINK(mFontFaceSet) @@ -12032,6 +12035,38 @@ nsDocument::IsFullScreenEnabled(bool aCallerIsChrome, bool aLogFailure) return allowed; } +uint16_t +nsDocument::CurrentOrientationAngle() const +{ + return mCurrentOrientationAngle; +} + +OrientationType +nsDocument::CurrentOrientationType() const +{ + return mCurrentOrientationType; +} + +void +nsDocument::SetCurrentOrientation(mozilla::dom::OrientationType aType, + uint16_t aAngle) +{ + mCurrentOrientationType = aType; + mCurrentOrientationAngle = aAngle; +} + +Promise* +nsDocument::GetOrientationPendingPromise() const +{ + return mOrientationPendingPromise; +} + +void +nsDocument::SetOrientationPendingPromise(Promise* aPromise) +{ + mOrientationPendingPromise = aPromise; +} + static void DispatchPointerLockChange(nsIDocument* aTarget) { diff --git a/dom/base/nsDocument.h b/dom/base/nsDocument.h index ca02523b06..4bd77b27d3 100644 --- a/dom/base/nsDocument.h +++ b/dom/base/nsDocument.h @@ -1273,6 +1273,13 @@ public: bool SetPointerLock(Element* aElement, int aCursorStyle); static void UnlockPointer(nsIDocument* aDoc = nullptr); + void SetCurrentOrientation(mozilla::dom::OrientationType aType, + uint16_t aAngle) override; + uint16_t CurrentOrientationAngle() const override; + mozilla::dom::OrientationType CurrentOrientationType() const override; + void SetOrientationPendingPromise(mozilla::dom::Promise* aPromise) override; + mozilla::dom::Promise* GetOrientationPendingPromise() const override; + // This method may fire a DOM event; if it does so it will happen // synchronously. void UpdateVisibilityState(); @@ -1510,6 +1517,8 @@ protected: virtual nsIScriptGlobalObject* GetScriptHandlingObjectInternal() const override; virtual bool InternalAllowXULXBL() override; + void UpdateScreenOrientation(); + #define NS_DOCUMENT_NOTIFY_OBSERVERS(func_, params_) \ NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers, nsIDocumentObserver, \ func_, params_); @@ -1674,6 +1683,13 @@ public: bool mAsyncFullscreenPending:1; + // ScreenOrientation "pending promise" as described by + // http://www.w3.org/TR/screen-orientation/ + nsRefPtr mOrientationPendingPromise; + + uint16_t mCurrentOrientationAngle; + mozilla::dom::OrientationType mCurrentOrientationType; + // Whether we're observing the "app-theme-changed" observer service // notification. We need to keep track of this because we might get multiple // OnPageShow notifications in a row without an OnPageHide in between, if diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index d018a60709..bbe3930262 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -79,6 +79,7 @@ GK_ATOM(allowevents, "allowevents") GK_ATOM(allownegativeassertions, "allownegativeassertions") GK_ATOM(allowforms,"allow-forms") GK_ATOM(allowfullscreen, "allowfullscreen") +GK_ATOM(alloworientationlock,"allow-orientation-lock") GK_ATOM(allowpointerlock,"allow-pointer-lock") GK_ATOM(allowpopups,"allow-popups") GK_ATOM(allowsameorigin,"allow-same-origin") diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h index b28c6dde38..a1e03e05c1 100644 --- a/dom/base/nsIDocument.h +++ b/dom/base/nsIDocument.h @@ -132,7 +132,9 @@ class MediaQueryList; class GlobalObject; class NodeFilter; class NodeIterator; +enum class OrientationType : uint32_t; class ProcessingInstruction; +class Promise; class Selection; class StyleSheetList; class SVGDocument; @@ -1204,6 +1206,14 @@ public: static void UnlockPointer(nsIDocument* aDoc = nullptr); + // ScreenOrientation related APIs + + virtual void SetCurrentOrientation(mozilla::dom::OrientationType aType, + uint16_t aAngle) = 0; + virtual uint16_t CurrentOrientationAngle() const = 0; + virtual mozilla::dom::OrientationType CurrentOrientationType() const = 0; + virtual void SetOrientationPendingPromise(mozilla::dom::Promise* aPromise) = 0; + virtual mozilla::dom::Promise* GetOrientationPendingPromise() const = 0; //---------------------------------------------------------------------- diff --git a/dom/base/nsSandboxFlags.h b/dom/base/nsSandboxFlags.h index 2725ce4baa..0435db5f61 100644 --- a/dom/base/nsSandboxFlags.h +++ b/dom/base/nsSandboxFlags.h @@ -76,4 +76,9 @@ const unsigned long SANDBOXED_DOMAIN = 0x100; * showModalDialog() method. */ const unsigned long SANDBOXED_AUXILIARY_NAVIGATION = 0x200; + +/** + * This flag prevents locking screen orientation. + */ +const unsigned long SANDBOXED_ORIENTATION_LOCK = 0x400; #endif diff --git a/dom/base/nsScreen.cpp b/dom/base/nsScreen.cpp index 0cbba5c5be..06d86d4753 100644 --- a/dom/base/nsScreen.cpp +++ b/dom/base/nsScreen.cpp @@ -4,7 +4,6 @@ * 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/. */ -#include "mozilla/Hal.h" #include "mozilla/dom/Event.h" // for nsIDOMEvent::InternalDOMEvent() #include "mozilla/dom/ScreenBinding.h" #include "nsScreen.h" @@ -36,36 +35,32 @@ nsScreen::Create(nsPIDOMWindow* aWindow) NS_ENSURE_TRUE(sgo, nullptr); nsRefPtr screen = new nsScreen(aWindow); - - hal::RegisterScreenConfigurationObserver(screen); - hal::ScreenConfiguration config; - hal::GetCurrentScreenConfiguration(&config); - screen->mOrientationInternal = config.orientation(); - return screen.forget(); } nsScreen::nsScreen(nsPIDOMWindow* aWindow) : DOMEventTargetHelper(aWindow) - , mEventListener(nullptr) + , mScreenOrientation(new ScreenOrientation(aWindow, this)) { } nsScreen::~nsScreen() { - MOZ_ASSERT(!mEventListener); - hal::UnregisterScreenConfigurationObserver(this); } // QueryInterface implementation for nsScreen -NS_INTERFACE_MAP_BEGIN(nsScreen) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(nsScreen) NS_INTERFACE_MAP_ENTRY(nsIDOMScreen) NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) NS_IMPL_ADDREF_INHERITED(nsScreen, DOMEventTargetHelper) NS_IMPL_RELEASE_INHERITED(nsScreen, DOMEventTargetHelper) +NS_IMPL_CYCLE_COLLECTION_INHERITED(nsScreen, + DOMEventTargetHelper, + mScreenOrientation) + int32_t nsScreen::GetPixelDepth(ErrorResult& aRv) { @@ -162,45 +157,33 @@ nsScreen::GetAvailRect(nsRect& aRect) return NS_OK; } -void -nsScreen::Notify(const hal::ScreenConfiguration& aConfiguration) +mozilla::dom::ScreenOrientation* +nsScreen::Orientation() const { - ScreenOrientationInternal previousOrientation = mOrientationInternal; - mOrientationInternal = aConfiguration.orientation(); - - NS_ASSERTION(mOrientationInternal == eScreenOrientation_PortraitPrimary || - mOrientationInternal == eScreenOrientation_PortraitSecondary || - mOrientationInternal == eScreenOrientation_LandscapePrimary || - mOrientationInternal == eScreenOrientation_LandscapeSecondary, - "Invalid orientation value passed to notify method!"); - - if (mOrientationInternal != previousOrientation) { - DispatchTrustedEvent(NS_LITERAL_STRING("mozorientationchange")); - } + return mScreenOrientation; } void -nsScreen::GetMozOrientation(nsString& aOrientation) +nsScreen::GetMozOrientation(nsString& aOrientation) const { if (ShouldResistFingerprinting()) { aOrientation.AssignLiteral("landscape-primary"); } else { - switch (mOrientationInternal) { - case eScreenOrientation_PortraitPrimary: + switch (mScreenOrientation->DeviceType()) { + case OrientationType::Portrait_primary: aOrientation.AssignLiteral("portrait-primary"); break; - case eScreenOrientation_PortraitSecondary: + case OrientationType::Portrait_secondary: aOrientation.AssignLiteral("portrait-secondary"); break; - case eScreenOrientation_LandscapePrimary: + case OrientationType::Landscape_primary: aOrientation.AssignLiteral("landscape-primary"); break; - case eScreenOrientation_LandscapeSecondary: + case OrientationType::Landscape_secondary: aOrientation.AssignLiteral("landscape-secondary"); break; - case eScreenOrientation_None: default: - MOZ_CRASH("Unacceptable mOrientationInternal value"); + MOZ_CRASH("Unacceptable screen orientation type."); } } } @@ -214,35 +197,6 @@ nsScreen::GetSlowMozOrientation(nsAString& aOrientation) return NS_OK; } -nsScreen::LockPermission -nsScreen::GetLockOrientationPermission() const -{ - nsCOMPtr owner = GetOwner(); - if (!owner) { - return LOCK_DENIED; - } - - // Chrome can always lock the screen orientation. - nsIDocShell* docShell = owner->GetDocShell(); - if (docShell && docShell->ItemType() == nsIDocShellTreeItem::typeChrome) { - return LOCK_ALLOWED; - } - - nsCOMPtr doc = owner->GetDoc(); - if (!doc || doc->Hidden()) { - return LOCK_DENIED; - } - - // Apps can always lock the screen orientation. - if (doc->NodePrincipal()->GetAppStatus() >= - nsIPrincipal::APP_STATUS_INSTALLED) { - return LOCK_ALLOWED; - } - - // Other content must be full-screen in order to lock orientation. - return doc->MozFullScreen() ? FULLSCREEN_LOCK_ALLOWED : LOCK_DENIED; -} - bool nsScreen::MozLockOrientation(const nsAString& aOrientation, ErrorResult& aRv) { @@ -287,34 +241,13 @@ nsScreen::MozLockOrientation(const Sequence& aOrientations, } } - switch (GetLockOrientationPermission()) { - case LOCK_DENIED: + switch (mScreenOrientation->GetLockOrientationPermission(false)) { + case ScreenOrientation::LOCK_DENIED: return false; - case LOCK_ALLOWED: - return hal::LockScreenOrientation(orientation); - case FULLSCREEN_LOCK_ALLOWED: { - // We need to register a listener so we learn when we leave full-screen - // 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. - nsCOMPtr target = do_QueryInterface(GetOwner()->GetDoc()); - if (!target) { - return false; - } - - if (!hal::LockScreenOrientation(orientation)) { - return false; - } - - // We are fullscreen and lock has been accepted. - if (!mEventListener) { - mEventListener = new FullScreenEventListener(); - } - - aRv = target->AddSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"), - mEventListener, /* useCapture = */ true); - return true; - } + case ScreenOrientation::LOCK_ALLOWED: + return mScreenOrientation->LockDeviceOrientation(orientation, false, aRv); + case ScreenOrientation::FULLSCREEN_LOCK_ALLOWED: + return mScreenOrientation->LockDeviceOrientation(orientation, true, aRv); } // This is only for compilers that don't understand that the previous switch @@ -325,20 +258,7 @@ nsScreen::MozLockOrientation(const Sequence& aOrientations, void nsScreen::MozUnlockOrientation() { - hal::UnlockScreenOrientation(); - - if (!mEventListener) { - return; - } - - // Remove event listener in case of fullscreen lock. - nsCOMPtr target = do_QueryInterface(GetOwner()->GetDoc()); - if (target) { - target->RemoveSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"), - mEventListener, /* useCapture */ true); - } - - mEventListener = nullptr; + mScreenOrientation->UnlockDeviceOrientation(); } bool @@ -361,39 +281,6 @@ nsScreen::WrapObject(JSContext* aCx, JS::Handle aGivenProto) return ScreenBinding::Wrap(aCx, this, aGivenProto); } -NS_IMPL_ISUPPORTS(nsScreen::FullScreenEventListener, nsIDOMEventListener) - -NS_IMETHODIMP -nsScreen::FullScreenEventListener::HandleEvent(nsIDOMEvent* aEvent) -{ -#ifdef DEBUG - nsAutoString eventType; - aEvent->GetType(eventType); - - MOZ_ASSERT(eventType.EqualsLiteral("mozfullscreenchange")); -#endif - - nsCOMPtr target = aEvent->InternalDOMEvent()->GetCurrentTarget(); - MOZ_ASSERT(target); - - nsCOMPtr doc = do_QueryInterface(target); - MOZ_ASSERT(doc); - - // 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->MozFullScreen()) { - return NS_OK; - } - - target->RemoveSystemEventListener(NS_LITERAL_STRING("mozfullscreenchange"), - this, true); - - hal::UnlockScreenOrientation(); - - return NS_OK; -} - nsresult nsScreen::GetWindowInnerRect(nsRect& aRect) { diff --git a/dom/base/nsScreen.h b/dom/base/nsScreen.h index 9030bb69d8..2041c1c759 100644 --- a/dom/base/nsScreen.h +++ b/dom/base/nsScreen.h @@ -10,7 +10,6 @@ #include "mozilla/dom/ScreenOrientation.h" #include "mozilla/DOMEventTargetHelper.h" #include "mozilla/ErrorResult.h" -#include "mozilla/HalScreenConfiguration.h" #include "nsIDOMScreen.h" #include "nsCOMPtr.h" #include "nsRect.h" @@ -20,7 +19,6 @@ class nsDeviceContext; // Script "screen" object class nsScreen : public mozilla::DOMEventTargetHelper , public nsIDOMScreen - , public mozilla::hal::ScreenConfigurationObserver { typedef mozilla::ErrorResult ErrorResult; public: @@ -28,6 +26,7 @@ public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIDOMSCREEN + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsScreen, mozilla::DOMEventTargetHelper) NS_REALLY_FORWARD_NSIDOMEVENTTARGET(mozilla::DOMEventTargetHelper) nsPIDOMWindow* GetParentObject() const @@ -115,7 +114,8 @@ public: return rect.height; } - void GetMozOrientation(nsString& aOrientation); + // Deprecated + void GetMozOrientation(nsString& aOrientation) const; IMPL_EVENT_HANDLER(mozorientationchange) @@ -125,7 +125,7 @@ public: virtual JSObject* WrapObject(JSContext* aCx, JS::Handle aGivenProto) override; - void Notify(const mozilla::hal::ScreenConfiguration& aConfiguration) override; + mozilla::dom::ScreenOrientation* Orientation() const; protected: nsDeviceContext* GetDeviceContext(); @@ -133,35 +133,15 @@ protected: nsresult GetAvailRect(nsRect& aRect); nsresult GetWindowInnerRect(nsRect& aRect); - mozilla::dom::ScreenOrientationInternal mOrientationInternal; - private: - class FullScreenEventListener final : public nsIDOMEventListener - { - ~FullScreenEventListener() {} - public: - FullScreenEventListener() {} - - NS_DECL_ISUPPORTS - NS_DECL_NSIDOMEVENTLISTENER - }; - explicit nsScreen(nsPIDOMWindow* aWindow); virtual ~nsScreen(); - enum LockPermission { - LOCK_DENIED, - FULLSCREEN_LOCK_ALLOWED, - LOCK_ALLOWED - }; - - LockPermission GetLockOrientationPermission() const; - bool IsDeviceSizePageSize(); bool ShouldResistFingerprinting() const; - nsRefPtr mEventListener; + nsRefPtr mScreenOrientation; }; #endif /* nsScreen_h___ */ diff --git a/dom/base/test/file_lock_orientation.html b/dom/base/test/file_lock_orientation.html new file mode 100644 index 0000000000..e370ab91c8 --- /dev/null +++ b/dom/base/test/file_lock_orientation.html @@ -0,0 +1,14 @@ + + + + + diff --git a/dom/base/test/file_record_orientation.html b/dom/base/test/file_record_orientation.html new file mode 100644 index 0000000000..a01587507b --- /dev/null +++ b/dom/base/test/file_record_orientation.html @@ -0,0 +1,16 @@ + + + + diff --git a/dom/base/test/mochitest.ini b/dom/base/test/mochitest.ini index 1ad4e0921a..db9beff154 100644 --- a/dom/base/test/mochitest.ini +++ b/dom/base/test/mochitest.ini @@ -179,11 +179,13 @@ support-files = file_htmlserializer_2_latin1.html file_htmlserializer_ipv6.html file_htmlserializer_ipv6_out.html + file_lock_orientation.html file_mozfiledataurl_audio.ogg file_mozfiledataurl_doc.html file_mozfiledataurl_img.jpg file_mozfiledataurl_inner.html file_mozfiledataurl_text.txt + file_record_orientation.html file_restrictedEventSource.sjs file_simplecontentpolicy.js file_websocket_basic_wsh.py @@ -222,6 +224,7 @@ support-files = invalid_accesscontrol.resource invalid_accesscontrol.resource^headers^ mutationobserver_dialog.html + orientationcommon.js progressserver.sjs responseIdentical.sjs script-1_bug597345.sjs @@ -304,6 +307,14 @@ skip-if = (buildapp == 'b2g' && toolkit != 'gonk') # Fails on b2g-desktop, track [test_pluginAudioNotification.html] skip-if = (buildapp == 'b2g' || buildapp == 'mulet' || toolkit == 'android') # Plugins don't work on Android and/or B2G/Mulet [test_screen_orientation.html] +[test_orientation_alternate.html] +skip-if = toolkit != 'gonk' +[test_orientation_frame.html] +skip-if = toolkit != 'gonk' +[test_orientation_frame_lock.html] +skip-if = toolkit != 'gonk' +[test_orientation_sandbox_no_lock.html] +skip-if = toolkit != 'gonk' [test_settimeout_extra_arguments.html] [test_settimeout_inner.html] [test_setting_opener.html] diff --git a/dom/base/test/orientationcommon.js b/dom/base/test/orientationcommon.js new file mode 100644 index 0000000000..2d87cf7207 --- /dev/null +++ b/dom/base/test/orientationcommon.js @@ -0,0 +1,21 @@ +function specialPowersLock(orientation) { + return new Promise(function(resolve, reject) { + SpecialPowers.pushPrefEnv({ + 'set': [ ["dom.screenorientation.testing.non_fullscreen_lock_allow", true] ] + }, function() { + var p = screen.orientation.lock(orientation); + resolve(p); + }); + }); +} + +function specialPowersUnlock() { + return new Promise(function(resolve, reject) { + SpecialPowers.pushPrefEnv({ + 'set': [ ["dom.screenorientation.testing.non_fullscreen_lock_allow", true] ] + }, function() { + screen.orientation.unlock(); + resolve(); + }); + }); +} diff --git a/dom/base/test/test_orientation_alternate.html b/dom/base/test/test_orientation_alternate.html new file mode 100644 index 0000000000..7276ad82cc --- /dev/null +++ b/dom/base/test/test_orientation_alternate.html @@ -0,0 +1,27 @@ + + +Test for ScreenOrientation API + + + +
+ diff --git a/dom/base/test/test_orientation_frame.html b/dom/base/test/test_orientation_frame.html new file mode 100644 index 0000000000..748b3264ea --- /dev/null +++ b/dom/base/test/test_orientation_frame.html @@ -0,0 +1,37 @@ + + +Test for ScreenOrientation API + + + +
+ + diff --git a/dom/base/test/test_orientation_frame_lock.html b/dom/base/test/test_orientation_frame_lock.html new file mode 100644 index 0000000000..f8b7a65d08 --- /dev/null +++ b/dom/base/test/test_orientation_frame_lock.html @@ -0,0 +1,46 @@ + + +Test for ScreenOrientation API + + + +
+ + diff --git a/dom/base/test/test_orientation_sandbox_no_lock.html b/dom/base/test/test_orientation_sandbox_no_lock.html new file mode 100644 index 0000000000..e020a6daa9 --- /dev/null +++ b/dom/base/test/test_orientation_sandbox_no_lock.html @@ -0,0 +1,36 @@ + + +Test for ScreenOrientation API + + + +
+ + diff --git a/dom/canvas/ImageBitmap.h b/dom/canvas/ImageBitmap.h index 568b46610d..f80f3ce452 100644 --- a/dom/canvas/ImageBitmap.h +++ b/dom/canvas/ImageBitmap.h @@ -18,6 +18,8 @@ struct JSContext; struct JSStructuredCloneReader; struct JSStructuredCloneWriter; +class nsIGlobalObject; + namespace mozilla { class ErrorResult; diff --git a/dom/mobilemessage/MobileMessageManager.h b/dom/mobilemessage/MobileMessageManager.h index 73502930cb..a858490189 100644 --- a/dom/mobilemessage/MobileMessageManager.h +++ b/dom/mobilemessage/MobileMessageManager.h @@ -14,11 +14,11 @@ class nsISmsService; class nsIDOMMozSmsMessage; class nsIDOMMozMmsMessage; -class Promise; namespace mozilla { namespace dom { +class Promise; class DOMRequest; class DOMCursor; struct MmsParameters; diff --git a/dom/tests/mochitest/general/test_interfaces.html b/dom/tests/mochitest/general/test_interfaces.html index 8bf542377c..f7867241d2 100644 --- a/dom/tests/mochitest/general/test_interfaces.html +++ b/dom/tests/mochitest/general/test_interfaces.html @@ -965,6 +965,8 @@ var interfaceNamesInGlobalScope = "RTCStatsReport", // IMPORTANT: Do not change this list without review from a DOM peer! "Screen", +// IMPORTANT: Do not change this list without review from a DOM peer! + "ScreenOrientation", // IMPORTANT: Do not change this list without review from a DOM peer! "ScriptProcessorNode", // IMPORTANT: Do not change this list without review from a DOM peer! diff --git a/dom/webidl/Screen.webidl b/dom/webidl/Screen.webidl index ca01103122..6b5824fa88 100644 --- a/dom/webidl/Screen.webidl +++ b/dom/webidl/Screen.webidl @@ -29,6 +29,7 @@ interface Screen : EventTarget { readonly attribute long availLeft; /** + * DEPRECATED, use ScreenOrientation API instead. * Returns the current screen orientation. * Can be: landscape-primary, landscape-secondary, * portrait-primary or portrait-secondary. @@ -38,6 +39,7 @@ interface Screen : EventTarget { attribute EventHandler onmozorientationchange; /** + * DEPRECATED, use ScreenOrientation API instead. * Lock screen orientation to the specified type. */ [Throws, UnsafeInPrerendering] @@ -46,8 +48,14 @@ interface Screen : EventTarget { boolean mozLockOrientation(sequence orientation); /** + * DEPRECATED, use ScreenOrientation API instead. * Unlock the screen orientation. */ [UnsafeInPrerendering] void mozUnlockOrientation(); }; + +// https://w3c.github.io/screen-orientation +partial interface Screen { + readonly attribute ScreenOrientation orientation; +}; diff --git a/dom/webidl/ScreenOrientation.webidl b/dom/webidl/ScreenOrientation.webidl new file mode 100644 index 0000000000..48a2c11702 --- /dev/null +++ b/dom/webidl/ScreenOrientation.webidl @@ -0,0 +1,42 @@ +/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* 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/. + * + * The origin of this IDL file is + * https://w3c.github.io/screen-orientation + * + * Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights + * Reserved. W3C liability, trademark and document use rules apply. + */ + +enum OrientationType { + "portrait-primary", + "portrait-secondary", + "landscape-primary", + "landscape-secondary" +}; + +enum OrientationLockType { + "any", + "natural", + "landscape", + "portrait", + "portrait-primary", + "portrait-secondary", + "landscape-primary", + "landscape-secondary" +}; + +[UnsafeInPrerendering] +interface ScreenOrientation : EventTarget { + [Throws] + Promise lock(OrientationLockType orientation); + [Throws] + void unlock(); + [Throws] + readonly attribute OrientationType type; + [Throws] + readonly attribute unsigned short angle; + attribute EventHandler onchange; +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 66e8168e92..25b0cdce98 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -385,6 +385,7 @@ WEBIDL_FILES = [ 'RGBColor.webidl', 'RTCStatsReport.webidl', 'Screen.webidl', + 'ScreenOrientation.webidl', 'ScriptProcessorNode.webidl', 'ScrollAreaEvent.webidl', 'ScrollBoxObject.webidl', diff --git a/dom/workers/ServiceWorker.cpp b/dom/workers/ServiceWorker.cpp index 4cf6fa61b4..46129c6c3d 100644 --- a/dom/workers/ServiceWorker.cpp +++ b/dom/workers/ServiceWorker.cpp @@ -52,11 +52,6 @@ ServiceWorker::ServiceWorker(nsPIDOMWindow* aWindow, MOZ_ASSERT(aInfo); MOZ_ASSERT(mSharedWorker); - if (aWindow) { - mDocument = aWindow->GetExtantDoc(); - mWindow = aWindow->GetOuterWindow(); - } - // This will update our state too. mInfo->AppendWorker(this); } @@ -74,7 +69,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ServiceWorker) NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper) NS_IMPL_CYCLE_COLLECTION_INHERITED(ServiceWorker, DOMEventTargetHelper, - mSharedWorker, mDocument, mWindow) + mSharedWorker) JSObject* ServiceWorker::WrapObject(JSContext* aCx, JS::Handle aGivenProto) @@ -103,12 +98,9 @@ ServiceWorker::PostMessage(JSContext* aCx, JS::Handle aMessage, return; } - MOZ_ASSERT(mDocument && mWindow, - "Cannot call PostMessage on a ServiceWorker object that doesn't " - "have a window"); - - nsAutoPtr clientInfo( - new ServiceWorkerClientInfo(mDocument, mWindow)); + nsCOMPtr window = do_QueryInterface(GetParentObject()); + nsCOMPtr doc = window->GetExtantDoc(); + nsAutoPtr clientInfo(new ServiceWorkerClientInfo(doc)); workerPrivate->PostMessageToServiceWorker(aCx, aMessage, aTransferable, clientInfo, aRv); diff --git a/dom/workers/ServiceWorker.h b/dom/workers/ServiceWorker.h index d744802714..9c438ba5c2 100644 --- a/dom/workers/ServiceWorker.h +++ b/dom/workers/ServiceWorker.h @@ -11,7 +11,6 @@ #include "mozilla/dom/BindingDeclarations.h" #include "mozilla/dom/ServiceWorkerBinding.h" // For ServiceWorkerState. -class nsIDocument; class nsPIDOMWindow; namespace mozilla { @@ -92,10 +91,6 @@ private: // can be released and recreated as required rather than re-implement some of // the SharedWorker logic. nsRefPtr mSharedWorker; - // We need to keep the document and window alive for PostMessage to be able - // to access them. - nsCOMPtr mDocument; - nsCOMPtr mWindow; }; } // namespace workers diff --git a/dom/workers/ServiceWorkerClient.cpp b/dom/workers/ServiceWorkerClient.cpp index 843f46fdf1..e52d26629e 100644 --- a/dom/workers/ServiceWorkerClient.cpp +++ b/dom/workers/ServiceWorkerClient.cpp @@ -29,8 +29,7 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ServiceWorkerClient) NS_INTERFACE_MAP_ENTRY(nsISupports) NS_INTERFACE_MAP_END -ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc, - nsPIDOMWindow* aWindow) +ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc) : mWindowId(0) { MOZ_ASSERT(aDoc); @@ -55,7 +54,7 @@ ServiceWorkerClientInfo::ServiceWorkerClientInfo(nsIDocument* aDoc, NS_WARNING("Failed to get focus information."); } - nsRefPtr outerWindow = static_cast(aWindow); + nsRefPtr outerWindow = static_cast(aDoc->GetWindow()); MOZ_ASSERT(outerWindow); if (!outerWindow->IsTopLevelWindow()) { mFrameType = FrameType::Nested; @@ -135,7 +134,7 @@ private: JS::Rooted messageData(aCx); if (!mBuffer.read(aCx, &messageData, - WorkerStructuredCloneCallbacks(true), &closure)) { + WorkerStructuredCloneCallbacks(), &closure)) { xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); return NS_ERROR_FAILURE; } @@ -195,7 +194,7 @@ ServiceWorkerClient::PostMessage(JSContext* aCx, JS::Handle aMessage, transferable.setObject(*array); } - const JSStructuredCloneCallbacks* callbacks = WorkerStructuredCloneCallbacks(false); + const JSStructuredCloneCallbacks* callbacks = WorkerStructuredCloneCallbacks(); WorkerStructuredCloneClosure closure; diff --git a/dom/workers/ServiceWorkerClient.h b/dom/workers/ServiceWorkerClient.h index 375017fff9..fcaf2cc647 100644 --- a/dom/workers/ServiceWorkerClient.h +++ b/dom/workers/ServiceWorkerClient.h @@ -15,7 +15,6 @@ #include "mozilla/dom/ClientBinding.h" class nsIDocument; -class nsPIDOMWindow; namespace mozilla { namespace dom { @@ -32,7 +31,7 @@ class ServiceWorkerClientInfo final friend class ServiceWorkerWindowClient; public: - ServiceWorkerClientInfo(nsIDocument* aDoc, nsPIDOMWindow* aWindow); + explicit ServiceWorkerClientInfo(nsIDocument* aDoc); private: nsString mClientId; diff --git a/dom/workers/ServiceWorkerManager.cpp b/dom/workers/ServiceWorkerManager.cpp index a724f45cef..8e83bf6cd9 100644 --- a/dom/workers/ServiceWorkerManager.cpp +++ b/dom/workers/ServiceWorkerManager.cpp @@ -3876,7 +3876,7 @@ ServiceWorkerManager::DispatchFetchEvent(const OriginAttributes& aOriginAttribut MOZ_ASSERT(aDoc); aRv = GetDocumentController(aDoc->GetInnerWindow(), failRunnable, getter_AddRefs(serviceWorker)); - clientInfo = new ServiceWorkerClientInfo(aDoc, aDoc->GetWindow()); + clientInfo = new ServiceWorkerClientInfo(aDoc); } else { nsCOMPtr internalChannel; aRv = aChannel->GetChannel(getter_AddRefs(internalChannel)); @@ -4261,7 +4261,7 @@ EnumControlledDocuments(nsISupports* aKey, return PL_DHASH_NEXT; } - ServiceWorkerClientInfo clientInfo(document, document->GetWindow()); + ServiceWorkerClientInfo clientInfo(document); data->mDocuments.AppendElement(clientInfo); return PL_DHASH_NEXT; diff --git a/dom/workers/ServiceWorkerWindowClient.cpp b/dom/workers/ServiceWorkerWindowClient.cpp index 8e0f531bff..3e0e2a06d6 100644 --- a/dom/workers/ServiceWorkerWindowClient.cpp +++ b/dom/workers/ServiceWorkerWindowClient.cpp @@ -91,9 +91,14 @@ public: UniquePtr clientInfo; if (window) { - nsContentUtils::DispatchChromeEvent(window->GetExtantDoc(), window->GetOuterWindow(), NS_LITERAL_STRING("DOMServiceWorkerFocusClient"), true, true); - clientInfo.reset(new ServiceWorkerClientInfo(window->GetDocument(), - window->GetOuterWindow())); + nsCOMPtr doc = window->GetDocument(); + if (doc) { + nsContentUtils::DispatchChromeEvent(doc, + window->GetOuterWindow(), + NS_LITERAL_STRING("DOMServiceWorkerFocusClient"), + true, true); + clientInfo.reset(new ServiceWorkerClientInfo(doc)); + } } DispatchResult(Move(clientInfo)); diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 179da982e9..8e1cef4b5e 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -406,8 +406,7 @@ EnsureBlobForBackgroundManager(BlobImpl* aBlobImpl, already_AddRefed ReadBlobOrFileNoWrap(JSContext* aCx, - JSStructuredCloneReader* aReader, - bool aIsMainThread) + JSStructuredCloneReader* aReader) { MOZ_ASSERT(aCx); MOZ_ASSERT(aReader); @@ -426,14 +425,11 @@ ReadBlobOrFileNoWrap(JSContext* aCx, MOZ_ASSERT(blobImpl); nsCOMPtr parent; - if (aIsMainThread) { - AssertIsOnMainThread(); - + if (NS_IsMainThread()) { nsCOMPtr scriptGlobal = nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(aCx)); parent = do_QueryInterface(scriptGlobal); } else { - MOZ_ASSERT(!NS_IsMainThread()); WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(aCx); MOZ_ASSERT(workerPrivate); @@ -450,10 +446,9 @@ ReadBlobOrFileNoWrap(JSContext* aCx, void ReadBlobOrFile(JSContext* aCx, JSStructuredCloneReader* aReader, - bool aIsMainThread, JS::MutableHandle aBlobOrFile) { - nsRefPtr blob = ReadBlobOrFileNoWrap(aCx, aReader, aIsMainThread); + nsRefPtr blob = ReadBlobOrFileNoWrap(aCx, aReader); aBlobOrFile.set(blob->WrapObject(aCx, nullptr)); } @@ -461,7 +456,6 @@ ReadBlobOrFile(JSContext* aCx, void ReadFormData(JSContext* aCx, JSStructuredCloneReader* aReader, - bool aIsMainThread, uint32_t aCount, JS::MutableHandle aFormData) { @@ -470,8 +464,7 @@ ReadFormData(JSContext* aCx, MOZ_ASSERT(!aFormData); nsCOMPtr parent; - if (aIsMainThread) { - AssertIsOnMainThread(); + if (NS_IsMainThread()) { nsCOMPtr scriptGlobal = nsJSUtils::GetStaticScriptGlobal(JS::CurrentGlobalOrNull(aCx)); parent = do_QueryInterface(scriptGlobal); @@ -502,7 +495,7 @@ ReadFormData(JSContext* aCx, if (isFile) { // Read out the tag since the blob reader isn't expecting it. MOZ_ALWAYS_TRUE(JS_ReadUint32Pair(aReader, &dummy, &dummy)); - nsRefPtr blob = ReadBlobOrFileNoWrap(aCx, aReader, aIsMainThread); + nsRefPtr blob = ReadBlobOrFileNoWrap(aCx, aReader); MOZ_ASSERT(blob); formData->Append(name, *blob, thirdArg); } else { @@ -516,28 +509,29 @@ ReadFormData(JSContext* aCx, } bool -WriteBlobOrFile(JSContext* aCx, - JSStructuredCloneWriter* aWriter, - BlobImpl* aBlobOrBlobImpl, +WriteBlobOrFile(JSStructuredCloneWriter* aWriter, + BlobImpl* aBlobImpl, WorkerStructuredCloneClosure& aClosure) { - MOZ_ASSERT(aCx); MOZ_ASSERT(aWriter); - MOZ_ASSERT(aBlobOrBlobImpl); + MOZ_ASSERT(aBlobImpl); - nsRefPtr blobImpl = EnsureBlobForBackgroundManager(aBlobOrBlobImpl); - MOZ_ASSERT(blobImpl); - - aBlobOrBlobImpl = blobImpl; - - if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0)) || - NS_WARN_IF(!JS_WriteBytes(aWriter, - &aBlobOrBlobImpl, - sizeof(aBlobOrBlobImpl)))) { + if (!aBlobImpl->MayBeClonedToOtherThreads()) { + NS_WARNING("Not all the blob implementations can be sent between threads."); return false; } - aClosure.mClonedObjects.AppendElement(aBlobOrBlobImpl); + nsRefPtr blobImpl = EnsureBlobForBackgroundManager(aBlobImpl); + MOZ_ASSERT(blobImpl); + + aBlobImpl = blobImpl; + + if (NS_WARN_IF(!JS_WriteUint32Pair(aWriter, DOMWORKER_SCTAG_BLOB, 0)) || + NS_WARN_IF(!JS_WriteBytes(aWriter, &aBlobImpl, sizeof(aBlobImpl)))) { + return false; + } + + aClosure.mClonedObjects.AppendElement(aBlobImpl); return true; } @@ -565,7 +559,8 @@ WriteFormData(JSContext* aCx, return false; } - class MOZ_STACK_CLASS Closure { + class MOZ_STACK_CLASS Closure final + { JSContext* mCx; JSStructuredCloneWriter* mWriter; WorkerStructuredCloneClosure& mClones; @@ -590,7 +585,8 @@ WriteFormData(JSContext* aCx, } if (isFile) { - if (!WriteBlobOrFile(closure->mCx, closure->mWriter, aFile->Impl(), closure->mClones)) { + if (!WriteBlobOrFile(closure->mWriter, aFile->Impl(), + closure->mClones)) { return false; } } else { @@ -613,27 +609,27 @@ struct WorkerStructuredCloneCallbacks Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, uint32_t aData, void* aClosure) { - JS::Rooted result(aCx); - // See if object is a nsIDOMBlob pointer. if (aTag == DOMWORKER_SCTAG_BLOB) { MOZ_ASSERT(!aData); JS::Rooted blobOrFile(aCx); - ReadBlobOrFile(aCx, aReader, /* aIsMainThread */ false, &blobOrFile); + ReadBlobOrFile(aCx, aReader, &blobOrFile); return blobOrFile; } + // See if the object is an ImageData. - else if (aTag == SCTAG_DOM_IMAGEDATA) { + if (aTag == SCTAG_DOM_IMAGEDATA) { MOZ_ASSERT(!aData); return ReadStructuredCloneImageData(aCx, aReader); } + // See if the object is a FormData. - else if (aTag == DOMWORKER_SCTAG_FORMDATA) { + if (aTag == DOMWORKER_SCTAG_FORMDATA) { JS::Rooted formData(aCx); // aData is the entry count. - ReadFormData(aCx, aReader, /* aIsMainThread */ false, aData, &formData); + ReadFormData(aCx, aReader, aData, &formData); return formData; } @@ -649,8 +645,7 @@ struct WorkerStructuredCloneCallbacks closure->mClonedImages, aData); } - Error(aCx, 0); - return nullptr; + return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr); } static bool @@ -668,7 +663,7 @@ struct WorkerStructuredCloneCallbacks BlobImpl* blobImpl = blob->Impl(); MOZ_ASSERT(blobImpl); - if (WriteBlobOrFile(aCx, aWriter, blobImpl, *closure)) { + if (WriteBlobOrFile(aWriter, blobImpl, *closure)) { return true; } } @@ -702,8 +697,7 @@ struct WorkerStructuredCloneCallbacks } } - Error(aCx, 0); - return false; + return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); } static void @@ -810,198 +804,6 @@ const JSStructuredCloneCallbacks gWorkerStructuredCloneCallbacks = { WorkerStructuredCloneCallbacks::FreeTransfer }; -struct MainThreadWorkerStructuredCloneCallbacks -{ - static JSObject* - Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, - uint32_t aData, void* aClosure) - { - AssertIsOnMainThread(); - - // See if object is a Blob/File pointer. - if (aTag == DOMWORKER_SCTAG_BLOB) { - MOZ_ASSERT(!aData); - - JS::Rooted blobOrFile(aCx); - ReadBlobOrFile(aCx, aReader, /* aIsMainThread */ true, &blobOrFile); - - return blobOrFile; - } - // See if the object is a FormData. - else if (aTag == DOMWORKER_SCTAG_FORMDATA) { - JS::Rooted formData(aCx); - // aData is the entry count. - ReadFormData(aCx, aReader, /* aIsMainThread */ true, aData, &formData); - return formData; - } - - // See if the object is a ImageBitmap - if (aTag == SCTAG_DOM_IMAGEBITMAP) { - NS_ASSERTION(aClosure, "Null pointer!"); - - // Get the current global object. - auto* closure = static_cast(aClosure); - nsCOMPtr parent = do_QueryInterface(closure->mParentWindow); - // aData is the index of the cloned image. - return ImageBitmap::ReadStructuredClone(aCx, aReader, parent, - closure->mClonedImages, aData); - } - - JS_ClearPendingException(aCx); - return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr); - } - - static bool - Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, - JS::Handle aObj, void* aClosure) - { - AssertIsOnMainThread(); - - NS_ASSERTION(aClosure, "Null pointer!"); - - auto* closure = static_cast(aClosure); - - // See if this is a Blob/File object. - { - nsRefPtr blob; - if (NS_SUCCEEDED(UNWRAP_OBJECT(Blob, aObj, blob))) { - BlobImpl* blobImpl = blob->Impl(); - MOZ_ASSERT(blobImpl); - - if (!blobImpl->MayBeClonedToOtherThreads()) { - NS_WARNING("Not all the blob implementations can be sent between threads."); - } else if (WriteBlobOrFile(aCx, aWriter, blobImpl, *closure)) { - return true; - } - } - } - - // Handle imageBitmap cloning - { - ImageBitmap* imageBitmap = nullptr; - if (NS_SUCCEEDED(UNWRAP_OBJECT(ImageBitmap, aObj, imageBitmap))) { - return ImageBitmap::WriteStructuredClone(aWriter, - closure->mClonedImages, - imageBitmap); - } - } - - JS_ClearPendingException(aCx); - return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); - } - - static void - Error(JSContext* aCx, uint32_t aErrorId) - { - AssertIsOnMainThread(); - - NS_DOMStructuredCloneError(aCx, aErrorId); - } -}; - -const JSStructuredCloneCallbacks gMainThreadWorkerStructuredCloneCallbacks = { - MainThreadWorkerStructuredCloneCallbacks::Read, - MainThreadWorkerStructuredCloneCallbacks::Write, - MainThreadWorkerStructuredCloneCallbacks::Error, - WorkerStructuredCloneCallbacks::ReadTransfer, - WorkerStructuredCloneCallbacks::Transfer, - WorkerStructuredCloneCallbacks::FreeTransfer -}; - -struct ChromeWorkerStructuredCloneCallbacks -{ - static JSObject* - Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, - uint32_t aData, void* aClosure) - { - return WorkerStructuredCloneCallbacks::Read(aCx, aReader, aTag, aData, - aClosure); - } - - static bool - Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, - JS::Handle aObj, void* aClosure) - { - return WorkerStructuredCloneCallbacks::Write(aCx, aWriter, aObj, aClosure); - } - - static void - Error(JSContext* aCx, uint32_t aErrorId) - { - return WorkerStructuredCloneCallbacks::Error(aCx, aErrorId); - } -}; - -const JSStructuredCloneCallbacks gChromeWorkerStructuredCloneCallbacks = { - ChromeWorkerStructuredCloneCallbacks::Read, - ChromeWorkerStructuredCloneCallbacks::Write, - ChromeWorkerStructuredCloneCallbacks::Error, - WorkerStructuredCloneCallbacks::ReadTransfer, - WorkerStructuredCloneCallbacks::Transfer, - WorkerStructuredCloneCallbacks::FreeTransfer -}; - -struct MainThreadChromeWorkerStructuredCloneCallbacks -{ - static JSObject* - Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, - uint32_t aData, void* aClosure) - { - AssertIsOnMainThread(); - - JSObject* clone = - MainThreadWorkerStructuredCloneCallbacks::Read(aCx, aReader, aTag, aData, - aClosure); - if (clone) { - return clone; - } - - clone = - ChromeWorkerStructuredCloneCallbacks::Read(aCx, aReader, aTag, aData, - aClosure); - if (clone) { - return clone; - } - - JS_ClearPendingException(aCx); - return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr); - } - - static bool - Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, - JS::Handle aObj, void* aClosure) - { - AssertIsOnMainThread(); - - if (MainThreadWorkerStructuredCloneCallbacks::Write(aCx, aWriter, aObj, - aClosure) || - ChromeWorkerStructuredCloneCallbacks::Write(aCx, aWriter, aObj, - aClosure) || - NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr)) { - return true; - } - - return false; - } - - static void - Error(JSContext* aCx, uint32_t aErrorId) - { - AssertIsOnMainThread(); - - NS_DOMStructuredCloneError(aCx, aErrorId); - } -}; - -const JSStructuredCloneCallbacks gMainThreadChromeWorkerStructuredCloneCallbacks = { - MainThreadChromeWorkerStructuredCloneCallbacks::Read, - MainThreadChromeWorkerStructuredCloneCallbacks::Write, - MainThreadChromeWorkerStructuredCloneCallbacks::Error, - nullptr, - nullptr, - nullptr -}; - class MainThreadReleaseRunnable final : public nsRunnable { nsTArray> mDoomed; @@ -1346,7 +1148,7 @@ public: JS::Rooted messageData(aCx); if (!mBuffer.read(aCx, &messageData, - workers::WorkerStructuredCloneCallbacks(aIsMainThread), + workers::WorkerStructuredCloneCallbacks(), &closure)) { xpc::Throw(aCx, NS_ERROR_DOM_DATA_CLONE_ERR); return false; @@ -1356,7 +1158,7 @@ public: nsresult rv = event->InitMessageEvent(NS_LITERAL_STRING("message"), false /* non-bubbling */, - true /* cancelable */, + false /* non-cancelable */, messageData, EmptyString(), EmptyString(), @@ -3483,26 +3285,6 @@ WorkerPrivateParent::PostMessageInternal( } } - const JSStructuredCloneCallbacks* callbacks; - if (GetParent()) { - if (IsChromeWorker()) { - callbacks = &gChromeWorkerStructuredCloneCallbacks; - } - else { - callbacks = &gWorkerStructuredCloneCallbacks; - } - } - else { - AssertIsOnMainThread(); - - if (IsChromeWorker()) { - callbacks = &gMainThreadChromeWorkerStructuredCloneCallbacks; - } - else { - callbacks = &gMainThreadWorkerStructuredCloneCallbacks; - } - } - JS::Rooted transferable(aCx, JS::UndefinedValue()); if (aTransferable.WasPassed()) { const Sequence& realTransferable = aTransferable.Value(); @@ -3527,7 +3309,8 @@ WorkerPrivateParent::PostMessageInternal( WorkerRunnable::WorkerThreadModifyBusyCount, aToMessagePort, aMessagePortSerial); - if (!runnable->Write(aCx, aMessage, transferable, callbacks)) { + if (!runnable->Write(aCx, aMessage, transferable, + &gWorkerStructuredCloneCallbacks)) { aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); return; } @@ -3577,8 +3360,6 @@ WorkerPrivateParent::DispatchMessageEventToMessagePort( AssertIsOnMainThread(); JSAutoStructuredCloneBuffer buffer(Move(aBuffer)); - const JSStructuredCloneCallbacks* callbacks = - WorkerStructuredCloneCallbacks(true); class MOZ_STACK_CLASS AutoCloneBufferCleaner final { @@ -3608,7 +3389,9 @@ WorkerPrivateParent::DispatchMessageEventToMessagePort( MOZ_ASSERT(aClosure.mMessagePorts.IsEmpty()); closure.mMessagePortIdentifiers.SwapElements(aClosure.mMessagePortIdentifiers); - AutoCloneBufferCleaner bufferCleaner(buffer, callbacks, closure); + AutoCloneBufferCleaner bufferCleaner(buffer, + &gWorkerStructuredCloneCallbacks, + closure); SharedWorker* sharedWorker; if (!mSharedWorkers.Get(aMessagePortSerial, &sharedWorker)) { @@ -3632,7 +3415,7 @@ WorkerPrivateParent::DispatchMessageEventToMessagePort( JSContext* cx = jsapi.cx(); JS::Rooted data(cx); - if (!buffer.read(cx, &data, WorkerStructuredCloneCallbacks(true), + if (!buffer.read(cx, &data, &gWorkerStructuredCloneCallbacks, &closure)) { return false; } @@ -6292,17 +6075,13 @@ WorkerPrivate::PostMessageToParentInternal( transferable.setObject(*array); } - const JSStructuredCloneCallbacks* callbacks = - IsChromeWorker() ? - &gChromeWorkerStructuredCloneCallbacks : - &gWorkerStructuredCloneCallbacks; - nsRefPtr runnable = new MessageEventRunnable(this, WorkerRunnable::ParentThreadUnchangedBusyCount, aToMessagePort, aMessagePortSerial); - if (!runnable->Write(aCx, aMessage, transferable, callbacks)) { + if (!runnable->Write(aCx, aMessage, transferable, + &gWorkerStructuredCloneCallbacks)) { aRv = NS_ERROR_DOM_DATA_CLONE_ERR; return; } @@ -7445,19 +7224,9 @@ GetWorkerCrossThreadDispatcher(JSContext* aCx, JS::Value aWorker) } const JSStructuredCloneCallbacks* -WorkerStructuredCloneCallbacks(bool aMainRuntime) +WorkerStructuredCloneCallbacks() { - return aMainRuntime ? - &gMainThreadWorkerStructuredCloneCallbacks : - &gWorkerStructuredCloneCallbacks; -} - -const JSStructuredCloneCallbacks* -ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime) -{ - return aMainRuntime ? - &gMainThreadChromeWorkerStructuredCloneCallbacks : - &gChromeWorkerStructuredCloneCallbacks; + return &gWorkerStructuredCloneCallbacks; } // Force instantiation. diff --git a/dom/workers/WorkerPrivate.h b/dom/workers/WorkerPrivate.h index 009b301841..0f95e58a12 100644 --- a/dom/workers/WorkerPrivate.h +++ b/dom/workers/WorkerPrivate.h @@ -1520,10 +1520,7 @@ enum WorkerStructuredDataType }; const JSStructuredCloneCallbacks* -WorkerStructuredCloneCallbacks(bool aMainRuntime); - -const JSStructuredCloneCallbacks* -ChromeWorkerStructuredCloneCallbacks(bool aMainRuntime); +WorkerStructuredCloneCallbacks(); class AutoSyncLoopHolder { diff --git a/dom/workers/XMLHttpRequest.cpp b/dom/workers/XMLHttpRequest.cpp index 61df0d4da1..8ce46effff 100644 --- a/dom/workers/XMLHttpRequest.cpp +++ b/dom/workers/XMLHttpRequest.cpp @@ -1229,9 +1229,7 @@ EventRunnable::PreDispatch(JSContext* aCx, WorkerPrivate* aWorkerPrivate) if (doClone) { // Anything subject to GC must be cloned. const JSStructuredCloneCallbacks* callbacks = - aWorkerPrivate->IsChromeWorker() ? - workers::ChromeWorkerStructuredCloneCallbacks(true) : - workers::WorkerStructuredCloneCallbacks(true); + workers::WorkerStructuredCloneCallbacks(); WorkerStructuredCloneClosure closure; @@ -1344,9 +1342,7 @@ EventRunnable::WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) JSAutoStructuredCloneBuffer responseBuffer(Move(mResponseBuffer)); const JSStructuredCloneCallbacks* callbacks = - aWorkerPrivate->IsChromeWorker() ? - workers::ChromeWorkerStructuredCloneCallbacks(false) : - workers::WorkerStructuredCloneCallbacks(false); + workers::WorkerStructuredCloneCallbacks(); WorkerStructuredCloneClosure closure; closure.mClonedObjects.SwapElements(mResponseClosure.mClonedObjects); @@ -1531,9 +1527,7 @@ SendRunnable::MainThreadRun() nsresult rv = NS_OK; const JSStructuredCloneCallbacks* callbacks = - mWorkerPrivate->IsChromeWorker() ? - workers::ChromeWorkerStructuredCloneCallbacks(true) : - workers::WorkerStructuredCloneCallbacks(true); + workers::WorkerStructuredCloneCallbacks(); JS::Rooted body(cx); if (mBody.read(cx, &body, callbacks, &mClosure)) { @@ -2178,9 +2172,7 @@ XMLHttpRequest::Send(JS::Handle aBody, ErrorResult& aRv) } const JSStructuredCloneCallbacks* callbacks = - mWorkerPrivate->IsChromeWorker() ? - ChromeWorkerStructuredCloneCallbacks(false) : - WorkerStructuredCloneCallbacks(false); + WorkerStructuredCloneCallbacks(); WorkerStructuredCloneClosure closure; @@ -2224,9 +2216,7 @@ XMLHttpRequest::Send(Blob& aBody, ErrorResult& aRv) } const JSStructuredCloneCallbacks* callbacks = - mWorkerPrivate->IsChromeWorker() ? - ChromeWorkerStructuredCloneCallbacks(false) : - WorkerStructuredCloneCallbacks(false); + WorkerStructuredCloneCallbacks(); WorkerStructuredCloneClosure closure; @@ -2262,9 +2252,7 @@ XMLHttpRequest::Send(nsFormData& aBody, ErrorResult& aRv) } const JSStructuredCloneCallbacks* callbacks = - mWorkerPrivate->IsChromeWorker() ? - ChromeWorkerStructuredCloneCallbacks(false) : - WorkerStructuredCloneCallbacks(false); + WorkerStructuredCloneCallbacks(); JSAutoStructuredCloneBuffer buffer; WorkerStructuredCloneClosure closure; diff --git a/js/xpconnect/wrappers/XrayWrapper.cpp b/js/xpconnect/wrappers/XrayWrapper.cpp index ba6d6c56eb..9c7db6b80f 100644 --- a/js/xpconnect/wrappers/XrayWrapper.cpp +++ b/js/xpconnect/wrappers/XrayWrapper.cpp @@ -117,7 +117,7 @@ GetXrayType(JSObject* obj) } JSObject* -XrayAwareCalleeGlobal(JSObject *fun) +XrayAwareCalleeGlobal(JSObject* fun) { MOZ_ASSERT(js::IsFunctionObject(fun)); @@ -127,17 +127,17 @@ XrayAwareCalleeGlobal(JSObject *fun) } // The functions we expect here have the Xray wrapper they're associated with - // in their XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT and, in a debug build, their - // JSNative in their XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_ASSERT. Assert that + // in their XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT and, in a debug build, + // themselves in their XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_SELF. Assert that // last bit. - MOZ_ASSERT(js::GetFunctionNativeReserved(fun, XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_ASSERT).toPrivate() == - js::GetFunctionObjectNative(fun)); + MOZ_ASSERT(&js::GetFunctionNativeReserved(fun, XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_SELF).toObject() == + fun); Value v = js::GetFunctionNativeReserved(fun, XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT); MOZ_ASSERT(IsXrayWrapper(&v.toObject())); - JSObject *xrayTarget = js::UncheckedUnwrap(&v.toObject()); + JSObject* xrayTarget = js::UncheckedUnwrap(&v.toObject()); return js::GetGlobalForObjectCrossCompartment(xrayTarget); } @@ -269,6 +269,21 @@ ReportWrapperDenial(JSContext* cx, HandleId id, WrapperDenialType type, const ch return true; } +bool JSXrayTraits::getOwnPropertyFromWrapperIfSafe(JSContext* cx, + HandleObject wrapper, + HandleId id, + MutableHandle outDesc) +{ + MOZ_ASSERT(js::IsObjectInContextCompartment(wrapper, cx)); + RootedObject target(cx, getTargetObject(wrapper)); + { + JSAutoCompartment ac(cx, target); + if (!getOwnPropertyFromTargetIfSafe(cx, target, wrapper, id, outDesc)) + return false; + } + return JS_WrapPropertyDescriptor(cx, outDesc); +} + bool JSXrayTraits::getOwnPropertyFromTargetIfSafe(JSContext* cx, HandleObject target, HandleObject wrapper, @@ -382,12 +397,7 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, // "should" look like over Xrays, the underlying object is squishy enough // that it makes sense to just treat them like Objects for Xray purposes. if (key == JSProto_Object || key == JSProto_Array) { - { - JSAutoCompartment ac(cx, target); - if (!getOwnPropertyFromTargetIfSafe(cx, target, wrapper, id, desc)) - return false; - } - return JS_WrapPropertyDescriptor(cx, desc); + return getOwnPropertyFromWrapperIfSafe(cx, wrapper, id, desc); } else if (IsTypedArrayKey(key)) { if (IsArrayIndex(GetArrayIndexFromId(cx, id))) { JS_ReportError(cx, "Accessing TypedArray data over Xrays is slow, and forbidden " @@ -450,10 +460,8 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, return true; } } else if (key == JSProto_RegExp) { - if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_LASTINDEX)) { - JSAutoCompartment ac(cx, target); - return getOwnPropertyFromTargetIfSafe(cx, target, wrapper, id, desc); - } + if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_LASTINDEX)) + return getOwnPropertyFromWrapperIfSafe(cx, wrapper, id, desc); } // The rest of this function applies only to prototypes. @@ -499,10 +507,8 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, } // Handle the 'lastIndex' property for RegExp prototypes. - if (key == JSProto_RegExp && id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_LASTINDEX)) { - JSAutoCompartment ac(cx, target); - return getOwnPropertyFromTargetIfSafe(cx, target, wrapper, id, desc); - } + if (key == JSProto_RegExp && id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_LASTINDEX)) + return getOwnPropertyFromWrapperIfSafe(cx, wrapper, id, desc); // Grab the JSClass. We require all Xrayable classes to have a ClassSpec. const js::Class* clasp = js::GetObjectClass(target); @@ -588,7 +594,7 @@ JSXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, } bool -JSXrayTraits::delete_(JSContext *cx, HandleObject wrapper, HandleId id, ObjectOpResult &result) +JSXrayTraits::delete_(JSContext* cx, HandleObject wrapper, HandleId id, ObjectOpResult& result) { RootedObject holder(cx, ensureHolder(cx, wrapper)); @@ -611,11 +617,11 @@ JSXrayTraits::delete_(JSContext *cx, HandleObject wrapper, HandleId id, ObjectOp } bool -JSXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, +JSXrayTraits::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, Handle desc, Handle existingDesc, - ObjectOpResult &result, - bool *defined) + ObjectOpResult& result, + bool* defined) { *defined = false; RootedObject holder(cx, ensureHolder(cx, wrapper)); @@ -1063,7 +1069,7 @@ XrayTraits::cloneExpandoChain(JSContext* cx, HandleObject dst, HandleObject src) // preserved when expandos were originally added to |src|. Assert the // wrapper for |src| has been preserved if it has expandos set. if (oldHead) { - nsISupports *identity = mozilla::dom::UnwrapDOMObjectToISupports(src); + nsISupports* identity = mozilla::dom::UnwrapDOMObjectToISupports(src); if (identity) { nsWrapperCache* cache = nullptr; CallQueryInterface(identity, &cache); @@ -1244,7 +1250,7 @@ XPCWrappedNativeXrayTraits::resolveNativeProperty(JSContext* cx, HandleObject wr if (id != nsXPConnect::GetRuntimeInstance()->GetStringID(XPCJSRuntime::IDX_TO_STRING)) return true; - JSFunction *toString = JS_NewFunction(cx, XrayToString, 0, 0, "toString"); + JSFunction* toString = JS_NewFunction(cx, XrayToString, 0, 0, "toString"); if (!toString) return false; @@ -1442,10 +1448,10 @@ XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsW } bool -XPCWrappedNativeXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, +XPCWrappedNativeXrayTraits::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, Handle desc, Handle existingDesc, - JS::ObjectOpResult &result, bool *defined) + JS::ObjectOpResult& result, bool* defined) { *defined = false; RootedObject holder(cx, singleton.ensureHolder(cx, wrapper)); @@ -1602,10 +1608,10 @@ DOMXrayTraits::resolveOwnProperty(JSContext* cx, const Wrapper& jsWrapper, Handl } bool -DOMXrayTraits::defineProperty(JSContext *cx, HandleObject wrapper, HandleId id, +DOMXrayTraits::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, Handle desc, Handle existingDesc, - JS::ObjectOpResult &result, bool *defined) + JS::ObjectOpResult& result, bool* defined) { // Check for an indexed property on a Window. If that's happening, do // nothing but claim we defined it so it won't get added as an expando. @@ -1685,7 +1691,7 @@ DOMXrayTraits::construct(JSContext* cx, HandleObject wrapper, } bool -DOMXrayTraits::getPrototype(JSContext *cx, JS::HandleObject wrapper, +DOMXrayTraits::getPrototype(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject target, JS::MutableHandleObject protop) { @@ -1816,8 +1822,8 @@ XrayToString(JSContext* cx, unsigned argc, Value* vp) template bool -XrayWrapper::preventExtensions(JSContext *cx, HandleObject wrapper, - ObjectOpResult &result) const +XrayWrapper::preventExtensions(JSContext* cx, HandleObject wrapper, + ObjectOpResult& result) const { // Xray wrappers are supposed to provide a clean view of the target // reflector, hiding any modifications by script in the target scope. So @@ -1957,7 +1963,7 @@ XrayWrapper::getOwnPropertyDescriptor(JSContext* cx, HandleObject // to the content object. This is ok, because the the expando object is only // ever accessed by code across the compartment boundary. static bool -RecreateLostWaivers(JSContext *cx, const JSPropertyDescriptor *orig, +RecreateLostWaivers(JSContext* cx, const JSPropertyDescriptor* orig, MutableHandle wrapped) { // Compute whether the original objects were waived, and implicitly, whether @@ -2001,9 +2007,9 @@ RecreateLostWaivers(JSContext *cx, const JSPropertyDescriptor *orig, template bool -XrayWrapper::defineProperty(JSContext *cx, HandleObject wrapper, +XrayWrapper::defineProperty(JSContext* cx, HandleObject wrapper, HandleId id, Handle desc, - ObjectOpResult &result) const + ObjectOpResult& result) const { assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::SET); @@ -2075,7 +2081,7 @@ XrayWrapper::ownPropertyKeys(JSContext* cx, HandleObject wrapper, template bool XrayWrapper::delete_(JSContext* cx, HandleObject wrapper, - HandleId id, ObjectOpResult &result) const + HandleId id, ObjectOpResult& result) const { assertEnteredPolicy(cx, wrapper, id, BaseProxyHandler::SET); @@ -2200,7 +2206,7 @@ XrayWrapper::defaultValue(JSContext* cx, HandleObject wrapper, template bool -XrayWrapper::getPrototype(JSContext *cx, JS::HandleObject wrapper, +XrayWrapper::getPrototype(JSContext* cx, JS::HandleObject wrapper, JS::MutableHandleObject protop) const { // We really only want this override for non-SecurityWrapper-inheriting @@ -2233,8 +2239,8 @@ XrayWrapper::getPrototype(JSContext *cx, JS::HandleObject wrapper, template bool -XrayWrapper::setPrototype(JSContext *cx, JS::HandleObject wrapper, - JS::HandleObject proto, JS::ObjectOpResult &result) const +XrayWrapper::setPrototype(JSContext* cx, JS::HandleObject wrapper, + JS::HandleObject proto, JS::ObjectOpResult& result) const { // Do this only for non-SecurityWrapper-inheriting |Base|. See the comment // in getPrototype(). diff --git a/js/xpconnect/wrappers/XrayWrapper.h b/js/xpconnect/wrappers/XrayWrapper.h index 8e6067a195..a66bebe4ce 100644 --- a/js/xpconnect/wrappers/XrayWrapper.h +++ b/js/xpconnect/wrappers/XrayWrapper.h @@ -18,9 +18,9 @@ // the Xray wrapper they're associated with. #define XRAY_DOM_FUNCTION_PARENT_WRAPPER_SLOT 0 // Slot where in debug builds Xray functions for Web IDL methods store -// a pointer to their JSNative, just so we can assert that they're the +// a pointer to their themselves, just so we can assert that they're the // sort of functions we expect. -#define XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_ASSERT 1 +#define XRAY_DOM_FUNCTION_NATIVE_SLOT_FOR_SELF 1 // Xray wrappers re-resolve the original native properties on the native // object and always directly access to those properties. @@ -78,8 +78,8 @@ public: JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, JS::MutableHandle desc); - bool delete_(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, - JS::ObjectOpResult &result) { + bool delete_(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, + JS::ObjectOpResult& result) { return result.succeed(); } @@ -132,10 +132,10 @@ public: virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, JS::MutableHandle desc) override; - bool defineProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, + bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::Handle desc, JS::Handle existingDesc, - JS::ObjectOpResult &result, bool *defined); + JS::ObjectOpResult& result, bool* defined); virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper, unsigned flags, JS::AutoIdVector& props); static bool call(JSContext* cx, JS::HandleObject wrapper, @@ -184,22 +184,22 @@ public: virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, JS::MutableHandle desc) override; - bool defineProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, + bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::Handle desc, JS::Handle existingDesc, - JS::ObjectOpResult &result, bool *defined); + JS::ObjectOpResult& result, bool* defined); virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper, unsigned flags, JS::AutoIdVector& props); static bool call(JSContext* cx, JS::HandleObject wrapper, const JS::CallArgs& args, const js::Wrapper& baseInstance); - static bool construct(JSContext *cx, JS::HandleObject wrapper, - const JS::CallArgs &args, const js::Wrapper& baseInstance); + static bool construct(JSContext* cx, JS::HandleObject wrapper, + const JS::CallArgs& args, const js::Wrapper& baseInstance); - static bool getPrototype(JSContext *cx, JS::HandleObject wrapper, + static bool getPrototype(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject target, JS::MutableHandleObject protop); - virtual void preserveWrapper(JSObject *target) override; + virtual void preserveWrapper(JSObject* target) override; virtual JSObject* createHolder(JSContext* cx, JSObject* wrapper) override; @@ -225,12 +225,12 @@ public: JS::HandleObject holder, JS::HandleId id, JS::MutableHandle desc) override; - bool delete_(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, JS::ObjectOpResult &result); + bool delete_(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::ObjectOpResult& result); - bool defineProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, + bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::Handle desc, JS::Handle existingDesc, - JS::ObjectOpResult &result, bool *defined); + JS::ObjectOpResult& result, bool* defined); virtual bool enumerateNames(JSContext* cx, JS::HandleObject wrapper, unsigned flags, JS::AutoIdVector& props); @@ -322,6 +322,13 @@ public: return static_cast(key); } + // Operates in the wrapper compartment. + static bool getOwnPropertyFromWrapperIfSafe(JSContext* cx, + JS::HandleObject wrapper, + JS::HandleId id, + JS::MutableHandle desc); + + // Like the above, but operates in the target compartment. static bool getOwnPropertyFromTargetIfSafe(JSContext* cx, JS::HandleObject target, JS::HandleObject wrapper, @@ -350,14 +357,14 @@ public: MOZ_CRASH("resolveNativeProperty hook should never be called with HasPrototype = 1"); } - virtual bool resolveOwnProperty(JSContext *cx, const js::Wrapper &jsWrapper, JS::HandleObject wrapper, + virtual bool resolveOwnProperty(JSContext* cx, const js::Wrapper& jsWrapper, JS::HandleObject wrapper, JS::HandleObject holder, JS::HandleId id, JS::MutableHandle desc) override; - bool defineProperty(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id, + bool defineProperty(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id, JS::Handle desc, JS::Handle existingDesc, - JS::ObjectOpResult &result, bool *defined) + JS::ObjectOpResult& result, bool* defined) { *defined = false; return true; @@ -385,7 +392,7 @@ public: return false; } - bool getPrototype(JSContext *cx, JS::HandleObject wrapper, + bool getPrototype(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject target, JS::MutableHandleObject protop) { @@ -434,7 +441,7 @@ class XrayWrapper : public Base { virtual bool ownPropertyKeys(JSContext* cx, JS::Handle wrapper, JS::AutoIdVector& props) const override; virtual bool delete_(JSContext* cx, JS::Handle wrapper, - JS::Handle id, JS::ObjectOpResult &result) const override; + JS::Handle id, JS::ObjectOpResult& result) const override; virtual bool enumerate(JSContext* cx, JS::Handle wrapper, JS::MutableHandle objp) const override; virtual bool getPrototype(JSContext* cx, JS::HandleObject wrapper, @@ -442,9 +449,9 @@ class XrayWrapper : public Base { virtual bool setPrototype(JSContext* cx, JS::HandleObject wrapper, JS::HandleObject proto, JS::ObjectOpResult& result) const override; virtual bool setImmutablePrototype(JSContext* cx, JS::HandleObject wrapper, - bool *succeeded) const override; - virtual bool preventExtensions(JSContext *cx, JS::Handle wrapper, - JS::ObjectOpResult &result) const override; + bool* succeeded) const override; + virtual bool preventExtensions(JSContext* cx, JS::Handle wrapper, + JS::ObjectOpResult& result) const override; virtual bool isExtensible(JSContext* cx, JS::Handle wrapper, bool* extensible) const override; virtual bool has(JSContext* cx, JS::Handle wrapper, JS::Handle id, bool* bp) const override; @@ -526,7 +533,7 @@ public: JS::Handle id, JS::MutableHandle vp) const override; virtual bool set(JSContext* cx, JS::Handle proxy, JS::Handle id, JS::Handle v, JS::Handle receiver, - JS::ObjectOpResult &result) const override; + JS::ObjectOpResult& result) const override; virtual bool getPropertyDescriptor(JSContext* cx, JS::Handle proxy, JS::Handle id, diff --git a/testing/web-platform/meta/screen-orientation/lock-bad-argument.html.ini b/testing/web-platform/meta/screen-orientation/lock-bad-argument.html.ini index c51e31520e..624ba7b227 100644 --- a/testing/web-platform/meta/screen-orientation/lock-bad-argument.html.ini +++ b/testing/web-platform/meta/screen-orientation/lock-bad-argument.html.ini @@ -1,6 +1,5 @@ [lock-bad-argument.html] type: testharness - expected: ERROR [Test that screen.orientation.lock() throws when the input isn't valid.] - expected: NOTRUN + expected: FAIL diff --git a/testing/web-platform/meta/screen-orientation/lock-basic.html.ini b/testing/web-platform/meta/screen-orientation/lock-basic.html.ini index d7ce5dfc89..2867b2bd3e 100644 --- a/testing/web-platform/meta/screen-orientation/lock-basic.html.ini +++ b/testing/web-platform/meta/screen-orientation/lock-basic.html.ini @@ -1,8 +1,6 @@ [lock-basic.html] type: testharness - [Test that screen.orientation.unlock() doesn't throw when there is no lock] - expected: FAIL - + expected: TIMEOUT [Test that screen.orientation.lock returns a pending promise.] - expected: FAIL + expected: TIMEOUT diff --git a/testing/web-platform/meta/screen-orientation/lock-sandboxed-iframe.html.ini b/testing/web-platform/meta/screen-orientation/lock-sandboxed-iframe.html.ini index d9787fc7aa..8948f8a2f2 100644 --- a/testing/web-platform/meta/screen-orientation/lock-sandboxed-iframe.html.ini +++ b/testing/web-platform/meta/screen-orientation/lock-sandboxed-iframe.html.ini @@ -2,7 +2,7 @@ type: testharness expected: TIMEOUT [Test without 'allow-orientation-lock' sandboxing directive] - expected: NOTRUN + expected: FAIL [Test with 'allow-orientation-lock' sandboxing directive] expected: NOTRUN diff --git a/testing/web-platform/meta/screen-orientation/onchange-event-subframe.html.ini b/testing/web-platform/meta/screen-orientation/onchange-event-subframe.html.ini index 9101e9ef97..614ed43b87 100644 --- a/testing/web-platform/meta/screen-orientation/onchange-event-subframe.html.ini +++ b/testing/web-platform/meta/screen-orientation/onchange-event-subframe.html.ini @@ -1,6 +1,6 @@ [onchange-event-subframe.html] type: testharness - expected: ERROR + expected: TIMEOUT [Test subframes receive orientation change events] expected: NOTRUN diff --git a/testing/web-platform/meta/screen-orientation/onchange-event.html.ini b/testing/web-platform/meta/screen-orientation/onchange-event.html.ini index af9d28ebbf..36bac914fb 100644 --- a/testing/web-platform/meta/screen-orientation/onchange-event.html.ini +++ b/testing/web-platform/meta/screen-orientation/onchange-event.html.ini @@ -1,6 +1,6 @@ [onchange-event.html] type: testharness - expected: ERROR + expected: TIMEOUT [Test that orientationchange event is fired when the orientation changes.] expected: NOTRUN diff --git a/testing/web-platform/meta/screen-orientation/orientation-api.html.ini b/testing/web-platform/meta/screen-orientation/orientation-api.html.ini deleted file mode 100644 index f1c792933d..0000000000 --- a/testing/web-platform/meta/screen-orientation/orientation-api.html.ini +++ /dev/null @@ -1,11 +0,0 @@ -[orientation-api.html] - type: testharness - [Test that the Screen Orientation API is present.] - expected: FAIL - - [Test Screen Orientation API property types.] - expected: FAIL - - [Test that screen.orientation is an EventTarget.] - expected: FAIL - diff --git a/testing/web-platform/meta/screen-orientation/orientation-reading.html.ini b/testing/web-platform/meta/screen-orientation/orientation-reading.html.ini index 3ad9413040..b31f157803 100644 --- a/testing/web-platform/meta/screen-orientation/orientation-reading.html.ini +++ b/testing/web-platform/meta/screen-orientation/orientation-reading.html.ini @@ -1,14 +1,8 @@ [orientation-reading.html] type: testharness - [Test screen.orientation properties] - expected: FAIL - [Test screen.orientation default values.] expected: FAIL - [Test that screen.orientation properties are not writable] - expected: FAIL - [Test that screen.orientation values change if the orientation changes] expected: FAIL diff --git a/testing/web-platform/meta/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/message-event.html.ini b/testing/web-platform/meta/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/message-event.html.ini deleted file mode 100644 index c810dcf32e..0000000000 --- a/testing/web-platform/meta/workers/interfaces/DedicatedWorkerGlobalScope/postMessage/message-event.html.ini +++ /dev/null @@ -1,5 +0,0 @@ -[message-event.html] - type: testharness - [Properties of the 'message' event] - expected: FAIL -