Merge m-c to s-c
@ -44,7 +44,6 @@ include $(DEPTH)/config/autoconf.mk
|
||||
MODULE = browserabout
|
||||
LIBRARY_NAME = browserabout_s
|
||||
FORCE_STATIC_LIB = 1
|
||||
FORCE_USE_PIC = 1
|
||||
ifndef MOZ_MEMORY
|
||||
USE_STATIC_LIBS = 1
|
||||
endif
|
||||
|
@ -50,7 +50,6 @@ DIRS = tests
|
||||
endif
|
||||
|
||||
FORCE_STATIC_LIB = 1
|
||||
FORCE_USE_PIC = 1
|
||||
|
||||
# Because we are an application component, link against the CRT statically
|
||||
# (on Windows, but only if we're not building our own CRT for jemalloc)
|
||||
|
@ -44,7 +44,6 @@ include $(DEPTH)/config/autoconf.mk
|
||||
MODULE = browser_feeds
|
||||
LIBRARY_NAME = browser_feeds_s
|
||||
FORCE_STATIC_LIB = 1
|
||||
FORCE_USE_PIC = 1
|
||||
ifndef MOZ_MEMORY
|
||||
USE_STATIC_LIBS = 1
|
||||
endif
|
||||
|
@ -44,7 +44,6 @@ include $(DEPTH)/config/autoconf.mk
|
||||
MODULE = migration
|
||||
LIBRARY_NAME = migration_s
|
||||
FORCE_STATIC_LIB = 1
|
||||
FORCE_USE_PIC = 1
|
||||
ifndef MOZ_MEMORY
|
||||
USE_STATIC_LIBS = 1
|
||||
endif
|
||||
|
@ -45,7 +45,6 @@ include $(DEPTH)/config/autoconf.mk
|
||||
MODULE = privatebrowsing
|
||||
LIBRARY_NAME = privatebrowsing_s
|
||||
FORCE_STATIC_LIB = 1
|
||||
FORCE_USE_PIC = 1
|
||||
ifndef MOZ_MEMORY
|
||||
USE_STATIC_LIBS = 1
|
||||
endif
|
||||
|
@ -57,14 +57,14 @@ function PROT_MalwareWarden() {
|
||||
this.prefs_.addObserver(kMalwareWardenEnabledPref, malwareWardenPrefObserver);
|
||||
|
||||
// Add a test chunk to the database
|
||||
var testData = "mozilla.com/firefox/its-an-attack.html";
|
||||
var testData = "mozilla.org/firefox/its-an-attack.html";
|
||||
|
||||
var testUpdate =
|
||||
"n:1000\ni:test-malware-simple\nad:1\n" +
|
||||
"a:1:32:" + testData.length + "\n" +
|
||||
testData;
|
||||
|
||||
testData = "mozilla.com/firefox/its-a-trap.html";
|
||||
testData = "mozilla.org/firefox/its-a-trap.html";
|
||||
testUpdate +=
|
||||
"n:1000\ni:test-phish-simple\nad:1\n" +
|
||||
"a:1:32:" + testData.length + "\n" +
|
||||
|
@ -8,7 +8,7 @@ function test() {
|
||||
// Navigate to malware site. Can't use an onload listener here since
|
||||
// error pages don't fire onload
|
||||
window.addEventListener("DOMContentLoaded", testMalware, true);
|
||||
content.location = "http://www.mozilla.com/firefox/its-an-attack.html";
|
||||
content.location = "http://www.mozilla.org/firefox/its-an-attack.html";
|
||||
}
|
||||
|
||||
function testMalware() {
|
||||
@ -23,7 +23,7 @@ function testMalware() {
|
||||
|
||||
// Now launch the phishing test
|
||||
window.addEventListener("DOMContentLoaded", testPhishing, true);
|
||||
content.location = "http://www.mozilla.com/firefox/its-a-trap.html";
|
||||
content.location = "http://www.mozilla.org/firefox/its-a-trap.html";
|
||||
}
|
||||
|
||||
function testPhishing() {
|
||||
|
@ -37,7 +37,7 @@ function testNormal_PopupListener() {
|
||||
|
||||
// Now launch the phishing test. Can't use onload here because error pages don't
|
||||
// fire normal load events.
|
||||
content.location = "http://www.mozilla.com/firefox/its-a-trap.html";
|
||||
content.location = "http://www.mozilla.org/firefox/its-a-trap.html";
|
||||
setTimeout(testPhishing, 2000);
|
||||
}
|
||||
|
||||
|
@ -117,11 +117,6 @@ const CAPABILITIES = [
|
||||
"DNSPrefetch", "Auth", "WindowControl"
|
||||
];
|
||||
|
||||
// These keys are for internal use only - they shouldn't be part of the JSON
|
||||
// that gets saved to disk nor part of the strings returned by the API.
|
||||
const INTERNAL_KEYS = ["_tabStillLoading", "_hosts", "_formDataSaved",
|
||||
"_shouldRestore", "_host", "_scheme"];
|
||||
|
||||
// These are tab events that we listen to.
|
||||
const TAB_EVENTS = ["TabOpen", "TabClose", "TabSelect", "TabShow", "TabHide",
|
||||
"TabPinned", "TabUnpinned"];
|
||||
@ -216,6 +211,9 @@ SessionStoreService.prototype = {
|
||||
// states for all currently opened windows
|
||||
_windows: {},
|
||||
|
||||
// internal states for all open windows (data we need to associate, but not write to disk)
|
||||
_internalWindows: {},
|
||||
|
||||
// states for all recently closed windows
|
||||
_closedWindows: [],
|
||||
|
||||
@ -379,6 +377,11 @@ SessionStoreService.prototype = {
|
||||
// We don't want to minimize and then open a window at startup.
|
||||
if (this._initialState.windows[0].sizemode == "minimized")
|
||||
this._initialState.windows[0].sizemode = "normal";
|
||||
// clear any lastSessionWindowID attributes since those don't matter
|
||||
// during normal restore
|
||||
this._initialState.windows.forEach(function(aWindow) {
|
||||
delete aWindow.__lastSessionWindowID;
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (ex) { debug("The session file is invalid: " + ex); }
|
||||
@ -550,6 +553,9 @@ SessionStoreService.prototype = {
|
||||
this._forEachBrowserWindow(function(aWindow) {
|
||||
Array.forEach(aWindow.gBrowser.tabs, function(aTab) {
|
||||
delete aTab.linkedBrowser.__SS_data;
|
||||
delete aTab.linkedBrowser.__SS_tabStillLoading;
|
||||
delete aTab.linkedBrowser.__SS_formDataSaved;
|
||||
delete aTab.linkedBrowser.__SS_hostSchemeData;
|
||||
if (aTab.linkedBrowser.__SS_restoreState)
|
||||
this._resetTabRestoringState(aTab);
|
||||
});
|
||||
@ -557,10 +563,13 @@ SessionStoreService.prototype = {
|
||||
});
|
||||
// also clear all data about closed tabs and windows
|
||||
for (let ix in this._windows) {
|
||||
if (ix in openWindows)
|
||||
if (ix in openWindows) {
|
||||
this._windows[ix]._closedTabs = [];
|
||||
else
|
||||
}
|
||||
else {
|
||||
delete this._windows[ix];
|
||||
delete this._internalWindows[ix];
|
||||
}
|
||||
}
|
||||
// also clear all data about closed windows
|
||||
this._closedWindows = [];
|
||||
@ -797,6 +806,10 @@ SessionStoreService.prototype = {
|
||||
|
||||
// and create its data object
|
||||
this._windows[aWindow.__SSi] = { tabs: [], selected: 0, _closedTabs: [], busy: false };
|
||||
|
||||
// and create its internal data object
|
||||
this._internalWindows[aWindow.__SSi] = { hosts: {} }
|
||||
|
||||
if (!this._isWindowLoaded(aWindow))
|
||||
this._windows[aWindow.__SSi]._restoring = true;
|
||||
if (!aWindow.toolbar.visible)
|
||||
@ -968,7 +981,9 @@ SessionStoreService.prototype = {
|
||||
winData.title = aWindow.content.document.title || tabbrowser.selectedTab.label;
|
||||
winData.title = this._replaceLoadingTitle(winData.title, tabbrowser,
|
||||
tabbrowser.selectedTab);
|
||||
this._updateCookies([winData]);
|
||||
let windows = {};
|
||||
windows[aWindow.__SSi] = winData;
|
||||
this._updateCookies(windows);
|
||||
}
|
||||
|
||||
#ifndef XP_MACOSX
|
||||
@ -989,6 +1004,7 @@ SessionStoreService.prototype = {
|
||||
|
||||
// clear this window from the list
|
||||
delete this._windows[aWindow.__SSi];
|
||||
delete this._internalWindows[aWindow.__SSi];
|
||||
|
||||
// save the state without this window to disk
|
||||
this.saveStateDelayed();
|
||||
@ -1046,6 +1062,9 @@ SessionStoreService.prototype = {
|
||||
browser.removeEventListener("DOMAutoComplete", this, true);
|
||||
|
||||
delete browser.__SS_data;
|
||||
delete browser.__SS_tabStillLoading;
|
||||
delete browser.__SS_formDataSaved;
|
||||
delete browser.__SS_hostSchemeData;
|
||||
|
||||
// If this tab was in the middle of restoring or still needs to be restored,
|
||||
// we need to reset that state. If the tab was restoring, we will attempt to
|
||||
@ -1125,6 +1144,8 @@ SessionStoreService.prototype = {
|
||||
}
|
||||
|
||||
delete aBrowser.__SS_data;
|
||||
delete aBrowser.__SS_tabStillLoading;
|
||||
delete aBrowser.__SS_formDataSaved;
|
||||
this.saveStateDelayed(aWindow);
|
||||
|
||||
// attempt to update the current URL we send in a crash report
|
||||
@ -1139,9 +1160,9 @@ SessionStoreService.prototype = {
|
||||
* Browser reference
|
||||
*/
|
||||
onTabInput: function sss_onTabInput(aWindow, aBrowser) {
|
||||
if (aBrowser.__SS_data)
|
||||
delete aBrowser.__SS_data._formDataSaved;
|
||||
|
||||
// deleting __SS_formDataSaved will cause us to recollect form data
|
||||
delete aBrowser.__SS_formDataSaved;
|
||||
|
||||
this.saveStateDelayed(aWindow, 3000);
|
||||
},
|
||||
|
||||
@ -1708,7 +1729,7 @@ SessionStoreService.prototype = {
|
||||
if (!browser || !browser.currentURI)
|
||||
// can happen when calling this function right after .addTab()
|
||||
return tabData;
|
||||
else if (browser.__SS_data && browser.__SS_data._tabStillLoading) {
|
||||
else if (browser.__SS_data && browser.__SS_tabStillLoading) {
|
||||
// use the data to be restored when the tab hasn't been completely loaded
|
||||
tabData = browser.__SS_data;
|
||||
if (aTab.pinned)
|
||||
@ -1743,10 +1764,11 @@ SessionStoreService.prototype = {
|
||||
tabData.index = history.index + 1;
|
||||
}
|
||||
else if (history && history.count > 0) {
|
||||
browser.__SS_hostSchemeData = [];
|
||||
try {
|
||||
for (var j = 0; j < history.count; j++) {
|
||||
let entry = this._serializeHistoryEntry(history.getEntryAtIndex(j, false),
|
||||
aFullData, aTab.pinned);
|
||||
aFullData, aTab.pinned, browser.__SS_hostSchemeData);
|
||||
tabData.entries.push(entry);
|
||||
}
|
||||
// If we make it through the for loop, then we're ok and we should clear
|
||||
@ -1835,15 +1857,16 @@ SessionStoreService.prototype = {
|
||||
* always return privacy sensitive data (use with care)
|
||||
* @param aIsPinned
|
||||
* the tab is pinned and should be treated differently for privacy
|
||||
* @param aHostSchemeData
|
||||
* an array of objects with host & scheme keys
|
||||
* @returns object
|
||||
*/
|
||||
_serializeHistoryEntry:
|
||||
function sss_serializeHistoryEntry(aEntry, aFullData, aIsPinned) {
|
||||
function sss_serializeHistoryEntry(aEntry, aFullData, aIsPinned, aHostSchemeData) {
|
||||
var entry = { url: aEntry.URI.spec };
|
||||
|
||||
try {
|
||||
entry._host = aEntry.URI.host;
|
||||
entry._scheme = aEntry.URI.scheme;
|
||||
aHostSchemeData.push({ host: aEntry.URI.host, scheme: aEntry.URI.scheme });
|
||||
}
|
||||
catch (ex) {
|
||||
// We just won't attempt to get cookies for this entry.
|
||||
@ -1946,7 +1969,7 @@ SessionStoreService.prototype = {
|
||||
var child = aEntry.GetChildAt(i);
|
||||
if (child) {
|
||||
entry.children.push(this._serializeHistoryEntry(child, aFullData,
|
||||
aIsPinned));
|
||||
aIsPinned, aHostSchemeData));
|
||||
}
|
||||
else { // to maintain the correct frame order, insert a dummy entry
|
||||
entry.children.push({ url: "about:blank" });
|
||||
@ -2044,7 +2067,7 @@ SessionStoreService.prototype = {
|
||||
var browsers = aWindow.gBrowser.browsers;
|
||||
this._windows[aWindow.__SSi].tabs.forEach(function (tabData, i) {
|
||||
if (browsers[i].__SS_data &&
|
||||
browsers[i].__SS_data._tabStillLoading)
|
||||
browsers[i].__SS_tabStillLoading)
|
||||
return; // ignore incompletely initialized tabs
|
||||
try {
|
||||
this._updateTextAndScrollDataForTab(aWindow, browsers[i], tabData);
|
||||
@ -2081,9 +2104,9 @@ SessionStoreService.prototype = {
|
||||
|
||||
this._updateTextAndScrollDataForFrame(aWindow, aBrowser.contentWindow,
|
||||
aTabData.entries[tabIndex],
|
||||
!aTabData._formDataSaved, aFullData,
|
||||
!aBrowser.__SS_formDataSaved, aFullData,
|
||||
!!aTabData.pinned);
|
||||
aTabData._formDataSaved = true;
|
||||
aBrowser.__SS_formDataSaved = true;
|
||||
if (aBrowser.currentURI.spec == "about:config")
|
||||
aTabData.entries[tabIndex].formdata = {
|
||||
"#textbox": aBrowser.contentDocument.getElementById("textbox").value
|
||||
@ -2260,8 +2283,8 @@ SessionStoreService.prototype = {
|
||||
* is the entry we're evaluating for a pinned tab; used only if
|
||||
* aCheckPrivacy
|
||||
*/
|
||||
_extractHostsForCookies:
|
||||
function sss__extractHostsForCookies(aEntry, aHosts, aCheckPrivacy, aIsPinned) {
|
||||
_extractHostsForCookiesFromEntry:
|
||||
function sss__extractHostsForCookiesFromEntry(aEntry, aHosts, aCheckPrivacy, aIsPinned) {
|
||||
|
||||
let host = aEntry._host,
|
||||
scheme = aEntry._scheme;
|
||||
@ -2275,23 +2298,11 @@ SessionStoreService.prototype = {
|
||||
let uri = this._getURIFromString(aEntry.url);
|
||||
host = uri.host;
|
||||
scheme = uri.scheme;
|
||||
this._extractHostsForCookiesFromHostScheme(host, scheme, aHosts, aCheckPrivacy, aIsPinned);
|
||||
}
|
||||
catch(ex) { }
|
||||
}
|
||||
|
||||
// host and scheme may not be set (for about: urls for example), in which
|
||||
// case testing scheme will be sufficient.
|
||||
if (/https?/.test(scheme) && !aHosts[host] &&
|
||||
(!aCheckPrivacy ||
|
||||
this._checkPrivacyLevel(scheme == "https", aIsPinned))) {
|
||||
// By setting this to true or false, we can determine when looking at
|
||||
// the host in _updateCookies if we should check for privacy.
|
||||
aHosts[host] = aIsPinned;
|
||||
}
|
||||
else if (scheme == "file") {
|
||||
aHosts[host] = true;
|
||||
}
|
||||
|
||||
if (aEntry.children) {
|
||||
aEntry.children.forEach(function(entry) {
|
||||
this._extractHostsForCookies(entry, aHosts, aCheckPrivacy, aIsPinned);
|
||||
@ -2299,25 +2310,63 @@ SessionStoreService.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* extract the base domain from a host & scheme
|
||||
* @param aHost
|
||||
* the host of a uri (usually via nsIURI.host)
|
||||
* @param aScheme
|
||||
* the scheme of a uri (usually via nsIURI.scheme)
|
||||
* @param aHosts
|
||||
* the hash that will be used to store hosts eg, { hostname: true }
|
||||
* @param aCheckPrivacy
|
||||
* should we check the privacy level for https
|
||||
* @param aIsPinned
|
||||
* is the entry we're evaluating for a pinned tab; used only if
|
||||
* aCheckPrivacy
|
||||
*/
|
||||
_extractHostsForCookiesFromHostScheme:
|
||||
function sss__extractHostsForCookiesFromHostScheme(aHost, aScheme, aHosts, aCheckPrivacy, aIsPinned) {
|
||||
// host and scheme may not be set (for about: urls for example), in which
|
||||
// case testing scheme will be sufficient.
|
||||
if (/https?/.test(aScheme) && !aHosts[aHost] &&
|
||||
(!aCheckPrivacy ||
|
||||
this._checkPrivacyLevel(aScheme == "https", aIsPinned))) {
|
||||
// By setting this to true or false, we can determine when looking at
|
||||
// the host in _updateCookies if we should check for privacy.
|
||||
aHosts[aHost] = aIsPinned;
|
||||
}
|
||||
else if (aScheme == "file") {
|
||||
aHosts[aHost] = true;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* store all hosts for a URL
|
||||
* @param aWindow
|
||||
* Window reference
|
||||
*/
|
||||
_updateCookieHosts: function sss_updateCookieHosts(aWindow) {
|
||||
var hosts = this._windows[aWindow.__SSi]._hosts = {};
|
||||
var hosts = this._internalWindows[aWindow.__SSi].hosts = {};
|
||||
|
||||
this._windows[aWindow.__SSi].tabs.forEach(function(aTabData) {
|
||||
aTabData.entries.forEach(function(entry) {
|
||||
this._extractHostsForCookies(entry, hosts, true, !!aTabData.pinned);
|
||||
}, this);
|
||||
}, this);
|
||||
// Since _updateCookiesHosts is only ever called for open windows during a
|
||||
// session, we can call into _extractHostsForCookiesFromHostScheme directly
|
||||
// using data that is attached to each browser.
|
||||
for (let i = 0; i < aWindow.gBrowser.tabs.length; i++) {
|
||||
let tab = aWindow.gBrowser.tabs[i];
|
||||
let hostSchemeData = tab.linkedBrowser.__SS_hostSchemeData || [];
|
||||
for (let j = 0; j < hostSchemeData.length; j++) {
|
||||
this._extractHostsForCookiesFromHostScheme(hostSchemeData[j].host,
|
||||
hostSchemeData[j].scheme,
|
||||
hosts, true, tab.pinned);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Serialize cookie data
|
||||
* @param aWindows
|
||||
* array of Window references
|
||||
* JS object containing window data references
|
||||
* { id: winData, etc. }
|
||||
*/
|
||||
_updateCookies: function sss_updateCookies(aWindows) {
|
||||
function addCookieToHash(aHash, aHost, aPath, aName, aCookie) {
|
||||
@ -2330,18 +2379,17 @@ SessionStoreService.prototype = {
|
||||
aHash[aHost][aPath][aName] = aCookie;
|
||||
}
|
||||
|
||||
// collect the cookies per window
|
||||
for (var i = 0; i < aWindows.length; i++)
|
||||
aWindows[i].cookies = [];
|
||||
|
||||
var jscookies = {};
|
||||
var _this = this;
|
||||
// MAX_EXPIRY should be 2^63-1, but JavaScript can't handle that precision
|
||||
var MAX_EXPIRY = Math.pow(2, 62);
|
||||
aWindows.forEach(function(aWindow) {
|
||||
if (!aWindow._hosts)
|
||||
|
||||
for (let [id, window] in Iterator(aWindows)) {
|
||||
window.cookies = [];
|
||||
let internalWindow = this._internalWindows[id];
|
||||
if (!internalWindow.hosts)
|
||||
return;
|
||||
for (var [host, isPinned] in Iterator(aWindow._hosts)) {
|
||||
for (var [host, isPinned] in Iterator(internalWindow.hosts)) {
|
||||
let list;
|
||||
try {
|
||||
list = CookieSvc.getCookiesFromHost(host);
|
||||
@ -2351,7 +2399,7 @@ SessionStoreService.prototype = {
|
||||
}
|
||||
while (list && list.hasMoreElements()) {
|
||||
var cookie = list.getNext().QueryInterface(Ci.nsICookie2);
|
||||
// aWindow._hosts will only have hosts with the right privacy rules,
|
||||
// window._hosts will only have hosts with the right privacy rules,
|
||||
// so there is no need to do anything special with this call to
|
||||
// _checkPrivacyLevel.
|
||||
if (cookie.isSession && _this._checkPrivacyLevel(cookie.isSecure, isPinned)) {
|
||||
@ -2370,16 +2418,15 @@ SessionStoreService.prototype = {
|
||||
|
||||
addCookieToHash(jscookies, cookie.host, cookie.path, cookie.name, jscookie);
|
||||
}
|
||||
aWindow.cookies.push(jscookies[cookie.host][cookie.path][cookie.name]);
|
||||
window.cookies.push(jscookies[cookie.host][cookie.path][cookie.name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// don't include empty cookie sections
|
||||
for (i = 0; i < aWindows.length; i++)
|
||||
if (aWindows[i].cookies.length == 0)
|
||||
delete aWindows[i].cookies;
|
||||
// don't include empty cookie sections
|
||||
if (!window.cookies.length)
|
||||
delete window.cookies;
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -2438,18 +2485,19 @@ SessionStoreService.prototype = {
|
||||
}
|
||||
|
||||
// collect the data for all windows
|
||||
var total = [], windows = [];
|
||||
var total = [], windows = {}, ids = [];
|
||||
var nonPopupCount = 0;
|
||||
var ix;
|
||||
for (ix in this._windows) {
|
||||
if (this._windows[ix]._restoring) // window data is still in _statesToRestore
|
||||
continue;
|
||||
total.push(this._windows[ix]);
|
||||
windows.push(ix);
|
||||
ids.push(ix);
|
||||
windows[ix] = this._windows[ix];
|
||||
if (!this._windows[ix].isPopup)
|
||||
nonPopupCount++;
|
||||
}
|
||||
this._updateCookies(total);
|
||||
this._updateCookies(windows);
|
||||
|
||||
// collect the data for all windows yet to be restored
|
||||
for (ix in this._statesToRestore) {
|
||||
@ -2500,7 +2548,7 @@ SessionStoreService.prototype = {
|
||||
if (activeWindow) {
|
||||
this.activeWindowSSiCache = activeWindow.__SSi || "";
|
||||
}
|
||||
ix = windows.indexOf(this.activeWindowSSiCache);
|
||||
ix = ids.indexOf(this.activeWindowSSiCache);
|
||||
// We don't want to restore focus to a minimized window or a window which had all its
|
||||
// tabs stripped out (doesn't exist).
|
||||
if (ix != -1 && total[ix] && total[ix].sizemode == "minimized")
|
||||
@ -2539,10 +2587,12 @@ SessionStoreService.prototype = {
|
||||
this._collectWindowData(aWindow);
|
||||
}
|
||||
|
||||
var total = [this._windows[aWindow.__SSi]];
|
||||
this._updateCookies(total);
|
||||
var winData = this._windows[aWindow.__SSi];
|
||||
let windows = {};
|
||||
windows[aWindow.__SSi] = winData;
|
||||
this._updateCookies(windows);
|
||||
|
||||
return { windows: total };
|
||||
return { windows: [winData] };
|
||||
},
|
||||
|
||||
_collectWindowData: function sss_collectWindowData(aWindow) {
|
||||
@ -2864,7 +2914,7 @@ SessionStoreService.prototype = {
|
||||
for (let name in tabData.attributes)
|
||||
this.xulAttributes[name] = true;
|
||||
|
||||
tabData._tabStillLoading = true;
|
||||
browser.__SS_tabStillLoading = true;
|
||||
|
||||
// keep the data around to prevent dataloss in case
|
||||
// a tab gets closed before it's been properly restored
|
||||
@ -2931,7 +2981,7 @@ SessionStoreService.prototype = {
|
||||
restoreHistory:
|
||||
function sss_restoreHistory(aWindow, aTabs, aTabData, aIdMap, aDocIdentMap) {
|
||||
var _this = this;
|
||||
while (aTabs.length > 0 && (!aTabData[0]._tabStillLoading || !aTabs[0].parentNode)) {
|
||||
while (aTabs.length > 0 && (!aTabs[0].linkedBrowser.__SS_tabStillLoading || !aTabs[0].parentNode)) {
|
||||
aTabs.shift(); // this tab got removed before being completely restored
|
||||
aTabData.shift();
|
||||
}
|
||||
@ -3327,31 +3377,53 @@ SessionStoreService.prototype = {
|
||||
if (!node)
|
||||
continue;
|
||||
|
||||
let eventType;
|
||||
let value = aData[key];
|
||||
if (typeof value == "string" && node.type != "file") {
|
||||
if (node.value == value)
|
||||
continue; // don't dispatch an input event for no change
|
||||
|
||||
node.value = value;
|
||||
|
||||
let event = aDocument.createEvent("UIEvents");
|
||||
event.initUIEvent("input", true, true, aDocument.defaultView, 0);
|
||||
node.dispatchEvent(event);
|
||||
eventType = "input";
|
||||
}
|
||||
else if (typeof value == "boolean")
|
||||
else if (typeof value == "boolean") {
|
||||
if (node.checked == value)
|
||||
continue; // don't dispatch a change event for no change
|
||||
|
||||
node.checked = value;
|
||||
else if (typeof value == "number")
|
||||
eventType = "change";
|
||||
}
|
||||
else if (typeof value == "number") {
|
||||
// We saved the value blindly since selects take more work to determine
|
||||
// default values. So now we should check to avoid unnecessary events.
|
||||
if (node.selectedIndex == value)
|
||||
continue;
|
||||
|
||||
try {
|
||||
node.selectedIndex = value;
|
||||
eventType = "change";
|
||||
} catch (ex) { /* throws for invalid indices */ }
|
||||
else if (value && value.fileList && value.type == "file" && node.type == "file")
|
||||
}
|
||||
else if (value && value.fileList && value.type == "file" && node.type == "file") {
|
||||
node.mozSetFileNameArray(value.fileList, value.fileList.length);
|
||||
eventType = "input";
|
||||
}
|
||||
else if (value && typeof value.indexOf == "function" && node.options) {
|
||||
Array.forEach(node.options, function(aOpt, aIx) {
|
||||
aOpt.selected = value.indexOf(aIx) > -1;
|
||||
|
||||
// Only fire the event here if this wasn't selected by default
|
||||
if (!aOpt.defaultSelected)
|
||||
eventType = "change";
|
||||
});
|
||||
}
|
||||
// NB: dispatching "change" events might have unintended side-effects
|
||||
|
||||
// Fire events for this node if applicable
|
||||
if (eventType) {
|
||||
let event = aDocument.createEvent("UIEvents");
|
||||
event.initUIEvent(eventType, true, true, aDocument.defaultView, 0);
|
||||
node.dispatchEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3563,6 +3635,7 @@ SessionStoreService.prototype = {
|
||||
while (oState._closedWindows.length) {
|
||||
let i = oState._closedWindows.length - 1;
|
||||
if (oState._closedWindows[i]._shouldRestore) {
|
||||
delete oState._closedWindows[i]._shouldRestore;
|
||||
oState.windows.unshift(oState._closedWindows.pop());
|
||||
}
|
||||
else {
|
||||
@ -4031,7 +4104,7 @@ SessionStoreService.prototype = {
|
||||
let cookieHosts = {};
|
||||
aTargetWinState.tabs.forEach(function(tab) {
|
||||
tab.entries.forEach(function(entry) {
|
||||
this._extractHostsForCookies(entry, cookieHosts, false)
|
||||
this._extractHostsForCookiesFromEntry(entry, cookieHosts, false);
|
||||
}, this);
|
||||
}, this);
|
||||
|
||||
@ -4062,18 +4135,7 @@ SessionStoreService.prototype = {
|
||||
* @returns the object's JSON representation
|
||||
*/
|
||||
_toJSONString: function sss_toJSONString(aJSObject) {
|
||||
// We never want to save __lastSessionWindowID across sessions, but we do
|
||||
// want it exported to consumers when running (eg. Private Browsing).
|
||||
let internalKeys = INTERNAL_KEYS;
|
||||
if (this._loadState == STATE_QUITTING) {
|
||||
internalKeys = internalKeys.slice();
|
||||
internalKeys.push("__lastSessionWindowID");
|
||||
}
|
||||
function exclude(key, value) {
|
||||
// returning undefined results in the exclusion of that key
|
||||
return internalKeys.indexOf(key) == -1 ? value : undefined;
|
||||
}
|
||||
return JSON.stringify(aJSObject, exclude);
|
||||
return JSON.stringify(aJSObject);
|
||||
},
|
||||
|
||||
_sendRestoreCompletedNotifications: function sss_sendRestoreCompletedNotifications() {
|
||||
|
@ -50,6 +50,8 @@ include $(topsrcdir)/config/rules.mk
|
||||
|
||||
_BROWSER_TEST_FILES = \
|
||||
head.js \
|
||||
browser_form_restore_events.js \
|
||||
browser_form_restore_events_sample.html \
|
||||
browser_248970_a.js \
|
||||
browser_248970_b.js \
|
||||
browser_248970_b_sample.html \
|
||||
@ -98,8 +100,6 @@ _BROWSER_TEST_FILES = \
|
||||
browser_465223.js \
|
||||
browser_466937.js \
|
||||
browser_466937_sample.html \
|
||||
browser_476161.js \
|
||||
browser_476161_sample.html \
|
||||
browser_477657.js \
|
||||
browser_480148.js \
|
||||
browser_480893.js \
|
||||
|
@ -1,24 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<title>Test for bug 476161</title>
|
||||
|
||||
<script>
|
||||
|
||||
document.addEventListener("input", function(aEvent) {
|
||||
var inputEl = aEvent.originalTarget;
|
||||
var changedEl = document.getElementById("changed");
|
||||
|
||||
changedEl.textContent += " " + inputEl.id;
|
||||
}, false);
|
||||
|
||||
</script>
|
||||
|
||||
<h3>Text fields with changed text</h3>
|
||||
<input type="text" id="modify1">
|
||||
<input type="text" id="modify2" value="preset value">
|
||||
|
||||
<h3>Text fields with unchanged text</h3>
|
||||
<input type="text" id="unchanged1">
|
||||
<input type="text" id="unchanged2" value="preset value">
|
||||
|
||||
<h3>Changed field IDs</h3>
|
||||
<div id="changed"></div>
|
@ -50,7 +50,7 @@ function test() {
|
||||
// Undo pinning
|
||||
gBrowser.unpinTab(tab1);
|
||||
|
||||
is(tab1.linkedBrowser.__SS_data._tabStillLoading, true,
|
||||
is(tab1.linkedBrowser.__SS_tabStillLoading, true,
|
||||
"_tabStillLoading should be true.");
|
||||
|
||||
// Close and restore tab
|
||||
|
@ -35,33 +35,64 @@
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
function test() {
|
||||
/** Test for Bug 476161 **/
|
||||
|
||||
/** Originally a test for Bug 476161, but then expanded to include all input types in bug 640136 **/
|
||||
|
||||
waitForExplicitFinish();
|
||||
|
||||
|
||||
let file = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties)
|
||||
.get("TmpD", Components.interfaces.nsIFile);
|
||||
|
||||
let testURL = "http://mochi.test:8888/browser/" +
|
||||
"browser/components/sessionstore/test/browser/browser_476161_sample.html";
|
||||
"browser/components/sessionstore/test/browser/browser_form_restore_events_sample.html";
|
||||
let tab = gBrowser.addTab(testURL);
|
||||
tab.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
let doc = tab.linkedBrowser.contentDocument;
|
||||
|
||||
doc.getElementById("modify1").value += Math.random();
|
||||
doc.getElementById("modify2").value += " " + Date.now();
|
||||
|
||||
|
||||
// text fields
|
||||
doc.getElementById("modify01").value += Math.random();
|
||||
doc.getElementById("modify02").value += " " + Date.now();
|
||||
|
||||
// textareas
|
||||
doc.getElementById("modify03").value += Math.random();
|
||||
doc.getElementById("modify04").value += " " + Date.now();
|
||||
|
||||
// file
|
||||
doc.getElementById("modify05").value = file.path;
|
||||
|
||||
// select
|
||||
doc.getElementById("modify06").selectedIndex = 1;
|
||||
var multipleChange = doc.getElementById("modify07");
|
||||
Array.forEach(multipleChange.options, function(option) option.selected = true);
|
||||
|
||||
// checkbox
|
||||
doc.getElementById("modify08").checked = true;
|
||||
doc.getElementById("modify09").checked = false;
|
||||
|
||||
// radio
|
||||
// select one then another in the same group - only last one should get event on restore
|
||||
doc.getElementById("modify10").checked = true;
|
||||
doc.getElementById("modify11").checked = true;
|
||||
|
||||
|
||||
let tab2 = gBrowser.duplicateTab(tab);
|
||||
tab2.linkedBrowser.addEventListener("load", function(aEvent) {
|
||||
tab2.linkedBrowser.removeEventListener("load", arguments.callee, true);
|
||||
let doc = tab2.linkedBrowser.contentDocument;
|
||||
let changed = doc.getElementById("changed").textContent.trim().split();
|
||||
|
||||
is(changed.sort().join(" "), "modify1 modify2",
|
||||
"input events were only dispatched for modified text fields");
|
||||
|
||||
let inputFired = doc.getElementById("inputFired").textContent.trim().split();
|
||||
let changeFired = doc.getElementById("changeFired").textContent.trim().split();
|
||||
|
||||
is(inputFired.sort().join(" "), "modify01 modify02 modify03 modify04 modify05",
|
||||
"input events were only dispatched for modified input, textarea fields");
|
||||
|
||||
is(changeFired.sort().join(" "), "modify06 modify07 modify08 modify09 modify11",
|
||||
"change events were only dispatched for modified select, checkbox, radio fields");
|
||||
|
||||
// clean up
|
||||
gBrowser.removeTab(tab2);
|
||||
gBrowser.removeTab(tab);
|
||||
|
||||
|
||||
finish();
|
||||
}, true);
|
||||
}, true);
|
@ -0,0 +1,98 @@
|
||||
<!DOCTYPE html>
|
||||
<title>Test for form restore events (originally bug 476161)</title>
|
||||
|
||||
<script>
|
||||
|
||||
document.addEventListener("input", function(aEvent) {
|
||||
var inputEl = aEvent.originalTarget;
|
||||
var changedEl = document.getElementById("inputFired");
|
||||
changedEl.textContent += " " + inputEl.id;
|
||||
}, false);
|
||||
|
||||
document.addEventListener("change", function(aEvent) {
|
||||
var inputEl = aEvent.originalTarget;
|
||||
var changedEl = document.getElementById("changeFired");
|
||||
changedEl.textContent += " " + inputEl.id;
|
||||
}, false);
|
||||
|
||||
</script>
|
||||
|
||||
<!-- input events -->
|
||||
<h3>Text fields with changed text</h3>
|
||||
<input type="text" id="modify1">
|
||||
<input type="text" id="modify2" value="preset value">
|
||||
<input type="text" id="modify01">
|
||||
<input type="text" id="modify02" value="preset value">
|
||||
|
||||
<h3>Text fields with unchanged text</h3>
|
||||
<input type="text" id="unchanged1">
|
||||
<input type="text" id="unchanged2" value="preset value">
|
||||
<input type="text" id="unchanged01">
|
||||
<input type="text" id="unchanged02" value="preset value">
|
||||
|
||||
<h3>Textarea with changed text</h3>
|
||||
<textarea id="modify03"></textarea>
|
||||
<textarea id="modify04">preset value</textarea>
|
||||
|
||||
<h3>Textarea with unchanged text</h3>
|
||||
<textarea id="unchanged03"></textarea>
|
||||
<textarea id="unchanged04">preset value</textarea>
|
||||
|
||||
<h3>file field with changed value</h3>
|
||||
<input type="file" id="modify05">
|
||||
|
||||
<h3>file field with unchanged value</h3>
|
||||
<input type="file" id="unchanged05">
|
||||
|
||||
<!-- change events -->
|
||||
|
||||
<h3>Select menu with changed selection</h3>
|
||||
<select id="modify06">
|
||||
<option value="one">one</option>
|
||||
<option value="two">two</option>
|
||||
<option value="three">three</option>
|
||||
</select>
|
||||
|
||||
<h3>Select menu with unchanged selection (change event still fires)</h3>
|
||||
<select id="unchanged06">
|
||||
<option value="one">one</option>
|
||||
<option value="two" selected>two</option>
|
||||
<option value="three">three</option>
|
||||
</select>
|
||||
|
||||
<h3>Multiple Select menu with changed selection</h3>
|
||||
<select id="modify07" multiple>
|
||||
<option value="one">one</option>
|
||||
<option value="two" selected>two</option>
|
||||
<option value="three">three</option>
|
||||
</select>
|
||||
|
||||
<h3>Select menu with unchanged selection</h3>
|
||||
<select id="unchanged07" multiple>
|
||||
<option value="one">one</option>
|
||||
<option value="two" selected>two</option>
|
||||
<option value="three" selected>three</option>
|
||||
</select>
|
||||
|
||||
<h3>checkbox with changed value</h3>
|
||||
<input type="checkbox" id="modify08">
|
||||
<input type="checkbox" id="modify09" checked>
|
||||
|
||||
<h3>checkbox with unchanged value</h3>
|
||||
<input type="checkbox" id="unchanged08">
|
||||
<input type="checkbox" id="unchanged09" checked>
|
||||
|
||||
<h3>radio with changed value</h3>
|
||||
<input type="radio" id="modify10" name="group">Radio 1</input>
|
||||
<input type="radio" id="modify11" name="group">Radio 2</input>
|
||||
<input type="radio" id="modify12" name="group" checked>Radio 3</input>
|
||||
|
||||
<h3>radio with unchanged value</h3>
|
||||
<input type="radio" id="unchanged10" name="group2">Radio 4</input>
|
||||
<input type="radio" id="unchanged11" name="group2">Radio 5</input>
|
||||
<input type="radio" id="unchanged12" name="group2" checked>Radio 6</input>
|
||||
|
||||
<h3>Changed field IDs</h3>
|
||||
<div id="changed"></div>
|
||||
<div id="inputFired"></div>
|
||||
<div id="changeFired"></div>
|
@ -44,7 +44,6 @@ include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
MODULE = shellservice
|
||||
FORCE_STATIC_LIB = 1
|
||||
FORCE_USE_PIC = 1
|
||||
ifndef MOZ_MEMORY
|
||||
USE_STATIC_LIBS = 1
|
||||
endif
|
||||
|
Before Width: | Height: | Size: 606 B After Width: | Height: | Size: 606 B |
Before Width: | Height: | Size: 7.9 KiB After Width: | Height: | Size: 7.9 KiB |
Before Width: | Height: | Size: 573 B After Width: | Height: | Size: 573 B |
Before Width: | Height: | Size: 767 B After Width: | Height: | Size: 767 B |
Before Width: | Height: | Size: 393 B After Width: | Height: | Size: 393 B |
@ -42,6 +42,17 @@ VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
DIRS = browser communicator
|
||||
DIRS = communicator
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
FILES := \
|
||||
icon.png \
|
||||
preview.png \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DIST)/bin/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
|
||||
|
||||
install:: $(FILES)
|
||||
$(SYSINSTALL) $(IFLAGS1) $(foreach f,$^,"$f") $(DESTDIR)$(mozappdir)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
|
||||
|
Before Width: | Height: | Size: 822 B After Width: | Height: | Size: 822 B |
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 865 B After Width: | Height: | Size: 865 B |
Before Width: | Height: | Size: 928 B After Width: | Height: | Size: 928 B |
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
Before Width: | Height: | Size: 6.7 KiB After Width: | Height: | Size: 6.7 KiB |
Before Width: | Height: | Size: 405 B After Width: | Height: | Size: 405 B |
Before Width: | Height: | Size: 293 B After Width: | Height: | Size: 293 B |
@ -51,7 +51,7 @@
|
||||
@namespace url("http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul");
|
||||
@namespace html url("http://www.w3.org/1999/xhtml");
|
||||
|
||||
%include ../../browserShared.inc
|
||||
%include ../browserShared.inc
|
||||
%filter substitution
|
||||
%define toolbarHighlight rgba(255,255,255,.3)
|
||||
%define selectedTabHighlight rgba(255,255,255,.8) 1px, rgba(255,255,255,.5) 3px
|
@ -1,56 +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 the Mozilla Browser code.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Netscape Communications Corporation.
|
||||
# Portions created by the Initial Developer are Copyright (C) 2002
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Brian Ryner <bryner@brianryner.com>
|
||||
#
|
||||
# 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 *****
|
||||
|
||||
DEPTH = ../../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
FILES := \
|
||||
icon.png \
|
||||
preview.png \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DIST)/bin/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
|
||||
|
||||
install:: $(FILES)
|
||||
$(SYSINSTALL) $(IFLAGS1) $(foreach f,$^,"$f") $(DESTDIR)$(mozappdir)/extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}
|
Before Width: | Height: | Size: 882 B After Width: | Height: | Size: 882 B |
Before Width: | Height: | Size: 869 B After Width: | Height: | Size: 869 B |
Before Width: | Height: | Size: 879 B After Width: | Height: | Size: 879 B |
Before Width: | Height: | Size: 879 B After Width: | Height: | Size: 879 B |
Before Width: | Height: | Size: 610 B After Width: | Height: | Size: 610 B |
Before Width: | Height: | Size: 1012 B After Width: | Height: | Size: 1012 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 982 B After Width: | Height: | Size: 982 B |
Before Width: | Height: | Size: 640 B After Width: | Height: | Size: 640 B |
Before Width: | Height: | Size: 855 B After Width: | Height: | Size: 855 B |
Before Width: | Height: | Size: 838 B After Width: | Height: | Size: 838 B |
Before Width: | Height: | Size: 858 B After Width: | Height: | Size: 858 B |
Before Width: | Height: | Size: 646 B After Width: | Height: | Size: 646 B |
Before Width: | Height: | Size: 872 B After Width: | Height: | Size: 872 B |
Before Width: | Height: | Size: 871 B After Width: | Height: | Size: 871 B |
Before Width: | Height: | Size: 871 B After Width: | Height: | Size: 871 B |
Before Width: | Height: | Size: 600 B After Width: | Height: | Size: 600 B |
Before Width: | Height: | Size: 1004 B After Width: | Height: | Size: 1004 B |
Before Width: | Height: | Size: 1007 B After Width: | Height: | Size: 1007 B |
Before Width: | Height: | Size: 957 B After Width: | Height: | Size: 957 B |
Before Width: | Height: | Size: 624 B After Width: | Height: | Size: 624 B |
Before Width: | Height: | Size: 846 B After Width: | Height: | Size: 846 B |
Before Width: | Height: | Size: 840 B After Width: | Height: | Size: 840 B |
Before Width: | Height: | Size: 854 B After Width: | Height: | Size: 854 B |
Before Width: | Height: | Size: 637 B After Width: | Height: | Size: 637 B |
Before Width: | Height: | Size: 661 B After Width: | Height: | Size: 661 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 799 B After Width: | Height: | Size: 799 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 799 B After Width: | Height: | Size: 799 B |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 799 B After Width: | Height: | Size: 799 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
Before Width: | Height: | Size: 6.6 KiB After Width: | Height: | Size: 6.6 KiB |
Before Width: | Height: | Size: 830 B After Width: | Height: | Size: 830 B |
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 8.6 KiB |
Before Width: | Height: | Size: 461 B After Width: | Height: | Size: 461 B |
Before Width: | Height: | Size: 508 B After Width: | Height: | Size: 508 B |
Before Width: | Height: | Size: 670 B After Width: | Height: | Size: 670 B |
Before Width: | Height: | Size: 599 B After Width: | Height: | Size: 599 B |
Before Width: | Height: | Size: 732 B After Width: | Height: | Size: 732 B |
Before Width: | Height: | Size: 767 B After Width: | Height: | Size: 767 B |
Before Width: | Height: | Size: 678 B After Width: | Height: | Size: 678 B |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 723 B After Width: | Height: | Size: 723 B |
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 877 B After Width: | Height: | Size: 877 B |
Before Width: | Height: | Size: 583 B After Width: | Height: | Size: 583 B |