diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index dfaaa051dfca..a6aa3f9cba4c 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -675,6 +675,9 @@ pref("accessibility.typeaheadfind.timeout", 5000); pref("accessibility.typeaheadfind.linksonly", false); pref("accessibility.typeaheadfind.flashBar", 1); +// Tracks when accessibility is loaded into the previous session. +pref("accessibility.loadedInLastSession", false); + pref("plugins.click_to_play", true); pref("plugins.testmode", false); @@ -988,6 +991,9 @@ pref("toolkit.crashreporter.infoURL", // base URL for web-based support pages pref("app.support.baseURL", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/"); +// a11y conflicts with e10s support page +pref("app.support.e10sAccessibilityUrl", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/accessibility-ppt"); + // base url for web-based feedback pages #ifdef MOZ_DEV_EDITION pref("app.feedback.baseURL", "https://input.mozilla.org/%LOCALE%/feedback/firefoxdev/%VERSION%/"); diff --git a/browser/components/nsBrowserGlue.js b/browser/components/nsBrowserGlue.js index 15e4b52e7425..a9ec7dda5c22 100644 --- a/browser/components/nsBrowserGlue.js +++ b/browser/components/nsBrowserGlue.js @@ -532,6 +532,13 @@ BrowserGlue.prototype = { this._flashHangCount = 0; this._firstWindowReady = new Promise(resolve => this._firstWindowLoaded = resolve); + + if (AppConstants.platform == "macosx" || + (AppConstants.platform == "win" && AppConstants.RELEASE_OR_BETA)) { + // Handles prompting to inform about incompatibilites when accessibility + // and e10s are active together. + E10SAccessibilityCheck.init(); + } }, // cleanup (called on application shutdown) @@ -1058,7 +1065,10 @@ BrowserGlue.prototype = { } this._sanitizer.onStartup(); + E10SAccessibilityCheck.onWindowsRestored(); + this._scheduleStartupIdleTasks(); + this._lateTasksIdleObserver = (idleService, topic, data) => { if (topic == "idle") { idleService.removeIdleObserver(this._lateTasksIdleObserver, @@ -2825,9 +2835,132 @@ var DefaultBrowserCheck = { }, }; +var E10SAccessibilityCheck = { + // tracks when an a11y init observer fires prior to the + // first window being opening. + _wantsPrompt: false, + + init() { + Services.obs.addObserver(this, "a11y-init-or-shutdown", true); + Services.obs.addObserver(this, "quit-application-granted", true); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]), + + get forcedOn() { + try { + return Services.prefs.getBoolPref("browser.tabs.remote.force-enable"); + } catch (e) {} + return false; + }, + + observe(subject, topic, data) { + switch (topic) { + case "quit-application-granted": + // Tag the profile with a11y load state. We use this in nsAppRunner + // checks on the next start. + Services.prefs.setBoolPref("accessibility.loadedInLastSession", + Services.appinfo.accessibilityEnabled); + break; + case "a11y-init-or-shutdown": + if (data == "1") { + // Update this so users can check this while still running + Services.prefs.setBoolPref("accessibility.loadedInLastSession", true); + this._showE10sAccessibilityWarning(); + } + break; + } + }, + + onWindowsRestored() { + if (this._wantsPrompt) { + this._wantsPrompt = false; + this._showE10sAccessibilityWarning(); + } + }, + + _warnedAboutAccessibility: false, + + _showE10sAccessibilityWarning() { + // We don't prompt about a11y incompat if e10s is off. + if (!Services.appinfo.browserTabsRemoteAutostart) { + return; + } + + // If the user set the forced pref and it's true, ignore a11y init. + // If the pref doesn't exist or if it's false, prompt. + if (this.forcedOn) { + return; + } + + // Only prompt once per session + if (this._warnedAboutAccessibility) { + return; + } + this._warnedAboutAccessibility = true; + + let win = RecentWindow.getMostRecentBrowserWindow(); + if (!win || !win.gBrowser || !win.gBrowser.selectedBrowser) { + Services.console.logStringMessage( + "Accessibility support is partially disabled due to compatibility issues with new features."); + this._wantsPrompt = true; + this._warnedAboutAccessibility = false; + return; + } + let browser = win.gBrowser.selectedBrowser; + + // We disable a11y for content and prompt on the chrome side letting + // a11y users know they need to disable e10s and restart. + let promptMessage = win.gNavigatorBundle.getFormattedString( + "e10s.accessibilityNotice.mainMessage2", + [gBrandBundle.GetStringFromName("brandShortName")] + ); + let notification; + let restartCallback = function() { + let cancelQuit = Cc["@mozilla.org/supports-PRBool;1"].createInstance(Ci.nsISupportsPRBool); + Services.obs.notifyObservers(cancelQuit, "quit-application-requested", "restart"); + if (cancelQuit.data) { + return; // somebody canceled our quit request + } + // Restart the browser + Services.startup.quit(Services.startup.eAttemptQuit | Services.startup.eRestart); + }; + // main option: an Ok button, keeps running with content accessibility disabled + let mainAction = { + label: win.gNavigatorBundle.getString("e10s.accessibilityNotice.acceptButton.label"), + accessKey: win.gNavigatorBundle.getString("e10s.accessibilityNotice.acceptButton.accesskey"), + callback() { + // If the user invoked the button option remove the notification, + // otherwise keep the alert icon around in the address bar. + notification.remove(); + }, + dismiss: true + }; + // secondary option: a restart now button. When we restart e10s will be disabled due to + // accessibility having been loaded in the previous session. + let secondaryActions = [{ + label: win.gNavigatorBundle.getString("e10s.accessibilityNotice.enableAndRestart.label"), + accessKey: win.gNavigatorBundle.getString("e10s.accessibilityNotice.enableAndRestart.accesskey"), + callback: restartCallback, + }]; + let options = { + popupIconURL: "chrome://browser/skin/e10s-64@2x.png", + learnMoreURL: Services.urlFormatter.formatURLPref("app.support.e10sAccessibilityUrl"), + persistent: true, + persistWhileVisible: true, + }; + + notification = + win.PopupNotifications.show(browser, "a11y_enabled_with_e10s", + promptMessage, null, mainAction, + secondaryActions, options); + }, +}; + var components = [BrowserGlue, ContentPermissionPrompt]; this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components); + // Listen for UITour messages. // Do it here instead of the UITour module itself so that the UITour module is lazy loaded // when the first message is received. diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index eadcc8160839..d81f585806f0 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -267,6 +267,11 @@ static NS_DEFINE_CID(kCClipboardCID, NS_CLIPBOARD_CID); +#if defined(XP_WIN) +// e10s forced enable pref, defined in nsAppRunner.cpp +extern const char* kForceEnableE10sPref; +#endif + using base::ChildPrivileges; using base::KillProcess; @@ -1305,8 +1310,13 @@ ContentParent::Init() // process. if (nsIPresShell::IsAccessibilityActive()) { #if defined(XP_WIN) - Unused << SendActivateA11y(::GetCurrentThreadId(), - a11y::AccessibleWrap::GetContentProcessIdFor(ChildID())); +#if defined(RELEASE_OR_BETA) + // On Windows we currently only enable a11y in the content process + // for testing purposes. + if (Preferences::GetBool(kForceEnableE10sPref, false)) +#endif + Unused << SendActivateA11y(::GetCurrentThreadId(), + a11y::AccessibleWrap::GetContentProcessIdFor(ChildID())); #else Unused << SendActivateA11y(0, 0); #endif @@ -2840,8 +2850,13 @@ ContentParent::Observe(nsISupports* aSubject, // Make sure accessibility is running in content process when // accessibility gets initiated in chrome process. #if defined(XP_WIN) - Unused << SendActivateA11y(::GetCurrentThreadId(), - a11y::AccessibleWrap::GetContentProcessIdFor(ChildID())); +#if defined(RELEASE_OR_BETA) + // On Windows we currently only enable a11y in the content process + // for testing purposes. + if (Preferences::GetBool(kForceEnableE10sPref, false)) +#endif + Unused << SendActivateA11y(::GetCurrentThreadId(), + a11y::AccessibleWrap::GetContentProcessIdFor(ChildID())); #else Unused << SendActivateA11y(0, 0); #endif diff --git a/toolkit/xre/nsAppRunner.cpp b/toolkit/xre/nsAppRunner.cpp index 43734af69ea6..6c16dd1f791a 100644 --- a/toolkit/xre/nsAppRunner.cpp +++ b/toolkit/xre/nsAppRunner.cpp @@ -5049,7 +5049,7 @@ enum { kE10sEnabledByDefault = 1, kE10sDisabledByUser = 2, // kE10sDisabledInSafeMode = 3, was removed in bug 1172491. - // kE10sDisabledForAccessibility = 4, + kE10sDisabledForAccessibility = 4, // kE10sDisabledForMacGfx = 5, was removed in bug 1068674. // kE10sDisabledForBidi = 6, removed in bug 1309599 kE10sDisabledForAddons = 7, @@ -5058,6 +5058,18 @@ enum { // kE10sDisabledForOperatingSystem = 10, removed due to xp-eol }; +const char* kAccessibilityLastRunDatePref = "accessibility.lastLoadDate"; +const char* kAccessibilityLoadedLastSessionPref = "accessibility.loadedInLastSession"; + +#if defined(XP_WIN) +static inline uint32_t +PRTimeToSeconds(PRTime t_usec) +{ + PRTime usec_per_sec = PR_USEC_PER_SEC; + return uint32_t(t_usec /= usec_per_sec); +} +#endif + const char* kForceEnableE10sPref = "browser.tabs.remote.force-enable"; const char* kForceDisableE10sPref = "browser.tabs.remote.force-disable"; @@ -5085,6 +5097,40 @@ MultiprocessBlockPolicy() return kE10sDisabledForAddons; } +#if defined(XP_WIN) && defined(RELEASE_OR_BETA) + bool disabledForA11y = false; + /** + * Avoids enabling e10s if accessibility has recently loaded. Performs the + * following checks: + * 1) Checks a pref indicating if a11y loaded in the last session. This pref + * is set in nsBrowserGlue.js. If a11y was loaded in the last session we + * do not enable e10s in this session. + * 2) Accessibility stores a last run date (PR_IntervalNow) when it is + * initialized (see nsBaseWidget.cpp). We check if this pref exists and + * compare it to now. If a11y hasn't run in an extended period of time or + * if the date pref does not exist we load e10s. + */ + disabledForA11y = Preferences::GetBool(kAccessibilityLoadedLastSessionPref, false); + if (!disabledForA11y && + Preferences::HasUserValue(kAccessibilityLastRunDatePref)) { + const uint32_t oneWeekInSeconds = 60 * 60 * 24 * 7; + uint32_t a11yRunDate = Preferences::GetInt(kAccessibilityLastRunDatePref, 0); + MOZ_ASSERT(0 != a11yRunDate); + // If a11y hasn't run for a period of time, clear the pref and load e10s + uint32_t now = PRTimeToSeconds(PR_Now()); + uint32_t difference = now - a11yRunDate; + if (difference > oneWeekInSeconds || !a11yRunDate) { + Preferences::ClearUser(kAccessibilityLastRunDatePref); + } else { + disabledForA11y = true; + } + } + + if (disabledForA11y) { + return kE10sDisabledForAccessibility; + } +#endif + /* * None of the blocking policies matched, so e10s is allowed to run. Return * 0, indicating success. diff --git a/widget/nsBaseWidget.cpp b/widget/nsBaseWidget.cpp index 0e8631aeea1d..7543451d7d61 100644 --- a/widget/nsBaseWidget.cpp +++ b/widget/nsBaseWidget.cpp @@ -171,6 +171,9 @@ nsBaseWidget::nsBaseWidget() , mUseAttachedEvents(false) , mIMEHasFocus(false) , mIsFullyOccluded(false) +#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) +, mAccessibilityInUseFlag(false) +#endif { #ifdef NOISY_WIDGET_LEAKS gNumWidgets++; @@ -1883,6 +1886,18 @@ nsBaseWidget::ZoomToRect(const uint32_t& aPresShellId, #ifdef ACCESSIBILITY +#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) +// defined in nsAppRunner.cpp +extern const char* kAccessibilityLastRunDatePref; + +static inline uint32_t +PRTimeToSeconds(PRTime t_usec) +{ + PRTime usec_per_sec = PR_USEC_PER_SEC; + return uint32_t(t_usec /= usec_per_sec); +} +#endif + a11y::Accessible* nsBaseWidget::GetRootAccessible() { @@ -1900,6 +1915,13 @@ nsBaseWidget::GetRootAccessible() // make sure it's not created at unsafe times. nsAccessibilityService* accService = GetOrCreateAccService(); if (accService) { +#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) + if (!mAccessibilityInUseFlag) { + mAccessibilityInUseFlag = true; + uint32_t now = PRTimeToSeconds(PR_Now()); + Preferences::SetInt(kAccessibilityLastRunDatePref, now); + } +#endif return accService->GetRootDocumentAccessible(presShell, nsContentUtils::IsSafeToRunScript()); } diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h index b92b78ecebb3..9146215ef172 100644 --- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -695,6 +695,9 @@ protected: bool mUseAttachedEvents; bool mIMEHasFocus; bool mIsFullyOccluded; +#if defined(XP_WIN) || defined(XP_MACOSX) || defined(MOZ_WIDGET_GTK) + bool mAccessibilityInUseFlag; +#endif static nsIRollupListener* gRollupListener; struct InitialZoomConstraints {