Bug 572214 - [e10s] Add support for remote and local rendering [r=vingtetun]
authorMark Finkle <mfinkle@mozilla.com>
Wed, 16 Jun 2010 10:47:13 -0400
changeset 66293 bdd353e67e8a5cefde98fef6f2db403631cf45be
parent 66292 5567c80b6eb51391c4720c0feaa03aad7ccef168
child 66294 f96a7037c7e17d0976adf49446e677e862fdc9fc
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)
reviewersvingtetun
bugs572214
Bug 572214 - [e10s] Add support for remote and local rendering [r=vingtetun]
mobile/app/mobile.js
mobile/chrome/content/BrowserView.js
mobile/chrome/content/TileManager.js.in
mobile/chrome/content/browser.js
--- a/mobile/app/mobile.js
+++ b/mobile/app/mobile.js
@@ -36,16 +36,17 @@
 
 #filter substitution
 
 pref("toolkit.defaultChromeURI", "chrome://browser/content/browser.xul");
 pref("general.useragent.extra.mobile", "@APP_UA_NAME_EXTRA@/@APP_VERSION_EXTRA@ Fennec/@APP_VERSION@");
 pref("browser.chromeURL", "chrome://browser/content/");
 
 pref("browser.tabs.warnOnClose", true);
+pref("browser.tabs.remote", false);
 
 pref("toolkit.screen.lock", false);
 
 // From libpref/src/init/all.js, extended to allow a slightly wider zoom range.
 pref("zoom.minPercent", 20);
 pref("zoom.maxPercent", 400);
 pref("toolkit.zoomManager.zoomValues", ".2,.3,.5,.67,.8,.9,1,1.1,1.2,1.33,1.5,1.7,2,2.4,3,4");
 pref("zoom.dpiScale", 150);
--- a/mobile/chrome/content/BrowserView.js
+++ b/mobile/chrome/content/BrowserView.js
@@ -475,18 +475,22 @@ BrowserView.prototype = {
     let browserChanged = (oldBrowser !== browser);
 
     if (oldBrowser) {
       oldBrowser.setAttribute("type", "content");
       oldBrowser.messageManager.sendAsyncMessage("Browser:Blur", {});
     }
 
     this._browser = browser;
-    this._contentWindow = (browser) ? browser.contentWindow : null;
     this._browserViewportState = browserViewportState;
+    try {
+      this._contentWindow = browser.contentWindow;
+    } catch(e) {
+      this._contentWindow = null;
+    }
 
     if (browser) {
       browser.setAttribute("type", "content-primary");
       browser.messageManager.sendAsyncMessage("Browser:Focus", {});
 
       this.beginBatchOperation();
 
       if (browserChanged)
@@ -793,22 +797,16 @@ BrowserView.prototype = {
     this._applyViewportChanges(viewportSizeChanged, dirtyAll);
   },
 
   _applyViewportChanges: function _applyViewportChanges(viewportSizeChanged, dirtyAll) {
     let bvs = this._browserViewportState;
     if (bvs) {
       BrowserView.Util.resizeContainerToViewport(this._container, bvs.viewportRect);
 
-      if (dirtyAll) {
-        // We're about to mark the entire viewport dirty, so we can clear any
-        // queued afterPaint events that will cause redundant draws
-        BrowserView.Util.getBrowserDOMWindowUtils(this._browser).clearMozAfterPaintEvents();
-      }
-
       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);
--- a/mobile/chrome/content/TileManager.js.in
+++ b/mobile/chrome/content/TileManager.js.in
@@ -94,16 +94,36 @@ const kXHTMLNamespaceURI  = "http://www.
 // 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
 
+// Helper used to hide IPC / non-IPC differences for renering to a canvas
+function rendererFactory(isRemote, aCanvas, aBrowser) {
+  if (isRemote) {
+    let wrapper = {};
+    wrapper.ctx = aCanvas.MozGetIPCContext("2d");
+    wrapper.drawContent = function(aLeft, aTop, aWidth, aHeight, aColor, aFlags) {
+      this.ctx.asyncDrawXULElement(aBrowser, aLeft, aTop, aWidth, aHeight, aColor, aFlags);
+    };
+    return wrapper;
+  }
+
+  let wrapper = {};
+  wrapper.ctx = aCanvas.getContext("2d");
+  wrapper.drawContent = function(aLeft, aTop, aWidth, aHeight, aColor, aFlags) {
+    this.ctx.drawWindow(aBrowser.contentWindow, aLeft, aTop, aWidth, aHeight, aColor, aFlags);
+  };
+  return wrapper;
+}
+
+
 /**
  * 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
@@ -370,86 +390,42 @@ TileManager.prototype = {
   /** 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.  We attempt to avoid a
-   * drawWindow() by copying the image (via drawImage()) from  cached tiles, we
-   * may have.  If we find that we're missing a necessary tile, we fall back on
-   * drawWindow() directly to the destination canvas.
+   * 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 ctx = destCanvas.getContext("2d");
-    drawMissing = drawMissing == false ? false : true;
-    if (!drawMissing) {
-      let pat = ctx.createPattern(this._checkerboard, "repeat");
-      ctx.fillStyle = pat;
-      ctx.fillRect(0, 0, destCanvas.width, destCanvas.height);
-    }
+
+    let renderer = rendererFactory(!bv._contentWindow, destCanvas, bv._browser);
+    let ctx = renderer.ctx;
+
+    bv.viewportToBrowserRect(srcRect);
+
     ctx.save();
+    bv.browserToViewportCanvasContext(ctx);
     ctx.scale(scalex, scaley);
-    ctx.translate(-srcRect.left, -srcRect.top);
-    
-    let completed = (function breakableLoop() {
-      BEGIN_FOREACH_IN_RECT(srcRect, tc, tile)
 
-      if (drawMissing && tile.isDirty()) {
-        return false;
-      } else if (!tile.isDirty()) {
-        // We expand the rect to work around a gfx issue (bug 556046)
-        ctx.drawImage(tile._canvas, tile.boundRect.left, tile.boundRect.top,
-                      kTileWidth + 8, kTileHeight + 8);
-      }
-      
-      END_FOREACH_IN_RECT
-
-      return true;
-    })();
+    renderer.drawContent(srcRect.left, srcRect.top, srcRect.width, srcRect.height,
+                   "white",
+                   (ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_CARET));
 
     ctx.restore();
-    
-    if (!completed) {
-      let bv = this._browserView;
-
-      bv.viewportToBrowserRect(srcRect);
-
-      ctx.save();
-
-      bv.browserToViewportCanvasContext(ctx);
-      ctx.scale(scalex, scaley);
-      ctx.drawWindow(bv._contentWindow,
-                     srcRect.left, srcRect.top, srcRect.width, srcRect.height,
-                     "white",
-                     (ctx.DRAWWINDOW_DO_NOT_FLUSH | ctx.DRAWWINDOW_DRAW_CARET));
-
-      ctx.restore();
-    }
   },
 
   _showTile: function _showTile(tile) {
-    if (tile.isDirty()) {
-/*
-      let ctx = tile._canvas.getContext("2d");
-      ctx.save();
-      ctx.fillStyle = "rgba(0,255,0,.5)";
-      ctx.translate(-tile.boundRect.left, -tile.boundRect.top);
-      ctx.fillRect(tile._dirtyTileCanvasRect.left, tile._dirtyTileCanvasRect.top,
-        tile._dirtyTileCanvasRect.width, tile._dirtyTileCanvasRect.height);
-      ctx.restore();
-      window.setTimeout(function(bv) {
-        tile.render(bv);
-      }, 1000, this._browserView);
- */
+    if (tile.isDirty())
       tile.render(this._browserView);
-    }
+
     this._appendTileSafe(tile);
   },
 
   _appendTileSafe: function _appendTileSafe(tile) {
     if (!tile.appended) {
       this._appendTile(tile);
       tile.appended = true;
     }
@@ -796,25 +772,25 @@ TileManager.Tile.prototype = {
       this.markDirty();
 
     let rect = this._dirtyTileCanvasRect;
     let x = rect.left - this.boundRect.left;
     let y = rect.top - this.boundRect.top;
 
     browserView.viewportToBrowserRect(rect);
 
-    let ctx = this._canvas.getContext("2d");
+    let renderer = rendererFactory(!browserView._contentWindow, this._canvas, browserView._browser);
+    let ctx = renderer.ctx;
+
     ctx.save();
-
     ctx.translate(x, y);
     browserView.browserToViewportCanvasContext(ctx);
+
     // We expand the rect to working around a gfx issue (bug 534054)
-    ctx.drawWindow(browserView._contentWindow,
-                   rect.left , rect.top,
-                   rect.right - rect.left + 1, rect.bottom - rect.top + 1,
+    renderer.drawContent(rect.left , rect.top, rect.right - rect.left + 1, rect.bottom - rect.top + 1,
                    "white",
                    (ctx.DRAWWINDOW_DRAW_CARET));
 
     ctx.restore();
 
     this.unmarkDirty();
   },
 
--- a/mobile/chrome/content/browser.js
+++ b/mobile/chrome/content/browser.js
@@ -2161,17 +2161,17 @@ IdentityHandler.prototype = {
     return this._lastStatus.serverCert;
   },
 
   /**
    * Determine the identity of the page being displayed by examining its SSL cert
    * (if available) and, if necessary, update the UI to reflect this.
    */
   checkIdentity: function() {
-    let browser= getBrowser();
+    let browser = getBrowser();
     let state = browser.securityUI.state;
     let location = browser.currentURI;
     let currentStatus = browser.securityUI.SSLStatus;
 
     this._lastStatus = currentStatus;
     this._lastLocation = {};
 
     try {
@@ -3160,17 +3160,19 @@ Tab.prototype = {
     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");
 
     browser.setAttribute("style", "overflow: -moz-hidden-unscrollable; visibility: hidden;");
     browser.setAttribute("type", "content");
-    browser.setAttribute("remote", "false");
+
+    let useRemote = gPrefService.getBoolPref("browser.tabs.remote");
+    browser.setAttribute("remote", 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