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.