diff --git a/browser/base/content/safeMode.css b/browser/base/content/safeMode.css index 4f093a452f..78be86e564 100644 --- a/browser/base/content/safeMode.css +++ b/browser/base/content/safeMode.css @@ -6,3 +6,11 @@ font-weight: bold; } +/* 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/. */ + +#resetProfileFooter { + font-weight: bold; +} + diff --git a/browser/base/content/safeMode.js b/browser/base/content/safeMode.js index e1e5c72859..5df931326e 100644 --- a/browser/base/content/safeMode.js +++ b/browser/base/content/safeMode.js @@ -2,127 +2,85 @@ 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/. */ -const Cc = Components.classes, - Ci = Components.interfaces, - Cu = Components.utils; - -Cu.import("resource://gre/modules/AddonManager.jsm"); +var Cc = Components.classes; +var Ci = Components.interfaces; +var Cu = Components.utils; + +const appStartup = Services.startup; + +Cu.import("resource://gre/modules/ResetProfile.jsm"); + +let defaultToReset = false; function restartApp() { - let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] - .getService(Ci.nsIAppStartup); - appStartup.quit(Ci.nsIAppStartup.eForceQuit | Ci.nsIAppStartup.eRestart); + appStartup.quit(appStartup.eForceQuit | appStartup.eRestart); } -function clearAllPrefs() { - var prefService = Cc["@mozilla.org/preferences-service;1"] - .getService(Ci.nsIPrefService); - prefService.resetUserPrefs(); - - // Remove the pref-overrides dir, if it exists - try { - var fileLocator = Cc["@mozilla.org/file/directory_service;1"] - .getService(Ci.nsIProperties); - const NS_APP_PREFS_OVERRIDE_DIR = "PrefDOverride"; - var prefOverridesDir = fileLocator.get(NS_APP_PREFS_OVERRIDE_DIR, - Ci.nsIFile); - prefOverridesDir.remove(true); - } catch (ex) { - Components.utils.reportError(ex); - } +function resetProfile() { + // Set the reset profile environment variable. + let env = Cc["@mozilla.org/process/environment;1"] + .getService(Ci.nsIEnvironment); + env.set("MOZ_RESET_PROFILE_RESTART", "1"); } -function restoreDefaultBookmarks() { - var prefBranch = Cc["@mozilla.org/preferences-service;1"] - .getService(Ci.nsIPrefBranch); - prefBranch.setBoolPref("browser.bookmarks.restore_default_bookmarks", true); -} - -function deleteLocalstore() { - const nsIDirectoryServiceContractID = "@mozilla.org/file/directory_service;1"; - const nsIProperties = Ci.nsIProperties; - var directoryService = Cc[nsIDirectoryServiceContractID] - .getService(nsIProperties); - // Local store file - var localstoreFile = directoryService.get("LStoreS", Components.interfaces.nsIFile); - // XUL store file - var xulstoreFile = directoryService.get("ProfD", Components.interfaces.nsIFile); - xulstoreFile.append("xulstore.json"); - try { - xulstoreFile.remove(false); - if (localstoreFile.exists()) { - localstoreFile.remove(false); - } - } catch(e) { - Components.utils.reportError(e); - } -} - -function disableAddons() { - AddonManager.getAllAddons(function(aAddons) { - aAddons.forEach(function(aAddon) { - if (aAddon.type == "theme") { - // Setting userDisabled to false on the default theme activates it, - // disables all other themes and deactivates the applied persona, if - // any. - const DEFAULT_THEME_ID = "{972ce4c6-7e08-4474-a285-3208198ce6fd}"; - if (aAddon.id == DEFAULT_THEME_ID) - aAddon.userDisabled = false; - } - else { - aAddon.userDisabled = true; - } - }); - - restartApp(); - }); -} - -function restoreDefaultSearchEngines() { - var searchService = Cc["@mozilla.org/browser/search-service;1"] - .getService(Ci.nsIBrowserSearchService); - - searchService.restoreDefaultEngines(); -} - -function onOK() { - try { - if (document.getElementById("resetUserPrefs").checked) - clearAllPrefs(); - if (document.getElementById("deleteBookmarks").checked) - restoreDefaultBookmarks(); - if (document.getElementById("resetToolbars").checked) - deleteLocalstore(); - if (document.getElementById("restoreSearch").checked) - restoreDefaultSearchEngines(); - if (document.getElementById("disableAddons").checked) { - disableAddons(); - // disableAddons will asynchronously restart the application - return false; - } - } catch(e) { - } - +function showResetDialog() { + // Prompt the user to confirm the reset. + let retVals = { + reset: false, + }; + window.openDialog("chrome://global/content/resetProfile.xul", null, + "chrome,modal,centerscreen,titlebar,dialog=yes", retVals); + if (!retVals.reset) + return; + resetProfile(); restartApp(); - return false; +} + +function onDefaultButton() { + if (defaultToReset) { + // Restart to reset the profile. + resetProfile(); + restartApp(); + // Return false to prevent starting into safe mode while restarting. + return false; + } else { + // Continue in safe mode. No restart needed. + return true; + } } function onCancel() { - let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"] - .getService(Ci.nsIAppStartup); - appStartup.quit(Ci.nsIAppStartup.eForceQuit); + appStartup.quit(appStartup.eForceQuit); +} + +function onExtra1() { + if (defaultToReset) { + // Continue in safe mode + window.close(); + return true; + } else { + // The reset dialog will handle starting the reset process if the user confirms. + showResetDialog(); + } + return false; } function onLoad() { - document.getElementById("tasks") - .addEventListener("CheckboxStateChange", UpdateOKButtonState, false); -} - -function UpdateOKButtonState() { - document.documentElement.getButton("accept").disabled = - !document.getElementById("resetUserPrefs").checked && - !document.getElementById("deleteBookmarks").checked && - !document.getElementById("resetToolbars").checked && - !document.getElementById("disableAddons").checked && - !document.getElementById("restoreSearch").checked; + let dialog = document.documentElement; + if (appStartup.automaticSafeModeNecessary) { + document.getElementById("autoSafeMode").hidden = false; + document.getElementById("safeMode").hidden = true; + if (ResetProfile.resetSupported()) { + document.getElementById("resetProfile").hidden = false; + } else { + // Hide the reset button is it's not supported. + document.documentElement.getButton("extra1").hidden = true; + } + } else { + if (!ResetProfile.resetSupported()) { + // Hide the reset button and text if it's not supported. + document.documentElement.getButton("extra1").hidden = true; + document.getElementById("resetProfileInstead").hidden = true; + } + } } diff --git a/browser/base/content/safeMode.xul b/browser/base/content/safeMode.xul index 656df6eaf8..a261a68a55 100644 --- a/browser/base/content/safeMode.xul +++ b/browser/base/content/safeMode.xul @@ -5,51 +5,49 @@ 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/. --> + %brandDTD; %safeModeDTD; - -%browserDTD; + +%resetProfileDTD; ]> + + buttons="accept,extra1" + buttonlabelaccept="&startSafeMode.label;" + buttonlabelextra1="&refreshProfile.label;" + maxwidth="&window.maxWidth;" + ondialogaccept="return onDefaultButton()" + ondialogcancel="onCancel();" + ondialogextra1="return onExtra1()" + onload="onLoad()"> + - - - &safeModeDescription.label; - - - - - - - - - - + + &autoSafeModeDescription3.label; - + + + &safeModeDescription3.label; + + &safeModeDescription4.label; + + &refreshProfileInstead.label; + + + + &refreshProfileInstead.label; + + diff --git a/browser/base/content/tabbrowser.xml b/browser/base/content/tabbrowser.xml index ed35c5ad9a..3b35eb7902 100644 --- a/browser/base/content/tabbrowser.xml +++ b/browser/base/content/tabbrowser.xml @@ -1447,11 +1447,6 @@ var uriIsAboutBlank = !aURI || aURI == "about:blank"; - if (!aURI || isBlankPageURL(aURI)) - t.setAttribute("label", this.mStringBundle.getString("tabs.emptyTabTitle")); - else - t.setAttribute("label", aURI); - t.setAttribute("crop", "end"); t.setAttribute("validate", "never"); //PMed t.setAttribute("onerror", "this.removeAttribute('image');"); @@ -1559,6 +1554,14 @@ // initialized by this point. this.mPanelContainer.appendChild(notificationbox); + // We've waited until the tab is in the DOM to set the label. This + // allows the TabLabelModified event to be properly dispatched. + if (!aURI || isBlankPageURL(aURI)) { + t.label = this.mStringBundle.getString("tabs.emptyTabTitle"); + } else { + t.label = aURI; + } + this.tabContainer.updateVisibility(); // wire up a progress listener for the new browser object. @@ -3401,8 +3404,7 @@ this._closeWindowWithLastTab = Services.prefs.getBoolPref("browser.tabs.closeWindowWithLastTab"); var tab = this.firstChild; - tab.setAttribute("label", - this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle")); + tab.label = this.tabbrowser.mStringBundle.getString("tabs.emptyTabTitle"); tab.setAttribute("crop", "end"); tab.setAttribute("onerror", "this.removeAttribute('image');"); this.adjustTabstrip(); @@ -4714,7 +4716,8 @@ role="presentation" anonid="tab-icon"/> + + + return this.getAttribute("label"); + + + this.setAttribute("label", val); + let event = new CustomEvent("TabLabelModified", { + bubbles: true, + cancelable: true + }); + this.dispatchEvent(event); + + // Let listeners prevent synchronizing the actual label to the + // visible label (allowing them to override the visible label). + if (!event.defaultPrevented) + this.visibleLabel = val; + + + + + return this.getAttribute("visibleLabel"); + + + this.setAttribute("visibleLabel", val); + + return this.getAttribute("pinned") == "true"; diff --git a/browser/base/content/test/general/browser_visibleLabel.js b/browser/base/content/test/general/browser_visibleLabel.js new file mode 100644 index 0000000000..c34b399af0 --- /dev/null +++ b/browser/base/content/test/general/browser_visibleLabel.js @@ -0,0 +1,94 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +/* Tests: + * verify that the visibleLabel attribute works + * verify the TabLabelModified event works for both existing and new tabs + */ + +function test() { + waitForExplicitFinish(); + registerCleanupFunction(function() { + gBrowser.removeCurrentTab({animate: false}); + }); + let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank", + {skipAnimation: true}); + tab.linkedBrowser.addEventListener("load", function onLoad(event) { + event.currentTarget.removeEventListener("load", onLoad, true); + executeSoon(afterLoad); + }, true); +} + +function afterLoad() { + let tab = gBrowser.selectedTab; + let xulLabel = document.getAnonymousElementByAttribute(tab, "anonid", + "tab-label"); + // Verify we're starting out on the right foot + is(tab.label, "New Tab", "Initial tab label is default"); + is(xulLabel.value, "New Tab", "Label element is default"); + is(tab.visibleLabel, "New Tab", "visibleLabel is default"); + + // Check that a normal label setting works correctly + tab.label = "Hello, world!"; + is(tab.label, "Hello, world!", "tab label attribute set via tab.label"); + is(xulLabel.value, "Hello, world!", "xul:label set via tab.label"); + is(tab.visibleLabel, "Hello, world!", "visibleLabel set via tab.label"); + + // Check that setting visibleLabel only affects the label element + tab.visibleLabel = "Goodnight, Irene"; + is(tab.label, "Hello, world!", "Tab.label unaffected by visibleLabel setter"); + is(xulLabel.value, "Goodnight, Irene", + "xul:label set by visibleLabel setter"); + is(tab.visibleLabel, "Goodnight, Irene", + "visibleLabel attribute set by visibleLabel setter"); + + // Check that setting the label property hits everything + tab.label = "One more label"; + is(tab.label, "One more label", + "Tab label set via label property after diverging from visibleLabel"); + is(xulLabel.value, "One more label", + "xul:label set via label property after diverging from visibleLabel"); + is(tab.visibleLabel, "One more label", + "visibleLabel set from label property after diverging from visibleLabel"); + + tab.addEventListener("TabLabelModified", overrideTabLabel, true); + tab.label = "This won't be the visibleLabel"; +} + +function overrideTabLabel(aEvent) { + aEvent.target.removeEventListener("TabLabelModified", overrideTabLabel, true); + aEvent.preventDefault(); + aEvent.stopPropagation(); + aEvent.target.visibleLabel = "Handler set this as the visible label"; + executeSoon(checkTabLabelModified); +} + +function checkTabLabelModified() { + let tab = gBrowser.selectedTab; + let xulLabel = document.getAnonymousElementByAttribute(tab, "anonid", + "tab-label"); + + is(tab.label, "This won't be the visibleLabel", + "Tab label set via label property that triggered event"); + is(xulLabel.value, "Handler set this as the visible label", + "xul:label set by TabLabelModified handler"); + is(tab.visibleLabel, "Handler set this as the visible label", + "visibleLabel set by TabLabelModified handler"); + + gBrowser.removeCurrentTab({animate: false}); + executeSoon(checkTabLabelModifiedOnNewTab); +} + +function checkTabLabelModifiedOnNewTab() { + gBrowser.tabContainer.addEventListener("TabLabelModified", + handleTabLabelModifiedOnNewTab, true); + let tab = gBrowser.selectedTab = gBrowser.addTab("about:blank", + {skipAnimation: true}); +} + +function handleTabLabelModifiedOnNewTab(aEvent) { + gBrowser.tabContainer.removeEventListener("TabLabelModified", + handleTabLabelModifiedOnNewTab, true); + ok(true, "Event received from new tab default being set"); + executeSoon(finish); +} diff --git a/browser/components/migration/content/aboutWelcomeBack.xhtml b/browser/components/migration/content/aboutWelcomeBack.xhtml index 7022682668..0fa76d4d87 100644 --- a/browser/components/migration/content/aboutWelcomeBack.xhtml +++ b/browser/components/migration/content/aboutWelcomeBack.xhtml @@ -33,7 +33,7 @@ - &welcomeback.pageTitle; + &welcomeback2.pageTitle; @@ -41,7 +41,9 @@ - &welcomeback.pageInfo; + &welcomeback2.pageInfo1; + + &welcomeback2.beforelink.pageInfo2;&welcomeback2.link.pageInfo2;&welcomeback2.afterlink.pageInfo2; @@ -66,21 +68,9 @@ -#ifdef XP_UNIX - - -#else - - -#endif diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index f6a17e2eae..7da50e2395 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -611,6 +611,41 @@ BrowserGlue.prototype = { nb.PRIORITY_INFO_LOW, buttons); }, + /** + * Show a notification bar offering a reset if the profile has been unused for some time. + */ + _resetUnusedProfileNotification: function () { + let win = this.getMostRecentBrowserWindow(); + if (!win) + return; + + Cu.import("resource://gre/modules/ResetProfile.jsm"); + if (!ResetProfile.resetSupported()) + return; + + let productName = Services.strings + .createBundle("chrome://branding/locale/brand.properties") + .GetStringFromName("brandShortName"); + let resetBundle = Services.strings + .createBundle("chrome://global/locale/resetProfile.properties"); + + let message = resetBundle.formatStringFromName("resetUnusedProfile.message", [productName], 1); + let buttons = [ + { + label: resetBundle.formatStringFromName("refreshProfile.resetButton.label", [productName], 1), + accessKey: resetBundle.GetStringFromName("refreshProfile.resetButton.accesskey"), + callback: function () { + ResetProfile.openConfirmationDialog(win); + } + }, + ]; + + let nb = win.document.getElementById("global-notificationbox"); + nb.appendNotification(message, "reset-unused-profile", + "chrome://global/skin/icons/question-16.png", + nb.PRIORITY_INFO_LOW, buttons); + }, + // the first browser window has finished initializing _onFirstWindowLoaded: function BG__onFirstWindowLoaded(aWindow) { #ifdef XP_WIN @@ -625,6 +660,15 @@ BrowserGlue.prototype = { #endif this._trackSlowStartup(); + + // Offer to reset a user's profile if it hasn't been used for 60 days. + const OFFER_PROFILE_RESET_INTERVAL_MS = 60 * 24 * 60 * 60 * 1000; + let processStartupTime = Services.startup.getStartupInfo().process; + let lastUse = Services.appinfo.replacedLockTime; + if (processStartupTime && lastUse && + processStartupTime.getTime() - lastUse >= OFFER_PROFILE_RESET_INTERVAL_MS) { + this._resetUnusedProfileNotification(); + } }, /** diff --git a/browser/components/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm b/browser/components/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm index 073708deec..521b05708b 100644 --- a/browser/components/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm +++ b/browser/components/sessionstore/RecentlyClosedTabsAndWindowsMenuUtils.jsm @@ -72,7 +72,7 @@ this.RecentlyClosedTabsAndWindowsMenuUtils = { let restoreAllTabs = fragment.appendChild(doc.createElementNS(kNSXUL, aTagName)); restoreAllTabs.setAttribute("label", navigatorBundle.GetStringFromName("menuRestoreAllTabs.label")); restoreAllTabs.setAttribute("oncommand", - "for (var i = 0; i < " + closedTabs.length + "; i++) undoCloseTab(0);"); + "for (var i = 0; i < " + closedTabs.length + "; i++) undoCloseTab();"); } return fragment; }, diff --git a/browser/components/sessionstore/SessionSaver.jsm b/browser/components/sessionstore/SessionSaver.jsm index 145f68a66f..8ac7461379 100644 --- a/browser/components/sessionstore/SessionSaver.jsm +++ b/browser/components/sessionstore/SessionSaver.jsm @@ -15,6 +15,8 @@ Cu.import("resource://gre/modules/Services.jsm", this); Cu.import("resource://gre/modules/XPCOMUtils.jsm", this); Cu.import("resource://gre/modules/TelemetryStopwatch.jsm", this); +XPCOMUtils.defineLazyModuleGetter(this, "AppConstants", + "resource://gre/modules/AppConstants.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "console", "resource://gre/modules/devtools/Console.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PrivacyFilter", @@ -206,23 +208,23 @@ let SessionSaverInternal = { delete state.deferredInitialState; } -#ifndef XP_MACOSX - // We want to restore closed windows that are marked with _shouldRestore. - // We're doing this here because we want to control this only when saving - // the file. - while (state._closedWindows.length) { - let i = state._closedWindows.length - 1; + if (AppConstants.platform != "macosx") { + // We want to restore closed windows that are marked with _shouldRestore. + // We're doing this here because we want to control this only when saving + // the file. + while (state._closedWindows.length) { + let i = state._closedWindows.length - 1; - if (!state._closedWindows[i]._shouldRestore) { - // We only need to go until _shouldRestore - // is falsy since we're going in reverse. - break; + if (!state._closedWindows[i]._shouldRestore) { + // We only need to go until _shouldRestore + // is falsy since we're going in reverse. + break; + } + + delete state._closedWindows[i]._shouldRestore; + state.windows.unshift(state._closedWindows.pop()); } - - delete state._closedWindows[i]._shouldRestore; - state.windows.unshift(state._closedWindows.pop()); } -#endif stopWatchFinish("COLLECT_DATA_MS", "COLLECT_DATA_LONGEST_OP_MS"); return this._writeState(state); diff --git a/browser/components/sessionstore/SessionStore.jsm b/browser/components/sessionstore/SessionStore.jsm index 5a5a52b37e..d1cc081678 100644 --- a/browser/components/sessionstore/SessionStore.jsm +++ b/browser/components/sessionstore/SessionStore.jsm @@ -131,29 +131,15 @@ XPCOMUtils.defineLazyModuleGetter(this, "console", "resource://gre/modules/devtools/Console.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "RecentWindow", "resource:///modules/RecentWindow.jsm"); + +XPCOMUtils.defineLazyModuleGetter(this, "AppConstants", + "resource://gre/modules/AppConstants.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "GlobalState", "resource:///modules/sessionstore/GlobalState.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PrivacyFilter", "resource:///modules/sessionstore/PrivacyFilter.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "RunState", "resource:///modules/sessionstore/RunState.jsm"); - -#ifdef MOZ_DEVTOOLS - -Object.defineProperty(this, "HUDService", { - get: function HUDService_getter() { - let devtools = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools; - return devtools.require("devtools/webconsole/hudservice").HUDService; - }, - configurable: true, - enumerable: true -}); -#endif - -XPCOMUtils.defineLazyModuleGetter(this, "DocumentUtils", - "resource:///modules/sessionstore/DocumentUtils.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "PrivacyLevel", - "resource:///modules/sessionstore/PrivacyLevel.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ScratchpadManager", "resource://gre/modules/devtools/scratchpad-manager.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "SessionSaver", @@ -162,8 +148,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "SessionCookies", "resource:///modules/sessionstore/SessionCookies.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "SessionFile", "resource:///modules/sessionstore/SessionFile.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "SessionHistory", - "resource:///modules/sessionstore/SessionHistory.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "TabAttributes", + "resource:///modules/sessionstore/TabAttributes.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "TabState", "resource:///modules/sessionstore/TabState.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "TabStateCache", @@ -368,6 +354,9 @@ let SessionStoreInternal = { // states for all currently opened windows _windows: {}, + // counter for creating unique window IDs + _nextWindowID: 0, + // states for all recently closed windows _closedWindows: [], @@ -498,10 +487,8 @@ let SessionStoreInternal = { } } - // Load the session start time from the previous state - this._sessionStartTime = state.session && - state.session.startTime || - this._sessionStartTime; + // Update the session start time using the restored session state. + this._updateSessionStartTime(state); // make sure that at least the first window doesn't have anything hidden delete state.windows[0].hidden; @@ -772,6 +759,15 @@ let SessionStoreInternal = { this._clearRestoringWindows(); }, + /** + * Generate a unique window identifier + * @return string + * A unique string to identify a window + */ + _generateWindowID: function ssi_generateWindowID() { + return "window" + (this._nextWindowID++); + }, + /** * If it's the first window load since app start... * - determine if we're reloading after a crash or a forced-restart @@ -792,8 +788,9 @@ let SessionStoreInternal = { if (RunState.isQuitting) return; - // assign it a unique identifier (timestamp) - aWindow.__SSi = "window" + Date.now(); + // Assign the window a unique identifier we can use to reference + // internal data about the window. + aWindow.__SSi = this._generateWindowID(); let mm = aWindow.getGroupMessageManager("browsers"); MESSAGES.forEach(msg => { @@ -889,9 +886,7 @@ let SessionStoreInternal = { if (closedWindowState) { let newWindowState; -#ifndef XP_MACOSX - if (!this._doResumeSession()) { -#endif + if (AppConstants.platform == "macosx" || !this._doResumeSession()) { // We want to split the window up into pinned tabs and unpinned tabs. // Pinned tabs should be restored. If there are any remaining tabs, // they should be added back to _closedWindows. @@ -915,7 +910,6 @@ let SessionStoreInternal = { delete normalTabsState.windows[0].__lastSessionWindowID; this._closedWindows[closedWindowIndex] = normalTabsState.windows[0]; } -#ifndef XP_MACOSX } else { // If we're just restoring the window, make sure it gets removed from @@ -924,7 +918,7 @@ let SessionStoreInternal = { newWindowState = closedWindowState; delete newWindowState.hidden; } -#endif + if (newWindowState) { // Ensure that the window state isn't hidden this._restoreCount = 1; @@ -1031,8 +1025,10 @@ let SessionStoreInternal = { // this window was about to be restored - conserve its original data, if any let isFullyLoaded = this._isWindowLoaded(aWindow); if (!isFullyLoaded) { - if (!aWindow.__SSi) - aWindow.__SSi = "window" + Date.now(); + if (!aWindow.__SSi) { + aWindow.__SSi = this._generateWindowID(); + } + this._windows[aWindow.__SSi] = this._statesToRestore[aWindow.__SS_restoreID]; delete this._statesToRestore[aWindow.__SS_restoreID]; delete aWindow.__SS_restoreID; @@ -1077,11 +1073,11 @@ let SessionStoreInternal = { SessionCookies.update([winData]); } -#ifndef XP_MACOSX - // Until we decide otherwise elsewhere, this window is part of a series - // of closing windows to quit. - winData._shouldRestore = true; -#endif + if (AppConstants.platform != "macosx") { + // Until we decide otherwise elsewhere, this window is part of a series + // of closing windows to quit. + winData._shouldRestore = true; + } // Store the window's close date to figure out when each individual tab // was closed. This timestamp should allow re-arranging data based on how @@ -1994,24 +1990,16 @@ let SessionStoreInternal = { this._capClosedWindows(); } -#ifdef MOZ_DEVTOOLS - // Scratchpad if (lastSessionState.scratchpads) { ScratchpadManager.restoreSession(lastSessionState.scratchpads); } - // The Browser Console - if (lastSessionState.browserConsole) { - HUDService.restoreBrowserConsoleSession(); - } -#endif - // Set data that persists between sessions this._recentCrashes = lastSessionState.session && lastSessionState.session.recentCrashes || 0; - this._sessionStartTime = lastSessionState.session && - lastSessionState.session.startTime || - this._sessionStartTime; + + // Update the session start time using the restored session state. + this._updateSessionStartTime(lastSessionState); LastSession.clear(); }, @@ -2194,21 +2182,21 @@ let SessionStoreInternal = { // shallow copy this._closedWindows to preserve current state let lastClosedWindowsCopy = this._closedWindows.slice(); -#ifndef XP_MACOSX - // If no non-popup browser window remains open, return the state of the last - // closed window(s). We only want to do this when we're actually "ending" - // the session. - //XXXzpao We should do this for _restoreLastWindow == true, but that has - // its own check for popups. c.f. bug 597619 - if (nonPopupCount == 0 && lastClosedWindowsCopy.length > 0 && - RunState.isQuitting) { - // prepend the last non-popup browser window, so that if the user loads more tabs - // at startup we don't accidentally add them to a popup window - do { - total.unshift(lastClosedWindowsCopy.shift()) - } while (total[0].isPopup && lastClosedWindowsCopy.length > 0) + if (AppConstants.platform != "macosx") { + // If no non-popup browser window remains open, return the state of the last + // closed window(s). We only want to do this when we're actually "ending" + // the session. + //XXXzpao We should do this for _restoreLastWindow == true, but that has + // its own check for popups. c.f. bug 597619 + if (nonPopupCount == 0 && lastClosedWindowsCopy.length > 0 && + RunState.isQuitting) { + // prepend the last non-popup browser window, so that if the user loads more tabs + // at startup we don't accidentally add them to a popup window + do { + total.unshift(lastClosedWindowsCopy.shift()) + } while (total[0].isPopup && lastClosedWindowsCopy.length > 0) + } } -#endif if (activeWindow) { this.activeWindowSSiCache = activeWindow.__SSi || ""; @@ -2494,17 +2482,10 @@ let SessionStoreInternal = { (overwriteTabs ? (parseInt(winData.selected || "1")) : 0)); } -#ifdef MOZ_DEVTOOLS if (aState.scratchpads) { ScratchpadManager.restoreSession(aState.scratchpads); } - // The Browser Console - if (aState.browserConsole) { - HUDService.restoreBrowserConsoleSession(); - } - -#endif // set smoothScroll back to the original value tabstrip.smoothScroll = smoothScroll; @@ -2907,6 +2888,20 @@ let SessionStoreInternal = { /* ........ Auxiliary Functions .............. */ + /** + * Update the session start time and send a telemetry measurement + * for the number of days elapsed since the session was started. + * + * @param state + * The session state. + */ + _updateSessionStartTime: function ssi_updateSessionStartTime(state) { + // Attempt to load the session start time from the session state + if (state.session && state.session.startTime) { + this._sessionStartTime = state.session.startTime; + } + }, + /** * call a callback for all currently opened browser windows * (might miss the most recent one) @@ -3396,15 +3391,15 @@ let SessionStoreInternal = { if (this._closedWindows.length <= this._max_windows_undo) return; let spliceTo = this._max_windows_undo; -#ifndef XP_MACOSX - let normalWindowIndex = 0; - // try to find a non-popup window in this._closedWindows - while (normalWindowIndex < this._closedWindows.length && - !!this._closedWindows[normalWindowIndex].isPopup) - normalWindowIndex++; - if (normalWindowIndex >= this._max_windows_undo) - spliceTo = normalWindowIndex + 1; -#endif + if (AppConstants.platform != "macosx") { + let normalWindowIndex = 0; + // try to find a non-popup window in this._closedWindows + while (normalWindowIndex < this._closedWindows.length && + !!this._closedWindows[normalWindowIndex].isPopup) + normalWindowIndex++; + if (normalWindowIndex >= this._max_windows_undo) + spliceTo = normalWindowIndex + 1; + } this._closedWindows.splice(spliceTo, this._closedWindows.length); }, @@ -3733,72 +3728,6 @@ let DirtyWindows = { } }; -// A map storing the number of tabs last closed per windoow. This only -// stores the most recent tab-close operation, and is used to undo -// batch tab-closing operations. -let NumberOfTabsClosedLastPerWindow = new WeakMap(); - -// A set of tab attributes to persist. We will read a given list of tab -// attributes when collecting tab data and will re-set those attributes when -// the given tab data is restored to a new tab. -let TabAttributes = { - _attrs: new Set(), - - // We never want to directly read or write those attributes. - // 'image' should not be accessed directly but handled by using the - // gBrowser.getIcon()/setIcon() methods. - // 'pending' is used internal by sessionstore and managed accordingly. - _skipAttrs: new Set(["image", "pending"]), - - persist: function (name) { - if (this._attrs.has(name) || this._skipAttrs.has(name)) { - return false; - } - - this._attrs.add(name); - return true; - }, - - get: function (tab) { - let data = {}; - - for (let name of this._attrs) { - if (tab.hasAttribute(name)) { - data[name] = tab.getAttribute(name); - } - } - - return data; - }, - - set: function (tab, data = {}) { - // Clear attributes. - for (let name of this._attrs) { - tab.removeAttribute(name); - } - - // Set attributes. - for (let name in data) { - tab.setAttribute(name, data[name]); - } - } -}; - - -// see nsPrivateBrowsingService.js -String.prototype.hasRootDomain = function hasRootDomain(aDomain) { - let index = this.indexOf(aDomain); - if (index == -1) - return false; - - if (this == aDomain) - return true; - - let prevChar = this[index - 1]; - return (index == (this.length - aDomain.length)) && - (prevChar == "." || prevChar == "/"); -}; - function TabData(obj = null) { if (obj) { if (obj instanceof TabData) { diff --git a/browser/components/sessionstore/content/aboutSessionRestore.js b/browser/components/sessionstore/content/aboutSessionRestore.js index 3911b77484..e51fde5a6a 100644 --- a/browser/components/sessionstore/content/aboutSessionRestore.js +++ b/browser/components/sessionstore/content/aboutSessionRestore.js @@ -2,8 +2,12 @@ * 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/. */ -const Cc = Components.classes; -const Ci = Components.interfaces; +const {classes: Cc, interfaces: Ci, utils: Cu} = Components; + +Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "AppConstants", + "resource://gre/modules/AppConstants.jsm"); var gStateObject; var gTreeData; @@ -11,6 +15,14 @@ var gTreeData; // Page initialization window.onload = function() { + // pages used by this script may have a link that needs to be updated to + // the in-product link. + let anchor = document.getElementById("linkMoreTroubleshooting"); + if (anchor) { + let baseURL = Services.urlFormatter.formatURLPref("app.support.baseURL"); + anchor.setAttribute("href", baseURL + "troubleshooting"); + } + // the crashed session state is kept inside a textbox so that SessionStore picks it up // (for when the tab is closed or the session crashes right again) var sessionData = document.getElementById("sessionData"); @@ -70,6 +82,14 @@ function initTreeView() { function restoreSession() { document.getElementById("errorTryAgain").disabled = true; + if (!gTreeData.some(aItem => aItem.checked)) { + // This should only be possible when we have no "cancel" button, and thus + // the "Restore session" button always remains enabled. In that case and + // when nothing is selected, we just want a new session. + startNewSession(); + return; + } + // remove all unselected tabs from the state before restoring it var ix = gStateObject.windows.length - 1; for (var t = gTreeData.length - 1; t >= 0; t--) { @@ -131,11 +151,9 @@ function onListClick(aEvent) { if (cell.col) { // Restore this specific tab in the same window for middle/double/accel clicking // on a tab's title. -#ifdef XP_MACOSX - let accelKey = aEvent.metaKey; -#else - let accelKey = aEvent.ctrlKey; -#endif + let accelKey = AppConstants.platform == "macosx" ? + aEvent.metaKey : + aEvent.ctrlKey; if ((aEvent.button == 1 || aEvent.button == 0 && aEvent.detail == 2 || accelKey) && cell.col.id == "title" && !treeView.isContainer(cell.row)) { @@ -158,14 +176,6 @@ function onListKeyDown(aEvent) { if (aEvent.ctrlKey && !treeView.isContainer(ix)) restoreSingleTab(ix, aEvent.shiftKey); break; - case KeyEvent.DOM_VK_UP: - case KeyEvent.DOM_VK_DOWN: - case KeyEvent.DOM_VK_PAGE_UP: - case KeyEvent.DOM_VK_PAGE_DOWN: - case KeyEvent.DOM_VK_HOME: - case KeyEvent.DOM_VK_END: - aEvent.preventDefault(); // else the page scrolls unwantedly - break; } } @@ -198,7 +208,10 @@ function toggleRowChecked(aIx) { treeView.treeBox.invalidateRow(gTreeData.indexOf(item.parent)); } - document.getElementById("errorTryAgain").disabled = !gTreeData.some(isChecked); + // we only disable the button when there's no cancel button. + if (document.getElementById("errorCancel")) { + document.getElementById("errorTryAgain").disabled = !gTreeData.some(isChecked); + } } function restoreSingleTab(aIx, aShifted) { diff --git a/browser/components/sessionstore/jar.mn b/browser/components/sessionstore/jar.mn index 529692e7eb..7e5bc07dc6 100644 --- a/browser/components/sessionstore/jar.mn +++ b/browser/components/sessionstore/jar.mn @@ -4,5 +4,5 @@ browser.jar: * content/browser/aboutSessionRestore.xhtml (content/aboutSessionRestore.xhtml) -* content/browser/aboutSessionRestore.js (content/aboutSessionRestore.js) + content/browser/aboutSessionRestore.js (content/aboutSessionRestore.js) content/browser/content-sessionStore.js (content/content-sessionStore.js) diff --git a/browser/components/sessionstore/moz.build b/browser/components/sessionstore/moz.build index d9e1c6ada8..6170b9fd21 100644 --- a/browser/components/sessionstore/moz.build +++ b/browser/components/sessionstore/moz.build @@ -34,7 +34,9 @@ EXTRA_JS_MODULES.sessionstore = [ 'SessionFile.jsm', 'SessionHistory.jsm', 'SessionMigration.jsm', + 'SessionSaver.jsm', 'SessionStorage.jsm', + 'SessionStore.jsm', 'SessionWorker.js', 'SessionWorker.jsm', 'TabAttributes.jsm', @@ -45,7 +47,3 @@ EXTRA_JS_MODULES.sessionstore = [ 'XPathGenerator.jsm', ] -EXTRA_PP_JS_MODULES.sessionstore += [ - 'SessionSaver.jsm', - 'SessionStore.jsm', -] diff --git a/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd b/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd index 51213d6567..4983a7aff6 100644 --- a/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd +++ b/browser/locales/en-US/chrome/browser/aboutSessionRestore.dtd @@ -23,12 +23,28 @@ - - - - - + + + + + + + + + + + + + + + + + diff --git a/browser/locales/en-US/chrome/browser/safeMode.dtd b/browser/locales/en-US/chrome/browser/safeMode.dtd index 79d3ca87c6..ab23731c16 100644 --- a/browser/locales/en-US/chrome/browser/safeMode.dtd +++ b/browser/locales/en-US/chrome/browser/safeMode.dtd @@ -3,25 +3,15 @@ - file, You can obtain one at http://mozilla.org/MPL/2.0/. --> - + - - + + - - + + - - + - - - - - - - - - - - + + diff --git a/dom/canvas/DocumentRendererChild.cpp b/dom/canvas/DocumentRendererChild.cpp index d81d00d052..e176578bab 100644 --- a/dom/canvas/DocumentRendererChild.cpp +++ b/dom/canvas/DocumentRendererChild.cpp @@ -80,6 +80,10 @@ DocumentRendererChild::RenderDocument(nsIDOMWindow *window, IntSize(renderSize.width, renderSize.height), 4 * renderSize.width, SurfaceFormat::B8G8R8A8); + if (!dt) { + gfxWarning() << "DocumentRendererChild::RenderDocument failed to Factory::CreateDrawTargetForData"; + return false; + } nsRefPtr ctx = new gfxContext(dt); ctx->SetMatrix(mozilla::gfx::ThebesMatrix(transform)); diff --git a/gfx/2d/DrawTargetTiled.h b/gfx/2d/DrawTargetTiled.h index b709aee694..aa9af05f16 100644 --- a/gfx/2d/DrawTargetTiled.h +++ b/gfx/2d/DrawTargetTiled.h @@ -187,6 +187,11 @@ public: Factory::CreateDrawTargetForData(BackendType::CAIRO, mappedSurf.mData, GetSize(), mappedSurf.mStride, GetFormat()); + if (!dt) { + gfxWarning() << "DrawTargetTiled::GetDataSurface failed in CreateDrawTargetForData"; + surf->Unmap(); + return nullptr; + } for (size_t i = 0; i < mSnapshots.size(); i++) { RefPtr dataSurf = mSnapshots[i]->GetDataSurface(); dt->CopySurface(dataSurf, IntRect(IntPoint(0, 0), mSnapshots[i]->GetSize()), mOrigins[i]); diff --git a/gfx/2d/FilterNodeSoftware.cpp b/gfx/2d/FilterNodeSoftware.cpp index 79363a227b..f67e149a68 100644 --- a/gfx/2d/FilterNodeSoftware.cpp +++ b/gfx/2d/FilterNodeSoftware.cpp @@ -994,6 +994,11 @@ FilterNodeBlendSoftware::Render(const IntRect& aRect) target->Stride(), target->GetFormat()); + if (!dt) { + gfxWarning() << "FilterNodeBlendSoftware::Render failed in CreateDrawTargetForData"; + return nullptr; + } + Rect r(0, 0, size.width, size.height); dt->DrawSurface(input2, r, r, DrawSurfaceOptions(), DrawOptions(1.0f, ToBlendOp(mBlendMode))); dt->Flush(); @@ -1102,6 +1107,7 @@ FilterNodeTransformSoftware::Render(const IntRect& aRect) mapping.mStride, surf->GetFormat()); if (!dt) { + gfxWarning() << "FilterNodeTransformSoftware::Render failed in CreateDrawTargetForData"; return nullptr; } diff --git a/gfx/layers/client/ImageClient.cpp b/gfx/layers/client/ImageClient.cpp index dee2154533..b500f9f6cf 100644 --- a/gfx/layers/client/ImageClient.cpp +++ b/gfx/layers/client/ImageClient.cpp @@ -229,6 +229,10 @@ ImageClientSingle::UpdateImage(ImageContainer* aContainer, uint32_t aContentFlag { // We must not keep a reference to the DrawTarget after it has been unlocked. DrawTarget* dt = texture->BorrowDrawTarget(); + if (!dt) { + gfxWarning() << "ImageClientSingle::UpdateImage failed in BorrowDrawTarget"; + return false; + } MOZ_ASSERT(surface.get()); dt->CopySurface(surface, IntRect(IntPoint(), surface->GetSize()), IntPoint()); } diff --git a/gfx/layers/client/TextureClient.cpp b/gfx/layers/client/TextureClient.cpp index cfed40c603..65e49d6ed4 100644 --- a/gfx/layers/client/TextureClient.cpp +++ b/gfx/layers/client/TextureClient.cpp @@ -544,7 +544,17 @@ bool TextureClient::CopyToTextureClient(TextureClient* aTarget, } RefPtr destinationTarget = aTarget->BorrowDrawTarget(); + if (!destinationTarget) { + gfxWarning() << "TextureClient::CopyToTextureClient (dest) failed in BorrowDrawTarget"; + return false; + } + RefPtr sourceTarget = BorrowDrawTarget(); + if (!sourceTarget) { + gfxWarning() << "TextureClient::CopyToTextureClient (src) failed in BorrowDrawTarget"; + return false; + } + RefPtr source = sourceTarget->Snapshot(); destinationTarget->CopySurface(source, aRect ? *aRect : gfx::IntRect(gfx::IntPoint(0, 0), GetSize()), diff --git a/gfx/layers/d3d11/TextureD3D11.cpp b/gfx/layers/d3d11/TextureD3D11.cpp index 4bb06ee4e9..a9aaad566a 100644 --- a/gfx/layers/d3d11/TextureD3D11.cpp +++ b/gfx/layers/d3d11/TextureD3D11.cpp @@ -291,11 +291,19 @@ TextureClientD3D11::Lock(OpenMode aMode) if (mNeedsClear) { mDrawTarget = BorrowDrawTarget(); + if (!mDrawTarget) { + Unlock(); + return false; + } mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height)); mNeedsClear = false; } if (mNeedsClearWhite) { mDrawTarget = BorrowDrawTarget(); + if (!mDrawTarget) { + Unlock(); + return false; + } mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0))); mNeedsClearWhite = false; } diff --git a/gfx/layers/d3d9/TextureD3D9.cpp b/gfx/layers/d3d9/TextureD3D9.cpp index d800133752..b917669b8c 100644 --- a/gfx/layers/d3d9/TextureD3D9.cpp +++ b/gfx/layers/d3d9/TextureD3D9.cpp @@ -295,17 +295,19 @@ TextureSourceD3D9::SurfaceToTexture(DeviceManagerD3D9* aDeviceManager, reinterpret_cast(lockedRect.pBits), aSize, lockedRect.Pitch, gfxPlatform::GetPlatform()->Optimal2DFormatForContent(aSurface->GetContentType())); - NativeSurface nativeSurf; - nativeSurf.mSize = aSize; - nativeSurf.mType = NativeSurfaceType::CAIRO_SURFACE; - // We don't know that this is actually the right format, but it's the best - // we can get for the content type. In practice this probably always works. - nativeSurf.mFormat = dt->GetFormat(); - nativeSurf.mSurface = aSurface->CairoSurface(); - RefPtr surf = dt->CreateSourceSurfaceFromNativeSurface(nativeSurf); + if (dt) { + NativeSurface nativeSurf; + nativeSurf.mSize = aSize; + nativeSurf.mType = NativeSurfaceType::CAIRO_SURFACE; + // We don't know that this is actually the right format, but it's the best + // we can get for the content type. In practice this probably always works. + nativeSurf.mFormat = dt->GetFormat(); + nativeSurf.mSurface = aSurface->CairoSurface(); - dt->CopySurface(surf, IntRect(IntPoint(), aSize), IntPoint()); + RefPtr surf = dt->CreateSourceSurfaceFromNativeSurface(nativeSurf); + dt->CopySurface(surf, IntRect(IntPoint(), aSize), IntPoint()); + } } FinishTextures(aDeviceManager, texture, surface); @@ -623,11 +625,19 @@ CairoTextureClientD3D9::Lock(OpenMode aMode) if (mNeedsClear) { mDrawTarget = BorrowDrawTarget(); + if (!mDrawTarget) { + Unlock(); + return false; + } mDrawTarget->ClearRect(Rect(0, 0, GetSize().width, GetSize().height)); mNeedsClear = false; } if (mNeedsClearWhite) { mDrawTarget = BorrowDrawTarget(); + if (!mDrawTarget) { + Unlock(); + return false; + } mDrawTarget->FillRect(Rect(0, 0, GetSize().width, GetSize().height), ColorPattern(Color(1.0, 1.0, 1.0, 1.0))); mNeedsClearWhite = false; } diff --git a/gfx/layers/opengl/CompositorOGL.cpp b/gfx/layers/opengl/CompositorOGL.cpp index 915e31748e..7c9bfbd1c1 100644 --- a/gfx/layers/opengl/CompositorOGL.cpp +++ b/gfx/layers/opengl/CompositorOGL.cpp @@ -1228,9 +1228,10 @@ CompositorOGL::EndFrame() mWidget->GetBounds(rect); } RefPtr target = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget(IntSize(rect.width, rect.height), SurfaceFormat::B8G8R8A8); - CopyToTarget(target, nsIntPoint(), Matrix()); - - WriteSnapshotToDumpFile(this, target); + if (target) { + CopyToTarget(target, nsIntPoint(), Matrix()); + WriteSnapshotToDumpFile(this, target); + } } #endif @@ -1342,6 +1343,7 @@ CompositorOGL::SetDestinationSurfaceSize(const gfx::IntSize& aSize) void CompositorOGL::CopyToTarget(DrawTarget* aTarget, const nsIntPoint& aTopLeft, const gfx::Matrix& aTransform) { + MOZ_ASSERT(aTarget); IntRect rect; if (mUseExternalSurfaceSize) { rect = IntRect(0, 0, mSurfaceSize.width, mSurfaceSize.height); diff --git a/gfx/thebes/gfxPlatform.cpp b/gfx/thebes/gfxPlatform.cpp index 111e97690e..1eb45c785a 100644 --- a/gfx/thebes/gfxPlatform.cpp +++ b/gfx/thebes/gfxPlatform.cpp @@ -729,6 +729,10 @@ gfxPlatform::CreateDrawTargetForSurface(gfxASurface *aSurface, const IntSize& aS { SurfaceFormat format = Optimal2DFormatForContent(aSurface->GetContentType()); RefPtr drawTarget = Factory::CreateDrawTargetForCairoSurface(aSurface->CairoSurface(), aSize, &format); + if (!drawTarget) { + gfxWarning() << "gfxPlatform::CreateDrawTargetForSurface failed in CreateDrawTargetForCairoSurface"; + return nullptr; + } aSurface->SetData(&kDrawTarget, drawTarget, nullptr); return drawTarget.forget(); } @@ -912,6 +916,10 @@ gfxPlatform::GetSourceSurfaceForSurface(DrawTarget *aTarget, gfxASurface *aSurfa surf.mSize = ToIntSize(aSurface->GetSize()); RefPtr drawTarget = Factory::CreateDrawTarget(BackendType::CAIRO, IntSize(1, 1), format); + if (!drawTarget) { + gfxWarning() << "gfxPlatform::GetSourceSurfaceForSurface failed in CreateDrawTarget"; + return nullptr; + } srcBuffer = drawTarget->CreateSourceSurfaceFromNativeSurface(surf); if (srcBuffer) { srcBuffer = aTarget->OptimizeSourceSurface(srcBuffer); diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index 2d14bc8ec4..f1d9373b28 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -14,6 +14,7 @@ #include "mozilla/Base64.h" #include "mozilla/gfx/2D.h" #include "mozilla/gfx/DataSurfaceHelpers.h" +#include "mozilla/gfx/Logging.h" #include "mozilla/Maybe.h" #include "mozilla/RefPtr.h" #include "mozilla/Vector.h" @@ -1038,6 +1039,11 @@ gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat(SourceSurface* aSurface, // GPU. RefPtr dt = gfxPlatform::GetPlatform()-> CreateOffscreenContentDrawTarget(aSurface->GetSize(), aFormat); + if (!dt) { + gfxWarning() << "gfxUtils::CopySurfaceToDataSourceSurfaceWithFormat failed in CreateOffscreenContentDrawTarget"; + return nullptr; + } + // Using DrawSurface() here rather than CopySurface() because CopySurface // is optimized for memcpy and therefore isn't good for format conversion. // Using OP_OVER since in our case it's equivalent to OP_SOURCE and diff --git a/image/DynamicImage.cpp b/image/DynamicImage.cpp index a967762ca5..728deabc30 100644 --- a/image/DynamicImage.cpp +++ b/image/DynamicImage.cpp @@ -184,6 +184,10 @@ DynamicImage::GetFrame(uint32_t aWhichFrame, RefPtr dt = gfxPlatform::GetPlatform()-> CreateOffscreenContentDrawTarget(IntSize(size.width, size.height), SurfaceFormat::B8G8R8A8); + if (!dt) { + gfxWarning() << "DynamicImage::GetFrame failed in CreateOffscreenContentDrawTarget"; + return nullptr; + } nsRefPtr context = new gfxContext(dt); auto result = Draw(context, size, ImageRegion::Create(size), diff --git a/image/RasterImage.cpp b/image/RasterImage.cpp index 1ca1f6bb49..7cb11f044a 100644 --- a/image/RasterImage.cpp +++ b/image/RasterImage.cpp @@ -710,6 +710,10 @@ RasterImage::CopyFrame(uint32_t aWhichFrame, uint32_t aFlags) size, mapping.mStride, SurfaceFormat::B8G8R8A8); + if (!target) { + gfxWarning() << "RasterImage::CopyFrame failed in CreateDrawTargetForData"; + return nullptr; + } nsIntRect intFrameRect = frameRef->GetRect(); Rect rect(intFrameRect.x, intFrameRect.y, diff --git a/image/imgFrame.cpp b/image/imgFrame.cpp index c0ec6f22be..c2215b4316 100644 --- a/image/imgFrame.cpp +++ b/image/imgFrame.cpp @@ -484,6 +484,10 @@ nsresult imgFrame::Optimize() mapping.mStride, optFormat); + if (!target) { + gfxWarning() << "imgFrame::Optimize failed in CreateDrawTargetForData"; + return NS_ERROR_OUT_OF_MEMORY; + } Rect rect(0, 0, mSize.width, mSize.height); target->DrawSurface(mImageSurface, rect, rect); target->Flush(); @@ -891,6 +895,10 @@ imgFrame::Deoptimize() mSize, mapping.mStride, format); + if (!target) { + gfxWarning() << "imgFrame::Deoptimize failed in CreateDrawTargetForData"; + return NS_ERROR_OUT_OF_MEMORY; + } Rect rect(0, 0, mSize.width, mSize.height); if (mSinglePixel) diff --git a/image/imgTools.cpp b/image/imgTools.cpp index b81ac32deb..c128df3f3f 100644 --- a/image/imgTools.cpp +++ b/image/imgTools.cpp @@ -221,6 +221,11 @@ NS_IMETHODIMP imgTools::EncodeScaledImage(imgIContainer *aContainer, dataSurface->GetSize(), map.mStride, SurfaceFormat::B8G8R8A8); + if (!dt) { + gfxWarning() << "imgTools::EncodeImage failed in CreateDrawTargetForData"; + return NS_ERROR_OUT_OF_MEMORY; + } + dt->DrawSurface(frame, Rect(0, 0, aScaledWidth, aScaledHeight), Rect(0, 0, frameWidth, frameHeight), @@ -293,6 +298,10 @@ NS_IMETHODIMP imgTools::EncodeCroppedImage(imgIContainer *aContainer, dataSurface->GetSize(), map.mStride, SurfaceFormat::B8G8R8A8); + if (!dt) { + gfxWarning() << "imgTools::EncodeCroppedImage failed in CreateDrawTargetForData"; + return NS_ERROR_OUT_OF_MEMORY; + } dt->CopySurface(frame, IntRect(aOffsetX, aOffsetY, aWidth, aHeight), IntPoint(0, 0)); diff --git a/js/src/jit/IonTypes.h b/js/src/jit/IonTypes.h index eb77c5545e..a3cec183e5 100644 --- a/js/src/jit/IonTypes.h +++ b/js/src/jit/IonTypes.h @@ -487,6 +487,8 @@ StringFromMIRType(MIRType type) return "MagicUninitializedLexical"; case MIRType_Value: return "Value"; + case MIRType_ObjectOrNull: + return "ObjectOrNull"; case MIRType_None: return "None"; case MIRType_Slots: @@ -495,10 +497,16 @@ StringFromMIRType(MIRType type) return "Elements"; case MIRType_Pointer: return "Pointer"; - case MIRType_Int32x4: - return "Int32x4"; + case MIRType_Shape: + return "Shape"; + case MIRType_ObjectGroup: + return "ObjectGroup"; case MIRType_Float32x4: return "Float32x4"; + case MIRType_Int32x4: + return "Int32x4"; + case MIRType_Doublex2: + return "Doublex2"; default: MOZ_CRASH("Unknown MIRType."); } diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 4647b5e067..205bc1e9c8 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -2685,9 +2685,11 @@ PaintInactiveLayer(nsDisplayListBuilder* aBuilder, tempDT = gfxPlatform::GetPlatform()->CreateOffscreenContentDrawTarget( itemVisibleRect.Size().ToIntSize(), SurfaceFormat::B8G8R8A8); - context = new gfxContext(tempDT); - context->SetMatrix(gfxMatrix::Translation(-itemVisibleRect.x, - -itemVisibleRect.y)); + if (tempDT) { + context = new gfxContext(tempDT); + context->SetMatrix(gfxMatrix::Translation(-itemVisibleRect.x, + -itemVisibleRect.y)); + } } #endif basic->BeginTransaction(); @@ -2709,7 +2711,7 @@ PaintInactiveLayer(nsDisplayListBuilder* aBuilder, basic->SetTarget(nullptr); #ifdef MOZ_DUMP_PAINTING - if (gfxUtils::sDumpPainting) { + if (gfxUtils::sDumpPainting && tempDT) { RefPtr surface = tempDT->Snapshot(); DumpPaintedImage(aItem, surface); diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 517cb46825..c1ccab1064 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -3685,14 +3685,6 @@ "extended_statistics_ok": true, "description": "Session restore: Time to collect all window data (ms)" }, - "FX_SESSION_RESTORE_COLLECT_SINGLE_WINDOW_DATA_MS": { - "expires_in_version": "40", - "kind": "exponential", - "high": "30000", - "n_buckets": 10, - "extended_statistics_ok": true, - "description": "Session restore: Time to collect the data of a single window (ms)" - }, "FX_SESSION_RESTORE_COLLECT_COOKIES_MS": { "expires_in_version": "40", "kind": "exponential", @@ -3758,14 +3750,6 @@ "extended_statistics_ok": true, "description": "Session restore: Time spent on the main thread sending the session data off the main thread for writing (ms)" }, - "FX_SESSION_RESTORE_WRITE_STATE_LONGEST_OP_MS": { - "expires_in_version": "40", - "kind": "exponential", - "high": "3000", - "n_buckets": 10, - "extended_statistics_ok": true, - "description": "Session restore: Time spent on the main thread serializing, broadcasting and sending the session data for writing (ms)" - }, "FX_SESSION_RESTORE_WRITE_FILE_MS": { "expires_in_version": "default", "kind": "exponential", diff --git a/toolkit/devtools/server/actors/script.js b/toolkit/devtools/server/actors/script.js index 9073b4c7a8..b5041059d9 100644 --- a/toolkit/devtools/server/actors/script.js +++ b/toolkit/devtools/server/actors/script.js @@ -4663,6 +4663,10 @@ BreakpointActor.prototype = { actorPrefix: "breakpoint", condition: null, + disconnect: function () { + this.removeScripts(); + }, + hasScript: function (aScript) { return this.scripts.has(aScript); }, diff --git a/toolkit/modules/AddonWatcher.jsm b/toolkit/modules/AddonWatcher.jsm index d85016db59..d9f0d437e0 100644 --- a/toolkit/modules/AddonWatcher.jsm +++ b/toolkit/modules/AddonWatcher.jsm @@ -68,10 +68,7 @@ let AddonWatcher = { let limit = this._interval * Preferences.get("browser.addon-watch.percentage-limit", 75) * 10; for (let addonId in addons) { if (!this._ignoreList.has(addonId)) { - if (!this._lastAddonTime[addonId]) { - this._lastAddonTime[addonId] = 0; - } - if ((addons[addonId] - this._lastAddonTime[addonId]) > limit) { + if (this._lastAddonTime[addonId] && ((addons[addonId] - this._lastAddonTime[addonId]) > limit)) { this._callback(addonId); } this._lastAddonTime[addonId] = addons[addonId]; diff --git a/toolkit/modules/ResetProfile.jsm b/toolkit/modules/ResetProfile.jsm index 7f4711c2ba..995ae8147d 100644 --- a/toolkit/modules/ResetProfile.jsm +++ b/toolkit/modules/ResetProfile.jsm @@ -6,6 +6,90 @@ this.EXPORTED_SYMBOLS = ["ResetProfile"]; +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; +#expand const MOZ_APP_NAME = "__MOZ_APP_NAME__"; +#expand const MOZ_BUILD_APP = "__MOZ_BUILD_APP__"; + +Cu.import("resource://gre/modules/Services.jsm"); + +this.ResetProfile = { + /** + * Check if reset is supported for the currently running profile. + * + * @return boolean whether reset is supported. + */ + resetSupported: function() { + let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]. + getService(Ci.nsIToolkitProfileService); + let currentProfileDir = Services.dirsvc.get("ProfD", Ci.nsIFile); + + // Reset is only supported for the default profile if the self-migrator used for reset exists. + try { + return currentProfileDir.equals(profileService.selectedProfile.rootDir) && + ("@mozilla.org/profile/migrator;1?app=" + MOZ_BUILD_APP + "&type=" + MOZ_APP_NAME in Cc); + } catch (e) { + // Catch exception when there is no selected profile. + Cu.reportError(e); + } + return false; + }, + + getMigratedData: function() { + Cu.import("resource:///modules/MigrationUtils.jsm"); + + // From migration.properties + const MIGRATED_TYPES = [ + 128,// Windows/Tabs + 4, // History and Bookmarks + 16, // Passwords + 8, // Form History + 2, // Cookies + ]; + + // Loop over possible data to migrate to give the user a list of what will be preserved. + let dataTypes = []; + for (let itemID of MIGRATED_TYPES) { + try { + let typeName = MigrationUtils.getLocalizedString(itemID + "_" + MOZ_APP_NAME); + dataTypes.push(typeName); + } catch (x) { + // Catch exceptions when the string for a data type doesn't exist. + Cu.reportError(x); + } + } + return dataTypes; + }, + + /** + * Ask the user if they wish to restart the application to reset the profile. + */ + openConfirmationDialog: function(window) { + // Prompt the user to confirm. + let params = { + reset: false, + }; + window.openDialog("chrome://global/content/resetProfile.xul", null, + "chrome,modal,centerscreen,titlebar,dialog=yes", params); + if (!params.reset) + return; + + // Set the reset profile environment variable. + let env = Cc["@mozilla.org/process/environment;1"] + .getService(Ci.nsIEnvironment); + env.set("MOZ_RESET_PROFILE_RESTART", "1"); + + let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"].getService(Ci.nsIAppStartup); + appStartup.quit(Ci.nsIAppStartup.eForceQuit | Ci.nsIAppStartup.eRestart); + }, +}; +/* 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/. */ + +"use strict"; + +this.EXPORTED_SYMBOLS = ["ResetProfile"]; + const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; //For Pale Moon: Hard-code MOZ_APP_NAME to firefox because of hard-coded type in migrator. diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index 738bc3bb61..118e1f9581 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -3455,6 +3455,7 @@ NSEvent* gLastDragMouseDownEvent = nil; gfx::Factory::CreateDrawTargetForCairoCGContext(aContext, gfx::IntSize(backingSize.width, backingSize.height)); + MOZ_ASSERT(dt); // see implementation dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr); targetContext = new gfxContext(dt); } else if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(gfx::BackendType::CAIRO)) { diff --git a/widget/gonk/nsWindow.cpp b/widget/gonk/nsWindow.cpp index 396325152d..42e3b6c6d2 100644 --- a/widget/gonk/nsWindow.cpp +++ b/widget/gonk/nsWindow.cpp @@ -45,6 +45,7 @@ #include "pixelflinger/format.h" #include "mozilla/BasicEvents.h" #include "mozilla/gfx/2D.h" +#include "mozilla/gfx/Logging.h" #include "mozilla/layers/APZCTreeManager.h" #include "mozilla/layers/APZThreadUtils.h" #include "mozilla/layers/CompositorParent.h" @@ -690,6 +691,9 @@ nsWindow::StartRemoteDrawing() mFramebufferTarget = Factory::CreateDrawTargetForData( BackendType::CAIRO, (uint8_t*)vaddr, IntSize(width, height), mFramebuffer->stride * bytepp, format); + if (!mFramebufferTarget) { + MOZ_CRASH("nsWindow::StartRemoteDrawing failed in CreateDrawTargetForData"); + } if (!mBackBuffer || mBackBuffer->GetSize() != mFramebufferTarget->GetSize() || mBackBuffer->GetFormat() != mFramebufferTarget->GetFormat()) { diff --git a/widget/windows/WinUtils.cpp b/widget/windows/WinUtils.cpp index d3ff133ce5..dcd1e8f0ce 100644 --- a/widget/windows/WinUtils.cpp +++ b/widget/windows/WinUtils.cpp @@ -1188,6 +1188,10 @@ AsyncFaviconDataReady::OnComplete(nsIURI *aFaviconURI, dataSurface->GetSize(), map.mStride, dataSurface->GetFormat()); + if (!dt) { + gfxWarning() << "AsyncFaviconDataReady::OnComplete failed in CreateDrawTargetForData"; + return NS_ERROR_OUT_OF_MEMORY; + } dt->FillRect(Rect(0, 0, size.width, size.height), ColorPattern(Color(1.0f, 1.0f, 1.0f, 1.0f))); dt->DrawSurface(surface, diff --git a/widget/windows/nsWindowGfx.cpp b/widget/windows/nsWindowGfx.cpp index 93b178ab1f..b851b2b482 100644 --- a/widget/windows/nsWindowGfx.cpp +++ b/widget/windows/nsWindowGfx.cpp @@ -378,6 +378,11 @@ bool nsWindow::OnPaint(HDC aDC, uint32_t aNestingLevel) gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(targetSurface, IntSize(paintRect.right - paintRect.left, paintRect.bottom - paintRect.top)); + if (!dt) { + gfxWarning() << "nsWindow::OnPaint failed in CreateDrawTargetForSurface"; + return false; + } + // don't need to double buffer with anything but GDI BufferMode doubleBuffering = mozilla::layers::BufferMode::BUFFER_NONE; if (IsRenderMode(gfxWindowsPlatform::RENDER_GDI) || @@ -615,6 +620,10 @@ nsresult nsWindowGfx::CreateIcon(imgIContainer *aContainer, dataSurface->GetSize(), map.mStride, SurfaceFormat::B8G8R8A8); + if (!dt) { + gfxWarning() << "nsWindowGfx::CreatesIcon failed in CreateDrawTargetForData"; + return NS_ERROR_OUT_OF_MEMORY; + } dt->DrawSurface(surface, Rect(0, 0, iconSize.width, iconSize.height), Rect(0, 0, frameSize.width, frameSize.height),
&welcomeback.pageInfo;
&welcomeback2.pageInfo1;
&welcomeback2.beforelink.pageInfo2;&welcomeback2.link.pageInfo2;&welcomeback2.afterlink.pageInfo2;