author | Dão Gottwald <dao@mozilla.com> |
Wed, 03 Sep 2014 19:14:01 +0200 | |
changeset 203431 | e4d0c551410ea750bb84599ac4b6eefc6dfa9cc5 |
parent 203430 | 8a5f6d1f48828680b069abbda59f5d4d0055a2df |
child 203432 | bfef88becbba6972b2a5c1f92afac2ab4a9f0d4c |
child 203477 | 0df611ce4a5bcd0fef854cf511e8ebb5f7482bab |
push id | 48665 |
push user | ryanvm@gmail.com |
push date | Wed, 03 Sep 2014 20:40:15 +0000 |
treeherder | mozilla-inbound@0da762e6868a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | ttaubert |
bugs | 1058237 |
milestone | 35.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/base/content/browser-tabPreviews.js +++ b/browser/base/content/browser-tabPreviews.js @@ -5,35 +5,29 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. #endif */ /** * Tab previews utility, produces thumbnails */ var tabPreviews = { - aspectRatio: 0.5625, // 16:9 - - get width() { - delete this.width; - return this.width = Math.ceil(screen.availWidth / 5.75); - }, - - get height() { - delete this.height; - return this.height = Math.round(this.width * this.aspectRatio); - }, - init: function tabPreviews_init() { if (this._selectedTab) return; this._selectedTab = gBrowser.selectedTab; gBrowser.tabContainer.addEventListener("TabSelect", this, false); gBrowser.tabContainer.addEventListener("SSTabRestored", this, false); + + let screenManager = Cc["@mozilla.org/gfx/screenmanager;1"] + .getService(Ci.nsIScreenManager); + let left = {}, top = {}, width = {}, height = {}; + screenManager.primaryScreen.GetRectDisplayPix(left, top, width, height); + this.aspectRatio = height.value / width.value; }, get: function tabPreviews_get(aTab) { let uri = aTab.linkedBrowser.currentURI.spec; if (aTab.__thumbnail_lastURI && aTab.__thumbnail_lastURI != uri) { aTab.__thumbnail = null; @@ -47,41 +41,45 @@ var tabPreviews = { let img = new Image; img.src = PageThumbs.getThumbnailURL(uri); return img; } return this.capture(aTab, !aTab.hasAttribute("busy")); }, - capture: function tabPreviews_capture(aTab, aStore) { - var thumbnail = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); - thumbnail.mozOpaque = true; - thumbnail.height = this.height; - thumbnail.width = this.width; - - // drawWindow doesn't yet work with e10s (bug 698371) - if (gMultiProcessBrowser) - return thumbnail; + capture: function tabPreviews_capture(aTab, aShouldCache) { + let browser = aTab.linkedBrowser; + let uri = browser.currentURI.spec; - var ctx = thumbnail.getContext("2d"); - var win = aTab.linkedBrowser.contentWindow; - var snippetWidth = win.innerWidth * .6; - var scale = this.width / snippetWidth; - ctx.scale(scale, scale); - ctx.drawWindow(win, win.scrollX, win.scrollY, - snippetWidth, snippetWidth * this.aspectRatio, "rgb(255,255,255)"); + // 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)) { + let img = new Image; - if (aStore && - aTab.linkedBrowser /* bug 795608: the tab may got removed while drawing the thumbnail */) { - aTab.__thumbnail = thumbnail; - aTab.__thumbnail_lastURI = aTab.linkedBrowser.currentURI.spec; + PageThumbs.captureAndStore(browser, function () { + img.src = PageThumbs.getThumbnailURL(uri); + }); + + aTab.__thumbnail = img; + aTab.__thumbnail_lastURI = uri; + return img; } - return thumbnail; + let canvas = PageThumbs.createCanvas(window); + + if (aShouldCache) { + aTab.__thumbnail = canvas; + aTab.__thumbnail_lastURI = uri; + } + + PageThumbs.captureToCanvas(aTab.linkedBrowser.contentWindow, canvas); + return canvas; }, handleEvent: function tabPreviews_handleEvent(event) { switch (event.type) { case "TabSelect": if (this._selectedTab && this._selectedTab.parentNode && !this._pendingUpdate) { @@ -177,18 +175,17 @@ var ctrlTab = { }, _selectedIndex: 0, get selected () this._selectedIndex < 0 ? document.activeElement : this.previews.item(this._selectedIndex), get isOpen () this.panel.state == "open" || this.panel.state == "showing" || this._timer, get tabCount () this.tabList.length, get tabPreviewCount () Math.min(this.previews.length - 1, this.tabCount), - get canvasWidth () Math.min(tabPreviews.width, - Math.ceil(screen.availWidth * .85 / this.tabPreviewCount)), + get canvasWidth () Math.ceil(screen.availWidth * .85 / this.tabPreviewCount), get canvasHeight () Math.round(this.canvasWidth * tabPreviews.aspectRatio), get tabList () { return this._recentlyUsedTabs; }, init: function ctrlTab_init() { if (!this._recentlyUsedTabs) { @@ -500,16 +497,25 @@ var ctrlTab = { break; case "popupshowing": if (event.target.id == "menu_viewPopup") document.getElementById("menu_showAllTabs").hidden = !allTabs.canOpen; break; } }, + filterForThumbnailExpiration: function (aCallback) { + let urls = []; + let previewCount = this.tabPreviewCount; + for (let i = 0; i < previewCount; i++) + urls.push(this.tabList[i].linkedBrowser.currentURI.spec); + + aCallback(urls); + }, + _initRecentlyUsedTabs: function () { this._recentlyUsedTabs = Array.filter(gBrowser.tabs, tab => !tab.closing) .sort((tab1, tab2) => tab2.lastAccessed - tab1.lastAccessed); }, _init: function ctrlTab__init(enable) { var toggleEventListener = enable ? "addEventListener" : "removeEventListener"; @@ -520,16 +526,21 @@ var ctrlTab = { tabContainer[toggleEventListener]("TabOpen", this, false); tabContainer[toggleEventListener]("TabAttrModified", this, false); tabContainer[toggleEventListener]("TabSelect", this, false); tabContainer[toggleEventListener]("TabClose", this, false); document[toggleEventListener]("keypress", this, false); gBrowser.mTabBox.handleCtrlTab = !enable; + if (enable) + PageThumbs.addExpirationFilter(this); + else + PageThumbs.removeExpirationFilter(this); + // If we're not running, hide the "Show All Tabs" menu item, // as Shift+Ctrl+Tab will be handled by the tab bar. document.getElementById("menu_showAllTabs").hidden = !enable; document.getElementById("menu_viewPopup")[toggleEventListener]("popupshowing", this); // Also disable the <key> to ensure Shift+Ctrl+Tab never triggers // Show All Tabs. var key_showAllTabs = document.getElementById("key_showAllTabs");
--- a/browser/base/content/browser-thumbnails.js +++ b/browser/base/content/browser-thumbnails.js @@ -98,17 +98,19 @@ let gBrowserThumbnails = { onStateChange: function Thumbnails_onStateChange(aBrowser, aWebProgress, aRequest, aStateFlags, aStatus) { if (aStateFlags & Ci.nsIWebProgressListener.STATE_STOP && aStateFlags & Ci.nsIWebProgressListener.STATE_IS_NETWORK) this._delayedCapture(aBrowser); }, _capture: function Thumbnails_capture(aBrowser) { - if (this._shouldCapture(aBrowser)) + // Only capture about:newtab top sites. + if (this._topSiteURLs.indexOf(aBrowser.currentURI.spec) >= 0 && + this._shouldCapture(aBrowser)) PageThumbs.captureAndStoreIfStale(aBrowser); }, _delayedCapture: function Thumbnails_delayedCapture(aBrowser) { if (this._timeouts.has(aBrowser)) clearTimeout(this._timeouts.get(aBrowser)); else aBrowser.addEventListener("scroll", this, true); @@ -116,25 +118,22 @@ let gBrowserThumbnails = { let timeout = setTimeout(function () { this._clearTimeout(aBrowser); 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) { // Capture only if it's the currently selected tab. if (aBrowser != gBrowser.selectedBrowser) return false; - // Only capture about:newtab top sites. - if (this._topSiteURLs.indexOf(aBrowser.currentURI.spec) < 0) - 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.
--- a/browser/base/content/test/general/browser_tabopen_reflows.js +++ b/browser/base/content/test/general/browser_tabopen_reflows.js @@ -44,24 +44,16 @@ const EXPECTED_REFLOWS = [ "TabItems_link@chrome://browser/content/tabview.js|" + "TabItems_init/this._eventListeners.open@chrome://browser/content/tabview.js|", // SessionStore.getWindowDimensions() "ssi_getWindowDimension@resource:///modules/sessionstore/SessionStore.jsm|" + "ssi_updateWindowFeatures/<@resource:///modules/sessionstore/SessionStore.jsm|" + "ssi_updateWindowFeatures@resource:///modules/sessionstore/SessionStore.jsm|" + "ssi_collectWindowData@resource:///modules/sessionstore/SessionStore.jsm|", - - // tabPreviews.capture() - "tabPreviews_capture@chrome://browser/content/browser.js|" + - "tabPreviews_handleEvent/<@chrome://browser/content/browser.js|", - - // tabPreviews.capture() - "tabPreviews_capture@chrome://browser/content/browser.js|" + - "@chrome://browser/content/browser.js|" ]; const PREF_PRELOAD = "browser.newtab.preload"; const PREF_NEWTAB_DIRECTORYSOURCE = "browser.newtabpage.directory.source"; /* * This test ensures that there are no unexpected * uninterruptible reflows when opening new tabs.
--- a/toolkit/components/thumbnails/PageThumbs.jsm +++ b/toolkit/components/thumbnails/PageThumbs.jsm @@ -174,17 +174,17 @@ this.PageThumbs = { * 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(); + 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); @@ -198,17 +198,17 @@ this.PageThumbs = { * @return {Promise} * @resolve {Blob} The thumbnail, as a Blob. */ captureToBlob: function PageThumbs_captureToBlob(aWindow) { if (!this._prefEnabled()) { return null; } - let canvas = this._createCanvas(); + let canvas = this.createCanvas(); this.captureToCanvas(aWindow, canvas); 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) { @@ -413,17 +413,17 @@ this.PageThumbs = { }, /** * 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) { + createCanvas: function PageThumbs_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;
--- a/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js +++ b/toolkit/components/thumbnails/content/backgroundPageThumbsContent.js @@ -122,17 +122,17 @@ 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 canvas = PageThumbs.createCanvas(content); let canvasDrawDate = new Date(); PageThumbs._captureToCanvas(content, canvas); capture.canvasDrawTime = new Date() - canvasDrawDate; canvas.toBlob(blob => { capture.imageBlob = blob; // Load about:blank to finish the capture and wait for onStateChange. this._loadAboutBlank();