author | Wes Kocher <wkocher@mozilla.com> |
Fri, 17 Oct 2014 18:33:34 -0700 | |
changeset 211225 | 5e9facc28af97e0f98e616c6a0856b621180fc98 |
parent 211224 | d8d5e2acfb7688fed3f70b9448ec74c90037cbde |
child 211226 | 37e5f630049bf37946698295a681b9d6a9a7140e |
push id | 1 |
push user | root |
push date | Mon, 20 Oct 2014 17:29:22 +0000 |
bugs | 698371 |
milestone | 36.0a1 |
backs out | 6c6d420a3acc312920562e4fa8133d4f93fdfec2 81378dee5a62a3c03006823121fda71fc21b12d4 d004bfd7f706abd404ec50881dfc388b312258e8 17bbdeffa8a63c894023012e61cd85508059c398 |
--- a/browser/base/content/browser-tabPreviews.js +++ b/browser/base/content/browser-tabPreviews.js @@ -42,16 +42,20 @@ var tabPreviews = { img.src = PageThumbs.getThumbnailURL(uri); return img; } return this.capture(aTab, !aTab.hasAttribute("busy")); }, capture: function tabPreviews_capture(aTab, aShouldCache) { + // Bug 863512 - Make page thumbnails work in electrolysis + if (gMultiProcessBrowser) + return new Image(); + let browser = aTab.linkedBrowser; let uri = browser.currentURI.spec; // FIXME: The gBrowserThumbnails._shouldCapture determines whether // thumbnails should be written to disk. This should somehow be part // of the PageThumbs API. (bug 1062414) if (aShouldCache && gBrowserThumbnails._shouldCapture(browser)) { @@ -68,17 +72,17 @@ var tabPreviews = { let canvas = PageThumbs.createCanvas(window); if (aShouldCache) { aTab.__thumbnail = canvas; aTab.__thumbnail_lastURI = uri; } - PageThumbs.captureToCanvas(browser, canvas); + PageThumbs.captureToCanvas(aTab.linkedBrowser.contentWindow, canvas); return canvas; }, handleEvent: function tabPreviews_handleEvent(event) { switch (event.type) { case "TabSelect": if (this._selectedTab && this._selectedTab.parentNode &&
--- a/browser/base/content/browser-thumbnails.js +++ b/browser/base/content/browser-thumbnails.js @@ -28,31 +28,39 @@ let gBrowserThumbnails = { _timeouts: null, /** * List of tab events we want to listen for. */ _tabEvents: ["TabClose", "TabSelect"], init: function Thumbnails_init() { + // Bug 863512 - Make page thumbnails work in electrolysis + if (gMultiProcessBrowser) + return; + PageThumbs.addExpirationFilter(this); gBrowser.addTabsProgressListener(this); Services.prefs.addObserver(this.PREF_DISK_CACHE_SSL, this, false); this._sslDiskCacheEnabled = Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL); this._tabEvents.forEach(function (aEvent) { gBrowser.tabContainer.addEventListener(aEvent, this, false); }, this); this._timeouts = new WeakMap(); }, uninit: function Thumbnails_uninit() { + // Bug 863512 - Make page thumbnails work in electrolysis + if (gMultiProcessBrowser) + return; + PageThumbs.removeExpirationFilter(this); gBrowser.removeTabsProgressListener(this); Services.prefs.removeObserver(this.PREF_DISK_CACHE_SSL, this); this._tabEvents.forEach(function (aEvent) { gBrowser.tabContainer.removeEventListener(aEvent, this, false); }, this); }, @@ -112,41 +120,41 @@ let gBrowserThumbnails = { this._capture(aBrowser); }.bind(this), this._captureDelayMS); this._timeouts.set(aBrowser, timeout); }, // FIXME: This should be part of the PageThumbs API. (bug 1062414) _shouldCapture: function Thumbnails_shouldCapture(aBrowser) { + // Don't try to capture in e10s yet (because of bug 698371) + if (gMultiProcessBrowser) + return false; + // Capture only if it's the currently selected tab. if (aBrowser != gBrowser.selectedBrowser) return false; // Don't capture in per-window private browsing mode. if (PrivateBrowsingUtils.isWindowPrivate(window)) return false; let doc = aBrowser.contentDocument; // FIXME Bug 720575 - Don't capture thumbnails for SVG or XML documents as // that currently regresses Talos SVG tests. if (doc instanceof SVGDocument || doc instanceof XMLDocument) return false; - // Don't take screenshots of about: pages. - if (aBrowser.currentURI.schemeIs("about")) + // There's no point in taking screenshot of loading pages. + if (aBrowser.docShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE) return false; - // FIXME e10s work around, we need channel information. bug 1073957 - if (!aBrowser.docShell) - return true; - - // There's no point in taking screenshot of loading pages. - if (aBrowser.docShell.busyFlags != Ci.nsIDocShell.BUSY_FLAGS_NONE) + // Don't take screenshots of about: pages. + if (aBrowser.currentURI.schemeIs("about")) return false; let channel = aBrowser.docShell.currentDocumentChannel; // No valid document channel. We shouldn't take a screenshot. if (!channel) return false;
--- a/browser/base/content/socialchat.xml +++ b/browser/base/content/socialchat.xml @@ -702,17 +702,17 @@ // canvas size (in CSS pixels) to the window's backing resolution in order // to get a full-resolution drag image for use on HiDPI displays. let windowUtils = window.getInterface(Ci.nsIDOMWindowUtils); let scale = windowUtils.screenPixelsPerCSSPixel / windowUtils.fullZoom; let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); canvas.mozOpaque = true; canvas.width = 160 * scale; canvas.height = 90 * scale; - PageThumbs.captureToCanvas(chatbox, canvas); + PageThumbs.captureToCanvas(chatbox.contentWindow, canvas); dt.setDragImage(canvas, -16 * scale, -16 * scale); event.stopPropagation(); ]]></handler> <handler event="dragend"><![CDATA[ let dt = event.dataTransfer; let draggedChat = dt.mozGetDataAt("application/x-moz-chatbox", 0);
--- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -4525,17 +4525,17 @@ let windowUtils = window.getInterface(Ci.nsIDOMWindowUtils); let scale = windowUtils.screenPixelsPerCSSPixel / windowUtils.fullZoom; let canvas = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); canvas.mozOpaque = true; canvas.width = 160 * scale; canvas.height = 90 * scale; if (!gMultiProcessBrowser) { // Bug 863512 - Make page thumbnails work in e10s - PageThumbs.captureToCanvas(browser, canvas); + PageThumbs.captureToCanvas(browser.contentWindow, canvas); } dt.setDragImage(canvas, -16 * scale, -16 * scale); // _dragData.offsetX/Y give the coordinates that the mouse should be // positioned relative to the corner of the new window created upon // dragend such that the mouse appears to have the same position // relative to the corner of the dragged tab. function clientX(ele) ele.getBoundingClientRect().left;
--- a/browser/components/tabview/tabitems.js +++ b/browser/components/tabview/tabitems.js @@ -1378,19 +1378,25 @@ TabCanvas.prototype = Utils.extend(new S // ---------- // Function: paint paint: function TabCanvas_paint(evt) { var w = this.canvas.width; var h = this.canvas.height; if (!w || !h) return; - gPageThumbnails.captureToCanvas(this.tab.linkedBrowser, this.canvas, () => { - this._sendToSubscribers("painted"); - }); + if (!this.tab.linkedBrowser.contentWindow) { + Utils.log('no tab.linkedBrowser.contentWindow in TabCanvas.paint()'); + return; + } + + let win = this.tab.linkedBrowser.contentWindow; + gPageThumbnails.captureToCanvas(win, this.canvas); + + this._sendToSubscribers("painted"); }, // ---------- // Function: toImageData toImageData: function TabCanvas_toImageData() { return this.canvas.toDataURL("image/png"); } });
deleted file mode 100644 --- a/toolkit/components/thumbnails/PageThumbUtils.jsm +++ /dev/null @@ -1,105 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, you can obtain one at http://mozilla.org/MPL/2.0/. */ - -/* - * Common thumbnailing routines used by various consumers, including - * PageThumbs and backgroundPageThumbsContent. - */ - -this.EXPORTED_SYMBOLS = ["PageThumbUtils"]; - -const { classes: Cc, interfaces: Ci, utils: Cu } = Components; - -Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); -Cu.import("resource://gre/modules/Services.jsm"); -Cu.import("resource://gre/modules/Promise.jsm", this); - -this.PageThumbUtils = { - // The default background color for page thumbnails. - THUMBNAIL_BG_COLOR: "#fff", - // The namespace for thumbnail canvas elements. - HTML_NAMESPACE: "http://www.w3.org/1999/xhtml", - - /** - * Creates a new canvas element in the context of aWindow, or if aWindow - * is undefined, in the context of hiddenDOMWindow. - * - * @param aWindow (optional) The document of this window will be used to - * create the canvas. If not given, the hidden window will be used. - * @return The newly created canvas. - */ - createCanvas: function (aWindow) { - let doc = (aWindow || Services.appShell.hiddenDOMWindow).document; - let canvas = doc.createElementNS(this.HTML_NAMESPACE, "canvas"); - canvas.mozOpaque = true; - canvas.mozImageSmoothingEnabled = true; - let [thumbnailWidth, thumbnailHeight] = this.getThumbnailSize(); - canvas.width = thumbnailWidth; - canvas.height = thumbnailHeight; - return canvas; - }, - - /** - * Calculates a preferred initial thumbnail size based on current desktop - * dimensions. The resulting dims will generally be about 1/3 the - * size of the desktop. (jimm: why??) - * - * @return The calculated thumbnail size or a default if unable to calculate. - */ - getThumbnailSize: function () { - if (!this._thumbnailWidth || !this._thumbnailHeight) { - let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"] - .getService(Ci.nsIScreenManager); - let left = {}, top = {}, width = {}, height = {}; - screenManager.primaryScreen.GetRectDisplayPix(left, top, width, height); - this._thumbnailWidth = Math.round(width.value / 3); - this._thumbnailHeight = Math.round(height.value / 3); - } - return [this._thumbnailWidth, this._thumbnailHeight]; - }, - - /** - * Determine a good thumbnail crop size and scale for a given content - * window. - * - * @param aWindow The content window. - * @param aCanvas The target canvas. - * @return An array containing width, height and scale. - */ - determineCropSize: function (aWindow, aCanvas) { - if (Cu.isCrossProcessWrapper(aWindow)) { - throw new Error('Do not pass cpows here.'); - } - let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) - .getInterface(Ci.nsIDOMWindowUtils); - // aWindow may be a cpow, add exposed props security values. - let sbWidth = {}, sbHeight = {}; - - try { - utils.getScrollbarSize(false, sbWidth, sbHeight); - } catch (e) { - // This might fail if the window does not have a presShell. - Cu.reportError("Unable to get scrollbar size in determineCropSize."); - sbWidth.value = sbHeight.value = 0; - } - - // Even in RTL mode, scrollbars are always on the right. - // So there's no need to determine a left offset. - let width = aWindow.innerWidth - sbWidth.value; - let height = aWindow.innerHeight - sbHeight.value; - - let {width: thumbnailWidth, height: thumbnailHeight} = aCanvas; - let scale = Math.min(Math.max(thumbnailWidth / width, thumbnailHeight / height), 1); - let scaledWidth = width * scale; - let scaledHeight = height * scale; - - if (scaledHeight > thumbnailHeight) - height -= Math.floor(Math.abs(scaledHeight - thumbnailHeight) * scale); - - if (scaledWidth > thumbnailWidth) - width -= Math.floor(Math.abs(scaledWidth - thumbnailWidth) * scale); - - return [width, height, scale]; - } -};
--- a/toolkit/components/thumbnails/PageThumbs.jsm +++ b/toolkit/components/thumbnails/PageThumbs.jsm @@ -5,34 +5,38 @@ "use strict"; this.EXPORTED_SYMBOLS = ["PageThumbs", "PageThumbsStorage"]; const Cu = Components.utils; const Cc = Components.classes; const Ci = Components.interfaces; +const HTML_NAMESPACE = "http://www.w3.org/1999/xhtml"; const PREF_STORAGE_VERSION = "browser.pagethumbnails.storage_version"; const LATEST_STORAGE_VERSION = 3; const EXPIRATION_MIN_CHUNK_SIZE = 50; const EXPIRATION_INTERVAL_SECS = 3600; -var gRemoteThumbId = 0; - // If a request for a thumbnail comes in and we find one that is "stale" // (or don't find one at all) we automatically queue a request to generate a // new one. const MAX_THUMBNAIL_AGE_SECS = 172800; // 2 days == 60*60*24*2 == 172800 secs. /** * Name of the directory in the profile that contains the thumbnails. */ const THUMBNAIL_DIRECTORY = "thumbnails"; +/** + * The default background color for page thumbnails. + */ +const THUMBNAIL_BG_COLOR = "#fff"; + Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); Cu.import("resource://gre/modules/PromiseWorker.jsm", this); Cu.import("resource://gre/modules/Promise.jsm", this); Cu.import("resource://gre/modules/osfile.jsm", this); XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); @@ -60,18 +64,16 @@ XPCOMUtils.defineLazyGetter(this, "gUnic }); XPCOMUtils.defineLazyModuleGetter(this, "Task", "resource://gre/modules/Task.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Deprecated", "resource://gre/modules/Deprecated.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown", "resource://gre/modules/AsyncShutdown.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "PageThumbUtils", - "resource://gre/modules/PageThumbUtils.jsm"); /** * Utilities for dealing with promises and Task.jsm */ const TaskUtils = { /** * Read the bytes from a blob, asynchronously. * @@ -161,195 +163,123 @@ this.PageThumbs = { * @param aUrl The web page's url. * @return The path of the thumbnail file. */ getThumbnailPath: function PageThumbs_getThumbnailPath(aUrl) { return PageThumbsStorage.getFilePathForURL(aUrl); }, /** - * Asynchronously returns a thumbnail as a blob for the given - * window. + * Captures a thumbnail for the given window. + * @param aWindow The DOM window to capture a thumbnail from. + * @param aCallback The function to be called when the thumbnail has been + * captured. The first argument will be the data stream + * containing the image data. + */ + capture: function PageThumbs_capture(aWindow, aCallback) { + if (!this._prefEnabled()) { + return; + } + + let canvas = this.createCanvas(); + this.captureToCanvas(aWindow, canvas); + + // Fetch the canvas data on the next event loop tick so that we allow + // some event processing in between drawing to the canvas and encoding + // its data. We want to block the UI as short as possible. See bug 744100. + Services.tm.currentThread.dispatch(function () { + canvas.mozFetchAsStream(aCallback, this.contentType); + }.bind(this), Ci.nsIThread.DISPATCH_NORMAL); + }, + + + /** + * Captures a thumbnail for the given window. * - * @param aBrowser The <browser> to capture a thumbnail from. + * @param aWindow The DOM window to capture a thumbnail from. * @return {Promise} * @resolve {Blob} The thumbnail, as a Blob. */ - captureToBlob: function PageThumbs_captureToBlob(aBrowser) { + captureToBlob: function PageThumbs_captureToBlob(aWindow) { if (!this._prefEnabled()) { return null; } - let deferred = Promise.defer(); + let canvas = this.createCanvas(); + this.captureToCanvas(aWindow, canvas); - let canvas = this.createCanvas(); - this.captureToCanvas(aBrowser, canvas, () => { - canvas.toBlob(blob => { - deferred.resolve(blob, this.contentType); - }); + let deferred = Promise.defer(); + let type = this.contentType; + // Fetch the canvas data on the next event loop tick so that we allow + // some event processing in between drawing to the canvas and encoding + // its data. We want to block the UI as short as possible. See bug 744100. + canvas.toBlob(function asBlob(blob) { + deferred.resolve(blob, type); }); - return deferred.promise; }, /** * Captures a thumbnail from a given window and draws it to the given canvas. - * Note, when dealing with remote content, this api draws into the passed - * canvas asynchronously. Pass aCallback to receive an async callback after - * canvas painting has completed. - * @param aBrowser The browser to capture a thumbnail from. + * @param aWindow The DOM window to capture a thumbnail from. * @param aCanvas The canvas to draw to. - * @param aCallback (optional) A callback invoked once the thumbnail has been - * rendered to aCanvas. */ - captureToCanvas: function PageThumbs_captureToCanvas(aBrowser, aCanvas, aCallback) { + captureToCanvas: function PageThumbs_captureToCanvas(aWindow, aCanvas) { let telemetryCaptureTime = new Date(); - this._captureToCanvas(aBrowser, aCanvas, function () { - Services.telemetry - .getHistogramById("FX_THUMBNAILS_CAPTURE_TIME_MS") - .add(new Date() - telemetryCaptureTime); - if (aCallback) { - aCallback(aCanvas); - } - }); + this._captureToCanvas(aWindow, aCanvas); + let telemetry = Services.telemetry; + telemetry.getHistogramById("FX_THUMBNAILS_CAPTURE_TIME_MS") + .add(new Date() - telemetryCaptureTime); }, // The background thumbnail service captures to canvas but doesn't want to // participate in this service's telemetry, which is why this method exists. - _captureToCanvas: function (aBrowser, aCanvas, aCallback) { - if (aBrowser.isRemoteBrowser) { - Task.spawn(function () { - let data = - yield this._captureRemoteThumbnail(aBrowser, aCanvas); - let canvas = data.thumbnail; - let ctx = canvas.getContext("2d"); - let imgData = ctx.getImageData(0, 0, canvas.width, canvas.height); - aCanvas.getContext("2d").putImageData(imgData, 0, 0); - if (aCallback) { - aCallback(aCanvas); - } - }.bind(this)); - return; - } - - // Generate in-process content thumbnail - let [width, height, scale] = - PageThumbUtils.determineCropSize(aBrowser.contentWindow, aCanvas); + _captureToCanvas: function PageThumbs__captureToCanvas(aWindow, aCanvas) { + let [sw, sh, scale] = this._determineCropSize(aWindow, aCanvas); let ctx = aCanvas.getContext("2d"); // Scale the canvas accordingly. ctx.save(); ctx.scale(scale, scale); try { // Draw the window contents to the canvas. - ctx.drawWindow(aBrowser.contentWindow, 0, 0, width, height, - PageThumbUtils.THUMBNAIL_BG_COLOR, + ctx.drawWindow(aWindow, 0, 0, sw, sh, THUMBNAIL_BG_COLOR, ctx.DRAWWINDOW_DO_NOT_FLUSH); } catch (e) { // We couldn't draw to the canvas for some reason. } + ctx.restore(); - - if (aCallback) { - aCallback(aCanvas); - } }, /** - * Asynchrnously render an appropriately scaled thumbnail to canvas. - * - * @param aBrowser The browser to capture a thumbnail from. - * @param aCanvas The canvas to draw to. - * @return a promise - */ - _captureRemoteThumbnail: function (aBrowser, aCanvas) { - let deferred = Promise.defer(); - - // The index we send with the request so we can identify the - // correct response. - let index = gRemoteThumbId++; - - // Thumbnail request response handler - let mm = aBrowser.messageManager; - - // Browser:Thumbnail:Response handler - let thumbFunc = function (aMsg) { - // Ignore events unrelated to our request - if (aMsg.data.id != index) { - return; - } - - mm.removeMessageListener("Browser:Thumbnail:Response", thumbFunc); - let imageBlob = aMsg.data.thumbnail; - let doc = aBrowser.parentElement.ownerDocument; - let reader = Cc["@mozilla.org/files/filereader;1"]. - createInstance(Ci.nsIDOMFileReader); - reader.addEventListener("loadend", function() { - let image = doc.createElementNS(PageThumbUtils.HTML_NAMESPACE, "img"); - image.onload = function () { - let thumbnail = doc.createElementNS(PageThumbUtils.HTML_NAMESPACE, "canvas"); - thumbnail.width = image.naturalWidth; - thumbnail.height = image.naturalHeight; - let ctx = thumbnail.getContext("2d"); - ctx.drawImage(image, 0, 0); - deferred.resolve({ - thumbnail: thumbnail - }); - } - image.src = reader.result; - }); - // xxx wish there was a way to skip this encoding step - reader.readAsDataURL(imageBlob); - } - - // Send a thumbnail request - mm.addMessageListener("Browser:Thumbnail:Response", thumbFunc); - mm.sendAsyncMessage("Browser:Thumbnail:Request", { - canvasWidth: aCanvas.width, - canvasHeight: aCanvas.height, - background: PageThumbUtils.THUMBNAIL_BG_COLOR, - id: index - }); - - return deferred.promise; - }, - - /** * Captures a thumbnail for the given browser and stores it to the cache. * @param aBrowser The browser to capture a thumbnail for. * @param aCallback The function to be called when finished (optional). */ captureAndStore: function PageThumbs_captureAndStore(aBrowser, aCallback) { if (!this._prefEnabled()) { return; } let url = aBrowser.currentURI.spec; - let originalURL; - let channelError = false; + let channel = aBrowser.docShell.currentDocumentChannel; + let originalURL = channel.originalURI.spec; - if (!aBrowser.isRemoteBrowser) { - let channel = aBrowser.docShell.currentDocumentChannel; - originalURL = channel.originalURI.spec; - // see if this was an error response. - channelError = this._isChannelErrorResponse(channel); - } else { - // We need channel info (bug 1073957) - originalURL = url; - } + // see if this was an error response. + let wasError = this._isChannelErrorResponse(channel); Task.spawn((function task() { let isSuccess = true; try { - let blob = yield this.captureToBlob(aBrowser); + let blob = yield this.captureToBlob(aBrowser.contentWindow); let buffer = yield TaskUtils.readBlob(blob); - yield this._store(originalURL, url, buffer, channelError); - } catch (ex) { - Components.utils.reportError("Exception thrown during thumbnail capture: '" + ex + "'"); + yield this._store(originalURL, url, buffer, wasError); + } catch (_) { isSuccess = false; } if (aCallback) { aCallback(isSuccess); } }).bind(this)); }, @@ -440,23 +370,84 @@ this.PageThumbs = { * Unregister an expiration filter. * @param aFilter A filter that was previously passed to addExpirationFilter. */ removeExpirationFilter: function PageThumbs_removeExpirationFilter(aFilter) { PageThumbsExpiration.removeFilter(aFilter); }, /** + * Determines the crop size for a given content window. + * @param aWindow The content window. + * @param aCanvas The target canvas. + * @return An array containing width, height and scale. + */ + _determineCropSize: function PageThumbs_determineCropSize(aWindow, aCanvas) { + let utils = aWindow.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + let sbWidth = {}, sbHeight = {}; + + try { + utils.getScrollbarSize(false, sbWidth, sbHeight); + } catch (e) { + // This might fail if the window does not have a presShell. + Cu.reportError("Unable to get scrollbar size in _determineCropSize."); + sbWidth.value = sbHeight.value = 0; + } + + // Even in RTL mode, scrollbars are always on the right. + // So there's no need to determine a left offset. + let sw = aWindow.innerWidth - sbWidth.value; + let sh = aWindow.innerHeight - sbHeight.value; + + let {width: thumbnailWidth, height: thumbnailHeight} = aCanvas; + let scale = Math.min(Math.max(thumbnailWidth / sw, thumbnailHeight / sh), 1); + let scaledWidth = sw * scale; + let scaledHeight = sh * scale; + + if (scaledHeight > thumbnailHeight) + sh -= Math.floor(Math.abs(scaledHeight - thumbnailHeight) * scale); + + if (scaledWidth > thumbnailWidth) + sw -= Math.floor(Math.abs(scaledWidth - thumbnailWidth) * scale); + + return [sw, sh, scale]; + }, + + /** * Creates a new hidden canvas element. * @param aWindow The document of this window will be used to create the * canvas. If not given, the hidden window will be used. * @return The newly created canvas. */ createCanvas: function PageThumbs_createCanvas(aWindow) { - return PageThumbUtils.createCanvas(aWindow); + let doc = (aWindow || Services.appShell.hiddenDOMWindow).document; + let canvas = doc.createElementNS(HTML_NAMESPACE, "canvas"); + canvas.mozOpaque = true; + canvas.mozImageSmoothingEnabled = true; + let [thumbnailWidth, thumbnailHeight] = this._getThumbnailSize(); + canvas.width = thumbnailWidth; + canvas.height = thumbnailHeight; + return canvas; + }, + + /** + * Calculates the thumbnail size based on current desktop's dimensions. + * @return The calculated thumbnail size or a default if unable to calculate. + */ + _getThumbnailSize: function PageThumbs_getThumbnailSize() { + if (!this._thumbnailWidth || !this._thumbnailHeight) { + let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"] + .getService(Ci.nsIScreenManager); + let left = {}, top = {}, width = {}, height = {}; + screenManager.primaryScreen.GetRectDisplayPix(left, top, width, height); + this._thumbnailWidth = Math.round(width.value / 3); + this._thumbnailHeight = Math.round(height.value / 3); + } + return [this._thumbnailWidth, this._thumbnailHeight]; }, /** * Given a channel, returns true if it should be considered an "error * response", false otherwise. */ _isChannelErrorResponse: function(channel) { // No valid document channel sounds like an error to me!
--- a/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js +++ b/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js @@ -1,17 +1,19 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +(function () { // bug 673569 workaround :( + const { classes: Cc, interfaces: Ci, utils: Cu } = Components; Cu.importGlobalProperties(['Blob']); -Cu.import("resource://gre/modules/PageThumbUtils.jsm"); +Cu.import("resource://gre/modules/PageThumbs.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/Services.jsm"); const STATE_LOADING = 1; const STATE_CAPTURING = 2; const STATE_CANCELED = 3; const backgroundPageThumbsContent = { @@ -42,17 +44,17 @@ const backgroundPageThumbsContent = { addProgressListener(this, Ci.nsIWebProgress.NOTIFY_STATE_WINDOW); }, observe: function (subj, topic, data) { // Arrange to prevent (most) popup dialogs for this window - popups done // in the parent (eg, auth) aren't prevented, but alert() etc are. // disableDialogs only works on the current inner window, so it has // to be called every page load, but before scripts run. - if (content && subj == content.document) { + if (subj == content.document) { content. QueryInterface(Ci.nsIInterfaceRequestor). getInterface(Ci.nsIDOMWindowUtils). disableDialogs(); } }, get _webNav() { @@ -122,29 +124,19 @@ const backgroundPageThumbsContent = { } }, _captureCurrentPage: function () { let capture = this._currentCapture; capture.finalURL = this._webNav.currentURI.spec; capture.pageLoadTime = new Date() - capture.pageLoadStartDate; + let canvas = PageThumbs.createCanvas(content); let canvasDrawDate = new Date(); - - let canvas = PageThumbUtils.createCanvas(content); - let [sw, sh, scale] = PageThumbUtils.determineCropSize(content, canvas); - - let ctx = canvas.getContext("2d"); - ctx.save(); - ctx.scale(scale, scale); - ctx.drawWindow(content, 0, 0, sw, sh, - PageThumbUtils.THUMBNAIL_BG_COLOR, - ctx.DRAWWINDOW_DO_NOT_FLUSH); - ctx.restore(); - + PageThumbs._captureToCanvas(content, canvas); capture.canvasDrawTime = new Date() - canvasDrawDate; canvas.toBlob(blob => { capture.imageBlob = new Blob([blob]); // Load about:blank to finish the capture and wait for onStateChange. this._loadAboutBlank(); }); }, @@ -187,8 +179,10 @@ const backgroundPageThumbsContent = { QueryInterface: XPCOMUtils.generateQI([ Ci.nsIWebProgressListener, Ci.nsISupportsWeakReference, Ci.nsIObserver, ]), }; backgroundPageThumbsContent.init(); + +})();
--- a/toolkit/components/thumbnails/moz.build +++ b/toolkit/components/thumbnails/moz.build @@ -10,12 +10,11 @@ EXTRA_COMPONENTS += [ 'BrowserPageThumbs.manifest', 'PageThumbsProtocol.js', ] EXTRA_JS_MODULES += [ 'BackgroundPageThumbs.jsm', 'PageThumbs.jsm', 'PageThumbsWorker.js', - 'PageThumbUtils.jsm', ] JAR_MANIFESTS += ['jar.mn']
--- a/toolkit/components/thumbnails/test/browser.ini +++ b/toolkit/components/thumbnails/test/browser.ini @@ -1,46 +1,40 @@ [DEFAULT] +skip-if = e10s # Bug 863512 - thumbnails are disabled with e10s enabled. support-files = background_red.html background_red_redirect.sjs background_red_scroll.html head.js privacy_cache_control.sjs thumbnails_background.sjs thumbnails_crash_content_helper.js thumbnails_update.sjs [browser_thumbnails_bg_bad_url.js] [browser_thumbnails_bg_crash_during_capture.js] -skip-if = buildapp == 'mulet' || !crashreporter || e10s # crashing the remote thumbnailer crashes the remote test tab +skip-if = buildapp == 'mulet' || !crashreporter [browser_thumbnails_bg_crash_while_idle.js] -skip-if = buildapp == 'mulet' || !crashreporter || e10s +skip-if = buildapp == 'mulet' || !crashreporter [browser_thumbnails_bg_basic.js] [browser_thumbnails_bg_queueing.js] [browser_thumbnails_bg_timeout.js] [browser_thumbnails_bg_redirect.js] [browser_thumbnails_bg_destroy_browser.js] [browser_thumbnails_bg_no_cookies_sent.js] -skip-if = e10s # e10s cookie problems [browser_thumbnails_bg_no_cookies_stored.js] [browser_thumbnails_bg_no_auth_prompt.js] [browser_thumbnails_bg_no_alert.js] [browser_thumbnails_bg_no_duplicates.js] [browser_thumbnails_bg_captureIfMissing.js] [browser_thumbnails_bug726727.js] skip-if = buildapp == 'mulet' [browser_thumbnails_bug727765.js] -skip-if = e10s # tries to open crypto/local file from the child [browser_thumbnails_bug818225.js] -skip-if = (e10s && os == 'linux') # load event issues. see original bug for follow up. [browser_thumbnails_capture.js] -skip-if = e10s # tries to call drawWindow with a remote browser. [browser_thumbnails_expiration.js] [browser_thumbnails_privacy.js] -skip-if = e10s # nsSSLStatus has null mServerCert, bug 820466 [browser_thumbnails_redirect.js] -skip-if = e10s # bug 1050869 [browser_thumbnails_storage.js] [browser_thumbnails_storage_migrate3.js] skip-if = buildapp == 'mulet' [browser_thumbnails_update.js] -skip-if = e10s # tries to open crypto/local file from the child
--- a/toolkit/components/thumbnails/test/head.js +++ b/toolkit/components/thumbnails/test/head.js @@ -132,17 +132,16 @@ function captureAndCheckColor(aRed, aGre next(); }); }); } /** * For a given URL, loads the corresponding thumbnail * to a canvas and passes its image data to the callback. - * Note, not compat with e10s! * @param aURL The url associated with the thumbnail. * @param aCallback The function to pass the image data to. */ function retrieveImageDataForURL(aURL, aCallback) { let width = 100, height = 100; let thumb = PageThumbs.getThumbnailURL(aURL, width, height); // create a tab with a chrome:// URL so it can host the thumbnail image. // Note that we tried creating the element directly in the top-level chrome
--- a/toolkit/content/browser-child.js +++ b/toolkit/content/browser-child.js @@ -6,19 +6,16 @@ let Cc = Components.classes; let Ci = Components.interfaces; let Cu = Components.utils; Cu.import("resource://gre/modules/Services.jsm"); Cu.import('resource://gre/modules/XPCOMUtils.jsm'); Cu.import("resource://gre/modules/RemoteAddonsChild.jsm"); Cu.import("resource://gre/modules/Timer.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "PageThumbUtils", - "resource://gre/modules/PageThumbUtils.jsm"); - #ifdef MOZ_CRASHREPORTER XPCOMUtils.defineLazyServiceGetter(this, "CrashReporter", "@mozilla.org/xre/app-info;1", "nsICrashReporter"); #endif let FocusSyncHandler = { init: function() { @@ -366,47 +363,16 @@ addEventListener("ZoomChangeUsingMouseWh sendAsyncMessage("ZoomChangeUsingMouseWheel", {}); }, false); addMessageListener("UpdateCharacterSet", function (aMessage) { docShell.charset = aMessage.data.value; docShell.gatherCharsetMenuTelemetry(); }); -/** - * Remote thumbnail request handler for PageThumbs thumbnails. - */ -addMessageListener("Browser:Thumbnail:Request", function (aMessage) { - let thumbnail = content.document.createElementNS(PageThumbUtils.HTML_NAMESPACE, - "canvas"); - thumbnail.mozOpaque = true; - thumbnail.mozImageSmoothingEnabled = true; - - thumbnail.width = aMessage.data.canvasWidth; - thumbnail.height = aMessage.data.canvasHeight; - - let [width, height, scale] = - PageThumbUtils.determineCropSize(content, thumbnail); - - let ctx = thumbnail.getContext("2d"); - ctx.save(); - ctx.scale(scale, scale); - ctx.drawWindow(content, 0, 0, width, height, - aMessage.data.background, - ctx.DRAWWINDOW_DO_NOT_FLUSH); - ctx.restore(); - - thumbnail.toBlob(function (aBlob) { - sendAsyncMessage("Browser:Thumbnail:Response", { - thumbnail: aBlob, - id: aMessage.data.id - }); - }); -}); - // The AddonsChild needs to be rooted so that it stays alive as long as // the tab. let AddonsChild; if (Services.appinfo.browserTabsRemoteAutostart) { // Currently, the addon shims are only supported when autostarting // with remote tabs. AddonsChild = RemoteAddonsChild.init(this);