Bug 603008 - Only delay panning on pages with touch listeners. r=mfinkle
authorWes Johnston <wjohnston@mozilla.com>
Wed, 25 Jan 2012 01:31:33 +0100
changeset 86513 a63b9ee257e8414ae610b0c4dcda0c06fb5b901e
parent 86512 0286995894b721ce49b392e0bc4d32eef9b46e1b
child 86514 1b16c4bd7aa2748041812e2e0bf54707c63faf51
push id805
push userakeybl@mozilla.com
push dateWed, 01 Feb 2012 18:17:35 +0000
treeherdermozilla-aurora@6fb3bf232436 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmfinkle
bugs603008
milestone12.0a1
Bug 603008 - Only delay panning on pages with touch listeners. r=mfinkle
dom/base/nsGlobalWindow.cpp
mobile/android/base/GeckoApp.java
mobile/android/base/Tab.java
mobile/android/base/gfx/LayerController.java
mobile/android/chrome/content/browser.js
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -190,16 +190,17 @@
 #include "nsIObserverService.h"
 #include "nsIXULAppInfo.h"
 #include "nsNetUtil.h"
 #include "nsFocusManager.h"
 #include "nsIXULWindow.h"
 #include "nsEventStateManager.h"
 #include "nsITimedChannel.h"
 #include "nsICookiePermission.h"
+#include "nsServiceManagerUtils.h"
 #ifdef MOZ_XUL
 #include "nsXULPopupManager.h"
 #include "nsIDOMXULControlElement.h"
 #include "nsMenuPopupFrame.h"
 #endif
 
 #include "xpcprivate.h"
 
@@ -290,16 +291,18 @@ PRInt32 gTimeoutCnt                     
 #if !(defined(NS_DEBUG) || defined(MOZ_ENABLE_JS_DUMP))
 static bool                 gDOMWindowDumpEnabled      = false;
 #endif
 
 #if defined(DEBUG_bryner) || defined(DEBUG_chb)
 #define DEBUG_PAGE_CACHE
 #endif
 
+#define DOM_TOUCH_LISTENER_ADDED "dom-touch-listener-added"
+
 // The default shortest interval/timeout we permit
 #define DEFAULT_MIN_TIMEOUT_VALUE 4 // 4ms
 #define DEFAULT_MIN_BACKGROUND_TIMEOUT_VALUE 1000 // 1000ms
 static PRInt32 gMinTimeoutValue;
 static PRInt32 gMinBackgroundTimeoutValue;
 inline PRInt32
 nsGlobalWindow::DOMMinTimeoutValue() const {
   bool isBackground = !mOuterWindow || mOuterWindow->IsBackground();
@@ -7623,16 +7626,25 @@ void nsGlobalWindow::UpdateTouchState()
   FORWARD_TO_INNER_VOID(UpdateTouchState, ());
 
   nsCOMPtr<nsIWidget> mainWidget = GetMainWidget();
   if (!mainWidget)
     return;
 
   if (mMayHaveTouchEventListener) {
     mainWidget->RegisterTouchWindow();
+
+    nsCOMPtr<nsIObserverService> observerService =
+      do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
+    if (observerService) {
+      nsPIDOMWindow *inner = GetCurrentInnerWindowInternal();
+      observerService->NotifyObservers(mainWidget,
+                                       DOM_TOUCH_LISTENER_ADDED,
+                                       nsnull);
+    }
   } else {
     mainWidget->UnregisterTouchWindow();
   }
 }
 
 void
 nsGlobalWindow::EnableDeviceMotionUpdates()
 {
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -710,27 +710,29 @@ abstract public class GeckoApp
             });
             return;
         }
 
         tab.updateFavicon(null);
         tab.updateFaviconURL(null);
         tab.updateSecurityMode("unknown");
         tab.removeTransientDoorHangers();
+        tab.setHasTouchListeners(false);
 
         maybeCancelFaviconLoad(tab);
 
         mMainHandler.post(new Runnable() {
             public void run() {
                 if (Tabs.getInstance().isSelectedTab(tab)) {
                     mBrowserToolbar.setTitle(uri);
                     mBrowserToolbar.setFavicon(null);
                     mBrowserToolbar.setSecurityMode("unknown");
                     mDoorHangerPopup.updatePopup();
                     mBrowserToolbar.setShadowVisibility(!(tab.getURL().startsWith("about:")));
+                    mLayerController.setWaitForTouchListeners(false);
                 }
             }
         });
     }
 
     void handleSecurityChange(final int tabId, final String mode) {
         final Tab tab = Tabs.getInstance().getTab(tabId);
         if (tab == null)
--- a/mobile/android/base/Tab.java
+++ b/mobile/android/base/Tab.java
@@ -73,16 +73,17 @@ public final class Tab {
     private boolean mExternal;
     private boolean mLoading;
     private boolean mBookmark;
     private HashMap<String, DoorHanger> mDoorHangers;
     private long mFaviconLoadId;
     private CheckBookmarkTask mCheckBookmarkTask;
     private String mDocumentURI;
     private String mContentType;
+    private boolean mHasTouchListeners;
 
     public static final class HistoryEntry {
         public String mUri;         // must never be null
         public String mTitle;       // must never be null
 
         public HistoryEntry(String uri, String title) {
             mUri = uri;
             mTitle = title;
@@ -250,16 +251,24 @@ public final class Tab {
     public void setLoading(boolean loading) {
         mLoading = loading;
     }
 
     private void setBookmark(boolean bookmark) {
         mBookmark = bookmark;
     }
 
+    public void setHasTouchListeners(boolean aValue) {
+        mHasTouchListeners = aValue;
+    }
+
+    public boolean hasTouchListeners() {
+        return mHasTouchListeners;
+    }
+
     public void setFaviconLoadId(long faviconLoadId) {
         mFaviconLoadId = faviconLoadId;
     }
 
     public long getFaviconLoadId() {
         return mFaviconLoadId;
     }
 
--- a/mobile/android/base/gfx/LayerController.java
+++ b/mobile/android/base/gfx/LayerController.java
@@ -73,16 +73,17 @@ import java.util.TimerTask;
  */
 public class LayerController {
     private static final String LOGTAG = "GeckoLayerController";
 
     private Layer mRootLayer;                   /* The root layer. */
     private LayerView mView;                    /* The main rendering view. */
     private Context mContext;                   /* The current context. */
     private ViewportMetrics mViewportMetrics;   /* The current viewport metrics. */
+    private boolean mWaitForTouchListeners;
 
     private PanZoomController mPanZoomController;
     /*
      * The panning and zooming controller, which interprets pan and zoom gestures for us and
      * updates our visible rect appropriately.
      */
 
     private OnTouchListener mOnTouchListener;       /* The touch listener. */
@@ -360,24 +361,27 @@ public class LayerController {
      * pan/zoom controller to do the dirty work.
      */
     public boolean onTouchEvent(MotionEvent event) {
         int action = event.getAction();
         if ((action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_DOWN) {
             post(new Runnable() {
                 public void run() {
                     mView.clearEventQueue();
-                    preventPanning(true);
+                    preventPanning(mWaitForTouchListeners);
                 }
             });
         }
 
         if (mOnTouchListener != null)
             mOnTouchListener.onTouch(mView, event);
 
+        if (!mWaitForTouchListeners)
+            return !allowDefaultActions;
+
         switch (action & MotionEvent.ACTION_MASK) {
             case MotionEvent.ACTION_MOVE: {
                 if (!inTouchSession && allowDefaultTimer == null) {
                     inTouchSession = true;
                     allowDefaultTimer = new Timer();
                     allowDefaultTimer.schedule(new TimerTask() {
                         public void run() {
                             post(new Runnable() {
@@ -409,16 +413,20 @@ public class LayerController {
         if (aValue) {
             mView.clearEventQueue();
             mPanZoomController.cancelTouch();
         } else {
             mView.processEventQueue();
         }
     }
 
+    public void setWaitForTouchListeners(boolean aValue) {
+        mWaitForTouchListeners = aValue;
+    }
+
     /** Retrieves the color that the checkerboard should be. */
     public int getCheckerboardColor() {
         return mCheckerboardColor;
     }
 
     /** Sets a new color for the checkerboard. */
     public void setCheckerboardColor(int newColor) {
         mCheckerboardColor = newColor;
--- a/mobile/android/chrome/content/browser.js
+++ b/mobile/android/chrome/content/browser.js
@@ -2073,16 +2073,17 @@ Tab.prototype = {
 
 var BrowserEventHandler = {
   init: function init() {
     Services.obs.addObserver(this, "Gesture:SingleTap", false);
     Services.obs.addObserver(this, "Gesture:ShowPress", false);
     Services.obs.addObserver(this, "Gesture:CancelTouch", false);
     Services.obs.addObserver(this, "Gesture:DoubleTap", false);
     Services.obs.addObserver(this, "Gesture:Scroll", false);
+    Services.obs.addObserver(this, "dom-touch-listener-added", false);
 
     BrowserApp.deck.addEventListener("DOMUpdatePageReport", PopupBlockerObserver.onUpdatePageReport, false);
   },
 
   observe: function(aSubject, aTopic, aData) {
     if (aTopic == "Gesture:Scroll") {
       // If we've lost our scrollable element, return. Don't cancel the
       // override, as we probably don't want Java to handle panning until the
@@ -2152,16 +2153,31 @@ var BrowserEventHandler = {
         } catch(e) {
           Cu.reportError(e);
         }
       }
       this._cancelTapHighlight();
     } else if (aTopic == "Gesture:DoubleTap") {
       this._cancelTapHighlight();
       this.onDoubleTap(aData);
+    } else if (aTopic == "dom-touch-listener-added") {
+      let browser = BrowserApp.getBrowserForWindow(aSubject);
+      if (!browser)
+        return;
+
+      let tab = BrowserApp.getTabForBrowser(browser);
+      if (!tab)
+        return;
+
+      sendMessageToJava({
+        gecko: {
+          type: "Tab:HasTouchListener",
+          tabID: tab.id
+        }
+      });
     }
   },
  
   _zoomOut: function() {
     this._zoomedToElement = null;
     // zoom out, try to keep the center in the center of the page
     setTimeout(function() {
       sendMessageToJava({ gecko: { type: "Browser:ZoomToPageWidth"} });