Backed out 2 changesets (bug 995394) for m-dt orange on a CLOSED TREE
authorWes Kocher <wkocher@mozilla.com>
Thu, 26 Feb 2015 17:56:14 -0800
changeset 231112 577937f4dce7cfcf2ec5d3485f8bdb0ba42f3952
parent 231111 00ccf3b425fdd5b5a79f9af887712bdfd3494500
child 231113 6bfb780221debb09d3cf094a4793988a6bd3c6cb
push id28344
push userryanvm@gmail.com
push dateFri, 27 Feb 2015 18:20:08 +0000
treeherdermozilla-central@9dd9d1e5b43c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs995394
milestone39.0a1
backs outa250f116b5633014a6fdf2b555eced5822f3cbeb
da37f3c9b4cec826cd33c38ff95fc30c80022ba8
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
Backed out 2 changesets (bug 995394) for m-dt orange on a CLOSED TREE Backed out changeset a250f116b563 (bug 995394) Backed out changeset da37f3c9b4ce (bug 995394)
dom/browser-element/BrowserElementChild.js
dom/browser-element/BrowserElementPanning.js
dom/browser-element/BrowserElementPanningAPZDisabled.js
dom/ipc/jar.mn
dom/ipc/preload.js
--- a/dom/browser-element/BrowserElementChild.js
+++ b/dom/browser-element/BrowserElementChild.js
@@ -37,28 +37,20 @@ if (!('BrowserElementIsPreloaded' in thi
   if (isTopBrowserElement(docShell) &&
       Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
     try {
       Services.scriptloader.loadSubScript("chrome://global/content/forms.js");
     } catch (e) {
     }
   }
 
-  if (docShell.asyncPanZoomEnabled === false) {
-    Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanningAPZDisabled.js");
-    ContentPanningAPZDisabled.init();
-  }
-
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js");
   ContentPanning.init();
 
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js");
 } else {
-  if (docShell.asyncPanZoomEnabled === false) {
-    ContentPanningAPZDisabled.init();
-  }
   ContentPanning.init();
 }
 
 var BrowserElementIsReady = true;
 
 
 sendAsyncMessage('browser-element-api:call', { 'msg_name': 'hello' });
--- a/dom/browser-element/BrowserElementPanning.js
+++ b/dom/browser-element/BrowserElementPanning.js
@@ -7,55 +7,501 @@
 
 "use strict";
 dump("############################### browserElementPanning.js loaded\n");
 
 let { classes: Cc, interfaces: Ci, results: Cr, utils: Cu }  = Components;
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://gre/modules/Geometry.jsm");
 
+var global = this;
+
 const kObservedEvents = [
   "BEC:ShownModalPrompt",
   "Activity:Success",
   "Activity:Error"
 ];
 
 const ContentPanning = {
+  // Are we listening to touch or mouse events?
+  watchedEventsType: '',
+
+  // Are mouse events being delivered to this content along with touch
+  // events, in violation of spec?
+  hybridEvents: false,
+
   init: function cp_init() {
+    // If APZ is enabled, we do active element handling in C++
+    // (see widget/xpwidgets/ActiveElementManager.h), and panning
+    // itself in APZ, so we don't need to handle any touch events here.
+    if (docShell.asyncPanZoomEnabled === false) {
+      this._setupListenersForPanning();
+    }
+
     addEventListener("unload",
 		     this._unloadHandler.bind(this),
 		     /* useCapture = */ false,
 		     /* wantsUntrusted = */ false);
 
     addMessageListener("Viewport:Change", this._recvViewportChange.bind(this));
     addMessageListener("Gesture:DoubleTap", this._recvDoubleTap.bind(this));
     addEventListener("visibilitychange", this._handleVisibilityChange.bind(this));
     kObservedEvents.forEach((topic) => {
       Services.obs.addObserver(this, topic, false);
     });
   },
 
+  _setupListenersForPanning: function cp_setupListenersForPanning() {
+    let events;
+
+    if (content.TouchEvent) {
+      events = ['touchstart', 'touchend', 'touchmove'];
+      this.watchedEventsType = 'touch';
+#ifdef MOZ_WIDGET_GONK
+      // The gonk widget backend does not deliver mouse events per
+      // spec.  Third-party content isn't exposed to this behavior,
+      // but that behavior creates some extra work for us here.
+      let appInfo = Cc["@mozilla.org/xre/app-info;1"];
+      let isParentProcess =
+        !appInfo || appInfo.getService(Ci.nsIXULRuntime)
+                           .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
+      this.hybridEvents = isParentProcess;
+#endif
+    } else {
+      // Touch events aren't supported, so fall back on mouse.
+      events = ['mousedown', 'mouseup', 'mousemove'];
+      this.watchedEventsType = 'mouse';
+    }
+
+    let els = Cc["@mozilla.org/eventlistenerservice;1"]
+                .getService(Ci.nsIEventListenerService);
+
+    events.forEach(function(type) {
+      // Using the system group for mouse/touch events to avoid
+      // missing events if .stopPropagation() has been called.
+      els.addSystemEventListener(global, type,
+                                 this.handleEvent.bind(this),
+                                 /* useCapture = */ false);
+    }.bind(this));
+  },
+
+  handleEvent: function cp_handleEvent(evt) {
+    // Ignore events targeting an oop <iframe mozbrowser> since those will be
+    // handle by the BrowserElementPanning.js instance in the child process.
+    if (evt.target instanceof Ci.nsIMozBrowserFrame) {
+      return;
+    }
+
+    // For in-process <iframe mozbrowser> the events are not targetting
+    // directly the container iframe element, but some node of the document.
+    // So, the BrowserElementPanning instance of the system app will receive
+    // the sequence of touch events, as well as the BrowserElementPanning
+    // instance in the targetted app.
+    // As a result, multiple mozbrowser iframes will try to interpret the
+    // sequence of touch events, which may results into multiple clicks.
+    let targetWindow = evt.target.ownerDocument.defaultView;
+    let frameElement = targetWindow.frameElement;
+    while (frameElement) {
+      targetWindow = frameElement.ownerDocument.defaultView;
+      frameElement = targetWindow.frameElement;
+    }
+
+    if (content !== targetWindow) {
+      return;
+    }
+
+    if (evt.defaultPrevented || evt.multipleActionsPrevented) {
+      // clean up panning state even if touchend/mouseup has been preventDefault.
+      if(evt.type === 'touchend' || evt.type === 'mouseup') {
+        if (this.dragging &&
+            (this.watchedEventsType === 'mouse' ||
+             this.findPrimaryPointer(evt.changedTouches))) {
+          this._finishPanning();
+        }
+      }
+      return;
+    }
+
+    switch (evt.type) {
+      case 'mousedown':
+      case 'touchstart':
+        this.onTouchStart(evt);
+        break;
+      case 'mousemove':
+      case 'touchmove':
+        this.onTouchMove(evt);
+        break;
+      case 'mouseup':
+      case 'touchend':
+        this.onTouchEnd(evt);
+        break;
+      case 'click':
+        evt.stopPropagation();
+        evt.preventDefault();
+
+        let target = evt.target;
+        let view = target.ownerDocument ? target.ownerDocument.defaultView
+                                        : target;
+        view.removeEventListener('click', this, true, true);
+        break;
+    }
+  },
+
   observe: function cp_observe(subject, topic, data) {
     this._resetHover();
   },
 
+  position: new Point(0 , 0),
+
+  findPrimaryPointer: function cp_findPrimaryPointer(touches) {
+    if (!('primaryPointerId' in this))
+      return null;
+
+    for (let i = 0; i < touches.length; i++) {
+      if (touches[i].identifier === this.primaryPointerId) {
+        return touches[i];
+      }
+    }
+    return null;
+  },
+
+  onTouchStart: function cp_onTouchStart(evt) {
+    let screenX, screenY;
+    if (this.watchedEventsType == 'touch') {
+      if ('primaryPointerId' in this || evt.touches.length >= 2) {
+        this._resetActive();
+        return;
+      }
+
+      let firstTouch = evt.changedTouches[0];
+      this.primaryPointerId = firstTouch.identifier;
+      this.pointerDownTarget = firstTouch.target;
+      screenX = firstTouch.screenX;
+      screenY = firstTouch.screenY;
+    } else {
+      this.pointerDownTarget = evt.target;
+      screenX = evt.screenX;
+      screenY = evt.screenY;
+    }
+    this.dragging = true;
+    this.panning = false;
+
+    let oldTarget = this.target;
+    [this.target, this.scrollCallback] = this.getPannable(this.pointerDownTarget);
+
+    // If we have a pointer down target, we may need to fill in for EventStateManager
+    // in setting the active state on the target element.  Set a timer to
+    // ensure the pointer-down target is active.  (If it's already
+    // active, the timer is a no-op.)
+    if (this.pointerDownTarget !== null) {
+      // If there's no possibility this is a drag/pan, activate now.
+      // Otherwise wait a little bit to see if the gesture isn't a
+      // tap.
+      if (this.target === null) {
+        this.notify(this._activationTimer);
+      } else {
+        this._activationTimer.initWithCallback(this,
+                                               this._activationDelayMs,
+                                               Ci.nsITimer.TYPE_ONE_SHOT);
+      }
+    }
+
+    // If there is a pan animation running (from a previous pan gesture) and
+    // the user touch back the screen, stop this animation immediatly and
+    // prevent the possible click action if the touch happens on the same
+    // target.
+    this.preventNextClick = false;
+    if (KineticPanning.active) {
+      KineticPanning.stop();
+
+      if (oldTarget && oldTarget == this.target)
+        this.preventNextClick = true;
+    }
+
+    this.position.set(screenX, screenY);
+    KineticPanning.reset();
+    KineticPanning.record(new Point(0, 0), evt.timeStamp);
+
+    // We prevent start events to avoid sending a focus event at the end of this
+    // touch series. See bug 889717.
+    if ((this.panning || this.preventNextClick)) {
+      evt.preventDefault();
+    }
+  },
+
+  onTouchEnd: function cp_onTouchEnd(evt) {
+    let touch = null;
+    if (!this.dragging ||
+        (this.watchedEventsType == 'touch' &&
+         !(touch = this.findPrimaryPointer(evt.changedTouches)))) {
+      return;
+    }
+
+    // !isPan() and evt.detail should always give the same answer here
+    // since they use the same heuristics, but use the native gecko
+    // computation when possible.
+    //
+    // NB: when we're using touch events, then !KineticPanning.isPan()
+    // => this.panning, so we'll never attempt to block the click
+    // event.  That's OK however, because we won't fire a synthetic
+    // click when we're using touch events and this touch series
+    // wasn't a "tap" gesture.
+    let click = (this.watchedEventsType == 'mouse') ?
+      evt.detail : !KineticPanning.isPan();
+    // Additionally, if we're seeing non-compliant hybrid events, a
+    // "real" click will be generated if we started and ended on the
+    // same element.
+    if (this.hybridEvents) {
+      let target =
+        content.document.elementFromPoint(touch.clientX, touch.clientY);
+      click |= (target === this.pointerDownTarget);
+    }
+
+    if (this.target && click && (this.panning || this.preventNextClick)) {
+      if (this.hybridEvents) {
+        let target = this.target;
+        let view = target.ownerDocument ? target.ownerDocument.defaultView
+                                        : target;
+        view.addEventListener('click', this, true, true);
+      } else {
+        // We prevent end events to avoid sending a focus event. See bug 889717.
+        evt.preventDefault();
+      }
+    } else if (this.target && click && !this.panning) {
+      this.notify(this._activationTimer);
+    }
+
+    this._finishPanning();
+
+    // Now that we're done, avoid entraining the thing we just panned.
+    this.pointerDownTarget = null;
+  },
+
+  onTouchMove: function cp_onTouchMove(evt) {
+    if (!this.dragging)
+      return;
+
+    let screenX, screenY;
+    if (this.watchedEventsType == 'touch') {
+      let primaryTouch = this.findPrimaryPointer(evt.changedTouches);
+      if (evt.touches.length > 1 || !primaryTouch)
+        return;
+      screenX = primaryTouch.screenX;
+      screenY = primaryTouch.screenY;
+    } else {
+      screenX = evt.screenX;
+      screenY = evt.screenY;
+    }
+
+    let current = this.position;
+    let delta = new Point(screenX - current.x, screenY - current.y);
+    current.set(screenX, screenY);
+
+    KineticPanning.record(delta, evt.timeStamp);
+
+    let isPan = KineticPanning.isPan();
+
+    // If we've detected a pan gesture, cancel the active state of the
+    // current target.
+    if (!this.panning && isPan) {
+      this._resetActive();
+    }
+
+    // There's no possibility of us panning anything.
+    if (!this.scrollCallback) {
+      return;
+    }
+
+    // Scroll manually.
+    this.scrollCallback(delta.scale(-1));
+
+    if (!this.panning && isPan) {
+      this.panning = true;
+      this._activationTimer.cancel();
+    }
+
+    if (this.panning) {
+      // Only do this when we're actually executing a pan gesture.
+      // Otherwise synthetic mouse events will be canceled.
+      evt.stopPropagation();
+      evt.preventDefault();
+    }
+  },
+
+  // nsITimerCallback
+  notify: function cp_notify(timer) {
+    this._setActive(this.pointerDownTarget);
+  },
+
+  onKineticBegin: function cp_onKineticBegin(evt) {
+  },
+
+  onKineticPan: function cp_onKineticPan(delta) {
+    return !this.scrollCallback(delta);
+  },
+
+  onKineticEnd: function cp_onKineticEnd() {
+    if (!this.dragging)
+      this.scrollCallback = null;
+  },
+
+  getPannable: function cp_getPannable(node) {
+    let pannableNode = this._findPannable(node);
+    if (pannableNode) {
+      return [pannableNode, this._generateCallback(pannableNode)];
+    }
+
+    return [null, null];
+  },
+
+  _findPannable: function cp_findPannable(node) {
+    if (!(node instanceof Ci.nsIDOMHTMLElement) || node.tagName == 'HTML') {
+      return null;
+    }
+
+    let nodeContent = node.ownerDocument.defaultView;
+    while (!(node instanceof Ci.nsIDOMHTMLBodyElement)) {
+      let style = nodeContent.getComputedStyle(node, null);
+
+      let overflow = [style.getPropertyValue('overflow'),
+                      style.getPropertyValue('overflow-x'),
+                      style.getPropertyValue('overflow-y')];
+
+      let rect = node.getBoundingClientRect();
+      let isAuto = (overflow.indexOf('auto') != -1 &&
+                   (rect.height < node.scrollHeight ||
+                    rect.width < node.scrollWidth));
+
+      let isScroll = (overflow.indexOf('scroll') != -1);
+
+      let isScrollableTextarea = (node.tagName == 'TEXTAREA' &&
+          (node.scrollHeight > node.clientHeight ||
+           node.scrollWidth > node.clientWidth ||
+           ('scrollLeftMax' in node && node.scrollLeftMax > 0) ||
+           ('scrollTopMax' in node && node.scrollTopMax > 0)));
+      if (isScroll || isAuto || isScrollableTextarea) {
+        return node;
+      }
+
+      node = node.parentNode;
+    }
+
+    if (nodeContent.scrollMaxX || nodeContent.scrollMaxY) {
+      return nodeContent;
+    }
+
+    if (nodeContent.frameElement) {
+      return this._findPannable(nodeContent.frameElement);
+    }
+
+    return null;
+  },
+
+  _generateCallback: function cp_generateCallback(root) {
+    let firstScroll = true;
+    let target;
+    let current;
+    let win, doc, htmlNode, bodyNode;
+
+    function doScroll(node, delta) {
+      if (node instanceof Ci.nsIDOMHTMLElement) {
+        return node.scrollByNoFlush(delta.x, delta.y);
+      } else if (node instanceof Ci.nsIDOMWindow) {
+        win = node;
+        doc = win.document;
+
+        // "overflow:hidden" on either the <html> or the <body> node should
+        // prevent the user from scrolling the root viewport.
+        if (doc instanceof Ci.nsIDOMHTMLDocument) {
+          htmlNode = doc.documentElement;
+          bodyNode = doc.body;
+          if (win.getComputedStyle(htmlNode, null).overflowX == "hidden" ||
+              win.getComputedStyle(bodyNode, null).overflowX == "hidden") {
+            delta.x = 0;
+          }
+          if (win.getComputedStyle(htmlNode, null).overflowY == "hidden" ||
+              win.getComputedStyle(bodyNode, null).overflowY == "hidden") {
+            delta.y = 0;
+          }
+        }
+        let oldX = node.scrollX;
+        let oldY = node.scrollY;
+        node.scrollBy(delta.x, delta.y);
+        return (node.scrollX != oldX || node.scrollY != oldY);
+      }
+      // If we get here, |node| isn't an HTML element and it's not a window,
+      // but findPannable apparently thought it was scrollable... What is it?
+      return false;
+    }
+
+    function targetParent(node) {
+      return node.parentNode || node.frameElement || null;
+    }
+
+    function scroll(delta) {
+      current = root;
+      firstScroll = true;
+      while (current) {
+        if (doScroll(current, delta)) {
+          firstScroll = false;
+          return true;
+        }
+
+        // TODO The current code looks for possible scrolling regions only if
+        // this is the first scroll action but this should be more dynamic.
+        if (!firstScroll) {
+          return false;
+        }
+
+        current = ContentPanning._findPannable(targetParent(current));
+      }
+
+      // There is nothing scrollable here.
+      return false;
+    }
+    return scroll;
+  },
+
   get _domUtils() {
     delete this._domUtils;
     return this._domUtils = Cc['@mozilla.org/inspector/dom-utils;1']
                               .getService(Ci.inIDOMUtils);
   },
 
+  get _activationTimer() {
+    delete this._activationTimer;
+    return this._activationTimer = Cc["@mozilla.org/timer;1"]
+                                     .createInstance(Ci.nsITimer);
+  },
+
+  get _activationDelayMs() {
+    let delay = Services.prefs.getIntPref('ui.touch_activation.delay_ms');
+    delete this._activationDelayMs;
+    return this._activationDelayMs = delay;
+  },
+
+  _resetActive: function cp_resetActive() {
+    let elt = this.pointerDownTarget || this.target;
+    let root = elt.ownerDocument || elt.document;
+    this._setActive(root.documentElement);
+  },
+
   _resetHover: function cp_resetHover() {
     const kStateHover = 0x00000004;
     try {
       let element = content.document.createElement('foo');
       this._domUtils.setContentState(element, kStateHover);
     } catch(e) {}
   },
 
+  _setActive: function cp_setActive(elt) {
+    const kStateActive = 0x00000001;
+    this._domUtils.setContentState(elt, kStateActive);
+  },
+
   _recvViewportChange: function(data) {
     let metrics = data.json;
     this._viewport = new Rect(metrics.x, metrics.y,
                               metrics.viewport.width,
                               metrics.viewport.height);
     this._cssCompositedRect = new Rect(metrics.x, metrics.y,
                                        metrics.cssCompositedRect.width,
                                        metrics.cssCompositedRect.height);
@@ -159,23 +605,234 @@ const ContentPanning = {
     let availHeight = Math.min(aRect.width * vRect.height / vRect.width, aRect.height);
     let showing = overlapArea / (aRect.width * availHeight);
     let ratioW = (aRect.width / vRect.width);
     let ratioH = (aRect.height / vRect.height);
 
     return (showing > 0.9 && (ratioW > 0.9 || ratioH > 0.9)); 
   },
 
+  _finishPanning: function() {
+    this.dragging = false;
+    delete this.primaryPointerId;
+    this._activationTimer.cancel();
+
+    // If there is a scroll action, let's do a manual kinetic panning action.
+    if (this.panning) {
+      KineticPanning.start(this);
+    }
+  },
+
   _unloadHandler: function() {
     kObservedEvents.forEach((topic) => {
       Services.obs.removeObserver(this, topic);
     });
   }
 };
 
+// Min/max velocity of kinetic panning. This is in pixels/millisecond.
+const kMinVelocity = 0.2;
+const kMaxVelocity = 6;
+
+// Constants that affect the "friction" of the scroll pane.
+const kExponentialC = 1000;
+const kPolynomialC = 100 / 1000000;
+
+// How often do we change the position of the scroll pane?
+// Too often and panning may jerk near the end.
+// Too little and panning will be choppy. In milliseconds.
+const kUpdateInterval = 16;
+
+// The numbers of momentums to use for calculating the velocity of the pan.
+// Those are taken from the end of the action
+const kSamples = 5;
+
+const KineticPanning = {
+  _position: new Point(0, 0),
+  _velocity: new Point(0, 0),
+  _acceleration: new Point(0, 0),
+
+  get active() {
+    return this.target !== null;
+  },
+
+  target: null,
+  start: function kp_start(target) {
+    this.target = target;
+
+    // Calculate the initial velocity of the movement based on user input
+    let momentums = this.momentums;
+    let flick = momentums[momentums.length - 1].time - momentums[0].time < 300;
+
+    let distance = new Point(0, 0);
+    momentums.forEach(function(momentum) {
+      distance.add(momentum.dx, momentum.dy);
+    });
+
+    function clampFromZero(x, min, max) {
+      if (x >= 0)
+        return Math.max(min, Math.min(max, x));
+      return Math.min(-min, Math.max(-max, x));
+    }
+
+    let elapsed = momentums[momentums.length - 1].time - momentums[0].time;
+    let velocityX = clampFromZero(distance.x / elapsed, 0, kMaxVelocity);
+    let velocityY = clampFromZero(distance.y / elapsed, 0, kMaxVelocity);
+
+    let velocity = this._velocity;
+    if (flick) {
+      // Very fast pan action that does not generate a click are very often pan
+      // action. If this is a small gesture then it will not move the view a lot
+      // and so it will be above the minimun threshold and not generate any
+      // kinetic panning. This does not look on a device since this is often
+      // a real gesture, so let's lower the velocity threshold for such moves.
+      velocity.set(velocityX, velocityY);
+    } else {
+      velocity.set(Math.abs(velocityX) < kMinVelocity ? 0 : velocityX,
+                   Math.abs(velocityY) < kMinVelocity ? 0 : velocityY);
+    }
+    this.momentums = [];
+
+    // Set acceleration vector to opposite signs of velocity
+    function sign(x) {
+      return x ? (x > 0 ? 1 : -1) : 0;
+    }
+
+    this._acceleration.set(velocity.clone().map(sign).scale(-kPolynomialC));
+
+    // Reset the position
+    this._position.set(0, 0);
+
+    this._startAnimation();
+
+    this.target.onKineticBegin();
+  },
+
+  stop: function kp_stop() {
+    this.reset();
+
+    if (!this.target)
+      return;
+
+    this.target.onKineticEnd();
+    this.target = null;
+  },
+
+  reset: function kp_reset() {
+    this.momentums = [];
+    this.distance.set(0, 0);
+  },
+
+  momentums: [],
+  record: function kp_record(delta, timestamp) {
+    this.momentums.push({ 'time': this._getTime(timestamp),
+                          'dx' : delta.x, 'dy' : delta.y });
+
+    // We only need to keep kSamples in this.momentums.
+    if (this.momentums.length > kSamples) {
+      this.momentums.shift();
+    }
+
+    this.distance.add(delta.x, delta.y);
+  },
+
+  _getTime: function kp_getTime(time) {
+    // Touch events generated by the platform or hand-made are defined in
+    // microseconds instead of milliseconds. Bug 77992 will fix this at the
+    // platform level.
+    if (time > Date.now()) {
+      return Math.floor(time / 1000);
+    } else {
+      return time;
+    }
+  },
+
+  get threshold() {
+    let dpi = content.QueryInterface(Ci.nsIInterfaceRequestor)
+                     .getInterface(Ci.nsIDOMWindowUtils)
+                     .displayDPI;
+
+    let threshold = Services.prefs.getIntPref('ui.dragThresholdX') / 240 * dpi;
+
+    delete this.threshold;
+    return this.threshold = threshold;
+  },
+
+  distance: new Point(0, 0),
+  isPan: function cp_isPan() {
+    return (Math.abs(this.distance.x) > this.threshold ||
+            Math.abs(this.distance.y) > this.threshold);
+  },
+
+  _startAnimation: function kp_startAnimation() {
+    let c = kExponentialC;
+    function getNextPosition(position, v, a, t) {
+      // Important traits for this function:
+      //   p(t=0) is 0
+      //   p'(t=0) is v0
+      //
+      // We use exponential to get a smoother stop, but by itself exponential
+      // is too smooth at the end. Adding a polynomial with the appropriate
+      // weight helps to balance
+      position.set(v.x * Math.exp(-t / c) * -c + a.x * t * t + v.x * c,
+                   v.y * Math.exp(-t / c) * -c + a.y * t * t + v.y * c);
+    }
+
+    let startTime = content.mozAnimationStartTime;
+    let elapsedTime = 0, targetedTime = 0, averageTime = 0;
+
+    let velocity = this._velocity;
+    let acceleration = this._acceleration;
+
+    let position = this._position;
+    let nextPosition = new Point(0, 0);
+    let delta = new Point(0, 0);
+
+    let callback = (function(timestamp) {
+      if (!this.target)
+        return;
+
+      // To make animation end fast enough but to keep smoothness, average the
+      // ideal time frame (smooth animation) with the actual time lapse
+      // (end fast enough).
+      // Animation will never take longer than 2 times the ideal length of time.
+      elapsedTime = timestamp - startTime;
+      targetedTime += kUpdateInterval;
+      averageTime = (targetedTime + elapsedTime) / 2;
+
+      // Calculate new position.
+      getNextPosition(nextPosition, velocity, acceleration, averageTime);
+      delta.set(Math.round(nextPosition.x - position.x),
+                Math.round(nextPosition.y - position.y));
+
+      // Test to see if movement is finished for each component.
+      if (delta.x * acceleration.x > 0)
+        delta.x = position.x = velocity.x = acceleration.x = 0;
+
+      if (delta.y * acceleration.y > 0)
+        delta.y = position.y = velocity.y = acceleration.y = 0;
+
+      if (velocity.equals(0, 0) || delta.equals(0, 0)) {
+        this.stop();
+        return;
+      }
+
+      position.add(delta);
+      if (this.target.onKineticPan(delta.scale(-1))) {
+        this.stop();
+        return;
+      }
+
+      content.mozRequestAnimationFrame(callback);
+    }).bind(this);
+
+    content.mozRequestAnimationFrame(callback);
+  }
+};
+
 const ElementTouchHelper = {
   anyElementFromPoint: function(aWindow, aX, aY) {
     let cwu = aWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
     let elem = cwu.elementFromPoint(aX, aY, true, true);
 
     let HTMLIFrameElement = Ci.nsIDOMHTMLIFrameElement;
     let HTMLFrameElement = Ci.nsIDOMHTMLFrameElement;
     while (elem && (elem instanceof HTMLIFrameElement || elem instanceof HTMLFrameElement)) {
deleted file mode 100644
--- a/dom/browser-element/BrowserElementPanningAPZDisabled.js
+++ /dev/null
@@ -1,675 +0,0 @@
-/* -*- tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*- */
-/* vim: set ts=2 sw=2 sts=2 et: */
-
-/* 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/. */
-
-"use strict";
-dump("############################### browserElementPanningAPZDisabled.js loaded\n");
-
-let { classes: Cc, interfaces: Ci, results: Cr, utils: Cu }  = Components;
-Cu.import("resource://gre/modules/Services.jsm");
-Cu.import("resource://gre/modules/Geometry.jsm");
-
-var global = this;
-
-const ContentPanningAPZDisabled = {
-  // Are we listening to touch or mouse events?
-  watchedEventsType: '',
-
-  // Are mouse events being delivered to this content along with touch
-  // events, in violation of spec?
-  hybridEvents: false,
-
-  init: function cp_init() {
-    this._setupListenersForPanning();
-  },
-
-  _setupListenersForPanning: function cp_setupListenersForPanning() {
-    let events;
-
-    if (content.TouchEvent) {
-      events = ['touchstart', 'touchend', 'touchmove'];
-      this.watchedEventsType = 'touch';
-#ifdef MOZ_WIDGET_GONK
-      // The gonk widget backend does not deliver mouse events per
-      // spec.  Third-party content isn't exposed to this behavior,
-      // but that behavior creates some extra work for us here.
-      let appInfo = Cc["@mozilla.org/xre/app-info;1"];
-      let isParentProcess =
-        !appInfo || appInfo.getService(Ci.nsIXULRuntime)
-                           .processType == Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
-      this.hybridEvents = isParentProcess;
-#endif
-    } else {
-      // Touch events aren't supported, so fall back on mouse.
-      events = ['mousedown', 'mouseup', 'mousemove'];
-      this.watchedEventsType = 'mouse';
-    }
-
-    let els = Cc["@mozilla.org/eventlistenerservice;1"]
-                .getService(Ci.nsIEventListenerService);
-
-    events.forEach(function(type) {
-      // Using the system group for mouse/touch events to avoid
-      // missing events if .stopPropagation() has been called.
-      els.addSystemEventListener(global, type,
-                                 this.handleEvent.bind(this),
-                                 /* useCapture = */ false);
-    }.bind(this));
-  },
-
-  handleEvent: function cp_handleEvent(evt) {
-    // Ignore events targeting an oop <iframe mozbrowser> since those will be
-    // handle by the BrowserElementPanning.js instance in the child process.
-    if (evt.target instanceof Ci.nsIMozBrowserFrame) {
-      return;
-    }
-
-    // For in-process <iframe mozbrowser> the events are not targetting
-    // directly the container iframe element, but some node of the document.
-    // So, the BrowserElementPanning instance of the system app will receive
-    // the sequence of touch events, as well as the BrowserElementPanning
-    // instance in the targetted app.
-    // As a result, multiple mozbrowser iframes will try to interpret the
-    // sequence of touch events, which may results into multiple clicks.
-    let targetWindow = evt.target.ownerDocument.defaultView;
-    let frameElement = targetWindow.frameElement;
-    while (frameElement) {
-      targetWindow = frameElement.ownerDocument.defaultView;
-      frameElement = targetWindow.frameElement;
-    }
-
-    if (content !== targetWindow) {
-      return;
-    }
-
-    if (evt.defaultPrevented || evt.multipleActionsPrevented) {
-      // clean up panning state even if touchend/mouseup has been preventDefault.
-      if(evt.type === 'touchend' || evt.type === 'mouseup') {
-        if (this.dragging &&
-            (this.watchedEventsType === 'mouse' ||
-             this.findPrimaryPointer(evt.changedTouches))) {
-          this._finishPanning();
-        }
-      }
-      return;
-    }
-
-    switch (evt.type) {
-      case 'mousedown':
-      case 'touchstart':
-        this.onTouchStart(evt);
-        break;
-      case 'mousemove':
-      case 'touchmove':
-        this.onTouchMove(evt);
-        break;
-      case 'mouseup':
-      case 'touchend':
-        this.onTouchEnd(evt);
-        break;
-      case 'click':
-        evt.stopPropagation();
-        evt.preventDefault();
-
-        let target = evt.target;
-        let view = target.ownerDocument ? target.ownerDocument.defaultView
-                                        : target;
-        view.removeEventListener('click', this, true, true);
-        break;
-    }
-  },
-
-  position: new Point(0 , 0),
-
-  findPrimaryPointer: function cp_findPrimaryPointer(touches) {
-    if (!('primaryPointerId' in this))
-      return null;
-
-    for (let i = 0; i < touches.length; i++) {
-      if (touches[i].identifier === this.primaryPointerId) {
-        return touches[i];
-      }
-    }
-    return null;
-  },
-
-  onTouchStart: function cp_onTouchStart(evt) {
-    let screenX, screenY;
-    if (this.watchedEventsType == 'touch') {
-      if ('primaryPointerId' in this || evt.touches.length >= 2) {
-        this._resetActive();
-        return;
-      }
-
-      let firstTouch = evt.changedTouches[0];
-      this.primaryPointerId = firstTouch.identifier;
-      this.pointerDownTarget = firstTouch.target;
-      screenX = firstTouch.screenX;
-      screenY = firstTouch.screenY;
-    } else {
-      this.pointerDownTarget = evt.target;
-      screenX = evt.screenX;
-      screenY = evt.screenY;
-    }
-    this.dragging = true;
-    this.panning = false;
-
-    let oldTarget = this.target;
-    [this.target, this.scrollCallback] = this.getPannable(this.pointerDownTarget);
-
-    // If we have a pointer down target, we may need to fill in for EventStateManager
-    // in setting the active state on the target element.  Set a timer to
-    // ensure the pointer-down target is active.  (If it's already
-    // active, the timer is a no-op.)
-    if (this.pointerDownTarget !== null) {
-      // If there's no possibility this is a drag/pan, activate now.
-      // Otherwise wait a little bit to see if the gesture isn't a
-      // tap.
-      if (this.target === null) {
-        this.notify(this._activationTimer);
-      } else {
-        this._activationTimer.initWithCallback(this,
-                                               this._activationDelayMs,
-                                               Ci.nsITimer.TYPE_ONE_SHOT);
-      }
-    }
-
-    // If there is a pan animation running (from a previous pan gesture) and
-    // the user touch back the screen, stop this animation immediatly and
-    // prevent the possible click action if the touch happens on the same
-    // target.
-    this.preventNextClick = false;
-    if (KineticPanning.active) {
-      KineticPanning.stop();
-
-      if (oldTarget && oldTarget == this.target)
-        this.preventNextClick = true;
-    }
-
-    this.position.set(screenX, screenY);
-    KineticPanning.reset();
-    KineticPanning.record(new Point(0, 0), evt.timeStamp);
-
-    // We prevent start events to avoid sending a focus event at the end of this
-    // touch series. See bug 889717.
-    if ((this.panning || this.preventNextClick)) {
-      evt.preventDefault();
-    }
-  },
-
-  onTouchEnd: function cp_onTouchEnd(evt) {
-    let touch = null;
-    if (!this.dragging ||
-        (this.watchedEventsType == 'touch' &&
-         !(touch = this.findPrimaryPointer(evt.changedTouches)))) {
-      return;
-    }
-
-    // !isPan() and evt.detail should always give the same answer here
-    // since they use the same heuristics, but use the native gecko
-    // computation when possible.
-    //
-    // NB: when we're using touch events, then !KineticPanning.isPan()
-    // => this.panning, so we'll never attempt to block the click
-    // event.  That's OK however, because we won't fire a synthetic
-    // click when we're using touch events and this touch series
-    // wasn't a "tap" gesture.
-    let click = (this.watchedEventsType == 'mouse') ?
-      evt.detail : !KineticPanning.isPan();
-    // Additionally, if we're seeing non-compliant hybrid events, a
-    // "real" click will be generated if we started and ended on the
-    // same element.
-    if (this.hybridEvents) {
-      let target =
-        content.document.elementFromPoint(touch.clientX, touch.clientY);
-      click |= (target === this.pointerDownTarget);
-    }
-
-    if (this.target && click && (this.panning || this.preventNextClick)) {
-      if (this.hybridEvents) {
-        let target = this.target;
-        let view = target.ownerDocument ? target.ownerDocument.defaultView
-                                        : target;
-        view.addEventListener('click', this, true, true);
-      } else {
-        // We prevent end events to avoid sending a focus event. See bug 889717.
-        evt.preventDefault();
-      }
-    } else if (this.target && click && !this.panning) {
-      this.notify(this._activationTimer);
-    }
-
-    this._finishPanning();
-
-    // Now that we're done, avoid entraining the thing we just panned.
-    this.pointerDownTarget = null;
-  },
-
-  onTouchMove: function cp_onTouchMove(evt) {
-    if (!this.dragging)
-      return;
-
-    let screenX, screenY;
-    if (this.watchedEventsType == 'touch') {
-      let primaryTouch = this.findPrimaryPointer(evt.changedTouches);
-      if (evt.touches.length > 1 || !primaryTouch)
-        return;
-      screenX = primaryTouch.screenX;
-      screenY = primaryTouch.screenY;
-    } else {
-      screenX = evt.screenX;
-      screenY = evt.screenY;
-    }
-
-    let current = this.position;
-    let delta = new Point(screenX - current.x, screenY - current.y);
-    current.set(screenX, screenY);
-
-    KineticPanning.record(delta, evt.timeStamp);
-
-    let isPan = KineticPanning.isPan();
-
-    // If we've detected a pan gesture, cancel the active state of the
-    // current target.
-    if (!this.panning && isPan) {
-      this._resetActive();
-    }
-
-    // There's no possibility of us panning anything.
-    if (!this.scrollCallback) {
-      return;
-    }
-
-    // Scroll manually.
-    this.scrollCallback(delta.scale(-1));
-
-    if (!this.panning && isPan) {
-      this.panning = true;
-      this._activationTimer.cancel();
-    }
-
-    if (this.panning) {
-      // Only do this when we're actually executing a pan gesture.
-      // Otherwise synthetic mouse events will be canceled.
-      evt.stopPropagation();
-      evt.preventDefault();
-    }
-  },
-
-  // nsITimerCallback
-  notify: function cp_notify(timer) {
-    this._setActive(this.pointerDownTarget);
-  },
-
-  onKineticBegin: function cp_onKineticBegin(evt) {
-  },
-
-  onKineticPan: function cp_onKineticPan(delta) {
-    return !this.scrollCallback(delta);
-  },
-
-  onKineticEnd: function cp_onKineticEnd() {
-    if (!this.dragging)
-      this.scrollCallback = null;
-  },
-
-  getPannable: function cp_getPannable(node) {
-    let pannableNode = this._findPannable(node);
-    if (pannableNode) {
-      return [pannableNode, this._generateCallback(pannableNode)];
-    }
-
-    return [null, null];
-  },
-
-  _findPannable: function cp_findPannable(node) {
-    if (!(node instanceof Ci.nsIDOMHTMLElement) || node.tagName == 'HTML') {
-      return null;
-    }
-
-    let nodeContent = node.ownerDocument.defaultView;
-    while (!(node instanceof Ci.nsIDOMHTMLBodyElement)) {
-      let style = nodeContent.getComputedStyle(node, null);
-
-      let overflow = [style.getPropertyValue('overflow'),
-                      style.getPropertyValue('overflow-x'),
-                      style.getPropertyValue('overflow-y')];
-
-      let rect = node.getBoundingClientRect();
-      let isAuto = (overflow.indexOf('auto') != -1 &&
-                   (rect.height < node.scrollHeight ||
-                    rect.width < node.scrollWidth));
-
-      let isScroll = (overflow.indexOf('scroll') != -1);
-
-      let isScrollableTextarea = (node.tagName == 'TEXTAREA' &&
-          (node.scrollHeight > node.clientHeight ||
-           node.scrollWidth > node.clientWidth ||
-           ('scrollLeftMax' in node && node.scrollLeftMax > 0) ||
-           ('scrollTopMax' in node && node.scrollTopMax > 0)));
-      if (isScroll || isAuto || isScrollableTextarea) {
-        return node;
-      }
-
-      node = node.parentNode;
-    }
-
-    if (nodeContent.scrollMaxX || nodeContent.scrollMaxY) {
-      return nodeContent;
-    }
-
-    if (nodeContent.frameElement) {
-      return this._findPannable(nodeContent.frameElement);
-    }
-
-    return null;
-  },
-
-  _generateCallback: function cp_generateCallback(root) {
-    let firstScroll = true;
-    let target;
-    let current;
-    let win, doc, htmlNode, bodyNode;
-
-    function doScroll(node, delta) {
-      if (node instanceof Ci.nsIDOMHTMLElement) {
-        return node.scrollByNoFlush(delta.x, delta.y);
-      } else if (node instanceof Ci.nsIDOMWindow) {
-        win = node;
-        doc = win.document;
-
-        // "overflow:hidden" on either the <html> or the <body> node should
-        // prevent the user from scrolling the root viewport.
-        if (doc instanceof Ci.nsIDOMHTMLDocument) {
-          htmlNode = doc.documentElement;
-          bodyNode = doc.body;
-          if (win.getComputedStyle(htmlNode, null).overflowX == "hidden" ||
-              win.getComputedStyle(bodyNode, null).overflowX == "hidden") {
-            delta.x = 0;
-          }
-          if (win.getComputedStyle(htmlNode, null).overflowY == "hidden" ||
-              win.getComputedStyle(bodyNode, null).overflowY == "hidden") {
-            delta.y = 0;
-          }
-        }
-        let oldX = node.scrollX;
-        let oldY = node.scrollY;
-        node.scrollBy(delta.x, delta.y);
-        return (node.scrollX != oldX || node.scrollY != oldY);
-      }
-      // If we get here, |node| isn't an HTML element and it's not a window,
-      // but findPannable apparently thought it was scrollable... What is it?
-      return false;
-    }
-
-    function targetParent(node) {
-      return node.parentNode || node.frameElement || null;
-    }
-
-    function scroll(delta) {
-      current = root;
-      firstScroll = true;
-      while (current) {
-        if (doScroll(current, delta)) {
-          firstScroll = false;
-          return true;
-        }
-
-        // TODO The current code looks for possible scrolling regions only if
-        // this is the first scroll action but this should be more dynamic.
-        if (!firstScroll) {
-          return false;
-        }
-
-        current = ContentPanningAPZDisabled._findPannable(targetParent(current));
-      }
-
-      // There is nothing scrollable here.
-      return false;
-    }
-    return scroll;
-  },
-
-  get _activationTimer() {
-    delete this._activationTimer;
-    return this._activationTimer = Cc["@mozilla.org/timer;1"]
-                                     .createInstance(Ci.nsITimer);
-  },
-
-  get _activationDelayMs() {
-    let delay = Services.prefs.getIntPref('ui.touch_activation.delay_ms');
-    delete this._activationDelayMs;
-    return this._activationDelayMs = delay;
-  },
-
-  get _domUtils() {
-    delete this._domUtils;
-    return this._domUtils = Cc['@mozilla.org/inspector/dom-utils;1']
-                              .getService(Ci.inIDOMUtils);
-  },
-
-  _resetActive: function cp_resetActive() {
-    let elt = this.pointerDownTarget || this.target;
-    let root = elt.ownerDocument || elt.document;
-    this._setActive(root.documentElement);
-  },
-
-  _setActive: function cp_setActive(elt) {
-    const kStateActive = 0x00000001;
-    this._domUtils.setContentState(elt, kStateActive);
-  },
-
-  _finishPanning: function() {
-    this.dragging = false;
-    delete this.primaryPointerId;
-    this._activationTimer.cancel();
-
-    // If there is a scroll action, let's do a manual kinetic panning action.
-    if (this.panning) {
-      KineticPanning.start(this);
-    }
-  },
-};
-
-// Min/max velocity of kinetic panning. This is in pixels/millisecond.
-const kMinVelocity = 0.2;
-const kMaxVelocity = 6;
-
-// Constants that affect the "friction" of the scroll pane.
-const kExponentialC = 1000;
-const kPolynomialC = 100 / 1000000;
-
-// How often do we change the position of the scroll pane?
-// Too often and panning may jerk near the end.
-// Too little and panning will be choppy. In milliseconds.
-const kUpdateInterval = 16;
-
-// The numbers of momentums to use for calculating the velocity of the pan.
-// Those are taken from the end of the action
-const kSamples = 5;
-
-const KineticPanning = {
-  _position: new Point(0, 0),
-  _velocity: new Point(0, 0),
-  _acceleration: new Point(0, 0),
-
-  get active() {
-    return this.target !== null;
-  },
-
-  target: null,
-  start: function kp_start(target) {
-    this.target = target;
-
-    // Calculate the initial velocity of the movement based on user input
-    let momentums = this.momentums;
-    let flick = momentums[momentums.length - 1].time - momentums[0].time < 300;
-
-    let distance = new Point(0, 0);
-    momentums.forEach(function(momentum) {
-      distance.add(momentum.dx, momentum.dy);
-    });
-
-    function clampFromZero(x, min, max) {
-      if (x >= 0)
-        return Math.max(min, Math.min(max, x));
-      return Math.min(-min, Math.max(-max, x));
-    }
-
-    let elapsed = momentums[momentums.length - 1].time - momentums[0].time;
-    let velocityX = clampFromZero(distance.x / elapsed, 0, kMaxVelocity);
-    let velocityY = clampFromZero(distance.y / elapsed, 0, kMaxVelocity);
-
-    let velocity = this._velocity;
-    if (flick) {
-      // Very fast pan action that does not generate a click are very often pan
-      // action. If this is a small gesture then it will not move the view a lot
-      // and so it will be above the minimun threshold and not generate any
-      // kinetic panning. This does not look on a device since this is often
-      // a real gesture, so let's lower the velocity threshold for such moves.
-      velocity.set(velocityX, velocityY);
-    } else {
-      velocity.set(Math.abs(velocityX) < kMinVelocity ? 0 : velocityX,
-                   Math.abs(velocityY) < kMinVelocity ? 0 : velocityY);
-    }
-    this.momentums = [];
-
-    // Set acceleration vector to opposite signs of velocity
-    function sign(x) {
-      return x ? (x > 0 ? 1 : -1) : 0;
-    }
-
-    this._acceleration.set(velocity.clone().map(sign).scale(-kPolynomialC));
-
-    // Reset the position
-    this._position.set(0, 0);
-
-    this._startAnimation();
-
-    this.target.onKineticBegin();
-  },
-
-  stop: function kp_stop() {
-    this.reset();
-
-    if (!this.target)
-      return;
-
-    this.target.onKineticEnd();
-    this.target = null;
-  },
-
-  reset: function kp_reset() {
-    this.momentums = [];
-    this.distance.set(0, 0);
-  },
-
-  momentums: [],
-  record: function kp_record(delta, timestamp) {
-    this.momentums.push({ 'time': this._getTime(timestamp),
-                          'dx' : delta.x, 'dy' : delta.y });
-
-    // We only need to keep kSamples in this.momentums.
-    if (this.momentums.length > kSamples) {
-      this.momentums.shift();
-    }
-
-    this.distance.add(delta.x, delta.y);
-  },
-
-  _getTime: function kp_getTime(time) {
-    // Touch events generated by the platform or hand-made are defined in
-    // microseconds instead of milliseconds. Bug 77992 will fix this at the
-    // platform level.
-    if (time > Date.now()) {
-      return Math.floor(time / 1000);
-    } else {
-      return time;
-    }
-  },
-
-  get threshold() {
-    let dpi = content.QueryInterface(Ci.nsIInterfaceRequestor)
-                     .getInterface(Ci.nsIDOMWindowUtils)
-                     .displayDPI;
-
-    let threshold = Services.prefs.getIntPref('ui.dragThresholdX') / 240 * dpi;
-
-    delete this.threshold;
-    return this.threshold = threshold;
-  },
-
-  distance: new Point(0, 0),
-  isPan: function cp_isPan() {
-    return (Math.abs(this.distance.x) > this.threshold ||
-            Math.abs(this.distance.y) > this.threshold);
-  },
-
-  _startAnimation: function kp_startAnimation() {
-    let c = kExponentialC;
-    function getNextPosition(position, v, a, t) {
-      // Important traits for this function:
-      //   p(t=0) is 0
-      //   p'(t=0) is v0
-      //
-      // We use exponential to get a smoother stop, but by itself exponential
-      // is too smooth at the end. Adding a polynomial with the appropriate
-      // weight helps to balance
-      position.set(v.x * Math.exp(-t / c) * -c + a.x * t * t + v.x * c,
-                   v.y * Math.exp(-t / c) * -c + a.y * t * t + v.y * c);
-    }
-
-    let startTime = content.mozAnimationStartTime;
-    let elapsedTime = 0, targetedTime = 0, averageTime = 0;
-
-    let velocity = this._velocity;
-    let acceleration = this._acceleration;
-
-    let position = this._position;
-    let nextPosition = new Point(0, 0);
-    let delta = new Point(0, 0);
-
-    let callback = (function(timestamp) {
-      if (!this.target)
-        return;
-
-      // To make animation end fast enough but to keep smoothness, average the
-      // ideal time frame (smooth animation) with the actual time lapse
-      // (end fast enough).
-      // Animation will never take longer than 2 times the ideal length of time.
-      elapsedTime = timestamp - startTime;
-      targetedTime += kUpdateInterval;
-      averageTime = (targetedTime + elapsedTime) / 2;
-
-      // Calculate new position.
-      getNextPosition(nextPosition, velocity, acceleration, averageTime);
-      delta.set(Math.round(nextPosition.x - position.x),
-                Math.round(nextPosition.y - position.y));
-
-      // Test to see if movement is finished for each component.
-      if (delta.x * acceleration.x > 0)
-        delta.x = position.x = velocity.x = acceleration.x = 0;
-
-      if (delta.y * acceleration.y > 0)
-        delta.y = position.y = velocity.y = acceleration.y = 0;
-
-      if (velocity.equals(0, 0) || delta.equals(0, 0)) {
-        this.stop();
-        return;
-      }
-
-      position.add(delta);
-      if (this.target.onKineticPan(delta.scale(-1))) {
-        this.stop();
-        return;
-      }
-
-      content.mozRequestAnimationFrame(callback);
-    }).bind(this);
-
-    content.mozRequestAnimationFrame(callback);
-  }
-};
--- a/dom/ipc/jar.mn
+++ b/dom/ipc/jar.mn
@@ -3,11 +3,10 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 toolkit.jar:
         content/global/test-ipc.xul (test.xul)
         content/global/remote-test-ipc.js (remote-test.js)
         content/global/BrowserElementChild.js (../browser-element/BrowserElementChild.js)
         content/global/BrowserElementChildPreload.js (../browser-element/BrowserElementChildPreload.js)
 *       content/global/BrowserElementPanning.js (../browser-element/BrowserElementPanning.js)
-*       content/global/BrowserElementPanningAPZDisabled.js (../browser-element/BrowserElementPanningAPZDisabled.js)
         content/global/preload.js (preload.js)
         content/global/post-fork-preload.js (post-fork-preload.js)
--- a/dom/ipc/preload.js
+++ b/dom/ipc/preload.js
@@ -86,23 +86,16 @@ const BrowserElementIsPreloaded = true;
 
   try {
     if (Services.prefs.getBoolPref("dom.mozInputMethod.enabled")) {
       Services.scriptloader.loadSubScript("chrome://global/content/forms.js", global);
     }
   } catch (e) {
   }
 
-  try {
-    if (Services.prefs.getBoolPref("layers.async-pan-zoom.enabled") === false) {
-      Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanningAPZDisabled.js", global);
-    }
-  } catch (e) {
-  }
-
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementPanning.js", global);
   Services.scriptloader.loadSubScript("chrome://global/content/BrowserElementChildPreload.js", global);
 
   Services.io.getProtocolHandler("app");
   Services.io.getProtocolHandler("default");
 
   docShell.isActive = false;
   docShell.createAboutBlankContentViewer(null);