зеркало из https://github.com/mozilla/gecko-dev.git
Bug 677310 - Thumbnails are lost when switching to private browsing mode; r=dietrich
This commit is contained in:
Родитель
0c839a3e27
Коммит
a13ddf90c3
|
@ -99,47 +99,27 @@ let Storage = {
|
|||
saveTab: function Storage_saveTab(tab, data) {
|
||||
Utils.assert(tab, "tab");
|
||||
|
||||
if (data != null) {
|
||||
let imageData = data.imageData;
|
||||
// Remove imageData from payload
|
||||
delete data.imageData;
|
||||
|
||||
if (imageData != null)
|
||||
ThumbnailStorage.saveThumbnail(tab, imageData);
|
||||
}
|
||||
|
||||
this._sessionStore.setTabValue(tab, this.TAB_DATA_IDENTIFIER,
|
||||
JSON.stringify(data));
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: getTabData
|
||||
// Load tab data from session store and return it. Asynchrously loads the tab's
|
||||
// thumbnail from the cache and calls <callback>(imageData) when done.
|
||||
getTabData: function Storage_getTabData(tab, callback) {
|
||||
// Load tab data from session store and return it.
|
||||
getTabData: function Storage_getTabData(tab) {
|
||||
Utils.assert(tab, "tab");
|
||||
Utils.assert(typeof callback == "function", "callback arg must be a function");
|
||||
|
||||
let existingData = null;
|
||||
|
||||
try {
|
||||
let tabData = this._sessionStore.getTabValue(tab, this.TAB_DATA_IDENTIFIER);
|
||||
if (tabData != "") {
|
||||
if (tabData != "")
|
||||
existingData = JSON.parse(tabData);
|
||||
}
|
||||
} catch (e) {
|
||||
// getTabValue will fail if the property doesn't exist.
|
||||
Utils.log(e);
|
||||
}
|
||||
|
||||
if (existingData) {
|
||||
ThumbnailStorage.loadThumbnail(
|
||||
tab, existingData.url,
|
||||
function(status, imageData) {
|
||||
callback(imageData);
|
||||
}
|
||||
);
|
||||
}
|
||||
return existingData;
|
||||
},
|
||||
|
||||
|
|
|
@ -69,6 +69,7 @@ function TabItem(tab, options) {
|
|||
let $div = iQ(div);
|
||||
|
||||
this._cachedImageData = null;
|
||||
this._thumbnailNeedsSaving = false;
|
||||
this.canvasSizeForced = false;
|
||||
this.$thumb = iQ('.thumb', $div);
|
||||
this.$fav = iQ('.favicon', $div);
|
||||
|
@ -80,19 +81,23 @@ 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;
|
||||
this.keepProportional = true;
|
||||
this._hasBeenDrawn = false;
|
||||
this._reconnected = false;
|
||||
this.isDragging = false;
|
||||
this.isStacked = false;
|
||||
this.url = "";
|
||||
|
||||
var self = this;
|
||||
|
||||
this.isDragging = false;
|
||||
|
||||
// Read off the total vertical and horizontal padding on the tab container
|
||||
// and cache this value, as it must be the same for every TabItem.
|
||||
if (Utils.isEmptyObject(TabItems.tabItemPadding)) {
|
||||
|
@ -194,11 +199,14 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
//
|
||||
// Parameters:
|
||||
// tabData - the tab data
|
||||
showCachedData: function TabItem_showCachedData(tabData) {
|
||||
this._cachedImageData = tabData.imageData;
|
||||
// imageData - the image data
|
||||
showCachedData: function TabItem_showCachedData(tabData, imageData) {
|
||||
this._cachedImageData = imageData;
|
||||
this.$cachedThumb.attr("src", this._cachedImageData).show();
|
||||
this.$canvas.css({opacity: 0.0});
|
||||
this.$canvas.css({opacity: 0});
|
||||
this.$tabTitle.text(tabData.title ? tabData.title : "");
|
||||
|
||||
this._sendToSubscribers("showingCachedData");
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -214,39 +222,23 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
// ----------
|
||||
// Function: getStorageData
|
||||
// Get data to be used for persistent storage of this object.
|
||||
//
|
||||
// Parameters:
|
||||
// getImageData - true to include thumbnail pixels (and page title as well); default false
|
||||
getStorageData: function TabItem_getStorageData(getImageData) {
|
||||
let imageData = null;
|
||||
|
||||
if (getImageData) {
|
||||
if (this._cachedImageData)
|
||||
imageData = this._cachedImageData;
|
||||
else if (this.tabCanvas)
|
||||
imageData = this.tabCanvas.toImageData();
|
||||
}
|
||||
|
||||
getStorageData: function TabItem_getStorageData() {
|
||||
return {
|
||||
url: this.tab.linkedBrowser.currentURI.spec,
|
||||
groupID: (this.parent ? this.parent.id : 0),
|
||||
imageData: imageData,
|
||||
title: getImageData && this.tab.label || null
|
||||
title: this.tab.label
|
||||
};
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: save
|
||||
// Store persistent for this object.
|
||||
//
|
||||
// Parameters:
|
||||
// saveImageData - true to include thumbnail pixels (and page title as well); default false
|
||||
save: function TabItem_save(saveImageData) {
|
||||
save: function TabItem_save() {
|
||||
try {
|
||||
if (!this.tab || this.tab.parentNode == null || !this._reconnected) // too soon/late to save
|
||||
return;
|
||||
|
||||
var data = this.getStorageData(saveImageData);
|
||||
let data = this.getStorageData();
|
||||
if (TabItems.storageSanity(data))
|
||||
Storage.saveTab(this.tab, data);
|
||||
} catch(e) {
|
||||
|
@ -254,6 +246,91 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: loadThumbnail
|
||||
// Loads the tabItems thumbnail.
|
||||
loadThumbnail: function TabItem_loadThumbnail(tabData) {
|
||||
Utils.assert(tabData, "invalid or missing argument <tabData>");
|
||||
|
||||
let self = this;
|
||||
|
||||
function TabItem_loadThumbnail_callback(error, imageData) {
|
||||
// we could have been unlinked while waiting for the thumbnail to load
|
||||
if (error || !imageData || !self.tab)
|
||||
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 (tabData.url == currentUrl || currentUrl == "about:blank")
|
||||
self.showCachedData(tabData, imageData);
|
||||
}
|
||||
|
||||
ThumbnailStorage.loadThumbnail(tabData.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};
|
||||
}
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: _reconnect
|
||||
// Load the reciever's persistent data from storage. If there is none,
|
||||
|
@ -262,29 +339,12 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
|||
Utils.assertThrow(!this._reconnected, "shouldn't already be reconnected");
|
||||
Utils.assertThrow(this.tab, "should have a xul:tab");
|
||||
|
||||
let tabData = null;
|
||||
let self = this;
|
||||
let imageDataCb = function(imageData) {
|
||||
// we could have been unlinked while waiting for the thumbnail to load
|
||||
if (!self.tab)
|
||||
return;
|
||||
let tabData = Storage.getTabData(this.tab);
|
||||
|
||||
Utils.assertThrow(tabData, "tabData");
|
||||
tabData.imageData = imageData;
|
||||
|
||||
let currentUrl = self.tab.linkedBrowser.currentURI.spec;
|
||||
// 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.
|
||||
if (tabData.imageData &&
|
||||
(tabData.url == currentUrl || currentUrl == 'about:blank')) {
|
||||
self.showCachedData(tabData);
|
||||
}
|
||||
};
|
||||
// getTabData returns the sessionstore contents, but passes
|
||||
// a callback to run when the thumbnail is finally loaded.
|
||||
tabData = Storage.getTabData(this.tab, imageDataCb);
|
||||
if (tabData && TabItems.storageSanity(tabData)) {
|
||||
this.loadThumbnail(tabData);
|
||||
|
||||
if (self.parent)
|
||||
self.parent.remove(self, {immediately: true});
|
||||
|
||||
|
@ -936,6 +996,7 @@ let TabItems = {
|
|||
tabItem._lastTabUpdateTime = this._lastUpdateTime;
|
||||
|
||||
tabItem.tabCanvas.paint();
|
||||
tabItem.saveThumbnail();
|
||||
|
||||
// ___ cache
|
||||
if (tabItem.isShowingCachedData())
|
||||
|
@ -1146,13 +1207,22 @@ let TabItems = {
|
|||
// ----------
|
||||
// Function: saveAll
|
||||
// Saves all open <TabItem>s.
|
||||
//
|
||||
// Parameters:
|
||||
// saveImageData - true to include thumbnail pixels (and page title as well); default false
|
||||
saveAll: function TabItems_saveAll(saveImageData) {
|
||||
var items = this.getItems();
|
||||
items.forEach(function(item) {
|
||||
item.save(saveImageData);
|
||||
saveAll: function TabItems_saveAll() {
|
||||
let tabItems = this.getItems();
|
||||
|
||||
tabItems.forEach(function TabItems_saveAll_forEach(tabItem) {
|
||||
tabItem.save();
|
||||
});
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: saveAllThumbnails
|
||||
// Saves thumbnails of all open <TabItem>s.
|
||||
saveAllThumbnails: function TabItems_saveAllThumbnails(options) {
|
||||
let tabItems = this.getItems();
|
||||
|
||||
tabItems.forEach(function TabItems_saveAllThumbnails_forEach(tabItem) {
|
||||
tabItem.saveThumbnail(options);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -1342,7 +1412,7 @@ function TabCanvas(tab, canvas) {
|
|||
this.canvas = canvas;
|
||||
};
|
||||
|
||||
TabCanvas.prototype = {
|
||||
TabCanvas.prototype = Utils.extend(new Subscribable(), {
|
||||
// ----------
|
||||
// Function: toString
|
||||
// Prints [TabCanvas (tab)] for debug use
|
||||
|
@ -1386,6 +1456,8 @@ TabCanvas.prototype = {
|
|||
// Draw directly to the destination canvas
|
||||
this._drawWindow(ctx, w, h, bgColor);
|
||||
}
|
||||
|
||||
this._sendToSubscribers("painted");
|
||||
},
|
||||
|
||||
// ----------
|
||||
|
@ -1454,4 +1526,4 @@ TabCanvas.prototype = {
|
|||
toImageData: function TabCanvas_toImageData() {
|
||||
return this.canvas.toDataURL("image/png");
|
||||
}
|
||||
};
|
||||
});
|
||||
|
|
|
@ -84,20 +84,38 @@ let ThumbnailStorage = {
|
|||
// Opens a cache entry for the given <url> and requests access <access>.
|
||||
// Calls <successCallback>(entry) when the entry was successfully opened with
|
||||
// requested access rights. Otherwise calls <errorCallback>().
|
||||
_openCacheEntry: function ThumbnailStorage__openCacheEntry(url, access, successCallback, errorCallback) {
|
||||
let onCacheEntryAvailable = function(entry, accessGranted, status) {
|
||||
//
|
||||
// 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 <url>");
|
||||
Utils.assert(access, "invalid or missing argument <access>");
|
||||
Utils.assert(successCallback, "invalid or missing argument <successCallback>");
|
||||
Utils.assert(errorCallback, "invalid or missing argument <errorCallback>");
|
||||
|
||||
function onCacheEntryAvailable(entry, accessGranted, status) {
|
||||
if (entry && access == accessGranted && Components.isSuccessCode(status)) {
|
||||
successCallback(entry);
|
||||
} else {
|
||||
entry && entry.close();
|
||||
if (entry)
|
||||
entry.close();
|
||||
|
||||
errorCallback();
|
||||
}
|
||||
}
|
||||
|
||||
let key = this.CACHE_PREFIX + url;
|
||||
|
||||
// switch to synchronous mode if parent window is about to close
|
||||
if (UI.isDOMWindowClosing) {
|
||||
if (options && options.synchronously) {
|
||||
let entry = this._cacheSession.openCacheEntry(key, access, true);
|
||||
let status = Cr.NS_OK;
|
||||
onCacheEntryAvailable(entry, entry.accessGranted, status);
|
||||
|
@ -109,47 +127,38 @@ let ThumbnailStorage = {
|
|||
|
||||
// ----------
|
||||
// Function: saveThumbnail
|
||||
// Saves the <imageData> to the cache using the given <url> as key.
|
||||
// Calls <callback>(status, data) when finished, passing true or false
|
||||
// (indicating whether the operation succeeded).
|
||||
saveThumbnail: function ThumbnailStorage_saveThumbnail(tab, imageData, callback) {
|
||||
Utils.assert(tab, "tab");
|
||||
Utils.assert(imageData, "imageData");
|
||||
|
||||
if (!StoragePolicy.canStoreThumbnailForTab(tab)) {
|
||||
tab._tabViewTabItem._sendToSubscribers("deniedToCacheImageData");
|
||||
if (callback)
|
||||
callback(false);
|
||||
return;
|
||||
}
|
||||
// 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 <url>");
|
||||
Utils.assert(imageData, "invalid or missing argument <imageData>");
|
||||
Utils.assert(callback, "invalid or missing argument <callback>");
|
||||
|
||||
let synchronously = (options && options.synchronously);
|
||||
let self = this;
|
||||
|
||||
let completed = function(status) {
|
||||
if (callback)
|
||||
callback(status);
|
||||
|
||||
if (status) {
|
||||
// Notify subscribers
|
||||
tab._tabViewTabItem._sendToSubscribers("savedCachedImageData");
|
||||
} else {
|
||||
Utils.log("Error while saving thumbnail: " + e);
|
||||
}
|
||||
};
|
||||
|
||||
let onCacheEntryAvailable = function(entry) {
|
||||
function onCacheEntryAvailable(entry) {
|
||||
let outputStream = entry.openOutputStream(0);
|
||||
|
||||
let cleanup = function() {
|
||||
function cleanup() {
|
||||
outputStream.close();
|
||||
entry.close();
|
||||
}
|
||||
|
||||
// switch to synchronous mode if parent window is about to close
|
||||
if (UI.isDOMWindowClosing) {
|
||||
// synchronous mode
|
||||
if (synchronously) {
|
||||
outputStream.write(imageData, imageData.length);
|
||||
cleanup();
|
||||
completed(true);
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -158,43 +167,32 @@ let ThumbnailStorage = {
|
|||
gNetUtil.asyncCopy(inputStream, outputStream, function (result) {
|
||||
cleanup();
|
||||
inputStream.close();
|
||||
completed(Components.isSuccessCode(result));
|
||||
callback(Components.isSuccessCode(result) ? "" : "failure");
|
||||
});
|
||||
}
|
||||
|
||||
let onCacheEntryUnavailable = function() {
|
||||
completed(false);
|
||||
function onCacheEntryUnavailable() {
|
||||
callback("unavailable");
|
||||
}
|
||||
|
||||
this._openCacheEntry(tab.linkedBrowser.currentURI.spec,
|
||||
Ci.nsICache.ACCESS_WRITE, onCacheEntryAvailable,
|
||||
onCacheEntryUnavailable);
|
||||
this._openCacheEntry(url, Ci.nsICache.ACCESS_WRITE, onCacheEntryAvailable,
|
||||
onCacheEntryUnavailable, options);
|
||||
},
|
||||
|
||||
// ----------
|
||||
// Function: loadThumbnail
|
||||
// Asynchrously loads image data from the cache using the given <url> as key.
|
||||
// Calls <callback>(status, data) when finished, passing true or false
|
||||
// (indicating whether the operation succeeded) and the retrieved image data.
|
||||
loadThumbnail: function ThumbnailStorage_loadThumbnail(tab, url, callback) {
|
||||
Utils.assert(tab, "tab");
|
||||
Utils.assert(url, "url");
|
||||
Utils.assert(typeof callback == "function", "callback arg must be a function");
|
||||
// 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 <url>");
|
||||
Utils.assert(callback, "invalid or missing argument <callback>");
|
||||
|
||||
let self = this;
|
||||
|
||||
let completed = function(status, imageData) {
|
||||
callback(status, imageData);
|
||||
|
||||
if (status) {
|
||||
// Notify subscribers
|
||||
tab._tabViewTabItem._sendToSubscribers("loadedCachedImageData");
|
||||
} else {
|
||||
Utils.log("Error while loading thumbnail");
|
||||
}
|
||||
}
|
||||
|
||||
let onCacheEntryAvailable = function(entry) {
|
||||
function onCacheEntryAvailable(entry) {
|
||||
let imageChunks = [];
|
||||
let nativeInputStream = entry.openInputStream(0);
|
||||
|
||||
|
@ -228,16 +226,16 @@ let ThumbnailStorage = {
|
|||
}
|
||||
|
||||
cleanup();
|
||||
completed(isSuccess, imageData);
|
||||
callback(isSuccess ? "" : "failure", imageData);
|
||||
});
|
||||
}
|
||||
|
||||
let onCacheEntryUnavailable = function() {
|
||||
completed(false);
|
||||
function onCacheEntryUnavailable() {
|
||||
callback("unavailable");
|
||||
}
|
||||
|
||||
this._openCacheEntry(url, Ci.nsICache.ACCESS_READ,
|
||||
onCacheEntryAvailable, onCacheEntryUnavailable);
|
||||
this._openCacheEntry(url, Ci.nsICache.ACCESS_READ, onCacheEntryAvailable,
|
||||
onCacheEntryUnavailable);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -283,13 +283,16 @@ let UI = {
|
|||
gWindow.addEventListener("SSWindowClosing", function onWindowClosing() {
|
||||
gWindow.removeEventListener("SSWindowClosing", onWindowClosing, false);
|
||||
|
||||
// XXX bug #635975 - don't unlink the tab if the dom window is closing.
|
||||
self.isDOMWindowClosing = true;
|
||||
|
||||
if (self.isTabViewVisible())
|
||||
GroupItems.removeHiddenGroups();
|
||||
|
||||
TabItems.saveAll();
|
||||
TabItems.saveAllThumbnails({synchronously: true});
|
||||
|
||||
Storage.saveActiveGroupName(gWindow);
|
||||
TabItems.saveAll(true);
|
||||
self._save();
|
||||
}, false);
|
||||
|
||||
|
@ -716,6 +719,11 @@ let UI = {
|
|||
if (data == "enter" || data == "exit") {
|
||||
hideSearch();
|
||||
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.
|
||||
|
|
|
@ -82,7 +82,6 @@ _BROWSER_FILES = \
|
|||
browser_tabview_bug600812.js \
|
||||
browser_tabview_bug602432.js \
|
||||
browser_tabview_bug604098.js \
|
||||
browser_tabview_bug604699.js \
|
||||
browser_tabview_bug606657.js \
|
||||
browser_tabview_bug606905.js \
|
||||
browser_tabview_bug607108.js \
|
||||
|
@ -154,6 +153,7 @@ _BROWSER_FILES = \
|
|||
browser_tabview_bug669694.js \
|
||||
browser_tabview_bug673196.js \
|
||||
browser_tabview_bug673729.js \
|
||||
browser_tabview_bug677310.js \
|
||||
browser_tabview_bug679853.js \
|
||||
browser_tabview_bug681599.js \
|
||||
browser_tabview_click_group.js \
|
||||
|
@ -170,6 +170,7 @@ _BROWSER_FILES = \
|
|||
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 \
|
||||
|
|
|
@ -34,7 +34,9 @@ function setupTwo(win) {
|
|||
|
||||
// force all canvases to update, and hook in imageData save detection
|
||||
tabItems.forEach(function(tabItem) {
|
||||
contentWindow.TabItems.update(tabItem.tab);
|
||||
// mark thumbnail as dirty
|
||||
tabItem.tabCanvas.paint();
|
||||
|
||||
tabItem.addSubscriber("savedCachedImageData", function onSaved(item) {
|
||||
item.removeSubscriber("savedCachedImageData", onSaved);
|
||||
|
||||
|
@ -81,8 +83,8 @@ function setupTwo(win) {
|
|||
let count = tabItems.length;
|
||||
|
||||
tabItems.forEach(function(tabItem) {
|
||||
tabItem.addSubscriber("loadedCachedImageData", function onLoaded() {
|
||||
tabItem.removeSubscriber("loadedCachedImageData", onLoaded);
|
||||
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);
|
||||
|
|
|
@ -1,85 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
function test() {
|
||||
let url = "http://www.example.com/";
|
||||
let cw;
|
||||
let tab = gBrowser.tabs[0];
|
||||
|
||||
let finishTest = function () {
|
||||
is(1, gBrowser.tabs.length, "there is one tab, only");
|
||||
ok(!TabView.isVisible(), "tabview is not visible");
|
||||
finish();
|
||||
}
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
let testErroneousLoading = function () {
|
||||
cw.ThumbnailStorage.loadThumbnail(tab, url, function (status, data) {
|
||||
ok(!status, "thumbnail entry failed to load");
|
||||
is(null, data, "no thumbnail data received");
|
||||
next();
|
||||
});
|
||||
}
|
||||
|
||||
let testAsynchronousSaving = function () {
|
||||
let saved = false;
|
||||
let data = "thumbnail-data-asynchronous";
|
||||
|
||||
cw.ThumbnailStorage.saveThumbnail(tab, data, function (status) {
|
||||
ok(status, "thumbnail entry was saved");
|
||||
ok(saved, "thumbnail was saved asynchronously");
|
||||
|
||||
cw.ThumbnailStorage.loadThumbnail(tab, url, function (status, imageData) {
|
||||
ok(status, "thumbnail entry was loaded");
|
||||
is(imageData, data, "valid thumbnail data received");
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
saved = true;
|
||||
}
|
||||
|
||||
let testSynchronousSaving = function () {
|
||||
let saved = false;
|
||||
let data = "thumbnail-data-synchronous";
|
||||
|
||||
cw.UI.isDOMWindowClosing = true;
|
||||
registerCleanupFunction(function () cw.UI.isDOMWindowClosing = false);
|
||||
|
||||
cw.ThumbnailStorage.saveThumbnail(tab, data, function (status) {
|
||||
ok(status, "thumbnail entry was saved");
|
||||
ok(!saved, "thumbnail was saved synchronously");
|
||||
|
||||
cw.ThumbnailStorage.loadThumbnail(tab, url, function (status, imageData) {
|
||||
ok(status, "thumbnail entry was loaded");
|
||||
is(imageData, data, "valid thumbnail data received");
|
||||
|
||||
cw.UI.isDOMWindowClosing = false;
|
||||
next();
|
||||
});
|
||||
});
|
||||
|
||||
saved = true;
|
||||
}
|
||||
|
||||
let tests = [testErroneousLoading, testAsynchronousSaving, testSynchronousSaving];
|
||||
|
||||
let next = function () {
|
||||
let test = tests.shift();
|
||||
if (test)
|
||||
test();
|
||||
else
|
||||
hideTabView(finishTest);
|
||||
}
|
||||
|
||||
tab.linkedBrowser.loadURI(url);
|
||||
afterAllTabsLoaded(function() {
|
||||
showTabView(function () {
|
||||
registerCleanupFunction(function () TabView.hide());
|
||||
cw = TabView.getContentWindow();
|
||||
|
||||
next();
|
||||
});
|
||||
});
|
||||
}
|
|
@ -22,8 +22,8 @@ function test() {
|
|||
tabItem.addSubscriber("savedCachedImageData", function onSaved() {
|
||||
tabItem.removeSubscriber("savedCachedImageData", onSaved);
|
||||
|
||||
tabItem.addSubscriber("loadedCachedImageData", function onLoaded() {
|
||||
tabItem.removeSubscriber("loadedCachedImageData", onLoaded);
|
||||
tabItem.addSubscriber("showingCachedData", function onLoaded() {
|
||||
tabItem.removeSubscriber("showingCachedData", onLoaded);
|
||||
|
||||
ok(tabItem.isShowingCachedData(), 'tabItem shows cached data');
|
||||
testChangeUrlAfterReconnect();
|
||||
|
@ -33,6 +33,7 @@ function test() {
|
|||
});
|
||||
|
||||
cw.Storage.saveTab(tab, data);
|
||||
tabItem.saveThumbnail();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* 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);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
|
@ -39,8 +39,8 @@ function test1() {
|
|||
ok(!contentWindow.StoragePolicy.canStoreThumbnailForTab(newTab),
|
||||
"Should not save the thumbnail for tab");
|
||||
|
||||
whenDeniedToCacheImageData(tabItem, test2);
|
||||
tabItem.save(true);
|
||||
whenDeniedToSaveImageData(tabItem, test2);
|
||||
tabItem.saveThumbnail({synchronously: true});
|
||||
HttpRequestObserver.cacheControlValue = null;
|
||||
});
|
||||
|
||||
|
@ -59,7 +59,7 @@ function test2() {
|
|||
"Should save the thumbnail for tab");
|
||||
|
||||
whenSavedCachedImageData(tabItem, test3);
|
||||
tabItem.save(true);
|
||||
tabItem.saveThumbnail({synchronously: true});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ function test3() {
|
|||
"Should save the thumbnail for tab");
|
||||
|
||||
whenSavedCachedImageData(tabItem, test4);
|
||||
tabItem.save(true);
|
||||
tabItem.saveThumbnail({synchronously: true});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -95,7 +95,7 @@ function test4() {
|
|||
"Should save the thumbnail for tab");
|
||||
|
||||
whenSavedCachedImageData(tabItem, test5);
|
||||
tabItem.save(true);
|
||||
tabItem.saveThumbnail({synchronously: true});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -109,13 +109,13 @@ function test5() {
|
|||
ok(!contentWindow.StoragePolicy.canStoreThumbnailForTab(newTab),
|
||||
"Should not save the thumbnail for tab");
|
||||
|
||||
whenDeniedToCacheImageData(tabItem, function () {
|
||||
whenDeniedToSaveImageData(tabItem, function () {
|
||||
hideTabView(function () {
|
||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||
finish();
|
||||
});
|
||||
});
|
||||
tabItem.save(true);
|
||||
tabItem.saveThumbnail({synchronously: true});
|
||||
});
|
||||
|
||||
newTab.linkedBrowser.loadURI("https://example.com/");
|
||||
|
@ -147,9 +147,9 @@ function whenSavedCachedImageData(tabItem, callback) {
|
|||
});
|
||||
}
|
||||
|
||||
function whenDeniedToCacheImageData(tabItem, callback) {
|
||||
tabItem.addSubscriber("deniedToCacheImageData", function onDenied() {
|
||||
tabItem.removeSubscriber("deniedToCacheImageData", onDenied);
|
||||
function whenDeniedToSaveImageData(tabItem, callback) {
|
||||
tabItem.addSubscriber("deniedToSaveImageData", function onDenied() {
|
||||
tabItem.removeSubscriber("deniedToSaveImageData", onDenied);
|
||||
callback();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,161 @@
|
|||
/* 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();
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче