Bug 859683 - Allow scrolling in full-screen mode if and only if the full-screen element is the document element. r=wesj
☠☠ backed out by 1b39c3a55620 ☠ ☠
authorKartikaya Gupta <kgupta@mozilla.com>
Tue, 06 May 2014 13:33:13 -0400
changeset 181873 14a43400007efbe1212307e09db3475126e4fe5b
parent 181834 ecd6d1b3670c0fb02c1bd1e755c9a52902581b8b
child 181874 76f2454c78661b45ae03de8f63677633227dfc2f
push id43162
push userkwierso@gmail.com
push dateWed, 07 May 2014 01:07:29 +0000
treeherdermozilla-inbound@8fcfb1107b03 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerswesj
bugs859683
milestone32.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 859683 - Allow scrolling in full-screen mode if and only if the full-screen element is the document element. r=wesj
mobile/android/base/GeckoApp.java
mobile/android/base/gfx/FullScreenState.java
mobile/android/base/gfx/GeckoLayerClient.java
mobile/android/base/gfx/JavaPanZoomController.java
mobile/android/base/gfx/LayerRenderer.java
mobile/android/base/gfx/LayerView.java
mobile/android/base/gfx/PanZoomTarget.java
mobile/android/base/moz.build
mobile/android/chrome/content/browser.js
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -31,16 +31,17 @@ import java.util.regex.Pattern;
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
 import org.mozilla.gecko.GeckoProfileDirectories.NoMozillaDirectoryException;
 import org.mozilla.gecko.background.announcements.AnnouncementsBroadcastService;
 import org.mozilla.gecko.db.BrowserDB;
 import org.mozilla.gecko.favicons.Favicons;
 import org.mozilla.gecko.gfx.BitmapUtils;
+import org.mozilla.gecko.gfx.FullScreenState;
 import org.mozilla.gecko.gfx.Layer;
 import org.mozilla.gecko.gfx.LayerView;
 import org.mozilla.gecko.gfx.PluginLayer;
 import org.mozilla.gecko.health.HealthRecorder;
 import org.mozilla.gecko.health.SessionInformation;
 import org.mozilla.gecko.health.StubbedHealthRecorder;
 import org.mozilla.gecko.menu.GeckoMenu;
 import org.mozilla.gecko.menu.GeckoMenuInflater;
@@ -559,23 +560,24 @@ public abstract class GeckoApp
             } else if (event.equals("ToggleChrome:Show")) {
                 toggleChrome(true);
             } else if (event.equals("ToggleChrome:Focus")) {
                 focusChrome();
             } else if (event.equals("DOMFullScreen:Start")) {
                 // Local ref to layerView for thread safety
                 LayerView layerView = mLayerView;
                 if (layerView != null) {
-                    layerView.setFullScreen(true);
+                    layerView.setFullScreenState(message.getBoolean("rootElement")
+                            ? FullScreenState.ROOT_ELEMENT : FullScreenState.NON_ROOT_ELEMENT);
                 }
             } else if (event.equals("DOMFullScreen:Stop")) {
                 // Local ref to layerView for thread safety
                 LayerView layerView = mLayerView;
                 if (layerView != null) {
-                    layerView.setFullScreen(false);
+                    layerView.setFullScreenState(FullScreenState.NONE);
                 }
             } else if (event.equals("Permissions:Data")) {
                 String host = message.getString("host");
                 JSONArray permissions = message.getJSONArray("permissions");
                 showSiteSettingsDialog(host, permissions);
             } else if (event.equals("Session:StatePurged")) {
                 onStatePurged();
             } else if (event.equals("Bookmark:Insert")) {
new file mode 100644
--- /dev/null
+++ b/mobile/android/base/gfx/FullScreenState.java
@@ -0,0 +1,12 @@
+/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
+ * 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/. */
+
+package org.mozilla.gecko.gfx;
+
+public enum FullScreenState {
+    NONE,
+    ROOT_ELEMENT,
+    NON_ROOT_ELEMENT
+}
--- a/mobile/android/base/gfx/GeckoLayerClient.java
+++ b/mobile/android/base/gfx/GeckoLayerClient.java
@@ -796,18 +796,18 @@ class GeckoLayerClient implements LayerV
     /** Implementation of PanZoomTarget */
     @Override
     public ZoomConstraints getZoomConstraints() {
         return mZoomConstraints;
     }
 
     /** Implementation of PanZoomTarget */
     @Override
-    public boolean isFullScreen() {
-        return mView.isFullScreen();
+    public FullScreenState getFullScreenState() {
+        return mView.getFullScreenState();
     }
 
     /** Implementation of PanZoomTarget */
     @Override
     public RectF getMaxMargins() {
         return mMarginsAnimator.getMaxMargins();
     }
 
--- a/mobile/android/base/gfx/JavaPanZoomController.java
+++ b/mobile/android/base/gfx/JavaPanZoomController.java
@@ -464,18 +464,21 @@ class JavaPanZoomController
             // fall through
         case ANIMATED_ZOOM:
         case NOTHING:
             // may happen if user double-taps and drags without lifting after the
             // second tap. ignore the move if this happens.
             return false;
 
         case TOUCHING:
-            // Don't allow panning if there is an element in full-screen mode. See bug 775511.
-            if ((mTarget.isFullScreen() && !mSubscroller.scrolling()) || panDistance(event) < PAN_THRESHOLD) {
+            // Don't allow panning if there is a non-root element in full-screen mode. See bug 775511 and bug 859683.
+            if (mTarget.getFullScreenState() == FullScreenState.NON_ROOT_ELEMENT && !mSubscroller.scrolling()) {
+                return false;
+            }
+            if (panDistance(event) < PAN_THRESHOLD) {
                 return false;
             }
             cancelTouch();
             startPanning(event.getX(0), event.getY(0), event.getEventTime());
             track(event);
             return true;
 
         case PANNING_HOLD_LOCKED_X:
@@ -1168,17 +1171,17 @@ class JavaPanZoomController
 
         GeckoAppShell.sendEventToGecko(GeckoEvent.createNativeGestureEvent(GeckoEvent.ACTION_MAGNIFY_START, mLastZoomFocus, getMetrics().zoomFactor));
 
         return true;
     }
 
     @Override
     public boolean onScale(SimpleScaleGestureDetector detector) {
-        if (mTarget.isFullScreen())
+        if (mTarget.getFullScreenState() != FullScreenState.NONE)
             return false;
 
         if (mState != PanZoomState.PINCHING)
             return false;
 
         float prevSpan = detector.getPreviousSpan();
         if (FloatUtils.fuzzyEquals(prevSpan, 0.0f)) {
             // let's eat this one to avoid setting the new zoom to infinity (bug 711453)
--- a/mobile/android/base/gfx/LayerRenderer.java
+++ b/mobile/android/base/gfx/LayerRenderer.java
@@ -499,19 +499,21 @@ public class LayerRenderer implements Ta
 
             mUpdated = true;
 
             Layer rootLayer = mView.getLayerClient().getRoot();
 
             // Run through pre-render tasks
             runRenderTasks(mTasks, false, mFrameStartTime);
 
-            if (!mPageContext.fuzzyEquals(mLastPageContext) && !mView.isFullScreen()) {
+            boolean hideScrollbars = (mView.getFullScreenState() == FullScreenState.NON_ROOT_ELEMENT);
+            if (!mPageContext.fuzzyEquals(mLastPageContext) && !hideScrollbars) {
                 // The viewport or page changed, so show the scrollbars again
-                // as per UX decision. Don't do this if we're in full-screen mode though.
+                // as per UX decision. Don't do this if we're disabling scrolling due to
+                // full-screen mode though.
                 mVertScrollLayer.unfade();
                 mHorizScrollLayer.unfade();
                 mFadeRunnable.scheduleStartFade(ScrollbarLayer.FADE_DELAY);
             } else if (mFadeRunnable.timeToFade()) {
                 boolean stillFading = mVertScrollLayer.fade() | mHorizScrollLayer.fade();
                 if (stillFading) {
                     mFadeRunnable.scheduleNextFadeFrame();
                 }
--- a/mobile/android/base/gfx/LayerView.java
+++ b/mobile/android/base/gfx/LayerView.java
@@ -59,17 +59,17 @@ public class LayerView extends FrameLayo
     private PanZoomController mPanZoomController;
     private LayerMarginsAnimator mMarginsAnimator;
     private GLController mGLController;
     private InputConnectionHandler mInputConnectionHandler;
     private LayerRenderer mRenderer;
     /* Must be a PAINT_xxx constant */
     private int mPaintState;
     private int mBackgroundColor;
-    private boolean mFullScreen;
+    private FullScreenState mFullScreenState;
 
     private SurfaceView mSurfaceView;
     private TextureView mTextureView;
 
     private Listener mListener;
 
     /* This should only be modified on the Java UI thread. */
     private final ArrayList<TouchEventInterceptor> mTouchInterceptors;
@@ -687,22 +687,26 @@ public class LayerView extends FrameLayo
     }
 
     @Override
     public void onFocusChanged (boolean gainFocus, int direction, Rect previouslyFocusedRect) {
         super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);
         GeckoAccessibility.onLayerViewFocusChanged(this, gainFocus);
     }
 
-    public void setFullScreen(boolean fullScreen) {
-        mFullScreen = fullScreen;
+    public void setFullScreenState(FullScreenState state) {
+        mFullScreenState = state;
     }
 
     public boolean isFullScreen() {
-        return mFullScreen;
+        return mFullScreenState != FullScreenState.NONE;
+    }
+
+    public FullScreenState getFullScreenState() {
+        return mFullScreenState;
     }
 
     @Override
     public void onTabChanged(Tab tab, Tabs.TabEvents msg, Object data) {
         if (msg == Tabs.TabEvents.VIEWPORT_CHANGE && Tabs.getInstance().isSelectedTab(tab) && mLayerClient != null) {
             setZoomConstraints(tab.getZoomConstraints());
             setIsRTL(tab.getIsRTL());
         }
--- a/mobile/android/base/gfx/PanZoomTarget.java
+++ b/mobile/android/base/gfx/PanZoomTarget.java
@@ -8,17 +8,17 @@ package org.mozilla.gecko.gfx;
 import org.mozilla.gecko.ZoomConstraints;
 
 import android.graphics.PointF;
 import android.graphics.RectF;
 
 public interface PanZoomTarget {
     public ImmutableViewportMetrics getViewportMetrics();
     public ZoomConstraints getZoomConstraints();
-    public boolean isFullScreen();
+    public FullScreenState getFullScreenState();
     public RectF getMaxMargins();
 
     public void setAnimationTarget(ImmutableViewportMetrics viewport);
     public void setViewportMetrics(ImmutableViewportMetrics viewport);
     public void scrollBy(float dx, float dy);
     public void scrollMarginsBy(float dx, float dy);
     public void panZoomStopped();
     /** This triggers an (asynchronous) viewport update/redraw. */
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -194,16 +194,17 @@ gbjar.sources += [
     'gfx/BufferedCairoImage.java',
     'gfx/CairoGLInfo.java',
     'gfx/CairoImage.java',
     'gfx/CairoUtils.java',
     'gfx/DisplayPortCalculator.java',
     'gfx/DisplayPortMetrics.java',
     'gfx/DrawTimingQueue.java',
     'gfx/FloatSize.java',
+    'gfx/FullScreenState.java',
     'gfx/GeckoLayerClient.java',
     'gfx/GLController.java',
     'gfx/ImmutableViewportMetrics.java',
     'gfx/InputConnectionHandler.java',
     'gfx/IntSize.java',
     'gfx/JavaPanZoomController.java',
     'gfx/Layer.java',
     'gfx/LayerMarginsAnimator.java',
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -341,22 +341,29 @@ var BrowserApp = {
     }
 
     window.addEventListener("fullscreen", function() {
       sendMessageToJava({
         type: window.fullScreen ? "ToggleChrome:Show" : "ToggleChrome:Hide"
       });
     }, false);
 
-    window.addEventListener("mozfullscreenchange", function() {
+    window.addEventListener("mozfullscreenchange", function(e) {
+      // This event gets fired on the document and its entire ancestor chain
+      // of documents. When enabling fullscreen, it is fired on the top-level
+      // document first and goes down; when disabling the order is reversed
+      // (per spec). This means the last event on enabling will be for the innermost
+      // document, which will have mozFullScreenElement set correctly.
+      let doc = e.target;
       sendMessageToJava({
-        type: document.mozFullScreen ? "DOMFullScreen:Start" : "DOMFullScreen:Stop"
+        type: doc.mozFullScreen ? "DOMFullScreen:Start" : "DOMFullScreen:Stop",
+        rootElement: (doc.mozFullScreen && doc.mozFullScreenElement == doc.documentElement)
       });
 
-      if (document.mozFullScreen)
+      if (doc.mozFullScreen)
         showFullScreenWarning();
     }, false);
 
     // When a restricted key is pressed in DOM full-screen mode, we should display
     // the "Press ESC to exit" warning message.
     window.addEventListener("MozShowFullScreenWarning", showFullScreenWarning, true);
 
     NativeWindow.init();