mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-26 06:11:37 +00:00
Merge inbound to central, a=merge
MozReview-Commit-ID: 4FEkd1x2GD
This commit is contained in:
commit
2a30786cad
@ -1,5 +1,4 @@
|
||||
[DEFAULT]
|
||||
skip-if = e10s && os == 'win' && release_or_beta
|
||||
support-files =
|
||||
head.js
|
||||
!/accessible/tests/browser/events.js
|
||||
|
@ -1,5 +1,4 @@
|
||||
[DEFAULT]
|
||||
skip-if = e10s && os == 'win' && release_or_beta
|
||||
support-files =
|
||||
head.js
|
||||
doc_treeupdate_ariadialog.html
|
||||
|
@ -1,5 +1,4 @@
|
||||
[DEFAULT]
|
||||
skip-if = e10s && os == 'win' && release_or_beta
|
||||
support-files =
|
||||
head.js
|
||||
!/accessible/tests/browser/events.js
|
||||
|
@ -1,5 +1,4 @@
|
||||
[DEFAULT]
|
||||
skip-if = e10s && os == 'win' && release_or_beta
|
||||
support-files =
|
||||
head.js
|
||||
!/accessible/tests/browser/events.js
|
||||
|
@ -1,5 +1,4 @@
|
||||
[DEFAULT]
|
||||
skip-if = e10s && os == 'win' && release_or_beta
|
||||
support-files =
|
||||
head.js
|
||||
!/accessible/tests/browser/events.js
|
||||
|
@ -1,5 +1,4 @@
|
||||
[DEFAULT]
|
||||
skip-if = e10s && os == 'win' && release_or_beta
|
||||
support-files =
|
||||
head.js
|
||||
!/accessible/tests/browser/events.js
|
||||
|
@ -667,9 +667,6 @@ 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);
|
||||
|
||||
@ -980,9 +977,6 @@ 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%/");
|
||||
|
@ -528,13 +528,6 @@ 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)
|
||||
@ -1009,10 +1002,7 @@ BrowserGlue.prototype = {
|
||||
}
|
||||
|
||||
this._sanitizer.onStartup();
|
||||
E10SAccessibilityCheck.onWindowsRestored();
|
||||
|
||||
this._scheduleStartupIdleTasks();
|
||||
|
||||
this._lateTasksIdleObserver = (idleService, topic, data) => {
|
||||
if (topic == "idle") {
|
||||
idleService.removeIdleObserver(this._lateTasksIdleObserver,
|
||||
@ -2800,132 +2790,9 @@ 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.
|
||||
|
@ -63,9 +63,6 @@ browser.jar:
|
||||
|
||||
skin/classic/browser/sync-desktopIcon.svg (../shared/sync-desktopIcon.svg)
|
||||
skin/classic/browser/sync-mobileIcon.svg (../shared/sync-mobileIcon.svg)
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
skin/classic/browser/e10s-64@2x.png (../shared/e10s-64@2x.png)
|
||||
#endif
|
||||
|
||||
[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
|
||||
% override chrome://browser/skin/feeds/audioFeedIcon.png chrome://browser/skin/feeds/feedIcon.png
|
||||
|
@ -87,9 +87,6 @@ browser.jar:
|
||||
skin/classic/browser/yosemite/menuPanel-exit@2x.png (menuPanel-exit-yosemite@2x.png)
|
||||
skin/classic/browser/yosemite/menuPanel-help.png (menuPanel-help-yosemite.png)
|
||||
skin/classic/browser/yosemite/menuPanel-help@2x.png (menuPanel-help-yosemite@2x.png)
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
skin/classic/browser/e10s-64@2x.png (../shared/e10s-64@2x.png)
|
||||
#endif
|
||||
|
||||
[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
|
||||
% override chrome://browser/skin/feeds/audioFeedIcon.png chrome://browser/skin/feeds/feedIcon.png
|
||||
|
@ -57,14 +57,13 @@
|
||||
|
||||
.customizationmode-button {
|
||||
border: 1px solid #b1b1b1;
|
||||
margin: 6px 10px;
|
||||
padding: 2px 5px;
|
||||
background-color: #fcfcfd;
|
||||
color: rgb(71,71,71);
|
||||
-moz-appearance: none;
|
||||
}
|
||||
|
||||
.customizationmode-checkbox {
|
||||
.customizationmode-checkbox,
|
||||
.customizationmode-button {
|
||||
color: rgb(71, 71, 71);
|
||||
margin: 6px 10px;
|
||||
padding: 2px 5px;
|
||||
}
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 20 KiB |
@ -83,10 +83,6 @@ browser.jar:
|
||||
skin/classic/browser/window-controls/restore-highcontrast.svg (window-controls/restore-highcontrast.svg)
|
||||
skin/classic/browser/window-controls/restore-themes.svg (window-controls/restore-themes.svg)
|
||||
|
||||
#ifdef E10S_TESTING_ONLY
|
||||
skin/classic/browser/e10s-64@2x.png (../shared/e10s-64@2x.png)
|
||||
#endif
|
||||
|
||||
[extensions/{972ce4c6-7e08-4474-a285-3208198ce6fd}] chrome.jar:
|
||||
% override chrome://browser/skin/page-livemarks.png chrome://browser/skin/feeds/feedIcon16.png
|
||||
% override chrome://browser/skin/feeds/audioFeedIcon.png chrome://browser/skin/feeds/feedIcon.png
|
||||
|
@ -420,6 +420,10 @@ body {
|
||||
--search-overlays-semitransparent: rgba(42, 46, 56, 0.66);
|
||||
--popup-shadow-color: #5c667b;
|
||||
}
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.debugger {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
@ -877,12 +881,6 @@ html .arrow.expanded svg {
|
||||
.managed-tree .tree .node.focused {
|
||||
color: white;
|
||||
background-color: var(--theme-selection-background);
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.theme-dark .managed-tree .tree .node.focused {
|
||||
background-color: var(--theme-selection-background-hover);
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
html:not([dir="rtl"]) .managed-tree .tree .node > div {
|
||||
@ -907,7 +905,7 @@ html[dir="rtl"] .managed-tree .tree .node > div {
|
||||
.close-btn .close {
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
transition: all 0.25s ease-in-out;
|
||||
transition: all 0.15s ease-in-out;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px;
|
||||
padding: 0;
|
||||
@ -1267,15 +1265,16 @@ html[dir="rtl"] .managed-tree .tree .node > div {
|
||||
|
||||
.toggle-search .text {
|
||||
margin-left: 1em;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.toggle-search .active {
|
||||
color: var(--theme-selection-background);
|
||||
cursor: default;
|
||||
}
|
||||
.sources-panel {
|
||||
flex: 1;
|
||||
background-color: var(--theme-sidebar-background);
|
||||
display: flex;
|
||||
flex: 1;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
@ -1287,7 +1286,8 @@ html[dir="rtl"] .managed-tree .tree .node > div {
|
||||
}
|
||||
|
||||
.sources-header {
|
||||
height: 30px;
|
||||
height: 29px;
|
||||
background-color: var(--theme-toolbar-background);
|
||||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
@ -2236,7 +2236,7 @@ html[dir="rtl"] .arrow svg,
|
||||
width: calc(100% - 1.5px);
|
||||
top: 30px;
|
||||
left: 0px;
|
||||
--editor-footer-height: 27px;
|
||||
--editor-footer-height: 24px;
|
||||
}
|
||||
|
||||
html[dir="rtl"] .editor-mount {
|
||||
@ -2440,24 +2440,8 @@ html[dir="rtl"] .editor-mount {
|
||||
|
||||
.cm-highlight-full::before {
|
||||
border: 1px solid var(--theme-comment-alt);
|
||||
}
|
||||
|
||||
.cm-highlight-start::before {
|
||||
border-left-width: 1px;
|
||||
border-left-style: solid;
|
||||
border-left-color: var(--theme-comment-alt);
|
||||
margin: 0 0 -1px -1px;
|
||||
border-top-left-radius: 2px;
|
||||
border-bottom-left-radius: 2px;
|
||||
}
|
||||
|
||||
.cm-highlight-end::before {
|
||||
border-right-width: 1px;
|
||||
border-right-style: solid;
|
||||
border-right-color: var(--theme-comment-alt);
|
||||
margin: 0 -1px -1px 0;
|
||||
border-top-right-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
border-radius: 2px;
|
||||
margin: 0 -1px -1px -1px;
|
||||
}
|
||||
.breakpoints-toggle {
|
||||
margin: 2px 3px;
|
||||
@ -2566,7 +2550,7 @@ html .breakpoints-list .breakpoint.paused {
|
||||
width: 100%;
|
||||
margin: 0px;
|
||||
border: 1px;
|
||||
background-color: var(--theme-body-background);
|
||||
background-color: var(--theme-sidebar-background);
|
||||
font-size: 12px;
|
||||
padding: 0px 20px;
|
||||
color: var(--theme-body-color);
|
||||
@ -2587,7 +2571,7 @@ html .breakpoints-list .breakpoint.paused {
|
||||
.expressions-list {
|
||||
/* TODO: add normalize */
|
||||
margin: 0;
|
||||
padding: 0.5em 0;
|
||||
padding: 0;
|
||||
}
|
||||
.expression-input-container {
|
||||
padding: 0.5em;
|
||||
@ -2851,18 +2835,29 @@ html .breakpoints-list .breakpoint.paused {
|
||||
.event-listeners .listener:hover .close {
|
||||
display: block;
|
||||
}
|
||||
|
||||
:root {
|
||||
--accordion-header-background: var(--theme-toolbar-background);
|
||||
}
|
||||
|
||||
:root.theme-dark {
|
||||
--accordion-header-background: #141416;
|
||||
}
|
||||
|
||||
.accordion {
|
||||
background-color: var(--theme-body-background);
|
||||
background-color: var(--theme-sidebar-background);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.accordion ._header {
|
||||
background-color: var(--theme-toolbar-background);
|
||||
background-color: var(--accordion-header-background);
|
||||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
display: flex;
|
||||
font-size: 12px;
|
||||
padding: 5px;
|
||||
padding: 4px;
|
||||
transition: all 0.25s ease;
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
align-items: center;
|
||||
|
||||
-webkit-user-select: none;
|
||||
@ -2872,10 +2867,6 @@ html .breakpoints-list .breakpoint.paused {
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.accordion ._header {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.accordion ._header:hover {
|
||||
background-color: var(--theme-toolbar-background-hover);
|
||||
}
|
||||
@ -2921,15 +2912,15 @@ html .breakpoints-list .breakpoint.paused {
|
||||
border: none;
|
||||
}
|
||||
.command-bar {
|
||||
flex: 0 0 30px;
|
||||
flex: 0 0 29px;
|
||||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
display: flex;
|
||||
height: 30px;
|
||||
height: 29px;
|
||||
overflow: hidden;
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 1;
|
||||
background-color: var(--theme-body-background);
|
||||
background-color: var(--theme-toolbar-background);
|
||||
}
|
||||
|
||||
.command-bar.vertical {
|
||||
@ -3083,14 +3074,17 @@ html .command-bar > button:disabled {
|
||||
text-align: center;
|
||||
font-size: 1.25em;
|
||||
color: var(--theme-comment-alt);
|
||||
background-color: var(--theme-tab-toolbar-background);
|
||||
background-color: var(--theme-toolbar-background);
|
||||
font-weight: lighter;
|
||||
z-index: 100;
|
||||
}
|
||||
|
||||
.theme-dark .welcomebox {
|
||||
background-color: var(--theme-body-background);
|
||||
}
|
||||
|
||||
.alignlabel {
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.welcomebox .toggle-button-end {
|
||||
@ -3101,13 +3095,25 @@ html .command-bar > button:disabled {
|
||||
offset-inline-start: auto;
|
||||
}
|
||||
|
||||
.shortcutKeys {
|
||||
text-align: right;
|
||||
float: left;
|
||||
font-family: Courier;
|
||||
}
|
||||
|
||||
.shortcutFunction {
|
||||
text-align: left;
|
||||
float: left;
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
html .welcomebox .toggle-button-end.collapsed {
|
||||
bottom: 1px;
|
||||
}
|
||||
.source-header {
|
||||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
width: 100%;
|
||||
height: 30px;
|
||||
height: 29px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
@ -3147,7 +3153,7 @@ html .welcomebox .toggle-button-end.collapsed {
|
||||
display: inline-flex;
|
||||
align-items: flex-end;
|
||||
position: relative;
|
||||
transition: all 0.25s ease;
|
||||
transition: all 0.15s ease;
|
||||
min-width: 40px;
|
||||
overflow: hidden;
|
||||
padding: 5px;
|
||||
|
File diff suppressed because one or more lines are too long
@ -4126,45 +4126,7 @@ module.exports = baseCreate;
|
||||
|
||||
|
||||
/***/ }),
|
||||
/* 404 */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
var isArrayLike = __webpack_require__(220),
|
||||
isObjectLike = __webpack_require__(14);
|
||||
|
||||
/**
|
||||
* This method is like `_.isArrayLike` except that it also checks if `value`
|
||||
* is an object.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @since 4.0.0
|
||||
* @category Lang
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if `value` is an array-like object,
|
||||
* else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isArrayLikeObject([1, 2, 3]);
|
||||
* // => true
|
||||
*
|
||||
* _.isArrayLikeObject(document.body.children);
|
||||
* // => true
|
||||
*
|
||||
* _.isArrayLikeObject('abc');
|
||||
* // => false
|
||||
*
|
||||
* _.isArrayLikeObject(_.noop);
|
||||
* // => false
|
||||
*/
|
||||
function isArrayLikeObject(value) {
|
||||
return isObjectLike(value) && isArrayLike(value);
|
||||
}
|
||||
|
||||
module.exports = isArrayLikeObject;
|
||||
|
||||
|
||||
/***/ }),
|
||||
/* 404 */,
|
||||
/* 405 */,
|
||||
/* 406 */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
@ -28517,6 +28479,9 @@ module.exports = basePropertyDeep;
|
||||
Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
|
||||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
||||
|
||||
exports.getNextStep = getNextStep;
|
||||
|
||||
var _debuggerHtml = __webpack_require__(843);
|
||||
@ -28525,45 +28490,40 @@ var _types = __webpack_require__(844);
|
||||
|
||||
var _closest = __webpack_require__(1055);
|
||||
|
||||
var _contains = __webpack_require__(1127);
|
||||
|
||||
var _helpers = __webpack_require__(1052);
|
||||
|
||||
function getNextStep(source, stepType, pausedPosition) {
|
||||
function getNextStep(source, pausedPosition) {
|
||||
var awaitExpression = getAwaitExpression(source, pausedPosition);
|
||||
if (!awaitExpression) {
|
||||
return null;
|
||||
}
|
||||
var awaitStatement = awaitExpression.getStatementParent();
|
||||
return getLocationAfterAwaitExpression(awaitStatement, pausedPosition);
|
||||
}
|
||||
|
||||
function getAwaitExpression(source, pausedPosition) {
|
||||
var closestPath = (0, _closest.getClosestPath)(source, pausedPosition);
|
||||
|
||||
if (!closestPath) {
|
||||
return { nextStepType: stepType };
|
||||
return null;
|
||||
}
|
||||
if ((0, _helpers.isAwaitExpression)(closestPath, pausedPosition)) {
|
||||
var nextHiddenBreakpointLocation = getLocationAfterAwaitExpression(closestPath, pausedPosition);
|
||||
return { nextStepType: "resume", nextHiddenBreakpointLocation };
|
||||
|
||||
if ((0, _helpers.isAwaitExpression)(closestPath)) {
|
||||
return closestPath;
|
||||
}
|
||||
return { nextStepType: stepType };
|
||||
|
||||
return closestPath.find(p => p.isAwaitExpression());
|
||||
}
|
||||
|
||||
function getLocationAfterAwaitExpression(path, position) {
|
||||
var children = getFunctionBodyChildren(path);
|
||||
if (!children) {
|
||||
return;
|
||||
function getLocationAfterAwaitExpression(statement, position) {
|
||||
var nextStatement = statement.getSibling(statement.key + 1);
|
||||
if (nextStatement.node) {
|
||||
return _extends({}, nextStatement.node.loc.start, {
|
||||
sourceId: position.sourceId
|
||||
});
|
||||
}
|
||||
for (var i = 0; i !== children.length; i++) {
|
||||
var child = children[i];
|
||||
if ((0, _contains.containsPosition)(child.loc, position)) {
|
||||
var nextChild = children[++i];
|
||||
var nextLocation = nextChild.loc.start;
|
||||
nextLocation.sourceId = position.sourceId;
|
||||
return nextLocation;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getFunctionBodyChildren(path) {
|
||||
var blockScope = path.scope.block;
|
||||
if (!blockScope) {
|
||||
return;
|
||||
}
|
||||
var children = blockScope.body.body;
|
||||
return children;
|
||||
return null;
|
||||
}
|
||||
|
||||
/***/ }),
|
||||
@ -28937,6 +28897,8 @@ var _getSymbols = __webpack_require__(1050);
|
||||
|
||||
var _getSymbols2 = _interopRequireDefault(_getSymbols);
|
||||
|
||||
var _ast = __webpack_require__(1051);
|
||||
|
||||
var _getOutOfScopeLocations = __webpack_require__(1072);
|
||||
|
||||
var _getOutOfScopeLocations2 = _interopRequireDefault(_getOutOfScopeLocations);
|
||||
@ -28959,6 +28921,7 @@ self.onmessage = workerHandler({
|
||||
getOutOfScopeLocations: _getOutOfScopeLocations2.default,
|
||||
getSymbols: _getSymbols2.default,
|
||||
clearSymbols: _getSymbols.clearSymbols,
|
||||
clearASTs: _ast.clearASTs,
|
||||
getVariablesInScope: _scopes.getVariablesInScope,
|
||||
getNextStep: _steps.getNextStep,
|
||||
getEmptyLines: _getEmptyLines2.default
|
||||
@ -29745,6 +29708,7 @@ Object.defineProperty(exports, "__esModule", {
|
||||
value: true
|
||||
});
|
||||
exports.getAst = getAst;
|
||||
exports.clearASTs = clearASTs;
|
||||
exports.traverseAst = traverseAst;
|
||||
|
||||
var _parseScriptTags = __webpack_require__(1023);
|
||||
@ -29822,6 +29786,10 @@ function getAst(source) {
|
||||
return ast;
|
||||
}
|
||||
|
||||
function clearASTs() {
|
||||
ASTs = new Map();
|
||||
}
|
||||
|
||||
function traverseAst(source, visitor) {
|
||||
var ast = getAst(source);
|
||||
if ((0, _isEmpty2.default)(ast)) {
|
||||
@ -32842,6 +32810,7 @@ function containsPosition(a, b) {
|
||||
|
||||
return startsBefore && endsAfter;
|
||||
}
|
||||
|
||||
function containsLocation(a, b) {
|
||||
return containsPosition(a, b.start) && containsPosition(a, b.end);
|
||||
}
|
||||
@ -32858,7 +32827,7 @@ function nodeContainsPosition(node, position) {
|
||||
var baseDifference = __webpack_require__(1131),
|
||||
baseFlatten = __webpack_require__(707),
|
||||
baseRest = __webpack_require__(411),
|
||||
isArrayLikeObject = __webpack_require__(404);
|
||||
isArrayLikeObject = __webpack_require__(1155);
|
||||
|
||||
/**
|
||||
* Creates an array of `array` values not included in the other given arrays
|
||||
@ -32964,6 +32933,68 @@ function baseDifference(array, values, iteratee, comparator) {
|
||||
module.exports = baseDifference;
|
||||
|
||||
|
||||
/***/ }),
|
||||
/* 1132 */,
|
||||
/* 1133 */,
|
||||
/* 1134 */,
|
||||
/* 1135 */,
|
||||
/* 1136 */,
|
||||
/* 1137 */,
|
||||
/* 1138 */,
|
||||
/* 1139 */,
|
||||
/* 1140 */,
|
||||
/* 1141 */,
|
||||
/* 1142 */,
|
||||
/* 1143 */,
|
||||
/* 1144 */,
|
||||
/* 1145 */,
|
||||
/* 1146 */,
|
||||
/* 1147 */,
|
||||
/* 1148 */,
|
||||
/* 1149 */,
|
||||
/* 1150 */,
|
||||
/* 1151 */,
|
||||
/* 1152 */,
|
||||
/* 1153 */,
|
||||
/* 1154 */,
|
||||
/* 1155 */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
var isArrayLike = __webpack_require__(220),
|
||||
isObjectLike = __webpack_require__(14);
|
||||
|
||||
/**
|
||||
* This method is like `_.isArrayLike` except that it also checks if `value`
|
||||
* is an object.
|
||||
*
|
||||
* @static
|
||||
* @memberOf _
|
||||
* @since 4.0.0
|
||||
* @category Lang
|
||||
* @param {*} value The value to check.
|
||||
* @returns {boolean} Returns `true` if `value` is an array-like object,
|
||||
* else `false`.
|
||||
* @example
|
||||
*
|
||||
* _.isArrayLikeObject([1, 2, 3]);
|
||||
* // => true
|
||||
*
|
||||
* _.isArrayLikeObject(document.body.children);
|
||||
* // => true
|
||||
*
|
||||
* _.isArrayLikeObject('abc');
|
||||
* // => false
|
||||
*
|
||||
* _.isArrayLikeObject(_.noop);
|
||||
* // => false
|
||||
*/
|
||||
function isArrayLikeObject(value) {
|
||||
return isObjectLike(value) && isArrayLike(value);
|
||||
}
|
||||
|
||||
module.exports = isArrayLikeObject;
|
||||
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
});
|
@ -317,7 +317,7 @@ function ignoreWhiteSpace(str) {
|
||||
|
||||
|
||||
function wholeMatch(query, wholeWord) {
|
||||
if (query == "" || !wholeWord) {
|
||||
if (query === "" || !wholeWord) {
|
||||
return query;
|
||||
}
|
||||
|
||||
@ -350,7 +350,7 @@ function buildQuery(originalQuery, modifiers, _ref) {
|
||||
wholeWord = modifiers.wholeWord;
|
||||
|
||||
|
||||
if (originalQuery == "") {
|
||||
if (originalQuery === "") {
|
||||
return new RegExp(originalQuery);
|
||||
}
|
||||
|
||||
@ -443,8 +443,6 @@ var _buildQuery2 = _interopRequireDefault(_buildQuery);
|
||||
|
||||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
||||
|
||||
var MAX_LENGTH = 100000;
|
||||
|
||||
function getMatches(query, text, modifiers) {
|
||||
if (!query || !text || !modifiers) {
|
||||
return [];
|
||||
@ -457,12 +455,8 @@ function getMatches(query, text, modifiers) {
|
||||
for (var i = 0; i < lines.length; i++) {
|
||||
var singleMatch = void 0;
|
||||
var line = lines[i];
|
||||
if (line.length <= MAX_LENGTH) {
|
||||
while ((singleMatch = regexQuery.exec(line)) !== null) {
|
||||
matchedLocations.push({ line: i, ch: singleMatch.index });
|
||||
}
|
||||
} else {
|
||||
return [];
|
||||
while ((singleMatch = regexQuery.exec(line)) !== null) {
|
||||
matchedLocations.push({ line: i, ch: singleMatch.index });
|
||||
}
|
||||
}
|
||||
return matchedLocations;
|
||||
@ -873,13 +867,20 @@ function getSourceLineCount(source) {
|
||||
function getMode(source) {
|
||||
var contentType = source.contentType,
|
||||
text = source.text,
|
||||
isWasm = source.isWasm;
|
||||
isWasm = source.isWasm,
|
||||
url = source.url;
|
||||
|
||||
|
||||
if (!text || isWasm) {
|
||||
return { name: "text" };
|
||||
}
|
||||
|
||||
// if the url ends with .marko we set the name to Javascript so
|
||||
// syntax highlighting works for marko too
|
||||
if (url && url.match(/\.marko$/i)) {
|
||||
return { name: "javascript" };
|
||||
}
|
||||
|
||||
// Use HTML mode for files in which the first non whitespace
|
||||
// character is `<` regardless of extension.
|
||||
var isHTMLLike = text.match(/^\s*</);
|
||||
|
@ -48,6 +48,7 @@ support-files =
|
||||
[browser_dbg-breaking.js]
|
||||
[browser_dbg-breaking-from-console.js]
|
||||
[browser_dbg-breakpoints.js]
|
||||
[browser_dbg-breakpoints-toggle.js]
|
||||
[browser_dbg-breakpoints-reloading.js]
|
||||
skip-if = true # Bug 1383576
|
||||
[browser_dbg-breakpoints-cond.js]
|
||||
|
@ -1,10 +1,7 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Tests async stepping will:
|
||||
// 1. step over await statements
|
||||
// 2. step into async functions
|
||||
// 3. step out of async functions
|
||||
// Tests async stepping will step over await statements
|
||||
add_task(async function test() {
|
||||
Services.prefs.setBoolPref("devtools.debugger.features.async-stepping", true);
|
||||
const dbg = await initDebugger("doc-async.html", "async");
|
||||
|
@ -9,16 +9,16 @@ async function waitOnToolbox(toolbox, event) {
|
||||
return new Promise(resolve => toolbox.on(event, resolve));
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
add_task(async function() {
|
||||
const url = EXAMPLE_URL + "doc-script-switching.html";
|
||||
const toolbox = yield openNewTabAndToolbox(url, "webconsole");
|
||||
const toolbox = await openNewTabAndToolbox(url, "webconsole");
|
||||
|
||||
// Type "debugger" into console
|
||||
let jsterm = toolbox.getPanel("webconsole").hud.jsterm;
|
||||
jsterm.execute("debugger");
|
||||
|
||||
// Wait for the debugger to be selected and make sure it's paused
|
||||
yield waitOnToolbox(toolbox, "jsdebugger-selected");
|
||||
await waitOnToolbox(toolbox, "jsdebugger-selected");
|
||||
is(toolbox.threadClient.state, "paused");
|
||||
|
||||
// Create a dbg context
|
||||
@ -26,7 +26,7 @@ add_task(function*() {
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
|
||||
// Make sure the thread is paused in the right source and location
|
||||
yield waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
await waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
is(dbg.win.cm.getValue(), "debugger");
|
||||
const source = getSelectedSource(getState()).toJS();
|
||||
assertPausedLocation(dbg);
|
||||
|
@ -3,30 +3,30 @@
|
||||
|
||||
// Tests the breakpoints are hit in various situations.
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
|
||||
// Make sure we can set a top-level breakpoint and it will be hit on
|
||||
// reload.
|
||||
yield addBreakpoint(dbg, "scripts.html", 18);
|
||||
await addBreakpoint(dbg, "scripts.html", 18);
|
||||
reload(dbg);
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
yield resume(dbg);
|
||||
await resume(dbg);
|
||||
|
||||
const paused = waitForPaused(dbg);
|
||||
|
||||
// Create an eval script that pauses itself.
|
||||
invokeInTab("doEval");
|
||||
|
||||
yield paused;
|
||||
yield resume(dbg);
|
||||
await paused;
|
||||
await resume(dbg);
|
||||
const source = getSelectedSource(getState()).toJS();
|
||||
ok(!source.url, "It is an eval source");
|
||||
|
||||
yield addBreakpoint(dbg, source, 5);
|
||||
await addBreakpoint(dbg, source, 5);
|
||||
invokeInTab("evaledFunc");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
});
|
||||
|
@ -24,49 +24,47 @@ function assertEditorBreakpoint(dbg, line, shouldExist) {
|
||||
);
|
||||
}
|
||||
|
||||
function setConditionalBreakpoint(dbg, index, condition) {
|
||||
return Task.spawn(function*() {
|
||||
rightClickElement(dbg, "gutter", index);
|
||||
selectMenuItem(dbg, 2);
|
||||
yield waitForElement(dbg, ".conditional-breakpoint-panel input");
|
||||
findElementWithSelector(dbg, ".conditional-breakpoint-panel input").focus();
|
||||
// Position cursor reliably at the end of the text.
|
||||
pressKey(dbg, "End");
|
||||
type(dbg, condition);
|
||||
pressKey(dbg, "Enter");
|
||||
});
|
||||
async function setConditionalBreakpoint(dbg, index, condition) {
|
||||
rightClickElement(dbg, "gutter", index);
|
||||
selectMenuItem(dbg, 2);
|
||||
await waitForElement(dbg, ".conditional-breakpoint-panel input");
|
||||
findElementWithSelector(dbg, ".conditional-breakpoint-panel input").focus();
|
||||
// Position cursor reliably at the end of the text.
|
||||
pressKey(dbg, "End");
|
||||
type(dbg, condition);
|
||||
pressKey(dbg, "Enter");
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
yield selectSource(dbg, "simple2");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
await selectSource(dbg, "simple2");
|
||||
|
||||
// Adding a conditional Breakpoint
|
||||
yield setConditionalBreakpoint(dbg, 5, "1");
|
||||
yield waitForDispatch(dbg, "ADD_BREAKPOINT");
|
||||
await setConditionalBreakpoint(dbg, 5, "1");
|
||||
await waitForDispatch(dbg, "ADD_BREAKPOINT");
|
||||
let bp = findBreakpoint(dbg, "simple2", 5);
|
||||
is(bp.condition, "1", "breakpoint is created with the condition");
|
||||
assertEditorBreakpoint(dbg, 5, true);
|
||||
|
||||
// Editing a conditional Breakpoint
|
||||
yield setConditionalBreakpoint(dbg, 5, "2");
|
||||
yield waitForDispatch(dbg, "SET_BREAKPOINT_CONDITION");
|
||||
await setConditionalBreakpoint(dbg, 5, "2");
|
||||
await waitForDispatch(dbg, "SET_BREAKPOINT_CONDITION");
|
||||
bp = findBreakpoint(dbg, "simple2", 5);
|
||||
is(bp.condition, "12", "breakpoint is created with the condition");
|
||||
assertEditorBreakpoint(dbg, 5, true);
|
||||
|
||||
// Removing a conditional breakpoint
|
||||
clickElement(dbg, "gutter", 5);
|
||||
yield waitForDispatch(dbg, "REMOVE_BREAKPOINT");
|
||||
await waitForDispatch(dbg, "REMOVE_BREAKPOINT");
|
||||
bp = findBreakpoint(dbg, "simple2", 5);
|
||||
is(bp, null, "breakpoint was removed");
|
||||
assertEditorBreakpoint(dbg, 5, false);
|
||||
|
||||
// Adding a condition to a breakpoint
|
||||
clickElement(dbg, "gutter", 5);
|
||||
yield waitForDispatch(dbg, "ADD_BREAKPOINT");
|
||||
yield setConditionalBreakpoint(dbg, 5, "1");
|
||||
yield waitForDispatch(dbg, "SET_BREAKPOINT_CONDITION");
|
||||
await waitForDispatch(dbg, "ADD_BREAKPOINT");
|
||||
await setConditionalBreakpoint(dbg, 5, "1");
|
||||
await waitForDispatch(dbg, "SET_BREAKPOINT_CONDITION");
|
||||
|
||||
bp = findBreakpoint(dbg, "simple2", 5);
|
||||
is(bp.condition, "1", "breakpoint is created with the condition");
|
||||
|
@ -23,21 +23,21 @@ function assertEditorBreakpoint(dbg, line) {
|
||||
ok(exists, `Breakpoint exists on line ${line}`);
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
add_task(async function() {
|
||||
requestLongerTimeout(3);
|
||||
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const { selectors: { getBreakpoints, getBreakpoint }, getState } = dbg;
|
||||
const source = findSource(dbg, "simple1.js");
|
||||
|
||||
yield selectSource(dbg, source.url);
|
||||
yield addBreakpoint(dbg, 5);
|
||||
yield addBreakpoint(dbg, 4);
|
||||
await selectSource(dbg, source.url);
|
||||
await addBreakpoint(dbg, 5);
|
||||
await addBreakpoint(dbg, 4);
|
||||
|
||||
const syncedBps = waitForDispatch(dbg, "SYNC_BREAKPOINT", 2);
|
||||
yield reload(dbg, "simple1");
|
||||
yield waitForSelectedSource(dbg);
|
||||
yield syncedBps;
|
||||
await reload(dbg, "simple1");
|
||||
await waitForSelectedSource(dbg);
|
||||
await syncedBps;
|
||||
|
||||
assertEditorBreakpoint(dbg, 4);
|
||||
assertEditorBreakpoint(dbg, 5);
|
||||
|
@ -0,0 +1,87 @@
|
||||
function toggleBreakpoint(dbg, index) {
|
||||
const bp = findElement(dbg, "breakpointItem", index);
|
||||
const input = bp.querySelector("input");
|
||||
input.click();
|
||||
}
|
||||
|
||||
async function removeBreakpoint(dbg, index) {
|
||||
const removed = waitForDispatch(dbg, "REMOVE_BREAKPOINT");
|
||||
const bp = findElement(dbg, "breakpointItem", index);
|
||||
bp.querySelector(".close-btn").click();
|
||||
await removed;
|
||||
}
|
||||
|
||||
async function disableBreakpoint(dbg, index) {
|
||||
const disabled = waitForDispatch(dbg, "DISABLE_BREAKPOINT");
|
||||
toggleBreakpoint(dbg, index);
|
||||
await disabled;
|
||||
}
|
||||
|
||||
async function enableBreakpoint(dbg, index) {
|
||||
const enabled = waitForDispatch(dbg, "ENABLE_BREAKPOINT");
|
||||
toggleBreakpoint(dbg, index);
|
||||
await enabled;
|
||||
}
|
||||
|
||||
function toggleBreakpoints(dbg, count) {
|
||||
clickElement(dbg, "toggleBreakpoints");
|
||||
}
|
||||
|
||||
function disableBreakpoints(dbg, count) {
|
||||
const toggled = waitForDispatch(dbg, "DISABLE_BREAKPOINT", count);
|
||||
toggleBreakpoints(dbg);
|
||||
return toggled;
|
||||
}
|
||||
|
||||
function enableBreakpoints(dbg, count) {
|
||||
const enabled = waitForDispatch(dbg, "ENABLE_BREAKPOINT", count);
|
||||
toggleBreakpoints(dbg);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
function findBreakpoint(dbg, url, line) {
|
||||
const { selectors: { getBreakpoint }, getState } = dbg;
|
||||
const source = findSource(dbg, url);
|
||||
return getBreakpoint(getState(), { sourceId: source.id, line });
|
||||
}
|
||||
|
||||
function findBreakpoints(dbg) {
|
||||
const { selectors: { getBreakpoints }, getState } = dbg;
|
||||
return getBreakpoints(getState());
|
||||
}
|
||||
|
||||
// toggle all breakpoints
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html", "simple2");
|
||||
|
||||
// Create two breakpoints
|
||||
await selectSource(dbg, "simple2");
|
||||
await addBreakpoint(dbg, "simple2", 3);
|
||||
await addBreakpoint(dbg, "simple2", 5);
|
||||
|
||||
// Disable all of the breakpoints
|
||||
await disableBreakpoints(dbg, 2);
|
||||
let bp1 = findBreakpoint(dbg, "simple2", 3);
|
||||
let bp2 = findBreakpoint(dbg, "simple2", 5);
|
||||
|
||||
if (!bp2) {
|
||||
debugger;
|
||||
}
|
||||
|
||||
is(bp1.disabled, true, "first breakpoint is disabled");
|
||||
is(bp2.disabled, true, "second breakpoint is disabled");
|
||||
|
||||
// Enable all of the breakpoints
|
||||
await enableBreakpoints(dbg, 2);
|
||||
bp1 = findBreakpoint(dbg, "simple2", 3);
|
||||
bp2 = findBreakpoint(dbg, "simple2", 5);
|
||||
|
||||
is(bp1.disabled, false, "first breakpoint is enabled");
|
||||
is(bp2.disabled, false, "second breakpoint is enabled");
|
||||
|
||||
// Remove the breakpoints
|
||||
await removeBreakpoint(dbg, 1);
|
||||
await removeBreakpoint(dbg, 1);
|
||||
const bps = findBreakpoints(dbg);
|
||||
is(bps.size, 0, "breakpoints are removed");
|
||||
});
|
@ -7,26 +7,23 @@ function toggleBreakpoint(dbg, index) {
|
||||
input.click();
|
||||
}
|
||||
|
||||
function removeBreakpoint(dbg, index) {
|
||||
return Task.spawn(function*() {
|
||||
const bp = findElement(dbg, "breakpointItem", index);
|
||||
bp.querySelector(".close-btn").click();
|
||||
yield waitForDispatch(dbg, "REMOVE_BREAKPOINT");
|
||||
});
|
||||
async function removeBreakpoint(dbg, index) {
|
||||
const removed = waitForDispatch(dbg, "REMOVE_BREAKPOINT");
|
||||
const bp = findElement(dbg, "breakpointItem", index);
|
||||
bp.querySelector(".close-btn").click();
|
||||
await removed;
|
||||
}
|
||||
|
||||
function disableBreakpoint(dbg, index) {
|
||||
return Task.spawn(function*() {
|
||||
toggleBreakpoint(dbg, index);
|
||||
yield waitForDispatch(dbg, "DISABLE_BREAKPOINT");
|
||||
});
|
||||
async function disableBreakpoint(dbg, index) {
|
||||
const disabled = waitForDispatch(dbg, "DISABLE_BREAKPOINT");
|
||||
toggleBreakpoint(dbg, index);
|
||||
await disabled;
|
||||
}
|
||||
|
||||
function enableBreakpoint(dbg, index) {
|
||||
return Task.spawn(function*() {
|
||||
toggleBreakpoint(dbg, index);
|
||||
yield waitForDispatch(dbg, "ENABLE_BREAKPOINT");
|
||||
});
|
||||
async function enableBreakpoint(dbg, index) {
|
||||
const enabled = waitForDispatch(dbg, "ENABLE_BREAKPOINT");
|
||||
toggleBreakpoint(dbg, index);
|
||||
await enabled;
|
||||
}
|
||||
|
||||
function toggleBreakpoints(dbg, count) {
|
||||
@ -34,13 +31,15 @@ function toggleBreakpoints(dbg, count) {
|
||||
}
|
||||
|
||||
function disableBreakpoints(dbg, count) {
|
||||
const toggled = waitForDispatch(dbg, "DISABLE_BREAKPOINT", count);
|
||||
toggleBreakpoints(dbg);
|
||||
return waitForDispatch(dbg, "DISABLE_BREAKPOINT", count);
|
||||
return toggled;
|
||||
}
|
||||
|
||||
function enableBreakpoints(dbg, count) {
|
||||
const enabled = waitForDispatch(dbg, "ENABLE_BREAKPOINT", count);
|
||||
toggleBreakpoints(dbg);
|
||||
return waitForDispatch(dbg, "ENABLE_BREAKPOINT", count);
|
||||
return enabled;
|
||||
}
|
||||
|
||||
function findBreakpoint(dbg, url, line) {
|
||||
@ -54,54 +53,24 @@ function findBreakpoints(dbg) {
|
||||
return getBreakpoints(getState());
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
|
||||
// Create two breakpoints
|
||||
yield selectSource(dbg, "simple2");
|
||||
yield addBreakpoint(dbg, "simple2", 3);
|
||||
yield addBreakpoint(dbg, "simple2", 5);
|
||||
await selectSource(dbg, "simple2");
|
||||
await addBreakpoint(dbg, "simple2", 3);
|
||||
await addBreakpoint(dbg, "simple2", 5);
|
||||
|
||||
// Disable the first one
|
||||
yield disableBreakpoint(dbg, 1);
|
||||
await disableBreakpoint(dbg, 1);
|
||||
let bp1 = findBreakpoint(dbg, "simple2", 3);
|
||||
let bp2 = findBreakpoint(dbg, "simple2", 5);
|
||||
is(bp1.disabled, true, "first breakpoint is disabled");
|
||||
is(bp2.disabled, false, "second breakpoint is enabled");
|
||||
|
||||
// Disable and Re-Enable the second one
|
||||
yield disableBreakpoint(dbg, 2);
|
||||
yield enableBreakpoint(dbg, 2);
|
||||
await disableBreakpoint(dbg, 2);
|
||||
await enableBreakpoint(dbg, 2);
|
||||
bp2 = findBreakpoint(dbg, "simple2", 5);
|
||||
is(bp2.disabled, false, "second breakpoint is enabled");
|
||||
});
|
||||
|
||||
// toggle all
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
|
||||
// Create two breakpoints
|
||||
yield selectSource(dbg, "simple2");
|
||||
yield addBreakpoint(dbg, "simple2", 3);
|
||||
yield addBreakpoint(dbg, "simple2", 5);
|
||||
|
||||
// Disable all of the breakpoints
|
||||
yield disableBreakpoints(dbg, 2);
|
||||
let bp1 = findBreakpoint(dbg, "simple2", 3);
|
||||
let bp2 = findBreakpoint(dbg, "simple2", 5);
|
||||
is(bp1.disabled, true, "first breakpoint is disabled");
|
||||
is(bp2.disabled, true, "second breakpoint is disabled");
|
||||
|
||||
// Enable all of the breakpoints
|
||||
yield enableBreakpoints(dbg, 2);
|
||||
bp1 = findBreakpoint(dbg, "simple2", 3);
|
||||
bp2 = findBreakpoint(dbg, "simple2", 5);
|
||||
is(bp1.disabled, false, "first breakpoint is enabled");
|
||||
is(bp2.disabled, false, "second breakpoint is enabled");
|
||||
|
||||
// Remove the breakpoints
|
||||
yield removeBreakpoint(dbg, 1);
|
||||
yield removeBreakpoint(dbg, 1);
|
||||
const bps = findBreakpoints(dbg);
|
||||
is(bps.size, 0, "breakpoints are removed");
|
||||
});
|
||||
|
@ -17,8 +17,8 @@ function toggleButton(dbg) {
|
||||
return callStackBody.querySelector(".show-more");
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
const dbg = yield initDebugger("doc-script-switching.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-script-switching.html");
|
||||
|
||||
toggleCallStack(dbg);
|
||||
|
||||
@ -26,7 +26,7 @@ add_task(function* () {
|
||||
is(notPaused, "Not Paused", "Not paused message is shown");
|
||||
|
||||
invokeInTab("firstCall");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
|
||||
ok(isFrameSelected(dbg, 1, "secondCall"), "the first frame is selected");
|
||||
|
||||
@ -34,13 +34,13 @@ add_task(function* () {
|
||||
ok(!button, "toggle button shouldn't be there");
|
||||
});
|
||||
|
||||
add_task(function* () {
|
||||
const dbg = yield initDebugger("doc-frames.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-frames.html");
|
||||
|
||||
toggleCallStack(dbg);
|
||||
|
||||
invokeInTab("startRecursion");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
|
||||
ok(isFrameSelected(dbg, 1, "recurseA"), "the first frame is selected");
|
||||
|
||||
|
@ -42,12 +42,12 @@ registerCleanupFunction(function() {
|
||||
gProcess = null;
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
add_task(async function() {
|
||||
// Windows XP and 8.1 test slaves are terribly slow at this test.
|
||||
requestLongerTimeout(5);
|
||||
Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true);
|
||||
|
||||
gProcess = yield initChromeDebugger();
|
||||
gProcess = await initChromeDebugger();
|
||||
|
||||
ok(
|
||||
gProcess._dbgProcess,
|
||||
@ -81,5 +81,5 @@ add_task(function*() {
|
||||
|
||||
info("profile path: " + gProcess._dbgProfilePath);
|
||||
|
||||
yield gProcess.close();
|
||||
await gProcess.close();
|
||||
});
|
||||
|
@ -68,21 +68,21 @@ registerCleanupFunction(function() {
|
||||
DebuggerServer = null;
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
add_task(async function() {
|
||||
gClient = initDebuggerClient();
|
||||
|
||||
const [type] = yield gClient.connect();
|
||||
const [type] = await gClient.connect();
|
||||
is(type, "browser", "Root actor should identify itself as a browser.");
|
||||
|
||||
const response = yield gClient.getProcess();
|
||||
const response = await gClient.getProcess();
|
||||
let actor = response.form.actor;
|
||||
gThreadClient = yield attachThread(gClient, actor);
|
||||
gThreadClient = await attachThread(gClient, actor);
|
||||
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser, "about:mozilla");
|
||||
|
||||
// listen for a new source and global
|
||||
gThreadClient.addListener("newSource", onNewSource);
|
||||
gClient.addListener("newGlobal", onNewGlobal);
|
||||
yield promise.all([gNewGlobal.promise, gNewChromeSource.promise]);
|
||||
await promise.all([gNewGlobal.promise, gNewChromeSource.promise]);
|
||||
|
||||
yield resumeAndCloseConnection();
|
||||
await resumeAndCloseConnection();
|
||||
});
|
||||
|
@ -25,20 +25,21 @@ function getSplitConsole(dbg) {
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function* () {
|
||||
add_task(async function() {
|
||||
Services.prefs.setBoolPref("devtools.toolbox.splitconsoleEnabled", true);
|
||||
const dbg = yield initDebugger("doc-script-switching.html");
|
||||
const dbg = await initDebugger("doc-script-switching.html");
|
||||
|
||||
yield selectSource(dbg, "switching-01");
|
||||
await selectSource(dbg, "switching-01");
|
||||
|
||||
// open the console
|
||||
yield getSplitConsole(dbg);
|
||||
await getSplitConsole(dbg);
|
||||
ok(dbg.toolbox.splitConsole, "Split console is shown.");
|
||||
|
||||
// close the console
|
||||
clickElement(dbg, "codeMirror");
|
||||
await clickElement(dbg, "codeMirror");
|
||||
// First time to focus out of text area
|
||||
pressKey(dbg, "Escape");
|
||||
|
||||
// Second time to hide console
|
||||
pressKey(dbg, "Escape");
|
||||
ok(!dbg.toolbox.splitConsole, "Split console is hidden.");
|
||||
|
@ -24,31 +24,31 @@ function clickStepOut(dbg) {
|
||||
* 4. stepOver to the end of a function
|
||||
* 5. stepUp at the end of a function
|
||||
*/
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-debugger-statements.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-debugger-statements.html");
|
||||
|
||||
yield reload(dbg);
|
||||
yield waitForPaused(dbg);
|
||||
await reload(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
// resume
|
||||
clickElement(dbg, "resume");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
// step over
|
||||
yield clickStepOver(dbg);
|
||||
await clickStepOver(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
// step into
|
||||
yield clickStepIn(dbg);
|
||||
await clickStepIn(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
// step over
|
||||
yield clickStepOver(dbg);
|
||||
await clickStepOver(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
// step out
|
||||
yield clickStepOut(dbg);
|
||||
await clickStepOut(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
});
|
||||
|
@ -25,22 +25,22 @@ function assertEditorBreakpoint(dbg, line, shouldExist) {
|
||||
);
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const { selectors: { getBreakpoints, getBreakpoint }, getState } = dbg;
|
||||
const source = findSource(dbg, "simple1.js");
|
||||
|
||||
yield selectSource(dbg, source.url);
|
||||
await selectSource(dbg, source.url);
|
||||
|
||||
// Make sure that clicking the gutter creates a breakpoint icon.
|
||||
clickGutter(dbg, 4);
|
||||
yield waitForDispatch(dbg, "ADD_BREAKPOINT");
|
||||
await waitForDispatch(dbg, "ADD_BREAKPOINT");
|
||||
is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
|
||||
assertEditorBreakpoint(dbg, 4, true);
|
||||
|
||||
// Make sure clicking at the same place removes the icon.
|
||||
clickGutter(dbg, 4);
|
||||
yield waitForDispatch(dbg, "REMOVE_BREAKPOINT");
|
||||
await waitForDispatch(dbg, "REMOVE_BREAKPOINT");
|
||||
is(getBreakpoints(getState()).size, 0, "No breakpoints exist");
|
||||
assertEditorBreakpoint(dbg, 4, false);
|
||||
});
|
||||
|
@ -5,8 +5,8 @@
|
||||
// matter if the source text doesn't exist yet or even if the source
|
||||
// doesn't exist.
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const { selectors: { getSource }, getState } = dbg;
|
||||
const sourceUrl = EXAMPLE_URL + "long.js";
|
||||
|
||||
@ -17,19 +17,19 @@ add_task(function*() {
|
||||
|
||||
// Wait for the source text to load and make sure we're in the right
|
||||
// place.
|
||||
yield waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
await waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
|
||||
// TODO: revisit highlighting lines when the debugger opens
|
||||
//assertHighlightLocation(dbg, "long.js", 66);
|
||||
|
||||
// Jump to line 16 and make sure the editor scrolled.
|
||||
yield selectSource(dbg, "long.js", 16);
|
||||
await selectSource(dbg, "long.js", 16);
|
||||
assertHighlightLocation(dbg, "long.js", 16);
|
||||
|
||||
// Make sure only one line is ever highlighted and the flash
|
||||
// animation is cancelled on old lines.
|
||||
yield selectSource(dbg, "long.js", 17);
|
||||
yield selectSource(dbg, "long.js", 18);
|
||||
await selectSource(dbg, "long.js", 17);
|
||||
await selectSource(dbg, "long.js", 18);
|
||||
assertHighlightLocation(dbg, "long.js", 18);
|
||||
is(
|
||||
findAllElements(dbg, "highlightLine").length,
|
||||
@ -45,7 +45,7 @@ add_task(function*() {
|
||||
// fully loaded, and check the highlighted line.
|
||||
const simple1 = findSource(dbg, "simple1.js");
|
||||
ok(getSource(getState(), simple1.id).get("loadedState"));
|
||||
yield waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
await waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
ok(getSource(getState(), simple1.id).get("text"));
|
||||
assertHighlightLocation(dbg, "simple1.js", 6);
|
||||
});
|
||||
|
@ -3,12 +3,12 @@
|
||||
|
||||
// Tests that the editor sets the correct mode for different file
|
||||
// types
|
||||
add_task(function* () {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
|
||||
yield selectSource(dbg, "simple1.js");
|
||||
await selectSource(dbg, "simple1.js");
|
||||
is(dbg.win.cm.getOption("mode").name, "javascript", "Mode is correct");
|
||||
|
||||
yield selectSource(dbg, "doc-scripts.html");
|
||||
await selectSource(dbg, "doc-scripts.html");
|
||||
is(dbg.win.cm.getOption("mode").name, "htmlmixed", "Mode is correct");
|
||||
});
|
||||
|
@ -11,44 +11,44 @@ function isElementVisible(dbg, elementName) {
|
||||
return bpLine && isVisibleWithin(cm, bpLine);
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
add_task(async function() {
|
||||
// This test runs too slowly on linux debug. I'd like to figure out
|
||||
// which is the slowest part of this and make it run faster, but to
|
||||
// fix a frequent failure allow a longer timeout.
|
||||
requestLongerTimeout(2);
|
||||
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
const simple1 = findSource(dbg, "simple1.js");
|
||||
const simple2 = findSource(dbg, "simple2.js");
|
||||
|
||||
// Set the initial breakpoint.
|
||||
yield addBreakpoint(dbg, simple1, 4);
|
||||
await addBreakpoint(dbg, simple1, 4);
|
||||
ok(!getSelectedSource(getState()), "No selected source");
|
||||
|
||||
// Call the function that we set a breakpoint in.
|
||||
invokeInTab("main");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
// Step through to another file and make sure it's paused in the
|
||||
// right place.
|
||||
yield stepIn(dbg);
|
||||
await stepIn(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
// Step back out to the initial file.
|
||||
yield stepOut(dbg);
|
||||
yield stepOut(dbg);
|
||||
await stepOut(dbg);
|
||||
await stepOut(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
yield resume(dbg);
|
||||
await resume(dbg);
|
||||
|
||||
// Make sure that we can set a breakpoint on a line out of the
|
||||
// viewport, and that pausing there scrolls the editor to it.
|
||||
let longSrc = findSource(dbg, "long.js");
|
||||
yield addBreakpoint(dbg, longSrc, 66);
|
||||
await addBreakpoint(dbg, longSrc, 66);
|
||||
|
||||
invokeInTab("testModel");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
ok(isElementVisible(dbg, "breakpoint"), "Breakpoint is visible");
|
||||
});
|
||||
|
@ -53,32 +53,32 @@ async function editExpression(dbg, input) {
|
||||
await waitForDispatch(dbg, "EVALUATE_EXPRESSION");
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-script-switching.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-script-switching.html");
|
||||
|
||||
invokeInTab("firstCall");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
|
||||
yield addExpression(dbg, "f");
|
||||
await addExpression(dbg, "f");
|
||||
is(getLabel(dbg, 1), "f");
|
||||
is(getValue(dbg, 1), "(unavailable)");
|
||||
|
||||
yield editExpression(dbg, "oo");
|
||||
await editExpression(dbg, "oo");
|
||||
is(getLabel(dbg, 1), "foo()");
|
||||
|
||||
// There is no "value" element for functions.
|
||||
assertEmptyValue(dbg, 1);
|
||||
|
||||
yield addExpression(dbg, "location");
|
||||
await addExpression(dbg, "location");
|
||||
is(getLabel(dbg, 2), "location");
|
||||
ok(getValue(dbg, 2).includes("Location"), "has a value");
|
||||
|
||||
// can expand an expression
|
||||
toggleExpression(dbg, 2);
|
||||
yield waitForDispatch(dbg, "LOAD_OBJECT_PROPERTIES");
|
||||
await waitForDispatch(dbg, "LOAD_OBJECT_PROPERTIES");
|
||||
|
||||
yield deleteExpression(dbg, "foo");
|
||||
yield deleteExpression(dbg, "location");
|
||||
await deleteExpression(dbg, "foo");
|
||||
await deleteExpression(dbg, "location");
|
||||
|
||||
is(findAllElements(dbg, "expressionNodes").length, 0);
|
||||
});
|
||||
|
@ -6,21 +6,21 @@
|
||||
* 1. pause in the main thread
|
||||
* 2. pause in the iframe
|
||||
*/
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-iframes.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-iframes.html");
|
||||
|
||||
// test pausing in the main thread
|
||||
yield reload(dbg);
|
||||
yield waitForPaused(dbg);
|
||||
await reload(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
// test pausing in the iframe
|
||||
yield resume(dbg);
|
||||
yield waitForPaused(dbg);
|
||||
await resume(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
// test pausing in the iframe
|
||||
yield resume(dbg);
|
||||
yield waitForPaused(dbg);
|
||||
await resume(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
});
|
||||
|
@ -10,26 +10,26 @@ function countSources(dbg) {
|
||||
* Test navigating
|
||||
* navigating while paused will reset the pause state and sources
|
||||
*/
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-script-switching.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-script-switching.html");
|
||||
const { selectors: { getSelectedSource, getPause }, getState } = dbg;
|
||||
|
||||
invokeInTab("firstCall");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
|
||||
yield navigate(dbg, "doc-scripts.html", "simple1.js");
|
||||
yield addBreakpoint(dbg, "simple1.js", 4);
|
||||
await navigate(dbg, "doc-scripts.html", "simple1.js");
|
||||
await addBreakpoint(dbg, "simple1.js", 4);
|
||||
invokeInTab("main");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
is(countSources(dbg), 4, "4 sources are loaded.");
|
||||
|
||||
yield navigate(dbg, "about:blank");
|
||||
yield waitForDispatch(dbg, "NAVIGATE");
|
||||
await navigate(dbg, "about:blank");
|
||||
await waitForDispatch(dbg, "NAVIGATE");
|
||||
is(countSources(dbg), 0, "0 sources are loaded.");
|
||||
ok(!getPause(getState()), "No pause state exists");
|
||||
|
||||
yield navigate(
|
||||
await navigate(
|
||||
dbg,
|
||||
"doc-scripts.html",
|
||||
"simple1.js",
|
||||
@ -41,10 +41,12 @@ add_task(function*() {
|
||||
is(countSources(dbg), 4, "4 sources are loaded.");
|
||||
|
||||
// Test that the current select source persists across reloads
|
||||
yield selectSource(dbg, "long.js");
|
||||
yield reload(dbg, "long.js");
|
||||
await selectSource(dbg, "long.js");
|
||||
await reload(dbg, "long.js");
|
||||
ok(
|
||||
getSelectedSource(getState()).get("url").includes("long.js"),
|
||||
getSelectedSource(getState())
|
||||
.get("url")
|
||||
.includes("long.js"),
|
||||
"Selected source is long.js"
|
||||
);
|
||||
});
|
||||
|
@ -16,30 +16,30 @@ function caughtException() {
|
||||
3. pause on a caught error
|
||||
4. skip a caught error
|
||||
*/
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-exceptions.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-exceptions.html");
|
||||
|
||||
// test skipping an uncaught exception
|
||||
yield uncaughtException();
|
||||
await uncaughtException();
|
||||
ok(!isPaused(dbg));
|
||||
|
||||
// Test pausing on an uncaught exception
|
||||
yield togglePauseOnExceptions(dbg, true, false);
|
||||
await togglePauseOnExceptions(dbg, true, false);
|
||||
uncaughtException();
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
yield resume(dbg);
|
||||
await resume(dbg);
|
||||
|
||||
// Test pausing on a caught Error
|
||||
caughtException();
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
yield resume(dbg);
|
||||
await resume(dbg);
|
||||
|
||||
// Test skipping a caught error
|
||||
yield togglePauseOnExceptions(dbg, true, true);
|
||||
await togglePauseOnExceptions(dbg, true, true);
|
||||
caughtException();
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
yield resume(dbg);
|
||||
await resume(dbg);
|
||||
});
|
||||
|
@ -3,21 +3,21 @@
|
||||
|
||||
// Tests pretty-printing a source that is currently paused.
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-minified.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-minified.html");
|
||||
|
||||
yield selectSource(dbg, "math.min.js");
|
||||
yield addBreakpoint(dbg, "math.min.js", 2);
|
||||
await selectSource(dbg, "math.min.js");
|
||||
await addBreakpoint(dbg, "math.min.js", 2);
|
||||
|
||||
invokeInTab("arithmetic");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
clickElement(dbg, "prettyPrintButton");
|
||||
yield waitForDispatch(dbg, "SELECT_SOURCE");
|
||||
await waitForDispatch(dbg, "SELECT_SOURCE");
|
||||
|
||||
// this doesnt work yet
|
||||
// assertPausedLocation(dbg);
|
||||
|
||||
yield resume(dbg);
|
||||
await resume(dbg);
|
||||
});
|
||||
|
@ -3,13 +3,13 @@
|
||||
|
||||
// Tests basic pretty-printing functionality.
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-minified.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-minified.html");
|
||||
|
||||
yield selectSource(dbg, "math.min.js", 2);
|
||||
await selectSource(dbg, "math.min.js", 2);
|
||||
clickElement(dbg, "prettyPrintButton");
|
||||
|
||||
yield waitForSource(dbg, "math.min.js:formatted");
|
||||
await waitForSource(dbg, "math.min.js:formatted");
|
||||
const ppSrc = findSource(dbg, "math.min.js:formatted");
|
||||
|
||||
ok(ppSrc, "Pretty-printed source exists");
|
||||
@ -17,19 +17,19 @@ add_task(function*() {
|
||||
// this is not implemented yet
|
||||
// assertHighlightLocation(dbg, "math.min.js:formatted", 18);
|
||||
|
||||
yield addBreakpoint(dbg, ppSrc, 18);
|
||||
await addBreakpoint(dbg, ppSrc, 18);
|
||||
|
||||
invokeInTab("arithmetic");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
yield stepOver(dbg);
|
||||
await stepOver(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
yield resume(dbg);
|
||||
await resume(dbg);
|
||||
|
||||
// The pretty-print button should go away in the pretty-printed
|
||||
// source.
|
||||
ok(!findElement(dbg, "editorFooter"), "Footer is hidden");
|
||||
|
||||
yield selectSource(dbg, "math.min.js");
|
||||
await selectSource(dbg, "math.min.js");
|
||||
ok(findElement(dbg, "editorFooter"), "Footer is hidden");
|
||||
});
|
||||
|
@ -23,14 +23,14 @@ function onLoadObjectProperties(dbg) {
|
||||
return waitForDispatch(dbg, "LOAD_OBJECT_PROPERTIES");
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-script-mutate.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-script-mutate.html");
|
||||
|
||||
toggleScopes(dbg);
|
||||
|
||||
let onPaused = waitForPaused(dbg);
|
||||
invokeInTab("mutate");
|
||||
yield onPaused;
|
||||
await onPaused;
|
||||
|
||||
is(
|
||||
getScopeNodeLabel(dbg, 2),
|
||||
@ -44,7 +44,7 @@ add_task(function*() {
|
||||
);
|
||||
|
||||
info("Expand `phonebook`");
|
||||
yield expandNode(dbg, 3);
|
||||
await expandNode(dbg, 3);
|
||||
is(
|
||||
getScopeNodeLabel(dbg, 4),
|
||||
"S",
|
||||
@ -52,7 +52,7 @@ add_task(function*() {
|
||||
);
|
||||
|
||||
info("Expand `S`");
|
||||
yield expandNode(dbg, 4);
|
||||
await expandNode(dbg, 4);
|
||||
is(
|
||||
getScopeNodeLabel(dbg, 5),
|
||||
"sarah",
|
||||
@ -65,7 +65,7 @@ add_task(function*() {
|
||||
);
|
||||
|
||||
info("Expand `sarah`");
|
||||
yield expandNode(dbg, 5);
|
||||
await expandNode(dbg, 5);
|
||||
is(
|
||||
getScopeNodeLabel(dbg, 6),
|
||||
"lastName",
|
||||
@ -79,8 +79,8 @@ add_task(function*() {
|
||||
|
||||
info("Resuming");
|
||||
onPaused = waitForPaused(dbg);
|
||||
yield resume(dbg);
|
||||
yield onPaused;
|
||||
await resume(dbg);
|
||||
await onPaused;
|
||||
|
||||
is(
|
||||
getScopeNodeLabel(dbg, 2),
|
||||
|
@ -9,23 +9,23 @@ function getLabel(dbg, index) {
|
||||
return findElement(dbg, "scopeNode", index).innerText;
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-script-switching.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-script-switching.html");
|
||||
|
||||
toggleScopes(dbg);
|
||||
|
||||
invokeInTab("firstCall");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
|
||||
is(getLabel(dbg, 1), "secondCall");
|
||||
is(getLabel(dbg, 2), "<this>");
|
||||
is(getLabel(dbg, 4), "foo()");
|
||||
|
||||
toggleNode(dbg, 4);
|
||||
yield waitForDispatch(dbg, "LOAD_OBJECT_PROPERTIES");
|
||||
await waitForDispatch(dbg, "LOAD_OBJECT_PROPERTIES");
|
||||
is(getLabel(dbg, 5), "arguments");
|
||||
|
||||
yield stepOver(dbg);
|
||||
await stepOver(dbg);
|
||||
is(getLabel(dbg, 4), "foo()");
|
||||
is(getLabel(dbg, 5), "Window");
|
||||
});
|
||||
|
@ -12,30 +12,30 @@ function getFocusedEl(dbg) {
|
||||
return doc.activeElement;
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
const {
|
||||
selectors: { getBreakpoints, getBreakpoint, getActiveSearch },
|
||||
getState
|
||||
} = dbg;
|
||||
const source = findSource(dbg, "simple1.js");
|
||||
|
||||
yield selectSource(dbg, source.url);
|
||||
await selectSource(dbg, source.url);
|
||||
|
||||
const cm = getCM(dbg);
|
||||
pressKey(dbg, "fileSearch");
|
||||
is(dbg.selectors.getActiveSearchState(dbg.getState()), "file");
|
||||
is(dbg.selectors.getActiveSearch(dbg.getState()), "file");
|
||||
|
||||
// test closing and re-opening
|
||||
pressKey(dbg, "Escape");
|
||||
is(dbg.selectors.getActiveSearchState(dbg.getState()), null);
|
||||
is(dbg.selectors.getActiveSearch(dbg.getState()), null);
|
||||
|
||||
pressKey(dbg, "fileSearch");
|
||||
|
||||
const el = getFocusedEl(dbg);
|
||||
|
||||
type(dbg, "con");
|
||||
yield waitForSearchState(dbg);
|
||||
await waitForSearchState(dbg);
|
||||
|
||||
const state = cm.state.search;
|
||||
|
||||
@ -55,7 +55,7 @@ add_task(function*() {
|
||||
is(state.posFrom.line, 4);
|
||||
|
||||
// selecting another source keeps search open
|
||||
yield selectSource(dbg, "simple2");
|
||||
await selectSource(dbg, "simple2");
|
||||
pressKey(dbg, "Enter");
|
||||
is(state.posFrom.line, 0);
|
||||
});
|
||||
|
@ -5,23 +5,21 @@ function openProjectSearch(dbg) {
|
||||
synthesizeKeyShortcut("CmdOrCtrl+Shift+F");
|
||||
return waitForState(
|
||||
dbg,
|
||||
state => dbg.selectors.getActiveSearchState(state) === "project"
|
||||
state => dbg.selectors.getActiveSearch(state) === "project"
|
||||
);
|
||||
}
|
||||
|
||||
function closeProjectSearch(dbg) {
|
||||
pressKey(dbg, "Escape");
|
||||
return waitForState(dbg, state => !dbg.selectors.getActiveSearchState(state));
|
||||
}
|
||||
|
||||
function getResult(dbg) {
|
||||
return findElementWithSelector(dbg, ".managed-tree .result");
|
||||
return waitForState(dbg, state => !dbg.selectors.getActiveSearch(state));
|
||||
}
|
||||
|
||||
async function selectResult(dbg) {
|
||||
const item = getResult(dbg);
|
||||
const select = waitForDispatch(dbg, "SELECT_SOURCE");
|
||||
item.click();
|
||||
const select = waitForState(
|
||||
dbg,
|
||||
() => !dbg.selectors.getActiveSearch(dbg.getState())
|
||||
);
|
||||
await clickElement(dbg, "fileMatch");
|
||||
return select;
|
||||
}
|
||||
|
||||
@ -36,28 +34,29 @@ function getResultsCount(dbg) {
|
||||
}
|
||||
|
||||
// Testing project search
|
||||
add_task(function*() {
|
||||
add_task(async function() {
|
||||
Services.prefs.setBoolPref(
|
||||
"devtools.debugger.project-text-search-enabled",
|
||||
true
|
||||
);
|
||||
|
||||
const dbg = yield initDebugger("doc-script-switching.html", "switching-01");
|
||||
const dbg = await initDebugger("doc-script-switching.html", "switching-01");
|
||||
|
||||
yield selectSource(dbg, "switching-01");
|
||||
await selectSource(dbg, "switching-01");
|
||||
|
||||
// test opening and closing
|
||||
yield openProjectSearch(dbg);
|
||||
yield closeProjectSearch(dbg);
|
||||
await openProjectSearch(dbg);
|
||||
await closeProjectSearch(dbg);
|
||||
|
||||
yield openProjectSearch(dbg);
|
||||
await openProjectSearch(dbg);
|
||||
type(dbg, "first");
|
||||
pressKey(dbg, "Enter");
|
||||
|
||||
yield waitForState(dbg, () => getResultsCount(dbg) === 1);
|
||||
await waitForState(dbg, () => getResultsCount(dbg) === 1);
|
||||
|
||||
yield selectResult(dbg);
|
||||
is(dbg.selectors.getActiveSearchState(dbg.getState()), null);
|
||||
await selectResult(dbg);
|
||||
|
||||
is(dbg.selectors.getActiveSearch(dbg.getState()), null);
|
||||
|
||||
const selectedSource = dbg.selectors.getSelectedSource(dbg.getState());
|
||||
ok(selectedSource.get("url").includes("switching-01"));
|
||||
|
@ -2,22 +2,22 @@
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Testing source search
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-script-switching.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-script-switching.html");
|
||||
|
||||
// test opening and closing
|
||||
pressKey(dbg, "sourceSearch");
|
||||
is(dbg.selectors.getActiveSearchState(dbg.getState()), "source");
|
||||
is(dbg.selectors.getActiveSearch(dbg.getState()), "source");
|
||||
pressKey(dbg, "Escape");
|
||||
is(dbg.selectors.getActiveSearchState(dbg.getState()), null);
|
||||
is(dbg.selectors.getActiveSearch(dbg.getState()), null);
|
||||
|
||||
pressKey(dbg, "sourceSearch");
|
||||
yield waitForElement(dbg, "input");
|
||||
await waitForElement(dbg, "input");
|
||||
findElementWithSelector(dbg, "input").focus();
|
||||
type(dbg, "sw");
|
||||
pressKey(dbg, "Enter");
|
||||
|
||||
yield waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
await waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
let source = dbg.selectors.getSelectedSource(dbg.getState());
|
||||
ok(source.get("url").match(/switching-01/), "first source is selected");
|
||||
|
||||
@ -28,7 +28,7 @@ add_task(function*() {
|
||||
pressKey(dbg, "Down");
|
||||
pressKey(dbg, "Enter");
|
||||
|
||||
yield waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
await waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
source = dbg.selectors.getSelectedSource(dbg.getState());
|
||||
ok(source.get("url").match(/switching-02/), "second source is selected");
|
||||
});
|
||||
|
@ -11,18 +11,18 @@ function resultCount(dbg) {
|
||||
}
|
||||
|
||||
// Testing function search
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-script-switching.html", "switching-01");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-script-switching.html", "switching-01");
|
||||
|
||||
yield selectSource(dbg, "switching-01");
|
||||
await selectSource(dbg, "switching-01");
|
||||
|
||||
// test opening and closing
|
||||
yield openFunctionSearch(dbg);
|
||||
is(dbg.selectors.getActiveSearchState(dbg.getState()), "symbol");
|
||||
await openFunctionSearch(dbg);
|
||||
is(dbg.selectors.getActiveSearch(dbg.getState()), "symbol");
|
||||
pressKey(dbg, "Escape");
|
||||
is(dbg.selectors.getActiveSearchState(dbg.getState()), null);
|
||||
is(dbg.selectors.getActiveSearch(dbg.getState()), null);
|
||||
|
||||
yield openFunctionSearch(dbg);
|
||||
await openFunctionSearch(dbg);
|
||||
is(resultCount(dbg), 1);
|
||||
|
||||
type(dbg, "x");
|
||||
|
@ -4,20 +4,20 @@
|
||||
// Test that an error while loading a sourcemap does not break
|
||||
// debugging.
|
||||
|
||||
add_task(function*() {
|
||||
add_task(async function() {
|
||||
// NOTE: the CORS call makes the test run times inconsistent
|
||||
requestLongerTimeout(2);
|
||||
|
||||
const dbg = yield initDebugger("doc-sourcemap-bogus.html");
|
||||
const dbg = await initDebugger("doc-sourcemap-bogus.html");
|
||||
const { selectors: { getSources }, getState } = dbg;
|
||||
|
||||
yield selectSource(dbg, "bogus-map.js");
|
||||
await selectSource(dbg, "bogus-map.js");
|
||||
|
||||
// We should still be able to set breakpoints and pause in the
|
||||
// generated source.
|
||||
yield addBreakpoint(dbg, "bogus-map.js", 4);
|
||||
await addBreakpoint(dbg, "bogus-map.js", 4);
|
||||
invokeInTab("runCode");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
// Make sure that only the single generated source exists. The
|
||||
|
@ -1,18 +1,18 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
add_task(function*() {
|
||||
add_task(async function() {
|
||||
// NOTE: the CORS call makes the test run times inconsistent
|
||||
requestLongerTimeout(2);
|
||||
|
||||
const dbg = yield initDebugger("doc-sourcemaps.html");
|
||||
const dbg = await initDebugger("doc-sourcemaps.html");
|
||||
const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
|
||||
|
||||
yield waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
|
||||
await waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
|
||||
ok(true, "Original sources exist");
|
||||
const entrySrc = findSource(dbg, "entry.js");
|
||||
|
||||
yield selectSource(dbg, entrySrc);
|
||||
await selectSource(dbg, entrySrc);
|
||||
ok(
|
||||
dbg.win.cm.getValue().includes("window.keepMeAlive"),
|
||||
"Original source text loaded correctly"
|
||||
@ -20,19 +20,19 @@ add_task(function*() {
|
||||
|
||||
// Test that breakpoint sliding is not attempted. The breakpoint
|
||||
// should not move anywhere.
|
||||
yield addBreakpoint(dbg, entrySrc, 13);
|
||||
await addBreakpoint(dbg, entrySrc, 13);
|
||||
is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
|
||||
ok(
|
||||
getBreakpoint(getState(), { sourceId: entrySrc.id, line: 13 }),
|
||||
"Breakpoint has correct line"
|
||||
);
|
||||
|
||||
yield addBreakpoint(dbg, entrySrc, 15);
|
||||
yield disableBreakpoint(dbg, entrySrc, 15);
|
||||
await addBreakpoint(dbg, entrySrc, 15);
|
||||
await disableBreakpoint(dbg, entrySrc, 15);
|
||||
|
||||
// Test reloading the debugger
|
||||
yield reload(dbg, "opts.js");
|
||||
yield waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
await reload(dbg, "opts.js");
|
||||
await waitForDispatch(dbg, "LOAD_SOURCE_TEXT");
|
||||
|
||||
is(getBreakpoints(getState()).size, 2, "One breakpoint exists");
|
||||
|
||||
|
@ -33,30 +33,30 @@ function clickGutter(dbg, line) {
|
||||
clickElement(dbg, "gutter", line);
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
add_task(async function() {
|
||||
// NOTE: the CORS call makes the test run times inconsistent
|
||||
requestLongerTimeout(2);
|
||||
|
||||
const dbg = yield initDebugger("doc-sourcemaps.html");
|
||||
const dbg = await initDebugger("doc-sourcemaps.html");
|
||||
const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
|
||||
|
||||
yield waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
|
||||
await waitForSources(dbg, "entry.js", "output.js", "times2.js", "opts.js");
|
||||
ok(true, "Original sources exist");
|
||||
const bundleSrc = findSource(dbg, "bundle.js");
|
||||
|
||||
yield selectSource(dbg, bundleSrc);
|
||||
await selectSource(dbg, bundleSrc);
|
||||
|
||||
yield clickGutter(dbg, 13);
|
||||
yield waitForDispatch(dbg, "ADD_BREAKPOINT");
|
||||
await clickGutter(dbg, 13);
|
||||
await waitForDispatch(dbg, "ADD_BREAKPOINT");
|
||||
assertEditorBreakpoint(dbg, 13, true);
|
||||
|
||||
yield clickGutter(dbg, 13);
|
||||
yield waitForDispatch(dbg, "REMOVE_BREAKPOINT");
|
||||
await clickGutter(dbg, 13);
|
||||
await waitForDispatch(dbg, "REMOVE_BREAKPOINT");
|
||||
is(getBreakpoints(getState()).size, 0, "No breakpoints exists");
|
||||
|
||||
const entrySrc = findSource(dbg, "entry.js");
|
||||
|
||||
yield selectSource(dbg, entrySrc);
|
||||
await selectSource(dbg, entrySrc);
|
||||
ok(
|
||||
dbg.win.cm.getValue().includes("window.keepMeAlive"),
|
||||
"Original source text loaded correctly"
|
||||
@ -64,25 +64,25 @@ add_task(function*() {
|
||||
|
||||
// Test that breakpoint sliding is not attempted. The breakpoint
|
||||
// should not move anywhere.
|
||||
yield addBreakpoint(dbg, entrySrc, 13);
|
||||
await addBreakpoint(dbg, entrySrc, 13);
|
||||
is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
|
||||
assertBreakpointExists(dbg, entrySrc, 13);
|
||||
|
||||
// Test breaking on a breakpoint
|
||||
yield addBreakpoint(dbg, "entry.js", 15);
|
||||
await addBreakpoint(dbg, "entry.js", 15);
|
||||
is(getBreakpoints(getState()).size, 2, "Two breakpoints exist");
|
||||
assertBreakpointExists(dbg, entrySrc, 15);
|
||||
|
||||
invokeInTab("keepMeAlive");
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
yield stepIn(dbg);
|
||||
await stepIn(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
yield stepOver(dbg);
|
||||
await stepOver(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
yield stepOut(dbg);
|
||||
yield stepOut(dbg);
|
||||
await stepOut(dbg);
|
||||
await stepOut(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
});
|
||||
|
@ -6,22 +6,22 @@
|
||||
|
||||
// This source map does not have source contents, so it's fetched separately
|
||||
|
||||
add_task(function*() {
|
||||
add_task(async function() {
|
||||
// NOTE: the CORS call makes the test run times inconsistent
|
||||
requestLongerTimeout(2);
|
||||
|
||||
const dbg = yield initDebugger("doc-sourcemaps2.html");
|
||||
const dbg = await initDebugger("doc-sourcemaps2.html");
|
||||
const { selectors: { getBreakpoint, getBreakpoints }, getState } = dbg;
|
||||
|
||||
yield waitForSources(dbg, "main.js", "main.min.js");
|
||||
await waitForSources(dbg, "main.js", "main.min.js");
|
||||
|
||||
ok(true, "Original sources exist");
|
||||
const mainSrc = findSource(dbg, "main.js");
|
||||
|
||||
yield selectSource(dbg, mainSrc);
|
||||
await selectSource(dbg, mainSrc);
|
||||
|
||||
// Test that breakpoint is not off by a line.
|
||||
yield addBreakpoint(dbg, mainSrc, 4);
|
||||
await addBreakpoint(dbg, mainSrc, 4);
|
||||
is(getBreakpoints(getState()).size, 1, "One breakpoint exists");
|
||||
ok(
|
||||
getBreakpoint(getState(), { sourceId: mainSrc.id, line: 4, column: 2 }),
|
||||
@ -30,6 +30,6 @@ add_task(function*() {
|
||||
|
||||
invokeInTab("logMessage");
|
||||
|
||||
yield waitForPaused(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
});
|
||||
|
@ -3,27 +3,27 @@
|
||||
|
||||
// Tests that the source tree works.
|
||||
|
||||
function* waitForSourceCount(dbg, i) {
|
||||
async function waitForSourceCount(dbg, i) {
|
||||
// We are forced to wait until the DOM nodes appear because the
|
||||
// source tree batches its rendering.
|
||||
yield waitUntil(() => {
|
||||
await waitUntil(() => {
|
||||
return findAllElements(dbg, "sourceNodes").length === i;
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-sources.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-sources.html");
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
|
||||
yield waitForSources(dbg, "simple1", "simple2", "nested-source", "long.js");
|
||||
await waitForSources(dbg, "simple1", "simple2", "nested-source", "long.js");
|
||||
|
||||
// Expand nodes and make sure more sources appear.
|
||||
is(findAllElements(dbg, "sourceNodes").length, 2);
|
||||
|
||||
clickElement(dbg, "sourceArrow", 2);
|
||||
await clickElement(dbg, "sourceArrow", 2);
|
||||
is(findAllElements(dbg, "sourceNodes").length, 7);
|
||||
|
||||
clickElement(dbg, "sourceArrow", 3);
|
||||
await clickElement(dbg, "sourceArrow", 3);
|
||||
is(findAllElements(dbg, "sourceNodes").length, 8);
|
||||
|
||||
// Select a source.
|
||||
@ -32,14 +32,16 @@ add_task(function*() {
|
||||
"Source is not focused"
|
||||
);
|
||||
const selected = waitForDispatch(dbg, "SELECT_SOURCE");
|
||||
clickElement(dbg, "sourceNode", 4);
|
||||
yield selected;
|
||||
await clickElement(dbg, "sourceNode", 4);
|
||||
await selected;
|
||||
ok(
|
||||
findElementWithSelector(dbg, ".sources-list .focused"),
|
||||
"Source is focused"
|
||||
);
|
||||
ok(
|
||||
getSelectedSource(getState()).get("url").includes("nested-source.js"),
|
||||
getSelectedSource(getState())
|
||||
.get("url")
|
||||
.includes("nested-source.js"),
|
||||
"The right source is selected"
|
||||
);
|
||||
|
||||
@ -50,7 +52,7 @@ add_task(function*() {
|
||||
content.document.body.appendChild(script);
|
||||
});
|
||||
|
||||
yield waitForSourceCount(dbg, 9);
|
||||
await waitForSourceCount(dbg, 9);
|
||||
is(
|
||||
findElement(dbg, "sourceNode", 7).textContent,
|
||||
"math.min.js",
|
||||
@ -60,16 +62,16 @@ add_task(function*() {
|
||||
// Make sure named eval sources appear in the list.
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-sources.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-sources.html");
|
||||
const { selectors: { getSelectedSource }, getState } = dbg;
|
||||
|
||||
yield waitForSources(dbg, "simple1", "simple2", "nested-source", "long.js");
|
||||
await waitForSources(dbg, "simple1", "simple2", "nested-source", "long.js");
|
||||
|
||||
ContentTask.spawn(gBrowser.selectedBrowser, null, function() {
|
||||
content.eval("window.evaledFunc = function() {} //# sourceURL=evaled.js");
|
||||
});
|
||||
yield waitForSourceCount(dbg, 3);
|
||||
await waitForSourceCount(dbg, 3);
|
||||
is(
|
||||
findElement(dbg, "sourceNode", 3).textContent,
|
||||
"(no domain)",
|
||||
@ -78,8 +80,8 @@ add_task(function*() {
|
||||
|
||||
// work around: the folder is rendered at the bottom, so we close the
|
||||
// root folder and open the (no domain) folder
|
||||
clickElement(dbg, "sourceArrow", 3);
|
||||
yield waitForSourceCount(dbg, 4);
|
||||
await clickElement(dbg, "sourceArrow", 3);
|
||||
await waitForSourceCount(dbg, 4);
|
||||
|
||||
is(
|
||||
findElement(dbg, "sourceNode", 4).textContent,
|
||||
|
@ -7,33 +7,33 @@ function countTabs(dbg) {
|
||||
return findElement(dbg, "sourceTabs").children.length;
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
let dbg = yield initDebugger("doc-scripts.html");
|
||||
add_task(async function() {
|
||||
let dbg = await initDebugger("doc-scripts.html");
|
||||
|
||||
yield selectSource(dbg, "simple1");
|
||||
yield selectSource(dbg, "simple2");
|
||||
await selectSource(dbg, "simple1");
|
||||
await selectSource(dbg, "simple2");
|
||||
is(countTabs(dbg), 2);
|
||||
|
||||
// Test reloading the debugger
|
||||
yield reload(dbg, "simple1", "simple2");
|
||||
await reload(dbg, "simple1", "simple2");
|
||||
is(countTabs(dbg), 2);
|
||||
yield waitForSelectedSource(dbg);
|
||||
await waitForSelectedSource(dbg);
|
||||
|
||||
// Test reloading the debuggee a second time
|
||||
yield reload(dbg, "simple1", "simple2");
|
||||
await reload(dbg, "simple1", "simple2");
|
||||
is(countTabs(dbg), 2);
|
||||
yield waitForSelectedSource(dbg);
|
||||
await waitForSelectedSource(dbg);
|
||||
});
|
||||
|
||||
add_task(function*() {
|
||||
let dbg = yield initDebugger("doc-scripts.html", "simple1", "simple2");
|
||||
add_task(async function() {
|
||||
let dbg = await initDebugger("doc-scripts.html", "simple1", "simple2");
|
||||
|
||||
yield selectSource(dbg, "simple1");
|
||||
yield selectSource(dbg, "simple2");
|
||||
await selectSource(dbg, "simple1");
|
||||
await selectSource(dbg, "simple2");
|
||||
closeTab(dbg, "simple1");
|
||||
closeTab(dbg, "simple2");
|
||||
|
||||
// Test reloading the debugger
|
||||
yield reload(dbg, "simple1", "simple2");
|
||||
await reload(dbg, "simple1", "simple2");
|
||||
is(countTabs(dbg), 0);
|
||||
});
|
||||
|
@ -25,10 +25,10 @@ function getSplitConsole(dbg) {
|
||||
});
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
|
||||
yield selectSource(dbg, "long");
|
||||
await selectSource(dbg, "long");
|
||||
dbg.win.cm.scrollTo(0, 284);
|
||||
|
||||
pressKey(dbg, "inspector");
|
||||
|
@ -25,22 +25,22 @@ function pressStepOut(dbg) {
|
||||
return waitForPaused(dbg);
|
||||
}
|
||||
|
||||
add_task(function*() {
|
||||
const dbg = yield initDebugger("doc-debugger-statements.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-debugger-statements.html");
|
||||
|
||||
yield reload(dbg);
|
||||
yield waitForPaused(dbg);
|
||||
await reload(dbg);
|
||||
await waitForPaused(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
yield pressResume(dbg);
|
||||
await pressResume(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
yield pressStepIn(dbg);
|
||||
await pressStepIn(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
yield pressStepOut(dbg);
|
||||
await pressStepOut(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
|
||||
yield pressStepOver(dbg);
|
||||
await pressStepOver(dbg);
|
||||
assertPausedLocation(dbg);
|
||||
});
|
||||
|
@ -3,27 +3,36 @@
|
||||
|
||||
// Tests that keyboard navigation into and out of debugger code editor
|
||||
|
||||
add_task(function* () {
|
||||
const dbg = yield initDebugger("doc-scripts.html");
|
||||
add_task(async function() {
|
||||
const dbg = await initDebugger("doc-scripts.html");
|
||||
let doc = dbg.win.document;
|
||||
|
||||
yield selectSource(dbg, "simple2");
|
||||
await selectSource(dbg, "simple2");
|
||||
|
||||
yield waitForElement(dbg, ".CodeMirror");
|
||||
await waitForElement(dbg, ".CodeMirror");
|
||||
findElementWithSelector(dbg, ".CodeMirror").focus();
|
||||
|
||||
// Enter code editor
|
||||
pressKey(dbg, "Enter");
|
||||
is(findElementWithSelector(dbg, "textarea"), doc.activeElement,
|
||||
"Editor is enabled");
|
||||
is(
|
||||
findElementWithSelector(dbg, "textarea"),
|
||||
doc.activeElement,
|
||||
"Editor is enabled"
|
||||
);
|
||||
|
||||
// Exit code editor and focus on container
|
||||
pressKey(dbg, "Escape");
|
||||
is(findElementWithSelector(dbg, ".CodeMirror"), doc.activeElement,
|
||||
"Focused on container");
|
||||
is(
|
||||
findElementWithSelector(dbg, ".CodeMirror"),
|
||||
doc.activeElement,
|
||||
"Focused on container"
|
||||
);
|
||||
|
||||
// Enter code editor
|
||||
pressKey(dbg, "Tab");
|
||||
is(findElementWithSelector(dbg, "textarea"), doc.activeElement,
|
||||
"Editor is enabled");
|
||||
is(
|
||||
findElementWithSelector(dbg, "textarea"),
|
||||
doc.activeElement,
|
||||
"Editor is enabled"
|
||||
);
|
||||
});
|
||||
|
@ -9,5 +9,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<button onclick="main()">Main</button>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -211,8 +211,9 @@ function waitForSource(dbg, url) {
|
||||
});
|
||||
}
|
||||
|
||||
function waitForElement(dbg, selector) {
|
||||
return waitUntil(() => findElementWithSelector(dbg, selector));
|
||||
async function waitForElement(dbg, selector) {
|
||||
await waitUntil(() => findElementWithSelector(dbg, selector));
|
||||
return findElementWithSelector(dbg, selector);
|
||||
}
|
||||
|
||||
function waitForSelectedSource(dbg, sourceId) {
|
||||
@ -290,7 +291,9 @@ function assertHighlightLocation(dbg, source, line) {
|
||||
"Highlighted line is visible"
|
||||
);
|
||||
ok(
|
||||
getCM(dbg).lineInfo(line - 1).wrapClass.includes("highlight-line"),
|
||||
getCM(dbg)
|
||||
.lineInfo(line - 1)
|
||||
.wrapClass.includes("highlight-line"),
|
||||
"Line is highlighted"
|
||||
);
|
||||
}
|
||||
@ -730,7 +733,8 @@ const selectors = {
|
||||
sourceNode: i => `.sources-list .tree-node:nth-child(${i})`,
|
||||
sourceNodes: ".sources-list .tree-node",
|
||||
sourceArrow: i => `.sources-list .tree-node:nth-child(${i}) .arrow`,
|
||||
resultItems: `.result-list .result-item`
|
||||
resultItems: `.result-list .result-item`,
|
||||
fileMatch: `.managed-tree .result`
|
||||
};
|
||||
|
||||
function getSelector(elementName, ...args) {
|
||||
@ -770,12 +774,17 @@ function findAllElements(dbg, elementName, ...args) {
|
||||
* @return {Promise}
|
||||
* @static
|
||||
*/
|
||||
function clickElement(dbg, elementName, ...args) {
|
||||
async function clickElement(dbg, elementName, ...args) {
|
||||
const selector = getSelector(elementName, ...args);
|
||||
const el = findElement(dbg, elementName, ...args);
|
||||
const el = await waitForElement(dbg, selector);
|
||||
|
||||
el.scrollIntoView();
|
||||
|
||||
return EventUtils.synthesizeMouseAtCenter(
|
||||
return clickElementWithSelector(dbg, selector);
|
||||
}
|
||||
|
||||
function clickElementWithSelector(dbg, selector) {
|
||||
EventUtils.synthesizeMouseAtCenter(
|
||||
findElementWithSelector(dbg, selector),
|
||||
{},
|
||||
dbg.win
|
||||
|
@ -26,6 +26,7 @@
|
||||
.accordion ._header {
|
||||
background-color: var(--accordion-header-background);
|
||||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
color: var(--theme-toolbar-color);
|
||||
cursor: pointer;
|
||||
font-size: 12px;
|
||||
padding: 4px;
|
||||
|
@ -143,6 +143,10 @@ sources.search.alt.key=CmdOrCtrl+O
|
||||
# full project text search for searching all the files the debugger has seen.
|
||||
projectTextSearch.key=CmdOrCtrl+Shift+F
|
||||
|
||||
# LOCALIZATION NOTE (functionSearch.key): A key shortcut to open the
|
||||
# modal for searching functions in a file.
|
||||
functionSearch.key=CmdOrCtrl+Shift+O
|
||||
|
||||
# LOCALIZATION NOTE (projectTextSearch.placeholder): A placeholder shown
|
||||
# when searching across all of the files in a project.
|
||||
projectTextSearch.placeholder=Find in files…
|
||||
@ -395,6 +399,10 @@ sourceFooter.unblackbox.accesskey=b
|
||||
# with a blackboxed source
|
||||
sourceFooter.blackboxed=Blackboxed Source
|
||||
|
||||
# LOCALIZATION NOTE (sourceFooter.codeCoverage): Text associated
|
||||
# with a code coverage button
|
||||
sourceFooter.codeCoverage=Code Coverage
|
||||
|
||||
# LOCALIZATION NOTE (sourceTabs.closeTabButtonTooltip): The tooltip that is displayed
|
||||
# for close tab button in source tabs.
|
||||
sourceTabs.closeTabButtonTooltip=Close tab
|
||||
@ -421,6 +429,9 @@ scopes.block=Block
|
||||
# LOCALIZATION NOTE (sources.header): Sources left sidebar header
|
||||
sources.header=Sources
|
||||
|
||||
# LOCALIZATION NOTE (outline.header): Outline left sidebar header
|
||||
outline.header=Outline
|
||||
|
||||
# LOCALIZATION NOTE (sources.search): Sources left sidebar prompt
|
||||
# e.g. Cmd+P to search. On a mac, we use the command unicode character.
|
||||
# On windows, it's ctrl.
|
||||
@ -444,9 +455,13 @@ welcome.search=%S to search for sources
|
||||
# a mac we use the unicode character.
|
||||
welcome.findInFiles=%S to find in files
|
||||
|
||||
# LOCALIZATION NOTE (welcome.searchFunction): Label displayed in the welcome
|
||||
# panel. %S is replaced by the keyboard shortcut to search for functions.
|
||||
welcome.searchFunction=%S to search for functions in file
|
||||
|
||||
# LOCALIZATION NOTE (sourceSearch.search): The center pane Source Search
|
||||
# prompt for searching for files.
|
||||
sourceSearch.search=Search Sources…
|
||||
sourceSearch.search=Search sources…
|
||||
|
||||
# LOCALIZATION NOTE (sourceSearch.noResults): The center pane Source Search
|
||||
# message when the query did not match any of the sources.
|
||||
|
@ -38,5 +38,5 @@ pref("devtools.debugger.expressions", "[]");
|
||||
pref("devtools.debugger.file-search-case-sensitive", false);
|
||||
pref("devtools.debugger.file-search-whole-word", false);
|
||||
pref("devtools.debugger.file-search-regex-match", false);
|
||||
pref("devtools.debugger.features.async-stepping", false);
|
||||
pref("devtools.debugger.features.async-stepping", true);
|
||||
pref("devtools.debugger.project-text-search-enabled", true);
|
||||
|
@ -81,7 +81,7 @@
|
||||
.theme-light .tabs .tabs-menu-item {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
color: var(--theme-content-color1);
|
||||
color: var(--theme-toolbar-color);
|
||||
}
|
||||
|
||||
.theme-dark .tabs .tabs-menu-item:last-child,
|
||||
|
@ -109,7 +109,6 @@ body {
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
color: var(--theme-content-color3);
|
||||
}
|
||||
|
||||
/* The top toolbar, containing the toggle-all button. And the timeline toolbar,
|
||||
|
@ -222,8 +222,9 @@
|
||||
}
|
||||
|
||||
.ruleview-header {
|
||||
background-color: var(--rule-header-background-color);
|
||||
background: var(--rule-header-background-color);
|
||||
border-bottom: 1px solid var(--theme-splitter-color);
|
||||
color: var(--theme-toolbar-color);
|
||||
font-size: 12px;
|
||||
padding: 4px;
|
||||
width: 100%;
|
||||
|
@ -140,12 +140,8 @@
|
||||
-moz-box-flex: initial;
|
||||
}
|
||||
|
||||
.theme-dark .devtools-tab {
|
||||
color: var(--theme-body-color-alt);
|
||||
}
|
||||
|
||||
.theme-light .devtools-tab {
|
||||
color: var(--theme-body-color);
|
||||
.devtools-tab {
|
||||
color: var(--theme-toolbar-color);
|
||||
}
|
||||
|
||||
.theme-dark .devtools-tab:hover {
|
||||
|
@ -24,6 +24,7 @@
|
||||
/* Toolbar */
|
||||
--theme-tab-toolbar-background: var(--grey-10);
|
||||
--theme-toolbar-background: var(--grey-10);
|
||||
--theme-toolbar-color: var(--grey-90);
|
||||
--theme-toolbar-background-hover: rgba(221, 225, 228, 0.66);
|
||||
--theme-toolbar-background-alt: #f5f5f5;
|
||||
--theme-toolbar-hover: rgba(170, 170, 170, .2);
|
||||
@ -41,7 +42,7 @@
|
||||
--theme-comment: #696969;
|
||||
--theme-comment-alt: #ccd1d5;
|
||||
|
||||
--theme-body-color: #393f4c;
|
||||
--theme-body-color: var(--grey-60);
|
||||
--theme-body-color-alt: #585959;
|
||||
--theme-body-color-inactive: #999797;
|
||||
--theme-content-color1: #292e33;
|
||||
@ -99,6 +100,7 @@
|
||||
/* Toolbar */
|
||||
--theme-tab-toolbar-background: var(--grey-90);
|
||||
--theme-toolbar-background: var(--grey-90);
|
||||
--theme-toolbar-color: var(--grey-40);
|
||||
--theme-toolbar-background-hover: #20232B;
|
||||
--theme-toolbar-background-alt: #2F343E;
|
||||
--theme-toolbar-hover: rgba(110, 120, 130, 0.1);
|
||||
@ -116,11 +118,11 @@
|
||||
--theme-comment: #757873;
|
||||
--theme-comment-alt: #5a6375;
|
||||
|
||||
--theme-body-color: #8fa1b2;
|
||||
--theme-body-color: var(--grey-40);
|
||||
--theme-body-color-alt: #b6babf;
|
||||
--theme-body-color-inactive: #8fa1b2;
|
||||
--theme-body-color-inactive: var(--grey-40);
|
||||
--theme-content-color1: #a9bacb;
|
||||
--theme-content-color2: #8fa1b2;
|
||||
--theme-content-color2: var(--grey-40);
|
||||
--theme-content-color3: #5f7387;
|
||||
|
||||
--theme-highlight-green: #00ff7f;
|
||||
|
@ -840,17 +840,20 @@ nsCopySupport::FireClipboardEvent(EventMessage aEventMessage,
|
||||
doDefault = (status != nsEventStatus_eConsumeNoDefault);
|
||||
}
|
||||
|
||||
// When this function exits, the event dispatch is over. We want to disconnect
|
||||
// our DataTransfer, which means setting its mode to `Protected` and clearing
|
||||
// all stored data, before we return.
|
||||
auto clearAfter = MakeScopeExit([&] {
|
||||
if (clipboardData) {
|
||||
clipboardData->SetMode(DataTransfer::Mode::Protected);
|
||||
clipboardData->ClearAll();
|
||||
}
|
||||
});
|
||||
|
||||
// No need to do anything special during a paste. Either an event listener
|
||||
// took care of it and cancelled the event, or the caller will handle it.
|
||||
// Return true to indicate that the event wasn't cancelled.
|
||||
if (originalEventMessage == ePaste) {
|
||||
// Clear and mark the clipboardData as readonly. This prevents someone
|
||||
// from reading the clipboard contents after the paste event has fired.
|
||||
if (clipboardData) {
|
||||
clipboardData->ClearAll();
|
||||
clipboardData->SetReadOnly();
|
||||
}
|
||||
|
||||
if (aActionTaken) {
|
||||
*aActionTaken = true;
|
||||
}
|
||||
|
@ -4534,7 +4534,7 @@ nsPIDOMWindowInner::UpdateWebSocketCount(int32_t aDelta)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsTopInnerWindow()) {
|
||||
if (mTopInnerWindow && !IsTopInnerWindow()) {
|
||||
mTopInnerWindow->UpdateWebSocketCount(aDelta);
|
||||
}
|
||||
|
||||
@ -4562,7 +4562,7 @@ nsPIDOMWindowInner::UpdateUserMediaCount(int32_t aDelta)
|
||||
return;
|
||||
}
|
||||
|
||||
if (!IsTopInnerWindow()) {
|
||||
if (mTopInnerWindow && !IsTopInnerWindow()) {
|
||||
mTopInnerWindow->UpdateUserMediaCount(aDelta);
|
||||
}
|
||||
|
||||
|
@ -21,6 +21,7 @@ class nsAttrName;
|
||||
class nsTextFragment;
|
||||
class nsIFrame;
|
||||
class nsXBLBinding;
|
||||
class nsITextControlElement;
|
||||
|
||||
namespace mozilla {
|
||||
class EventChainPreVisitor;
|
||||
@ -980,6 +981,11 @@ public:
|
||||
|
||||
virtual bool OwnedOnlyByTheDOMTree() { return false; }
|
||||
|
||||
virtual already_AddRefed<nsITextControlElement> GetAsTextControlElement()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Hook for implementing GetID. This is guaranteed to only be
|
||||
|
@ -599,8 +599,14 @@ protected:
|
||||
template<typename A, typename B>
|
||||
RangeBoundaryBase& operator=(const RangeBoundaryBase<A,B>& aOther)
|
||||
{
|
||||
mParent = aOther.mParent;
|
||||
mRef = aOther.mRef;
|
||||
// Since the member variables may be nsCOMPtrs, better to try to avoid
|
||||
// extra Release/AddRef calls.
|
||||
if (mParent != aOther.mParent) {
|
||||
mParent = aOther.mParent;
|
||||
}
|
||||
if (mRef != aOther.mRef) {
|
||||
mRef = aOther.mRef;
|
||||
}
|
||||
mOffset = aOther.mOffset;
|
||||
return *this;
|
||||
}
|
||||
|
2
dom/cache/TypeUtils.cpp
vendored
2
dom/cache/TypeUtils.cpp
vendored
@ -343,7 +343,7 @@ TypeUtils::ToInternalRequest(const CacheRequest& aIn)
|
||||
|
||||
nsCOMPtr<nsIInputStream> stream = ReadStream::Create(aIn.body());
|
||||
|
||||
internalRequest->SetBody(stream);
|
||||
internalRequest->SetBody(stream, -1);
|
||||
|
||||
return internalRequest.forget();
|
||||
}
|
||||
|
@ -81,6 +81,27 @@ enum CustomClipboardTypeId {
|
||||
eCustomClipboardTypeId_String
|
||||
};
|
||||
|
||||
static DataTransfer::Mode
|
||||
ModeForEvent(EventMessage aEventMessage)
|
||||
{
|
||||
switch (aEventMessage) {
|
||||
case eCut:
|
||||
case eCopy:
|
||||
case eDragStart:
|
||||
// For these events, we want to be able to add data to the data transfer,
|
||||
// Otherwise, the data is already present.
|
||||
return DataTransfer::Mode::ReadWrite;
|
||||
case eDrop:
|
||||
case ePaste:
|
||||
case ePasteNoFormatting:
|
||||
// For these events we want to be able to read the data which is stored in
|
||||
// the DataTransfer, rather than just the type information.
|
||||
return DataTransfer::Mode::ReadOnly;
|
||||
default:
|
||||
return DataTransfer::Mode::Protected;
|
||||
}
|
||||
}
|
||||
|
||||
DataTransfer::DataTransfer(nsISupports* aParent, EventMessage aEventMessage,
|
||||
bool aIsExternal, int32_t aClipboardType)
|
||||
: mParent(aParent)
|
||||
@ -88,7 +109,7 @@ DataTransfer::DataTransfer(nsISupports* aParent, EventMessage aEventMessage,
|
||||
, mEffectAllowed(nsIDragService::DRAGDROP_ACTION_UNINITIALIZED)
|
||||
, mEventMessage(aEventMessage)
|
||||
, mCursorState(false)
|
||||
, mReadOnly(true)
|
||||
, mMode(ModeForEvent(aEventMessage))
|
||||
, mIsExternal(aIsExternal)
|
||||
, mUserCancelled(false)
|
||||
, mIsCrossDomainSubFrameDrop(false)
|
||||
@ -97,14 +118,9 @@ DataTransfer::DataTransfer(nsISupports* aParent, EventMessage aEventMessage,
|
||||
, mDragImageY(0)
|
||||
{
|
||||
mItems = new DataTransferItemList(this, aIsExternal);
|
||||
// For these events, we want to be able to add data to the data transfer, so
|
||||
// clear the readonly state. Otherwise, the data is already present. For
|
||||
// external usage, cache the data from the native clipboard or drag.
|
||||
if (aEventMessage == eCut ||
|
||||
aEventMessage == eCopy ||
|
||||
aEventMessage == eDragStart) {
|
||||
mReadOnly = false;
|
||||
} else if (mIsExternal) {
|
||||
|
||||
// For external usage, cache the data from the native clipboard or drag.
|
||||
if (mIsExternal && mMode != Mode::ReadWrite) {
|
||||
if (aEventMessage == ePasteNoFormatting) {
|
||||
mEventMessage = ePaste;
|
||||
CacheExternalClipboardFormats(true);
|
||||
@ -134,7 +150,7 @@ DataTransfer::DataTransfer(nsISupports* aParent,
|
||||
, mEffectAllowed(aEffectAllowed)
|
||||
, mEventMessage(aEventMessage)
|
||||
, mCursorState(aCursorState)
|
||||
, mReadOnly(true)
|
||||
, mMode(ModeForEvent(aEventMessage))
|
||||
, mIsExternal(aIsExternal)
|
||||
, mUserCancelled(aUserCancelled)
|
||||
, mIsCrossDomainSubFrameDrop(aIsCrossDomainSubFrameDrop)
|
||||
@ -429,7 +445,7 @@ DataTransfer::ClearData(const Optional<nsAString>& aFormat,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (mReadOnly) {
|
||||
if (IsReadOnly()) {
|
||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
return;
|
||||
}
|
||||
@ -659,6 +675,25 @@ DataTransfer::TypesListMayHaveChanged()
|
||||
DataTransferBinding::ClearCachedTypesValue(this);
|
||||
}
|
||||
|
||||
already_AddRefed<DataTransfer>
|
||||
DataTransfer::MozCloneForEvent(const nsAString& aEvent, ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<nsIAtom> atomEvt = NS_Atomize(aEvent);
|
||||
if (!atomEvt) {
|
||||
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
return nullptr;
|
||||
}
|
||||
EventMessage eventMessage = nsContentUtils::GetEventMessage(atomEvt);
|
||||
|
||||
RefPtr<DataTransfer> dt;
|
||||
nsresult rv = Clone(mParent, eventMessage, false, false, getter_AddRefs(dt));
|
||||
if (NS_FAILED(rv)) {
|
||||
aRv.Throw(rv);
|
||||
return nullptr;
|
||||
}
|
||||
return dt.forget();
|
||||
}
|
||||
|
||||
nsresult
|
||||
DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
|
||||
uint32_t aIndex,
|
||||
@ -668,7 +703,7 @@ DataTransfer::SetDataAtInternal(const nsAString& aFormat, nsIVariant* aData,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (mReadOnly) {
|
||||
if (IsReadOnly()) {
|
||||
return NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR;
|
||||
}
|
||||
|
||||
@ -716,7 +751,7 @@ DataTransfer::MozClearDataAt(const nsAString& aFormat, uint32_t aIndex,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (mReadOnly) {
|
||||
if (IsReadOnly()) {
|
||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
return;
|
||||
}
|
||||
@ -753,7 +788,7 @@ DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
|
||||
nsIPrincipal& aSubjectPrincipal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(!mReadOnly);
|
||||
MOZ_ASSERT(!IsReadOnly());
|
||||
MOZ_ASSERT(aIndex < MozItemCount());
|
||||
MOZ_ASSERT(aIndex == 0 ||
|
||||
(mEventMessage != eCut && mEventMessage != eCopy &&
|
||||
@ -768,7 +803,7 @@ DataTransfer::MozClearDataAtHelper(const nsAString& aFormat, uint32_t aIndex,
|
||||
void
|
||||
DataTransfer::SetDragImage(Element& aImage, int32_t aX, int32_t aY)
|
||||
{
|
||||
if (!mReadOnly) {
|
||||
if (!IsReadOnly()) {
|
||||
mDragImage = &aImage;
|
||||
mDragImageX = aX;
|
||||
mDragImageY = aY;
|
||||
@ -848,7 +883,7 @@ DataTransfer::GetFiles(bool aRecursiveFlag,
|
||||
void
|
||||
DataTransfer::AddElement(Element& aElement, ErrorResult& aRv)
|
||||
{
|
||||
if (mReadOnly) {
|
||||
if (IsReadOnly()) {
|
||||
aRv.Throw(NS_ERROR_DOM_NO_MODIFICATION_ALLOWED_ERR);
|
||||
return;
|
||||
}
|
||||
|
@ -61,6 +61,14 @@ public:
|
||||
return static_cast<DataTransfer*>(aArg);
|
||||
}
|
||||
|
||||
/// An enum which represents which "Drag Data Store Mode" the DataTransfer is
|
||||
/// in according to the spec.
|
||||
enum class Mode : uint8_t {
|
||||
ReadWrite,
|
||||
ReadOnly,
|
||||
Protected,
|
||||
};
|
||||
|
||||
protected:
|
||||
|
||||
// hide the default constructor
|
||||
@ -68,6 +76,7 @@ protected:
|
||||
|
||||
// this constructor is used only by the Clone method to copy the fields as
|
||||
// needed to a new data transfer.
|
||||
// NOTE: Do not call this method directly.
|
||||
DataTransfer(nsISupports* aParent,
|
||||
EventMessage aEventMessage,
|
||||
const uint32_t aEffectAllowed,
|
||||
@ -214,13 +223,25 @@ public:
|
||||
return mItems;
|
||||
}
|
||||
|
||||
// a readonly dataTransfer cannot have new data added or existing data
|
||||
// removed. Only the dropEffect and effectAllowed may be modified.
|
||||
bool IsReadOnly() const {
|
||||
return mReadOnly;
|
||||
// Returns the current "Drag Data Store Mode" of the DataTransfer. This
|
||||
// determines what modifications may be performed on the DataTransfer, and
|
||||
// what data may be read from it.
|
||||
Mode GetMode() const {
|
||||
return mMode;
|
||||
}
|
||||
void SetReadOnly() {
|
||||
mReadOnly = true;
|
||||
void SetMode(Mode aMode) {
|
||||
mMode = aMode;
|
||||
}
|
||||
|
||||
// Helper method. Is true if the DataTransfer's mode is ReadOnly or Protected,
|
||||
// which means that the DataTransfer cannot be modified.
|
||||
bool IsReadOnly() const {
|
||||
return mMode != Mode::ReadWrite;
|
||||
}
|
||||
// Helper method. Is true if the DataTransfer's mode is Protected, which means
|
||||
// that DataTransfer type information may be read, but data may not be.
|
||||
bool IsProtected() const {
|
||||
return mMode == Mode::Protected;
|
||||
}
|
||||
|
||||
int32_t ClipboardType() const {
|
||||
@ -278,6 +299,12 @@ public:
|
||||
return mDragImage;
|
||||
}
|
||||
|
||||
// This method makes a copy of the DataTransfer object, with a few properties
|
||||
// changed, and the mode updated to reflect the correct mode for the given
|
||||
// event. This method is used during the drag operation to generate the
|
||||
// DataTransfer objects for each event after `dragstart`. Event objects will
|
||||
// lazily clone the DataTransfer stored in the DragSession (which is a clone
|
||||
// of the DataTransfer used in the `dragstart` event) when requested.
|
||||
nsresult Clone(nsISupports* aParent, EventMessage aEventMessage,
|
||||
bool aUserCancelled, bool aIsCrossDomainSubFrameDrop,
|
||||
DataTransfer** aResult);
|
||||
@ -295,6 +322,11 @@ public:
|
||||
// GetTypes being added or removed or changing item kinds.
|
||||
void TypesListMayHaveChanged();
|
||||
|
||||
// Testing method used to emulate internal DataTransfer management.
|
||||
// NOTE: Please don't use this. See the comments in the webidl for more.
|
||||
already_AddRefed<DataTransfer> MozCloneForEvent(const nsAString& aEvent,
|
||||
ErrorResult& aRv);
|
||||
|
||||
protected:
|
||||
|
||||
// caches text and uri-list data formats that exist in the drag service or
|
||||
@ -343,9 +375,8 @@ protected:
|
||||
// Indicates the behavior of the cursor during drag operations
|
||||
bool mCursorState;
|
||||
|
||||
// readonly data transfers may not be modified except the drop effect and
|
||||
// effect allowed.
|
||||
bool mReadOnly;
|
||||
// The current "Drag Data Store Mode" which the DataTransfer is in.
|
||||
Mode mMode;
|
||||
|
||||
// true for drags started without a data transfer, for example, those from
|
||||
// another application.
|
||||
|
@ -503,14 +503,20 @@ DataTransferItem::Data(nsIPrincipal* aPrincipal, ErrorResult& aRv)
|
||||
{
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
|
||||
nsCOMPtr<nsIVariant> variant = DataNoSecurityCheck();
|
||||
|
||||
// If the inbound principal is system, we can skip the below checks, as
|
||||
// they will trivially succeed.
|
||||
if (nsContentUtils::IsSystemPrincipal(aPrincipal)) {
|
||||
return variant.forget();
|
||||
return DataNoSecurityCheck();
|
||||
}
|
||||
|
||||
// We should not allow raw data to be accessed from a Protected DataTransfer.
|
||||
// We don't prevent this access if the accessing document is Chrome.
|
||||
if (mDataTransfer->IsProtected()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIVariant> variant = DataNoSecurityCheck();
|
||||
|
||||
MOZ_ASSERT(!ChromeOnly(), "Non-chrome code shouldn't see a ChromeOnly DataTransferItem");
|
||||
if (ChromeOnly()) {
|
||||
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
|
||||
|
@ -562,6 +562,14 @@ DataTransferItemList::GenerateFiles(FileList* aFiles,
|
||||
{
|
||||
MOZ_ASSERT(aFiles);
|
||||
MOZ_ASSERT(aFilesPrincipal);
|
||||
|
||||
// For non-system principals, the Files list should be empty if the
|
||||
// DataTransfer is protected.
|
||||
if (!nsContentUtils::IsSystemPrincipal(aFilesPrincipal) &&
|
||||
mDataTransfer->IsProtected()) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t count = Length();
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
bool found;
|
||||
|
@ -1772,6 +1772,12 @@ EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
|
||||
|
||||
RefPtr<DataTransfer> dataTransfer =
|
||||
new DataTransfer(window, eDragStart, false, -1);
|
||||
auto protectDataTransfer = MakeScopeExit([&] {
|
||||
if (dataTransfer) {
|
||||
dataTransfer->SetMode(DataTransfer::Mode::Protected);
|
||||
dataTransfer->ClearAll();
|
||||
}
|
||||
});
|
||||
|
||||
nsCOMPtr<nsISelection> selection;
|
||||
nsCOMPtr<nsIContent> eventContent, targetContent;
|
||||
@ -1839,11 +1845,6 @@ EventStateManager::GenerateDragGesture(nsPresContext* aPresContext,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
// now that the dataTransfer has been updated in the dragstart and
|
||||
// draggesture events, make it read only so that the data doesn't
|
||||
// change during the drag.
|
||||
dataTransfer->SetReadOnly();
|
||||
|
||||
if (status != nsEventStatus_eConsumeNoDefault) {
|
||||
bool dragStarted = DoDefaultDragStart(aPresContext, event, dataTransfer,
|
||||
targetContent, selection);
|
||||
@ -2006,6 +2007,18 @@ EventStateManager::DoDefaultDragStart(nsPresContext* aPresContext,
|
||||
if (!transArray)
|
||||
return false;
|
||||
|
||||
// After this function returns, the DataTransfer will be cleared so it appears
|
||||
// empty to content. We need to pass a DataTransfer into the Drag Session, so
|
||||
// we need to make a copy.
|
||||
RefPtr<DataTransfer> dataTransfer;
|
||||
aDataTransfer->Clone(aDragTarget, eDrop, aDataTransfer->MozUserCancelled(),
|
||||
false, getter_AddRefs(dataTransfer));
|
||||
|
||||
// Copy over the drop effect, as Clone doesn't copy it for us.
|
||||
uint32_t dropEffect;
|
||||
aDataTransfer->GetDropEffectInt(&dropEffect);
|
||||
dataTransfer->SetDropEffectInt(dropEffect);
|
||||
|
||||
// XXXndeakin don't really want to create a new drag DOM event
|
||||
// here, but we need something to pass to the InvokeDragSession
|
||||
// methods.
|
||||
@ -2018,7 +2031,7 @@ EventStateManager::DoDefaultDragStart(nsPresContext* aPresContext,
|
||||
// other than a selection is being dragged.
|
||||
if (!dragImage && aSelection) {
|
||||
dragService->InvokeDragSessionWithSelection(aSelection, transArray,
|
||||
action, event, aDataTransfer);
|
||||
action, event, dataTransfer);
|
||||
}
|
||||
else {
|
||||
// if dragging within a XUL tree and no custom drag image was
|
||||
@ -2045,7 +2058,7 @@ EventStateManager::DoDefaultDragStart(nsPresContext* aPresContext,
|
||||
dragImage ? dragImage->AsDOMNode() :
|
||||
nullptr,
|
||||
imageX, imageY, event,
|
||||
aDataTransfer);
|
||||
dataTransfer);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -130,6 +130,9 @@
|
||||
var dt = e.dataTransfer;
|
||||
dragenterFired++;
|
||||
|
||||
// NOTE: This test is run with chrome privileges.
|
||||
// For back-compat reasons, protected mode acts like readonly mode for
|
||||
// chrome documents.
|
||||
readOnly(e);
|
||||
}
|
||||
|
||||
|
@ -34,8 +34,8 @@ SimpleTest.waitForFocus(() => {
|
||||
"clipboard contains html text");
|
||||
|
||||
window.addEventListener("paste", (e) => {
|
||||
ok(e.clipboardData.types.indexOf('text/html'), -1, "clipboardData shouldn't have text/html");
|
||||
ok(e.clipboardData.getData('text/plain'), "Formatted Text", "getData(text/plain) should return plain text");
|
||||
is(e.clipboardData.types.indexOf('text/html'), -1, "clipboardData shouldn't have text/html");
|
||||
is(e.clipboardData.getData('text/plain'), "Formatted Text", "getData(text/plain) should return plain text");
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
|
@ -74,7 +74,7 @@ function runTests()
|
||||
|
||||
SpecialPowers.addChromeEventListener("drop", chromeListener, true, false);
|
||||
var targetNotHandling = document.getElementById("nothandling_target");
|
||||
fireDrop(targetNotHandling, true, true);
|
||||
fireDrop(targetNotHandling, false, true);
|
||||
SpecialPowers.removeChromeEventListener("drop", chromeListener, true);
|
||||
ok(chromeGotEvent, "Chrome should have got drop event!");
|
||||
is(gGotHandlingDrop, false, "Didn't get drop on accepting element (2)");
|
||||
|
@ -369,12 +369,15 @@ FetchDriver::HttpFetch()
|
||||
MOZ_ASSERT_IF(!hasContentTypeHeader, contentType.IsVoid());
|
||||
#endif // DEBUG
|
||||
|
||||
int64_t bodyLength;
|
||||
nsCOMPtr<nsIInputStream> bodyStream;
|
||||
mRequest->GetBody(getter_AddRefs(bodyStream));
|
||||
mRequest->GetBody(getter_AddRefs(bodyStream), &bodyLength);
|
||||
if (bodyStream) {
|
||||
nsAutoCString method;
|
||||
mRequest->GetMethod(method);
|
||||
rv = uploadChan->ExplicitSetUploadStream(bodyStream, contentType, -1, method, false /* aStreamHasHeaders */);
|
||||
rv = uploadChan->ExplicitSetUploadStream(bodyStream, contentType,
|
||||
bodyLength, method,
|
||||
false /* aStreamHasHeaders */);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
}
|
||||
|
@ -30,6 +30,7 @@ InternalRequest::GetRequestConstructorCopy(nsIGlobalObject* aGlobal, ErrorResult
|
||||
copy->mHeaders = new InternalHeaders(*mHeaders);
|
||||
copy->SetUnsafeRequest();
|
||||
copy->mBodyStream = mBodyStream;
|
||||
copy->mBodyLength = mBodyLength;
|
||||
copy->mForceOriginHeader = true;
|
||||
// The "client" is not stored in our implementation. Fetch API users should
|
||||
// use the appropriate window/document/principal and other Gecko security
|
||||
@ -79,6 +80,7 @@ InternalRequest::InternalRequest(const nsACString& aURL,
|
||||
const nsACString& aFragment)
|
||||
: mMethod("GET")
|
||||
, mHeaders(new InternalHeaders(HeadersGuardEnum::None))
|
||||
, mBodyLength(InternalResponse::UNKNOWN_BODY_SIZE)
|
||||
, mContentPolicyType(nsIContentPolicy::TYPE_FETCH)
|
||||
, mReferrer(NS_LITERAL_STRING(kFETCH_CLIENT_REFERRER_STR))
|
||||
, mReferrerPolicy(ReferrerPolicy::_empty)
|
||||
|
@ -462,20 +462,25 @@ public:
|
||||
}
|
||||
|
||||
void
|
||||
SetBody(nsIInputStream* aStream)
|
||||
SetBody(nsIInputStream* aStream, int64_t aBodyLength)
|
||||
{
|
||||
// A request's body may not be reset once set.
|
||||
MOZ_ASSERT_IF(aStream, !mBodyStream);
|
||||
mBodyStream = aStream;
|
||||
mBodyLength = aBodyLength;
|
||||
}
|
||||
|
||||
// Will return the original stream!
|
||||
// Use a tee or copy if you don't want to erase the original.
|
||||
void
|
||||
GetBody(nsIInputStream** aStream)
|
||||
GetBody(nsIInputStream** aStream, int64_t* aBodyLength = nullptr)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> s = mBodyStream;
|
||||
s.forget(aStream);
|
||||
|
||||
if (aBodyLength) {
|
||||
*aBodyLength = mBodyLength;
|
||||
}
|
||||
}
|
||||
|
||||
// The global is used as the client for the new object.
|
||||
@ -554,6 +559,7 @@ private:
|
||||
nsTArray<nsCString> mURLList;
|
||||
RefPtr<InternalHeaders> mHeaders;
|
||||
nsCOMPtr<nsIInputStream> mBodyStream;
|
||||
int64_t mBodyLength;
|
||||
|
||||
nsContentPolicyType mContentPolicyType;
|
||||
|
||||
|
@ -212,7 +212,7 @@ public:
|
||||
return;
|
||||
}
|
||||
|
||||
return GetUnfilteredBody(aStream, aBodySize);
|
||||
GetUnfilteredBody(aStream, aBodySize);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -580,11 +580,11 @@ Request::Constructor(const GlobalObject& aGlobal,
|
||||
const fetch::OwningBodyInit& bodyInit = bodyInitNullable.Value();
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
nsAutoCString contentTypeWithCharset;
|
||||
uint64_t contentLengthUnused;
|
||||
uint64_t contentLength = 0;
|
||||
aRv = ExtractByteStreamFromBody(bodyInit,
|
||||
getter_AddRefs(stream),
|
||||
contentTypeWithCharset,
|
||||
contentLengthUnused);
|
||||
contentLength);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -604,10 +604,10 @@ Request::Constructor(const GlobalObject& aGlobal,
|
||||
request->ClearCreatedByFetchEvent();
|
||||
|
||||
if (hasCopiedBody) {
|
||||
request->SetBody(nullptr);
|
||||
request->SetBody(nullptr, 0);
|
||||
}
|
||||
|
||||
request->SetBody(temporaryBody);
|
||||
request->SetBody(temporaryBody, contentLength);
|
||||
}
|
||||
}
|
||||
|
||||
@ -619,7 +619,7 @@ Request::Constructor(const GlobalObject& aGlobal,
|
||||
nsCOMPtr<nsIInputStream> body;
|
||||
inputReq->GetBody(getter_AddRefs(body));
|
||||
if (body) {
|
||||
inputReq->SetBody(nullptr);
|
||||
inputReq->SetBody(nullptr, 0);
|
||||
inputReq->SetBodyUsed(aGlobal.Context(), aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return nullptr;
|
||||
|
@ -126,13 +126,19 @@ public:
|
||||
|
||||
Headers* Headers_();
|
||||
|
||||
void
|
||||
GetBody(nsIInputStream** aStream) { return mRequest->GetBody(aStream); }
|
||||
|
||||
using FetchBody::GetBody;
|
||||
|
||||
void
|
||||
SetBody(nsIInputStream* aStream) { return mRequest->SetBody(aStream); }
|
||||
GetBody(nsIInputStream** aStream, int64_t* aBodyLength = nullptr)
|
||||
{
|
||||
mRequest->GetBody(aStream, aBodyLength);
|
||||
}
|
||||
|
||||
void
|
||||
SetBody(nsIInputStream* aStream, int64_t aBodyLength)
|
||||
{
|
||||
mRequest->SetBody(aStream, aBodyLength);
|
||||
}
|
||||
|
||||
static already_AddRefed<Request>
|
||||
Constructor(const GlobalObject& aGlobal, const RequestOrUSVString& aInput,
|
||||
|
@ -105,7 +105,10 @@ public:
|
||||
Headers* Headers_();
|
||||
|
||||
void
|
||||
GetBody(nsIInputStream** aStream) { return mInternalResponse->GetBody(aStream); }
|
||||
GetBody(nsIInputStream** aStream, int64_t* aBodyLength = nullptr)
|
||||
{
|
||||
mInternalResponse->GetBody(aStream, aBodyLength);
|
||||
}
|
||||
|
||||
using FetchBody::GetBody;
|
||||
|
||||
|
@ -9,13 +9,18 @@
|
||||
#include "IPCBlobInputStreamStorage.h"
|
||||
#include "mozilla/ipc/InputStreamParams.h"
|
||||
#include "nsIAsyncInputStream.h"
|
||||
#include "nsIStreamTransportService.h"
|
||||
#include "nsITransport.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
namespace {
|
||||
|
||||
class CallbackRunnable final : public CancelableRunnable
|
||||
static NS_DEFINE_CID(kStreamTransportServiceCID, NS_STREAMTRANSPORTSERVICE_CID);
|
||||
|
||||
class InputStreamCallbackRunnable final : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
static void
|
||||
@ -23,8 +28,8 @@ public:
|
||||
nsIEventTarget* aEventTarget,
|
||||
IPCBlobInputStream* aStream)
|
||||
{
|
||||
RefPtr<CallbackRunnable> runnable =
|
||||
new CallbackRunnable(aCallback, aStream);
|
||||
RefPtr<InputStreamCallbackRunnable> runnable =
|
||||
new InputStreamCallbackRunnable(aCallback, aStream);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target = aEventTarget;
|
||||
if (!target) {
|
||||
@ -44,9 +49,9 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
CallbackRunnable(nsIInputStreamCallback* aCallback,
|
||||
IPCBlobInputStream* aStream)
|
||||
: CancelableRunnable("dom::CallbackRunnable")
|
||||
InputStreamCallbackRunnable(nsIInputStreamCallback* aCallback,
|
||||
IPCBlobInputStream* aStream)
|
||||
: CancelableRunnable("dom::InputStreamCallbackRunnable")
|
||||
, mCallback(aCallback)
|
||||
, mStream(aStream)
|
||||
{
|
||||
@ -58,6 +63,49 @@ private:
|
||||
RefPtr<IPCBlobInputStream> mStream;
|
||||
};
|
||||
|
||||
class FileMetadataCallbackRunnable final : public CancelableRunnable
|
||||
{
|
||||
public:
|
||||
static void
|
||||
Execute(nsIFileMetadataCallback* aCallback,
|
||||
nsIEventTarget* aEventTarget,
|
||||
IPCBlobInputStream* aStream)
|
||||
{
|
||||
RefPtr<FileMetadataCallbackRunnable> runnable =
|
||||
new FileMetadataCallbackRunnable(aCallback, aStream);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> target = aEventTarget;
|
||||
if (!target) {
|
||||
target = NS_GetCurrentThread();
|
||||
}
|
||||
|
||||
target->Dispatch(runnable, NS_DISPATCH_NORMAL);
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
mCallback->OnFileMetadataReady(mStream);
|
||||
mCallback = nullptr;
|
||||
mStream = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
FileMetadataCallbackRunnable(nsIFileMetadataCallback* aCallback,
|
||||
IPCBlobInputStream* aStream)
|
||||
: CancelableRunnable("dom::FileMetadataCallbackRunnable")
|
||||
, mCallback(aCallback)
|
||||
, mStream(aStream)
|
||||
{
|
||||
MOZ_ASSERT(mCallback);
|
||||
MOZ_ASSERT(mStream);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFileMetadataCallback> mCallback;
|
||||
RefPtr<IPCBlobInputStream> mStream;
|
||||
};
|
||||
|
||||
} // anonymous
|
||||
|
||||
NS_IMPL_ADDREF(IPCBlobInputStream);
|
||||
@ -69,8 +117,8 @@ NS_INTERFACE_MAP_BEGIN(IPCBlobInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsICloneableInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream)
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream())
|
||||
NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFileMetadata, IsFileMetadata())
|
||||
NS_INTERFACE_MAP_ENTRY(nsIFileMetadata)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIAsyncFileMetadata)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
@ -109,7 +157,22 @@ IPCBlobInputStream::Available(uint64_t* aLength)
|
||||
|
||||
if (mState == eRunning) {
|
||||
MOZ_ASSERT(mRemoteStream);
|
||||
return mRemoteStream->Available(aLength);
|
||||
|
||||
// This will go away eventually: an async input stream can return 0 in
|
||||
// Available(), but this is not currently fully supported in the rest of
|
||||
// gecko.
|
||||
if (!mAsyncRemoteStream) {
|
||||
*aLength = mActor->Size();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult rv = EnsureAsyncRemoteStream();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mAsyncRemoteStream);
|
||||
return mAsyncRemoteStream->Available(aLength);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mState == eClosed);
|
||||
@ -125,7 +188,15 @@ IPCBlobInputStream::Read(char* aBuffer, uint32_t aCount, uint32_t* aReadCount)
|
||||
}
|
||||
|
||||
if (mState == eRunning) {
|
||||
return mRemoteStream->Read(aBuffer, aCount, aReadCount);
|
||||
MOZ_ASSERT(mRemoteStream);
|
||||
|
||||
nsresult rv = EnsureAsyncRemoteStream();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mAsyncRemoteStream);
|
||||
return mAsyncRemoteStream->Read(aBuffer, aCount, aReadCount);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mState == eClosed);
|
||||
@ -142,7 +213,15 @@ IPCBlobInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
|
||||
}
|
||||
|
||||
if (mState == eRunning) {
|
||||
return mRemoteStream->ReadSegments(aWriter, aClosure, aCount, aResult);
|
||||
MOZ_ASSERT(mRemoteStream);
|
||||
|
||||
nsresult rv = EnsureAsyncRemoteStream();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mAsyncRemoteStream);
|
||||
return mAsyncRemoteStream->ReadSegments(aWriter, aClosure, aCount, aResult);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mState == eClosed);
|
||||
@ -164,12 +243,21 @@ IPCBlobInputStream::Close()
|
||||
mActor = nullptr;
|
||||
}
|
||||
|
||||
if (mAsyncRemoteStream) {
|
||||
mAsyncRemoteStream->Close();
|
||||
mAsyncRemoteStream = nullptr;
|
||||
}
|
||||
|
||||
if (mRemoteStream) {
|
||||
mRemoteStream->Close();
|
||||
mRemoteStream = nullptr;
|
||||
}
|
||||
|
||||
mCallback = nullptr;
|
||||
mInputStreamCallback = nullptr;
|
||||
mInputStreamCallbackEventTarget = nullptr;
|
||||
|
||||
mFileMetadataCallback = nullptr;
|
||||
mFileMetadataCallbackEventTarget = nullptr;
|
||||
|
||||
mState = eClosed;
|
||||
return NS_OK;
|
||||
@ -222,8 +310,8 @@ IPCBlobInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
|
||||
case eInit:
|
||||
MOZ_ASSERT(mActor);
|
||||
|
||||
mCallback = aCallback;
|
||||
mCallbackEventTarget = aEventTarget;
|
||||
mInputStreamCallback = aCallback;
|
||||
mInputStreamCallbackEventTarget = aEventTarget;
|
||||
mState = ePending;
|
||||
|
||||
mActor->StreamNeeded(this, aEventTarget);
|
||||
@ -231,17 +319,17 @@ IPCBlobInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
|
||||
|
||||
// We are still waiting for the remote inputStream
|
||||
case ePending:
|
||||
if (mCallback && aCallback) {
|
||||
if (mInputStreamCallback && aCallback) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mCallback = aCallback;
|
||||
mCallbackEventTarget = aEventTarget;
|
||||
mInputStreamCallback = aCallback;
|
||||
mInputStreamCallbackEventTarget = aEventTarget;
|
||||
return NS_OK;
|
||||
|
||||
// We have the remote inputStream, let's check if we can execute the callback.
|
||||
case eRunning:
|
||||
return MaybeExecuteCallback(aCallback, aEventTarget);
|
||||
return MaybeExecuteInputStreamCallback(aCallback, aEventTarget);
|
||||
|
||||
// Stream is closed.
|
||||
default:
|
||||
@ -265,58 +353,66 @@ IPCBlobInputStream::StreamReady(nsIInputStream* aInputStream)
|
||||
// stream is not available anymore. We keep the state as pending just to block
|
||||
// any additional operation.
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> callback;
|
||||
callback.swap(mCallback);
|
||||
if (!aInputStream) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIEventTarget> callbackEventTarget;
|
||||
callbackEventTarget.swap(mCallbackEventTarget);
|
||||
mRemoteStream = aInputStream;
|
||||
|
||||
if (aInputStream && callback) {
|
||||
MOZ_ASSERT(mState == ePending);
|
||||
MOZ_ASSERT(mState == ePending);
|
||||
mState = eRunning;
|
||||
|
||||
mRemoteStream = aInputStream;
|
||||
mState = eRunning;
|
||||
nsCOMPtr<nsIFileMetadataCallback> fileMetadataCallback;
|
||||
fileMetadataCallback.swap(mFileMetadataCallback);
|
||||
|
||||
MaybeExecuteCallback(callback, callbackEventTarget);
|
||||
nsCOMPtr<nsIEventTarget> fileMetadataCallbackEventTarget;
|
||||
fileMetadataCallbackEventTarget.swap(mFileMetadataCallbackEventTarget);
|
||||
|
||||
if (fileMetadataCallback) {
|
||||
FileMetadataCallbackRunnable::Execute(fileMetadataCallback,
|
||||
fileMetadataCallbackEventTarget,
|
||||
this);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStreamCallback> inputStreamCallback;
|
||||
inputStreamCallback.swap(mInputStreamCallback);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> inputStreamCallbackEventTarget;
|
||||
inputStreamCallbackEventTarget.swap(mInputStreamCallbackEventTarget);
|
||||
|
||||
if (inputStreamCallback) {
|
||||
MaybeExecuteInputStreamCallback(inputStreamCallback,
|
||||
inputStreamCallbackEventTarget);
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
IPCBlobInputStream::MaybeExecuteCallback(nsIInputStreamCallback* aCallback,
|
||||
nsIEventTarget* aCallbackEventTarget)
|
||||
IPCBlobInputStream::MaybeExecuteInputStreamCallback(nsIInputStreamCallback* aCallback,
|
||||
nsIEventTarget* aCallbackEventTarget)
|
||||
{
|
||||
MOZ_ASSERT(mState == eRunning);
|
||||
MOZ_ASSERT(mRemoteStream);
|
||||
|
||||
// If the stream supports nsIAsyncInputStream, we need to call its AsyncWait
|
||||
// and wait for OnInputStreamReady.
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(mRemoteStream);
|
||||
if (asyncStream) {
|
||||
// If the callback has been already set, we return an error.
|
||||
if (mCallback && aCallback) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mCallback = aCallback;
|
||||
mCallbackEventTarget = aCallbackEventTarget;
|
||||
|
||||
if (!mCallback) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
RefPtr<nsIEventTarget> target = GetCurrentThreadEventTarget();
|
||||
return asyncStream->AsyncWait(this, 0, 0, target);
|
||||
// If the callback has been already set, we return an error.
|
||||
if (mInputStreamCallback && aCallback) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!mCallback);
|
||||
MOZ_ASSERT(!mCallbackEventTarget);
|
||||
mInputStreamCallback = aCallback;
|
||||
mInputStreamCallbackEventTarget = aCallbackEventTarget;
|
||||
|
||||
if (!aCallback) {
|
||||
if (!mInputStreamCallback) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
CallbackRunnable::Execute(aCallback, aCallbackEventTarget, this);
|
||||
return NS_OK;
|
||||
nsresult rv = EnsureAsyncRemoteStream();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mAsyncRemoteStream);
|
||||
|
||||
return mAsyncRemoteStream->AsyncWait(this, 0, 0, aCallbackEventTarget);
|
||||
}
|
||||
|
||||
// nsIInputStreamCallback
|
||||
@ -330,18 +426,20 @@ IPCBlobInputStream::OnInputStreamReady(nsIAsyncInputStream* aStream)
|
||||
}
|
||||
|
||||
MOZ_ASSERT(mState == eRunning);
|
||||
MOZ_ASSERT(mRemoteStream == aStream);
|
||||
MOZ_ASSERT(mAsyncRemoteStream == aStream);
|
||||
|
||||
// The callback has been canceled in the meantime.
|
||||
if (!mCallback) {
|
||||
if (!mInputStreamCallback) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
CallbackRunnable::Execute(mCallback, mCallbackEventTarget, this);
|
||||
|
||||
mCallback = nullptr;
|
||||
mCallbackEventTarget = nullptr;
|
||||
nsCOMPtr<nsIInputStreamCallback> callback;
|
||||
callback.swap(mInputStreamCallback);
|
||||
|
||||
nsCOMPtr<nsIEventTarget> callbackEventTarget;
|
||||
callbackEventTarget.swap(mInputStreamCallbackEventTarget);
|
||||
|
||||
InputStreamCallbackRunnable::Execute(callback, callbackEventTarget, this);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -371,17 +469,50 @@ IPCBlobInputStream::ExpectedSerializedLength()
|
||||
return mozilla::Nothing();
|
||||
}
|
||||
|
||||
// nsIFileMetadata
|
||||
// nsIAsyncFileMetadata
|
||||
|
||||
bool
|
||||
IPCBlobInputStream::IsFileMetadata() const
|
||||
NS_IMETHODIMP
|
||||
IPCBlobInputStream::AsyncWait(nsIFileMetadataCallback* aCallback,
|
||||
nsIEventTarget* aEventTarget)
|
||||
{
|
||||
// We are nsIFileMetadata only if we have the remote stream and that is a
|
||||
// nsIFileMetadata.
|
||||
nsCOMPtr<nsIFileMetadata> fileMetadata = do_QueryInterface(mRemoteStream);
|
||||
return !!fileMetadata;
|
||||
// See IPCBlobInputStream.h for more information about this state machine.
|
||||
|
||||
switch (mState) {
|
||||
// First call, we need to retrieve the stream from the parent actor.
|
||||
case eInit:
|
||||
MOZ_ASSERT(mActor);
|
||||
|
||||
mFileMetadataCallback = aCallback;
|
||||
mFileMetadataCallbackEventTarget = aEventTarget;
|
||||
mState = ePending;
|
||||
|
||||
mActor->StreamNeeded(this, aEventTarget);
|
||||
return NS_OK;
|
||||
|
||||
// We are still waiting for the remote inputStream
|
||||
case ePending:
|
||||
if (mFileMetadataCallback && aCallback) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mFileMetadataCallback = aCallback;
|
||||
mFileMetadataCallbackEventTarget = aEventTarget;
|
||||
return NS_OK;
|
||||
|
||||
// We have the remote inputStream, let's check if we can execute the callback.
|
||||
case eRunning:
|
||||
FileMetadataCallbackRunnable::Execute(aCallback, aEventTarget, this);
|
||||
return NS_OK;
|
||||
|
||||
// Stream is closed.
|
||||
default:
|
||||
MOZ_ASSERT(mState == eClosed);
|
||||
return NS_BASE_STREAM_CLOSED;
|
||||
}
|
||||
}
|
||||
|
||||
// nsIFileMetadata
|
||||
|
||||
NS_IMETHODIMP
|
||||
IPCBlobInputStream::GetSize(int64_t* aRetval)
|
||||
{
|
||||
@ -415,44 +546,60 @@ IPCBlobInputStream::GetFileDescriptor(PRFileDesc** aRetval)
|
||||
return fileMetadata->GetFileDescriptor(aRetval);
|
||||
}
|
||||
|
||||
// nsISeekableStream
|
||||
|
||||
bool
|
||||
IPCBlobInputStream::IsSeekableStream() const
|
||||
nsresult
|
||||
IPCBlobInputStream::EnsureAsyncRemoteStream()
|
||||
{
|
||||
// We are nsISeekableStream only if we have the remote stream and that is a
|
||||
// nsISeekableStream.
|
||||
nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(mRemoteStream);
|
||||
return !!seekableStream;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IPCBlobInputStream::Seek(int32_t aWhence, int64_t aOffset)
|
||||
{
|
||||
nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(mRemoteStream);
|
||||
if (!seekableStream) {
|
||||
return mState == eClosed ? NS_BASE_STREAM_CLOSED : NS_ERROR_FAILURE;
|
||||
if (!mRemoteStream) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return seekableStream->Seek(aWhence, aOffset);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
IPCBlobInputStream::Tell(int64_t *aResult)
|
||||
{
|
||||
nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(mRemoteStream);
|
||||
if (!seekableStream) {
|
||||
return mState == eClosed ? NS_BASE_STREAM_CLOSED : NS_ERROR_FAILURE;
|
||||
// We already have an async remote stream.
|
||||
if (mAsyncRemoteStream) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return seekableStream->Tell(aResult);
|
||||
}
|
||||
// If the stream is blocking, we want to make it unblocking using a pipe.
|
||||
bool nonBlocking = false;
|
||||
nsresult rv = mRemoteStream->IsNonBlocking(&nonBlocking);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(mRemoteStream);
|
||||
if (!asyncStream || !nonBlocking) {
|
||||
nsCOMPtr<nsIStreamTransportService> sts =
|
||||
do_GetService(kStreamTransportServiceCID, &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITransport> transport;
|
||||
rv = sts->CreateInputTransport(mRemoteStream,
|
||||
/* aStartOffset */ 0,
|
||||
/* aReadLimit */ -1,
|
||||
/* aCloseWhenDone */ true,
|
||||
getter_AddRefs(transport));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> wrapper;
|
||||
rv = transport->OpenInputStream(/* aFlags */ 0,
|
||||
/* aSegmentSize */ 0,
|
||||
/* aSegmentCount */ 0,
|
||||
getter_AddRefs(wrapper));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
asyncStream = do_QueryInterface(wrapper);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(asyncStream);
|
||||
mAsyncRemoteStream = asyncStream;
|
||||
|
||||
return NS_OK;
|
||||
|
||||
NS_IMETHODIMP
|
||||
IPCBlobInputStream::SetEOF()
|
||||
{
|
||||
// This is a read-only stream.
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "nsICloneableInputStream.h"
|
||||
#include "nsIFileStreams.h"
|
||||
#include "nsIIPCSerializableInputStream.h"
|
||||
#include "nsISeekableStream.h"
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
@ -23,8 +22,7 @@ class IPCBlobInputStream final : public nsIAsyncInputStream
|
||||
, public nsIInputStreamCallback
|
||||
, public nsICloneableInputStream
|
||||
, public nsIIPCSerializableInputStream
|
||||
, public nsISeekableStream
|
||||
, public nsIFileMetadata
|
||||
, public nsIAsyncFileMetadata
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
@ -33,8 +31,8 @@ public:
|
||||
NS_DECL_NSIINPUTSTREAMCALLBACK
|
||||
NS_DECL_NSICLONEABLEINPUTSTREAM
|
||||
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
|
||||
NS_DECL_NSISEEKABLESTREAM
|
||||
NS_DECL_NSIFILEMETADATA
|
||||
NS_DECL_NSIASYNCFILEMETADATA
|
||||
|
||||
explicit IPCBlobInputStream(IPCBlobInputStreamChild* aActor);
|
||||
|
||||
@ -45,14 +43,11 @@ private:
|
||||
~IPCBlobInputStream();
|
||||
|
||||
nsresult
|
||||
MaybeExecuteCallback(nsIInputStreamCallback* aCallback,
|
||||
nsIEventTarget* aEventTarget);
|
||||
MaybeExecuteInputStreamCallback(nsIInputStreamCallback* aCallback,
|
||||
nsIEventTarget* aEventTarget);
|
||||
|
||||
bool
|
||||
IsSeekableStream() const;
|
||||
|
||||
bool
|
||||
IsFileMetadata() const;
|
||||
nsresult
|
||||
EnsureAsyncRemoteStream();
|
||||
|
||||
RefPtr<IPCBlobInputStreamChild> mActor;
|
||||
|
||||
@ -78,10 +73,15 @@ private:
|
||||
} mState;
|
||||
|
||||
nsCOMPtr<nsIInputStream> mRemoteStream;
|
||||
nsCOMPtr<nsIAsyncInputStream> mAsyncRemoteStream;
|
||||
|
||||
// These 2 values are set only if mState is ePending.
|
||||
nsCOMPtr<nsIInputStreamCallback> mCallback;
|
||||
nsCOMPtr<nsIEventTarget> mCallbackEventTarget;
|
||||
nsCOMPtr<nsIInputStreamCallback> mInputStreamCallback;
|
||||
nsCOMPtr<nsIEventTarget> mInputStreamCallbackEventTarget;
|
||||
|
||||
// These 2 values are set only if mState is ePending.
|
||||
nsCOMPtr<nsIFileMetadataCallback> mFileMetadataCallback;
|
||||
nsCOMPtr<nsIEventTarget> mFileMetadataCallbackEventTarget;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -687,7 +687,7 @@ HttpServer::Connection::ConsumeLine(const char* aBuffer,
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mCurrentRequestBody = do_QueryInterface(output);
|
||||
mPendingReq->SetBody(input);
|
||||
mPendingReq->SetBody(input, -1);
|
||||
} else {
|
||||
LOG_V("HttpServer::Connection::ConsumeLine(%p) - No body", this);
|
||||
mState = eRequestLine;
|
||||
|
@ -343,6 +343,12 @@ public:
|
||||
return mHasPatternAttribute;
|
||||
}
|
||||
|
||||
virtual already_AddRefed<nsITextControlElement> GetAsTextControlElement() override
|
||||
{
|
||||
nsCOMPtr<nsITextControlElement> txt = this;
|
||||
return txt.forget();
|
||||
}
|
||||
|
||||
// nsIConstraintValidation
|
||||
bool IsTooLong();
|
||||
bool IsTooShort();
|
||||
|
@ -168,6 +168,12 @@ public:
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLTextAreaElement,
|
||||
nsGenericHTMLFormElementWithState)
|
||||
|
||||
virtual already_AddRefed<nsITextControlElement> GetAsTextControlElement() override
|
||||
{
|
||||
nsCOMPtr<nsITextControlElement> txt = this;
|
||||
return txt.forget();
|
||||
}
|
||||
|
||||
// nsIConstraintValidation
|
||||
bool IsTooLong();
|
||||
bool IsTooShort();
|
||||
|
@ -1477,6 +1477,7 @@ DispatchFileHandleSuccessEvent(FileHandleResultHelper* aResultHelper)
|
||||
class BackgroundRequestChild::PreprocessHelper final
|
||||
: public CancelableRunnable
|
||||
, public nsIInputStreamCallback
|
||||
, public nsIFileMetadataCallback
|
||||
{
|
||||
typedef std::pair<nsCOMPtr<nsIInputStream>,
|
||||
nsCOMPtr<nsIInputStream>> StreamPair;
|
||||
@ -1560,9 +1561,13 @@ private:
|
||||
void
|
||||
ContinueWithStatus(nsresult aStatus);
|
||||
|
||||
nsresult
|
||||
DataIsReady(nsIInputStream* aInputStream);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIRUNNABLE
|
||||
NS_DECL_NSIINPUTSTREAMCALLBACK
|
||||
NS_DECL_NSIFILEMETADATACALLBACK
|
||||
|
||||
virtual nsresult
|
||||
Cancel() override;
|
||||
@ -3518,6 +3523,17 @@ PreprocessHelper::WaitForStreamReady(nsIInputStream* aInputStream)
|
||||
MOZ_ASSERT(!IsOnOwningThread());
|
||||
MOZ_ASSERT(aInputStream);
|
||||
|
||||
nsCOMPtr<nsIAsyncFileMetadata> asyncFileMetadata =
|
||||
do_QueryInterface(aInputStream);
|
||||
if (asyncFileMetadata) {
|
||||
nsresult rv = asyncFileMetadata->AsyncWait(this, mTaskQueueEventTarget);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(aInputStream);
|
||||
if (!asyncStream) {
|
||||
return NS_ERROR_NO_INTERFACE;
|
||||
@ -3564,7 +3580,8 @@ PreprocessHelper::ContinueWithStatus(nsresult aStatus)
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(BackgroundRequestChild::PreprocessHelper,
|
||||
CancelableRunnable, nsIInputStreamCallback)
|
||||
CancelableRunnable, nsIInputStreamCallback,
|
||||
nsIFileMetadataCallback)
|
||||
|
||||
NS_IMETHODIMP
|
||||
BackgroundRequestChild::
|
||||
@ -3582,6 +3599,23 @@ PreprocessHelper::Run()
|
||||
NS_IMETHODIMP
|
||||
BackgroundRequestChild::
|
||||
PreprocessHelper::OnInputStreamReady(nsIAsyncInputStream* aStream)
|
||||
{
|
||||
return DataIsReady(aStream);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BackgroundRequestChild::
|
||||
PreprocessHelper::OnFileMetadataReady(nsIAsyncFileMetadata* aObject)
|
||||
{
|
||||
nsCOMPtr<nsIInputStream> stream = do_QueryInterface(aObject);
|
||||
MOZ_ASSERT(stream, "It was a stream before!");
|
||||
|
||||
return DataIsReady(stream);
|
||||
}
|
||||
|
||||
nsresult
|
||||
BackgroundRequestChild::
|
||||
PreprocessHelper::DataIsReady(nsIInputStream* aStream)
|
||||
{
|
||||
MOZ_ASSERT(!IsOnOwningThread());
|
||||
MOZ_ASSERT(aStream);
|
||||
|
@ -268,11 +268,6 @@
|
||||
|
||||
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;
|
||||
|
||||
@ -1311,13 +1306,8 @@ ContentParent::Init()
|
||||
// process.
|
||||
if (nsIPresShell::IsAccessibilityActive()) {
|
||||
#if defined(XP_WIN)
|
||||
#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()));
|
||||
Unused << SendActivateA11y(::GetCurrentThreadId(),
|
||||
a11y::AccessibleWrap::GetContentProcessIdFor(ChildID()));
|
||||
#else
|
||||
Unused << SendActivateA11y(0, 0);
|
||||
#endif
|
||||
@ -2851,13 +2841,8 @@ ContentParent::Observe(nsISupports* aSubject,
|
||||
// Make sure accessibility is running in content process when
|
||||
// accessibility gets initiated in chrome process.
|
||||
#if defined(XP_WIN)
|
||||
#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()));
|
||||
Unused << SendActivateA11y(::GetCurrentThreadId(),
|
||||
a11y::AccessibleWrap::GetContentProcessIdFor(ChildID()));
|
||||
#else
|
||||
Unused << SendActivateA11y(0, 0);
|
||||
#endif
|
||||
|
@ -659,22 +659,19 @@ function checkCachedDataTransfer(cd, eventtype)
|
||||
setClipboardText("Some Clipboard Text");
|
||||
|
||||
var oldtext = cd.getData("text/plain");
|
||||
ok(oldtext != "Some Clipboard Text", "clipboard get using " + testprefix);
|
||||
ok(!oldtext, "clipboard get using " + testprefix);
|
||||
|
||||
var exh = false;
|
||||
try { cd.mozSetDataAt("text/plain", "Test Cache Data", 0); } catch (ex) { exh = true; }
|
||||
ok(eventtype == "paste" ? exh : !exh, "exception occured setting " + testprefix);
|
||||
|
||||
var newtext = (eventtype == "paste") ? cd.getData("text/plain") :
|
||||
cd.mozGetDataAt("text/plain", 0);
|
||||
is(newtext, (eventtype == "paste") ? oldtext : "Test Cache Data",
|
||||
" clipboardData not changed using " + testprefix);
|
||||
try {
|
||||
cd.mozSetDataAt("text/plain", "Test Cache Data", 0);
|
||||
} catch (ex) {}
|
||||
ok(!cd.getData("text/plain"), "clipboard set using " + testprefix);
|
||||
|
||||
is(getClipboardText(), "Some Clipboard Text", "clipboard not changed using " + testprefix);
|
||||
|
||||
var exh = false;
|
||||
try { cd.mozClearDataAt("text/plain", 0); } catch (ex) { exh = true; }
|
||||
ok(eventtype == "paste" ? exh : !exh, "exception occured clearing " + testprefix);
|
||||
try {
|
||||
cd.mozClearDataAt("text/plain", 0);
|
||||
} catch (ex) {}
|
||||
ok(!cd.getData("text/plain"), "clipboard clear using " + testprefix);
|
||||
|
||||
is(getClipboardText(), "Some Clipboard Text", "clipboard not changed using " + testprefix);
|
||||
}
|
||||
|
@ -155,4 +155,16 @@ partial interface DataTransfer {
|
||||
*/
|
||||
[UseCounter]
|
||||
readonly attribute Node? mozSourceNode;
|
||||
|
||||
/**
|
||||
* Copy the given DataTransfer for the given event. Used by testing code for
|
||||
* creating emulated Drag and Drop events in the UI.
|
||||
*
|
||||
* NOTE: Don't expose a DataTransfer produced with this method to the web or
|
||||
* use this for non-testing purposes. It can easily be used to get the
|
||||
* DataTransfer into an invalid state, and is an unstable implementation
|
||||
* detail of EventUtils.synthesizeDrag.
|
||||
*/
|
||||
[Throws, ChromeOnly]
|
||||
DataTransfer mozCloneForEvent(DOMString event);
|
||||
};
|
||||
|
@ -209,8 +209,14 @@ FileReaderSync::ReadAsText(Blob& aBlob,
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t blobSize = aBlob.GetSize(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())){
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> syncStream;
|
||||
aRv = ConvertAsyncToSyncStream(stream, getter_AddRefs(syncStream));
|
||||
aRv = ConvertAsyncToSyncStream(blobSize - sniffBuf.Length(), stream,
|
||||
getter_AddRefs(syncStream));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
@ -255,8 +261,13 @@ FileReaderSync::ReadAsDataURL(Blob& aBlob, nsAString& aResult,
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t blobSize = aBlob.GetSize(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())){
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> syncStream;
|
||||
aRv = ConvertAsyncToSyncStream(stream, getter_AddRefs(syncStream));
|
||||
aRv = ConvertAsyncToSyncStream(blobSize, stream, getter_AddRefs(syncStream));
|
||||
if (NS_WARN_IF(aRv.Failed())) {
|
||||
return;
|
||||
}
|
||||
@ -269,11 +280,6 @@ FileReaderSync::ReadAsDataURL(Blob& aBlob, nsAString& aResult,
|
||||
return;
|
||||
}
|
||||
|
||||
uint64_t blobSize = aBlob.GetSize(aRv);
|
||||
if (NS_WARN_IF(aRv.Failed())){
|
||||
return;
|
||||
}
|
||||
|
||||
// The file is changed in the meantime?
|
||||
if (blobSize != size) {
|
||||
return;
|
||||
@ -466,7 +472,8 @@ FileReaderSync::SyncRead(nsIInputStream* aStream, char* aBuffer,
|
||||
}
|
||||
|
||||
nsresult
|
||||
FileReaderSync::ConvertAsyncToSyncStream(nsIInputStream* aAsyncStream,
|
||||
FileReaderSync::ConvertAsyncToSyncStream(uint64_t aStreamSize,
|
||||
nsIInputStream* aAsyncStream,
|
||||
nsIInputStream** aSyncStream)
|
||||
{
|
||||
// If the stream is not async, we just need it to be bufferable.
|
||||
@ -475,30 +482,19 @@ FileReaderSync::ConvertAsyncToSyncStream(nsIInputStream* aAsyncStream,
|
||||
return NS_NewBufferedInputStream(aSyncStream, aAsyncStream, 4096);
|
||||
}
|
||||
|
||||
uint64_t length;
|
||||
nsresult rv = aAsyncStream->Available(&length);
|
||||
if (rv == NS_BASE_STREAM_CLOSED) {
|
||||
// The stream has already been closed. Nothing to do.
|
||||
*aSyncStream = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsAutoCString buffer;
|
||||
if (!buffer.SetLength(length, fallible)) {
|
||||
if (!buffer.SetLength(aStreamSize, fallible)) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
uint32_t read;
|
||||
rv = SyncRead(aAsyncStream, buffer.BeginWriting(), length, &read);
|
||||
nsresult rv =
|
||||
SyncRead(aAsyncStream, buffer.BeginWriting(), aStreamSize, &read);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (read != length) {
|
||||
if (read != aStreamSize) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
|
@ -32,7 +32,8 @@ private:
|
||||
nsresult ConvertStream(nsIInputStream *aStream, const char *aCharset,
|
||||
nsAString &aResult);
|
||||
|
||||
nsresult ConvertAsyncToSyncStream(nsIInputStream* aAsyncStream,
|
||||
nsresult ConvertAsyncToSyncStream(uint64_t aStreamSize,
|
||||
nsIInputStream* aAsyncStream,
|
||||
nsIInputStream** aSyncStream);
|
||||
|
||||
nsresult SyncRead(nsIInputStream* aStream, char* aBuffer,
|
||||
|
@ -1603,7 +1603,7 @@ private:
|
||||
mReferrerPolicy,
|
||||
mContentPolicyType,
|
||||
mIntegrity);
|
||||
internalReq->SetBody(mUploadStream);
|
||||
internalReq->SetBody(mUploadStream, -1);
|
||||
// For Telemetry, note that this Request object was created by a Fetch event.
|
||||
internalReq->SetCreatedByFetchEvent();
|
||||
|
||||
|
@ -646,6 +646,8 @@ public:
|
||||
}
|
||||
aFontEntry->mSkipDefaultFeatureSpaceCheck = mSkipDefaultFeatureSpaceCheck;
|
||||
mAvailableFonts.AppendElement(aFontEntry);
|
||||
mIsSimpleFamily = false; // CheckForSimpleFamily may set this later,
|
||||
// but at this point we're not sure
|
||||
}
|
||||
|
||||
// note that the styles for this family have been added
|
||||
|
@ -183,14 +183,17 @@ MacOSFontEntry::ReadCMAP(FontInfoData *aFontInfoData)
|
||||
// characters it supports, so only check/clear the
|
||||
// complex-script ranges for non-Graphite fonts
|
||||
|
||||
// for layout support, check for the presence of mort/morx and/or
|
||||
// for layout support, check for the presence of mort/morx/kerx and/or
|
||||
// opentype layout tables
|
||||
bool hasAATLayout = HasFontTable(TRUETYPE_TAG('m','o','r','x')) ||
|
||||
HasFontTable(TRUETYPE_TAG('m','o','r','t'));
|
||||
bool hasAppleKerning = HasFontTable(TRUETYPE_TAG('k','e','r','x'));
|
||||
bool hasGSUB = HasFontTable(TRUETYPE_TAG('G','S','U','B'));
|
||||
bool hasGPOS = HasFontTable(TRUETYPE_TAG('G','P','O','S'));
|
||||
if (hasAATLayout && !(hasGSUB || hasGPOS)) {
|
||||
mRequiresAAT = true; // prefer CoreText if font has no OTL tables
|
||||
if ((hasAATLayout && !(hasGSUB || hasGPOS)) || hasAppleKerning) {
|
||||
mRequiresAAT = true; // prefer CoreText if font has no OTL tables,
|
||||
// or if it uses the Apple-specific 'kerx'
|
||||
// variant of kerning table
|
||||
}
|
||||
|
||||
for (const ScriptRange* sr = gfxPlatformFontList::sComplexScriptRanges;
|
||||
|
@ -974,8 +974,13 @@ js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason)
|
||||
return;
|
||||
#endif
|
||||
|
||||
bool canUsePromotionRate;
|
||||
const float promotionRate = calcPromotionRate(&canUsePromotionRate);
|
||||
/*
|
||||
* This incorrect promotion rate results in better nursery sizing
|
||||
* decisions, however we should to better tuning based on the real
|
||||
* promotion rate in the future.
|
||||
*/
|
||||
const float promotionRate =
|
||||
float(previousGC.tenuredBytes) / float(previousGC.nurseryCapacity);
|
||||
|
||||
newMaxNurseryChunks = runtime()->gc.tunables.gcMaxNurseryBytes() >> ChunkShift;
|
||||
if (newMaxNurseryChunks != maxNurseryChunks_) {
|
||||
@ -986,15 +991,11 @@ js::Nursery::maybeResizeNursery(JS::gcreason::Reason reason)
|
||||
/* We need to shrink the nursery */
|
||||
shrinkAllocableSpace(extraChunks);
|
||||
|
||||
if (canUsePromotionRate)
|
||||
previousPromotionRate_ = promotionRate;
|
||||
previousPromotionRate_ = promotionRate;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (!canUsePromotionRate)
|
||||
return;
|
||||
|
||||
if (promotionRate > GrowThreshold)
|
||||
growAllocableSpace();
|
||||
else if (promotionRate < ShrinkThreshold && previousPromotionRate_ < ShrinkThreshold)
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user