Merge fx-team to m-c
|
@ -1018,6 +1018,8 @@ pref("browser.sessionstore.restore_pinned_tabs_on_demand", false);
|
|||
pref("browser.sessionstore.upgradeBackup.latestBuildID", "");
|
||||
// End-users should not run sessionstore in debug mode
|
||||
pref("browser.sessionstore.debug", false);
|
||||
// Forget closed windows/tabs after two weeks
|
||||
pref("browser.sessionstore.cleanup.forget_closed_after", 1209600000);
|
||||
|
||||
// allow META refresh by default
|
||||
pref("accessibility.blockautorefresh", false);
|
||||
|
|
|
@ -111,14 +111,20 @@ function restoreSession() {
|
|||
|
||||
// restore the session into a new window and close the current tab
|
||||
var newWindow = top.openDialog(top.location, "_blank", "chrome,dialog=no,all");
|
||||
newWindow.addEventListener("load", function() {
|
||||
newWindow.removeEventListener("load", arguments.callee, true);
|
||||
|
||||
var obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
|
||||
obs.addObserver(function observe(win, topic) {
|
||||
if (win != newWindow) {
|
||||
return;
|
||||
}
|
||||
|
||||
obs.removeObserver(observe, topic);
|
||||
ss.setWindowState(newWindow, stateString, true);
|
||||
|
||||
var tabbrowser = top.gBrowser;
|
||||
var tabIndex = tabbrowser.getBrowserIndexForDocument(document);
|
||||
tabbrowser.removeTab(tabbrowser.tabs[tabIndex]);
|
||||
}, true);
|
||||
}, "browser-delayed-startup-finished", false);
|
||||
}
|
||||
|
||||
function startNewSession() {
|
||||
|
|
|
@ -36,6 +36,7 @@ const OBSERVING = [
|
|||
"quit-application", "browser:purge-session-history",
|
||||
"browser:purge-domain-data",
|
||||
"gather-telemetry",
|
||||
"idle-daily",
|
||||
];
|
||||
|
||||
// XUL Window properties to (re)store
|
||||
|
@ -384,15 +385,14 @@ let SessionStoreInternal = {
|
|||
* Initialize the session using the state provided by SessionStartup
|
||||
*/
|
||||
initSession: function () {
|
||||
TelemetryStopwatch.start("FX_SESSION_RESTORE_STARTUP_INIT_SESSION_MS");
|
||||
let state;
|
||||
let ss = gSessionStartup;
|
||||
|
||||
try {
|
||||
if (ss.doRestore() ||
|
||||
ss.sessionType == Ci.nsISessionStartup.DEFER_SESSION)
|
||||
state = ss.state;
|
||||
if (ss.doRestore() ||
|
||||
ss.sessionType == Ci.nsISessionStartup.DEFER_SESSION) {
|
||||
state = ss.state;
|
||||
}
|
||||
catch(ex) { dump(ex + "\n"); } // no state to restore, which is ok
|
||||
|
||||
if (state) {
|
||||
try {
|
||||
|
@ -466,6 +466,7 @@ let SessionStoreInternal = {
|
|||
|
||||
this._performUpgradeBackup();
|
||||
|
||||
TelemetryStopwatch.finish("FX_SESSION_RESTORE_STARTUP_INIT_SESSION_MS");
|
||||
return state;
|
||||
},
|
||||
|
||||
|
@ -570,6 +571,9 @@ let SessionStoreInternal = {
|
|||
case "gather-telemetry":
|
||||
this.onGatherTelemetry();
|
||||
break;
|
||||
case "idle-daily":
|
||||
this.onIdleDaily();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -966,7 +970,10 @@ let SessionStoreInternal = {
|
|||
} else {
|
||||
let initialState = this.initSession();
|
||||
this._sessionInitialized = true;
|
||||
|
||||
TelemetryStopwatch.start("FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS");
|
||||
this.onLoad(aWindow, initialState);
|
||||
TelemetryStopwatch.finish("FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS");
|
||||
|
||||
// Let everyone know we're done.
|
||||
this._deferredInitialized.resolve();
|
||||
|
@ -1425,6 +1432,39 @@ let SessionStoreInternal = {
|
|||
return SessionFile.gatherTelemetry(stateString);
|
||||
},
|
||||
|
||||
// Clean up data that has been closed a long time ago.
|
||||
// Do not reschedule a save. This will wait for the next regular
|
||||
// save.
|
||||
onIdleDaily: function() {
|
||||
// Remove old closed windows
|
||||
this._cleanupOldData([this._closedWindows]);
|
||||
|
||||
// Remove closed tabs of closed windows
|
||||
this._cleanupOldData([winData._closedTabs for (winData of this._closedWindows)]);
|
||||
|
||||
// Remove closed tabs of open windows
|
||||
this._cleanupOldData([this._windows[key]._closedTabs for (key of Object.keys(this._windows))]);
|
||||
},
|
||||
|
||||
// Remove "old" data from an array
|
||||
_cleanupOldData: function(targets) {
|
||||
const TIME_TO_LIVE = this._prefBranch.getIntPref("sessionstore.cleanup.forget_closed_after");
|
||||
const now = Date.now();
|
||||
|
||||
for (let array of targets) {
|
||||
for (let i = array.length - 1; i >= 0; --i) {
|
||||
let data = array[i];
|
||||
// Make sure that we have a timestamp to tell us when the target
|
||||
// has been closed. If we don't have a timestamp, default to a
|
||||
// safe timestamp: just now.
|
||||
data.closedAt = data.closedAt || now;
|
||||
if (now - data.closedAt > TIME_TO_LIVE) {
|
||||
array.splice(i, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/* ........ nsISessionStore API .............. */
|
||||
|
||||
getBrowserState: function ssi_getBrowserState() {
|
||||
|
@ -1668,6 +1708,8 @@ let SessionStoreInternal = {
|
|||
|
||||
// reopen the window
|
||||
let state = { windows: this._closedWindows.splice(aIndex, 1) };
|
||||
delete state.windows[0].closedAt; // Window is now open.
|
||||
|
||||
let window = this._openWindowWithState(state);
|
||||
this.windowToFocus = window;
|
||||
return window;
|
||||
|
@ -2469,6 +2511,7 @@ let SessionStoreInternal = {
|
|||
} else {
|
||||
delete tab.__SS_extdata;
|
||||
}
|
||||
delete tabData.closedAt; // Tab is now open.
|
||||
|
||||
// Flush all data from the content script synchronously. This is done so
|
||||
// that all async messages that are still on their way to chrome will
|
||||
|
|
|
@ -57,9 +57,11 @@ support-files =
|
|||
#disabled-for-intermittent-failures--bug-766044, browser_459906_sample.html
|
||||
#disabled-for-intermittent-failures--bug-765389, browser_461743_sample.html
|
||||
|
||||
[browser_aboutSessionRestore.js]
|
||||
[browser_attributes.js]
|
||||
[browser_broadcast.js]
|
||||
[browser_capabilities.js]
|
||||
[browser_cleaner.js]
|
||||
[browser_dying_cache.js]
|
||||
[browser_dynamic_frames.js]
|
||||
[browser_form_restore_events.js]
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const CRASH_SHENTRY = {url: "about:mozilla"};
|
||||
const CRASH_TAB = {entries: [CRASH_SHENTRY]};
|
||||
const CRASH_STATE = {windows: [{tabs: [CRASH_TAB]}]};
|
||||
|
||||
const TAB_FORMDATA = {id: {sessionData: CRASH_STATE}};
|
||||
const TAB_SHENTRY = {url: "about:sessionrestore", formdata: TAB_FORMDATA};
|
||||
const TAB_STATE = {entries: [TAB_SHENTRY]};
|
||||
|
||||
const FRAME_SCRIPT = "data:," +
|
||||
"content.document.getElementById('errorTryAgain').click()";
|
||||
|
||||
add_task(function* () {
|
||||
// Prepare a blank tab.
|
||||
let tab = gBrowser.addTab("about:blank");
|
||||
let browser = tab.linkedBrowser;
|
||||
yield promiseBrowserLoaded(browser);
|
||||
|
||||
// Fake a post-crash tab.
|
||||
ss.setTabState(tab, JSON.stringify(TAB_STATE));
|
||||
yield promiseTabRestored(tab);
|
||||
|
||||
ok(gBrowser.tabs.length > 1, "we have more than one tab");
|
||||
browser.messageManager.loadFrameScript(FRAME_SCRIPT, true);
|
||||
|
||||
// Wait until the new window was restored.
|
||||
let win = yield waitForNewWindow();
|
||||
yield promiseWindowClosed(win);
|
||||
|
||||
let [{tabs: [{entries: [{url}]}]}] = JSON.parse(ss.getClosedWindowData());
|
||||
is(url, "about:mozilla", "session was restored correctly");
|
||||
ss.forgetClosedWindow(0);
|
||||
});
|
||||
|
||||
function waitForNewWindow() {
|
||||
return new Promise(resolve => {
|
||||
Services.obs.addObserver(function observe(win, topic) {
|
||||
Services.obs.removeObserver(observe, topic);
|
||||
resolve(win);
|
||||
}, "browser-delayed-startup-finished", false);
|
||||
});
|
||||
}
|
|
@ -0,0 +1,160 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
|
||||
/*
|
||||
* This test ensures that Session Restore eventually forgets about
|
||||
* tabs and windows that have been closed a long time ago.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm", this);
|
||||
Cu.import("resource://gre/modules/osfile.jsm", this);
|
||||
Cu.import("resource://gre/modules/Task.jsm", this);
|
||||
|
||||
const LONG_TIME_AGO = 1;
|
||||
|
||||
const URL_TAB1 = "http://example.com/browser_cleaner.js?newtab1=" + Math.random();
|
||||
const URL_TAB2 = "http://example.com/browser_cleaner.js?newtab2=" + Math.random();
|
||||
const URL_NEWWIN = "http://example.com/browser_cleaner.js?newwin=" + Math.random();
|
||||
|
||||
function isRecent(stamp) {
|
||||
is(typeof stamp, "number", "This is a timestamp");
|
||||
return Date.now() - stamp <= 60000;
|
||||
}
|
||||
|
||||
function promiseCleanup () {
|
||||
info("Cleaning up browser");
|
||||
|
||||
return promiseBrowserState(getClosedState());
|
||||
};
|
||||
|
||||
function getClosedState() {
|
||||
return Cu.cloneInto(CLOSED_STATE, {});
|
||||
}
|
||||
|
||||
let CLOSED_STATE;
|
||||
|
||||
add_task(function* init() {
|
||||
while (ss.getClosedWindowCount() > 0) {
|
||||
ss.forgetClosedWindow(0);
|
||||
}
|
||||
while (ss.getClosedTabCount(window) > 0) {
|
||||
ss.forgetClosedTab(window, 0);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(function* test_open_and_close() {
|
||||
let newTab1 = gBrowser.addTab(URL_TAB1);
|
||||
yield promiseBrowserLoaded(newTab1.linkedBrowser);
|
||||
|
||||
let newTab2 = gBrowser.addTab(URL_TAB2);
|
||||
yield promiseBrowserLoaded(newTab2.linkedBrowser);
|
||||
|
||||
let newWin = yield promiseNewWindowLoaded();
|
||||
let tab = newWin.gBrowser.addTab(URL_NEWWIN);
|
||||
|
||||
yield promiseBrowserLoaded(tab.linkedBrowser);
|
||||
|
||||
|
||||
|
||||
info("1. Making sure that before closing, we don't have closedAt");
|
||||
// For the moment, no "closedAt"
|
||||
let state = JSON.parse(ss.getBrowserState());
|
||||
is(state.windows[0].closedAt || false, false, "1. Main window doesn't have closedAt");
|
||||
is(state.windows[1].closedAt || false, false, "1. Second window doesn't have closedAt");
|
||||
is(state.windows[0].tabs[0].closedAt || false, false, "1. First tab doesn't have closedAt");
|
||||
is(state.windows[0].tabs[1].closedAt || false, false, "1. Second tab doesn't have closedAt");
|
||||
|
||||
|
||||
|
||||
info("2. Making sure that after closing, we have closedAt");
|
||||
|
||||
// Now close stuff, this should add closeAt
|
||||
yield promiseWindowClosed(newWin);
|
||||
gBrowser.removeTab(newTab1);
|
||||
gBrowser.removeTab(newTab2);
|
||||
|
||||
state = CLOSED_STATE = JSON.parse(ss.getBrowserState());
|
||||
|
||||
is(state.windows[0].closedAt || false, false, "2. Main window doesn't have closedAt");
|
||||
ok(isRecent(state._closedWindows[0].closedAt), "2. Second window was closed recently");
|
||||
ok(isRecent(state.windows[0]._closedTabs[0].closedAt), "2. First tab was closed recently");
|
||||
ok(isRecent(state.windows[0]._closedTabs[1].closedAt), "2. Second tab was closed recently");
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_restore() {
|
||||
info("3. Making sure that after restoring, we don't have closedAt");
|
||||
yield promiseBrowserState(CLOSED_STATE);
|
||||
|
||||
let newWin = ss.undoCloseWindow(0);
|
||||
yield promiseDelayedStartupFinished(newWin);
|
||||
|
||||
let newTab2 = ss.undoCloseTab(window, 0);
|
||||
yield promiseTabRestored(newTab2);
|
||||
|
||||
let newTab1 = ss.undoCloseTab(window, 0);
|
||||
yield promiseTabRestored(newTab1);
|
||||
|
||||
let state = JSON.parse(ss.getBrowserState());
|
||||
|
||||
is(state.windows[0].closedAt || false, false, "3. Main window doesn't have closedAt");
|
||||
is(state.windows[1].closedAt || false, false, "3. Second window doesn't have closedAt");
|
||||
is(state.windows[0].tabs[0].closedAt || false, false, "3. First tab doesn't have closedAt");
|
||||
is(state.windows[0].tabs[1].closedAt || false, false, "3. Second tab doesn't have closedAt");
|
||||
|
||||
yield promiseWindowClosed(newWin);
|
||||
gBrowser.removeTab(newTab1);
|
||||
gBrowser.removeTab(newTab2);
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_old_data() {
|
||||
info("4. Removing closedAt from the sessionstore, making sure that it is added upon idle-daily");
|
||||
|
||||
let state = getClosedState();
|
||||
delete state._closedWindows[0].closedAt;
|
||||
delete state.windows[0]._closedTabs[0].closedAt;
|
||||
delete state.windows[0]._closedTabs[1].closedAt;
|
||||
yield promiseBrowserState(state);
|
||||
|
||||
info("Sending idle-daily");
|
||||
Services.obs.notifyObservers(null, "idle-daily", "");
|
||||
info("Sent idle-daily");
|
||||
|
||||
state = JSON.parse(ss.getBrowserState());
|
||||
is(state.windows[0].closedAt || false, false, "4. Main window doesn't have closedAt");
|
||||
ok(isRecent(state._closedWindows[0].closedAt), "4. Second window was closed recently");
|
||||
ok(isRecent(state.windows[0]._closedTabs[0].closedAt), "4. First tab was closed recently");
|
||||
ok(isRecent(state.windows[0]._closedTabs[1].closedAt), "4. Second tab was closed recently");
|
||||
yield promiseCleanup();
|
||||
});
|
||||
|
||||
|
||||
add_task(function* test_cleanup() {
|
||||
|
||||
info("5. Altering closedAt to an old date, making sure that stuff gets collected, eventually");
|
||||
yield promiseCleanup();
|
||||
|
||||
let state = getClosedState();
|
||||
state._closedWindows[0].closedAt = LONG_TIME_AGO;
|
||||
state.windows[0]._closedTabs[0].closedAt = LONG_TIME_AGO;
|
||||
state.windows[0]._closedTabs[1].closedAt = Date.now();
|
||||
let url = state.windows[0]._closedTabs[1].state.entries[0].url;
|
||||
|
||||
yield promiseBrowserState(state);
|
||||
|
||||
info("Sending idle-daily");
|
||||
Services.obs.notifyObservers(null, "idle-daily", "");
|
||||
info("Sent idle-daily");
|
||||
|
||||
state = JSON.parse(ss.getBrowserState());
|
||||
is(state._closedWindows[0], undefined, "5. Second window was forgotten");
|
||||
|
||||
is(state.windows[0]._closedTabs.length, 1, "5. Only one closed tab left");
|
||||
is(state.windows[0]._closedTabs[0].state.entries[0].url, url, "5. The second tab is still here");
|
||||
yield promiseCleanup();
|
||||
});
|
||||
|
|
@ -88,6 +88,12 @@ function provideWindow(aCallback, aURL, aFeatures) {
|
|||
|
||||
// This assumes that tests will at least have some state/entries
|
||||
function waitForBrowserState(aState, aSetStateCallback) {
|
||||
if (typeof aState == "string") {
|
||||
aState = JSON.parse(aState);
|
||||
}
|
||||
if (typeof aState != "object") {
|
||||
throw new TypeError("Argument must be an object or a JSON representation of an object");
|
||||
}
|
||||
let windows = [window];
|
||||
let tabsRestored = 0;
|
||||
let expectedTabsRestored = 0;
|
||||
|
@ -172,6 +178,10 @@ function waitForBrowserState(aState, aSetStateCallback) {
|
|||
ss.setBrowserState(JSON.stringify(aState));
|
||||
}
|
||||
|
||||
function promiseBrowserState(aState) {
|
||||
return new Promise(resolve => waitForBrowserState(aState, resolve));
|
||||
}
|
||||
|
||||
// Doesn't assume that the tab needs to be closed in a cleanup function.
|
||||
// If that's the case, the test author should handle that in the test.
|
||||
function waitForTabState(aTab, aState, aCallback) {
|
||||
|
@ -481,6 +491,9 @@ function whenDelayedStartupFinished(aWindow, aCallback) {
|
|||
}
|
||||
}, "browser-delayed-startup-finished", false);
|
||||
}
|
||||
function promiseDelayedStartupFinished(aWindow) {
|
||||
return new Promise((resolve) => whenDelayedStartupFinished(aWindow, resolve));
|
||||
}
|
||||
|
||||
/**
|
||||
* The test runner that controls the execution flow of our tests.
|
||||
|
|
|
@ -26,6 +26,11 @@
|
|||
min-height: 18px;
|
||||
}
|
||||
|
||||
#downloads-button[cui-areatype="toolbar"] > #downloads-indicator-anchor > #downloads-indicator-icon:-moz-lwtheme-brighttext {
|
||||
background: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"),
|
||||
0, 198, 18, 180) center no-repeat;
|
||||
}
|
||||
|
||||
#downloads-button[cui-areatype="toolbar"][attention] > #downloads-indicator-anchor > #downloads-indicator-icon {
|
||||
background-image: url("chrome://browser/skin/downloads/download-glow.png");
|
||||
}
|
||||
|
@ -44,6 +49,11 @@
|
|||
background-size: 12px;
|
||||
}
|
||||
|
||||
#downloads-button:not([counter]) > #downloads-indicator-anchor >
|
||||
#downloads-button-progress-area > #downloads-indicator-counter:-moz-lwtheme-brighttext {
|
||||
background-image: -moz-image-rect(url("chrome://browser/skin/Toolbar-inverted.png"), 0, 198, 18, 180);
|
||||
}
|
||||
|
||||
#downloads-button:not([counter])[attention] > #downloads-indicator-anchor > #downloads-indicator-progress-area > #downloads-indicator-counter {
|
||||
background-image: url("chrome://browser/skin/downloads/download-glow.png");
|
||||
}
|
||||
|
@ -105,6 +115,12 @@
|
|||
text-align: center;
|
||||
}
|
||||
|
||||
#downloads-indicator-counter:-moz-lwtheme-brighttext {
|
||||
color: white;
|
||||
text-shadow: 0 0 1px rgba(0,0,0,.7),
|
||||
0 1px 1.5px rgba(0,0,0,.5);
|
||||
}
|
||||
|
||||
#downloads-indicator-progress {
|
||||
width: 18px;
|
||||
height: 6px;
|
||||
|
|
|
@ -577,7 +577,7 @@ nsDOMWindowUtils::GetResolution(float* aXResolution, float* aYResolution)
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMWindowUtils::GetIsHistoryRestored(bool* aIsHistoryRestored) {
|
||||
nsDOMWindowUtils::GetIsResolutionSet(bool* aIsResolutionSet) {
|
||||
if (!nsContentUtils::IsCallerChrome()) {
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
|
@ -588,7 +588,7 @@ nsDOMWindowUtils::GetIsHistoryRestored(bool* aIsHistoryRestored) {
|
|||
}
|
||||
|
||||
const nsIScrollableFrame* sf = presShell->GetRootScrollFrameAsScrollable();
|
||||
*aIsHistoryRestored = sf && sf->DidHistoryRestore();
|
||||
*aIsResolutionSet = sf && sf->IsResolutionSet();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@ interface nsIRunnable;
|
|||
interface nsICompositionStringSynthesizer;
|
||||
interface nsITranslationNodeList;
|
||||
|
||||
[scriptable, uuid(8489681a-7407-457e-b889-53d1ae999b30)]
|
||||
[scriptable, uuid(aae2d993-366f-43e6-aa51-f2eb83935e7d)]
|
||||
interface nsIDOMWindowUtils : nsISupports {
|
||||
|
||||
/**
|
||||
|
@ -231,13 +231,13 @@ interface nsIDOMWindowUtils : nsISupports {
|
|||
void getResolution(out float aXResolution, out float aYResolution);
|
||||
|
||||
/**
|
||||
* Whether the current window has been restored from session history.
|
||||
* This gives a way to check whether the provided resolution and scroll
|
||||
* position are default values or restored from a previous session.
|
||||
* Whether the resolution has been set by the user.
|
||||
* This gives a way to check whether the provided resolution is the default
|
||||
* value or restored from a previous session.
|
||||
*
|
||||
* Can only be accessed with chrome privileges.
|
||||
*/
|
||||
readonly attribute boolean isHistoryRestored;
|
||||
readonly attribute boolean isResolutionSet;
|
||||
|
||||
/**
|
||||
* Whether the next paint should be flagged as the first paint for a document.
|
||||
|
|
|
@ -1607,6 +1607,7 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter,
|
|||
, mCollapsedResizer(false)
|
||||
, mShouldBuildScrollableLayer(false)
|
||||
, mHasBeenScrolled(false)
|
||||
, mIsResolutionSet(false)
|
||||
{
|
||||
mScrollingActive = IsAlwaysActive();
|
||||
|
||||
|
@ -2795,6 +2796,7 @@ void
|
|||
ScrollFrameHelper::SetResolution(const gfxSize& aResolution)
|
||||
{
|
||||
mResolution = aResolution;
|
||||
mIsResolutionSet = true;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -4538,6 +4540,7 @@ ScrollFrameHelper::RestoreState(nsPresState* aState)
|
|||
mDidHistoryRestore = true;
|
||||
mLastPos = mScrolledFrame ? GetLogicalScrollPosition() : nsPoint(0,0);
|
||||
mResolution = aState->GetResolution();
|
||||
mIsResolutionSet = true;
|
||||
|
||||
if (mIsRoot) {
|
||||
mOuter->PresContext()->PresShell()->SetResolution(mResolution.width, mResolution.height);
|
||||
|
|
|
@ -407,6 +407,10 @@ public:
|
|||
// True if this frame has been scrolled at least once
|
||||
bool mHasBeenScrolled:1;
|
||||
|
||||
// True if the frame's resolution has been set via SetResolution or restored
|
||||
// via RestoreState.
|
||||
bool mIsResolutionSet:1;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @note This method might destroy the frame, pres shell and other objects.
|
||||
|
@ -658,6 +662,9 @@ public:
|
|||
virtual void ResetScrollPositionForLayerPixelAlignment() MOZ_OVERRIDE {
|
||||
mHelper.ResetScrollPositionForLayerPixelAlignment();
|
||||
}
|
||||
virtual bool IsResolutionSet() const MOZ_OVERRIDE {
|
||||
return mHelper.mIsResolutionSet;
|
||||
}
|
||||
virtual bool DidHistoryRestore() const MOZ_OVERRIDE {
|
||||
return mHelper.mDidHistoryRestore;
|
||||
}
|
||||
|
@ -972,6 +979,9 @@ public:
|
|||
virtual void ResetScrollPositionForLayerPixelAlignment() MOZ_OVERRIDE {
|
||||
mHelper.ResetScrollPositionForLayerPixelAlignment();
|
||||
}
|
||||
virtual bool IsResolutionSet() const MOZ_OVERRIDE {
|
||||
return mHelper.mIsResolutionSet;
|
||||
}
|
||||
virtual bool DidHistoryRestore() const MOZ_OVERRIDE {
|
||||
return mHelper.mDidHistoryRestore;
|
||||
}
|
||||
|
|
|
@ -271,6 +271,10 @@ public:
|
|||
* Was the current presentation state for this frame restored from history?
|
||||
*/
|
||||
virtual bool DidHistoryRestore() const = 0;
|
||||
/**
|
||||
* Was the current resolution set by the user or just default initialized?
|
||||
*/
|
||||
virtual bool IsResolutionSet() const = 0;
|
||||
/**
|
||||
* Clear the flag so that DidHistoryRestore() returns false until the next
|
||||
* RestoreState call.
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{ "title": "Firefox Marketplace",
|
||||
"url": "http://marketplace.firefox.com",
|
||||
"url": "https://marketplace.firefox.com/",
|
||||
"bgcolor": "#0095dd" }
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
{ "title": "Mozilla",
|
||||
"url": "http://mozilla.org",
|
||||
"url": "http://www.mozilla.org/en-US/",
|
||||
"bgcolor": "#c13832" }
|
||||
|
|
После Ширина: | Высота: | Размер: 803 B |
После Ширина: | Высота: | Размер: 722 B |
После Ширина: | Высота: | Размер: 668 B |
После Ширина: | Высота: | Размер: 716 B |
После Ширина: | Высота: | Размер: 813 B |
После Ширина: | Высота: | Размер: 670 B |
После Ширина: | Высота: | Размер: 727 B |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/alert_download_animation_1.png
Normal file
После Ширина: | Высота: | Размер: 541 B |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/alert_download_animation_2.png
Normal file
После Ширина: | Высота: | Размер: 539 B |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/alert_download_animation_3.png
Normal file
После Ширина: | Высота: | Размер: 562 B |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/alert_download_animation_4.png
Normal file
После Ширина: | Высота: | Размер: 553 B |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/alert_download_animation_5.png
Normal file
После Ширина: | Высота: | Размер: 562 B |
Двоичные данные
mobile/android/base/resources/drawable-hdpi/alert_download_animation_6.png
Normal file
После Ширина: | Высота: | Размер: 556 B |
После Ширина: | Высота: | Размер: 803 B |
После Ширина: | Высота: | Размер: 722 B |
После Ширина: | Высота: | Размер: 668 B |
После Ширина: | Высота: | Размер: 716 B |
После Ширина: | Высота: | Размер: 813 B |
После Ширина: | Высота: | Размер: 670 B |
После Ширина: | Высота: | Размер: 727 B |
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/alert_download_animation_1.png
Normal file
После Ширина: | Высота: | Размер: 541 B |
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/alert_download_animation_2.png
Normal file
После Ширина: | Высота: | Размер: 539 B |
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/alert_download_animation_3.png
Normal file
После Ширина: | Высота: | Размер: 562 B |
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/alert_download_animation_4.png
Normal file
После Ширина: | Высота: | Размер: 553 B |
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/alert_download_animation_5.png
Normal file
После Ширина: | Высота: | Размер: 562 B |
Двоичные данные
mobile/android/base/resources/drawable-xhdpi/alert_download_animation_6.png
Normal file
После Ширина: | Высота: | Размер: 556 B |
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:oneshot="false">
|
||||
|
||||
<item android:drawable="@drawable/alert_app_animation_1" android:duration="150" />
|
||||
<item android:drawable="@drawable/alert_app_animation_2" android:duration="150" />
|
||||
<item android:drawable="@drawable/alert_app_animation_3" android:duration="150" />
|
||||
<item android:drawable="@drawable/alert_app_animation_4" android:duration="150" />
|
||||
<item android:drawable="@drawable/alert_app_animation_5" android:duration="150" />
|
||||
<item android:drawable="@drawable/alert_app_animation_6" android:duration="150" />
|
||||
<item android:drawable="@drawable/alert_app_animation_7" android:duration="150" />
|
||||
|
||||
</animation-list>
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
|
||||
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:oneshot="false">
|
||||
|
||||
<item android:drawable="@drawable/alert_download_animation_1" android:duration="150" />
|
||||
<item android:drawable="@drawable/alert_download_animation_2" android:duration="150" />
|
||||
<item android:drawable="@drawable/alert_download_animation_3" android:duration="150" />
|
||||
<item android:drawable="@drawable/alert_download_animation_4" android:duration="150" />
|
||||
<item android:drawable="@drawable/alert_download_animation_5" android:duration="150" />
|
||||
<item android:drawable="@drawable/alert_download_animation_6" android:duration="150" />
|
||||
|
||||
</animation-list>
|
|
@ -4233,7 +4233,7 @@ Tab.prototype = {
|
|||
restoredSessionZoom: function() {
|
||||
let cwu = this.browser.contentWindow.QueryInterface(Ci.nsIInterfaceRequestor).getInterface(Ci.nsIDOMWindowUtils);
|
||||
|
||||
if (this._restoreZoom && cwu.isHistoryRestored) {
|
||||
if (this._restoreZoom && cwu.isResolutionSet) {
|
||||
return this._getGeckoZoom();
|
||||
}
|
||||
return null;
|
||||
|
|
|
@ -46,6 +46,7 @@ relativesrcdir toolkit/locales:
|
|||
locale/@AB_CD@/browser/overrides/about.dtd (%chrome/global/about.dtd)
|
||||
locale/@AB_CD@/browser/overrides/aboutAbout.dtd (%chrome/global/aboutAbout.dtd)
|
||||
locale/@AB_CD@/browser/overrides/aboutRights.dtd (%chrome/global/aboutRights.dtd)
|
||||
locale/@AB_CD@/browser/overrides/charsetMenu.properties (%chrome/global/charsetMenu.properties)
|
||||
locale/@AB_CD@/browser/overrides/commonDialogs.properties (%chrome/global/commonDialogs.properties)
|
||||
locale/@AB_CD@/browser/overrides/intl.properties (%chrome/global/intl.properties)
|
||||
locale/@AB_CD@/browser/overrides/intl.css (%chrome/global/intl.css)
|
||||
|
@ -70,6 +71,7 @@ relativesrcdir toolkit/locales:
|
|||
% override chrome://global/locale/about.dtd chrome://browser/locale/overrides/about.dtd
|
||||
% override chrome://global/locale/aboutAbout.dtd chrome://browser/locale/overrides/aboutAbout.dtd
|
||||
% override chrome://global/locale/aboutRights.dtd chrome://browser/locale/overrides/aboutRights.dtd
|
||||
% override chrome://global/locale/charsetMenu.properties chrome://browser/locale/overrides/charsetMenu.properties
|
||||
% override chrome://global/locale/commonDialogs.properties chrome://browser/locale/overrides/commonDialogs.properties
|
||||
% override chrome://mozapps/locale/handling/handling.properties chrome://browser/locale/handling.properties
|
||||
% override chrome://global/locale/intl.properties chrome://browser/locale/overrides/intl.properties
|
||||
|
|
|
@ -351,8 +351,7 @@ this.WebappManager = {
|
|||
notification = this._notify({
|
||||
title: Strings.GetStringFromName("checkingForUpdatesTitle"),
|
||||
message: Strings.GetStringFromName("checkingForUpdatesMessage"),
|
||||
// TODO: replace this with an animated icon.
|
||||
icon: "drawable://alert_app",
|
||||
icon: "drawable://alert_app_animation",
|
||||
progress: NaN,
|
||||
});
|
||||
}
|
||||
|
@ -392,10 +391,7 @@ this.WebappManager = {
|
|||
title: PluralForm.get(aApps.length, Strings.GetStringFromName("downloadingUpdateTitle")).
|
||||
replace("#1", aApps.length),
|
||||
message: Strings.formatStringFromName("downloadingUpdateMessage", [downloadingNames], 1),
|
||||
// TODO: replace this with an animated icon. UpdateService uses
|
||||
// android.R.drawable.stat_sys_download, but I don't think we can reference
|
||||
// a system icon with a drawable: URL here, so we'll have to craft our own.
|
||||
icon: "drawable://alert_download",
|
||||
icon: "drawable://alert_download_animation",
|
||||
// TODO: make this a determinate progress indicator once we can determine
|
||||
// the sizes of the APKs and observe their progress.
|
||||
progress: NaN,
|
||||
|
|
|
@ -2843,6 +2843,7 @@ SearchService.prototype = {
|
|||
this._initObservers.resolve(this._initRV);
|
||||
|
||||
Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "init-complete");
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_INIT_SYNC").add(true);
|
||||
|
||||
LOG("_syncInit end");
|
||||
},
|
||||
|
@ -2866,6 +2867,8 @@ SearchService.prototype = {
|
|||
gInitialized = true;
|
||||
this._initObservers.resolve(this._initRV);
|
||||
Services.obs.notifyObservers(null, SEARCH_SERVICE_TOPIC, "init-complete");
|
||||
Services.telemetry.getHistogramById("SEARCH_SERVICE_INIT_SYNC").add(false);
|
||||
|
||||
LOG("_asyncInit: Completed _asyncInit");
|
||||
}.bind(this));
|
||||
},
|
||||
|
|
|
@ -3330,6 +3330,22 @@
|
|||
"extended_statistics_ok": true,
|
||||
"description": "Widget: Time it takes for the message before a UI message (ms)"
|
||||
},
|
||||
"FX_SESSION_RESTORE_STARTUP_INIT_SESSION_MS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "30000",
|
||||
"n_buckets": 20,
|
||||
"extended_statistics_ok": true,
|
||||
"description": "Session restore: Time it takes to prepare the data structures for restoring a session (ms)"
|
||||
},
|
||||
"FX_SESSION_RESTORE_STARTUP_ONLOAD_INITIAL_WINDOW_MS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
"high": "30000",
|
||||
"n_buckets": 20,
|
||||
"extended_statistics_ok": true,
|
||||
"description": "Session restore: Time it takes to finish restoration once we have first opened a window (ms)"
|
||||
},
|
||||
"FX_SESSION_RESTORE_COLLECT_ALL_WINDOWS_DATA_MS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
|
@ -4267,6 +4283,11 @@
|
|||
"extended_statistics_ok": true,
|
||||
"description": "Time (ms) it takes to initialize the search service"
|
||||
},
|
||||
"SEARCH_SERVICE_INIT_SYNC": {
|
||||
"expires_in_version": "35",
|
||||
"kind": "boolean",
|
||||
"description": "search service has been initialized synchronously"
|
||||
},
|
||||
"SEARCH_SERVICE_BUILD_CACHE_MS": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "exponential",
|
||||
|
|