From 80b5199be2422817eecc600137c85242b374d789 Mon Sep 17 00:00:00 2001 From: Raymond Lee Date: Thu, 19 Apr 2012 00:19:48 +0800 Subject: [PATCH 1/4] Bug 659594 - Use MozAfterPaint to redraw thumbnails r=ttaubert --- browser/components/tabview/content.js | 12 +- browser/components/tabview/tabitems.js | 117 ++++++++++++------ browser/components/tabview/test/Makefile.in | 1 + .../tabview/test/browser_tabview_bug594958.js | 15 ++- .../tabview/test/browser_tabview_bug597248.js | 11 +- .../tabview/test/browser_tabview_bug610242.js | 46 ++++--- .../tabview/test/browser_tabview_bug659594.js | 39 ++++++ .../tabview/test/browser_tabview_expander.js | 3 +- browser/components/tabview/test/head.js | 16 ++- 9 files changed, 179 insertions(+), 81 deletions(-) create mode 100644 browser/components/tabview/test/browser_tabview_bug659594.js diff --git a/browser/components/tabview/content.js b/browser/components/tabview/content.js index 41e1cb0014d..19fc2419912 100644 --- a/browser/components/tabview/content.js +++ b/browser/components/tabview/content.js @@ -74,12 +74,21 @@ let WindowEventHandler = { // as quick as possible, switch the selected tab and hide the tabview // before the modal dialog is shown sendSyncMessage("Panorama:DOMWillOpenModalDialog"); + }, + + // ---------- + // Function: onMozAfterPaint + // Sends an asynchronous message when the "onMozAfterPaint" event + // is fired. + onMozAfterPaint: function WEH_onMozAfterPaint(event) { + sendAsyncMessage("Panorama:MozAfterPaint"); } }; // add event listeners addEventListener("DOMContentLoaded", WindowEventHandler.onDOMContentLoaded, false); addEventListener("DOMWillOpenModalDialog", WindowEventHandler.onDOMWillOpenModalDialog, false); +addEventListener("MozAfterPaint", WindowEventHandler.onMozAfterPaint, false); // ---------- // WindowMessageHandler @@ -90,7 +99,7 @@ let WindowMessageHandler = { // Function: isDocumentLoaded // Checks if the currently active document is loaded. isDocumentLoaded: function WMH_isDocumentLoaded(cx) { - let isLoaded = (content.document.readyState == "complete" && + let isLoaded = (content.document.readyState != "uninitialized" && !webProgress.isLoadingDocument); sendAsyncMessage(cx.name, {isLoaded: isLoaded}); @@ -197,3 +206,4 @@ let WebProgressListener = { // add web progress listener webProgress.addProgressListener(WebProgressListener, Ci.nsIWebProgress.NOTIFY_STATE_WINDOW); + diff --git a/browser/components/tabview/tabitems.js b/browser/components/tabview/tabitems.js index a754fe7239d..4b2d44991fd 100644 --- a/browser/components/tabview/tabitems.js +++ b/browser/components/tabview/tabitems.js @@ -801,6 +801,33 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), { transformOrigin: xOrigin + "% " + yOrigin + "%", transform: "scale(" + zoomScaleFactor + ")" }; + }, + + // ---------- + // Function: updateCanvas + // Updates the tabitem's canvas. + updateCanvas: function TabItem_updateCanvas() { + // ___ thumbnail + let $canvas = this.$canvas; + if (!this.canvasSizeForced) { + let w = $canvas.width(); + let h = $canvas.height(); + if (w != $canvas[0].width || h != $canvas[0].height) { + $canvas[0].width = w; + $canvas[0].height = h; + } + } + + TabItems._lastUpdateTime = Date.now(); + this._lastTabUpdateTime = TabItems._lastUpdateTime; + + if (this.tabCanvas) + this.tabCanvas.paint(); + this.saveThumbnail(); + + // ___ cache + if (this.isShowingCachedData()) + this.hideCachedData(); } }); @@ -828,6 +855,7 @@ let TabItems = { tempCanvas: null, _reconnectingPaused: false, tabItemPadding: {}, + _mozAfterPaintHandler: null, // ---------- // Function: toString @@ -859,6 +887,10 @@ let TabItems = { this.tempCanvas.width = 150; this.tempCanvas.height = 112; + let mm = gWindow.messageManager; + this._mozAfterPaintHandler = this.onMozAfterPaint.bind(this); + mm.addMessageListener("Panorama:MozAfterPaint", this._mozAfterPaintHandler); + // When a tab is opened, create the TabItem this._eventListeners.open = function (event) { let tab = event.target; @@ -908,6 +940,9 @@ let TabItems = { // ---------- // Function: uninit uninit: function TabItems_uninit() { + let mm = gWindow.messageManager; + mm.removeMessageListener("Panorama:MozAfterPaint", this._mozAfterPaintHandler); + for (let name in this._eventListeners) { AllTabs.unregister(name, this._eventListeners[name]); } @@ -946,20 +981,33 @@ let TabItems = { return this._fragment; }, - // ---------- - // Function: isComplete - // Return whether the xul:tab has fully loaded. - isComplete: function TabItems_isComplete(tab) { - // If our readyState is complete, but we're showing about:blank, - // and we're not loading about:blank, it means we haven't really - // started loading. This can happen to the first few tabs in a - // page. + // Function: _isComplete + // Checks whether the xul:tab has fully loaded and calls a callback with a + // boolean indicates whether the tab is loaded or not. + _isComplete: function TabItems__isComplete(tab, callback) { Utils.assertThrow(tab, "tab"); - return ( - tab.linkedBrowser.contentDocument.readyState == 'complete' && - !(tab.linkedBrowser.contentDocument.URL == 'about:blank' && - tab._tabViewTabItem.getTabState().url != 'about:blank') - ); + + let mm = tab.linkedBrowser.messageManager; + let message = "Panorama:isDocumentLoaded"; + + mm.addMessageListener(message, function onMessage(cx) { + mm.removeMessageListener(cx.name, onMessage); + callback(cx.json.isLoaded); + }); + mm.sendAsyncMessage(message); + }, + + // ---------- + // Function: onMozAfterPaint + // Called when a web page is painted. + onMozAfterPaint: function TabItems_onMozAfterPaint(cx) { + let index = gBrowser.browsers.indexOf(cx.target); + if (index == -1) + return; + + let tab = gBrowser.tabs[index]; + if (!tab.pinned) + this.update(tab); }, // ---------- @@ -1040,35 +1088,22 @@ let TabItems = { tabItem.$container.attr("title", label + "\n" + tabUrl); // ___ Make sure the tab is complete and ready for updating. - if (!this.isComplete(tab) && (!options || !options.force)) { - // If it's incomplete, stick it on the end of the queue - this._tabsWaitingForUpdate.push(tab); - return; + if (options && options.force) { + tabItem.updateCanvas(); + tabItem._sendToSubscribers("updated"); + } else { + this._isComplete(tab, function TabItems__update_isComplete(isComplete) { + if (!Utils.isValidXULTab(tab) || tab.pinned) + return; + + if (isComplete) { + tabItem.updateCanvas(); + tabItem._sendToSubscribers("updated"); + } else { + this._tabsWaitingForUpdate.push(tab); + } + }.bind(this)); } - - // ___ thumbnail - let $canvas = tabItem.$canvas; - if (!tabItem.canvasSizeForced) { - let w = $canvas.width(); - let h = $canvas.height(); - if (w != tabItem.$canvas[0].width || h != tabItem.$canvas[0].height) { - tabItem.$canvas[0].width = w; - tabItem.$canvas[0].height = h; - } - } - - this._lastUpdateTime = Date.now(); - tabItem._lastTabUpdateTime = this._lastUpdateTime; - - tabItem.tabCanvas.paint(); - tabItem.saveThumbnail(); - - // ___ cache - if (tabItem.isShowingCachedData()) - tabItem.hideCachedData(); - - // ___ notify subscribers that a full update has completed. - tabItem._sendToSubscribers("updated"); } catch(e) { Utils.log(e); } diff --git a/browser/components/tabview/test/Makefile.in b/browser/components/tabview/test/Makefile.in index 3d5b1a5325f..ac1d6e6a89b 100644 --- a/browser/components/tabview/test/Makefile.in +++ b/browser/components/tabview/test/Makefile.in @@ -151,6 +151,7 @@ _BROWSER_FILES = \ browser_tabview_bug655269.js \ browser_tabview_bug656778.js \ browser_tabview_bug656913.js \ + browser_tabview_bug659594.js \ browser_tabview_bug662266.js \ browser_tabview_bug663421.js \ browser_tabview_bug665502.js \ diff --git a/browser/components/tabview/test/browser_tabview_bug594958.js b/browser/components/tabview/test/browser_tabview_bug594958.js index 0ac228a415b..0756ef80cdc 100644 --- a/browser/components/tabview/test/browser_tabview_bug594958.js +++ b/browser/components/tabview/test/browser_tabview_bug594958.js @@ -54,12 +54,17 @@ function test() { let test = tests.shift(); let tab = win.gBrowser.tabs[0]; - tab.linkedBrowser.addEventListener('load', function onLoad() { - tab.linkedBrowser.removeEventListener('load', onLoad, true); - checkUrl(test); + let browser = tab.linkedBrowser; + browser.addEventListener("load", function onLoad(event) { + browser.removeEventListener("load", onLoad, true); + + let tabItem = tab._tabViewTabItem; + tabItem.addSubscriber("updated", function onUpdated() { + tabItem.removeSubscriber("updated", onUpdated); + checkUrl(test); + }); }, true); - - tab.linkedBrowser.loadURI(test.url); + browser.loadURI(test.url); } let checkUrl = function (test) { diff --git a/browser/components/tabview/test/browser_tabview_bug597248.js b/browser/components/tabview/test/browser_tabview_bug597248.js index 98490c1b29f..ff70b8a6272 100644 --- a/browser/components/tabview/test/browser_tabview_bug597248.js +++ b/browser/components/tabview/test/browser_tabview_bug597248.js @@ -134,10 +134,13 @@ function updateAndCheck() { let tabItems = contentWindow.TabItems.getItems(); tabItems.forEach(function(tabItem) { - contentWindow.TabItems._update(tabItem.tab); - ok(!tabItem.isShowingCachedData(), - "Tab item is not showing cached data anymore. " + - tabItem.tab.linkedBrowser.currentURI.spec); + tabItem.addSubscriber("updated", function onUpdated() { + tabItem.removeSubscriber("updated", onUpdated); + ok(!tabItem.isShowingCachedData(), + "Tab item is not showing cached data anymore. " + + tabItem.tab.linkedBrowser.currentURI.spec); + }); + contentWindow.TabItems.update(tabItem.tab); }); // clean up and finish diff --git a/browser/components/tabview/test/browser_tabview_bug610242.js b/browser/components/tabview/test/browser_tabview_bug610242.js index b0a40b525c6..507910fe8aa 100644 --- a/browser/components/tabview/test/browser_tabview_bug610242.js +++ b/browser/components/tabview/test/browser_tabview_bug610242.js @@ -67,34 +67,30 @@ function onTabViewWindowLoaded(win) { } afterAllTabsLoaded(function() { - afterAllTabItemsUpdated(function() { - let children = group.getChildren(); - let len = children.length; - let iconUpdateCounter = 0; + let children = group.getChildren(); + let len = children.length; + let iconUpdateCounter = 0; - children.forEach(function(tabItem) { - tabItem.addSubscriber("iconUpdated", function onIconUpdated() { - // the tab is not loaded completely so ignore it. - if (tabItem.tab.linkedBrowser.currentURI.spec == "about:blank") - return; + children.forEach(function(tabItem) { + tabItem.addSubscriber("iconUpdated", function onIconUpdated() { + tabItem.removeSubscriber("iconUpdated", onIconUpdated); - tabItem.removeSubscriber("iconUpdated", onIconUpdated); + if (++iconUpdateCounter == len) { + check(datatext, "datatext", false); + check(datahtml, "datahtml", false); + check(mozilla, "about:mozilla", false); + check(robots, "about:robots", true); + check(html, "html", true); + check(png, "png", false); + check(svg, "svg", true); - if (++iconUpdateCounter == len) { - check(datatext, "datatext", false); - check(datahtml, "datahtml", false); - check(mozilla, "about:mozilla", false); - check(robots, "about:robots", true); - check(html, "html", true); - check(png, "png", false); - check(svg, "svg", true); - - // Get rid of the group and its children - // The group close will trigger a finish(). - closeGroupItem(group); - } - }); + // Get rid of the group and its children + // The group close will trigger a finish(). + closeGroupItem(group); + } }); - }, win); + }); + + afterAllTabItemsUpdated(function () {}, win); }, win); } diff --git a/browser/components/tabview/test/browser_tabview_bug659594.js b/browser/components/tabview/test/browser_tabview_bug659594.js new file mode 100644 index 00000000000..6352fabafa0 --- /dev/null +++ b/browser/components/tabview/test/browser_tabview_bug659594.js @@ -0,0 +1,39 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +function test() { + waitForExplicitFinish(); + + newWindowWithTabView(function(win) { + let numTabsToUpdate = 2; + + showTabView(function() { + let contentWindow = win.TabView.getContentWindow(); + let groupItem = contentWindow.GroupItems.groupItems[0]; + + groupItem.getChildren().forEach(function(tabItem) { + tabItem.addSubscriber("updated", function onUpdated() { + tabItem.removeSubscriber("updated", onUpdated); + + if (--numTabsToUpdate == 0) + finish(); + }); + contentWindow.TabItems.update(tabItem.tab); + }); + }, win); + }, function(win) { + BrowserOffline.toggleOfflineStatus(); + ok(Services.io.offline, "It is now offline"); + + let originalTab = win.gBrowser.tabs[0]; + originalTab.linkedBrowser.loadURI("http://www.example.com/foo"); + win.gBrowser.addTab("http://www.example.com/bar"); + + registerCleanupFunction(function () { + if (Services.io.offline) + BrowserOffline.toggleOfflineStatus(); + win.close(); + }); + }); +} + diff --git a/browser/components/tabview/test/browser_tabview_expander.js b/browser/components/tabview/test/browser_tabview_expander.js index 305f0995710..88c624b0503 100644 --- a/browser/components/tabview/test/browser_tabview_expander.js +++ b/browser/components/tabview/test/browser_tabview_expander.js @@ -26,14 +26,13 @@ function onTabViewWindowLoaded(win) { // procreate! contentWindow.UI.setActive(group); for (var i=0; i<7; i++) { - win.gBrowser.loadOneTab('about:blank#' + i, {inBackground: true}); + win.gBrowser.loadOneTab('http://example.com#' + i, {inBackground: true}); } let children = group.getChildren(); // Wait until they all update because, once updated, they will notice that they // don't have favicons and this will change their styling at some unknown time. afterAllTabItemsUpdated(function() { - ok(!group.shouldStack(group._children.length), "The group should not stack."); is(expander[0].style.display, "none", "The expander is hidden."); diff --git a/browser/components/tabview/test/head.js b/browser/components/tabview/test/head.js index 5b60387a8ee..c93162dfccb 100644 --- a/browser/components/tabview/test/head.js +++ b/browser/components/tabview/test/head.js @@ -78,13 +78,23 @@ function closeGroupItem(groupItem, callback) { function afterAllTabItemsUpdated(callback, win) { win = win || window; let tabItems = win.document.getElementById("tab-view").contentWindow.TabItems; + let counter = 0; for (let a = 0; a < win.gBrowser.tabs.length; a++) { let tabItem = win.gBrowser.tabs[a]._tabViewTabItem; - if (tabItem) - tabItems._update(win.gBrowser.tabs[a]); + if (tabItem) { + let tab = win.gBrowser.tabs[a]; + counter++; + tabItem.addSubscriber("updated", function onUpdated() { + tabItem.removeSubscriber("updated", onUpdated); + if (--counter == 0) + callback(); + }); + tabItems.update(tab); + } } - callback(); + if (counter == 0) + callback(); } // --------- From 8fd12e8742dacf66aa45a75a91c2f870c7c728de Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Thu, 19 Apr 2012 08:24:32 +0200 Subject: [PATCH 2/4] Bug 745303 - Part 1 - Make Panorama use the thumbnail service; r=dietrich --- browser/components/tabview/content.js | 135 +-------- browser/components/tabview/storagePolicy.js | 208 -------------- browser/components/tabview/tabitems.js | 139 ++------- browser/components/tabview/tabview.js | 15 +- .../components/tabview/thumbnailStorage.js | 266 ------------------ browser/components/tabview/ui.js | 13 - 6 files changed, 26 insertions(+), 750 deletions(-) delete mode 100644 browser/components/tabview/storagePolicy.js delete mode 100644 browser/components/tabview/thumbnailStorage.js diff --git a/browser/components/tabview/content.js b/browser/components/tabview/content.js index 19fc2419912..89d9318544c 100644 --- a/browser/components/tabview/content.js +++ b/browser/components/tabview/content.js @@ -1,38 +1,6 @@ -/* ***** 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 content.js. - * - * The Initial Developer of the Original Code is the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Tim Taubert - * - * 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 ***** */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ "use strict"; @@ -52,14 +20,6 @@ __defineGetter__("webProgress", function () { // // Handles events dispatched by the content window. let WindowEventHandler = { - // ---------- - // Function: onDOMContentLoaded - // Sends an asynchronous message when the "onDOMContentLoaded" event for the - // current page is fired. - onDOMContentLoaded: function WEH_onDOMContentLoaded(event) { - sendAsyncMessage("Panorama:DOMContentLoaded"); - }, - // ---------- // Function: onDOMWillOpenModalDialog // Sends a synchronous message when the "onDOMWillOpenModalDialog" event @@ -86,7 +46,6 @@ let WindowEventHandler = { }; // add event listeners -addEventListener("DOMContentLoaded", WindowEventHandler.onDOMContentLoaded, false); addEventListener("DOMWillOpenModalDialog", WindowEventHandler.onDOMWillOpenModalDialog, false); addEventListener("MozAfterPaint", WindowEventHandler.onMozAfterPaint, false); @@ -119,91 +78,3 @@ let WindowMessageHandler = { addMessageListener("Panorama:isDocumentLoaded", WindowMessageHandler.isDocumentLoaded); addMessageListener("Panorama:isImageDocument", WindowMessageHandler.isImageDocument); -// ---------- -// WebProgressListener -// -// Observe the web progress of content pages loaded into this browser. When the -// state of a page changes we check if we're still allowed to store page -// information permanently. -let WebProgressListener = { - // ---------- - // Function: onStateChange - // Called by the webProgress when its state changes. - onStateChange: function WPL_onStateChange(webProgress, request, flag, status) { - // The browser just started loading (again). Explicitly grant storage - // because the browser might have been blocked before (e.g. when navigating - // from a https-page to a http-page). - if (flag & Ci.nsIWebProgressListener.STATE_START) { - // ensure the dom window is the top one - if (this._isTopWindow(webProgress)) - sendAsyncMessage("Panorama:StoragePolicy:granted"); - } - - // The browser finished loading - check the cache control headers. Send - // a message if we're not allowed to store information about this page. - if (flag & Ci.nsIWebProgressListener.STATE_STOP) { - // ensure the dom window is the top one - if (this._isTopWindow(webProgress) && - request && request instanceof Ci.nsIHttpChannel) { - request.QueryInterface(Ci.nsIHttpChannel); - - let exclude = false; - let reason = ""; - - // Check if the "Cache-Control" header is "no-store". In this case we're - // not allowed to store information about the current page. - if (this._isNoStoreResponse(request)) { - exclude = true; - reason = "no-store"; - } - // Otherwise we'll deny storage if we're currently viewing a https - // page without a "Cache-Control: public" header. - else if (request.URI.schemeIs("https")) { - let cacheControlHeader = this._getCacheControlHeader(request); - if (cacheControlHeader && !(/public/i).test(cacheControlHeader)) { - exclude = true; - reason = "https"; - } - } - - if (exclude) - sendAsyncMessage("Panorama:StoragePolicy:denied", {reason: reason}); - } - } - }, - - // ---------- - // Function: _isTopWindow - // Returns whether the DOMWindow associated with the webProgress is the - // top content window (and not an iframe or similar). - _isTopWindow: function WPL__isTopWindow(webProgress) { - // can throw if there's no associated DOMWindow - return !!Utils.attempt(function () webProgress.DOMWindow == content); - }, - - // ---------- - // Function: _isNoStoreResponse - // Checks if the "Cache-Control" header is "no-store". - _isNoStoreResponse: function WPL__isNoStoreResponse(req) { - // can throw if called before the response has been received - return !!Utils.attempt(function () req.isNoStoreResponse()); - }, - - // ---------- - // Function: _getCacheControlHeader - // Returns the value of the "Cache-Control" header. - _getCacheControlHeader: function WPL__getCacheControlHeader(req) { - // can throw when the "Cache-Control" header doesn't exist - return Utils.attempt(function () req.getResponseHeader("Cache-Control")); - }, - - // ---------- - // Implements progress listener interface. - QueryInterface: XPCOMUtils.generateQI([Ci.nsIWebProgressListener, - Ci.nsISupportsWeakReference, - Ci.nsISupports]) -}; - -// add web progress listener -webProgress.addProgressListener(WebProgressListener, Ci.nsIWebProgress.NOTIFY_STATE_WINDOW); - diff --git a/browser/components/tabview/storagePolicy.js b/browser/components/tabview/storagePolicy.js deleted file mode 100644 index 6c66939119b..00000000000 --- a/browser/components/tabview/storagePolicy.js +++ /dev/null @@ -1,208 +0,0 @@ -/* ***** 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 storagePolicy.js. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Tim Taubert - * - * 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 ***** */ - -// ********** -// Title: storagePolicy.js - -// ########## -// Class: StoragePolicy -// Singleton for implementing a storage policy for sensitive data. -let StoragePolicy = { - // Pref that controls whether we can store SSL content on disk - PREF_DISK_CACHE_SSL: "browser.cache.disk_cache_ssl", - - // Used to keep track of disk_cache_ssl preference - _enablePersistentHttpsCaching: null, - - // Used to keep track of browsers whose data we shouldn't store permanently - _deniedBrowsers: [], - - // ---------- - // Function: toString - // Prints [StoragePolicy] for debug use. - toString: function StoragePolicy_toString() { - return "[StoragePolicy]"; - }, - - // ---------- - // Function: init - // Initializes the StoragePolicy object. - init: function StoragePolicy_init() { - // store the preference value - this._enablePersistentHttpsCaching = - Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL); - - Services.prefs.addObserver(this.PREF_DISK_CACHE_SSL, this, false); - - // tabs are already loaded before UI is initialized so cache-control - // values are unknown. We add browsers with https to the list for now. - if (!this._enablePersistentHttpsCaching) - Array.forEach(gBrowser.browsers, this._initializeBrowser.bind(this)); - - // make sure to remove tab browsers when tabs get closed - this._onTabClose = this._onTabClose.bind(this); - gBrowser.tabContainer.addEventListener("TabClose", this._onTabClose, false); - - let mm = gWindow.messageManager; - - // add message listeners for storage granted - this._onGranted = this._onGranted.bind(this); - mm.addMessageListener("Panorama:StoragePolicy:granted", this._onGranted); - - // add message listeners for storage denied - this._onDenied = this._onDenied.bind(this); - mm.addMessageListener("Panorama:StoragePolicy:denied", this._onDenied); - }, - - // ---------- - // Function: _initializeBrowser - // Initializes the given browser and checks if we need to add it to our - // internal exclusion list. - _initializeBrowser: function StoragePolicy__initializeBrowser(browser) { - let self = this; - - function checkExclusion() { - if (browser.currentURI.schemeIs("https")) - self._deniedBrowsers.push(browser); - } - - function waitForDocumentLoad() { - let mm = browser.messageManager; - - mm.addMessageListener("Panorama:DOMContentLoaded", function onLoad(cx) { - mm.removeMessageListener(cx.name, onLoad); - checkExclusion(browser); - }); - } - - this._isDocumentLoaded(browser, function (isLoaded) { - if (isLoaded) - checkExclusion(); - else - waitForDocumentLoad(); - }); - }, - - // ---------- - // Function: _isDocumentLoaded - // Check if the given browser's document is loaded. - _isDocumentLoaded: function StoragePolicy__isDocumentLoaded(browser, callback) { - let mm = browser.messageManager; - let message = "Panorama:isDocumentLoaded"; - - mm.addMessageListener(message, function onMessage(cx) { - mm.removeMessageListener(cx.name, onMessage); - callback(cx.json.isLoaded); - }); - - mm.sendAsyncMessage(message); - }, - - // ---------- - // Function: uninit - // Is called by UI.init() when the browser windows is closed. - uninit: function StoragePolicy_uninit() { - Services.prefs.removeObserver(this.PREF_DISK_CACHE_SSL, this); - gBrowser.removeTabsProgressListener(this); - gBrowser.tabContainer.removeEventListener("TabClose", this._onTabClose, false); - - let mm = gWindow.messageManager; - - // remove message listeners - mm.removeMessageListener("Panorama:StoragePolicy:granted", this._onGranted); - mm.removeMessageListener("Panorama:StoragePolicy:denied", this._onDenied); - }, - - // ---------- - // Function: _onGranted - // Handle the 'granted' message and remove the given browser from the list - // of denied browsers. - _onGranted: function StoragePolicy__onGranted(cx) { - let index = this._deniedBrowsers.indexOf(cx.target); - - if (index > -1) - this._deniedBrowsers.splice(index, 1); - }, - - // ---------- - // Function: _onDenied - // Handle the 'denied' message and add the given browser to the list of denied - // browsers. - _onDenied: function StoragePolicy__onDenied(cx) { - // exclusion is optional because cache-control is not no-store or public and - // the protocol is https. don't exclude when persistent https caching is - // enabled. - if ("https" == cx.json.reason && this._enablePersistentHttpsCaching) - return; - - let browser = cx.target; - - if (this._deniedBrowsers.indexOf(browser) == -1) - this._deniedBrowsers.push(browser); - }, - - // ---------- - // Function: _onTabClose - // Remove the browser from our internal exclusion list when a tab gets closed. - _onTabClose: function StoragePolicy__onTabClose(event) { - let browser = event.target.linkedBrowser; - let index = this._deniedBrowsers.indexOf(browser); - - if (index > -1) - this._deniedBrowsers.splice(index, 1); - }, - - // ---------- - // Function: canStoreThumbnailForTab - // Returns whether we're allowed to store the thumbnail of the given tab. - canStoreThumbnailForTab: function StoragePolicy_canStoreThumbnailForTab(tab) { - // deny saving thumbnails in private browsing mode - if (gPrivateBrowsing.privateBrowsingEnabled && - UI._privateBrowsing.transitionMode != "enter") - return false; - - return (this._deniedBrowsers.indexOf(tab.linkedBrowser) == -1); - }, - - // ---------- - // Function: observe - // Observe pref changes. - observe: function StoragePolicy_observe(subject, topic, data) { - this._enablePersistentHttpsCaching = - Services.prefs.getBoolPref(this.PREF_DISK_CACHE_SSL); - } -}; diff --git a/browser/components/tabview/tabitems.js b/browser/components/tabview/tabitems.js index 4b2d44991fd..087f4aa9e14 100644 --- a/browser/components/tabview/tabitems.js +++ b/browser/components/tabview/tabitems.js @@ -68,8 +68,7 @@ function TabItem(tab, options) { let div = document.body.lastChild; let $div = iQ(div); - this._cachedImageData = null; - this._thumbnailNeedsSaving = false; + this._showsCachedData = false; this.canvasSizeForced = false; this.$thumb = iQ('.thumb', $div); this.$fav = iQ('.favicon', $div); @@ -81,13 +80,6 @@ function TabItem(tab, options) { this.tabCanvas = new TabCanvas(this.tab, this.$canvas[0]); - let self = this; - - // when we paint onto the canvas make sure our thumbnail gets saved - this.tabCanvas.addSubscriber("painted", function () { - self._thumbnailNeedsSaving = true; - }); - this.defaultSize = new Point(TabItems.tabWidth, TabItems.tabHeight); this._hidden = false; this.isATabItem = true; @@ -123,6 +115,8 @@ function TabItem(tab, options) { this.draggable(); + let self = this; + // ___ more div setup $div.mousedown(function(e) { if (!Utils.isRightClick(e)) @@ -190,35 +184,32 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), { // Returns a boolean indicates whether the cached data is being displayed or // not. isShowingCachedData: function TabItem_isShowingCachedData() { - return (this._cachedImageData != null); + return this._showsCachedData; }, // ---------- // Function: showCachedData // Shows the cached data i.e. image and title. Note: this method should only // be called at browser startup with the cached data avaliable. - // - // Parameters: - // imageData - the image data - showCachedData: function TabItem_showCachedData(imageData) { - this._cachedImageData = imageData; - this.$cachedThumb.attr("src", this._cachedImageData).show(); + showCachedData: function TabItem_showCachedData() { + let {title, url} = this.getTabState(); + let thumbnailURL = gPageThumbnails.getThumbnailURL(url); + + this.$cachedThumb.attr("src", thumbnailURL).show(); this.$canvas.css({opacity: 0}); - let {title, url} = this.getTabState(); - this.$tabTitle.text(title).attr("title", title ? title + "\n" + url : url); - - this._sendToSubscribers("showingCachedData"); + let tooltip = (title && title != url ? title + "\n" + url : url); + this.$tabTitle.text(title).attr("title", tooltip); + this._showsCachedData = true; }, // ---------- // Function: hideCachedData // Hides the cached data i.e. image and title and show the canvas. hideCachedData: function TabItem_hideCachedData() { - this.$cachedThumb.hide(); + this.$cachedThumb.attr("src", "").hide(); this.$canvas.css({opacity: 1.0}); - if (this._cachedImageData) - this._cachedImageData = null; + this._showsCachedData = false; }, // ---------- @@ -290,89 +281,6 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), { // Function: loadThumbnail // Loads the tabItems thumbnail. loadThumbnail: function TabItem_loadThumbnail() { - let self = this; - - function TabItem_loadThumbnail_callback(error, imageData) { - // we could have been unlinked while waiting for the thumbnail to load - if (!self.tab) - return; - - if (error || !imageData) { - // paint the canvas to avoid leaving traces when dragging tab over it - self.tabCanvas.paint(); - return; - } - - self._sendToSubscribers("loadedCachedImageData"); - - // If we have a cached image, then show it if the loaded URL matches - // what the cache is from, OR the loaded URL is blank, which means - // that the page hasn't loaded yet. - let currentUrl = self.tab.linkedBrowser.currentURI.spec; - if (self.getTabState().url == currentUrl || currentUrl == "about:blank") - self.showCachedData(imageData); - } - - ThumbnailStorage.loadThumbnail(this.getTabState().url, TabItem_loadThumbnail_callback); - }, - - // ---------- - // Function: saveThumbnail - // Saves the tabItems thumbnail. - saveThumbnail: function TabItem_saveThumbnail(options) { - if (!this.tabCanvas) - return; - - // nothing to do if the thumbnail hasn't changed - if (!this._thumbnailNeedsSaving) - return; - - // check the storage policy to see if we're allowed to store the thumbnail - if (!StoragePolicy.canStoreThumbnailForTab(this.tab)) { - this._sendToSubscribers("deniedToSaveImageData"); - return; - } - - let url = this.tab.linkedBrowser.currentURI.spec; - let delayed = this._saveThumbnailDelayed; - let synchronously = (options && options.synchronously); - - // is there a delayed save waiting? - if (delayed) { - // check if url has changed since last call to saveThumbnail - if (!synchronously && url == delayed.url) - return; - - // url has changed in the meantime, clear the timeout - clearTimeout(delayed.timeout); - } - - let self = this; - - function callback(error) { - if (!error) { - self._thumbnailNeedsSaving = false; - self._sendToSubscribers("savedCachedImageData"); - } - } - - function doSaveThumbnail() { - self._saveThumbnailDelayed = null; - - // we could have been unlinked in the meantime - if (!self.tabCanvas) - return; - - let imageData = self.tabCanvas.toImageData(); - ThumbnailStorage.saveThumbnail(url, imageData, callback, options); - } - - if (synchronously) { - doSaveThumbnail(); - } else { - let timeout = setTimeout(doSaveThumbnail, 2000); - this._saveThumbnailDelayed = {url: url, timeout: timeout}; - } }, // ---------- @@ -394,7 +302,9 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), { let groupItem; if (tabData && TabItems.storageSanity(tabData)) { - this.loadThumbnail(); + // Show the cached data while we're waiting for the tabItem to be updated. + // If the tab isn't restored yet this acts as a placeholder until it is. + this.showCachedData(); if (this.parent) this.parent.remove(this, {immediately: true}); @@ -823,7 +733,6 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), { if (this.tabCanvas) this.tabCanvas.paint(); - this.saveThumbnail(); // ___ cache if (this.isShowingCachedData()) @@ -1085,7 +994,8 @@ let TabItems = { // ___ URL let tabUrl = tab.linkedBrowser.currentURI.spec; - tabItem.$container.attr("title", label + "\n" + tabUrl); + let tooltip = (label == tabUrl ? label : label + "\n" + tabUrl); + tabItem.$container.attr("title", tooltip); // ___ Make sure the tab is complete and ready for updating. if (options && options.force) { @@ -1315,17 +1225,6 @@ let TabItems = { }); }, - // ---------- - // Function: saveAllThumbnails - // Saves thumbnails of all open s. - saveAllThumbnails: function TabItems_saveAllThumbnails(options) { - let tabItems = this.getItems(); - - tabItems.forEach(function TabItems_saveAllThumbnails_forEach(tabItem) { - tabItem.saveThumbnail(options); - }); - }, - // ---------- // Function: storageSanity // Checks the specified data (as returned by TabItem.getStorageData or loaded from storage) diff --git a/browser/components/tabview/tabview.js b/browser/components/tabview/tabview.js index 1b930a93f38..ef5c3a2ce27 100644 --- a/browser/components/tabview/tabview.js +++ b/browser/components/tabview/tabview.js @@ -25,16 +25,11 @@ XPCOMUtils.defineLazyGetter(this, "gPrefBranch", function() { return Services.prefs.getBranch("browser.panorama."); }); -XPCOMUtils.defineLazyGetter(this, "gPrivateBrowsing", function() { - return Cc["@mozilla.org/privatebrowsing;1"]. - getService(Ci.nsIPrivateBrowsingService); -}); +XPCOMUtils.defineLazyServiceGetter(this, "gPrivateBrowsing", + "@mozilla.org/privatebrowsing;1", "nsIPrivateBrowsingService"); -XPCOMUtils.defineLazyGetter(this, "gNetUtil", function() { - var obj = {}; - Cu.import("resource://gre/modules/NetUtil.jsm", obj); - return obj.NetUtil; -}); +XPCOMUtils.defineLazyModuleGetter(this, "gPageThumbnails", + "resource:///modules/PageThumbs.jsm", "PageThumbs"); var gWindow = window.parent; var gBrowser = gWindow.gBrowser; @@ -71,13 +66,11 @@ let AllTabs = { #include iq.js #include storage.js -#include storagePolicy.js #include items.js #include groupitems.js #include tabitems.js #include favicons.js #include drag.js #include trench.js -#include thumbnailStorage.js #include search.js #include ui.js diff --git a/browser/components/tabview/thumbnailStorage.js b/browser/components/tabview/thumbnailStorage.js deleted file mode 100644 index 0b9e63c9bee..00000000000 --- a/browser/components/tabview/thumbnailStorage.js +++ /dev/null @@ -1,266 +0,0 @@ -/* ***** 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 thumbnailStorage.js. - * - * The Initial Developer of the Original Code is - * the Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2011 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Raymond Lee - * - * 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 ***** */ - -// ********** -// Title: thumbnailStorage.js - -// ########## -// Class: ThumbnailStorage -// Singleton for persistent storage of thumbnail data. -let ThumbnailStorage = { - CACHE_CLIENT_IDENTIFIER: "tabview-cache", - CACHE_PREFIX: "moz-panorama:", - - // Holds the cache session reference - _cacheSession: null, - - // Holds the string input stream reference - _stringInputStream: null, - - // Holds the storage stream reference - _storageStream: null, - - // ---------- - // Function: toString - // Prints [ThumbnailStorage] for debug use. - toString: function ThumbnailStorage_toString() { - return "[ThumbnailStorage]"; - }, - - // ---------- - // Function: init - // Should be called when UI is initialized. - init: function ThumbnailStorage_init() { - // Create stream-based cache session for tabview - let cacheService = - Cc["@mozilla.org/network/cache-service;1"]. - getService(Ci.nsICacheService); - this._cacheSession = cacheService.createSession( - this.CACHE_CLIENT_IDENTIFIER, Ci.nsICache.STORE_ON_DISK, true); - this._stringInputStream = Components.Constructor( - "@mozilla.org/io/string-input-stream;1", "nsIStringInputStream", - "setData"); - this._storageStream = Components.Constructor( - "@mozilla.org/storagestream;1", "nsIStorageStream", - "init"); - }, - - // ---------- - // Function: _openCacheEntry - // Opens a cache entry for the given and requests access . - // Calls (entry) when the entry was successfully opened with - // requested access rights. Otherwise calls (). - // - // Parameters: - // url - the url to use as the storage key - // access - access flags, see Ci.nsICache.ACCESS_* - // successCallback - the callback to be called on success - // errorCallback - the callback to be called when an error occured - // options - an object with additional parameters, see below - // - // Possible options: - // synchronously - set to true to force sync mode - _openCacheEntry: - function ThumbnailStorage__openCacheEntry(url, access, successCallback, - errorCallback, options) { - Utils.assert(url, "invalid or missing argument "); - Utils.assert(access, "invalid or missing argument "); - Utils.assert(successCallback, "invalid or missing argument "); - Utils.assert(errorCallback, "invalid or missing argument "); - - function onCacheEntryAvailable(entry, accessGranted, status) { - if (entry && access == accessGranted && Components.isSuccessCode(status)) { - successCallback(entry); - } else { - if (entry) - entry.close(); - - errorCallback(); - } - } - - let key = this.CACHE_PREFIX + url; - - if (options && options.synchronously) { - let entry = this._cacheSession.openCacheEntry(key, access, true); - let status = Cr.NS_OK; - onCacheEntryAvailable(entry, entry.accessGranted, status); - } else { - let listener = new CacheListener(onCacheEntryAvailable); - this._cacheSession.asyncOpenCacheEntry(key, access, listener); - } - }, - - // ---------- - // Function: saveThumbnail - // Saves the given thumbnail in the cache. - // - // Parameters: - // url - the url to use as the storage key - // imageData - the image data to save for the given key - // callback - the callback that is called when the operation is finished - // options - an object with additional parameters, see below - // - // Possible options: - // synchronously - set to true to force sync mode - saveThumbnail: - function ThumbnailStorage_saveThumbnail(url, imageData, callback, options) { - Utils.assert(url, "invalid or missing argument "); - Utils.assert(imageData, "invalid or missing argument "); - Utils.assert(callback, "invalid or missing argument "); - - let synchronously = (options && options.synchronously); - let self = this; - - function onCacheEntryAvailable(entry) { - let outputStream = entry.openOutputStream(0); - - function cleanup() { - outputStream.close(); - entry.close(); - } - - // synchronous mode - if (synchronously) { - outputStream.write(imageData, imageData.length); - cleanup(); - callback(); - return; - } - - // asynchronous mode - let inputStream = new self._stringInputStream(imageData, imageData.length); - gNetUtil.asyncCopy(inputStream, outputStream, function (result) { - cleanup(); - inputStream.close(); - callback(Components.isSuccessCode(result) ? "" : "failure"); - }); - } - - function onCacheEntryUnavailable() { - callback("unavailable"); - } - - this._openCacheEntry(url, Ci.nsICache.ACCESS_WRITE, onCacheEntryAvailable, - onCacheEntryUnavailable, options); - }, - - // ---------- - // Function: loadThumbnail - // Loads a thumbnail from the cache. - // - // Parameters: - // url - the url to use as the storage key - // callback - the callback that is called when the operation is finished - loadThumbnail: function ThumbnailStorage_loadThumbnail(url, callback) { - Utils.assert(url, "invalid or missing argument "); - Utils.assert(callback, "invalid or missing argument "); - - let self = this; - - function onCacheEntryAvailable(entry) { - let imageChunks = []; - let nativeInputStream = entry.openInputStream(0); - - const CHUNK_SIZE = 0x10000; // 65k - const PR_UINT32_MAX = 0xFFFFFFFF; - let storageStream = new self._storageStream(CHUNK_SIZE, PR_UINT32_MAX, null); - let storageOutStream = storageStream.getOutputStream(0); - - let cleanup = function () { - nativeInputStream.close(); - storageStream.close(); - storageOutStream.close(); - entry.close(); - } - - gNetUtil.asyncCopy(nativeInputStream, storageOutStream, function (result) { - // cancel if parent window has already been closed - if (typeof UI == "undefined") { - cleanup(); - return; - } - - let imageData = null; - let isSuccess = Components.isSuccessCode(result); - - if (isSuccess) { - let storageInStream = storageStream.newInputStream(0); - imageData = gNetUtil.readInputStreamToString(storageInStream, - storageInStream.available()); - storageInStream.close(); - } - - cleanup(); - callback(isSuccess ? "" : "failure", imageData); - }); - } - - function onCacheEntryUnavailable() { - callback("unavailable"); - } - - this._openCacheEntry(url, Ci.nsICache.ACCESS_READ, onCacheEntryAvailable, - onCacheEntryUnavailable); - } -} - -// ########## -// Class: CacheListener -// Generic CacheListener for feeding to asynchronous cache calls. -// Calls (entry, access, status) when the requested cache entry -// is available. -function CacheListener(callback) { - Utils.assert(typeof callback == "function", "callback arg must be a function"); - this.callback = callback; -}; - -CacheListener.prototype = { - // ---------- - // Function: toString - // Prints [CacheListener] for debug use - toString: function CacheListener_toString() { - return "[CacheListener]"; - }, - - QueryInterface: XPCOMUtils.generateQI([Ci.nsICacheListener]), - onCacheEntryAvailable: function CacheListener_onCacheEntryAvailable( - entry, access, status) { - this.callback(entry, access, status); - } -}; - diff --git a/browser/components/tabview/ui.js b/browser/components/tabview/ui.js index f1474b6a611..ebaff2dc381 100644 --- a/browser/components/tabview/ui.js +++ b/browser/components/tabview/ui.js @@ -158,15 +158,9 @@ let UI = { // initialize the direction of the page this._initPageDirection(); - // ___ thumbnail storage - ThumbnailStorage.init(); - // ___ storage Storage.init(); - // ___ storage policy - StoragePolicy.init(); - if (Storage.readWindowBusyState(gWindow)) this.storageBusy(); @@ -277,7 +271,6 @@ let UI = { GroupItems.removeHiddenGroups(); TabItems.saveAll(); - TabItems.saveAllThumbnails({synchronously: true}); self._save(); }, false); @@ -319,7 +312,6 @@ let UI = { GroupItems.uninit(); FavIcons.uninit(); Storage.uninit(); - StoragePolicy.uninit(); this._removeTabActionHandlers(); this._currentTab = null; @@ -717,11 +709,6 @@ let UI = { if (data == "enter" || data == "exit") { Search.hide(); self._privateBrowsing.transitionMode = data; - - // make sure to save all thumbnails that haven't been saved yet - // before we enter the private browsing mode - if (data == "enter") - TabItems.saveAllThumbnails({synchronously: true}); } } else if (topic == "private-browsing-transition-complete") { // We use .transitionMode here, as aData is empty. From 3ab05de260c0cec3e3573de47f64879dac6626f1 Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Thu, 19 Apr 2012 08:24:47 +0200 Subject: [PATCH 3/4] Bug 745303 - Part 2 - Correct Panorama tests; r=dietrich --- browser/components/tabview/test/Makefile.in | 5 - .../tabview/test/browser_tabview_bug595020.js | 2 - .../tabview/test/browser_tabview_bug597248.js | 149 ---------------- .../tabview/test/browser_tabview_bug627288.js | 93 ---------- .../tabview/test/browser_tabview_bug655269.js | 11 +- .../tabview/test/browser_tabview_bug677310.js | 48 ------ .../test/browser_tabview_thumbnail_storage.js | 161 ------------------ 7 files changed, 6 insertions(+), 463 deletions(-) delete mode 100644 browser/components/tabview/test/browser_tabview_bug597248.js delete mode 100644 browser/components/tabview/test/browser_tabview_bug627288.js delete mode 100644 browser/components/tabview/test/browser_tabview_bug677310.js delete mode 100644 browser/components/tabview/test/browser_tabview_thumbnail_storage.js diff --git a/browser/components/tabview/test/Makefile.in b/browser/components/tabview/test/Makefile.in index ac1d6e6a89b..25ee5a1c375 100644 --- a/browser/components/tabview/test/Makefile.in +++ b/browser/components/tabview/test/Makefile.in @@ -71,7 +71,6 @@ _BROWSER_FILES = \ browser_tabview_bug595943.js \ browser_tabview_bug595965.js \ browser_tabview_bug596781.js \ - browser_tabview_bug597248.js \ browser_tabview_bug597360.js \ browser_tabview_bug597399.js \ browser_tabview_bug598375.js \ @@ -115,7 +114,6 @@ _BROWSER_FILES = \ browser_tabview_bug626455.js \ browser_tabview_bug626525.js \ browser_tabview_bug626791.js \ - browser_tabview_bug627288.js \ browser_tabview_bug627736.js \ browser_tabview_bug628061.js \ browser_tabview_bug628165.js \ @@ -158,7 +156,6 @@ _BROWSER_FILES = \ browser_tabview_bug669694.js \ browser_tabview_bug673196.js \ browser_tabview_bug673729.js \ - browser_tabview_bug677310.js \ browser_tabview_bug678374.js \ browser_tabview_bug679853.js \ browser_tabview_bug681599.js \ @@ -189,8 +186,6 @@ _BROWSER_FILES = \ browser_tabview_search.js \ browser_tabview_snapping.js \ browser_tabview_startup_transitions.js \ - browser_tabview_storage_policy.js \ - browser_tabview_thumbnail_storage.js \ browser_tabview_undo_group.js \ dummy_page.html \ head.js \ diff --git a/browser/components/tabview/test/browser_tabview_bug595020.js b/browser/components/tabview/test/browser_tabview_bug595020.js index c3b5d436658..82211be12f1 100644 --- a/browser/components/tabview/test/browser_tabview_bug595020.js +++ b/browser/components/tabview/test/browser_tabview_bug595020.js @@ -1,8 +1,6 @@ /* Any copyright is dedicated to the Public Domain. http://creativecommons.org/publicdomain/zero/1.0/ */ -let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore); - let stateStartup = {windows:[ {tabs:[{entries:[{url:"about:home"}]}], extData:{"tabview-last-session-group-name":"title"}} ]}; diff --git a/browser/components/tabview/test/browser_tabview_bug597248.js b/browser/components/tabview/test/browser_tabview_bug597248.js deleted file mode 100644 index ff70b8a6272..00000000000 --- a/browser/components/tabview/test/browser_tabview_bug597248.js +++ /dev/null @@ -1,149 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -let newTabOne; -let newTabTwo; -let newTabThree; -let restoredNewTabTwoLoaded = false; -let restoredNewTabThreeLoaded = false; -let frameInitialized = false; - -function test() { - waitForExplicitFinish(); - newWindowWithTabView(setupOne); -} - -function setupOne(win) { - win.TabView.firstUseExperienced = true; - - win.gBrowser.addTab("http://mochi.test:8888/browser/browser/components/tabview/test/search1.html"); - win.gBrowser.addTab("http://mochi.test:8888/browser/browser/components/tabview/test/dummy_page.html"); - - afterAllTabsLoaded(function () setupTwo(win), win); -} - -let restoredWin; - -function setupTwo(win) { - let contentWindow = win.TabView.getContentWindow(); - - let tabItems = contentWindow.TabItems.getItems(); - is(tabItems.length, 3, "There should be 3 tab items before closing"); - - let numTabsToSave = tabItems.length; - - // force all canvases to update, and hook in imageData save detection - tabItems.forEach(function(tabItem) { - // mark thumbnail as dirty - tabItem.tabCanvas.paint(); - - tabItem.addSubscriber("savedCachedImageData", function onSaved(item) { - item.removeSubscriber("savedCachedImageData", onSaved); - - if (!--numTabsToSave) - restoreWindow(); - }); - }); - - // after the window is closed, restore it. - let restoreWindow = function() { - executeSoon(function() { - restoredWin = undoCloseWindow(); - restoredWin.addEventListener("load", function onLoad(event) { - restoredWin.removeEventListener("load", onLoad, false); - - registerCleanupFunction(function() restoredWin.close()); - is(restoredWin.gBrowser.tabs.length, 3, "The total number of tabs is 3"); - - // setup tab variables and listen to the tabs load progress - newTabOne = restoredWin.gBrowser.tabs[0]; - newTabTwo = restoredWin.gBrowser.tabs[1]; - newTabThree = restoredWin.gBrowser.tabs[2]; - restoredWin.gBrowser.addTabsProgressListener(gTabsProgressListener); - - // execute code when the frame is initialized - let onTabViewFrameInitialized = function() { - restoredWin.removeEventListener( - "tabviewframeinitialized", onTabViewFrameInitialized, false); - - let restoredContentWindow = restoredWin.TabView.getContentWindow(); - // prevent TabItems._update being called before checking cached images - restoredContentWindow.TabItems._pauseUpdateForTest = true; - - let nextStep = function() { - // since we are not sure whether the frame is initialized first or two tabs - // compete loading first so we need this. - if (restoredNewTabTwoLoaded && restoredNewTabThreeLoaded) - updateAndCheck(); - else - frameInitialized = true; - } - - let tabItems = restoredContentWindow.TabItems.getItems(); - let count = tabItems.length; - - tabItems.forEach(function(tabItem) { - tabItem.addSubscriber("showingCachedData", function onLoaded() { - tabItem.removeSubscriber("showingCachedData", onLoaded); - ok(tabItem.isShowingCachedData(), - "Tab item is showing cached data and is just connected. " + - tabItem.tab.linkedBrowser.currentURI.spec); - if (--count == 0) - nextStep(); - }); - }); - } - - restoredWin.addEventListener( - "tabviewframeinitialized", onTabViewFrameInitialized, false); - }, false); - }); - }; - - win.close(); -} - -let gTabsProgressListener = { - onStateChange: function(browser, webProgress, request, stateFlags, status) { - // ensure about:blank doesn't trigger the code - if ((stateFlags & Ci.nsIWebProgressListener.STATE_STOP) && - (stateFlags & Ci.nsIWebProgressListener.STATE_IS_WINDOW) && - browser.currentURI.spec != "about:blank") { - if (newTabTwo.linkedBrowser == browser) - restoredNewTabTwoLoaded = true; - else if (newTabThree.linkedBrowser == browser) - restoredNewTabThreeLoaded = true; - - // since we are not sure whether the frame is initialized first or two tabs - // compete loading first so we need this. - if (restoredNewTabTwoLoaded && restoredNewTabThreeLoaded) { - restoredWin.gBrowser.removeTabsProgressListener(gTabsProgressListener); - - if (frameInitialized) - updateAndCheck(); - } - } - } -}; - -function updateAndCheck() { - // force all canvas to update - let contentWindow = restoredWin.TabView.getContentWindow(); - - contentWindow.TabItems._pauseUpdateForTest = false; - - let tabItems = contentWindow.TabItems.getItems(); - tabItems.forEach(function(tabItem) { - tabItem.addSubscriber("updated", function onUpdated() { - tabItem.removeSubscriber("updated", onUpdated); - ok(!tabItem.isShowingCachedData(), - "Tab item is not showing cached data anymore. " + - tabItem.tab.linkedBrowser.currentURI.spec); - }); - contentWindow.TabItems.update(tabItem.tab); - }); - - // clean up and finish - restoredWin.close(); - finish(); -} diff --git a/browser/components/tabview/test/browser_tabview_bug627288.js b/browser/components/tabview/test/browser_tabview_bug627288.js deleted file mode 100644 index 39dac283a9c..00000000000 --- a/browser/components/tabview/test/browser_tabview_bug627288.js +++ /dev/null @@ -1,93 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -function test() { - let cw; - let tab; - - let testReconnectWithSameUrl = function () { - tab = gBrowser.loadOneTab('http://mochi.test:8888/', {inBackground: true}); - - afterAllTabsLoaded(function () { - let tabItem = tab._tabViewTabItem; - let data = tabItem.getStorageData(true); - gBrowser.removeTab(tab); - - cw.TabItems.pauseReconnecting(); - tab = gBrowser.loadOneTab('http://mochi.test:8888/', {inBackground: true}); - - afterAllTabsLoaded(function () { - tabItem = tab._tabViewTabItem; - - tabItem.addSubscriber("savedCachedImageData", function onSaved() { - tabItem.removeSubscriber("savedCachedImageData", onSaved); - - tabItem.addSubscriber("showingCachedData", function onLoaded() { - tabItem.removeSubscriber("showingCachedData", onLoaded); - - ok(tabItem.isShowingCachedData(), 'tabItem shows cached data'); - testChangeUrlAfterReconnect(); - }); - - cw.TabItems.resumeReconnecting(); - }); - - cw.Storage.saveTab(tab, data); - tabItem.saveThumbnail(); - }); - }); - } - - let testChangeUrlAfterReconnect = function () { - tab.linkedBrowser.loadURI('http://mochi.test:8888/browser/'); - - whenTabAttrModified(tab, function () { - cw.TabItems._update(tab); - - let tabItem = tab._tabViewTabItem; - let currentLabel = tabItem.$tabTitle.text(); - - is(currentLabel, 'mochitest index /browser/', 'tab label is up-to-date'); - testReconnectWithNewUrl(); - }); - } - - let testReconnectWithNewUrl = function () { - let tabItem = tab._tabViewTabItem; - let data = tabItem.getStorageData(true); - gBrowser.removeTab(tab); - - cw.TabItems.pauseReconnecting(); - tab = gBrowser.loadOneTab('http://mochi.test:8888/', {inBackground: true}); - cw.Storage.saveTab(tab, data); - - whenTabAttrModified(tab, function () { - tabItem = tab._tabViewTabItem; - cw.TabItems.resumeReconnecting(); - ok(!tabItem.isShowingCachedData(), 'tabItem does not show cached data'); - - gBrowser.removeTab(tab); - hideTabView(finish); - }); - } - - waitForExplicitFinish(); - - showTabView(function () { - cw = TabView.getContentWindow(); - testReconnectWithSameUrl(); - }); -} - -// ---------- -function whenTabAttrModified(tab, callback) { - let onModified = function (event) { - tab.removeEventListener(event.type, onModified, false); - // we need executeSoon here because the tabItem also listens for the - // TabAttrModified event. so this is to make sure the tabItem logic - // is executed before the test logic. - executeSoon(callback); - } - - tab.addEventListener("TabAttrModified", onModified, false); -} diff --git a/browser/components/tabview/test/browser_tabview_bug655269.js b/browser/components/tabview/test/browser_tabview_bug655269.js index c03cc39fd17..e3c7207d22c 100644 --- a/browser/components/tabview/test/browser_tabview_bug655269.js +++ b/browser/components/tabview/test/browser_tabview_bug655269.js @@ -6,13 +6,14 @@ function test() { newWindowWithTabView(function (win) { let cw = win.TabView.getContentWindow(); - let tabItem = win.gBrowser.tabs[0]._tabViewTabItem; - tabItem.addSubscriber("savedCachedImageData", function onSaved() { - tabItem.removeSubscriber("savedCachedImageData", onSaved); + win.addEventListener("SSWindowClosing", function onClose() { + win.removeEventListener("SSWindowClosing", onClose); - ok(cw.UI.isDOMWindowClosing, "dom window is closing"); - waitForFocus(finish); + executeSoon(function () { + ok(cw.UI.isDOMWindowClosing, "dom window is closing"); + waitForFocus(finish); + }); }); win.close(); diff --git a/browser/components/tabview/test/browser_tabview_bug677310.js b/browser/components/tabview/test/browser_tabview_bug677310.js deleted file mode 100644 index 48bd079bcff..00000000000 --- a/browser/components/tabview/test/browser_tabview_bug677310.js +++ /dev/null @@ -1,48 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -let pb = Cc["@mozilla.org/privatebrowsing;1"]. - getService(Ci.nsIPrivateBrowsingService); - -function test() { - let thumbnailsSaved = false; - - waitForExplicitFinish(); - - registerCleanupFunction(function () { - ok(thumbnailsSaved, "thumbs have been saved before entering pb mode"); - pb.privateBrowsingEnabled = false; - }); - - afterAllTabsLoaded(function () { - showTabView(function () { - hideTabView(function () { - let numConditions = 2; - - function check() { - if (--numConditions) - return; - - togglePrivateBrowsing(finish); - } - - let tabItem = gBrowser.tabs[0]._tabViewTabItem; - - // save all thumbnails synchronously to cancel all delayed thumbnail - // saves that might be active - tabItem.saveThumbnail({synchronously: true}); - - // force a tabCanvas paint to flag the thumbnail as dirty - tabItem.tabCanvas.paint(); - - tabItem.addSubscriber("savedCachedImageData", function onSaved() { - tabItem.removeSubscriber("savedCachedImageData", onSaved); - thumbnailsSaved = true; - check(); - }); - - togglePrivateBrowsing(check); - }); - }); - }); -} diff --git a/browser/components/tabview/test/browser_tabview_thumbnail_storage.js b/browser/components/tabview/test/browser_tabview_thumbnail_storage.js deleted file mode 100644 index 23409f1a82b..00000000000 --- a/browser/components/tabview/test/browser_tabview_thumbnail_storage.js +++ /dev/null @@ -1,161 +0,0 @@ -/* Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ */ - -let tests = [testRawSyncSave, testRawAsyncSave, testRawLoadError, - testAsyncSave, testSyncSave, testOverrideAsyncSave, - testSaveCleanThumbnail]; - -function test() { - waitForExplicitFinish(); - loadTabView(next); -} - -function testRawSyncSave() { - let cw = TabView.getContentWindow(); - let url = "http://example.com/sync-url"; - let data = "thumbnail-data-sync"; - let saved = false; - - cw.ThumbnailStorage.saveThumbnail(url, data, function (error) { - ok(!error, "thumbnail entry was saved"); - ok(!saved, "thumbnail was saved synchronously"); - - cw.ThumbnailStorage.loadThumbnail(url, function (error, imageData) { - ok(!error, "thumbnail entry was loaded"); - is(imageData, data, "valid thumbnail data received"); - next(); - }); - }, {synchronously: true}); - - saved = true; -} - -function testRawAsyncSave() { - let cw = TabView.getContentWindow(); - let url = "http://example.com/async-url"; - let data = "thumbnail-data-async"; - let saved = false; - - cw.ThumbnailStorage.saveThumbnail(url, data, function (error) { - ok(!error, "thumbnail entry was saved"); - ok(saved, "thumbnail was saved asynchronously"); - - cw.ThumbnailStorage.loadThumbnail(url, function (error, imageData) { - ok(!error, "thumbnail entry was loaded"); - is(imageData, data, "valid thumbnail data received"); - next(); - }); - }); - - saved = true; -} - -function testRawLoadError() { - let cw = TabView.getContentWindow(); - - cw.ThumbnailStorage.loadThumbnail("non-existant-url", function (error, data) { - ok(error, "thumbnail entry failed to load"); - is(null, data, "no thumbnail data received"); - next(); - }); -} - -function testSyncSave() { - let tabItem = gBrowser.tabs[0]._tabViewTabItem; - - // set the thumbnail to dirty - tabItem.tabCanvas.paint(); - - let saved = false; - - whenThumbnailSaved(tabItem, function () { - ok(!saved, "thumbnail was saved synchronously"); - next(); - }); - - tabItem.saveThumbnail({synchronously: true}); - saved = true; -} - -function testAsyncSave() { - let tabItem = gBrowser.tabs[0]._tabViewTabItem; - - // set the thumbnail to dirty - tabItem.tabCanvas.paint(); - - let saved = false; - - whenThumbnailSaved(tabItem, function () { - ok(saved, "thumbnail was saved asynchronously"); - next(); - }); - - tabItem.saveThumbnail(); - saved = true; -} - -function testOverrideAsyncSave() { - let tabItem = gBrowser.tabs[0]._tabViewTabItem; - - // set the thumbnail to dirty - tabItem.tabCanvas.paint(); - - // initiate async save - tabItem.saveThumbnail(); - - let saveCount = 0; - - whenThumbnailSaved(tabItem, function () { - saveCount = 1; - }); - - tabItem.saveThumbnail({synchronously: true}); - - is(saveCount, 1, "thumbnail got saved once"); - next(); -} - -function testSaveCleanThumbnail() { - let tabItem = gBrowser.tabs[0]._tabViewTabItem; - - // set the thumbnail to dirty - tabItem.tabCanvas.paint(); - - let saveCount = 0; - - whenThumbnailSaved(tabItem, function () saveCount++); - tabItem.saveThumbnail({synchronously: true}); - tabItem.saveThumbnail({synchronously: true}); - - is(saveCount, 1, "thumbnail got saved once, only"); - next(); -} - -// ---------- -function whenThumbnailSaved(tabItem, callback) { - tabItem.addSubscriber("savedCachedImageData", function onSaved() { - tabItem.removeSubscriber("savedCachedImageData", onSaved); - callback(); - }); -} - -// ---------- -function loadTabView(callback) { - afterAllTabsLoaded(function () { - showTabView(function () { - hideTabView(callback); - }); - }); -} - -// ---------- -function next() { - let test = tests.shift(); - - if (test) { - info("* running " + test.name + "..."); - test(); - } else { - finish(); - } -} From 35bb5a3e9466892aab0e3eb0f02fd30a05b797ea Mon Sep 17 00:00:00 2001 From: Tim Taubert Date: Thu, 19 Apr 2012 08:35:05 +0200 Subject: [PATCH 4/4] Bug 745303 - Part 3 - Remove empty method; r=me --- browser/components/tabview/tabitems.js | 6 ------ 1 file changed, 6 deletions(-) diff --git a/browser/components/tabview/tabitems.js b/browser/components/tabview/tabitems.js index 087f4aa9e14..0f35c0042ee 100644 --- a/browser/components/tabview/tabitems.js +++ b/browser/components/tabview/tabitems.js @@ -277,12 +277,6 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), { return {title: title, url: url}; }, - // ---------- - // Function: loadThumbnail - // Loads the tabItems thumbnail. - loadThumbnail: function TabItem_loadThumbnail() { - }, - // ---------- // Function: _reconnect // Load the reciever's persistent data from storage. If there is none,