merge with trunk
authorBenjamin Stover <bstover@mozilla.com>
Tue, 24 Aug 2010 11:39:14 -0700
changeset 66601 44c17562bf07a1acc26940e0b307eae674abf30e
parent 66483 87b0bb5d1ade67a7704d3ae4a215d813c8c82996 (current diff)
parent 66600 6fabb170df185524e4c9b7fe7b40eaa5b6901ed0 (diff)
child 66602 6555c6740f1c360a572cbe16db0c81f965751880
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
merge with trunk
mobile/app/mobile.js
mobile/chrome/content/AnimatedZoom.js
mobile/chrome/content/BrowserView.js
mobile/chrome/content/InputHandler.js
mobile/chrome/content/TileManager.js.in
mobile/chrome/content/bindings.xml
mobile/chrome/content/browser-ui.js
mobile/chrome/content/browser.js
mobile/chrome/content/browser.xul
mobile/chrome/content/content.js
mobile/chrome/content/tabs.xml
mobile/chrome/jar.mn
mobile/themes/core/browser.css
--- a/mobile/chrome/Makefile.in
+++ b/mobile/chrome/Makefile.in
@@ -47,19 +47,9 @@ DEFINES += -DAB_CD=$(MOZ_UI_LOCALE) \
            -DMOZ_APP_VERSION=$(MOZ_APP_VERSION) \
            $(NULL)
 
 
 ifdef ENABLE_TESTS
 DIRS += tests
 endif
 
-# Preprocess some JS files!
-TileManager.js: $(srcdir)/content/TileManager.js.in
-ifneq (,$(filter WINNT WINCE,$(OS_ARCH)))
-	cl -EP -C -nologo -I$(srcdir) $< > $@
-else
-	$(CC) -x c -C -E -P -I$(srcdir) $< > $@
-endif
-
 include $(topsrcdir)/config/rules.mk
-
-export:: TileManager.js
--- a/mobile/chrome/content/AnimatedZoom.js
+++ b/mobile/chrome/content/AnimatedZoom.js
@@ -44,16 +44,17 @@ let Ci = Components.interfaces;
 let Cu = Components.utils;
 
 /**
  * Responsible for zooming in to a given view rectangle
  * @param aBrowserView BrowserView instance
  * @param aZoomRect Optional. Zoom rectangle to be configured
  */
 function AnimatedZoom(aBrowserView) {
+  return;
   this.bv = aBrowserView;
 
   this.snapshot = AnimatedZoom.createCanvas();
   if (this.snapshot.pending_render)
     return;
 
   // Render a snapshot of the viewport contents around the visible rect
   let [w, h] = this.bv.getViewportDimensions();
@@ -102,16 +103,19 @@ AnimatedZoom.createCanvas = function(aRe
     canvas.height = Math.max(window.innerWidth, window.innerHeight) * 2;
     canvas.mozOpaque = true;
     this._canvas = canvas;
   }
   return this._canvas;
 };
 
 AnimatedZoom.prototype.setupCanvas = function() {
+{
+  return;
+
   // stop live rendering during zooming
   this.bv.pauseRendering();
 
   // hide ui elements to avoid undefined states after zoom
   Browser.hideTitlebar();
   Browser.hideSidebars();
 
   let clientVis = Browser.browserViewToClientRect(this.bv.getCriticalRect());
@@ -229,16 +233,17 @@ AnimatedZoom.prototype._callback = funct
     Util.dumpLn("Error while zooming. Please report error at:", e);
     this.finish();
     throw e;
   }
 };
 
 /** Stop animation, zoom to point, and clean up. */
 AnimatedZoom.prototype.finish = function() {
+  return;
   try {
     Elements.viewBuffer.style.display = "none";
 
     // resume live rendering
     this.bv.resumeRendering(true);
 
     // if we actually zoomed somewhere, clean up the UI to normal
     if (this.zoomRect)
--- a/mobile/chrome/content/BrowserView.js
+++ b/mobile/chrome/content/BrowserView.js
@@ -39,18 +39,16 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 let Ci = Components.interfaces;
 
 const kBrowserFormZoomLevelMin = 1.0;
 const kBrowserFormZoomLevelMax = 2.0;
 const kBrowserViewZoomLevelPrecision = 10000;
-const kBrowserViewPrefetchBeginIdleWait = 1;    // seconds
-const kBrowserViewPrefetchBeginIdleWaitLoading = 10;    // seconds
 
 /**
  * A BrowserView maintains state of the viewport (browser, zoom level,
  * dimensions) and the visible rectangle into the viewport, for every
  * browser it is given (cf setBrowser()).  In updates to the viewport state,
  * a BrowserView (using its TileManager) renders parts of the page quasi-
  * intelligently, with guarantees of having rendered and appended all of the
  * visible browser content (aka the "critical rectangle").
@@ -151,38 +149,16 @@ BrowserView.Util = {
   visibleRectToCriticalRect: function visibleRectToCriticalRect(visibleRect, browserViewportState) {
     return visibleRect.intersect(browserViewportState.viewportRect);
   },
 
   createBrowserViewportState: function createBrowserViewportState() {
     return new BrowserView.BrowserViewportState(new Rect(0, 0, 800, 800), 0, 0, 1);
   },
 
-  getViewportStateFromBrowser: function getViewportStateFromBrowser(browser) {
-    return browser.__BrowserView__vps;
-  },
-
-  getNewBatchOperationState: function getNewBatchOperationState() {
-    return {
-      viewportSizeChanged: false,
-      dirtyAll: false
-    };
-  },
-
-  initContainer: function initContainer(container, visibleRect) {
-    container.style.width = visibleRect.width  + 'px';
-    container.style.height = visibleRect.height + 'px';
-    container.style.overflow = '-moz-hidden-unscrollable';
-  },
-
-  resizeContainerToViewport: function resizeContainerToViewport(container, viewportRect) {
-    container.style.width = viewportRect.width  + 'px';
-    container.style.height = viewportRect.height + 'px';
-  },
-
   ensureMozScrolledAreaEvent: function ensureMozScrolledAreaEvent(aBrowser, aWidth, aHeight) {
     let message = {};
     message.target = aBrowser;
     message.name = "Browser:MozScrolledAreaChanged";
     message.json = { width: aWidth, height: aHeight };
 
     Browser._browserView.updateScrolledArea(message);
   }
@@ -190,50 +166,24 @@ BrowserView.Util = {
 
 BrowserView.prototype = {
 
   // -----------------------------------------------------------
   // Public instance methods
   //
 
   init: function init(container, visibleRectFactory) {
-    this._batchOps = [];
     this._container = container;
     this._browser = null;
     this._browserViewportState = null;
-    this._renderMode = 0;
-    this._offscreenDepth = 0;
-
-    let cacheSize = Services.prefs.getIntPref("tile.cache.size");
-
-    this._tileManager = new TileManager(this._appendTile, this._removeTile, this, cacheSize, container);
     this._visibleRectFactory = visibleRectFactory;
-
-    this._idleServiceObserver = new BrowserView.IdleServiceObserver(this);
-    this._idleService = Cc["@mozilla.org/widget/idleservice;1"].getService(Ci.nsIIdleService);
-    this._idleService.addIdleObserver(this._idleServiceObserver, kBrowserViewPrefetchBeginIdleWait);
-    this._idleServiceWait = kBrowserViewPrefetchBeginIdleWait;
-
-    let self = this;
     messageManager.addMessageListener("Browser:MozScrolledAreaChanged", this);
-    messageManager.addMessageListener("Browser:MozAfterPaint", this);
-    messageManager.addMessageListener("Browser:PageScroll", this);
   },
 
   uninit: function uninit() {
-    this.setBrowser(null, null);
-    this._idleService.removeIdleObserver(this._idleServiceObserver, this._idleServiceWait);
-  },
-
-  /** When aggressive, spend more time rendering tiles. */
-  setAggressive: function setAggressive(aggro) {
-    let wait = aggro ? kBrowserViewPrefetchBeginIdleWait : kBrowserViewPrefetchBeginIdleWaitLoading;
-    this._idleService.removeIdleObserver(this._idleServiceObserver, this._idleServiceWait);
-    this._idleService.addIdleObserver(this._idleServiceObserver, wait);
-    this._idleServiceWait = wait;
   },
 
   getVisibleRect: function getVisibleRect() {
     return this._visibleRectFactory();
   },
 
   getCriticalRect: function getCriticalRect() {
     let bvs = this._browserViewportState;
@@ -248,28 +198,30 @@ BrowserView.prototype = {
     let bvs = this._browserViewportState;
     if (!bvs)
       throw "Cannot get viewport dimensions when no browser is set";
 
     return [bvs.viewportRect.right, bvs.viewportRect.bottom];
   },
 
   setZoomLevel: function setZoomLevel(zoomLevel) {
+    return;
+
     let bvs = this._browserViewportState;
     if (!bvs)
       return;
 
     let newZoomLevel = this.clampZoomLevel(zoomLevel);
     if (newZoomLevel != bvs.zoomLevel) {
       let browserW = this.viewportToBrowser(bvs.viewportRect.right);
       let browserH = this.viewportToBrowser(bvs.viewportRect.bottom);
       bvs.zoomLevel = newZoomLevel; // side-effect: now scale factor in transformations is newZoomLevel
       bvs.viewportRect.right  = this.browserToViewport(browserW);
       bvs.viewportRect.bottom = this.browserToViewport(browserH);
-      this._viewportChanged(true, true);
+      this._viewportChanged();
 
       if (this._browser) {
         let event = document.createEvent("Events");
         event.initEvent("ZoomChanged", true, false);
         this._browser.dispatchEvent(event);
       }
     }
   },
@@ -295,218 +247,55 @@ BrowserView.prototype = {
 
       bounded = Math.max(bounded, this.getPageZoomLevel());
     }
 
     let rounded = Math.round(bounded * kBrowserViewZoomLevelPrecision) / kBrowserViewZoomLevelPrecision;
     return rounded || 1.0;
   },
 
-  beginOffscreenOperation: function beginOffscreenOperation(rect) {
-    if (this._offscreenDepth == 0) {
-      let vis = this.getVisibleRect();
-      rect = rect || vis;
-      let zoomRatio = vis.width / rect.width;
-      let viewBuffer = Elements.viewBuffer;
-      viewBuffer.width = vis.width;
-      viewBuffer.height = vis.height;
-
-      this._tileManager.renderRectToCanvas(rect, viewBuffer, zoomRatio, zoomRatio, false);
-      viewBuffer.style.display = "block";
-      window.QueryInterface(Ci.nsIInterfaceRequestor)
-        .getInterface(Ci.nsIDOMWindowUtils).processUpdates();
-      this.pauseRendering();
-    }
-    this._offscreenDepth++;
-  },
-
-  commitOffscreenOperation: function commitOffscreenOperation() {
-    this._offscreenDepth--;
-    if (this._offscreenDepth == 0) {
-      this.resumeRendering();
-      Elements.viewBuffer.style.display = "none";
-    }
-  },
-
-  beginBatchOperation: function beginBatchOperation() {
-    this._batchOps.push(BrowserView.Util.getNewBatchOperationState());
-    this.pauseRendering();
-  },
-
-  commitBatchOperation: function commitBatchOperation() {
-    let bops = this._batchOps;
-    if (bops.length == 0)
-      return;
-
-    let opState = bops.pop();
-
-    // XXX If stack is not empty, this just assigns opState variables to the next one
-    // on top. Why then have a stack of these booleans?
-    this._viewportChanged(opState.viewportSizeChanged, opState.dirtyAll);
-    this.resumeRendering();
-  },
-
-  discardBatchOperation: function discardBatchOperation() {
-    let bops = this._batchOps;
-    bops.pop();
-    this.resumeRendering();
-  },
-
-  discardAllBatchOperations: function discardAllBatchOperations() {
-    let bops = this._batchOps;
-    while (bops.length > 0)
-      this.discardBatchOperation();
-  },
-
-  /**
-   * Calls to this function need to be one-to-one with calls to
-   * resumeRendering()
-   */
-  pauseRendering: function pauseRendering() {
-    this._renderMode++;
-    if (this._renderMode == 1 && this._browser) {
-      let event = document.createEvent("Events");
-      event.initEvent("RenderStateChanged", true, false);
-      event.isRendering = false;
-      this._browser.dispatchEvent(event);
-    }
-  },
-
-  /**
-   * Calls to this function need to be one-to-one with calls to
-   * pauseRendering()
-   */
-  resumeRendering: function resumeRendering(renderNow) {
-    if (this._renderMode > 0)
-      this._renderMode--;
-
-    if (renderNow || this._renderMode == 0)
-      this.renderNow();
-
-    if (this._renderMode == 0 && this._browser) {
-      let event = document.createEvent("Events");
-      event.initEvent("RenderStateChanged", true, false);
-      event.isRendering = true;
-      this._browser.dispatchEvent(event);
-    }
-  },
-
-  /**
-   * Called while rendering is paused to allow update of critical area
-   */
-  renderNow: function renderNow() {
-    this._tileManager.criticalRectPaint();
-  },
-
-  isRendering: function isRendering() {
-    return (this._renderMode == 0);
-  },
-
-  onAfterVisibleMove: function onAfterVisibleMove() {
-    let vs = this._browserViewportState;
-    let vr = this.getVisibleRect();
-
-    vs.visibleX = vr.left;
-    vs.visibleY = vr.top;
-
-    let cr = BrowserView.Util.visibleRectToCriticalRect(vr, vs);
-
-    this._tileManager.criticalMove(cr, this.isRendering());
-  },
-
   /**
    * Swap out the current browser and browser viewport state with a new pair.
    */
   setBrowser: function setBrowser(browser, browserViewportState) {
     if (browser && !browserViewportState) {
       throw "Cannot set non-null browser with null BrowserViewportState";
     }
 
     let oldBrowser = this._browser;
     let browserChanged = (oldBrowser !== browser);
 
     if (oldBrowser) {
       oldBrowser.setAttribute("type", "content");
+      oldBrowser.setAttribute("style", "display: none;");
       oldBrowser.messageManager.sendAsyncMessage("Browser:Blur", {});
     }
 
     this._browser = browser;
     this._browserViewportState = browserViewportState;
 
     if (browser) {
       browser.setAttribute("type", "content-primary");
+      browser.setAttribute("style", "display: block;");
       browser.messageManager.sendAsyncMessage("Browser:Focus", {});
-
-      this.beginBatchOperation();
-
-      if (browserChanged)
-        this._viewportChanged(true, true);
-
-      this.commitBatchOperation();
     }
   },
 
   getBrowser: function getBrowser() {
     return this._browser;
   },
 
   receiveMessage: function receiveMessage(aMessage) {
     switch (aMessage.name) {
-      case "Browser:MozAfterPaint":
-        this.updateDirtyTiles(aMessage);
-        break;
-      case "Browser:PageScroll":
-        this.updatePageScroll(aMessage);
-        break;
       case "Browser:MozScrolledAreaChanged":
         this.updateScrolledArea(aMessage);
         break;
     }
   },
 
-  updateDirtyTiles: function updateDirtyTiles(aMessage) {
-    let browser = aMessage.target;
-    if (browser != this._browser)
-      return;
-    
-    let rects = aMessage.json.rects;
-
-    let tm = this._tileManager;
-    let vs = this._browserViewportState;
-
-    let dirtyRects = [];
-    // loop backwards to avoid xpconnect penalty for .length
-    for (let i = rects.length - 1; i >= 0; --i) {
-      let r = Rect.fromRect(rects[i]);
-      r = this.browserToViewportRect(r);
-      r.expandToIntegers();
-
-      r.restrictTo(vs.viewportRect);
-      if (!r.isEmpty())
-        dirtyRects.push(r);
-    }
-
-    tm.dirtyRects(dirtyRects, this.isRendering(), true);
-  },
-
-  /** If browser scrolls, pan content to new scroll area. */
-  updatePageScroll: function updatePageScroll(aMessage) {
-    if (aMessage.target != this._browser || this._ignorePageScroll)
-      return;
-
-    // XXX shouldn't really make calls to Browser
-    let json = aMessage.json;
-    Browser.scrollContentToBrowser(json.scrollX, json.scrollY);
-  },
-
-  _ignorePageScroll: false,
-  ignorePageScroll: function ignorePageScroll(aIgnoreScroll) {
-    this._ignorePageScroll = aIgnoreScroll;
-  },
-
   updateScrolledArea: function updateScrolledArea(aMessage) {
     let browser = aMessage.target;
     let tab = Browser.getTabForBrowser(browser);
     if (!browser || !tab)
       return;
 
     let json = aMessage.json;
     let bvs = tab.browserViewportState;
@@ -514,26 +303,18 @@ BrowserView.prototype = {
     let vis = this.getVisibleRect();
     let viewport = bvs.viewportRect;
     let oldRight = viewport.right;
     let oldBottom = viewport.bottom;
     viewport.right  = bvs.zoomLevel * json.width;
     viewport.bottom = bvs.zoomLevel * json.height;
 
     if (browser == this._browser) {
-      // Page has now loaded enough to allow zooming.
-      let sizeChanged = oldRight != viewport.right || oldBottom != viewport.bottom;
-      this._viewportChanged(sizeChanged, false);
+      this._viewportChanged();
       this.updateDefaultZoom();
-      if (vis.right > viewport.right || vis.bottom > viewport.bottom) {
-        // Content has shrunk outside of the visible rectangle.
-        // XXX for some reason scroller doesn't know it is outside its bounds
-        Browser.contentScrollboxScroller.scrollBy(0, 0);
-        this.onAfterVisibleMove();
-      }
     }
   },
 
   /** Call when default zoom level may change. */
   updateDefaultZoom: function updateDefaultZoom() {
     let bvs = this._browserViewportState;
     if (!bvs)
       return false;
@@ -597,83 +378,45 @@ BrowserView.prototype = {
 
   get allowZoom() {
     let bvs = this._browserViewportState;
     if (!bvs || !bvs.metaData)
       return true;
     return bvs.metaData.allowZoom;
   },
 
-  //
-  // MozAfterPaint events do not guarantee to inform us of all
-  // invalidated paints (See
-  // https://developer.mozilla.org/en/Gecko-Specific_DOM_Events#Important_notes
-  // for details on what the event *does* guarantee).  This is only an
-  // issue when the same current <browser> is used to navigate to a
-  // new page.  Unless a zoom was issued during the page transition
-  // (e.g. a call to setZoomLevel() or something of that nature), we
-  // aren't guaranteed that we've actually invalidated the entire
-  // page.  We don't want to leave bits of the previous page in the
-  // view of the new one, so this method exists as a way for Browser
-  // to inform us that the page is changing, and that we really ought
-  // to invalidate everything.  Ideally, we wouldn't have to rely on
-  // this being called, and we would get proper invalidates for the
-  // whole page no matter what is or is not visible.
-  //
-  // Note that calling this function isn't necessary in almost all
-  // cases, but should be done for correctness.  Most of the time, one
-  // of the following two conditions is satisfied.  Either
-  //
-  //   (1) Pages have different widths so the Browser calls a
-  //       updateDefaultZoom() which forces a dirtyAll, or
-  //   (2) MozAfterPaint does indeed inform us of dirtyRects covering
-  //       the entire page (everything that could possibly become
-  //       visible).
-  /**
-   * Invalidates the entire page by throwing away any cached graphical
-   * portions of the view and refusing to allow a updateDefaultZoom() until
-   * the next explicit update of the viewport dimensions.
-   *
-   * This method should be called when the <browser> last set by
-   * setBrowser() is about to navigate to a new page.
-   */
-  invalidateEntireView: function invalidateEntireView() {
-    if (this._browserViewportState) {
-      this._viewportChanged(false, true);
-    }
-  },
-
   /**
    * Render a rectangle within the browser viewport to the destination canvas
    * under the given scale.
    *
    * @param destCanvas The destination canvas into which the image is rendered.
    * @param destWidth Destination width
    * @param destHeight Destination height
    * @param srcRect [optional] The source rectangle in BrowserView coordinates.
    * This defaults to the visible rect rooted at the x,y of the critical rect.
    */
   renderToCanvas: function renderToCanvas(destCanvas, destWidth, destHeight, srcRect) {
+    return;
+
     let bvs = this._browserViewportState;
     if (!bvs) {
       throw "Browser viewport state null in call to renderToCanvas (probably no browser set on BrowserView).";
     }
 
     if (!srcRect) {
       let vr = this.getVisibleRect();
       vr.x = bvs.viewportRect.left;
       vr.y = bvs.viewportRect.top;
       srcRect = vr;
     }
 
     let scalex = (destWidth / srcRect.width) || 1;
     let scaley = (destHeight / srcRect.height) || 1;
 
     srcRect.restrictTo(bvs.viewportRect);
-    this._tileManager.renderRectToCanvas(srcRect, destCanvas, scalex, scaley);
   },
 
   viewportToBrowser: function viewportToBrowser(x) {
     let bvs = this._browserViewportState;
     if (!bvs)
       throw "No browser is set";
 
     return x / bvs.zoomLevel;
@@ -697,98 +440,20 @@ BrowserView.prototype = {
     return rect.scale(f, f);
   },
 
   browserToViewportCanvasContext: function browserToViewportCanvasContext(ctx) {
     let f = this.browserToViewport(1.0);
     ctx.scale(f, f);
   },
 
-  forceContainerResize: function forceContainerResize() {
-    let bvs = this._browserViewportState;
-    if (bvs)
-      BrowserView.Util.resizeContainerToViewport(this._container, bvs.viewportRect);
-  },
-
-  /**
-   * Force any pending viewport changes to occur.  Batch operations will still be on the
-   * stack so commitBatchOperation is still necessary afterwards.
-   */
-  forceViewportChange: function forceViewportChange() {
-    let bops = this._batchOps;
-    if (bops.length > 0) {
-      let opState = bops[bops.length - 1];
-      this._applyViewportChanges(opState.viewportSizeChanged, opState.dirtyAll);
-      opState.viewportSizeChanged = false;
-      opState.dirtyAll = false;
-    }
-  },
-
-  // -----------------------------------------------------------
-  // Private instance methods
-  //
-
-  _viewportChanged: function _viewportChanged(viewportSizeChanged, dirtyAll) {
-    let bops = this._batchOps;
-    if (bops.length > 0) {
-      let opState = bops[bops.length - 1];
-
-      if (viewportSizeChanged)
-        opState.viewportSizeChanged = viewportSizeChanged;
-      if (dirtyAll)
-        opState.dirtyAll = dirtyAll;
-
-      return;
-    }
-
-    this._applyViewportChanges(viewportSizeChanged, dirtyAll);
+  _viewportChanged: function() {
+    getBrowser().style.MozTransformOrigin = "left top";
+    Browser.contentScrollboxScroller.updateTransition();
   },
-
-  _applyViewportChanges: function _applyViewportChanges(viewportSizeChanged, dirtyAll) {
-    let bvs = this._browserViewportState;
-    if (bvs) {
-      BrowserView.Util.resizeContainerToViewport(this._container, bvs.viewportRect);
-
-      let vr = this.getVisibleRect();
-      this._tileManager.viewportChangeHandler(bvs.viewportRect,
-                                              BrowserView.Util.visibleRectToCriticalRect(vr, bvs),
-                                              viewportSizeChanged,
-                                              dirtyAll);
-
-      let rects = vr.subtract(bvs.viewportRect);
-      this._tileManager.clearRects(rects);
-    }
-  },
-
-  _appendTile: function _appendTile(tile) {
-    let canvas = tile.getContentImage();
-
-    //canvas.style.position = "absolute";
-    //canvas.style.left = tile.x + "px";
-    //canvas.style.top  = tile.y + "px";
-
-    // XXX The above causes a trace abort, and this function is called back in the tight
-    // render-heavy loop in TileManager, so even though what we do below isn't so proper
-    // and takes longer on the Platform/C++ emd, it's better than causing a trace abort
-    // in our tight loop.
-    //
-    // But this also overwrites some style already set on the canvas in Tile constructor.
-    // Hack fail...
-    //
-    canvas.setAttribute("style", "display: none; position: absolute; left: " + tile.boundRect.left + "px; " + "top: " + tile.boundRect.top + "px;");
-
-    this._container.appendChild(canvas);
-  },
-
-  _removeTile: function _removeTile(tile) {
-    let canvas = tile.getContentImage();
-
-    this._container.removeChild(canvas);
-  }
-
 };
 
 
 // -----------------------------------------------------------
 // Helper structures
 //
 
 /**
@@ -817,45 +482,8 @@ BrowserView.BrowserViewportState.prototy
                  "\tvisibleX="     + this.visibleX,
                  "\tvisibleY="     + this.visibleY,
                  "\tzoomLevel="    + this.zoomLevel];
 
     return "[BrowserViewportState] {\n" + props.join(",\n") + "\n}";
   }
 
 };
-
-
-/**
- * nsIObserver that implements a callback for the nsIIdleService, which starts
- * and stops the BrowserView's TileManager's prefetch crawl according to user
- * idleness.
- */
-BrowserView.IdleServiceObserver = function IdleServiceObserver(browserView) {
-  this._browserView = browserView;
-  this._idle = false;
-  this._paused = false;
-};
-
-BrowserView.IdleServiceObserver.prototype = {
-  /** No matter what idle is, make sure prefetching is not active. */
-  pause: function pause() {
-    this._paused = true;
-    this._updateTileManager();
-  },
-
-  /** Prefetch tiles in idle mode. */
-  resume: function resume() {
-    this._paused = false;
-    this._updateTileManager();
-  },
-
-  /** Idle event handler. */
-  observe: function observe(aSubject, aTopic, aUserIdleTime) {
-    this._idle = (aTopic == "idle") ? true : false;
-    this._updateTileManager();
-  },
-
-  _updateTileManager: function _updateTileManager() {
-    let bv = this._browserView;
-    bv._tileManager.setPrefetch(this._idle && !this._paused);
-  }
-};
--- a/mobile/chrome/content/InputHandler.js
+++ b/mobile/chrome/content/InputHandler.js
@@ -228,20 +228,16 @@ InputHandler.prototype = {
 
   /**
    * InputHandler's DOM event handler.
    */
   handleEvent: function handleEvent(aEvent) {
     if (this._ignoreEvents)
       return;
 
-    /* ignore all events that belong to other windows or documents (e.g. content events) */
-    if (aEvent.view != window)
-      return;
-
     if (this._suppressNextClick && aEvent.type == "click") {
       this._suppressNextClick = false;
       aEvent.stopPropagation();
       aEvent.preventDefault();
       return;
     }
 
     aEvent.time = Date.now();
@@ -345,16 +341,26 @@ function MouseModule(owner, browserViewC
 }
 
 
 MouseModule.prototype = {
   handleEvent: function handleEvent(aEvent) {
     if (aEvent.button !== 0 && aEvent.type != "contextmenu")
       return;
 
+    try {
+      if (aEvent.view != window) {
+        // XXX we'd really like to do this to stop dragging code, but at least in
+        // non-e10s this is a problem.  Since we catch the simulated mouseup and
+        // mousedown events, we eat up the ones we just generated.
+        // evt.stopPropagation();
+        // evt.preventDefault();
+      }
+    } catch (e) {};
+
     switch (aEvent.type) {
       case "mousedown":
         this._onMouseDown(aEvent);
         break;
       case "mousemove":
         this._onMouseMove(aEvent);
         break;
       case "mouseup":
@@ -421,53 +427,59 @@ MouseModule.prototype = {
       // Somehow a mouse up was missed.
       let [sX, sY] = dragData.panPosition();
       this._doDragStop(sX, sY, !dragData.isPan());
     }
     dragData.reset();
 
     // walk up the DOM tree in search of nearest scrollable ancestor.  nulls are
     // returned if none found.
+    let target = (aEvent.view == window) ? aEvent.target : getBrowser();
     let [targetScrollbox, targetScrollInterface]
-      = this.getScrollboxFromElement(aEvent.target);
+      = this.getScrollboxFromElement(target);
+    let targetDragger = targetScrollbox ? targetScrollbox.customDragger : null;
+    if (!targetDragger && targetScrollInterface)
+      targetDragger = this._defaultDragger;
 
     // stop kinetic panning if targetScrollbox has changed
-    let oldInterface = this._targetScrollInterface;
-    if (this._kinetic.isActive() && targetScrollInterface != oldInterface)
+    let oldDragger = this._dragger;
+    if (this._kinetic.isActive() && targetDragger != oldDragger)
       this._kinetic.end();
 
-    let targetClicker = this.getClickerFromElement(aEvent.target);
+    // If the target is not part of the chrome UI, assume it comes from the current browser element.
+    let targetClicker = this.getClickerFromElement(target);
 
     this._targetScrollInterface = targetScrollInterface;
-    this._dragger = (targetScrollInterface) ? (targetScrollbox.customDragger || this._defaultDragger)
-                                            : null;
+    this._dragger = targetDragger;
     this._clicker = (targetClicker) ? targetClicker.customClicker : null;
 
     if (this._clicker)
       this._clicker.mouseDown(aEvent.clientX, aEvent.clientY);
 
-    if (targetScrollInterface && this._dragger.isDraggable(targetScrollbox, targetScrollInterface))
+    let draggable = this._dragger ? this._dragger.isDraggable(targetScrollbox, targetScrollInterface) : {};
+    if (this._dragger && (draggable.xDraggable || draggable.yDraggable))
       this._doDragStart(aEvent);
+    else
+      this._dragger = null;
 
     if (this._targetIsContent(aEvent)) {
       this._recordEvent(aEvent);
+      aEvent.stopPropagation();
+      aEvent.preventDefault();
     }
     else {
       if (this._clickTimeout) {
         // cancel all pending content clicks
         window.clearTimeout(this._clickTimeout);
         this._cleanClickBuffer();
       }
 
-      if (targetScrollInterface) {
+      if (this._dragger) {
         // do not allow axis locking if panning is only possible in one direction
-        let cX = {}, cY = {};
-        targetScrollInterface.getScrolledSize(cX, cY);
-        let rect = targetScrollbox.getBoundingClientRect();
-        dragData.locked = ((cX.value > rect.width) != (cY.value > rect.height));
+        dragData.locked = !draggable.xDraggable || !draggable.yDraggable;
       }
     }
   },
 
   /**
    * Handle a mouseup by swallowing the event (just as we did the mousedown) as
    * well as the possible DOM click event that follows, making one last drag
    * (which, do note, might just be the beginning of a kinetic drag that will
@@ -481,16 +493,18 @@ MouseModule.prototype = {
     let oldIsPan = dragData.isPan();
     if (dragData.dragging) {
       dragData.setDragPosition(aEvent.screenX, aEvent.screenY);
       let [sX, sY] = dragData.panPosition();
       this._doDragStop(sX, sY, !dragData.isPan());
     }
 
     if (this._targetIsContent(aEvent)) {
+      aEvent.stopPropagation();
+      aEvent.preventDefault();
       // User possibly clicked on something in content
       this._recordEvent(aEvent);
       let commitToClicker = this._clicker && dragData.isClick() && (this._downUpEvents.length > 1);
       if (commitToClicker)
         // commit this click to the doubleclick timewait buffer
         this._commitAnotherClick();
       else
         // clean the click buffer ourselves, since there was no clicker
@@ -542,26 +556,17 @@ MouseModule.prototype = {
       }
     }
   },
 
   /**
    * Check if the event concern the browser content
    */
   _targetIsContent: function _targetIsContent(aEvent) {
-    let target = aEvent.target;
-    while (target) {
-      if (target === window)
-        return false;
-      if (target === this._browserViewContainer)
-        return true;
-
-      target = target.parentNode;
-    }
-    return false;
+    return aEvent.view !== window || aEvent.target.tagName == "browser";
   },
 
   /**
    * Inform our dragger of a dragStart.
    */
   _doDragStart: function _doDragStart(event) {
     let dragData = this._dragData;
     dragData.setDragStart(event.screenX, event.screenY);
@@ -705,17 +710,17 @@ MouseModule.prototype = {
    * element that provides no customDragger.  Simply performs the expected
    * regular scrollBy calls on the scroller.
    */
   _defaultDragger: {
     isDraggable: function isDraggable(target, scroller) {
       let sX = {}, sY = {};
       scroller.getScrolledSize(sX, sY);
       let rect = target.getBoundingClientRect();
-      return sX.value > rect.width || sY.value > rect.height;
+      return { xDraggable: sX.value > rect.width, yDraggable: sY.value > rect.height };
     },
 
     dragStart: function dragStart(cx, cy, target, scroller) {},
 
     dragStop : function dragStop(dx, dy, scroller) {
       return this.dragMove(dx, dy, scroller);
     },
 
@@ -770,16 +775,19 @@ MouseModule.prototype = {
         } else if (elem.boxObject) {
           let qi = (elem._cachedSBO) ? elem._cachedSBO
                                      : elem.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
           if (qi) {
             scrollbox = elem;
             scrollbox._cachedSBO = qinterface = qi;
             break;
           }
+        } else if (elem.customDragger) {
+          scrollbox = elem;
+          break;
         }
       } catch (e) { /* we aren't here to deal with your exceptions, we'll just keep
                        traversing until we find something more well-behaved, as we
                        prefer default behaviour to whiny scrollers. */ }
       prev = elem;
     }
     return [scrollbox, qinterface, prev];
   },
@@ -1288,17 +1296,17 @@ GestureModule.prototype = {
     // start gesture if it's not taking place already, or over a XUL element
     if (this._pinchZoom || (aEvent.target instanceof XULElement) || !bv.allowZoom)
       return;
 
     // grab events during pinch
     this._owner.grab(this);
 
     // hide element highlight
-    document.getElementById("tile-container").customClicker.panBegin();
+    //document.getElementById("tile-container").customClicker.panBegin();
 
     // create the AnimatedZoom object for fast arbitrary zooming
     this._pinchZoom = new AnimatedZoom(bv);
 
     // start from current zoom level
     this._pinchZoomLevel = bv.getZoomLevel();
     this._pinchDelta = 0;
     this._ignoreNextUpdate = true; // first update gives useless, huge delta
deleted file mode 100644
--- a/mobile/chrome/content/TileManager.js.in
+++ /dev/null
@@ -1,1044 +0,0 @@
-// -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
-/*
- * ***** BEGIN LICENSE BLOCK *****
- * Version: MPL 1.1/GPL 2.0/LGPL 2.1
- *
- * The contents of this file are subject to the Mozilla Public License Version
- * 1.1 (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- * http://www.mozilla.org/MPL/
- *
- * Software distributed under the License is distributed on an "AS IS" basis,
- * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
- * for the specific language governing rights and limitations under the
- * License.
- *
- * The Original Code is Mozilla Mobile Browser.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Corporation.
- * Portions created by the Initial Developer are Copyright (C) 2009
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Roy Frostig <rfrostig@mozilla.com>
- *   Stuart Parmenter <stuart@mozilla.com>
- *
- * Alternatively, the contents of this file may be used under the terms of
- * either the GNU General Public License Version 2 or later (the "GPL"), or
- * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
- * in which case the provisions of the GPL or the LGPL are applicable instead
- * of those above. If you wish to allow use of your version of this file only
- * under the terms of either the GPL or the LGPL, and not to allow others to
- * use your version of this file under the terms of the MPL, indicate your
- * decision by deleting the provisions above and replace them with the notice
- * and other provisions required by the GPL or the LGPL. If you do not delete
- * the provisions above, a recipient may use your version of this file under
- * the terms of any one of the MPL, the GPL or the LGPL.
- *
- * ***** END LICENSE BLOCK ***** */
-
-#define BEGIN_FOREACH_IN_RECT(rect, tilecache, tile)                           \
-  {                                                                            \
-    let __starti = (rect).left  >> kTileExponentWidth;                         \
-    let __endi   = (rect).right >> kTileExponentWidth;                         \
-    let __startj = (rect).top    >> kTileExponentHeight;                       \
-    let __endj   = (rect).bottom >> kTileExponentHeight;                       \
-                                                                               \
-    let tile = null;                                                           \
-    let __i, __j;                                                              \
-    for (__j = __startj; __j <= __endj; ++__j) {                               \
-      for (__i = __starti; __i <= __endi; ++__i) {                             \
-        tile = (tilecache).getTile(__i, __j, false, null);                     \
-        if (tile) {
-
-#define END_FOREACH_IN_RECT                                                    \
-        }                                                                      \
-      }                                                                        \
-    }                                                                          \
-  }
-
-#define BEGIN_FORCREATE_IN_RECT(rect, tilecache, tile)                         \
-  {                                                                            \
-    let __starti = (rect).left  >> kTileExponentWidth;                         \
-    let __endi   = (rect).right >> kTileExponentWidth;                         \
-    let __startj = (rect).top    >> kTileExponentHeight;                       \
-    let __endj   = (rect).bottom >> kTileExponentHeight;                       \
-                                                                               \
-    let tile = null;                                                           \
-    let __i, __j;                                                              \
-    for (__j = __startj; __j <= __endj; ++__j) {                               \
-      for (__i = __starti; __i <= __endi; ++__i) {                             \
-        tile = (tilecache).getTile(__i, __j, true, null);                      \
-        if (tile) {                                                            \
-
-#define END_FORCREATE_IN_RECT                                                  \
-        }                                                                      \
-      }                                                                        \
-    }                                                                          \
-  }
-
-#define FOREACH_IN_RECT(rect, tilecache, fn, thisObj)                          \
-  BEGIN_FOREACH_IN_RECT(rect, tilecache, tile)                                 \
-  (fn).call((thisObj), tile);                                                  \
-  END_FOREACH_IN_RECT
-
-#define FORCREATE_IN_RECT(rect, tilecache, fn, thisObj)                        \
-  BEGIN_FORCREATE_IN_RECT(rect, tilecache, tile)                               \
-  (fn).call((thisObj), tile);                                                  \
-  END_FORCREATE_IN_RECT
-
-
-const kXHTMLNamespaceURI  = "http://www.w3.org/1999/xhtml";
-
-// base-2 exponent for width, height of a single tile.
-const kTileExponentWidth  = 9;
-const kTileExponentHeight = 9;
-const kTileWidth  = Math.pow(2, kTileExponentWidth);   // 2^9 = 512
-const kTileHeight = Math.pow(2, kTileExponentHeight);  // 2^9 = 512
-const kTileCrawlTimeCap = 100;    // millis
-const kTileCrawlComeAgain = 0;    // millis
-
-/**
- * The Tile Manager!
- *
- * @param appendTile The function the tile manager should call in order to
- * "display" a tile (e.g. append it to the DOM).  The argument to this
- * function is a TileManager.Tile object.
- * @param removeTile The function the tile manager should call in order to
- * "undisplay" a tile (e.g. remove it from the DOM).  The argument to this
- * function is a TileManager.Tile object.
- */
-function TileManager(appendTile, removeTile, browserView, cacheSize, parentNode) {
-  /* backref to the BrowserView object that owns us */
-  this._browserView = browserView;
-
-  /* callbacks to append / remove a tile to / from the parent */
-  this._appendTile = appendTile;
-  this._removeTile = removeTile;
-
-  /* tile cache holds tile objects and pools them under a given capacity */
-  let self = this;
-
-  function onBeforeDetach(tile) {
-    // Tile is being reassigned or discarded.
-    self._hideTile(tile);
-  }
-
-  function onCreate(tile) {
-    // New tile was just made
-    tile.getContentImage().setAttribute("style", "display: none");
-    self._appendTileSafe(tile);
-  }
-
-  this._tileCache = new TileManager.TileCache(onBeforeDetach, onCreate, -1, -1, cacheSize);
-
-  /* Rectangle within the viewport that is visible to the user.  It is "critical"
-   * in the sense that it must be rendered as soon as it becomes dirty, and tiles
-   * within this rectangle should not be evicted for use elsewhere. */
-  this._criticalRect = new Rect(0, 0, 0, 0);
-
-  /* timeout of the non-visible-tiles-crawler to cache renders from the browser */
-  this._idleTileCrawlerTimeout = 0;
-
-  /* object that keeps state on our current prefetch crawl */
-  this._crawler = new TileManager.CrawlIterator(this._tileCache, new Rect(0, 0, 0, 0));
-
-  /* remember if critical rect was changed so that we only do hard work one time */
-  this._lastCriticalRect = new Rect(0, 0, 0, 0);
-
-  /* if true, fetch offscreen dirty tiles in the "background" */
-  this._prefetch = false;
-
-  /* create one Image of the checkerboard to be reused */
-  this._checkerboard = new Image();
-  this._checkerboard.src = "chrome://browser/content/checkerboard.png";
-
-  parentNode.addEventListener("MozAsyncCanvasRender", this, false);
-}
-
-TileManager.prototype = {
-
-  /**
-   * Entry point by which the BrowserView informs of changes to the viewport or
-   * critical rect.
-   */
-  viewportChangeHandler: function viewportChangeHandler(viewportRect,
-                                                        criticalRect,
-                                                        boundsSizeChanged,
-                                                        dirtyAll) {
-    let tc = this._tileCache;
-
-    let iBoundOld = tc.iBound;
-    let jBoundOld = tc.jBound;
-    let iBound = tc.iBound = Math.ceil(viewportRect.right / kTileWidth) - 1;
-    let jBound = tc.jBound = Math.ceil(viewportRect.bottom / kTileHeight) - 1;
-
-    if (criticalRect.isEmpty() || !criticalRect.equals(this._criticalRect)) {
-      this.criticalMove(criticalRect, !(dirtyAll || boundsSizeChanged));
-    } else {
-      // The critical rect hasn't changed, but there are possibly more tiles lounging about offscreen,
-      // waiting to be rendered. Make sure crawler and eviction knows about them.
-      this.recenterCrawler();
-    }
-
-    if (dirtyAll) {
-      this.dirtyRects([viewportRect.clone()], true);
-    } else if (boundsSizeChanged) {
-      // This is a special case.  The bounds size changed, but we are
-      // told that not everything is dirty (so mayhap content grew or
-      // shrank vertically or horizontally).  We might have old tiles
-      // around in those areas just due to the fact that they haven't
-      // been yet evicted, so we patrol the new regions in search of
-      // any such leftover tiles and mark those we find as dirty.
-      //
-      // The two dirty rects below mark dirty any renegade tiles in
-      // the newly annexed grid regions as per the following diagram
-      // of the "new" viewport.
-      //
-      //   +------------+------+
-      //   |old         | A    |
-      //   |viewport    |      |
-      //   |            |      |
-      //   |            |      |
-      //   |            |      |
-      //   +------------+      |
-      //   | B          |      |
-      //   |            |      |
-      //   +------------+------+
-      //
-      // The first rectangle covers annexed region A, the second
-      // rectangle covers annexed region B.
-      //
-      // XXXrf If the tiles are large, then we are creating some
-      // redundant work here by invalidating the entire tile that
-      // the old viewport boundary crossed (note markDirty() being
-      // called with no rectangle parameter).  The rectangular area
-      // within the tile lying beyond the old boundary is certainly
-      // dirty, but not the area before.  Moreover, since we mark
-      // dirty entire tiles that may cross into the old viewport,
-      // they might, in particular, cross into the critical rect
-      // (which is anyhwere in the old viewport), so we call a
-      // criticalRectPaint() for such cleanup. We do all this more
-      // or less because we don't have much of a notion of "the old
-      // viewport" here except for in the sense that we know the
-      // index bounds on the tilecache grid from before (and the new
-      // index bounds now).
-      //
-
-      let t, l, b, r, rect;
-      let rects = [];
-
-      if (iBoundOld <= iBound) {
-        l = iBoundOld * kTileWidth;
-        t = 0;
-        r = (iBound + 1) * kTileWidth;
-        b = (jBound + 1) * kTileHeight;
-
-        rect = new Rect(l, t, r - l, b - t);
-        rect.restrictTo(viewportRect);
-
-        if (!rect.isEmpty())
-          rects.push(rect);
-      }
-
-      if (jBoundOld <= jBound) {
-        l = 0;
-        t = jBoundOld * kTileHeight;
-        r = (iBound + 1) * kTileWidth;
-        b = (jBound + 1) * kTileHeight;
-
-        rect = new Rect(l, t, r - l, b - t);
-        rect.restrictTo(viewportRect);
-
-        if (!rect.isEmpty())
-          rects.push(rect);
-      }
-
-      this.dirtyRects(rects, true);
-    }
-  },
-
-  /**
-   * Erase everything in these rects.  Useful for tiles that are outside of the viewport rect but
-   * still visible.
-   */
-  clearRects: function clearRects(rects) {
-/*    let criticalIsDirty = false;
-    let criticalRect = this._criticalRect;
-    let tc = this._tileCache;
-
-    let rect;
-    for (let i = rects.length - 1; i >= 0; --i) {
-      rect = rects[i];
-
-      BEGIN_FOREACH_IN_RECT(rect, tc, tile)
-      tile.clear(rect);
-      END_FOREACH_IN_RECT
-    }
-
-    if (criticalIsDirty && doCriticalRender)
-      this.criticalRectPaint(); */
-  },
-
-  dirtyRects: function dirtyRects(rects, doCriticalRender, keepTileInDom) {
-    let outsideIsDirty = false;
-    let criticalIsDirty = false;
-    let criticalRect = this._criticalRect;
-    let tc = this._tileCache;
-    let crawler = this._crawler;
-
-    for (let i = 0, len = rects.length; i < len; ++i) {
-      let rect = rects[i];
-
-      BEGIN_FOREACH_IN_RECT(rect, tc, tile)
-
-      if (!tile.boundRect.intersects(criticalRect)) {
-        // Dirty tile outside of viewport. Just remove and redraw later.
-        if (!keepTileInDom)
-          this._hideTile(tile);
-        crawler.enqueue(tile.i, tile.j);
-        outsideIsDirty = true;
-      } else {
-        criticalIsDirty = true;
-      }
-
-      tile.markDirty(rects[i]);
-
-      END_FOREACH_IN_RECT
-    }
-
-    if (criticalIsDirty && doCriticalRender)
-      this.criticalRectPaint();
-    if (outsideIsDirty)
-      this.restartPrefetchCrawl();
-  },
-
-  criticalRectPaint: function criticalRectPaint() {
-    let cr = this._criticalRect;
-    let lastCr = this._lastCriticalRect;
-
-    if (!lastCr.isEmpty()) {
-      // This is the first paint since the last critical move.
-      let tc = this._tileCache;
-      BEGIN_FOREACH_IN_RECT(lastCr, tc, tile)
-        tc.releaseTile(tile);
-      END_FOREACH_IN_RECT
-
-      lastCr.setRect(0, 0, 0, 0);
-
-      if (!cr.isEmpty())
-        this.recenterEvictionQueue(cr.center().map(Math.round));
-      this.recenterCrawler();
-    }
-
-    if (!cr.isEmpty())
-      this._renderAppendHoldRect(cr);
-  },
-
-  criticalMove: function criticalMove(destCriticalRect, doCriticalPaint) {
-    let cr = this._criticalRect;
-    let lastCr = this._lastCriticalRect;
-    if (lastCr.isEmpty() && !cr.equals(destCriticalRect))
-      lastCr.copyFrom(cr);
-    cr.copyFrom(destCriticalRect);
-
-    if (doCriticalPaint)
-      this.criticalRectPaint();
-  },
-
-  setPrefetch: function setPrefetch(prefetch) {
-    if (prefetch != this._prefetch) {
-      this._prefetch = prefetch;
-
-      if (prefetch)
-        this.restartPrefetchCrawl();
-      else
-        this.stopPrefetchCrawl();
-    }
-  },
-
-  restartPrefetchCrawl: function restartPrefetchCrawl() {
-    if (this._prefetch && !this._idleTileCrawlerTimeout)
-      this._idleTileCrawlerTimeout = setTimeout(this._idleTileCrawler, kTileCrawlComeAgain, this);
-  },
-
-  stopPrefetchCrawl: function stopPrefetchCrawl() {
-    if (this._idleTileCrawlerTimeout)
-      clearTimeout(this._idleTileCrawlerTimeout);
-    delete this._idleTileCrawlerTimeout;
-  },
-
-  recenterEvictionQueue: function recenterEvictionQueue(ctr) {
-    let ctri = ctr.x >> kTileExponentWidth;
-    let ctrj = ctr.y >> kTileExponentHeight;
-
-    this._tileCache.sortEvictionQueue(function evictFarTiles(a, b) {
-      let dista = Math.max(Math.abs(a.i - ctri), Math.abs(a.j - ctrj));
-      let distb = Math.max(Math.abs(b.i - ctri), Math.abs(b.j - ctrj));
-      return dista - distb;
-    });
-  },
-
-  /** Crawler will recalculate the tiles it is supposed to fetch in the background. */
-  recenterCrawler: function recenterCrawler() {
-    let cr = this._criticalRect;
-    this._crawler.recenter(cr.clone());
-    this.restartPrefetchCrawl();
-  },
-
-  /**
-   * Render a rect to the canvas under the given scale.
-   */
-  renderRectToCanvas: function renderRectToCanvas(srcRect, destCanvas, scalex, scaley, drawMissing) {
-    let bv = this._browserView;
-    let tc = this._tileCache;
-
-    let renderer = rendererFactory(bv._browser, destCanvas);
-    bv.viewportToBrowserRect(srcRect);
-
-    renderer.drawContent(function(ctx, draw) {
-      ctx.save();
-      bv.browserToViewportCanvasContext(ctx);
-      ctx.scale(scalex, scaley);
-
-      draw(bv._browser,
-           srcRect.left, srcRect.top, srcRect.width, srcRect.height,
-           "white",
-           (ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_CARET));
-
-      ctx.restore();
-    });
-  },
-
-  /** MozAsyncCanvasRender event */
-  handleEvent: function(e) {
-    let tc = this._tileCache;
-    let canvas = e.originalTarget;
-    let tile = tc.tileFromCanvas(canvas);
-    if (tile) {
-      tile.renderFinish(this._browserView);
-      if (!tile.isDirty() && !tile.isPending()) {
-        // Only show if there are no more pending paints on this
-        // tile and if it hasn't been dirtied while we waited for this paint.
-
-        // XXX Using the style property causes a trace abort, and this function is called back
-        // in the tight loop, so even though what we do below isn't so proper and takes longer
-        // on the Platform/C++ emd, it's better than causing a trace abort in our tight loop.
-        //
-        // But this also overwrites some style already set on the canvas in Tile constructor.
-        // Hack fail...
-        canvas.setAttribute("style", ["position: absolute; left: ", tile.boundRect.left, "px; ",
-                                      "top: ", tile.boundRect.top, "px; display: block"].join(''));
-      }
-    }
-  },
-
-  _hideTile: function _hideTile(tile) {
-    let canvas = tile.getContentImage();
-    canvas.setAttribute("style", "display: none");
-  },
-
-  _showTile: function _showTile(tile) {
-    if (tile.isDirty())
-      tile.render(this._browserView);
-  },
-
-  _appendTileSafe: function _appendTileSafe(tile) {
-    if (!tile.appended) {
-      this._appendTile(tile);
-      tile.appended = true;
-    }
-  },
-
-  _removeTileSafe: function _removeTileSafe(tile) {
-    if (tile.appended) {
-      this._removeTile(tile);
-      tile.appended = false;
-    }
-  },
-
-  _renderAppendHoldRect: function _renderAppendHoldRect(rect) {
-    let tc = this._tileCache;
-
-    // XXX this can evict crawl tiles that might just be rerendered later. It would be nice if
-    // getTile understood which tiles had priority so that we don't waste time.
-    BEGIN_FORCREATE_IN_RECT(rect, tc, tile)
-
-    this._showTile(tile);
-    this._tileCache.holdTile(tile);
-
-    END_FORCREATE_IN_RECT
-  },
-
-  _idleTileCrawler: function _idleTileCrawler(self) {
-    if (!self)
-      self = this;
-
-    let start = Date.now();
-    let comeAgain = true;
-
-    let tile;
-    while ((Date.now() - start) <= kTileCrawlTimeCap) {
-      tile = self._crawler.next();
-      if (!tile) {
-        comeAgain = false;
-        break;
-      }
-      self._showTile(tile);
-    }
-
-    if (comeAgain) {
-      self._idleTileCrawlerTimeout = setTimeout(self._idleTileCrawler, kTileCrawlComeAgain, self);
-    } else {
-      self.stopPrefetchCrawl();
-    }
-  }
-};
-
-/**
- * The tile cache used by the tile manager to hold and index all
- * tiles.  Also responsible for pooling tiles and maintaining the
- * number of tiles under given capacity.
- *
- * @param onBeforeTileDetach callback set by the TileManager to call before
- * we must "detach" a tile from a tileholder due to needing it elsewhere or
- * having to discard it on capacity decrease
- * @param capacity the initial capacity of the tile cache, i.e. the max number
- * of tiles the cache can have allocated
- */
-TileManager.TileCache = function TileCache(onBeforeTileDetach, onTileCreate, iBound, jBound, capacity) {
-  if (arguments.length <= 3 || capacity < 0)
-    capacity = Infinity;
-
-  // A way to map guids to tiles, needed for canvas draw event
-  this._tileGuidMap = {};
-  this._guidCounter = 0;
-
-  // We track all pooled tiles in a 2D array (row, column) ordered as
-  // they "appear on screen".  The array is a grid that functions for
-  // storage of the tiles and as a lookup map.  Each array entry is
-  // a reference to the tile occupying that space ("tileholder").  Entries
-  // are not unique, so a tile could be referenced by multiple array entries,
-  // i.e. a tile could "span" many tile placeholders (e.g. if we merge
-  // neighbouring tiles).
-  this._tileMap = [];
-
-  // holds the same tiles that _tileMap holds, but as contiguous array
-  // elements, for pooling tiles for reuse under finite capacity
-  this._tilePool = [];
-  this._pos = -1;
-
-  this._capacity = capacity;
-
-  this._onBeforeTileDetach = onBeforeTileDetach;
-  this._onTileCreate = onTileCreate;
-
-  this.iBound = iBound;
-  this.jBound = jBound;
-};
-
-TileManager.TileCache.prototype = {
-
-  get size() { return this._tilePool.length; },
-
-  /**
-   * The default tile comparison function used to order the tile pool such that
-   * tiles most eligible for eviction have higher index.
-   *
-   * Unless reset, this is a comparison function that will compare free tiles
-   * as greater than all non-free tiles.  Useful, for instance, to shrink
-   * the tile pool when capacity is lowered, as we want to remove all tiles
-   * at the new cap and beyond, favoring removal of free tiles first.
-   */
-  evictionCmp: function evictionCmp(a, b) {
-    if (a.free == b.free) return (a.j == b.j) ? b.i - a.i : b.j - a.j;
-    return (a.free) ? 1 : -1;
-  },
-
-  lookup: function lookup(i, j) {
-    let tile = null;
-    if (this._tileMap[i])
-      tile = this._tileMap[i][j] || null;
-
-    return tile;
-  },
-
-  getCapacity: function getCapacity() { return this._capacity; },
-
-  inBounds: function inBounds(i, j) {
-    return (0 <= i && 0 <= j && i <= this.iBound && j <= this.jBound);
-  },
-
-  sortEvictionQueue: function sortEvictionQueue(cmp) {
-    let pool = this._tilePool;
-
-    pool.sort(cmp ? cmp : this.evictionCmp);
-    this._pos = pool.length - 1;
-  },
-
-  /**
-   * Get a tile by its indices
-   *
-   * @param i Column
-   * @param j Row
-   * @param create Flag true if the tile should be created in case there is no
-   * tile at (i, j)
-   * @param reuseCondition Boolean-valued function to restrict conditions under
-   * which an old tile may be reused for creating this one.  This can happen if
-   * the cache has reached its capacity and must reuse existing tiles in order to
-   * create this one.  The function is given a Tile object as its argument and
-   * returns true if the tile is OK for reuse. This argument has no effect if the
-   * create argument is false.
-   */
-  getTile: function getTile(i, j, create, evictionGuard) {
-    if (!this.inBounds(i, j))
-      return null;
-
-    let tile = this.lookup(i, j);
-    if (!tile && create) {
-      tile = this._createTile(i, j, evictionGuard);
-      if (tile) tile.markDirty();
-    }
-
-    return tile;
-  },
-
-  /**
-   * Look up (possibly creating) a tile from its viewport coordinates.
-   *
-   * @param x
-   * @param y
-   * @param create Flag true if the tile should be created in case it doesn't
-   * already exist at the tileholder corresponding to (x, y)
-   */
-  tileFromPoint: function tileFromPoint(x, y, create) {
-    let i = x >> kTileExponentWidth;
-    let j = y >> kTileExponentHeight;
-
-    return this.getTile(i, j, create);
-  },
-
-  /** Get tile object from canvas element. */
-  tileFromCanvas: function(canvas) {
-    return this._tileGuidMap[canvas.guid];
-  },
-
-  /**
-   * Hold a tile (i.e. mark it non-free).
-   */
-  holdTile: function holdTile(tile) {
-    if (tile) tile.free = false;
-  },
-
-  /**
-   * Release a tile (i.e. mark it free).
-   */
-  releaseTile: function releaseTile(tile) {
-    if (tile) tile.free = true;
-  },
-
-  _detachTile: function _detachTile(i, j) {
-    let tile = this.lookup(i, j);
-    if (tile) {
-      if (this._onBeforeTileDetach)
-        this._onBeforeTileDetach(tile);
-
-      this.releaseTile(tile);
-      delete this._tileMap[i][j];
-    }
-    return tile;
-  },
-
-  /**
-   * Pluck tile from its current tileMap position and drop it in position
-   * given by (i, j).
-   */
-  _reassignTile: function _reassignTile(tile, i, j) {
-    this._detachTile(tile.i, tile.j);    // detach
-    tile.init(i, j);                     // re-init
-    this._tileMap[i][j] = tile;          // attach
-    return tile;
-  },
-
-  _evictTile: function _evictTile(evictionGuard) {
-    let k = this._pos;
-    let pool = this._tilePool;
-    let victim = null;
-
-    let tile;
-    for (; k >= 0; --k) {
-      tile = pool[k];
-      if (!this.inBounds(tile.i, tile.j) || tile.free && ( !evictionGuard || evictionGuard(tile) )) {
-        victim = tile;
-        --k;
-        break;
-      }
-    }
-
-    this._pos = k;
-
-    return victim;
-  },
-
-  _createTile: function _createTile(i, j, evictionGuard) {
-    if (!this._tileMap[i])
-      this._tileMap[i] = [];
-
-    let tile = null;
-    let guid = 0;
-    if (this._tilePool.length < this._capacity) { // either capacity is
-      tile = new TileManager.Tile(i, j);          // infinite, or we have
-      this._tileMap[i][j] = tile;                 // room to allocate more
-      guid = ++this._guidCounter;
-      tile.getContentImage().guid = guid;
-      this._tileGuidMap[guid] = tile;
-      this._tilePool.push(tile);
-      this._onTileCreate(tile);
-    } else {
-      tile = this._evictTile(evictionGuard);
-      if (tile)
-        this._reassignTile(tile, i, j);
-    }
-
-    return tile;
-  }
-
-};
-
-
-/**
- * A tile is a little object with an <html:canvas> DOM element that it used for
- * caching renders from drawWindow().
- *
- * Supports the dirtying of only a subrectangle of the bounding rectangle, as
- * well as just dirtying the entire tile.
- */
-TileManager.Tile = function Tile(i, j) {
-  this._canvas = document.createElementNS(kXHTMLNamespaceURI, "canvas");
-  this._canvas.setAttribute("width", String(kTileWidth));
-  this._canvas.setAttribute("height", String(kTileHeight));
-  this._canvas.setAttribute("moz-opaque", "true");
-
-  this._pendingState = this.NO_PENDING;
-  this.init(i, j);  // defines more properties, cf below
-};
-
-TileManager.Tile.prototype = {
-  NO_PENDING: 0,
-  PENDING: 1,
-  PENDING_RERENDER: 2,
-
-  init: function init(i, j) {
-    if (!this.boundRect)
-      this.boundRect = new Rect(i * kTileWidth, j * kTileHeight, kTileWidth, kTileHeight);
-    else
-      this.boundRect.setRect(i * kTileWidth, j * kTileHeight, kTileWidth, kTileHeight);
-
-    /* indices of this tile in the tile cache's tile grid map */
-    this.i = i;    // row
-    this.j = j;    // column
-
-    /* flag used by TileManager to avoid re-appending tiles that have already
-     * been appended */
-    this.appended = false;
-
-    /* flag used by the TileCache to mark tiles as ineligible for eviction,
-     * usually because they are fixed in some critical position */
-    this.free = true;
-
-    /* flag is true if we need to repaint our own local canvas */
-    this._dirtyTileCanvas = true;
-
-    /* keep a dirty rectangle (i.e. only part of the tile is dirty) */
-    this._dirtyTileCanvasRect = this.boundRect.clone();
-
-    if (this.isPending()) {
-      this._recreateCanvas();
-    }
-  },
-
-  get x() { return this.boundRect.left; },
-  get y() { return this.boundRect.top; },
-
-  /**
-   * Get the <html:canvas> DOM element with this tile's cached paint.
-   */
-  getContentImage: function getContentImage() { return this._canvas; },
-
-  isDirty: function isDirty() { return this._dirtyTileCanvas; },
-
-  isPending: function isPending() { return this._pendingState != this.NO_PENDING; },
-
-  /** Clear region in rect. */
-  clear: function clear(rect) {
-/*    let boundRect = this.boundRect;
-    let region = rect.intersect(boundRect).expandToIntegers().translate(-boundRect.left, -boundRect.top);
-    let ctx = this._canvas.getContext("2d");
-    ctx.fillStyle = "white";
-    ctx.fillRect(region.left, region.top, region.right - region.left, region.bottom - region.top); */
-  },
-
-  /**
-   * This will mark dirty at least everything in dirtyRect (which must be
-   * specified in canvas coordinates).  If dirtyRect is not given then
-   * the entire tile is marked dirty (i.e. the whole tile needs to be rendered
-   * on next render).
-   */
-  markDirty: function markDirty(dirtyRect) {
-    if (!dirtyRect) {
-      this._dirtyTileCanvasRect.copyFrom(this.boundRect);
-    } else {
-      this._dirtyTileCanvasRect.expandToContain(dirtyRect.intersect(this.boundRect)).expandToIntegers();
-    }
-
-    // XXX if, after the above, the dirty rectangle takes up a large enough
-    // portion of the boundRect, we should probably just mark the entire tile
-    // dirty and fastpath for future calls.
-    if (!this._dirtyTileCanvasRect.isEmpty())
-      this._dirtyTileCanvas = true;
-  },
-
-  unmarkDirty: function unmarkDirty() {
-    this._dirtyTileCanvasRect.setRect(0, 0, 0, 0);
-    this._dirtyTileCanvas = false;
-  },
-
-  _recreateCanvas: function() {
-    let oldCanvas = this._canvas;
-    this._canvas = document.createElementNS(kXHTMLNamespaceURI, "canvas");
-    this._canvas.setAttribute("width", String(kTileWidth));
-    this._canvas.setAttribute("height", String(kTileHeight));
-    this._canvas.setAttribute("moz-opaque", "true");
-    this._canvas.setAttribute("style", "display: none");
-    this._canvas.guid = oldCanvas.guid;
-    oldCanvas.parentNode.replaceChild(this._canvas, oldCanvas);
-    this._pendingState = this.NO_PENDING;
-    this.markDirty();
-    this._renderer = null;
-  },
-
-  /**
-   * Actually draw the browser content into the dirty region of this tile.  This
-   * requires us to actually draw with nsIDOMCanvasRenderingContext2D::
-   * drawWindow(), which we expect to be a heavy operation.
-   *
-   * You likely want to check if the tile isDirty() before asking it
-   * to render, as this will cause the entire tile to re-render in the
-   * case that it is not dirty.
-   */
-  render: function render(browserView) {
-    if (!this._renderer) {
-      this._renderer = rendererFactory(browserView._browser, this._canvas);
-    }
-    else if (!this._renderer.checkBrowser(browserView._browser)) {
-      this._recreateCanvas();
-      this._renderer = rendererFactory(browserView._browser, this._canvas);
-    }
-      
-    if (this.isPending()) {
-      this._pendingState = this.PENDING_RERENDER;
-      return;
-    }
-
-    let dirtyRect = this._dirtyTileCanvasRect.clone();
-
-    this._pendingState = this.PENDING;
-    this.unmarkDirty();
-
-    let self = this;
-    this._renderer.drawContent(function(ctx, draw) {
-      let rect = dirtyRect.clone();
-      let boundRect = self.boundRect.clone();
-
-      let x = rect.left - boundRect.left;
-      let y = rect.top - boundRect.top;
-
-      browserView.viewportToBrowserRect(rect);
-
-      ctx.save();
-      ctx.translate(x, y);
-      browserView.browserToViewportCanvasContext(ctx);
-
-      // We expand the rect to working around a gfx issue (bug 534054)
-      try {
-        draw(browserView._browser,
-             rect.left , rect.top, rect.right - rect.left + 1, rect.bottom - rect.top + 1,
-             "white",
-             (ctx.DRAWWINDOW_DRAW_CARET));
-        ctx.restore();
-      } catch(e) {
-        // Failed drawing.
-        self._recreateCanvas(browserView._browser);
-        self.render(browserView);
-      }
-    });
-  },
-
-  renderFinish: function renderFinish(browserView) {
-    if (this._pendingState == this.PENDING) {
-      this._pendingState = this.NO_PENDING;
-    } else if (this._pendingState == this.PENDING_RERENDER) {
-      // a render occured while we were pending another render.
-      this._pendingState = this.NO_PENDING;
-      this.render(browserView);
-    }
-  },
-
-  /**
-   * Standard toString prints "Tile(<row>, <column>)", but if `more' flags true
-   * then some extra information is printed.
-   */
-  toString: function toString(more) {
-    if (more) {
-      return 'Tile(' + this.i                                   + ', '
-                     + this.j                                   + ', '
-                     + 'dirty=' + this.isDirty()                + ', '
-                     + 'boundRect=' + this.boundRect.toString() + ')';
-    }
-
-    return 'Tile(' + this.i + ', ' + this.j + ')';
-  }
-};
-
-
-/**
- * A CrawlIterator is in charge of creating and returning subsequent tiles "crawled"
- * over as we render tiles lazily.
- *
- * Currently the CrawlIterator is built to expand a rectangle iteratively and return
- * subsequent tiles that intersect the boundary of the rectangle.  Each expansion of
- * the rectangle is one unit of tile dimensions in each direction.  This is repeated
- * until all tiles from elsewhere have been reused (assuming the cache has finite
- * capacity) in this crawl, so that we don't start reusing tiles from the beginning
- * of our crawl.  Afterward, the CrawlIterator enters a state where it operates as a
- * FIFO queue, and calls to next() simply dequeue elements, which must be added with
- * enqueue().
- *
- * @param tc The TileCache over whose tiles this CrawlIterator will crawl
- * @param rect The rectangle that we grow in the first (rectangle * expansion)
- *             iteration state. If empty, doesn't crawl.
- */
-TileManager.CrawlIterator = function CrawlIterator(tc, rect) {
-  this._tileCache = tc;
-
-  this.recenter(rect);
-};
-
-TileManager.CrawlIterator.prototype = {
-  _generateCrawlQueue: function _generateCrawlQueue(rect) {
-    function add(i, j) {
-      if (tc.inBounds(i, j)) {
-        outOfBounds = false;
-        result.push([i, j]);
-        --index;
-        return true;
-      }
-      return false;
-    }
-
-    let tc = this._tileCache;
-    let capacity = tc.getCapacity();
-    let result = [];
-    let index = capacity;
-    let outOfBounds;
-    let counter;
-    let starti = rect.left  >> kTileExponentWidth;
-    let endi   = rect.right >> kTileExponentWidth;
-    let startj = rect.top    >> kTileExponentHeight;
-    let endj   = rect.bottom >> kTileExponentHeight;
-    let i, j;
-    while (!outOfBounds) {
-      starti -= 1;
-      endi += 1;
-      startj -= 1;
-      endj += 1;
-      outOfBounds = true;
-
-      // top, bottom rect borders
-      for each (j in [startj, endj]) {
-        for (counter = 1, i = Math.floor((starti + endi) / 2); i >= starti && i <= endi;) {
-          if (add(i, j) && index == 0)
-            return result;
-          i += counter;
-          counter = -counter + (counter > 0 ? -1 : 1);
-        }
-      }
-
-      // left, right rect borders
-      for each (i in [starti, endi]) {
-        counter = 1;
-        for (counter = 1, j = Math.floor((startj + endj) / 2); j >= startj && j <= endj;) {
-          if (add(i, j) && index == 0)
-            return result;
-          j += counter;
-          counter = -counter + (counter > 0 ? -1 : 1);
-        }
-      }
-    }
-    return result;
-  },
-
-  recenter: function recenter(rect) {
-    // Queue should not be very big, so put first priorities last in order to pop quickly.
-    this._crawlQueue = rect.isEmpty() ? [] : this._generateCrawlQueue(rect).reverse();
-
-    // used to remember tiles that we've reused during this crawl
-    this._visited = {}
-
-    // filters the tiles we've already reused once from being considered victims
-    // for reuse when we ask the tile cache to create a new tile
-    let visited = this._visited;
-    this._notVisited = function(tile) { return !visited[tile.i + "," + tile.j]; };
-
-    // after we finish the rectangle iteration state, we enter the FILO queue state
-    // no need to remember old dirty tiles, if it's important we'll get to it anyways
-    this._queue = [];
-
-    // use a dictionary to prevent tiles from being enqueued twice --- "patience, we'll get to
-    // it in a moment"
-    this._enqueued = {};
-  },
-
-  next: function next() {
-    // Priority for next goes to the crawl queue, dirty tiles afterwards. Since dirty
-    // tile queue does not really have a necessary order, pop off the top.
-    let coords = this._crawlQueue.pop() || this.dequeue();
-    let tile = null;
-    if (coords) {
-      let [i, j] = coords;
-      // getTile will create a tile only if there are any left in our capacity that have not been
-      // visited already by the crawler.
-      tile = this._tileCache.getTile(i, j, true, this._notVisited);
-      if (tile) {
-        this._visited[this._strIndices(i, j)] = true;
-      } else {
-        tile = this.next();
-      }
-    }
-    return tile;
-  },
-
-  dequeue: function dequeue() {
-    if (this._queue.length) {
-      let [i, j] = this._queue.pop();
-      this._enqueued[this._strIndices(i, j)] = false;
-      return [i, j];
-    } else {
-      return null;
-    }
-  },
-
-  enqueue: function enqueue(i, j) {
-    let index = this._strIndices(i, j);
-    let enqueued = this._enqueued;
-    if (!enqueued[index]) {
-      this._queue.push([i, j]);
-      enqueued[index] = true;
-    }
-  },
-
-  _strIndices: function _strIndices(i, j) {
-    return i + "," + j;
-  },
-};
--- a/mobile/chrome/content/bindings.xml
+++ b/mobile/chrome/content/bindings.xml
@@ -1284,17 +1284,16 @@
 
           this._model = null;
           this._spacer.hidden = true;
 
           // give the form spacer area back to the content
           // XXX this should probably be removed with layers
           Browser.forceChromeReflow();
           Browser.contentScrollboxScroller.scrollBy(0, 0);
-          Browser._browserView.onAfterVisibleMove();
         ]]></body>
       </method>
     </implementation>
   </binding>
 
   <binding id="menulist" display="xul:box" extends="chrome://global/content/bindings/menulist.xml#menulist">
     <handlers>
       <handler event="mousedown" phase="capturing">
--- a/mobile/chrome/content/browser-ui.js
+++ b/mobile/chrome/content/browser-ui.js
@@ -1494,25 +1494,23 @@ var FindHelperUI = {
 
   handleEvent: function findHelperHandleEvent(aEvent) {
     if (aEvent.type == "TabSelect" || aEvent.type == "URLChanged")
       this.hide();
   },
 
   show: function findHelperShow() {
     BrowserUI.pushPopup(this, this._container);
-    Browser._browserView.ignorePageScroll(true);
     this._container.show(this);
     this.search("");
     this._textbox.focus();
   },
 
   hide: function findHelperHide() {
     BrowserUI.popPopup();
-    Browser._browserView.ignorePageScroll(false);
     this._textbox.value = "";
     this._container.hide(this);
   },
 
   goToPrevious: function findHelperGoToPrevious() {
     Browser.selectedBrowser.messageManager.sendAsyncMessage("FindAssist:Previous", { });
   },
 
@@ -1675,18 +1673,16 @@ var FormHelperUI = {
   get _open() {
     return (this._container.getAttribute("type") == this.type);
   },
 
   set _open(aVal) {
     if (aVal == this._open)
       return;
 
-    let bv = Browser._browserView;
-    bv.ignorePageScroll(aVal);
     this._container.hidden = !aVal;
 
     if (aVal) {
       this._zoomStart();
       this._container.show(this);
     } else {
       this._zoomFinish();
       this._currentElement = null;
@@ -1783,17 +1779,16 @@ var FormHelperUI = {
     if (aCaretRect) {
       let caretRect = bv.browserToViewportRect(aCaretRect);
       if (zoomRect.contains(caretRect))
         return;
 
       let [deltaX, deltaY] = this._getOffsetForCaret(caretRect, zoomRect);
       if (deltaX != 0 || deltaY != 0) {
         Browser.contentScrollboxScroller.scrollBy(deltaX, deltaY);
-        bv.onAfterVisibleMove();
       }
 
       Browser.animatedZoomTo(zoomRect);
     }
   },
 
   /* Store the current zoom level, and scroll positions to restore them if needed */
   _zoomStart: function _formHelperZoomStart() {
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -65,291 +65,82 @@ window.sizeToContent = function() {
 
 #ifdef MOZ_CRASH_REPORTER
 XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter",
   "@mozilla.org/xre/app-info;1", "nsICrashReporter");
 #endif
 
 const endl = '\n';
 
-function debug() {
-  let bv = Browser._browserView;
-  let tc = bv._tileManager._tileCache;
-  let scrollbox = document.getElementById("content-scrollbox")
-                .boxObject.QueryInterface(Ci.nsIScrollBoxObject);
-
-  let x = {};
-  let y = {};
-  let w = {};
-  let h = {};
-  scrollbox.getPosition(x, y);
-  scrollbox.getScrolledSize(w, h);
-  let container = document.getElementById("tile-container");
-  let [x, y] = [x.value, y.value];
-  let [w, h] = [w.value, h.value];
-  if (bv) {
-    dump('----------------------DEBUG!-------------------------\n');
-    dump(bv._browserViewportState.toString() + endl);
-
-    dump(endl);
-
-    dump('location from Browser: ' + Browser.selectedBrowser.currentURI.spec + endl);
-    dump('location from BV     : ' + bv.getBrowser().currentURI.spec + endl);
-
-    dump(endl + endl);
-
-    let cr = bv._tileManager._criticalRect;
-    dump('criticalRect from BV: ' + (cr ? cr.toString() : null) + endl);
-    dump('visibleRect from BV : ' + bv.getVisibleRect().toString() + endl);
-    dump('visibleRect from foo: ' + Browser.getVisibleRect().toString() + endl);
-
-    dump('bv batchops depth:    ' + bv._batchOps.length + endl);
-    dump('renderpause depth:    ' + bv._renderMode + endl);
-
-    dump(endl);
-
-    dump('window.innerWidth : ' + window.innerWidth  + endl);
-    dump('window.innerHeight: ' + window.innerHeight + endl);
-
-    dump(endl);
-
-    dump('container width,height from BV: ' + bv._container.style.width + ', '
-                                            + bv._container.style.height + endl);
-    dump('container width,height via DOM: ' + container.style.width + ', '
-                                            + container.style.height + endl);
-
-    dump(endl);
-
-    dump('scrollbox position    : ' + x + ', ' + y + endl);
-    dump('scrollbox scrolledsize: ' + w + ', ' + h + endl);
-
-
-    let sb = document.getElementById("content-scrollbox");
-    dump('container location:     ' + Math.round(container.getBoundingClientRect().left) + " " +
-                                      Math.round(container.getBoundingClientRect().top) + endl);
-
-    dump(endl);
-
-    let mouseModule = ih._modules[0];
-    dump('ih grabber  : ' + ih._grabber           + endl);
-    dump('ih grabdepth: ' + ih._grabDepth         + endl);
-    dump('ih listening: ' + !ih._ignoreEvents     + endl);
-    dump('ih suppress : ' + ih._suppressNextClick + endl);
-    dump('mouseModule : ' + mouseModule           + endl);
-
-    dump(endl);
-
-    dump('tilecache capacity: ' + bv._tileManager._tileCache.getCapacity() + endl);
-    dump('tilecache size    : ' + bv._tileManager._tileCache.size          + endl);
-    dump('tilecache iBound  : ' + bv._tileManager._tileCache.iBound        + endl);
-    dump('tilecache jBound  : ' + bv._tileManager._tileCache.jBound        + endl);
-
-    dump('-----------------------------------------------------\n');
-  }
-}
-
-function debugTile(i, j) {
-  let bv = Browser._browserView;
-  let tc = bv._tileManager._tileCache;
-  let t  = tc.getTile(i, j);
-
-  dump('------ DEBUGGING TILE (' + i + ',' + j + ') --------\n');
-
-  dump('in bounds: ' + tc.inBounds(i, j) + endl);
-  dump('occupied : ' + !!tc.lookup(i, j) + endl);
-  if (t)
-  {
-  dump('toString : ' + t.toString(true) + endl);
-  dump('free     : ' + t.free + endl);
-  dump('dirtyRect: ' + t._dirtyTileCanvasRect + endl);
-
-  let len = tc._tilePool.length;
-  for (let k = 0; k < len; ++k)
-    if (tc._tilePool[k] === t)
-      dump('found in tilePool at index ' + k + endl);
-  }
-
-  dump('------------------------------------\n');
-}
-
 function onDebugKeyPress(ev) {
   let bv = Browser._browserView;
 
   if (!ev.ctrlKey)
     return;
 
   // use capitals so we require SHIFT here too
 
-  const a = 65;   // debug all critical tiles
-  const b = 66;   // dump an ASCII graphic of the tile map
+  const a = 65;
+  const b = 66;
   const c = 67;
   const d = 68;  // debug dump
   const e = 69;
   const f = 70;  // free memory by clearing a tab.
   const g = 71;
   const h = 72;
   const i = 73;  // toggle info click mode
   const j = 74;
   const k = 75;
   const l = 76;  // restart lazy crawl
   const m = 77;  // fix mouseout
   const n = 78;
   const o = 79;
-  const p = 80;  // debug tiles in pool order
+  const p = 80;
   const q = 81;  // toggle orientation
   const r = 82;  // reset visible rect
   const s = 83;
   const t = 84;
-  const u = 85;  // debug given list of tiles separated by space
+  const u = 85;
   const v = 86;
   const w = 87;
   const x = 88;
   const y = 89;
   const z = 90;  // set zoom level to 1
 
-  if (window.tileMapMode) {
-    function putChar(ev, col, row) {
-      let tile = tc.getTile(col, row);
-      switch (ev.charCode) {
-      case h: // held tiles
-        dump(tile ? (tile.free ? '*' : 'h') : ' ');
-        break;
-      case d: // dirty tiles
-        dump(tile ? (tile.isDirty() ? 'd' : '*') : ' ');
-        break;
-      case o: // occupied tileholders
-        dump(tc.lookup(col, row) ? 'o' : ' ');
-        break;
-      }
-    }
-
-    let tc = Browser._browserView._tileManager._tileCache;
-    let col, row;
-
-    dump(endl);
-
-    dump('  ');
-    for (col = 0; col < tc.iBound; ++col)
-      dump(col % 10);
-
-    dump(endl);
-
-    for (row = 0; row < tc.jBound; ++row) {
-
-      dump((row % 10) + ' ');
-
-      for (col = 0; col < tc.iBound; ++col) {
-        putChar(ev, col, row);
-      }
-
-      dump(endl);
-    }
-    dump(endl + endl);
-
-    for (let ii = 0; ii < tc._tilePool.length; ++ii) {
-      let tile = tc._tilePool[ii];
-      putChar(ev, tile.i, tile.j);
-    }
-
-    dump(endl + endl);
-
-    window.tileMapMode = false;
-    return;
-  }
-
   switch (ev.charCode) {
   case f:
     MemoryObserver.observe();
     dump("Forced a GC\n");
     break;
-  case r:
-    bv.onAfterVisibleMove();
-    //bv.setVisibleRect(Browser.getVisibleRect());
-
-  case d:
-    debug();
-
-    break;
-  case l:
-    bv._tileManager.restartLazyCrawl(bv._tileManager._criticalRect);
-
-    break;
-  case b:
-    window.tileMapMode = true;
-    break;
-  case u:
-    let ijstrs = window.prompt('row,col plz').split(' ');
-    for each (let ijstr in ijstrs) {
-      let [i, j] = ijstr.split(',').map(function (x) { return parseInt(x); });
-      debugTile(i, j);
-    }
-
-    break;
-  case a:
-    let cr = bv._tileManager._criticalRect;
-    dump('>>>>>> critical rect is ' + (cr ? cr.toString() : cr) + '\n');
-    if (cr) {
-      let starti = cr.left  >> kTileExponentWidth;
-      let endi   = cr.right >> kTileExponentWidth;
-
-      let startj = cr.top    >> kTileExponentHeight;
-      let endj   = cr.bottom >> kTileExponentHeight;
-
-      for (var jj = startj; jj <= endj; ++jj)
-        for (var ii = starti; ii <= endi; ++ii)
-          debugTile(ii, jj);
-    }
-
-    break;
   case i:
     window.infoMode = !window.infoMode;
     break;
-  case m:
-    Util.dumpLn("renderMode:", bv._renderMode);
-    Util.dumpLn("batchOps:",bv._batchOps.length);
-    bv.resumeRendering();
-    break;
-  case p:
-    let tc = bv._tileManager._tileCache;
-    dump('************* TILE POOL ****************\n');
-    for (let ii = 0, len = tc._tilePool.length; ii < len; ++ii) {
-      if (window.infoMode)
-        debugTile(tc._tilePool[ii].i, tc._tilePool[ii].j);
-      else
-        dump(tc._tilePool[ii].i + ',' + tc._tilePool[ii].j + '\n');
-    }
-    dump('****************************************\n');
-    break;
 #ifndef MOZ_PLATFORM_MAEMO
   case q:
     if (Util.isPortrait())
       window.top.resizeTo(800,480);
     else
       window.top.resizeTo(480,800);
     break;
 #endif
   case z:
     bv.setZoomLevel(1.0);
     break;
   default:
     break;
   }
 }
-window.infoMode = false;
-window.tileMapMode = false;
 
 var ih = null;
 
 var Browser = {
   _tabs : [],
   _selectedTab : null,
   windowUtils: window.QueryInterface(Ci.nsIInterfaceRequestor)
                      .getInterface(Ci.nsIDOMWindowUtils),
-  contentScrollbox: null,
-  contentScrollboxScroller: null,
   controlsScrollbox: null,
   controlsScrollboxScroller: null,
   pageScrollbox: null,
   pageScrollboxScroller: null,
   styles: {},
 
   startup: function startup() {
     var self = this;
@@ -362,46 +153,120 @@ var Browser = {
       // XXX whatever is calling startup needs to dump errors!
       dump("###########" + e + "\n");
     }
 
     let needOverride = Util.needHomepageOverride();
     if (needOverride == "new profile")
       this.initNewProfile();
 
-    let container = document.getElementById("tile-container");
+    let container = document.getElementById("browsers");
     let bv = this._browserView = new BrowserView(container, Browser.getVisibleRect);
 
-    /* handles dispatching clicks on tiles into clicks in content or zooms */
+    /* handles dispatching clicks on browser into clicks in content or zooms */
     container.customClicker = new ContentCustomClicker(bv);
     container.customKeySender = new ContentCustomKeySender(bv);
-
-    /* scrolling box that contains tiles */
-    let contentScrollbox = this.contentScrollbox = document.getElementById("content-scrollbox");
-    this.contentScrollboxScroller = contentScrollbox.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
-    contentScrollbox.customDragger = new Browser.MainDragger(bv);
+    container.customDragger = new Browser.MainDragger(bv);
+
+    // Warning, total hack ahead. All of the real-browser related scrolling code
+    // lies in a pretend scrollbox here. Let's not land this as-is. Maybe it's time
+    // to redo all the dragging code.
+    this.contentScrollbox = container;
+    this.contentScrollboxScroller = {
+      position: new Point(0, 0),
+      pendingTranslation: new Point(0, 0),
+      afterTranslation: new Point(0, 0),
+      flushing: false,
+
+      updateTransition: function() {
+        let tx = -(this.pendingTranslation.x + this.afterTranslation.x);
+        let ty = -(this.pendingTranslation.y + this.afterTranslation.y);
+        getBrowser().style.MozTransform = "translate(" + tx + "px)" + " translateY(" + ty + "px) scale(" + Browser._browserView.getZoomLevel() + ")";
+      },
+
+      flush: function() {
+        getBrowser().messageManager.sendAsyncMessage("MozScrollBy", this.pendingTranslation);
+        this.flushing = true;
+      },
+
+      receiveMessage: function(message) {
+        this.flushing = false;
+        this.pendingTranslation.set(this.afterTranslation);
+        this.afterTranslation.set(0, 0);
+        this.position.set(message.json.x, message.json.y);
+        this.updateTransition();
+        if (!this.pendingTranslation.isZero())
+          this.flush();
+      },
+
+      scrollBy: function(x, y) {
+        let finalPos = this.position.clone().add(this.pendingTranslation).add(this.afterTranslation);
+        let [width, height] = Browser._browserView.getViewportDimensions();
+        let browserWidth = window.innerWidth;
+        let browserHeight = window.innerHeight;
+        x = Math.max(0, Math.min(width - browserWidth, finalPos.x + x)) - finalPos.x;
+        y = Math.max(0, Math.min(height - browserHeight, finalPos.y + y)) - finalPos.y;
+
+        if (x == 0 && y == 0)
+          return;
+
+        if (getBrowser().contentWindow) {
+          getBrowser().contentWindow.scrollBy(x, y);
+        }
+        else {
+          if (!this.flushing)
+            this.pendingTranslation.add(x, y);
+          else
+            this.afterTranslation.add(x, y);
+
+          this.updateTransition();
+        }
+      },
+
+      scrollTo: function(x, y) {
+        if (getBrowser().contentWindow) {
+          getBrowser().contentWindow.scrollTo(x, y);
+        }
+        else {
+          let finalPos = this.position.clone().add(this.pendingTranslation).add(this.afterTranslation);
+          this.scrollBy(x - finalPos.x, y - finalPos.y);
+        }
+      },
+
+      getPosition: function(scrollX, scrollY) {
+        if (getBrowser().contentWindow) {
+          let cwu = Util.getWindowUtils(getBrowser().contentWindow);
+          cwu.getScrollXY(false, scrollX, scrollY);
+        }
+        else {
+          let finalPos = this.position.clone().add(this.pendingTranslation).add(this.afterTranslation);
+          let [width, height] = Browser._browserView.getViewportDimensions();
+          scrollX.value = Math.max(0, Math.min(width - window.innerWidth, finalPos.x));
+          scrollY.value = Math.max(0, Math.min(height - window.innerHeight, finalPos.y));
+        }
+      }
+    };
+
+    messageManager.addMessageListener("MozScrolled", this.contentScrollboxScroller);
 
     /* horizontally scrolling box that holds the sidebars as well as the contentScrollbox */
     let controlsScrollbox = this.controlsScrollbox = document.getElementById("controls-scrollbox");
     this.controlsScrollboxScroller = controlsScrollbox.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
     controlsScrollbox.customDragger = {
-      isDraggable: function isDraggable(target, content) { return false; },
+      isDraggable: function isDraggable(target, content) { return {}; },
       dragStart: function dragStart(cx, cy, target, scroller) {},
       dragStop: function dragStop(dx, dy, scroller) { return false; },
       dragMove: function dragMove(dx, dy, scroller) { return false; }
     };
 
     /* vertically scrolling box that contains the url bar, notifications, and content */
     let pageScrollbox = this.pageScrollbox = document.getElementById("page-scrollbox");
     this.pageScrollboxScroller = pageScrollbox.boxObject.QueryInterface(Ci.nsIScrollBoxObject);
     pageScrollbox.customDragger = controlsScrollbox.customDragger;
 
-    // during startup a lot of viewportHandler calls happen due to content and window resizes
-    bv.beginBatchOperation();
-
     let stylesheet = document.styleSheets[0];
     for each (let style in ["viewport-width", "viewport-height", "window-width", "window-height", "toolbar-height"]) {
       let index = stylesheet.insertRule("." + style + " {}", stylesheet.cssRules.length);
       this.styles[style] = stylesheet.cssRules[index].style;
     }
 
     function resizeHandler(e) {
       if (e.target != window)
@@ -409,25 +274,23 @@ var Browser = {
 
       // XXX is this code right here actually needed?
       let w = window.innerWidth;
       let h = window.innerHeight;
       let maximize = (document.documentElement.getAttribute("sizemode") == "maximized");
       if (maximize && w > screen.width)
         return;
 
-      bv.beginBatchOperation();
-
       let toolbarHeight = Math.round(document.getElementById("toolbar-main").getBoundingClientRect().height);
       let scaledDefaultH = (kDefaultBrowserWidth * (h / w));
       let scaledScreenH = (window.screen.width * (h / w));
       let dpiScale = Services.prefs.getIntPref("zoom.dpiScale") / 100;
 
-      Browser.styles["viewport-width"].width = (w / dpiScale) + "px";
-      Browser.styles["viewport-height"].height = (h / dpiScale) + "px";
+      Browser.styles["viewport-width"].width = (w /* XXX / dpiScale */) + "px";
+      Browser.styles["viewport-height"].height = (h /* XXX / dpiScale */) + "px";
       Browser.styles["window-width"].width = w + "px";
       Browser.styles["window-height"].height = h + "px";
       Browser.styles["toolbar-height"].height = toolbarHeight + "px";
 
       // Tell the UI to resize the browser controls
       BrowserUI.sizeControls(w, h);
 
       // XXX During the launch, the resize of the window arrive after we add
@@ -438,44 +301,37 @@ var Browser = {
         bvs.viewportRect.width = window.innerWidth;
         bvs.viewportRect.height = window.innerHeight;
       }
 
       bv.updateDefaultZoom();
       if (bv.isDefaultZoom())
         // XXX this should really only happen on browser startup, not every resize
         Browser.hideSidebars();
-      bv.onAfterVisibleMove();
 
       for (let i = Browser.tabs.length - 1; i >= 0; i--)
         Browser.tabs[i].updateViewportSize();
 
-      bv.commitBatchOperation();
-
       let curEl = document.activeElement;
       if (curEl && curEl.scrollIntoView)
         curEl.scrollIntoView(false);
-
-      // Preload the zoom snapshot canvas, because it's slow on Android (bug 586353)
-      AnimatedZoom.createCanvas().MozGetIPCContext("2d");
     }
     window.addEventListener("resize", resizeHandler, false);
 
     function fullscreenHandler() {
       if (!window.fullScreen)
         document.getElementById("toolbar-main").setAttribute("fullscreen", "true");
       else
         document.getElementById("toolbar-main").removeAttribute("fullscreen");
     }
     window.addEventListener("fullscreen", fullscreenHandler, false);
 
     function notificationHandler() {
       // Let the view know that the layout might have changed
       Browser.forceChromeReflow();
-      bv.onAfterVisibleMove();
     }
     let notifications = document.getElementById("notifications");
     notifications.addEventListener("AlertActive", notificationHandler, false);
     notifications.addEventListener("AlertClose", notificationHandler, false);
 
     BrowserUI.init();
 
     // initialize input handling
@@ -543,18 +399,16 @@ var Browser = {
     this.addTab(whereURI, true);
 
     // JavaScript Error Console
     if (Services.prefs.getBoolPref("browser.console.showInPanel")){
       let button = document.getElementById("tool-console");
       button.hidden = false;
     }
 
-    bv.commitBatchOperation();
-
     // If some add-ons were disabled during during an application update, alert user
     if (Services.prefs.prefHasUserValue("extensions.disabledAddons")) {
       let addons = Services.prefs.getCharPref("extensions.disabledAddons").split(",");
       if (addons.length > 0) {
         let disabledStrings = Elements.browserBundle.getString("alertAddonsDisabled");
         let label = PluralForm.get(addons.length, disabledStrings).replace("#1", addons.length);
 
         let alerts = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
@@ -583,17 +437,17 @@ var Browser = {
       return false;
 
     // Prompt if we have multiple tabs before closing window
     let numTabs = this._tabs.length;
     if (numTabs > 1) {
       let shouldPrompt = Services.prefs.getBoolPref("browser.tabs.warnOnClose");
       if (shouldPrompt) {
         let prompt = Services.prompt;
-  
+
         // Default to true: if it were false, we wouldn't get this far
         let warnOnClose = { value: true };
 
         let messageBase = Elements.browserBundle.getString("tabs.closeWarning");
         let message = PluralForm.get(numTabs, messageBase).replace("#1", numTabs);
 
         let title = Elements.browserBundle.getString("tabs.closeWarningTitle");
         let closeText = Elements.browserBundle.getString("tabs.closeButton");
@@ -627,17 +481,17 @@ var Browser = {
     if (!lastBrowser)
       return true;
 
     // Let everyone know we are closing the last browser window
     let closingCanceled = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool);
     Services.obs.notifyObservers(closingCanceled, "browser-lastwindow-close-requested", null);
     if (closingCanceled.data)
       return false;
-  
+
     Services.obs.notifyObservers(null, "browser-lastwindow-close-granted", null);
     return true;
   },
 
   shutdown: function shutdown() {
     this._browserView.uninit();
     BrowserUI.uninit();
 
@@ -665,51 +519,29 @@ var Browser = {
 
   get browsers() {
     return this._tabs.map(function(tab) { return tab.browser; });
   },
 
   scrollContentToTop: function scrollContentToTop() {
     this.contentScrollboxScroller.scrollTo(0, 0);
     this.pageScrollboxScroller.scrollTo(0, 0);
-    this._browserView.onAfterVisibleMove();
-  },
-
-  /** Let current browser's scrollbox know about where content has been panned. */
-  scrollBrowserToContent: function scrollBrowserToContent() {
-    let browser = this.selectedBrowser;
-    if (browser) {
-      let scroll = Browser.getScrollboxPosition(Browser.contentScrollboxScroller);
-      browser.messageManager.sendAsyncMessage("Content:ScrollTo", { x: scroll.x, y: scroll.y });
-    }
-  },
-
-  /** Update viewport to location of browser's scrollbars. */
-  scrollContentToBrowser: function scrollContentToBrowser(aScrollX, aScrollY) {
-    if (aScrollY != 0)
-      Browser.hideTitlebar();
-
-    let zoomLevel = this._browserView.getZoomLevel();
-    Browser.contentScrollboxScroller.scrollTo(aScrollX*zoomLevel, aScrollY*zoomLevel);
-    this._browserView.onAfterVisibleMove();
   },
 
   hideSidebars: function scrollSidebarsOffscreen() {
-    let container = this.contentScrollbox;
+    let container = document.getElementById("browsers");
     let rect = container.getBoundingClientRect();
     this.controlsScrollboxScroller.scrollBy(Math.round(rect.left), 0);
-    this._browserView.onAfterVisibleMove();
   },
 
   hideTitlebar: function hideTitlebar() {
-    let container = this.contentScrollbox;
+    let container = document.getElementById("browsers");
     let rect = container.getBoundingClientRect();
     this.pageScrollboxScroller.scrollBy(0, Math.round(rect.top));
     this.tryUnfloatToolbar();
-    this._browserView.onAfterVisibleMove();
   },
 
   /**
    * Load a URI in the current tab, or a new tab if necessary.
    * @param aURI String
    * @param aParams Object with optional properties that will be passed to loadURIWithFlags:
    *    flags, referrerURI, charset, postData.
    */
@@ -831,36 +663,32 @@ var Browser = {
 
     if (tab instanceof XULElement)
       tab = this.getTabFromChrome(tab);
 
     if (!tab || this._selectedTab == tab)
       return;
 
     if (this._selectedTab) {
-      this._selectedTab.contentScrollOffset = this.getScrollboxPosition(this.contentScrollboxScroller);
       this._selectedTab.pageScrollOffset = this.getScrollboxPosition(this.pageScrollboxScroller);
 
       // Make sure we leave the toolbar in an unlocked state
       if (this._selectedTab.isLoading())
         BrowserUI.unlockToolbar();
     }
 
     let isFirstTab = this._selectedTab == null;
     let lastTab = this._selectedTab;
     this._selectedTab = tab;
 
     // Lock the toolbar if the new tab is still loading
     if (this._selectedTab.isLoading())
       BrowserUI.lockToolbar();
 
-    bv.beginBatchOperation();
-
     bv.setBrowser(tab.browser, tab.browserViewportState);
-    bv.forceContainerResize();
     bv.updateDefaultZoom();
 
     document.getElementById("tabs").selectedTab = tab.chromeTab;
 
     if (!isFirstTab) {
       // Update all of our UI to reflect the new tab's location
       BrowserUI.updateURI();
       getIdentityHandler().checkIdentity();
@@ -868,29 +696,20 @@ var Browser = {
       let event = document.createEvent("Events");
       event.initEvent("TabSelect", true, false);
       event.lastTab = lastTab;
       tab.chromeTab.dispatchEvent(event);
     }
 
     tab.lastSelected = Date.now();
 
-    // XXX incorrect behavior if page was scrolled by tab in the background.
-    if (tab.contentScrollOffset) {
-      let { x: scrollX, y: scrollY } = tab.contentScrollOffset;
-      Browser.contentScrollboxScroller.scrollTo(scrollX, scrollY);
-    }
     if (tab.pageScrollOffset) {
       let { x: pageScrollX, y: pageScrollY } = tab.pageScrollOffset;
       Browser.pageScrollboxScroller.scrollTo(pageScrollX, pageScrollY);
     }
-
-    bv.setAggressive(!tab._loading);
-
-    bv.commitBatchOperation();
   },
 
   supportsCommand: function(cmd) {
     var isSupported = false;
     switch (cmd) {
       case "cmd_fullscreen":
         isSupported = true;
         break;
@@ -1165,44 +984,22 @@ var Browser = {
   setVisibleRect: function setVisibleRect(rect) {
     let bv = this._browserView;
     let vis = bv.getVisibleRect();
     let zoomRatio = vis.width / rect.width;
     let zoomLevel = bv.getZoomLevel() * zoomRatio;
     let scrollX = rect.left * zoomRatio;
     let scrollY = rect.top * zoomRatio;
 
-    // The order of operations below is important for artifacting and for performance. Important
-    // side effects of functions are noted below.
-
-    // Hardware scrolling happens immediately when scrollTo is called.  Hide to prevent artifacts.
-    bv.beginOffscreenOperation(rect);
-
-    // We must scroll to the correct area before TileManager is informed of the change
-    // so that only one render is done. Ensures setZoomLevel puts it off.
-    bv.beginBatchOperation();
-
-    // Critical rect changes when controls are hidden. Must hide before tilemanager viewport.
     this.hideSidebars();
     this.hideTitlebar();
 
     bv.setZoomLevel(zoomLevel);
 
-    // Ensure container is big enough for scroll values.
-    bv.forceContainerResize();
-    this.forceChromeReflow();
     this.contentScrollboxScroller.scrollTo(scrollX, scrollY);
-    bv.onAfterVisibleMove();
-
-    // Inform tile manager, which happens to render new tiles too. Must call in case a batch
-    // operation was in progress before zoom.
-    bv.forceViewportChange();
-
-    bv.commitBatchOperation();
-    bv.commitOffscreenOperation();
   },
 
   zoomToPoint: function zoomToPoint(cX, cY, aRect) {
     let bv = this._browserView;
     if (!bv.allowZoom)
       return null;
 
     let zoomRect = null;
@@ -1226,60 +1023,60 @@ var Browser = {
       this.animatedZoomTo(zoomRect);
     }
   },
 
   /**
    * Transform x and y from client coordinates to BrowserView coordinates.
    */
   clientToBrowserView: function clientToBrowserView(x, y) {
-    let container = document.getElementById("tile-container");
+    let container = document.getElementById("browsers");
     let containerBCR = container.getBoundingClientRect();
 
     let x0 = Math.round(containerBCR.left);
     let y0;
     if (arguments.length > 1)
       y0 = Math.round(containerBCR.top);
 
     return (arguments.length > 1) ? [x - x0, y - y0] : (x - x0);
   },
 
   browserViewToClient: function browserViewToClient(x, y) {
-    let container = document.getElementById("tile-container");
+    let container = document.getElementById("browsers");
     let containerBCR = container.getBoundingClientRect();
 
     let x0 = Math.round(-containerBCR.left);
     let y0;
     if (arguments.length > 1)
       y0 = Math.round(-containerBCR.top);
 
     return (arguments.length > 1) ? [x - x0, y - y0] : (x - x0);
   },
 
   browserViewToClientRect: function browserViewToClientRect(rect) {
-    let container = document.getElementById("tile-container");
+    let container = document.getElementById("browsers");
     let containerBCR = container.getBoundingClientRect();
     return rect.clone().translate(Math.round(containerBCR.left), Math.round(containerBCR.top));
   },
 
   /**
    * turn client coordinates into page-relative ones (adjusted for
    * zoom and page position)
    */
   transformClientToBrowser: function transformClientToBrowser(cX, cY) {
     return this.clientToBrowserView(cX, cY).map(this._browserView.viewportToBrowser);
   },
 
   /**
    * Return the visible rect in coordinates with origin at the (left, top) of
-   * the tile container, i.e. BrowserView coordinates.
+   * the browser container, i.e. BrowserView coordinates.
    */
   getVisibleRect: function getVisibleRect() {
     let stack = document.getElementById("tile-stack");
-    let container = document.getElementById("tile-container");
+    let container = document.getElementById("browsers");
     let containerBCR = container.getBoundingClientRect();
 
     let x = Math.round(-containerBCR.left);
     let y = Math.round(-containerBCR.top);
     let w = window.innerWidth;
     let h = stack.getBoundingClientRect().height;
 
     return new Rect(x, y, w, h);
@@ -1338,61 +1135,51 @@ var Browser = {
 };
 
 
 Browser.MainDragger = function MainDragger(browserView) {
   this.bv = browserView;
 };
 
 Browser.MainDragger.prototype = {
-  isDraggable: function isDraggable(target, scroller) { return true; },
+  isDraggable: function isDraggable(target, scroller) {
+    return { xDraggable: true, yDraggable: true };
+  },
 
   dragStart: function dragStart(clientX, clientY, target, scroller) {
-    this._nextRender = Date.now() + 500;
-    this._dragMoved = false;
   },
 
   dragStop: function dragStop(dx, dy, scroller) {
     this.draggedFrame = null;
     this.dragMove(Browser.snapSidebars(), 0, scroller);
 
     Browser.tryUnfloatToolbar();
-
-    if (this._dragMoved)
-      this.bv.resumeRendering();
+    Browser.contentScrollboxScroller.flush();
   },
 
   dragMove: function dragMove(dx, dy, scroller) {
     let doffset = new Point(dx, dy);
 
     if (!this._dragMoved) {
       this._dragMoved = true;
-      this.bv.pauseRendering();
     }
 
     // First calculate any panning to take sidebars out of view
     let panOffset = this._panControlsAwayOffset(doffset);
 
     // Do content panning
     this._panScroller(Browser.contentScrollboxScroller, doffset);
 
     // Any leftover panning in doffset would bring controls into view. Add to sidebar
     // away panning for the total scroll offset.
     doffset.add(panOffset);
     Browser.tryFloatToolbar(doffset.x, 0);
     this._panScroller(Browser.controlsScrollboxScroller, doffset);
     this._panScroller(Browser.pageScrollboxScroller, doffset);
 
-    this.bv.onAfterVisibleMove();
-
-    if (Date.now() >= this._nextRender) {
-      this.bv.renderNow();
-      this._nextRender = Date.now() + 500;
-    }
-
     return !doffset.equals(dx, dy);
   },
 
   /** Return offset that pans controls away from screen. Updates doffset with leftovers. */
   _panControlsAwayOffset: function(doffset) {
     let x = 0, y = 0, rect;
 
     rect = Rect.fromRect(Browser.pageScrollbox.getBoundingClientRect()).map(Math.round);
@@ -1596,19 +1383,21 @@ ContentCustomClicker.prototype = {
     let [x, y] = Browser.transformClientToBrowser(aX, aY);
     browser.messageManager.sendAsyncMessage(aName, { x: x, y: y, modifiers: aModifiers });
   },
 
   mouseDown: function mouseDown(aX, aY) {
     // Ensure that the content process has gets an activate event
     let browser = this._browserView.getBrowser();
     let fl = browser.QueryInterface(Ci.nsIFrameLoaderOwner).frameLoader;
+    browser.focus();
     try {
       fl.activateRemoteFrame();
-    } catch (e) {}
+    } catch (e) {
+    }
     this._dispatchMouseEvent("Browser:MouseDown", aX, aY);
   },
 
   mouseUp: function mouseUp(aX, aY) {
   },
 
   panBegin: function panBegin() {
     TapHighlightHelper.hide();
@@ -1625,22 +1414,22 @@ ContentCustomClicker.prototype = {
     this._dispatchMouseEvent("Browser:MouseCancel");
   },
 
   doubleClick: function doubleClick(aX1, aY1, aX2, aY2) {
     TapHighlightHelper.hide();
 
     this._dispatchMouseEvent("Browser:MouseCancel");
 
-    const kDoubleClickRadius = 32;
+/*    const kDoubleClickRadius = 32;
 
     let maxRadius = kDoubleClickRadius * Browser._browserView.getZoomLevel();
     let isClickInRadius = (Math.abs(aX1 - aX2) < maxRadius && Math.abs(aY1 - aY2) < maxRadius);
     if (isClickInRadius)
-      this._dispatchMouseEvent("Browser:ZoomToPoint", aX1, aY1);
+      this._dispatchMouseEvent("Browser:ZoomToPoint", aX1, aY1); */
   },
 
   toString: function toString() {
     return "[ContentCustomClicker] { }";
   }
 };
 
 
@@ -2389,35 +2178,19 @@ ProgressController.prototype = {
     if (this._tab == Browser.selectedTab)
       BrowserUI.update(TOOLBARSTATE_LOADED);
 
     if (this.browser.currentURI.spec != "about:blank")
       this._tab.updateThumbnail();
   },
 
   _documentStop: function _documentStop() {
-    if (this._tab == Browser.selectedTab) {
-      // XXX Sometimes MozScrolledAreaChanged has not occurred, so the scroll pane will not
-      // be resized yet. We are assuming this event is on the queue, so scroll the pane
-      // "soon."
-      Util.executeSoon(function() {
-        let scroll = Browser.getScrollboxPosition(Browser.contentScrollboxScroller);
-        if (scroll.isZero())
-          Browser.scrollContentToBrowser(0, 0);
-      });
-    }
-    else {
-      // XXX: We don't know the current scroll position of the content, so assume
-      // it's at the top. This will be fixed by Layers
-      this._tab.contentScrollOffset = new Point(0, 0);
-
       // Make sure the URLbar is in view. If this were the selected tab,
       // onLocationChange would scroll to top.
       this._tab.pageScrollOffset = new Point(0, 0);
-    }
   }
 };
 
 var OfflineApps = {
   offlineAppRequested: function(aRequest) {
     if (!Services.prefs.getBoolPref("browser.offline-apps.notify"))
       return;
 
@@ -2583,54 +2356,38 @@ Tab.prototype = {
         viewportH = viewportW * (screenH / screenW);
       } else if (!validW && validH) {
         viewportW = viewportH * (screenW / screenH);
       } else {
         viewportW = kDefaultBrowserWidth;
         viewportH = kDefaultBrowserWidth * (screenH / screenW);
       }
 
-      browser.style.width = viewportW + "px";
-      browser.style.height = viewportH + "px";
+      browser.style.width = screenW /* XXX viewportW */ + "px";
+      browser.style.height = screenH /* XXX viewportH */ + "px";
     }
 
     // Local XUL documents are not firing MozScrolledAreaChanged
     let contentDocument = browser.contentDocument;
     if (contentDocument && contentDocument instanceof XULDocument) {
       let width = contentDocument.documentElement.scrollWidth;
       let height = contentDocument.documentElement.scrollHeight;
       BrowserView.Util.ensureMozScrolledAreaEvent(browser, width, height);
     }
   },
 
   startLoading: function startLoading() {
     if (this._loading) throw "Already Loading!";
 
     this._loading = true;
-
-    let bv = Browser._browserView;
-
-    if (this == Browser.selectedTab) {
-      bv.setAggressive(false);
-      // Sync up browser so previous and forward scroll positions are set. This is a good time to do
-      // this because the resulting invalidation is irrelevant.
-      bv.ignorePageScroll(true);
-      Browser.scrollBrowserToContent();
-    }
   },
 
   endLoading: function endLoading() {
     if (!this._loading) throw "Not Loading!";
     this._loading = false;
-
-    if (this == Browser.selectedTab) {
-      let bv = Browser._browserView;
-      bv.ignorePageScroll(false);
-      bv.setAggressive(true);
-    }
   },
 
   isLoading: function isLoading() {
     return this._loading;
   },
 
   create: function create(aURI) {
     // Initialize a viewport state for BrowserView
@@ -2649,23 +2406,22 @@ Tab.prototype = {
   _createBrowser: function _createBrowser(aURI) {
     if (this._browser)
       throw "Browser already exists";
 
     // Create the browser using the current width the dynamically size the height
     let browser = this._browser = document.createElement("browser");
     this._chromeTab.linkedBrowser = browser;
 
-    browser.setAttribute("style", "overflow: -moz-hidden-unscrollable; visibility: hidden;");
     browser.setAttribute("type", "content");
 
     let useRemote = Services.prefs.getBoolPref("browser.tabs.remote");
     let useLocal = Util.isLocalScheme(aURI);
     browser.setAttribute("remote", (!useLocal && useRemote) ? "true" : "false");
-    
+
     // Append the browser to the document, which should start the page load
     document.getElementById("browsers").appendChild(browser);
 
     // stop about:blank from loading
     browser.stop();
 
     // Attach a separate progress listener to the browser
     let flags = Ci.nsIWebProgress.NOTIFY_LOCATION |
@@ -2711,43 +2467,8 @@ Tab.prototype = {
     // even set yet. So fallback to something sane for now.
     this._chromeTab.updateThumbnail(this._browser, 800, 500);
   },
 
   toString: function() {
     return "[Tab " + (this._browser ? this._browser.currentURI.spec : "(no browser)") + "]";
   }
 };
-
-// Helper used to hide IPC / non-IPC differences for rendering to a canvas
-function rendererFactory(aBrowser, aCanvas) {
-  let wrapper = {};
-
-  if (aBrowser.contentWindow) {
-    let ctx = aCanvas.getContext("2d");
-    let draw = function(browser, aLeft, aTop, aWidth, aHeight, aColor, aFlags) {
-      ctx.drawWindow(browser.contentWindow, aLeft, aTop, aWidth, aHeight, aColor, aFlags);
-      let e = document.createEvent("HTMLEvents");
-      e.initEvent("MozAsyncCanvasRender", true, true);
-      aCanvas.dispatchEvent(e);
-    };
-    wrapper.checkBrowser = function(browser) {
-      return browser.contentWindow;
-    };
-    wrapper.drawContent = function(callback) {
-      callback(ctx, draw);
-    };
-  }
-  else {
-    let ctx = aCanvas.MozGetIPCContext("2d");
-    let draw = function(browser, aLeft, aTop, aWidth, aHeight, aColor, aFlags) {
-      ctx.asyncDrawXULElement(browser, aLeft, aTop, aWidth, aHeight, aColor, aFlags);
-    };
-    wrapper.checkBrowser = function(browser) {
-      return !browser.contentWindow;
-    };
-    wrapper.drawContent = function(callback) {
-      callback(ctx, draw);
-    };
-  }
-
-  return wrapper;
-}
--- a/mobile/chrome/content/browser.xul
+++ b/mobile/chrome/content/browser.xul
@@ -79,17 +79,16 @@
   <script type="application/javascript" src="chrome://browser/content/browser-ui.js"/>
   <script type="application/javascript" src="chrome://browser/content/sanitize.js"/>
   <script type="application/javascript" src="chrome://browser/content/preferences.js"/>
   <script type="application/javascript" src="chrome://browser/content/extensions.js"/>
   <script type="application/javascript" src="chrome://browser/content/downloads.js"/>
   <script type="application/javascript" src="chrome://browser/content/console.js"/>
   <script type="application/javascript" src="chrome://browser/content/Util.js"/>
   <script type="application/javascript" src="chrome://browser/content/InputHandler.js"/>
-  <script type="application/javascript" src="chrome://browser/content/TileManager.js"/>
   <script type="application/javascript" src="chrome://browser/content/BrowserView.js"/>
   <script type="application/javascript" src="chrome://browser/content/AnimatedZoom.js"/>
 #ifdef MOZ_SERVICES_SYNC
   <script type="application/javascript" src="chrome://browser/content/sync.js"/>
 #endif
 
   <stringbundleset id="stringbundleset">
     <stringbundle id="bundle_browser" src="chrome://browser/locale/browser.properties"/>
@@ -264,23 +263,20 @@
               </box>
             </box>
 
             <notificationbox id="notifications" class="window-width"/>
 
             <!-- Content viewport -->
             <vbox class="window-width window-height">
               <stack id="tile-stack" class="window-width" flex="1">
-                <scrollbox id="content-scrollbox" style="overflow: hidden;" class="window-width" flex="1">
-                  <!-- Content viewport -->
-                  <html:div id="tile-container" style="overflow: hidden;" tabindex="-1">
-                    <html:canvas id="content-overlay" style="display: none; position: absolute; z-index: 1000; left: 0; top: 0;">
-                    </html:canvas>
-                  </html:div>
-                </scrollbox>
+              <!-- Content viewport -->
+                <html:div id="browsers" style="overflow: hidden;"/>
+                <html:canvas id="content-overlay" style="display: none; position: absolute; z-index: 1000; left: 0; top: 0;">
+                </html:canvas>
                 <html:canvas id="view-buffer" style="display: none;" moz-opaque="true">
                 </html:canvas>
               </stack>
               <box id="content-navigator-spacer" hidden="true"/>
             </vbox>
           </vbox>
         </scrollbox>
 
@@ -581,15 +577,14 @@
         <label id="alerts-title" value=""/>
         <description id="alerts-text" flex="1"/>
       </vbox>
     </hbox>
   </stack>
 
   <box>
     <html:div style="position: relative; overflow: -moz-hidden-unscrollable; max-width: 0px; max-height: 0px; visibility: hidden;">
-      <html:div id="browsers" style="position: absolute;"/>
     </html:div>
   </box>
 
   <tooltip default="true" id="default-tooltip"/>
 
 </window>
--- a/mobile/chrome/content/content.css
+++ b/mobile/chrome/content/content.css
@@ -43,16 +43,20 @@
 * > *:not(embed):focus, * > *:focus > font {
   outline: 2px solid #8db8d8 !important;
   /*
     XXX How do I preserve mac focusring without blowing focus color on other platforms?
     outline-color: -moz-mac-focusring !important;
   */
 }
 
+html {
+  background: white;
+}
+
 *:link:focus, *:visited:focus {
   outline-offset: -2px;
 }
 
 /* Style the scrollbars */
 xul|scrollbar {
   -moz-appearance: none !important;
   display: none !important;
--- a/mobile/chrome/content/content.js
+++ b/mobile/chrome/content/content.js
@@ -206,24 +206,18 @@ function getContentClientRects(aElement)
                   height: r.height
                 });
   }
   return result;
 };
 
 /** Reponsible for sending messages about viewport size changes and painting. */
 function Coalescer() {
-  this._pendingDirtyRect = new Rect(0, 0, 0, 0);
   this._pendingSizeChange = null;
   this._timer = new Util.Timeout(this);
-
-  // XXX When moving back and forward in docShell history, MozAfterPaint does not get called properly and
-  // some dirty rectangles are never flagged properly.  To fix this, coalescer will fake a paint event that
-  // dirties the entire viewport.
-  this._incremental = false;
 }
 
 Coalescer.prototype = {
   start: function start() {
     this._emptyPage();
     this._timer.interval(1000);
   },
 
@@ -232,22 +226,16 @@ Coalescer.prototype = {
   },
 
   notify: function notify() {
     this.flush();
   },
 
   handleEvent: function handleEvent(aEvent) {
     switch (aEvent.type) {
-      case "MozAfterPaint": {
-        let win = aEvent.originalTarget;
-        let scrollOffset = Util.getScrollOffset(win);
-        this.dirty(scrollOffset, aEvent.clientRects);
-        break;
-      }
       case "MozScrolledAreaChanged": {
         // XXX if it's possible to get a scroll area change with the same values,
         // it would be optimal if this didn't send the same message twice.
         let doc = aEvent.originalTarget;
         let win = doc.defaultView;
         let scrollOffset = Util.getScrollOffset(win);
         if (win.parent != win) // We are only interested in root scroll pane changes
           return;
@@ -258,20 +246,16 @@ Coalescer.prototype = {
         let doc = aEvent.originalTarget;
         sendAsyncMessage("Browser:MozApplicationManifest", {
           location: doc.documentURIObject.spec,
           manifest: doc.documentElement.getAttribute("manifest"),
           charset: doc.characterSet
         });
         break;
       }
-      case "scroll":
-        let scroll = Util.getScrollOffset(content);
-        sendAsyncMessage("Browser:PageScroll", { scrollX: scroll.x, scrollY: scroll.y });
-        break;
     }
   },
 
   /** Next scroll size change event will invalidate all previous content. See constructor. */
   _emptyPage: function _emptyPage() {
     this._incremental = false;
   },
 
@@ -281,61 +265,25 @@ Coalescer.prototype = {
     // quadrants other than x > 0 && y > 0.
     x = x + scrollOffset.x;
     y = y + scrollOffset.y;
     this._pendingSizeChange = {
       width: width + (x < 0 ? x : 0),
       height: height + (y < 0 ? y : 0)
     };
 
-    // Clear any pending dirty rectangles since entire viewport will be invalidated
-    // anyways.
-    let rect = this._pendingDirtyRect;
-    rect.top = rect.bottom;
-    rect.left = rect.right;
-
     if (!this._timer.isPending())
       this.flush();
   },
 
-  dirty: function dirty(scrollOffset, clientRects) {
-    if (!this._pendingSizeChange) {
-      let unionRect = this._pendingDirtyRect;
-      for (let i = clientRects.length - 1; i >= 0; i--) {
-        let e = clientRects.item(i);
-        unionRect.expandToContain(new Rect(
-          e.left + scrollOffset.x, e.top + scrollOffset.y, e.width, e.height));
-      }
-
-      if (!this._timer.isPending())
-        this.flush();
-    }
-  },
-
   flush: function flush() {
-    let dirtyRect = this._pendingDirtyRect;
     let sizeChange = this._pendingSizeChange;
     if (sizeChange) {
       sendAsyncMessage("Browser:MozScrolledAreaChanged", { width: sizeChange.width, height: sizeChange.height });
-      if (!this._incremental)
-        sendAsyncMessage("Browser:MozAfterPaint", { rects: [ { left: 0, top: 0, right: sizeChange.width, bottom: sizeChange.height } ] });
-
       this._pendingSizeChange = null;
-
-      // After first size change has been issued, assume subsequent size changes are only incremental
-      // changes to the current page.
-      this._incremental = true;
-    }
-    else if (!dirtyRect.isEmpty()) {
-      // No size change has occurred, but areas have been dirtied.
-      sendAsyncMessage("Browser:MozAfterPaint", { rects: [dirtyRect] });
-
-      // Reset the rect to empty
-      dirtyRect.top = dirtyRect.bottom;
-      dirtyRect.left = dirtyRect.right;
     }
   }
 };
 
 
 /**
  * Responsible for sending messages about security, location, and page load state.
  * @param loadingController Object with methods startLoading and stopLoading
@@ -424,20 +372,24 @@ function Content() {
   addMessageListener("Browser:KeyEvent", this);
   addMessageListener("Browser:MouseDown", this);
   addMessageListener("Browser:MouseUp", this);
   addMessageListener("Browser:MouseCancel", this);
   addMessageListener("Browser:SaveAs", this);
   addMessageListener("Browser:ZoomToPoint", this);
 
   this._coalescer = new Coalescer();
-  addEventListener("MozAfterPaint", this._coalescer, false);
   addEventListener("MozScrolledAreaChanged", this._coalescer, false);
   addEventListener("MozApplicationManifest", this._coalescer, false);
-  addEventListener("scroll", this._coalescer, false);
+
+  addMessageListener("MozScrollBy", function(message) {
+    content.scrollBy(message.json.x, message.json.y);
+    let scroll = Util.getScrollOffset(content);
+    sendAsyncMessage("MozScrolled", scroll);
+  }, false);
 
   this._progressController = new ProgressController(this);
   this._progressController.start();
 
   this._formAssistant = new FormAssistant();
   this._overlayTimeout = new Util.Timeout();
   this._contextTimeout = new Util.Timeout();
 }
@@ -474,28 +426,28 @@ Content.prototype = {
             keyCode: json.keyCode,
             charCode: json.charCode
           });
         }
         break;
 
       case "Browser:MouseDown":
         this._overlayTimeout.clear();
-        this._overlayTimeout.clear();
 
         let element = elementFromPoint(x, y);
         if (!element)
           return;
 
-        if (element.mozMatchesSelector("*:link,*:visited,*:link *,*:visited *,*[role=button],button,input,option,select,textarea,label")) {
+// XXX somehow this always take up the entire screen
+/*        if (element.mozMatchesSelector("*:link,*:visited,*:link *,*:visited *,*[role=button],button,input,option,select,textarea,label")) {
           this._overlayTimeout.once(kTapOverlayTimeout, function() {
             let rects = getContentClientRects(element);
             sendAsyncMessage("Browser:Highlight", { rects: rects });
           });
-        }
+        } */
 
         // We add a few milliseconds because of how the InputHandler wait before
         // dispatching a single click (default: 500)
         this._contextTimeout.once(500 + 200, function() {
           let event = content.document.createEvent("PopupEvents");
           event.initEvent("contextmenu", true, true);
           element.dispatchEvent(event);
         });
--- a/mobile/chrome/content/tabs.xml
+++ b/mobile/chrome/content/tabs.xml
@@ -39,28 +39,22 @@
       </method>
 
       <method name="updateThumbnail">
         <parameter name="browser"/>
         <parameter name="width"/>
         <parameter name="height"/>
         <body>
           <![CDATA[
+            return;
             const tabWidth = 106;
             const tabHeight = 64;
 
             let canvas = document.getAnonymousElementByAttribute(this, "anonid", "canvas");
-            let renderer = rendererFactory(browser, canvas)
-            renderer.drawContent(function(ctx, callback) {
-              ctx.clearRect(0, 0, tabWidth, tabHeight);
-              ctx.save();
-              ctx.scale(tabWidth / width, tabHeight / height);
-              callback(browser, 0, 0, width, height, "white");
-              ctx.restore();
-            });
+            dump("Not implemented updateThumbnail\n");
           ]]>
         </body>
       </method>
     </implementation>
   </binding>
 
   <binding id="tablist">
     <implementation>
--- a/mobile/chrome/jar.mn
+++ b/mobile/chrome/jar.mn
@@ -35,17 +35,16 @@ chrome.jar:
   content/bindings/setting.xml         (content/bindings/setting.xml)
   content/browser.css                  (content/browser.css)
   content/cursor.css                   (content/cursor.css)
   content/content.css                  (content/content.css)
   content/checkerboard.png             (content/checkerboard.png)
 % content branding %content/branding/
   content/sanitize.js                  (content/sanitize.js)
 * content/BrowserView.js               (content/BrowserView.js)
-  content/TileManager.js               (TileManager.js)
 * content/InputHandler.js              (content/InputHandler.js)
 * content/Util.js                      (content/Util.js)
   content/forms.js                     (content/forms.js)
 * content/preferences.js               (content/preferences.js)
   content/exceptions.js                (content/exceptions.js)
   content/extensions.js                (content/extensions.js)
   content/downloads.js                 (content/downloads.js)
   content/console.js                   (content/console.js)
--- a/mobile/themes/core/browser.css
+++ b/mobile/themes/core/browser.css
@@ -30,21 +30,16 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
-/* browser area -------------------------------------------------- */
-#tile-container {
-  background-image: url("chrome://browser/content/checkerboard.png");
-}
-
 /* main toolbar (URL bar) -------------------------------------------------- */
 #toolbar-main {
   -moz-appearance: none;
   -moz-box-align: center;
   padding: 4px 8px; /* half core spacing & core spacing */
   border: none;
 }