зеркало из 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) {
|
saveTab: function Storage_saveTab(tab, data) {
|
||||||
Utils.assert(tab, "tab");
|
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,
|
this._sessionStore.setTabValue(tab, this.TAB_DATA_IDENTIFIER,
|
||||||
JSON.stringify(data));
|
JSON.stringify(data));
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// Function: getTabData
|
// Function: getTabData
|
||||||
// Load tab data from session store and return it. Asynchrously loads the tab's
|
// Load tab data from session store and return it.
|
||||||
// thumbnail from the cache and calls <callback>(imageData) when done.
|
getTabData: function Storage_getTabData(tab) {
|
||||||
getTabData: function Storage_getTabData(tab, callback) {
|
|
||||||
Utils.assert(tab, "tab");
|
Utils.assert(tab, "tab");
|
||||||
Utils.assert(typeof callback == "function", "callback arg must be a function");
|
|
||||||
|
|
||||||
let existingData = null;
|
let existingData = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
let tabData = this._sessionStore.getTabValue(tab, this.TAB_DATA_IDENTIFIER);
|
let tabData = this._sessionStore.getTabValue(tab, this.TAB_DATA_IDENTIFIER);
|
||||||
if (tabData != "") {
|
if (tabData != "")
|
||||||
existingData = JSON.parse(tabData);
|
existingData = JSON.parse(tabData);
|
||||||
}
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// getTabValue will fail if the property doesn't exist.
|
// getTabValue will fail if the property doesn't exist.
|
||||||
Utils.log(e);
|
Utils.log(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (existingData) {
|
|
||||||
ThumbnailStorage.loadThumbnail(
|
|
||||||
tab, existingData.url,
|
|
||||||
function(status, imageData) {
|
|
||||||
callback(imageData);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return existingData;
|
return existingData;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -69,6 +69,7 @@ function TabItem(tab, options) {
|
||||||
let $div = iQ(div);
|
let $div = iQ(div);
|
||||||
|
|
||||||
this._cachedImageData = null;
|
this._cachedImageData = null;
|
||||||
|
this._thumbnailNeedsSaving = false;
|
||||||
this.canvasSizeForced = false;
|
this.canvasSizeForced = false;
|
||||||
this.$thumb = iQ('.thumb', $div);
|
this.$thumb = iQ('.thumb', $div);
|
||||||
this.$fav = iQ('.favicon', $div);
|
this.$fav = iQ('.favicon', $div);
|
||||||
|
@ -80,19 +81,23 @@ function TabItem(tab, options) {
|
||||||
|
|
||||||
this.tabCanvas = new TabCanvas(this.tab, this.$canvas[0]);
|
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.defaultSize = new Point(TabItems.tabWidth, TabItems.tabHeight);
|
||||||
this._hidden = false;
|
this._hidden = false;
|
||||||
this.isATabItem = true;
|
this.isATabItem = true;
|
||||||
this.keepProportional = true;
|
this.keepProportional = true;
|
||||||
this._hasBeenDrawn = false;
|
this._hasBeenDrawn = false;
|
||||||
this._reconnected = false;
|
this._reconnected = false;
|
||||||
|
this.isDragging = false;
|
||||||
this.isStacked = false;
|
this.isStacked = false;
|
||||||
this.url = "";
|
this.url = "";
|
||||||
|
|
||||||
var self = this;
|
|
||||||
|
|
||||||
this.isDragging = false;
|
|
||||||
|
|
||||||
// Read off the total vertical and horizontal padding on the tab container
|
// 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.
|
// and cache this value, as it must be the same for every TabItem.
|
||||||
if (Utils.isEmptyObject(TabItems.tabItemPadding)) {
|
if (Utils.isEmptyObject(TabItems.tabItemPadding)) {
|
||||||
|
@ -194,11 +199,14 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||||
//
|
//
|
||||||
// Parameters:
|
// Parameters:
|
||||||
// tabData - the tab data
|
// tabData - the tab data
|
||||||
showCachedData: function TabItem_showCachedData(tabData) {
|
// imageData - the image data
|
||||||
this._cachedImageData = tabData.imageData;
|
showCachedData: function TabItem_showCachedData(tabData, imageData) {
|
||||||
|
this._cachedImageData = imageData;
|
||||||
this.$cachedThumb.attr("src", this._cachedImageData).show();
|
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.$tabTitle.text(tabData.title ? tabData.title : "");
|
||||||
|
|
||||||
|
this._sendToSubscribers("showingCachedData");
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
|
@ -214,39 +222,23 @@ TabItem.prototype = Utils.extend(new Item(), new Subscribable(), {
|
||||||
// ----------
|
// ----------
|
||||||
// Function: getStorageData
|
// Function: getStorageData
|
||||||
// Get data to be used for persistent storage of this object.
|
// Get data to be used for persistent storage of this object.
|
||||||
//
|
getStorageData: function TabItem_getStorageData() {
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: this.tab.linkedBrowser.currentURI.spec,
|
url: this.tab.linkedBrowser.currentURI.spec,
|
||||||
groupID: (this.parent ? this.parent.id : 0),
|
groupID: (this.parent ? this.parent.id : 0),
|
||||||
imageData: imageData,
|
title: this.tab.label
|
||||||
title: getImageData && this.tab.label || null
|
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// Function: save
|
// Function: save
|
||||||
// Store persistent for this object.
|
// Store persistent for this object.
|
||||||
//
|
save: function TabItem_save() {
|
||||||
// Parameters:
|
|
||||||
// saveImageData - true to include thumbnail pixels (and page title as well); default false
|
|
||||||
save: function TabItem_save(saveImageData) {
|
|
||||||
try {
|
try {
|
||||||
if (!this.tab || this.tab.parentNode == null || !this._reconnected) // too soon/late to save
|
if (!this.tab || this.tab.parentNode == null || !this._reconnected) // too soon/late to save
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var data = this.getStorageData(saveImageData);
|
let data = this.getStorageData();
|
||||||
if (TabItems.storageSanity(data))
|
if (TabItems.storageSanity(data))
|
||||||
Storage.saveTab(this.tab, data);
|
Storage.saveTab(this.tab, data);
|
||||||
} catch(e) {
|
} 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
|
// Function: _reconnect
|
||||||
// Load the reciever's persistent data from storage. If there is none,
|
// 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._reconnected, "shouldn't already be reconnected");
|
||||||
Utils.assertThrow(this.tab, "should have a xul:tab");
|
Utils.assertThrow(this.tab, "should have a xul:tab");
|
||||||
|
|
||||||
let tabData = null;
|
|
||||||
let self = this;
|
let self = this;
|
||||||
let imageDataCb = function(imageData) {
|
let tabData = Storage.getTabData(this.tab);
|
||||||
// we could have been unlinked while waiting for the thumbnail to load
|
|
||||||
if (!self.tab)
|
|
||||||
return;
|
|
||||||
|
|
||||||
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)) {
|
if (tabData && TabItems.storageSanity(tabData)) {
|
||||||
|
this.loadThumbnail(tabData);
|
||||||
|
|
||||||
if (self.parent)
|
if (self.parent)
|
||||||
self.parent.remove(self, {immediately: true});
|
self.parent.remove(self, {immediately: true});
|
||||||
|
|
||||||
|
@ -936,6 +996,7 @@ let TabItems = {
|
||||||
tabItem._lastTabUpdateTime = this._lastUpdateTime;
|
tabItem._lastTabUpdateTime = this._lastUpdateTime;
|
||||||
|
|
||||||
tabItem.tabCanvas.paint();
|
tabItem.tabCanvas.paint();
|
||||||
|
tabItem.saveThumbnail();
|
||||||
|
|
||||||
// ___ cache
|
// ___ cache
|
||||||
if (tabItem.isShowingCachedData())
|
if (tabItem.isShowingCachedData())
|
||||||
|
@ -1146,13 +1207,22 @@ let TabItems = {
|
||||||
// ----------
|
// ----------
|
||||||
// Function: saveAll
|
// Function: saveAll
|
||||||
// Saves all open <TabItem>s.
|
// Saves all open <TabItem>s.
|
||||||
//
|
saveAll: function TabItems_saveAll() {
|
||||||
// Parameters:
|
let tabItems = this.getItems();
|
||||||
// saveImageData - true to include thumbnail pixels (and page title as well); default false
|
|
||||||
saveAll: function TabItems_saveAll(saveImageData) {
|
tabItems.forEach(function TabItems_saveAll_forEach(tabItem) {
|
||||||
var items = this.getItems();
|
tabItem.save();
|
||||||
items.forEach(function(item) {
|
});
|
||||||
item.save(saveImageData);
|
},
|
||||||
|
|
||||||
|
// ----------
|
||||||
|
// 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;
|
this.canvas = canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
TabCanvas.prototype = {
|
TabCanvas.prototype = Utils.extend(new Subscribable(), {
|
||||||
// ----------
|
// ----------
|
||||||
// Function: toString
|
// Function: toString
|
||||||
// Prints [TabCanvas (tab)] for debug use
|
// Prints [TabCanvas (tab)] for debug use
|
||||||
|
@ -1386,6 +1456,8 @@ TabCanvas.prototype = {
|
||||||
// Draw directly to the destination canvas
|
// Draw directly to the destination canvas
|
||||||
this._drawWindow(ctx, w, h, bgColor);
|
this._drawWindow(ctx, w, h, bgColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._sendToSubscribers("painted");
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
|
@ -1454,4 +1526,4 @@ TabCanvas.prototype = {
|
||||||
toImageData: function TabCanvas_toImageData() {
|
toImageData: function TabCanvas_toImageData() {
|
||||||
return this.canvas.toDataURL("image/png");
|
return this.canvas.toDataURL("image/png");
|
||||||
}
|
}
|
||||||
};
|
});
|
||||||
|
|
|
@ -84,20 +84,38 @@ let ThumbnailStorage = {
|
||||||
// Opens a cache entry for the given <url> and requests access <access>.
|
// Opens a cache entry for the given <url> and requests access <access>.
|
||||||
// Calls <successCallback>(entry) when the entry was successfully opened with
|
// Calls <successCallback>(entry) when the entry was successfully opened with
|
||||||
// requested access rights. Otherwise calls <errorCallback>().
|
// 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)) {
|
if (entry && access == accessGranted && Components.isSuccessCode(status)) {
|
||||||
successCallback(entry);
|
successCallback(entry);
|
||||||
} else {
|
} else {
|
||||||
entry && entry.close();
|
if (entry)
|
||||||
|
entry.close();
|
||||||
|
|
||||||
errorCallback();
|
errorCallback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let key = this.CACHE_PREFIX + url;
|
let key = this.CACHE_PREFIX + url;
|
||||||
|
|
||||||
// switch to synchronous mode if parent window is about to close
|
if (options && options.synchronously) {
|
||||||
if (UI.isDOMWindowClosing) {
|
|
||||||
let entry = this._cacheSession.openCacheEntry(key, access, true);
|
let entry = this._cacheSession.openCacheEntry(key, access, true);
|
||||||
let status = Cr.NS_OK;
|
let status = Cr.NS_OK;
|
||||||
onCacheEntryAvailable(entry, entry.accessGranted, status);
|
onCacheEntryAvailable(entry, entry.accessGranted, status);
|
||||||
|
@ -109,47 +127,38 @@ let ThumbnailStorage = {
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// Function: saveThumbnail
|
// Function: saveThumbnail
|
||||||
// Saves the <imageData> to the cache using the given <url> as key.
|
// Saves the given thumbnail in the cache.
|
||||||
// Calls <callback>(status, data) when finished, passing true or false
|
//
|
||||||
// (indicating whether the operation succeeded).
|
// Parameters:
|
||||||
saveThumbnail: function ThumbnailStorage_saveThumbnail(tab, imageData, callback) {
|
// url - the url to use as the storage key
|
||||||
Utils.assert(tab, "tab");
|
// imageData - the image data to save for the given key
|
||||||
Utils.assert(imageData, "imageData");
|
// callback - the callback that is called when the operation is finished
|
||||||
|
// options - an object with additional parameters, see below
|
||||||
if (!StoragePolicy.canStoreThumbnailForTab(tab)) {
|
//
|
||||||
tab._tabViewTabItem._sendToSubscribers("deniedToCacheImageData");
|
// Possible options:
|
||||||
if (callback)
|
// synchronously - set to true to force sync mode
|
||||||
callback(false);
|
saveThumbnail:
|
||||||
return;
|
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 self = this;
|
||||||
|
|
||||||
let completed = function(status) {
|
function onCacheEntryAvailable(entry) {
|
||||||
if (callback)
|
|
||||||
callback(status);
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
// Notify subscribers
|
|
||||||
tab._tabViewTabItem._sendToSubscribers("savedCachedImageData");
|
|
||||||
} else {
|
|
||||||
Utils.log("Error while saving thumbnail: " + e);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let onCacheEntryAvailable = function(entry) {
|
|
||||||
let outputStream = entry.openOutputStream(0);
|
let outputStream = entry.openOutputStream(0);
|
||||||
|
|
||||||
let cleanup = function() {
|
function cleanup() {
|
||||||
outputStream.close();
|
outputStream.close();
|
||||||
entry.close();
|
entry.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
// switch to synchronous mode if parent window is about to close
|
// synchronous mode
|
||||||
if (UI.isDOMWindowClosing) {
|
if (synchronously) {
|
||||||
outputStream.write(imageData, imageData.length);
|
outputStream.write(imageData, imageData.length);
|
||||||
cleanup();
|
cleanup();
|
||||||
completed(true);
|
callback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,43 +167,32 @@ let ThumbnailStorage = {
|
||||||
gNetUtil.asyncCopy(inputStream, outputStream, function (result) {
|
gNetUtil.asyncCopy(inputStream, outputStream, function (result) {
|
||||||
cleanup();
|
cleanup();
|
||||||
inputStream.close();
|
inputStream.close();
|
||||||
completed(Components.isSuccessCode(result));
|
callback(Components.isSuccessCode(result) ? "" : "failure");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let onCacheEntryUnavailable = function() {
|
function onCacheEntryUnavailable() {
|
||||||
completed(false);
|
callback("unavailable");
|
||||||
}
|
}
|
||||||
|
|
||||||
this._openCacheEntry(tab.linkedBrowser.currentURI.spec,
|
this._openCacheEntry(url, Ci.nsICache.ACCESS_WRITE, onCacheEntryAvailable,
|
||||||
Ci.nsICache.ACCESS_WRITE, onCacheEntryAvailable,
|
onCacheEntryUnavailable, options);
|
||||||
onCacheEntryUnavailable);
|
|
||||||
},
|
},
|
||||||
|
|
||||||
// ----------
|
// ----------
|
||||||
// Function: loadThumbnail
|
// Function: loadThumbnail
|
||||||
// Asynchrously loads image data from the cache using the given <url> as key.
|
// Loads a thumbnail from the cache.
|
||||||
// Calls <callback>(status, data) when finished, passing true or false
|
//
|
||||||
// (indicating whether the operation succeeded) and the retrieved image data.
|
// Parameters:
|
||||||
loadThumbnail: function ThumbnailStorage_loadThumbnail(tab, url, callback) {
|
// url - the url to use as the storage key
|
||||||
Utils.assert(tab, "tab");
|
// callback - the callback that is called when the operation is finished
|
||||||
Utils.assert(url, "url");
|
loadThumbnail: function ThumbnailStorage_loadThumbnail(url, callback) {
|
||||||
Utils.assert(typeof callback == "function", "callback arg must be a function");
|
Utils.assert(url, "invalid or missing argument <url>");
|
||||||
|
Utils.assert(callback, "invalid or missing argument <callback>");
|
||||||
|
|
||||||
let self = this;
|
let self = this;
|
||||||
|
|
||||||
let completed = function(status, imageData) {
|
function onCacheEntryAvailable(entry) {
|
||||||
callback(status, imageData);
|
|
||||||
|
|
||||||
if (status) {
|
|
||||||
// Notify subscribers
|
|
||||||
tab._tabViewTabItem._sendToSubscribers("loadedCachedImageData");
|
|
||||||
} else {
|
|
||||||
Utils.log("Error while loading thumbnail");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let onCacheEntryAvailable = function(entry) {
|
|
||||||
let imageChunks = [];
|
let imageChunks = [];
|
||||||
let nativeInputStream = entry.openInputStream(0);
|
let nativeInputStream = entry.openInputStream(0);
|
||||||
|
|
||||||
|
@ -228,16 +226,16 @@ let ThumbnailStorage = {
|
||||||
}
|
}
|
||||||
|
|
||||||
cleanup();
|
cleanup();
|
||||||
completed(isSuccess, imageData);
|
callback(isSuccess ? "" : "failure", imageData);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let onCacheEntryUnavailable = function() {
|
function onCacheEntryUnavailable() {
|
||||||
completed(false);
|
callback("unavailable");
|
||||||
}
|
}
|
||||||
|
|
||||||
this._openCacheEntry(url, Ci.nsICache.ACCESS_READ,
|
this._openCacheEntry(url, Ci.nsICache.ACCESS_READ, onCacheEntryAvailable,
|
||||||
onCacheEntryAvailable, onCacheEntryUnavailable);
|
onCacheEntryUnavailable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -283,13 +283,16 @@ let UI = {
|
||||||
gWindow.addEventListener("SSWindowClosing", function onWindowClosing() {
|
gWindow.addEventListener("SSWindowClosing", function onWindowClosing() {
|
||||||
gWindow.removeEventListener("SSWindowClosing", onWindowClosing, false);
|
gWindow.removeEventListener("SSWindowClosing", onWindowClosing, false);
|
||||||
|
|
||||||
|
// XXX bug #635975 - don't unlink the tab if the dom window is closing.
|
||||||
self.isDOMWindowClosing = true;
|
self.isDOMWindowClosing = true;
|
||||||
|
|
||||||
if (self.isTabViewVisible())
|
if (self.isTabViewVisible())
|
||||||
GroupItems.removeHiddenGroups();
|
GroupItems.removeHiddenGroups();
|
||||||
|
|
||||||
|
TabItems.saveAll();
|
||||||
|
TabItems.saveAllThumbnails({synchronously: true});
|
||||||
|
|
||||||
Storage.saveActiveGroupName(gWindow);
|
Storage.saveActiveGroupName(gWindow);
|
||||||
TabItems.saveAll(true);
|
|
||||||
self._save();
|
self._save();
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
|
@ -716,6 +719,11 @@ let UI = {
|
||||||
if (data == "enter" || data == "exit") {
|
if (data == "enter" || data == "exit") {
|
||||||
hideSearch();
|
hideSearch();
|
||||||
self._privateBrowsing.transitionMode = data;
|
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") {
|
} else if (topic == "private-browsing-transition-complete") {
|
||||||
// We use .transitionMode here, as aData is empty.
|
// We use .transitionMode here, as aData is empty.
|
||||||
|
|
|
@ -82,7 +82,6 @@ _BROWSER_FILES = \
|
||||||
browser_tabview_bug600812.js \
|
browser_tabview_bug600812.js \
|
||||||
browser_tabview_bug602432.js \
|
browser_tabview_bug602432.js \
|
||||||
browser_tabview_bug604098.js \
|
browser_tabview_bug604098.js \
|
||||||
browser_tabview_bug604699.js \
|
|
||||||
browser_tabview_bug606657.js \
|
browser_tabview_bug606657.js \
|
||||||
browser_tabview_bug606905.js \
|
browser_tabview_bug606905.js \
|
||||||
browser_tabview_bug607108.js \
|
browser_tabview_bug607108.js \
|
||||||
|
@ -154,6 +153,7 @@ _BROWSER_FILES = \
|
||||||
browser_tabview_bug669694.js \
|
browser_tabview_bug669694.js \
|
||||||
browser_tabview_bug673196.js \
|
browser_tabview_bug673196.js \
|
||||||
browser_tabview_bug673729.js \
|
browser_tabview_bug673729.js \
|
||||||
|
browser_tabview_bug677310.js \
|
||||||
browser_tabview_bug679853.js \
|
browser_tabview_bug679853.js \
|
||||||
browser_tabview_bug681599.js \
|
browser_tabview_bug681599.js \
|
||||||
browser_tabview_click_group.js \
|
browser_tabview_click_group.js \
|
||||||
|
@ -170,6 +170,7 @@ _BROWSER_FILES = \
|
||||||
browser_tabview_snapping.js \
|
browser_tabview_snapping.js \
|
||||||
browser_tabview_startup_transitions.js \
|
browser_tabview_startup_transitions.js \
|
||||||
browser_tabview_storage_policy.js \
|
browser_tabview_storage_policy.js \
|
||||||
|
browser_tabview_thumbnail_storage.js \
|
||||||
browser_tabview_undo_group.js \
|
browser_tabview_undo_group.js \
|
||||||
dummy_page.html \
|
dummy_page.html \
|
||||||
head.js \
|
head.js \
|
||||||
|
|
|
@ -34,7 +34,9 @@ function setupTwo(win) {
|
||||||
|
|
||||||
// force all canvases to update, and hook in imageData save detection
|
// force all canvases to update, and hook in imageData save detection
|
||||||
tabItems.forEach(function(tabItem) {
|
tabItems.forEach(function(tabItem) {
|
||||||
contentWindow.TabItems.update(tabItem.tab);
|
// mark thumbnail as dirty
|
||||||
|
tabItem.tabCanvas.paint();
|
||||||
|
|
||||||
tabItem.addSubscriber("savedCachedImageData", function onSaved(item) {
|
tabItem.addSubscriber("savedCachedImageData", function onSaved(item) {
|
||||||
item.removeSubscriber("savedCachedImageData", onSaved);
|
item.removeSubscriber("savedCachedImageData", onSaved);
|
||||||
|
|
||||||
|
@ -81,8 +83,8 @@ function setupTwo(win) {
|
||||||
let count = tabItems.length;
|
let count = tabItems.length;
|
||||||
|
|
||||||
tabItems.forEach(function(tabItem) {
|
tabItems.forEach(function(tabItem) {
|
||||||
tabItem.addSubscriber("loadedCachedImageData", function onLoaded() {
|
tabItem.addSubscriber("showingCachedData", function onLoaded() {
|
||||||
tabItem.removeSubscriber("loadedCachedImageData", onLoaded);
|
tabItem.removeSubscriber("showingCachedData", onLoaded);
|
||||||
ok(tabItem.isShowingCachedData(),
|
ok(tabItem.isShowingCachedData(),
|
||||||
"Tab item is showing cached data and is just connected. " +
|
"Tab item is showing cached data and is just connected. " +
|
||||||
tabItem.tab.linkedBrowser.currentURI.spec);
|
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.addSubscriber("savedCachedImageData", function onSaved() {
|
||||||
tabItem.removeSubscriber("savedCachedImageData", onSaved);
|
tabItem.removeSubscriber("savedCachedImageData", onSaved);
|
||||||
|
|
||||||
tabItem.addSubscriber("loadedCachedImageData", function onLoaded() {
|
tabItem.addSubscriber("showingCachedData", function onLoaded() {
|
||||||
tabItem.removeSubscriber("loadedCachedImageData", onLoaded);
|
tabItem.removeSubscriber("showingCachedData", onLoaded);
|
||||||
|
|
||||||
ok(tabItem.isShowingCachedData(), 'tabItem shows cached data');
|
ok(tabItem.isShowingCachedData(), 'tabItem shows cached data');
|
||||||
testChangeUrlAfterReconnect();
|
testChangeUrlAfterReconnect();
|
||||||
|
@ -33,6 +33,7 @@ function test() {
|
||||||
});
|
});
|
||||||
|
|
||||||
cw.Storage.saveTab(tab, data);
|
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),
|
ok(!contentWindow.StoragePolicy.canStoreThumbnailForTab(newTab),
|
||||||
"Should not save the thumbnail for tab");
|
"Should not save the thumbnail for tab");
|
||||||
|
|
||||||
whenDeniedToCacheImageData(tabItem, test2);
|
whenDeniedToSaveImageData(tabItem, test2);
|
||||||
tabItem.save(true);
|
tabItem.saveThumbnail({synchronously: true});
|
||||||
HttpRequestObserver.cacheControlValue = null;
|
HttpRequestObserver.cacheControlValue = null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ function test2() {
|
||||||
"Should save the thumbnail for tab");
|
"Should save the thumbnail for tab");
|
||||||
|
|
||||||
whenSavedCachedImageData(tabItem, test3);
|
whenSavedCachedImageData(tabItem, test3);
|
||||||
tabItem.save(true);
|
tabItem.saveThumbnail({synchronously: true});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,7 +77,7 @@ function test3() {
|
||||||
"Should save the thumbnail for tab");
|
"Should save the thumbnail for tab");
|
||||||
|
|
||||||
whenSavedCachedImageData(tabItem, test4);
|
whenSavedCachedImageData(tabItem, test4);
|
||||||
tabItem.save(true);
|
tabItem.saveThumbnail({synchronously: true});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +95,7 @@ function test4() {
|
||||||
"Should save the thumbnail for tab");
|
"Should save the thumbnail for tab");
|
||||||
|
|
||||||
whenSavedCachedImageData(tabItem, test5);
|
whenSavedCachedImageData(tabItem, test5);
|
||||||
tabItem.save(true);
|
tabItem.saveThumbnail({synchronously: true});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,13 +109,13 @@ function test5() {
|
||||||
ok(!contentWindow.StoragePolicy.canStoreThumbnailForTab(newTab),
|
ok(!contentWindow.StoragePolicy.canStoreThumbnailForTab(newTab),
|
||||||
"Should not save the thumbnail for tab");
|
"Should not save the thumbnail for tab");
|
||||||
|
|
||||||
whenDeniedToCacheImageData(tabItem, function () {
|
whenDeniedToSaveImageData(tabItem, function () {
|
||||||
hideTabView(function () {
|
hideTabView(function () {
|
||||||
gBrowser.removeTab(gBrowser.tabs[1]);
|
gBrowser.removeTab(gBrowser.tabs[1]);
|
||||||
finish();
|
finish();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
tabItem.save(true);
|
tabItem.saveThumbnail({synchronously: true});
|
||||||
});
|
});
|
||||||
|
|
||||||
newTab.linkedBrowser.loadURI("https://example.com/");
|
newTab.linkedBrowser.loadURI("https://example.com/");
|
||||||
|
@ -147,9 +147,9 @@ function whenSavedCachedImageData(tabItem, callback) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function whenDeniedToCacheImageData(tabItem, callback) {
|
function whenDeniedToSaveImageData(tabItem, callback) {
|
||||||
tabItem.addSubscriber("deniedToCacheImageData", function onDenied() {
|
tabItem.addSubscriber("deniedToSaveImageData", function onDenied() {
|
||||||
tabItem.removeSubscriber("deniedToCacheImageData", onDenied);
|
tabItem.removeSubscriber("deniedToSaveImageData", onDenied);
|
||||||
callback();
|
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();
|
||||||
|
}
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче