mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge fx-team to m-c.
This commit is contained in:
commit
9305d5716f
@ -85,7 +85,13 @@ add_task(function*() {
|
||||
ok(otherTB.querySelector("#sync-button"), "Sync button is on other toolbar, too.");
|
||||
|
||||
let wasInformedCorrectlyOfAreaDisappearing = false;
|
||||
let windowClosed = null;
|
||||
//XXXgijs So we could be using promiseWindowClosed here. However, after
|
||||
// repeated random oranges, I'm instead relying on onWindowClosed below to
|
||||
// fire appropriately - it is linked to an unload event as well, and so
|
||||
// reusing it prevents a potential race between unload handlers where the
|
||||
// one from promiseWindowClosed could fire before the onWindowClosed
|
||||
// (and therefore onAreaNodeRegistered) one, causing the test to fail.
|
||||
let windowCloseDeferred = Promise.defer();
|
||||
listener = {
|
||||
onAreaNodeUnregistered: function(aArea, aNode, aReason) {
|
||||
if (aArea == TOOLBARID) {
|
||||
@ -96,8 +102,7 @@ add_task(function*() {
|
||||
},
|
||||
onWindowClosed: function(aWindow) {
|
||||
if (aWindow == otherWin) {
|
||||
info("Got window closed notification for correct window.");
|
||||
windowClosed = aWindow;
|
||||
windowCloseDeferred.resolve(aWindow);
|
||||
} else {
|
||||
info("Other window was closed!");
|
||||
info("Other window title: " + (aWindow.document && aWindow.document.title));
|
||||
@ -106,7 +111,8 @@ add_task(function*() {
|
||||
},
|
||||
};
|
||||
CustomizableUI.addListener(listener);
|
||||
yield promiseWindowClosed(otherWin);
|
||||
otherWin.close();
|
||||
let windowClosed = yield windowCloseDeferred.promise;
|
||||
|
||||
is(windowClosed, otherWin, "Window should have sent onWindowClosed notification.");
|
||||
ok(wasInformedCorrectlyOfAreaDisappearing, "Should be told about window closing.");
|
||||
|
@ -249,8 +249,13 @@ function openAndLoadWindow(aOptions, aWaitForDelayedStartup=false) {
|
||||
}
|
||||
|
||||
function promiseWindowClosed(win) {
|
||||
let deferred = Promise.defer();
|
||||
win.addEventListener("unload", function onunload() {
|
||||
win.removeEventListener("unload", onunload);
|
||||
deferred.resolve();
|
||||
});
|
||||
win.close();
|
||||
return waitForCondition(() => win.closed);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promisePanelShown(win) {
|
||||
|
@ -203,6 +203,11 @@ var gPermissionManager = {
|
||||
{
|
||||
if (aTopic == "perm-changed") {
|
||||
var permission = aSubject.QueryInterface(Components.interfaces.nsIPermission);
|
||||
|
||||
// Ignore unrelated permission types.
|
||||
if (permission.type != this._type)
|
||||
return;
|
||||
|
||||
if (aData == "added") {
|
||||
this._addPermissionToList(permission);
|
||||
++this._view._rowCount;
|
||||
|
@ -8,6 +8,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
this.EXPORTED_SYMBOLS = [ "BingTranslation" ];
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
Cu.import("resource://gre/modules/Promise.jsm");
|
||||
Cu.import("resource://gre/modules/Task.jsm");
|
||||
@ -327,14 +328,16 @@ let BingTokenManager = {
|
||||
let params = [
|
||||
"grant_type=client_credentials",
|
||||
"scope=" + encodeURIComponent("http://api.microsofttranslator.com"),
|
||||
"client_id=",
|
||||
"client_secret="
|
||||
"client_id=" +
|
||||
getAuthTokenParam("%BING_API_CLIENTID%", "browser.translation.bing.clientIdOverride"),
|
||||
"client_secret=" +
|
||||
getAuthTokenParam("%BING_API_KEY%", "browser.translation.bing.apiKeyOverride")
|
||||
];
|
||||
|
||||
let deferred = Promise.defer();
|
||||
this._pendingRequest = deferred.promise;
|
||||
request.post(params.join("&"), function(err) {
|
||||
this._pendingRequest = null;
|
||||
BingTokenManager._pendingRequest = null;
|
||||
|
||||
if (err) {
|
||||
deferred.reject(err);
|
||||
@ -367,3 +370,16 @@ function escapeXML(aStr) {
|
||||
.replace("<", "<", "g")
|
||||
.replace(">", ">", "g");
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch an auth token (clientID or client secret), which may be overridden by
|
||||
* a pref if it's set.
|
||||
*/
|
||||
function getAuthTokenParam(key, prefName) {
|
||||
let val;
|
||||
try {
|
||||
val = Services.prefs.getCharPref(prefName);
|
||||
} catch(ex) {}
|
||||
|
||||
return encodeURIComponent(Services.urlFormatter.formatURL(val || key));
|
||||
}
|
||||
|
@ -42,10 +42,10 @@
|
||||
</xul:hbox>
|
||||
|
||||
<!-- translating -->
|
||||
<xul:hbox class="translating-box" pack="center">
|
||||
<xul:vbox class="translating-box" pack="center">
|
||||
<xul:label class="translate-infobar-element"
|
||||
value="&translation.translatingContent.label;"/>
|
||||
</xul:hbox>
|
||||
</xul:vbox>
|
||||
|
||||
<!-- translated -->
|
||||
<xul:hbox class="translated-box" align="center">
|
||||
@ -58,11 +58,13 @@
|
||||
</xul:menulist>
|
||||
<xul:label class="translate-infobar-element"
|
||||
value="&translation.translatedTo.label;"/>
|
||||
<xul:menulist anonid="toLanguage"
|
||||
<xul:menulist class="translate-infobar-element"
|
||||
anonid="toLanguage"
|
||||
oncommand="document.getBindingParent(this).translate()">
|
||||
<xul:menupopup/>
|
||||
</xul:menulist>
|
||||
<xul:label value="&translation.translatedToSuffix.label;"/>
|
||||
<xul:label class="translate-infobar-element"
|
||||
value="&translation.translatedToSuffix.label;"/>
|
||||
<xul:button anonid="showOriginal"
|
||||
class="translate-infobar-element"
|
||||
label="&translation.showOriginal.button;"
|
||||
|
@ -113,6 +113,8 @@ skip-if = os == 'win' # bug 1005274
|
||||
[browser_dbg_break-on-dom-06.js]
|
||||
[browser_dbg_break-on-dom-07.js]
|
||||
[browser_dbg_break-on-dom-08.js]
|
||||
[browser_dbg_break-on-dom-event.js]
|
||||
skip-if = os == "mac" || e10s # Bug 895426
|
||||
[browser_dbg_breakpoints-actual-location.js]
|
||||
[browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js]
|
||||
[browser_dbg_breakpoints-button-01.js]
|
||||
@ -124,6 +126,7 @@ skip-if = os == 'win' # bug 1005274
|
||||
[browser_dbg_breakpoints-highlight.js]
|
||||
[browser_dbg_breakpoints-new-script.js]
|
||||
[browser_dbg_breakpoints-pane.js]
|
||||
[browser_dbg_chrome-create.js]
|
||||
[browser_dbg_chrome-debugging.js]
|
||||
[browser_dbg_clean-exit-window.js]
|
||||
skip-if = true # Bug 933950 (leaky test)
|
||||
@ -165,6 +168,8 @@ skip-if = true # Bug 933950 (leaky test)
|
||||
[browser_dbg_navigation.js]
|
||||
[browser_dbg_no-page-sources.js]
|
||||
[browser_dbg_on-pause-highlight.js]
|
||||
[browser_dbg_on-pause-raise.js]
|
||||
skip-if = os == "linux" || e10s # Bug 888811 & bug 891176
|
||||
[browser_dbg_optimized-out-vars.js]
|
||||
[browser_dbg_panel-size.js]
|
||||
[browser_dbg_parser-01.js]
|
||||
@ -298,9 +303,3 @@ skip-if = (os == 'mac' || os == 'win') && (debug == false) # Bug 986166
|
||||
[browser_dbg_variables-view-webidl.js]
|
||||
[browser_dbg_watch-expressions-01.js]
|
||||
[browser_dbg_watch-expressions-02.js]
|
||||
[browser_dbg_chrome-create.js]
|
||||
skip-if = true # Test doesn't clean up after itself (bug 918507), but also bug 847558 on Linux
|
||||
[browser_dbg_on-pause-raise.js]
|
||||
skip-if = os == "linux" || e10s # Bug 888811 & bug 891176
|
||||
[browser_dbg_break-on-dom-event.js]
|
||||
skip-if = os == "mac" || e10s # Bug 895426
|
||||
|
@ -11,16 +11,16 @@
|
||||
|
||||
<!ENTITY color "Text and Background">
|
||||
<!ENTITY textColor.label "Text:">
|
||||
<!ENTITY textColor.accesskey "t">
|
||||
<!ENTITY textColor.accesskey "T">
|
||||
<!ENTITY backgroundColor.label "Background:">
|
||||
<!ENTITY backgroundColor.accesskey "b">
|
||||
<!ENTITY backgroundColor.accesskey "B">
|
||||
<!ENTITY useSystemColors.label "Use system colors">
|
||||
<!ENTITY useSystemColors.accesskey "s">
|
||||
|
||||
<!ENTITY underlineLinks.label "Underline links">
|
||||
<!ENTITY underlineLinks.accesskey "u">
|
||||
<!ENTITY underlineLinks.accesskey "U">
|
||||
<!ENTITY links "Link Colors">
|
||||
<!ENTITY linkColor.label "Unvisited Links:">
|
||||
<!ENTITY linkColor.accesskey "l">
|
||||
<!ENTITY linkColor.accesskey "L">
|
||||
<!ENTITY visitedLinkColor.label "Visited Links:">
|
||||
<!ENTITY visitedLinkColor.accesskey "v">
|
||||
<!ENTITY visitedLinkColor.accesskey "V">
|
||||
|
@ -250,7 +250,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/itemArrow-rtl.svg (../shared/devtools/images/itemArrow-rtl.svg)
|
||||
skin/classic/browser/devtools/itemArrow-ltr.svg (../shared/devtools/images/itemArrow-ltr.svg)
|
||||
skin/classic/browser/devtools/noise.png (../shared/devtools/images/noise.png)
|
||||
skin/classic/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
|
||||
skin/classic/browser/devtools/dropmarker.svg (../shared/devtools/images/dropmarker.svg)
|
||||
skin/classic/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
|
||||
skin/classic/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
|
||||
skin/classic/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
|
||||
|
@ -368,7 +368,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/itemArrow-rtl.svg (../shared/devtools/images/itemArrow-rtl.svg)
|
||||
skin/classic/browser/devtools/itemArrow-ltr.svg (../shared/devtools/images/itemArrow-ltr.svg)
|
||||
skin/classic/browser/devtools/noise.png (../shared/devtools/images/noise.png)
|
||||
skin/classic/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
|
||||
skin/classic/browser/devtools/dropmarker.svg (../shared/devtools/images/dropmarker.svg)
|
||||
skin/classic/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
|
||||
skin/classic/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
|
||||
skin/classic/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
|
||||
|
@ -153,6 +153,11 @@
|
||||
|
||||
/* Debugging pane controls */
|
||||
|
||||
#debugging-controls .devtools-toolbarbutton > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#resume {
|
||||
list-style-image: url(debugger-play.png);
|
||||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
@ -170,6 +175,25 @@
|
||||
list-style-image: url(debugger-step-out.png);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#resume {
|
||||
list-style-image: url(debugger-play@2x.png);
|
||||
-moz-image-region: rect(0px,64px,32px,32px);
|
||||
}
|
||||
|
||||
#step-over {
|
||||
list-style-image: url(debugger-step-over@2x.png);
|
||||
}
|
||||
|
||||
#step-in {
|
||||
list-style-image: url(debugger-step-in@2x.png);
|
||||
}
|
||||
|
||||
#step-out {
|
||||
list-style-image: url(debugger-step-out@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
#debugging-controls > toolbarbutton {
|
||||
transition: opacity 0.15s ease-in-out;
|
||||
}
|
||||
@ -256,6 +280,12 @@
|
||||
background-size: 12px;
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
.selected .call-item-gutter {
|
||||
background-image: url("editor-debug-location@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
.theme-dark .call-item-gutter {
|
||||
background-color: #181d20;
|
||||
color: #5f7387;
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 218 B |
3
browser/themes/shared/devtools/images/dropmarker.svg
Normal file
3
browser/themes/shared/devtools/images/dropmarker.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="8" height="4" viewBox="0 0 8 4" enable-background="new 0 0 8 4">
|
||||
<polygon points="0,0 4,4 8,0" fill="#B6BABF" />
|
||||
</svg>
|
After Width: | Height: | Size: 213 B |
@ -96,7 +96,7 @@
|
||||
-moz-appearance: none;
|
||||
display: -moz-box;
|
||||
background-color: transparent;
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
|
||||
-moz-box-align: center;
|
||||
border-width: 0;
|
||||
min-width: 16px;
|
||||
@ -122,7 +122,7 @@
|
||||
.devtools-responsiveui-toolbarbutton[type=menu] > .toolbarbutton-menu-dropmarker,
|
||||
.devtools-responsiveui-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-dropmarker {
|
||||
-moz-appearance: none !important;
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
|
||||
-moz-box-align: center;
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
@ -136,7 +136,7 @@
|
||||
.devtools-menulist > .menulist-dropmarker {
|
||||
-moz-appearance: none;
|
||||
display: -moz-box;
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
|
||||
-moz-box-align: center;
|
||||
min-width: 16px;
|
||||
}
|
||||
@ -168,7 +168,7 @@
|
||||
.devtools-toolbarbutton[type=menu] > .toolbarbutton-menu-dropmarker,
|
||||
.devtools-toolbarbutton[type=menu-button] > .toolbarbutton-menubutton-dropmarker {
|
||||
-moz-appearance: none !important;
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.png");
|
||||
list-style-image: url("chrome://browser/skin/devtools/dropmarker.svg");
|
||||
-moz-box-align: center;
|
||||
padding: 0 3px;
|
||||
}
|
||||
|
@ -125,6 +125,11 @@ text {
|
||||
-moz-image-region: rect(0px,16px,16px,0px);
|
||||
}
|
||||
|
||||
#inspector-pane-toggle > .toolbarbutton-icon {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
#inspector-pane-toggle[pane-collapsed] {
|
||||
list-style-image: url(debugger-expand.png);
|
||||
}
|
||||
@ -132,3 +137,18 @@ text {
|
||||
#inspector-pane-toggle:active {
|
||||
-moz-image-region: rect(0px,32px,16px,16px);
|
||||
}
|
||||
|
||||
@media (min-resolution: 2dppx) {
|
||||
#inspector-pane-toggle {
|
||||
list-style-image: url(debugger-collapse@2x.png);
|
||||
-moz-image-region: rect(0px,32px,32px,0px);
|
||||
}
|
||||
|
||||
#inspector-pane-toggle[pane-collapsed] {
|
||||
list-style-image: url(debugger-expand@2x.png);
|
||||
}
|
||||
|
||||
#inspector-pane-toggle:active {
|
||||
-moz-image-region: rect(0px,64px,32px,32px);
|
||||
}
|
||||
}
|
@ -288,7 +288,7 @@ browser.jar:
|
||||
skin/classic/browser/devtools/itemArrow-rtl.svg (../shared/devtools/images/itemArrow-rtl.svg)
|
||||
skin/classic/browser/devtools/itemArrow-ltr.svg (../shared/devtools/images/itemArrow-ltr.svg)
|
||||
skin/classic/browser/devtools/noise.png (../shared/devtools/images/noise.png)
|
||||
skin/classic/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
|
||||
skin/classic/browser/devtools/dropmarker.svg (../shared/devtools/images/dropmarker.svg)
|
||||
skin/classic/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
|
||||
skin/classic/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
|
||||
skin/classic/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
|
||||
@ -688,7 +688,7 @@ browser.jar:
|
||||
skin/classic/aero/browser/devtools/itemArrow-rtl.svg (../shared/devtools/images/itemArrow-rtl.svg)
|
||||
skin/classic/aero/browser/devtools/itemArrow-ltr.svg (../shared/devtools/images/itemArrow-ltr.svg)
|
||||
skin/classic/aero/browser/devtools/noise.png (../shared/devtools/images/noise.png)
|
||||
skin/classic/aero/browser/devtools/dropmarker.png (../shared/devtools/images/dropmarker.png)
|
||||
skin/classic/aero/browser/devtools/dropmarker.svg (../shared/devtools/images/dropmarker.svg)
|
||||
skin/classic/aero/browser/devtools/layoutview.css (../shared/devtools/layoutview.css)
|
||||
skin/classic/aero/browser/devtools/debugger-collapse.png (../shared/devtools/images/debugger-collapse.png)
|
||||
skin/classic/aero/browser/devtools/debugger-collapse@2x.png (../shared/devtools/images/debugger-collapse@2x.png)
|
||||
|
@ -227,6 +227,7 @@ public class SQLiteBridge {
|
||||
cursor.moveToFirst();
|
||||
String version = cursor.getString(0);
|
||||
ret = Integer.parseInt(version);
|
||||
cursor.close();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -402,7 +402,18 @@ AbstractHealthReporter.prototype = Object.freeze({
|
||||
// The database needs to be shut down by the end of shutdown
|
||||
// phase profileBeforeChange.
|
||||
Metrics.Storage.shutdown.addBlocker("FHR: Flushing storage shutdown",
|
||||
this._promiseShutdown);
|
||||
this._promiseShutdown,
|
||||
() => ({
|
||||
shutdownInitiated: this._shutdownInitiated,
|
||||
initialized: this._initialized,
|
||||
shutdownRequested: this._shutdownRequested,
|
||||
initializeHadError: this._initializeHadError,
|
||||
providerManagerInProgress: this._providerManagerInProgress,
|
||||
storageInProgress: this._storageInProgress,
|
||||
hasProviderManager: !!this._providerManager,
|
||||
hasStorage: !!this._storage,
|
||||
shutdownComplete: this.shutdownComplete
|
||||
}));
|
||||
|
||||
try {
|
||||
this._storageInProgress = true;
|
||||
@ -571,7 +582,7 @@ AbstractHealthReporter.prototype = Object.freeze({
|
||||
if (this._initializeHadError) {
|
||||
this._log.warn("Initialization had error. Shutting down immediately.");
|
||||
} else {
|
||||
if (this._providerManagerInProcess) {
|
||||
if (this._providerManagerInProgress) {
|
||||
this._log.warn("Provider manager is in progress of initializing. " +
|
||||
"Waiting to finish.");
|
||||
return;
|
||||
|
@ -10,6 +10,7 @@ skip-if = e10s # Bug ?????? - intermittent crash of child process reported when
|
||||
[browser_bug982298.js]
|
||||
[browser_default_image_filename.js]
|
||||
skip-if = e10s # Bug 933103 - mochitest's EventUtils.synthesizeMouse functions not e10s friendly
|
||||
[browser_f7_caret_browsing.js]
|
||||
[browser_findbar.js]
|
||||
skip-if = e10s # Disabled for e10s: Bug ?????? - seems to be a timing issue with RemoteFinder.jsm messages coming later than the tests expect.
|
||||
[browser_input_file_tooltips.js]
|
||||
|
279
toolkit/content/tests/browser/browser_f7_caret_browsing.js
Normal file
279
toolkit/content/tests/browser/browser_f7_caret_browsing.js
Normal file
@ -0,0 +1,279 @@
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
|
||||
"resource://gre/modules/Promise.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Task",
|
||||
"resource://gre/modules/Task.jsm");
|
||||
|
||||
let gTab = null;
|
||||
let gListener = null;
|
||||
const kURL = "data:text/html;charset=utf-8,Caret browsing is fun.<input id='in'>";
|
||||
|
||||
const kPrefShortcutEnabled = "accessibility.browsewithcaret_shortcut.enabled";
|
||||
const kPrefWarnOnEnable = "accessibility.warn_on_browsewithcaret";
|
||||
const kPrefCaretBrowsingOn = "accessibility.browsewithcaret";
|
||||
|
||||
let oldPrefs = {};
|
||||
for (let pref of [kPrefShortcutEnabled, kPrefWarnOnEnable, kPrefCaretBrowsingOn]) {
|
||||
oldPrefs[pref] = Services.prefs.getBoolPref(pref);
|
||||
}
|
||||
|
||||
Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
|
||||
Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
|
||||
Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
if (gTab)
|
||||
gBrowser.removeTab(gTab);
|
||||
if (gListener)
|
||||
Services.wm.removeListener(gListener);
|
||||
|
||||
for (let pref of [kPrefShortcutEnabled, kPrefWarnOnEnable, kPrefCaretBrowsingOn]) {
|
||||
Services.prefs.setBoolPref(pref, oldPrefs[pref]);
|
||||
}
|
||||
});
|
||||
|
||||
function waitForCondition(aConditionFn, aMaxTries=50, aCheckInterval=100) {
|
||||
function tryNow() {
|
||||
tries++;
|
||||
if (aConditionFn()) {
|
||||
deferred.resolve();
|
||||
} else if (tries < aMaxTries) {
|
||||
tryAgain();
|
||||
} else {
|
||||
deferred.reject("Condition timed out: " + aConditionFn.toSource());
|
||||
}
|
||||
}
|
||||
function tryAgain() {
|
||||
setTimeout(tryNow, aCheckInterval);
|
||||
}
|
||||
let deferred = Promise.defer();
|
||||
let tries = 0;
|
||||
tryAgain();
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseWaitForDialogUnload(dialog) {
|
||||
let deferred = Promise.defer();
|
||||
dialog.addEventListener("unload", function listener() {
|
||||
dialog.removeEventListener("unload", listener, false);
|
||||
deferred.resolve();
|
||||
}, false);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseWaitForFocusEvent(el) {
|
||||
if (el.ownerDocument.activeElement == el) {
|
||||
return true;
|
||||
}
|
||||
let deferred = Promise.defer();
|
||||
el.addEventListener("focus", function listener() {
|
||||
el.removeEventListener("focus", listener, false);
|
||||
deferred.resolve();
|
||||
}, false);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseTestPageLoad() {
|
||||
let deferred = Promise.defer();
|
||||
info("Waiting for test page to load.");
|
||||
|
||||
gTab = gBrowser.selectedTab = gBrowser.addTab(kURL);
|
||||
let browser = gBrowser.selectedBrowser;
|
||||
browser.addEventListener("load", function listener() {
|
||||
if (browser.currentURI.spec == "about:blank")
|
||||
return;
|
||||
info("Page loaded: " + browser.currentURI.spec);
|
||||
browser.removeEventListener("load", listener, true);
|
||||
|
||||
deferred.resolve();
|
||||
}, true);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function promiseCaretPromptOpened() {
|
||||
let deferred = Promise.defer();
|
||||
if (gListener) {
|
||||
console.trace();
|
||||
ok(false, "Should not be waiting for another prompt right now.");
|
||||
return false;
|
||||
}
|
||||
info("Waiting for caret prompt to open");
|
||||
gListener = {
|
||||
onOpenWindow: function(win) {
|
||||
let window = win.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindow);
|
||||
window.addEventListener("load", function listener() {
|
||||
window.removeEventListener("load", listener);
|
||||
if (window.location.href == "chrome://global/content/commonDialog.xul") {
|
||||
info("Caret prompt opened, removing listener and focusing");
|
||||
Services.wm.removeListener(gListener);
|
||||
gListener = null;
|
||||
deferred.resolve(window);
|
||||
}
|
||||
});
|
||||
},
|
||||
onCloseWindow: function() {},
|
||||
};
|
||||
Services.wm.addListener(gListener);
|
||||
return deferred.promise;
|
||||
}
|
||||
|
||||
function hitF7(async = true) {
|
||||
let f7 = () => EventUtils.sendKey("F7", window.content);
|
||||
// Need to not stop execution inside this task:
|
||||
if (async) {
|
||||
executeSoon(f7);
|
||||
} else {
|
||||
f7();
|
||||
}
|
||||
}
|
||||
|
||||
function syncToggleCaretNoDialog(expected) {
|
||||
let openedDialog = false;
|
||||
promiseCaretPromptOpened().then(function(win) {
|
||||
openedDialog = true;
|
||||
win.close(); // This will eventually return focus here and allow the test to continue...
|
||||
});
|
||||
// Cause the dialog to appear sync, if it still does.
|
||||
hitF7(false);
|
||||
if (gListener) {
|
||||
Services.wm.removeListener(gListener);
|
||||
gListener = null;
|
||||
}
|
||||
let expectedStr = expected ? "on." : "off.";
|
||||
ok(!openedDialog, "Shouldn't open a dialog to turn caret browsing " + expectedStr);
|
||||
let prefVal = Services.prefs.getBoolPref(kPrefCaretBrowsingOn);
|
||||
is(prefVal, expected, "Caret browsing should now be " + expectedStr);
|
||||
}
|
||||
|
||||
add_task(function* checkTogglingCaretBrowsing() {
|
||||
yield promiseTestPageLoad();
|
||||
let textEl = window.content.document.getElementById("in");
|
||||
textEl.focus();
|
||||
|
||||
let promiseGotKey = promiseCaretPromptOpened();
|
||||
hitF7();
|
||||
let prompt = yield promiseGotKey;
|
||||
let doc = prompt.document;
|
||||
is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
|
||||
ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
|
||||
let promiseDialogUnloaded = promiseWaitForDialogUnload(prompt);
|
||||
doc.documentElement.cancelDialog();
|
||||
yield promiseDialogUnloaded;
|
||||
yield waitForCondition(() => textEl.ownerDocument.activeElement == textEl);
|
||||
ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off after cancelling the dialog.");
|
||||
|
||||
promiseGotKey = promiseCaretPromptOpened();
|
||||
hitF7();
|
||||
prompt = yield promiseGotKey;
|
||||
|
||||
doc = prompt.document;
|
||||
is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
|
||||
ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
|
||||
promiseDialogUnloaded = promiseWaitForDialogUnload(prompt);
|
||||
doc.documentElement.acceptDialog();
|
||||
yield promiseDialogUnloaded;
|
||||
yield waitForCondition(() => textEl.ownerDocument.activeElement == textEl);
|
||||
ok(Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should be on after accepting the dialog.");
|
||||
|
||||
syncToggleCaretNoDialog(false);
|
||||
|
||||
promiseGotKey = promiseCaretPromptOpened();
|
||||
hitF7();
|
||||
prompt = yield promiseGotKey;
|
||||
doc = prompt.document;
|
||||
|
||||
is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
|
||||
ok(!doc.getElementById("checkbox").checked, "Checkbox shouldn't be checked by default.");
|
||||
|
||||
promiseDialogUnloaded = promiseWaitForDialogUnload(prompt);
|
||||
doc.documentElement.cancelDialog();
|
||||
yield promiseDialogUnloaded;
|
||||
yield waitForCondition(() => textEl.ownerDocument.activeElement == textEl);
|
||||
|
||||
ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off after cancelling the dialog.");
|
||||
|
||||
Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
|
||||
Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
|
||||
Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
|
||||
|
||||
gBrowser.removeTab(gTab);
|
||||
gTab = null;
|
||||
});
|
||||
|
||||
add_task(function* toggleCheckboxNoCaretBrowsing() {
|
||||
yield promiseTestPageLoad();
|
||||
let textEl = window.content.document.getElementById("in");
|
||||
textEl.focus();
|
||||
|
||||
let promiseGotKey = promiseCaretPromptOpened();
|
||||
hitF7();
|
||||
let prompt = yield promiseGotKey;
|
||||
let doc = prompt.document;
|
||||
is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
|
||||
let checkbox = doc.getElementById("checkbox");
|
||||
ok(!checkbox.checked, "Checkbox shouldn't be checked by default.");
|
||||
|
||||
// Check the box:
|
||||
checkbox.click();
|
||||
let promiseDialogUnloaded = promiseWaitForDialogUnload(prompt);
|
||||
// Say no:
|
||||
doc.documentElement.getButton("cancel").click();
|
||||
yield promiseDialogUnloaded;
|
||||
yield waitForCondition(() => textEl.ownerDocument.activeElement == textEl);
|
||||
ok(!Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should still be off.");
|
||||
|
||||
ok(!Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should now be disabled.");
|
||||
|
||||
syncToggleCaretNoDialog(false);
|
||||
ok(!Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should still be disabled.");
|
||||
|
||||
Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
|
||||
Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
|
||||
Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
|
||||
|
||||
gBrowser.removeTab(gTab);
|
||||
gTab = null;
|
||||
});
|
||||
|
||||
|
||||
add_task(function* toggleCheckboxWantCaretBrowsing() {
|
||||
yield promiseTestPageLoad();
|
||||
let textEl = window.content.document.getElementById("in");
|
||||
textEl.focus();
|
||||
|
||||
let promiseGotKey = promiseCaretPromptOpened();
|
||||
hitF7();
|
||||
let prompt = yield promiseGotKey;
|
||||
let doc = prompt.document;
|
||||
is(doc.documentElement.defaultButton, "cancel", "No button should be the default");
|
||||
let checkbox = doc.getElementById("checkbox");
|
||||
ok(!checkbox.checked, "Checkbox shouldn't be checked by default.");
|
||||
|
||||
// Check the box:
|
||||
checkbox.click();
|
||||
let promiseDialogUnloaded = promiseWaitForDialogUnload(prompt);
|
||||
// Say yes:
|
||||
doc.documentElement.acceptDialog();
|
||||
yield promiseDialogUnloaded;
|
||||
yield waitForCondition(() => textEl.ownerDocument.activeElement == textEl);
|
||||
ok(Services.prefs.getBoolPref(kPrefCaretBrowsingOn), "Caret browsing should now be on.");
|
||||
ok(Services.prefs.getBoolPref(kPrefShortcutEnabled), "Shortcut should still be enabled.");
|
||||
ok(!Services.prefs.getBoolPref(kPrefWarnOnEnable), "Should no longer warn when enabling.");
|
||||
|
||||
|
||||
syncToggleCaretNoDialog(false);
|
||||
syncToggleCaretNoDialog(true);
|
||||
syncToggleCaretNoDialog(false);
|
||||
|
||||
Services.prefs.setBoolPref(kPrefShortcutEnabled, true);
|
||||
Services.prefs.setBoolPref(kPrefWarnOnEnable, true);
|
||||
Services.prefs.setBoolPref(kPrefCaretBrowsingOn, false);
|
||||
|
||||
gBrowser.removeTab(gTab);
|
||||
gTab = null;
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
@ -1100,7 +1100,11 @@
|
||||
if (event.defaultPrevented || !event.isTrusted)
|
||||
return;
|
||||
|
||||
var isEnabled = this.mPrefs.getBoolPref("accessibility.browsewithcaret_shortcut.enabled");
|
||||
const kPrefShortcutEnabled = "accessibility.browsewithcaret_shortcut.enabled";
|
||||
const kPrefWarnOnEnable = "accessibility.warn_on_browsewithcaret";
|
||||
const kPrefCaretBrowsingOn = "accessibility.browsewithcaret";
|
||||
|
||||
var isEnabled = this.mPrefs.getBoolPref(kPrefShortcutEnabled);
|
||||
if (!isEnabled)
|
||||
return;
|
||||
|
||||
@ -1109,12 +1113,12 @@
|
||||
var warn = true;
|
||||
|
||||
try {
|
||||
warn = this.mPrefs.getBoolPref("accessibility.warn_on_browsewithcaret");
|
||||
warn = this.mPrefs.getBoolPref(kPrefWarnOnEnable);
|
||||
} catch (ex) {
|
||||
}
|
||||
|
||||
try {
|
||||
browseWithCaretOn = this.mPrefs.getBoolPref("accessibility.browsewithcaret");
|
||||
browseWithCaretOn = this.mPrefs.getBoolPref(kPrefCaretBrowsingOn);
|
||||
} catch (ex) {
|
||||
}
|
||||
if (warn && !browseWithCaretOn) {
|
||||
@ -1125,14 +1129,22 @@
|
||||
var buttonPressed = promptService.confirmEx(window,
|
||||
this.mStrBundle.GetStringFromName('browsewithcaret.checkWindowTitle'),
|
||||
this.mStrBundle.GetStringFromName('browsewithcaret.checkLabel'),
|
||||
promptService.STD_YES_NO_BUTTONS,
|
||||
// Make "No" the default:
|
||||
promptService.STD_YES_NO_BUTTONS | promptService.BUTTON_POS_1_DEFAULT,
|
||||
null, null, null, this.mStrBundle.GetStringFromName('browsewithcaret.checkMsg'),
|
||||
checkValue);
|
||||
if (buttonPressed != 0)
|
||||
if (buttonPressed != 0) {
|
||||
if (checkValue.value) {
|
||||
try {
|
||||
this.mPrefs.setBoolPref(kPrefShortcutEnabled, false);
|
||||
} catch (ex) {
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (checkValue.value) {
|
||||
try {
|
||||
this.mPrefs.setBoolPref("accessibility.warn_on_browsewithcaret", false);
|
||||
this.mPrefs.setBoolPref(kPrefWarnOnEnable, false);
|
||||
}
|
||||
catch (ex) {
|
||||
}
|
||||
@ -1141,7 +1153,7 @@
|
||||
|
||||
// Toggle the pref
|
||||
try {
|
||||
this.mPrefs.setBoolPref("accessibility.browsewithcaret",!browseWithCaretOn);
|
||||
this.mPrefs.setBoolPref(kPrefCaretBrowsingOn, !browseWithCaretOn);
|
||||
} catch (ex) {
|
||||
}
|
||||
]]>
|
||||
|
@ -20,15 +20,18 @@ function setup_crash() {
|
||||
});
|
||||
|
||||
Services.obs.notifyObservers(null, TOPIC, null);
|
||||
dump(new Error().stack + "\n");
|
||||
dump("Waiting for crash\n");
|
||||
}
|
||||
|
||||
function after_crash(mdump, extra) {
|
||||
do_print("after crash: " + extra.AsyncShutdownTimeout);
|
||||
let info = JSON.parse(extra.AsyncShutdownTimeout);
|
||||
do_check_eq(info.phase, "testing-async-shutdown-crash");
|
||||
do_print("Condition: " + JSON.stringify(info.conditions));
|
||||
do_check_true(JSON.stringify(info.conditions).indexOf("A blocker that is never satisfied") != -1);
|
||||
Assert.equal(info.phase, "testing-async-shutdown-crash");
|
||||
Assert.equal(info.conditions[0].name, "A blocker that is never satisfied");
|
||||
// This test spawns subprocesses by using argument "-e" of xpcshell, so
|
||||
// this is the filename known to xpcshell.
|
||||
Assert.equal(info.conditions[0].filename, "-e");
|
||||
}
|
||||
|
||||
// Test that AsyncShutdown + OS.File reports errors correctly, in a case in which
|
||||
|
@ -428,12 +428,22 @@ function Barrier(name) {
|
||||
" has already begun, it is too late to register" +
|
||||
" completion condition '" + name + "'.");
|
||||
}
|
||||
|
||||
// Determine the filename and line number of the caller.
|
||||
let leaf = Components.stack;
|
||||
let frame;
|
||||
for (frame = leaf; frame != null && frame.filename == leaf.filename; frame = frame.caller) {
|
||||
// Climb up the stack
|
||||
}
|
||||
let set = this._conditions.get(condition);
|
||||
if (!set) {
|
||||
set = [];
|
||||
this._conditions.set(condition, set);
|
||||
}
|
||||
set.push({name: name, fetchState: fetchState});
|
||||
set.push({name: name,
|
||||
fetchState: fetchState,
|
||||
filename: frame ? frame.filename : "?",
|
||||
lineNumber: frame ? frame.lineNumber : -1});
|
||||
}.bind(this),
|
||||
|
||||
/**
|
||||
@ -480,9 +490,12 @@ Barrier.prototype = Object.freeze({
|
||||
return "Complete";
|
||||
}
|
||||
let frozen = [];
|
||||
for (let {name, isComplete, fetchState} of this._monitors) {
|
||||
for (let {name, isComplete, fetchState, filename, lineNumber} of this._monitors) {
|
||||
if (!isComplete) {
|
||||
frozen.push({name: name, state: safeGetState(fetchState)});
|
||||
frozen.push({name: name,
|
||||
state: safeGetState(fetchState),
|
||||
filename: filename,
|
||||
lineNumber: lineNumber});
|
||||
}
|
||||
}
|
||||
return frozen;
|
||||
@ -536,7 +549,7 @@ Barrier.prototype = Object.freeze({
|
||||
for (let _condition of conditions.keys()) {
|
||||
for (let current of conditions.get(_condition)) {
|
||||
let condition = _condition; // Avoid capturing the wrong variable
|
||||
let {name, fetchState} = current;
|
||||
let {name, fetchState, filename, lineNumber} = current;
|
||||
|
||||
// An indirection on top of condition, used to let clients
|
||||
// cancel a blocker through removeBlocker.
|
||||
@ -565,7 +578,9 @@ Barrier.prototype = Object.freeze({
|
||||
let monitor = {
|
||||
isComplete: false,
|
||||
name: name,
|
||||
fetchState: fetchState
|
||||
fetchState: fetchState,
|
||||
filename: filename,
|
||||
lineNumber: lineNumber
|
||||
};
|
||||
|
||||
condition = condition.then(null, function onError(error) {
|
||||
@ -669,12 +684,16 @@ Barrier.prototype = Object.freeze({
|
||||
// Report the problem as best as we can, then crash.
|
||||
let state = this.state;
|
||||
|
||||
let msg = "At least one completion condition failed to complete" +
|
||||
// If you change the following message, please make sure
|
||||
// that any information on the topic and state appears
|
||||
// within the first 200 characters of the message. This
|
||||
// helps automatically sort oranges.
|
||||
let msg = "AsyncShutdown timeout in " + topic +
|
||||
" Conditions: " + JSON.stringify(state) +
|
||||
" At least one completion condition failed to complete" +
|
||||
" within a reasonable amount of time. Causing a crash to" +
|
||||
" ensure that we do not leave the user with an unresponsive" +
|
||||
" process draining resources." +
|
||||
" Conditions: " + JSON.stringify(state) +
|
||||
" Barrier: " + topic;
|
||||
err(msg);
|
||||
if (gCrashReporter && gCrashReporter.enabled) {
|
||||
let data = {
|
||||
@ -682,13 +701,27 @@ Barrier.prototype = Object.freeze({
|
||||
conditions: state
|
||||
};
|
||||
gCrashReporter.annotateCrashReport("AsyncShutdownTimeout",
|
||||
JSON.stringify(data));
|
||||
JSON.stringify(data));
|
||||
} else {
|
||||
warn("No crash reporter available");
|
||||
}
|
||||
|
||||
let error = new Error();
|
||||
gDebug.abort(error.fileName, error.lineNumber + 1);
|
||||
// To help sorting out bugs, we want to make sure that the
|
||||
// call to nsIDebug.abort points to a guilty client, rather
|
||||
// than to AsyncShutdown itself. We search through all the
|
||||
// clients until we find one that is guilty and use its
|
||||
// filename/lineNumber, which have been determined during
|
||||
// the call to `addBlocker`.
|
||||
let filename = "?";
|
||||
let lineNumber = -1;
|
||||
for (let monitor of this._monitors) {
|
||||
if (monitor.isComplete) {
|
||||
continue;
|
||||
}
|
||||
filename = monitor.filename;
|
||||
lineNumber = monitor.lineNumber;
|
||||
}
|
||||
gDebug.abort(filename, lineNumber);
|
||||
}.bind(this),
|
||||
function onSatisfied() {
|
||||
// The promise has been rejected, which means that we have satisfied
|
||||
@ -697,7 +730,7 @@ Barrier.prototype = Object.freeze({
|
||||
|
||||
promise = promise.then(function() {
|
||||
timeToCrash.reject();
|
||||
}.bind(this)/* No error is possible here*/);
|
||||
}/* No error is possible here*/);
|
||||
}
|
||||
|
||||
return promise;
|
||||
|
@ -270,7 +270,35 @@ add_task(function* test_phase_removeBlocker() {
|
||||
|
||||
});
|
||||
|
||||
add_task(function() {
|
||||
add_task(function* test_state() {
|
||||
do_print("Testing information contained in `state`");
|
||||
|
||||
let BLOCKER_NAME = "test_state blocker " + Math.random();
|
||||
|
||||
// Set up the barrier. Note that we cannot test `barrier.state`
|
||||
// immediately, as it initially contains "Not started"
|
||||
let barrier = new AsyncShutdown.Barrier("test_filename");
|
||||
let deferred = Promise.defer();
|
||||
let {filename, lineNumber} = Components.stack;
|
||||
barrier.client.addBlocker(BLOCKER_NAME,
|
||||
function() {
|
||||
return deferred.promise;
|
||||
});
|
||||
|
||||
let promiseDone = barrier.wait();
|
||||
|
||||
// Now that we have called `wait()`, the state contains interesting things
|
||||
let state = barrier.state[0];
|
||||
do_print("State: " + JSON.stringify(barrier.state, null, "\t"));
|
||||
Assert.equal(state.filename, filename);
|
||||
Assert.equal(state.lineNumber, lineNumber + 2);
|
||||
Assert.equal(state.name, BLOCKER_NAME);
|
||||
|
||||
deferred.resolve();
|
||||
yield promiseDone;
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");
|
||||
});
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user