Bug 1357785 - Expose the Visual Viewport API to web content. r=botond,Nika
☠☠ backed out by c5fa12d5a014 ☠ ☠
authorTanushree Podder <tpodder@mozilla.com>
Wed, 25 Jul 2018 23:08:20 -0400
changeset 432412 a236c987f26c926f9bf4f82e351aaad39c7ae639
parent 432411 2c023d39fa5a5163e828fc9702f14e4d6b46e6db
child 432413 c5fa12d5a014c72e27c08669175f39315ae7b13b
push id106731
push usershindli@mozilla.com
push dateMon, 20 Aug 2018 16:36:25 +0000
treeherdermozilla-inbound@14ef4dec6126 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond, Nika
bugs1357785, 1478776
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
dom/base/VisualViewport.cpp
dom/base/VisualViewport.h
dom/base/moz.build
dom/base/nsGlobalWindowInner.cpp
dom/base/nsGlobalWindowInner.h
dom/bindings/Bindings.conf
dom/tests/mochitest/general/test_interfaces.js
dom/webidl/VisualViewport.webidl
dom/webidl/Window.webidl
dom/webidl/moz.build
gfx/thebes/gfxPrefs.h
modules/libpref/init/all.js
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
@@ -222,16 +222,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',
     ]
@@ -378,16 +379,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
@@ -28,16 +28,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"
@@ -2212,16 +2213,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
@@ -121,16 +121,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;
@@ -759,16 +760,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);
@@ -1388,16 +1390,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
@@ -1059,16 +1059,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
@@ -1157,16 +1157,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;
 interface nsIDOMWindowUtils;
 
 typedef OfflineResourceList ApplicationCache;
@@ -560,8 +561,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
@@ -913,16 +913,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
@@ -367,16 +367,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
@@ -5632,16 +5632,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", "");