This commit is contained in:
Wes Kocher 2014-05-14 14:54:46 -07:00
Родитель 08b6cb88ca 219e6bff01
Коммит 33757bdbb1
48 изменённых файлов: 384 добавлений и 24 удалений

Просмотреть файл

@ -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

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 541 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 539 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 562 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 553 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 562 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 556 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 803 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 722 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 668 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 716 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 813 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 670 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 727 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 541 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 539 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 562 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 553 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 562 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 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",