diff options
Diffstat (limited to '')
-rw-r--r-- | dom/base/nsScreen.cpp | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/dom/base/nsScreen.cpp b/dom/base/nsScreen.cpp new file mode 100644 index 0000000000..b4ac142f35 --- /dev/null +++ b/dom/base/nsScreen.cpp @@ -0,0 +1,232 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsContentUtils.h" +#include "nsScreen.h" +#include "mozilla/dom/Document.h" +#include "nsIDocShell.h" +#include "nsPresContext.h" +#include "nsCOMPtr.h" +#include "nsIDocShellTreeItem.h" +#include "nsLayoutUtils.h" +#include "nsJSUtils.h" +#include "nsDeviceContext.h" +#include "mozilla/widget/ScreenManager.h" + +using namespace mozilla; +using namespace mozilla::dom; + +/* static */ +already_AddRefed<nsScreen> nsScreen::Create(nsPIDOMWindowInner* aWindow) { + MOZ_ASSERT(aWindow); + + if (!aWindow->GetDocShell()) { + return nullptr; + } + + nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow); + NS_ENSURE_TRUE(sgo, nullptr); + + RefPtr<nsScreen> screen = new nsScreen(aWindow); + return screen.forget(); +} + +nsScreen::nsScreen(nsPIDOMWindowInner* aWindow) + : DOMEventTargetHelper(aWindow), + mScreenOrientation(new ScreenOrientation(aWindow, this)) {} + +nsScreen::~nsScreen() = default; + +// QueryInterface implementation for nsScreen +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsScreen) +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) { + // Return 24 to prevent fingerprinting. + if (ShouldResistFingerprinting()) { + return 24; + } + + nsDeviceContext* context = GetDeviceContext(); + + if (!context) { + aRv.Throw(NS_ERROR_FAILURE); + return -1; + } + + return context->GetDepth(); +} + +nsPIDOMWindowOuter* nsScreen::GetOuter() const { + if (nsPIDOMWindowInner* inner = GetOwner()) { + return inner->GetOuterWindow(); + } + + return nullptr; +} + +nsDeviceContext* nsScreen::GetDeviceContext() const { + return nsLayoutUtils::GetDeviceContextForScreenInfo(GetOuter()); +} + +nsresult nsScreen::GetRect(CSSIntRect& aRect) { + // Return window inner rect to prevent fingerprinting. + if (ShouldResistFingerprinting()) { + return GetWindowInnerRect(aRect); + } + + // Here we manipulate the value of aRect to represent the screen size, + // if in RDM. + if (nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner()) { + if (Document* doc = owner->GetExtantDoc()) { + Maybe<CSSIntSize> deviceSize = + nsGlobalWindowOuter::GetRDMDeviceSize(*doc); + if (deviceSize.isSome()) { + const CSSIntSize& size = deviceSize.value(); + aRect.SetRect(0, 0, size.width, size.height); + return NS_OK; + } + } + } + + nsDeviceContext* context = GetDeviceContext(); + + if (!context) { + return NS_ERROR_FAILURE; + } + + nsRect r; + context->GetRect(r); + aRect = CSSIntRect::FromAppUnitsRounded(r); + return NS_OK; +} + +nsresult nsScreen::GetAvailRect(CSSIntRect& aRect) { + // Return window inner rect to prevent fingerprinting. + if (ShouldResistFingerprinting()) { + return GetWindowInnerRect(aRect); + } + + // Here we manipulate the value of aRect to represent the screen size, + // if in RDM. + if (nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner()) { + if (Document* doc = owner->GetExtantDoc()) { + Maybe<CSSIntSize> deviceSize = + nsGlobalWindowOuter::GetRDMDeviceSize(*doc); + if (deviceSize.isSome()) { + const CSSIntSize& size = deviceSize.value(); + aRect.SetRect(0, 0, size.width, size.height); + return NS_OK; + } + } + } + + nsDeviceContext* context = GetDeviceContext(); + if (!context) { + return NS_ERROR_FAILURE; + } + + nsRect r; + context->GetClientRect(r); + aRect = CSSIntRect::FromAppUnitsRounded(r); + return NS_OK; +} + +uint16_t nsScreen::GetOrientationAngle() const { + nsDeviceContext* context = GetDeviceContext(); + if (context) { + return context->GetScreenOrientationAngle(); + } + RefPtr<widget::Screen> s = + widget::ScreenManager::GetSingleton().GetPrimaryScreen(); + return s->GetOrientationAngle(); +} + +hal::ScreenOrientation nsScreen::GetOrientationType() const { + nsDeviceContext* context = GetDeviceContext(); + if (context) { + return context->GetScreenOrientationType(); + } + RefPtr<widget::Screen> s = + widget::ScreenManager::GetSingleton().GetPrimaryScreen(); + return s->GetOrientationType(); +} + +ScreenOrientation* nsScreen::Orientation() const { return mScreenOrientation; } + +void nsScreen::GetMozOrientation(nsString& aOrientation, + CallerType aCallerType) const { + switch (mScreenOrientation->DeviceType(aCallerType)) { + case OrientationType::Portrait_primary: + aOrientation.AssignLiteral("portrait-primary"); + break; + case OrientationType::Portrait_secondary: + aOrientation.AssignLiteral("portrait-secondary"); + break; + case OrientationType::Landscape_primary: + aOrientation.AssignLiteral("landscape-primary"); + break; + case OrientationType::Landscape_secondary: + aOrientation.AssignLiteral("landscape-secondary"); + break; + default: + MOZ_CRASH("Unacceptable screen orientation type."); + } +} + +bool nsScreen::MozLockOrientation(const nsAString& aOrientation, + ErrorResult& aRv) { + nsString orientation(aOrientation); + Sequence<nsString> orientations; + if (!orientations.AppendElement(orientation, fallible)) { + aRv.Throw(NS_ERROR_OUT_OF_MEMORY); + return false; + } + return MozLockOrientation(orientations, aRv); +} + +// This function is deprecated, use ScreenOrientation API instead. +bool nsScreen::MozLockOrientation(const Sequence<nsString>& aOrientations, + ErrorResult& aRv) { + return false; +} + +void nsScreen::MozUnlockOrientation() {} + +/* virtual */ +JSObject* nsScreen::WrapObject(JSContext* aCx, + JS::Handle<JSObject*> aGivenProto) { + return Screen_Binding::Wrap(aCx, this, aGivenProto); +} + +nsresult nsScreen::GetWindowInnerRect(CSSIntRect& aRect) { + aRect.x = 0; + aRect.y = 0; + nsCOMPtr<nsPIDOMWindowInner> win = GetOwner(); + if (!win) { + return NS_ERROR_FAILURE; + } + double width; + double height; + nsresult rv = win->GetInnerWidth(&width); + NS_ENSURE_SUCCESS(rv, rv); + rv = win->GetInnerHeight(&height); + NS_ENSURE_SUCCESS(rv, rv); + aRect.SizeTo(std::round(width), std::round(height)); + return NS_OK; +} + +bool nsScreen::ShouldResistFingerprinting() const { + nsCOMPtr<nsPIDOMWindowInner> owner = GetOwner(); + return owner && + nsGlobalWindowInner::Cast(owner)->ShouldResistFingerprinting(); +} |