Bug 1357785 - Expose the Visual Viewport API to web content. r?botond, nika
Summary:
Implemented the non-event handler attributes of the Visual Viewport API
according to the spec: https://wicg.github.io/visual-viewport
The 'onresize' and 'onscroll' attributes will be implemented in the
bug
1478776.
MozReview-Commit-ID: G4bkIZ9VtZ2
new file mode 100644
--- /dev/null
+++ b/dom/base/VisualViewport.cpp
@@ -0,0 +1,140 @@
+/* -*- 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 "VisualViewport.h"
+#include "nsIScrollableFrame.h"
+#include "nsIDocShell.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+
+VisualViewport::VisualViewport(nsPIDOMWindowInner* aWindow)
+ : DOMEventTargetHelper(aWindow)
+{
+}
+
+VisualViewport::~VisualViewport()
+{
+}
+
+/* virtual */
+JSObject*
+VisualViewport::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+ return VisualViewport_Binding::Wrap(aCx, this, aGivenProto);
+}
+
+CSSSize
+VisualViewport::VisualViewportSize() const
+{
+ CSSSize size = CSSSize(0,0);
+
+ nsIPresShell* presShell = GetPresShell();
+ if (presShell) {
+ if (presShell->IsScrollPositionClampingScrollPortSizeSet()) {
+ size = CSSRect::FromAppUnits(
+ presShell->GetScrollPositionClampingScrollPortSize());
+ } else {
+ nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
+ if (sf) {
+ size = CSSRect::FromAppUnits(sf->GetScrollPortRect().Size());
+ }
+ }
+ }
+ return size;
+}
+
+double
+VisualViewport::Width() const
+{
+ CSSSize size = VisualViewportSize();
+ return size.width;
+}
+
+double
+VisualViewport::Height() const
+{
+ CSSSize size = VisualViewportSize();
+ return size.height;
+}
+
+double
+VisualViewport::Scale() const
+{
+ double scale = 1;
+ nsIPresShell* presShell = GetPresShell();
+ if (presShell) {
+ scale = presShell->GetResolution();
+ }
+ return scale;
+}
+
+CSSPoint
+VisualViewport::VisualViewportOffset() const
+{
+ CSSPoint offset = CSSPoint(0,0);
+
+ nsIPresShell* presShell = GetPresShell();
+ if (presShell) {
+ offset = CSSPoint::FromAppUnits(presShell->GetVisualViewportOffset());
+ }
+ return offset;
+}
+
+CSSPoint
+VisualViewport::LayoutViewportOffset() const
+{
+ CSSPoint offset = CSSPoint(0,0);
+
+ nsIPresShell* presShell = GetPresShell();
+ if (presShell) {
+ nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
+ if (sf) {
+ offset = CSSPoint::FromAppUnits(sf->GetScrollPosition());
+ }
+ }
+ return offset;
+}
+
+double
+VisualViewport::PageLeft() const
+{
+ return VisualViewportOffset().X();
+}
+
+double
+VisualViewport::PageTop() const
+{
+ return VisualViewportOffset().Y();
+}
+
+double
+VisualViewport::OffsetLeft() const
+{
+ return PageLeft() - LayoutViewportOffset().X();
+}
+
+double
+VisualViewport::OffsetTop() const
+{
+ return PageTop() - LayoutViewportOffset().Y();
+}
+
+nsIPresShell*
+VisualViewport::GetPresShell() const
+{
+ nsCOMPtr<nsPIDOMWindowInner> window = GetOwner();
+ if (!window) {
+ return nullptr;
+ }
+
+ nsIDocShell* docShell = window->GetDocShell();
+ if (!docShell) {
+ return nullptr;
+ }
+
+ return docShell->GetPresShell();
+}
new file mode 100644
--- /dev/null
+++ b/dom/base/VisualViewport.h
@@ -0,0 +1,48 @@
+/* -*- 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/. */
+
+
+#ifndef mozilla_dom_VisualViewport_h
+#define mozilla_dom_VisualViewport_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/VisualViewportBinding.h"
+#include "Units.h"
+#include "nsIPresShell.h"
+
+namespace mozilla {
+namespace dom {
+
+/* Visual Viewport API spec: https://wicg.github.io/visual-viewport/#the-visualviewport-interface */
+class VisualViewport final: public mozilla::DOMEventTargetHelper
+{
+
+public:
+ explicit VisualViewport(nsPIDOMWindowInner* aWindow);
+
+ double OffsetLeft() const;
+ double OffsetTop() const;
+ double PageLeft() const;
+ double PageTop() const;
+ double Width() const;
+ double Height() const;
+ double Scale() const;
+
+ virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
+
+private:
+ virtual ~VisualViewport();
+
+ CSSSize VisualViewportSize() const;
+ CSSPoint VisualViewportOffset() const;
+ CSSPoint LayoutViewportOffset() const;
+ nsIPresShell* GetPresShell() const;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_VisualViewport_h
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -219,16 +219,17 @@ EXPORTS.mozilla.dom += [
'SyncMessageSender.h',
'TabGroup.h',
'Text.h',
'Timeout.h',
'TimeoutHandler.h',
'TimeoutManager.h',
'TreeIterator.h',
'TreeWalker.h',
+ 'VisualViewport.h',
'WebKitCSSMatrix.h',
'WindowOrientationObserver.h',
]
if CONFIG['FUZZING']:
EXPORTS.mozilla.dom += [
'FuzzingFunctions.h',
]
@@ -371,16 +372,17 @@ UNIFIED_SOURCES += [
'TextInputProcessor.cpp',
'ThirdPartyUtil.cpp',
'Timeout.cpp',
'TimeoutBudgetManager.cpp',
'TimeoutExecutor.cpp',
'TimeoutHandler.cpp',
'TimeoutManager.cpp',
'TreeWalker.cpp',
+ 'VisualViewport.cpp',
'WebKitCSSMatrix.cpp',
'WindowDestroyedEvent.cpp',
'WindowNamedPropertiesHandler.cpp',
'WindowOrientationObserver.cpp',
'XPathGenerator.cpp',
]
if CONFIG['MOZ_WEBRTC']:
--- a/dom/base/nsGlobalWindowInner.cpp
+++ b/dom/base/nsGlobalWindowInner.cpp
@@ -27,16 +27,17 @@
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
#include "mozilla/dom/StorageNotifierService.h"
#include "mozilla/dom/StorageUtils.h"
#include "mozilla/dom/Timeout.h"
#include "mozilla/dom/TimeoutHandler.h"
#include "mozilla/dom/TimeoutManager.h"
+#include "mozilla/dom/VisualViewport.h"
#include "mozilla/IntegerPrintfMacros.h"
#if defined(MOZ_WIDGET_ANDROID)
#include "mozilla/dom/WindowOrientationObserver.h"
#endif
#include "nsDOMOfflineResourceList.h"
#include "nsError.h"
#include "nsIIdleService.h"
#include "nsISizeOfEventTarget.h"
@@ -2228,16 +2229,25 @@ nsPIDOMWindowInner::Navigator()
{
if (!mNavigator) {
mNavigator = new mozilla::dom::Navigator(this);
}
return mNavigator;
}
+VisualViewport* nsGlobalWindowInner::VisualViewport()
+{
+ if (!mVisualViewport) {
+ mVisualViewport = new mozilla::dom::VisualViewport(this);
+ }
+
+ return mVisualViewport;
+}
+
nsScreen*
nsGlobalWindowInner::GetScreen(ErrorResult& aError)
{
if (!mScreen) {
mScreen = nsScreen::Create(this);
if (!mScreen) {
aError.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
--- a/dom/base/nsGlobalWindowInner.h
+++ b/dom/base/nsGlobalWindowInner.h
@@ -119,16 +119,17 @@ class Promise;
class PostMessageEvent;
struct RequestInit;
class RequestOrUSVString;
class Selection;
class SpeechSynthesis;
class TabGroup;
class Timeout;
class U2F;
+class VisualViewport;
class VRDisplay;
enum class VRDisplayEventReason : uint8_t;
class VREventObserver;
class WakeLock;
#if defined(MOZ_WIDGET_ANDROID)
class WindowOrientationObserver;
#endif
class Worklet;
@@ -767,16 +768,17 @@ public:
mozilla::dom::Storage* GetSessionStorage(mozilla::ErrorResult& aError);
mozilla::dom::Storage*
GetLocalStorage(mozilla::ErrorResult& aError);
mozilla::dom::Selection* GetSelection(mozilla::ErrorResult& aError);
mozilla::dom::IDBFactory* GetIndexedDB(mozilla::ErrorResult& aError);
already_AddRefed<nsICSSDeclaration>
GetComputedStyle(mozilla::dom::Element& aElt, const nsAString& aPseudoElt,
mozilla::ErrorResult& aError) override;
+ mozilla::dom::VisualViewport* VisualViewport();
already_AddRefed<mozilla::dom::MediaQueryList> MatchMedia(
const nsAString& aQuery,
mozilla::dom::CallerType aCallerType,
mozilla::ErrorResult& aError);
nsScreen* GetScreen(mozilla::ErrorResult& aError);
void MoveTo(int32_t aXPos, int32_t aYPos,
mozilla::dom::CallerType aCallerType,
mozilla::ErrorResult& aError);
@@ -1394,16 +1396,18 @@ protected:
RefPtr<mozilla::dom::Storage> mLocalStorage;
RefPtr<mozilla::dom::Storage> mSessionStorage;
RefPtr<mozilla::EventListenerManager> mListenerManager;
RefPtr<mozilla::dom::Location> mLocation;
RefPtr<nsHistory> mHistory;
RefPtr<mozilla::dom::CustomElementRegistry> mCustomElements;
+ RefPtr<mozilla::dom::VisualViewport> mVisualViewport;
+
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
// mTabChild is only ever populated in the content process.
nsCOMPtr<nsITabChild> mTabChild;
uint32_t mSuspendDepth;
uint32_t mFreezeDepth;
// the method that was used to focus mFocusedNode
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -1050,16 +1050,20 @@ DOMInterfaces = {
'TreeContentView': {
'nativeType': 'nsTreeContentView',
},
'TreeWalker': {
'wrapperCache': False,
},
+'VisualViewport': {
+ 'nativeType': 'mozilla::dom::VisualViewport',
+},
+
'VTTCue': {
'nativeType': 'mozilla::dom::TextTrackCue'
},
'VTTRegion': {
'nativeType': 'mozilla::dom::TextTrackRegion',
},
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -1152,16 +1152,18 @@ var interfaceNamesInGlobalScope =
{name: "UserProximityEvent", insecureContext: true, disabled: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "ValidityState", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "VideoPlaybackQuality", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "VideoStreamTrack", insecureContext: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
+ {name: "VisualViewport", insecureContext: true},
+// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "VRDisplay", insecureContext: true, releaseNonWindows: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "VRDisplayCapabilities", insecureContext: true, releaseNonWindows: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "VRDisplayEvent", insecureContext: true, releaseNonWindows: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "VREyeParameters", insecureContext: true, releaseNonWindows: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
new file mode 100644
--- /dev/null
+++ b/dom/webidl/VisualViewport.webidl
@@ -0,0 +1,21 @@
+/* -*- 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://wicg.github.io/visual-viewport/#the-visualviewport-interface
+ */
+
+interface VisualViewport : EventTarget {
+ readonly attribute double offsetLeft;
+ readonly attribute double offsetTop;
+
+ readonly attribute double pageLeft;
+ readonly attribute double pageTop;
+
+ readonly attribute double width;
+ readonly attribute double height;
+
+ readonly attribute double scale;
+};
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -11,16 +11,17 @@
* http://dev.w3.org/csswg/cssom-view/
* https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/RequestAnimationFrame/Overview.html
* https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/Overview.html
* https://dvcs.w3.org/hg/webcrypto-api/raw-file/tip/spec/Overview.html
* http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html
* https://w3c.github.io/webappsec-secure-contexts/#monkey-patching-global-object
* https://w3c.github.io/requestidlecallback/
* https://drafts.css-houdini.org/css-paint-api-1/#dom-window-paintworklet
+ * https://wicg.github.io/visual-viewport/#the-visualviewport-interface
*/
interface IID;
interface nsIBrowserDOMWindow;
interface XULControllers;
typedef OfflineResourceList ApplicationCache;
@@ -555,8 +556,14 @@ partial interface Window {
* Getter funcion for IntlUtils, which provides helper functions for
* localization.
*/
[Throws, Func="IsChromeOrXBL"]
readonly attribute IntlUtils intlUtils;
};
Window implements WebGPUProvider;
+
+partial interface Window {
+ [SameObject, Pref="dom.visualviewport.enabled", Replaceable]
+ readonly attribute VisualViewport visualViewport;
+
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -910,16 +910,17 @@ WEBIDL_FILES = [
'UIEvent.webidl',
'URL.webidl',
'URLSearchParams.webidl',
'ValidityState.webidl',
'VideoPlaybackQuality.webidl',
'VideoStreamTrack.webidl',
'VideoTrack.webidl',
'VideoTrackList.webidl',
+ 'VisualViewport.webidl',
'VRDisplay.webidl',
'VRDisplayEvent.webidl',
'VRServiceTest.webidl',
'VTTCue.webidl',
'VTTRegion.webidl',
'WaveShaperNode.webidl',
'WebAuthentication.webidl',
'WebComponents.webidl',
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -366,16 +366,17 @@ private:
DECL_GFX_PREF(Live, "apz.scale_repaint_delay_ms", APZScaleRepaintDelay, int32_t, 500);
DECL_GFX_PREF(Live, "browser.ui.scroll-toolbar-threshold", ToolbarScrollThreshold, int32_t, 10);
DECL_GFX_PREF(Live, "browser.ui.zoom.force-user-scalable", ForceUserScalable, bool, false);
DECL_GFX_PREF(Live, "browser.viewport.desktopWidth", DesktopViewportWidth, int32_t, 980);
DECL_GFX_PREF(Live, "dom.ipc.plugins.asyncdrawing.enabled", PluginAsyncDrawingEnabled, bool, false);
DECL_GFX_PREF(Live, "dom.meta-viewport.enabled", MetaViewportEnabled, bool, false);
+ DECL_GFX_PREF(Live, "dom.visualviewport.enabled", VisualViewportEnabled, bool, false);
DECL_GFX_PREF(Once, "dom.vr.enabled", VREnabled, bool, false);
DECL_GFX_PREF(Live, "dom.vr.autoactivate.enabled", VRAutoActivateEnabled, bool, false);
DECL_GFX_PREF(Live, "dom.vr.controller_trigger_threshold", VRControllerTriggerThreshold, float, 0.1f);
DECL_GFX_PREF(Once, "dom.vr.external.enabled", VRExternalEnabled, bool, true);
DECL_GFX_PREF(Live, "dom.vr.navigation.timeout", VRNavigationTimeout, int32_t, 1000);
DECL_GFX_PREF(Once, "dom.vr.oculus.enabled", VROculusEnabled, bool, true);
DECL_GFX_PREF(Live, "dom.vr.oculus.invisible.enabled", VROculusInvisibleEnabled, bool, true);
DECL_GFX_PREF(Live, "dom.vr.oculus.present.timeout", VROculusPresentTimeout, int32_t, 500);
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5561,16 +5561,19 @@ pref("dom.presentation.session_transport
// following pref, when turned on, disables this behavior. See bug 1188425.
pref("intl.allow-insecure-text-input", false);
#endif
#endif // XP_MACOSX
// Enable meta-viewport support in remote APZ-enabled frames.
pref("dom.meta-viewport.enabled", false);
+// Disable Visual Viewport API
+pref("dom.visualviewport.enabled", false);
+
// Search service settings
pref("browser.search.log", false);
pref("browser.search.update", true);
pref("browser.search.update.log", false);
pref("browser.search.update.interval", 21600);
pref("browser.search.suggest.enabled", true);
pref("browser.search.reset.enabled", false);
pref("browser.search.reset.whitelist", "");