Bug 1357785 - Expose the Visual Viewport API to web content. r?botond, nika draft
authorTanushree Podder <tpodder@mozilla.com>
Wed, 25 Jul 2018 23:08:20 -0400
changeset 830116 e113e1c4610fab818e0e4530526d9c02d48d9c9f
parent 818679 7764e30046d332307b726617ad9cd413623d9fd2
push id118816
push userbmo:tanushree.podder.103@gmail.com
push dateSun, 19 Aug 2018 22:10:38 +0000
reviewersbotond, nika
bugs1357785, 1478776
milestone63.0a1
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
@@ -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", "");