зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to inbound, a=merge
MozReview-Commit-ID: 77Uz3uceUmk
This commit is contained in:
Коммит
6472928439
|
@ -64,10 +64,10 @@ var shutdown = Task.async(function* () {
|
|||
|
||||
// This is what makes the sidebar widget able to load/unload the panel.
|
||||
function setPanel(panel) {
|
||||
return startup(panel).catch(e => console.error(e));
|
||||
return startup(panel).catch(console.error);
|
||||
}
|
||||
function destroy() {
|
||||
return shutdown().catch(e => console.error(e));
|
||||
return shutdown().catch(console.error);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -261,7 +261,7 @@ var AnimationsController = {
|
|||
|
||||
return this.animationsFront.toggleAll()
|
||||
.then(() => this.emit(this.ALL_ANIMATIONS_TOGGLED_EVENT, this))
|
||||
.catch(e => console.error(e));
|
||||
.catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -179,9 +179,9 @@ var AnimationsPanel = {
|
|||
// the page if the selected node does not have any animation on it.
|
||||
if (event.keyCode === KeyCodes.DOM_VK_SPACE) {
|
||||
if (AnimationsController.animationPlayers.length > 0) {
|
||||
this.playPauseTimeline().catch(ex => console.error(ex));
|
||||
this.playPauseTimeline().catch(console.error);
|
||||
} else {
|
||||
this.toggleAll().catch(ex => console.error(ex));
|
||||
this.toggleAll().catch(console.error);
|
||||
}
|
||||
event.preventDefault();
|
||||
}
|
||||
|
@ -208,7 +208,7 @@ var AnimationsPanel = {
|
|||
},
|
||||
|
||||
onToggleAllClicked: function () {
|
||||
this.toggleAll().catch(ex => console.error(ex));
|
||||
this.toggleAll().catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -221,7 +221,7 @@ var AnimationsPanel = {
|
|||
}),
|
||||
|
||||
onTimelinePlayClicked: function () {
|
||||
this.playPauseTimeline().catch(ex => console.error(ex));
|
||||
this.playPauseTimeline().catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -241,7 +241,7 @@ var AnimationsPanel = {
|
|||
},
|
||||
|
||||
onTimelineRewindClicked: function () {
|
||||
this.rewindTimeline().catch(ex => console.error(ex));
|
||||
this.rewindTimeline().catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -263,7 +263,7 @@ var AnimationsPanel = {
|
|||
onRateChanged: function (e, rate) {
|
||||
AnimationsController.setPlaybackRateAll(rate)
|
||||
.then(() => this.refreshAnimationsStateAndUI())
|
||||
.catch(ex => console.error(ex));
|
||||
.catch(console.error);
|
||||
},
|
||||
|
||||
onTabNavigated: function () {
|
||||
|
@ -289,7 +289,7 @@ var AnimationsPanel = {
|
|||
if (isUserDrag && !this.setCurrentTimeAllPromise) {
|
||||
this.setCurrentTimeAllPromise =
|
||||
AnimationsController.setCurrentTimeAll(time, true)
|
||||
.catch(error => console.error(error))
|
||||
.catch(console.error)
|
||||
.then(() => {
|
||||
this.setCurrentTimeAllPromise = null;
|
||||
});
|
||||
|
|
|
@ -288,7 +288,7 @@ var CallsListView = Heritage.extend(WidgetMethods, {
|
|||
frameSnapshot.generateScreenshotFor(functionCall).then(screenshot => {
|
||||
this.showScreenshot(screenshot);
|
||||
this.highlightedThumbnail = screenshot.index;
|
||||
}).catch(e => console.error(e));
|
||||
}).catch(console.error);
|
||||
});
|
||||
},
|
||||
|
||||
|
|
|
@ -302,14 +302,14 @@ BoxModel.prototype = {
|
|||
properties[0].name = property.substring(9);
|
||||
}
|
||||
|
||||
session.setProperties(properties).catch(e => console.error(e));
|
||||
session.setProperties(properties).catch(console.error);
|
||||
},
|
||||
done: (value, commit) => {
|
||||
editor.elt.parentNode.classList.remove("boxmodel-editing");
|
||||
if (!commit) {
|
||||
session.revert().then(() => {
|
||||
session.destroy();
|
||||
}, e => console.error(e));
|
||||
}, console.error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -322,7 +322,7 @@ BoxModel.prototype = {
|
|||
autoMargins: true,
|
||||
}).then(layout => {
|
||||
this.store.dispatch(updateLayout(layout));
|
||||
}, e => console.error(e));
|
||||
}, console.error);
|
||||
},
|
||||
cssProperties: getCssProperties(this.inspector.toolbox)
|
||||
}, event);
|
||||
|
|
|
@ -509,7 +509,7 @@ CssComputedView.prototype = {
|
|||
);
|
||||
this._refreshProcess.schedule();
|
||||
});
|
||||
}).catch((err) => console.error(err));
|
||||
}).catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -58,7 +58,7 @@ exports.items = [{
|
|||
}],
|
||||
exec: function* (args, context) {
|
||||
if (args.hide) {
|
||||
context.updateExec("eyedropper_server_hide").catch(e => console.error(e));
|
||||
context.updateExec("eyedropper_server_hide").catch(console.error);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ exports.items = [{
|
|||
|
||||
let telemetry = new Telemetry();
|
||||
telemetry.toolOpened(args.frommenu ? "menueyedropper" : "eyedropper");
|
||||
context.updateExec("eyedropper_server").catch(e => console.error(e));
|
||||
context.updateExec("eyedropper_server").catch(console.error);
|
||||
}
|
||||
}, {
|
||||
item: "command",
|
||||
|
|
|
@ -72,7 +72,7 @@ InspectorSearch.prototype = {
|
|||
|
||||
_onSearch: function (reverse = false) {
|
||||
this.doFullTextSearch(this.searchBox.value, reverse)
|
||||
.catch(e => console.error(e));
|
||||
.catch(console.error);
|
||||
},
|
||||
|
||||
doFullTextSearch: Task.async(function* (query, reverse) {
|
||||
|
|
|
@ -224,13 +224,13 @@ Inspector.prototype = {
|
|||
return promise.all([
|
||||
this._target.actorHasMethod("domwalker", "duplicateNode").then(value => {
|
||||
this._supportsDuplicateNode = value;
|
||||
}).catch(e => console.error(e)),
|
||||
}).catch(console.error),
|
||||
this._target.actorHasMethod("domnode", "scrollIntoView").then(value => {
|
||||
this._supportsScrollIntoView = value;
|
||||
}).catch(e => console.error(e)),
|
||||
}).catch(console.error),
|
||||
this._target.actorHasMethod("inspector", "resolveRelativeURL").then(value => {
|
||||
this._supportsResolveRelativeURL = value;
|
||||
}).catch(e => console.error(e)),
|
||||
}).catch(console.error),
|
||||
]);
|
||||
});
|
||||
},
|
||||
|
@ -1627,7 +1627,7 @@ Inspector.prototype = {
|
|||
this.eyeDropperButton.classList.add("checked");
|
||||
this.startEyeDropperListeners();
|
||||
return this.inspector.pickColorFromPage(this.toolbox, {copyOnSelect: true})
|
||||
.catch(e => console.error(e));
|
||||
.catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1644,7 +1644,7 @@ Inspector.prototype = {
|
|||
this.eyeDropperButton.classList.remove("checked");
|
||||
this.stopEyeDropperListeners();
|
||||
return this.inspector.cancelPickColorFromPage()
|
||||
.catch(e => console.error(e));
|
||||
.catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1839,7 +1839,7 @@ Inspector.prototype = {
|
|||
_copyLongString: function (longStringActorPromise) {
|
||||
return this._getLongString(longStringActorPromise).then(string => {
|
||||
clipboardHelper.copyString(string);
|
||||
}).catch(e => console.error(e));
|
||||
}).catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1851,10 +1851,10 @@ Inspector.prototype = {
|
|||
_getLongString: function (longStringActorPromise) {
|
||||
return longStringActorPromise.then(longStringActor => {
|
||||
return longStringActor.string().then(string => {
|
||||
longStringActor.release().catch(e => console.error(e));
|
||||
longStringActor.release().catch(console.error);
|
||||
return string;
|
||||
});
|
||||
}).catch(e => console.error(e));
|
||||
}).catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1868,7 +1868,7 @@ Inspector.prototype = {
|
|||
this.telemetry.toolOpened("copyuniquecssselector");
|
||||
this.selection.nodeFront.getUniqueSelector().then(selector => {
|
||||
clipboardHelper.copyString(selector);
|
||||
}).catch(e => console.error);
|
||||
}).catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1882,7 +1882,7 @@ Inspector.prototype = {
|
|||
this.telemetry.toolOpened("copyfullcssselector");
|
||||
this.selection.nodeFront.getCssPath().then(path => {
|
||||
clipboardHelper.copyString(path);
|
||||
}).catch(e => console.error);
|
||||
}).catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1896,7 +1896,7 @@ Inspector.prototype = {
|
|||
this.telemetry.toolOpened("copyxpath");
|
||||
this.selection.nodeFront.getXPath().then(path => {
|
||||
clipboardHelper.copyString(path);
|
||||
}).catch(e => console.error);
|
||||
}).catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -1942,7 +1942,7 @@ Inspector.prototype = {
|
|||
selection.isPseudoElementNode()) {
|
||||
return;
|
||||
}
|
||||
this.walker.duplicateNode(selection.nodeFront).catch(e => console.error(e));
|
||||
this.walker.duplicateNode(selection.nodeFront).catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -2043,7 +2043,7 @@ Inspector.prototype = {
|
|||
return this.toolbox.viewSourceInDebugger(url);
|
||||
}
|
||||
return null;
|
||||
}).catch(e => console.error(e));
|
||||
}).catch(console.error);
|
||||
} else if (type == "idref") {
|
||||
// Select the node in the same document.
|
||||
this.walker.document(this.selection.nodeFront).then(doc => {
|
||||
|
@ -2054,7 +2054,7 @@ Inspector.prototype = {
|
|||
}
|
||||
this.selection.setNodeFront(node);
|
||||
});
|
||||
}).catch(e => console.error(e));
|
||||
}).catch(console.error);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -184,7 +184,7 @@ MarkupView.prototype = {
|
|||
_onToolboxPickerHover: function (event, nodeFront) {
|
||||
this.showNode(nodeFront).then(() => {
|
||||
this._showContainerAsHovered(nodeFront);
|
||||
}, e => console.error(e));
|
||||
}, console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -897,7 +897,7 @@ CssRuleView.prototype = {
|
|||
// Notify anyone that cares that we refreshed.
|
||||
return onEditorsReady.then(() => {
|
||||
this.emit("ruleview-refreshed");
|
||||
}, e => console.error(e));
|
||||
}, console.error);
|
||||
}).catch(promiseWarn);
|
||||
},
|
||||
|
||||
|
|
|
@ -275,7 +275,7 @@ RuleEditor.prototype = {
|
|||
this.rule.getOriginalSourceStrings().then((strings) => {
|
||||
sourceLabel.textContent = strings.short;
|
||||
sourceLabel.setAttribute("title", strings.full);
|
||||
}, e => console.error(e)).then(() => {
|
||||
}, console.error).then(() => {
|
||||
this.emit("source-link-updated");
|
||||
});
|
||||
} else {
|
||||
|
|
|
@ -196,7 +196,7 @@ DomNodePreview.prototype = {
|
|||
},
|
||||
|
||||
destroy: function () {
|
||||
HighlighterLock.unhighlight().catch(e => console.error(e));
|
||||
HighlighterLock.unhighlight().catch(console.error);
|
||||
|
||||
this.stopListeners();
|
||||
|
||||
|
@ -218,7 +218,7 @@ DomNodePreview.prototype = {
|
|||
return;
|
||||
}
|
||||
this.highlighterUtils.highlightNodeFront(this.nodeFront)
|
||||
.catch(e => console.error(e));
|
||||
.catch(console.error);
|
||||
},
|
||||
|
||||
onPreviewMouseOut: function () {
|
||||
|
@ -226,7 +226,7 @@ DomNodePreview.prototype = {
|
|||
return;
|
||||
}
|
||||
this.highlighterUtils.unhighlight()
|
||||
.catch(e => console.error(e));
|
||||
.catch(console.error);
|
||||
},
|
||||
|
||||
onSelectElClick: function () {
|
||||
|
@ -246,12 +246,12 @@ DomNodePreview.prototype = {
|
|||
classList.remove("selected");
|
||||
HighlighterLock.unhighlight().then(() => {
|
||||
this.emit("target-highlighter-unlocked");
|
||||
}, error => console.error(error));
|
||||
}, console.error);
|
||||
} else {
|
||||
classList.add("selected");
|
||||
HighlighterLock.highlight(this).then(() => {
|
||||
this.emit("target-highlighter-locked");
|
||||
}, error => console.error(error));
|
||||
}, console.error);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -535,7 +535,7 @@ HighlightersOverlay.prototype = {
|
|||
// whether the result is truthy before installing the handler.
|
||||
let onHidden = this.highlighters[this.hoveredHighlighterShown].hide();
|
||||
if (onHidden) {
|
||||
onHidden.catch(e => console.error(e));
|
||||
onHidden.catch(console.error);
|
||||
}
|
||||
|
||||
this.hoveredHighlighterShown = null;
|
||||
|
|
|
@ -189,7 +189,7 @@ const ResponsiveUIManager = exports.ResponsiveUIManager = {
|
|||
break;
|
||||
default:
|
||||
}
|
||||
completed.catch(e => console.error(e));
|
||||
completed.catch(console.error);
|
||||
},
|
||||
|
||||
handleMenuCheck({target}) {
|
||||
|
|
|
@ -1736,7 +1736,7 @@ var Scratchpad = {
|
|||
this.populateRecentFilesMenu();
|
||||
PreferenceObserver.init();
|
||||
CloseObserver.init();
|
||||
}).catch((err) => console.error(err));
|
||||
}).catch(console.error);
|
||||
this._setupCommandListeners();
|
||||
this._updateViewMenuItems();
|
||||
this._setupPopupShowingListeners();
|
||||
|
|
|
@ -314,7 +314,7 @@ var ShadersListView = Heritage.extend(WidgetMethods, {
|
|||
getShaders()
|
||||
.then(getSources)
|
||||
.then(showSources)
|
||||
.catch(e => console.error(e));
|
||||
.catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -575,7 +575,7 @@ CSSFilterEditorWidget.prototype = {
|
|||
// If the click happened on the remove button.
|
||||
presets.splice(id, 1);
|
||||
this.setPresets(presets).then(this.renderPresets,
|
||||
ex => console.error(ex));
|
||||
console.error);
|
||||
} else {
|
||||
// Or if the click happened on a preset.
|
||||
let p = presets[id];
|
||||
|
@ -583,7 +583,7 @@ CSSFilterEditorWidget.prototype = {
|
|||
this.setCssValue(p.value);
|
||||
this.addPresetInput.value = p.name;
|
||||
}
|
||||
}, ex => console.error(ex));
|
||||
}, console.error);
|
||||
},
|
||||
|
||||
_togglePresets: function () {
|
||||
|
@ -612,8 +612,8 @@ CSSFilterEditorWidget.prototype = {
|
|||
}
|
||||
|
||||
this.setPresets(presets).then(this.renderPresets,
|
||||
ex => console.error(ex));
|
||||
}, ex => console.error(ex));
|
||||
console.error);
|
||||
}, console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -952,12 +952,12 @@ CSSFilterEditorWidget.prototype = {
|
|||
}
|
||||
|
||||
return presets;
|
||||
}, e => console.error(e));
|
||||
}, console.error);
|
||||
},
|
||||
|
||||
setPresets: function (presets) {
|
||||
return asyncStorage.setItem("cssFilterPresets", presets)
|
||||
.catch(e => console.error(e));
|
||||
.catch(console.error);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -171,7 +171,7 @@ SwatchColorPickerTooltip.prototype = extend(SwatchBasedEditorTooltip.prototype,
|
|||
this.hide();
|
||||
|
||||
this.tooltip.emit("eyedropper-opened");
|
||||
}, e => console.error(e));
|
||||
}, console.error);
|
||||
|
||||
inspector.once("color-picked", color => {
|
||||
toolbox.win.focus();
|
||||
|
|
|
@ -237,7 +237,7 @@ function autoComplete({ ed, cm }) {
|
|||
});
|
||||
popup.openPopup(cursorElement, -1 * left, 0);
|
||||
autocompleteOpts.suggestionInsertedOnce = false;
|
||||
}).catch(e => console.error(e));
|
||||
}).catch(console.error);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -234,7 +234,7 @@ StyleEditorUI.prototype = {
|
|||
_onNewDocument: function () {
|
||||
this._debuggee.getStyleSheets().then((styleSheets) => {
|
||||
return this._resetStyleSheetList(styleSheets);
|
||||
}).catch(e => console.error(e));
|
||||
}).catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -634,7 +634,7 @@ StyleEditorUI.prototype = {
|
|||
this.emit("error", { key: "error-compressed", level: "info" });
|
||||
}
|
||||
}
|
||||
}.bind(this)).catch(e => console.error(e));
|
||||
}.bind(this)).catch(console.error);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
@ -919,7 +919,7 @@ StyleEditorUI.prototype = {
|
|||
sidebar.hidden = !showSidebar || !inSource;
|
||||
|
||||
this.emit("media-list-changed", editor);
|
||||
}.bind(this)).catch(e => console.error(e));
|
||||
}.bind(this)).catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -127,7 +127,7 @@ function StyleSheetEditor(styleSheet, win, file, isNew, walker, highlighter) {
|
|||
this.mediaRules = [];
|
||||
if (this.cssSheet.getMediaRules) {
|
||||
this.cssSheet.getMediaRules().then(this._onMediaRulesChanged,
|
||||
e => console.error(e));
|
||||
console.error);
|
||||
}
|
||||
this.cssSheet.on("media-rules-changed", this._onMediaRulesChanged);
|
||||
this.cssSheet.on("style-applied", this._onStyleApplied);
|
||||
|
@ -518,7 +518,7 @@ StyleSheetEditor.prototype = {
|
|||
* Toggled the disabled state of the underlying stylesheet.
|
||||
*/
|
||||
toggleDisabled: function () {
|
||||
this.styleSheet.toggleDisabled().catch(e => console.error(e));
|
||||
this.styleSheet.toggleDisabled().catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -560,7 +560,7 @@ StyleSheetEditor.prototype = {
|
|||
|
||||
this._isUpdating = true;
|
||||
this.styleSheet.update(this._state.text, this.transitionsEnabled)
|
||||
.catch(e => console.error(e));
|
||||
.catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -3072,7 +3072,7 @@ Widgets.ObjectRenderers.add({
|
|||
// the message is destroyed.
|
||||
this.message.widgets.add(this);
|
||||
|
||||
this.linkToInspector().catch(e => console.error(e));
|
||||
this.linkToInspector().catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -3160,7 +3160,7 @@ Widgets.ObjectRenderers.add({
|
|||
unhighlightDomNode: function () {
|
||||
return this.linkToInspector().then(() => {
|
||||
return this.toolbox.highlighterUtils.unhighlight();
|
||||
}).catch(e => console.error(e));
|
||||
}).catch(console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -97,7 +97,7 @@ function mixedContentOverrideTest2(hud, browser) {
|
|||
objects: true,
|
||||
},
|
||||
],
|
||||
}).then(msgs => deferred.resolve(msgs), e => console.error(e));
|
||||
}).then(msgs => deferred.resolve(msgs), console.error);
|
||||
|
||||
return deferred.promise;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ function CheckLockState() {
|
|||
adbCheckResult.textContent = sNo;
|
||||
adbRootAction.removeAttribute("hidden");
|
||||
}
|
||||
}, e => console.error(e));
|
||||
}, console.error);
|
||||
} else {
|
||||
adbCheckResult.textContent = sUnknown;
|
||||
}
|
||||
|
@ -120,7 +120,7 @@ function CheckLockState() {
|
|||
} else {
|
||||
devtoolsCheckResult.textContent = sYes;
|
||||
}
|
||||
}, e => console.error(e));
|
||||
}, console.error);
|
||||
} catch (e) {
|
||||
// Exception. pref actor is only accessible if forbird-certified-apps is false
|
||||
devtoolsCheckResult.textContent = sNo;
|
||||
|
@ -147,5 +147,5 @@ function EnableCertApps() {
|
|||
|
||||
function RootADB() {
|
||||
let device = AppManager.selectedRuntime.device;
|
||||
device.summonRoot().then(CheckLockState, (e) => console.error(e));
|
||||
device.summonRoot().then(CheckLockState, console.error);
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ The `hasActor` method returns a boolean synchronously.
|
|||
```js
|
||||
toolbox.target.actorHasMethod("domwalker", "duplicateNode").then(hasMethod => {
|
||||
|
||||
}).catch(e => console.error(e));
|
||||
}).catch(console.error);
|
||||
```
|
||||
|
||||
The `actorHasMethod` returns a promise that resolves to a boolean.
|
||||
|
|
|
@ -383,7 +383,7 @@ EyeDropper.prototype = {
|
|||
}
|
||||
|
||||
this.emit("selected", toColorString(this.centerColor, this.format));
|
||||
onColorSelected.then(() => this.hide(), e => console.error(e));
|
||||
onColorSelected.then(() => this.hide(), console.error);
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -1251,7 +1251,7 @@ Front.prototype = extend(Pool.prototype, {
|
|||
this.actor().then(actorID => {
|
||||
packet.to = actorID;
|
||||
this.conn._transport.send(packet);
|
||||
}).catch(e => console.error(e));
|
||||
}).catch(console.error);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ ScrollingLayersHelper::ScrollingLayersHelper(WebRenderLayer* aLayer,
|
|||
PushLayerLocalClip(aStackingContext);
|
||||
}
|
||||
|
||||
PushScrollLayer(fm, aStackingContext);
|
||||
DefineAndPushScrollLayer(fm, aStackingContext);
|
||||
}
|
||||
|
||||
// The scrolled clip on the layer is "inside" all of the scrollable metadatas
|
||||
|
@ -146,10 +146,7 @@ ScrollingLayersHelper::DefineAndPushScrollLayers(nsDisplayItem* aItem,
|
|||
if (!aAsr) {
|
||||
return;
|
||||
}
|
||||
Maybe<ScrollMetadata> metadata = aAsr->mScrollableFrame->ComputeScrollMetadata(
|
||||
nullptr, aItem->ReferenceFrame(), ContainerLayerParameters(), nullptr);
|
||||
MOZ_ASSERT(metadata);
|
||||
FrameMetrics::ViewID scrollId = metadata->GetMetrics().GetScrollId();
|
||||
FrameMetrics::ViewID scrollId = nsLayoutUtils::ViewIDForASR(aAsr);
|
||||
if (aBuilder.TopmostScrollId() == scrollId) {
|
||||
// it's already been pushed, so we don't need to recurse any further.
|
||||
return;
|
||||
|
@ -176,11 +173,19 @@ ScrollingLayersHelper::DefineAndPushScrollLayers(nsDisplayItem* aItem,
|
|||
// push exactly what we want.
|
||||
DefineAndPushChain(asrClippedBy, aBuilder, aStackingContext,
|
||||
aAppUnitsPerDevPixel, aCache);
|
||||
// Finally, push the ASR itself as a scroll layer. Note that the
|
||||
// implementation of wr_push_scroll_layer in bindings.rs makes sure the
|
||||
// scroll layer doesn't get defined multiple times so we don't need to worry
|
||||
// about that here.
|
||||
if (PushScrollLayer(metadata->GetMetrics(), aStackingContext)) {
|
||||
// Finally, push the ASR itself as a scroll layer. If it's already defined
|
||||
// we can skip the expensive step of computing the ScrollMetadata.
|
||||
bool pushed = false;
|
||||
if (mBuilder->IsScrollLayerDefined(scrollId)) {
|
||||
mBuilder->PushScrollLayer(scrollId);
|
||||
pushed = true;
|
||||
} else {
|
||||
Maybe<ScrollMetadata> metadata = aAsr->mScrollableFrame->ComputeScrollMetadata(
|
||||
nullptr, aItem->ReferenceFrame(), ContainerLayerParameters(), nullptr);
|
||||
MOZ_ASSERT(metadata);
|
||||
pushed = DefineAndPushScrollLayer(metadata->GetMetrics(), aStackingContext);
|
||||
}
|
||||
if (pushed) {
|
||||
mPushedClips.push_back(wr::ScrollOrClipId(scrollId));
|
||||
}
|
||||
}
|
||||
|
@ -228,8 +233,8 @@ ScrollingLayersHelper::DefineAndPushChain(const DisplayItemClipChain* aChain,
|
|||
}
|
||||
|
||||
bool
|
||||
ScrollingLayersHelper::PushScrollLayer(const FrameMetrics& aMetrics,
|
||||
const StackingContextHelper& aStackingContext)
|
||||
ScrollingLayersHelper::DefineAndPushScrollLayer(const FrameMetrics& aMetrics,
|
||||
const StackingContextHelper& aStackingContext)
|
||||
{
|
||||
if (!aMetrics.IsScrollable()) {
|
||||
return false;
|
||||
|
@ -251,9 +256,10 @@ ScrollingLayersHelper::PushScrollLayer(const FrameMetrics& aMetrics,
|
|||
// WebRender at all. Instead, we take the position from the composition
|
||||
// bounds.
|
||||
contentRect.MoveTo(clipBounds.TopLeft());
|
||||
mBuilder->PushScrollLayer(aMetrics.GetScrollId(),
|
||||
mBuilder->DefineScrollLayer(aMetrics.GetScrollId(),
|
||||
aStackingContext.ToRelativeLayoutRect(contentRect),
|
||||
aStackingContext.ToRelativeLayoutRect(clipBounds));
|
||||
mBuilder->PushScrollLayer(aMetrics.GetScrollId());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,8 +49,8 @@ private:
|
|||
const StackingContextHelper& aStackingContext,
|
||||
int32_t aAppUnitsPerDevPixel,
|
||||
WebRenderLayerManager::ClipIdMap& aCache);
|
||||
bool PushScrollLayer(const FrameMetrics& aMetrics,
|
||||
const StackingContextHelper& aStackingContext);
|
||||
bool DefineAndPushScrollLayer(const FrameMetrics& aMetrics,
|
||||
const StackingContextHelper& aStackingContext);
|
||||
void PushLayerLocalClip(const StackingContextHelper& aStackingContext);
|
||||
void PushLayerClip(const LayerClip& aClip,
|
||||
const StackingContextHelper& aSc);
|
||||
|
|
|
@ -694,21 +694,39 @@ DisplayListBuilder::PushBuiltDisplayList(BuiltDisplayList &dl)
|
|||
&dl.dl.inner);
|
||||
}
|
||||
|
||||
void
|
||||
DisplayListBuilder::PushScrollLayer(const layers::FrameMetrics::ViewID& aScrollId,
|
||||
const wr::LayoutRect& aContentRect,
|
||||
const wr::LayoutRect& aClipRect)
|
||||
bool
|
||||
DisplayListBuilder::IsScrollLayerDefined(layers::FrameMetrics::ViewID aScrollId) const
|
||||
{
|
||||
WRDL_LOG("PushScrollLayer id=%" PRIu64 " co=%s cl=%s\n", mWrState,
|
||||
return mScrollParents.find(aScrollId) != mScrollParents.end();
|
||||
}
|
||||
|
||||
void
|
||||
DisplayListBuilder::DefineScrollLayer(const layers::FrameMetrics::ViewID& aScrollId,
|
||||
const wr::LayoutRect& aContentRect,
|
||||
const wr::LayoutRect& aClipRect)
|
||||
{
|
||||
WRDL_LOG("DefineScrollLayer id=%" PRIu64 " co=%s cl=%s\n", mWrState,
|
||||
aScrollId, Stringify(aContentRect).c_str(), Stringify(aClipRect).c_str());
|
||||
wr_dp_push_scroll_layer(mWrState, aScrollId, aContentRect, aClipRect);
|
||||
if (!mScrollIdStack.empty()) {
|
||||
auto it = mScrollParents.insert({aScrollId, mScrollIdStack.back()});
|
||||
if (!it.second) { // aScrollId was already a key in mScrollParents
|
||||
// so check that the parent value is the same.
|
||||
MOZ_ASSERT(it.first->second == mScrollIdStack.back());
|
||||
}
|
||||
|
||||
Maybe<layers::FrameMetrics::ViewID> parent =
|
||||
mScrollIdStack.empty() ? Nothing() : Some(mScrollIdStack.back());
|
||||
auto it = mScrollParents.insert({aScrollId, parent});
|
||||
if (it.second) {
|
||||
// An insertion took place, which means we haven't defined aScrollId before.
|
||||
// So let's define it now.
|
||||
wr_dp_define_scroll_layer(mWrState, aScrollId, aContentRect, aClipRect);
|
||||
} else {
|
||||
// aScrollId was already a key in mScrollParents so check that the parent
|
||||
// value is the same.
|
||||
MOZ_ASSERT(it.first->second == parent);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
DisplayListBuilder::PushScrollLayer(const layers::FrameMetrics::ViewID& aScrollId)
|
||||
{
|
||||
WRDL_LOG("PushScrollLayer id=%" PRIu64 "\n", mWrState, aScrollId);
|
||||
wr_dp_push_scroll_layer(mWrState, aScrollId);
|
||||
mScrollIdStack.push_back(aScrollId);
|
||||
}
|
||||
|
||||
|
@ -1027,7 +1045,7 @@ Maybe<layers::FrameMetrics::ViewID>
|
|||
DisplayListBuilder::ParentScrollIdFor(layers::FrameMetrics::ViewID aScrollId)
|
||||
{
|
||||
auto it = mScrollParents.find(aScrollId);
|
||||
return (it == mScrollParents.end() ? Nothing() : Some(it->second));
|
||||
return (it == mScrollParents.end() ? Nothing() : it->second);
|
||||
}
|
||||
|
||||
} // namespace wr
|
||||
|
|
|
@ -203,9 +203,11 @@ public:
|
|||
|
||||
void PushBuiltDisplayList(wr::BuiltDisplayList &dl);
|
||||
|
||||
void PushScrollLayer(const layers::FrameMetrics::ViewID& aScrollId,
|
||||
const wr::LayoutRect& aContentRect, // TODO: We should work with strongly typed rects
|
||||
const wr::LayoutRect& aClipRect);
|
||||
bool IsScrollLayerDefined(layers::FrameMetrics::ViewID aScrollId) const;
|
||||
void DefineScrollLayer(const layers::FrameMetrics::ViewID& aScrollId,
|
||||
const wr::LayoutRect& aContentRect, // TODO: We should work with strongly typed rects
|
||||
const wr::LayoutRect& aClipRect);
|
||||
void PushScrollLayer(const layers::FrameMetrics::ViewID& aScrollId);
|
||||
void PopScrollLayer();
|
||||
|
||||
void PushClipAndScrollInfo(const layers::FrameMetrics::ViewID& aScrollId,
|
||||
|
@ -356,8 +358,10 @@ protected:
|
|||
std::vector<wr::WrClipId> mClipIdStack;
|
||||
std::vector<layers::FrameMetrics::ViewID> mScrollIdStack;
|
||||
|
||||
// Track the parent scroll id of each scroll id that we encountered.
|
||||
std::unordered_map<layers::FrameMetrics::ViewID, layers::FrameMetrics::ViewID> mScrollParents;
|
||||
// Track the parent scroll id of each scroll id that we encountered. A
|
||||
// Nothing() value indicates a root scroll id. We also use this structure to
|
||||
// ensure that we don't define a particular scroll layer multiple times.
|
||||
std::unordered_map<layers::FrameMetrics::ViewID, Maybe<layers::FrameMetrics::ViewID>> mScrollParents;
|
||||
|
||||
friend class WebRenderAPI;
|
||||
};
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use std::collections::HashSet;
|
||||
use std::ffi::CString;
|
||||
use std::{mem, slice};
|
||||
use std::path::PathBuf;
|
||||
|
@ -954,7 +953,6 @@ pub unsafe extern "C" fn wr_api_get_namespace(dh: &mut DocumentHandle) -> WrIdNa
|
|||
pub struct WebRenderFrameBuilder {
|
||||
pub root_pipeline_id: WrPipelineId,
|
||||
pub dl_builder: webrender_api::DisplayListBuilder,
|
||||
pub scroll_clips_defined: HashSet<ClipId>,
|
||||
}
|
||||
|
||||
impl WebRenderFrameBuilder {
|
||||
|
@ -963,7 +961,6 @@ impl WebRenderFrameBuilder {
|
|||
WebRenderFrameBuilder {
|
||||
root_pipeline_id: root_pipeline_id,
|
||||
dl_builder: webrender_api::DisplayListBuilder::new(root_pipeline_id, content_size),
|
||||
scroll_clips_defined: HashSet::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1130,21 +1127,22 @@ pub extern "C" fn wr_dp_pop_clip(state: &mut WrState) {
|
|||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_dp_push_scroll_layer(state: &mut WrState,
|
||||
scroll_id: u64,
|
||||
content_rect: LayoutRect,
|
||||
clip_rect: LayoutRect) {
|
||||
pub extern "C" fn wr_dp_define_scroll_layer(state: &mut WrState,
|
||||
scroll_id: u64,
|
||||
content_rect: LayoutRect,
|
||||
clip_rect: LayoutRect) {
|
||||
assert!(unsafe { is_in_main_thread() });
|
||||
let clip_id = ClipId::new(scroll_id, state.pipeline_id);
|
||||
// Avoid defining multiple scroll clips with the same clip id, as that
|
||||
// results in undefined behaviour or assertion failures.
|
||||
if !state.frame_builder.scroll_clips_defined.contains(&clip_id) {
|
||||
state.frame_builder.dl_builder.define_scroll_frame(
|
||||
Some(clip_id), content_rect, clip_rect, vec![], None,
|
||||
ScrollSensitivity::Script);
|
||||
}
|
||||
|
||||
state.frame_builder.dl_builder.define_scroll_frame(
|
||||
Some(clip_id), content_rect, clip_rect, vec![], None,
|
||||
ScrollSensitivity::Script);
|
||||
state.frame_builder.scroll_clips_defined.insert(clip_id);
|
||||
}
|
||||
#[no_mangle]
|
||||
pub extern "C" fn wr_dp_push_scroll_layer(state: &mut WrState,
|
||||
scroll_id: u64) {
|
||||
assert!(unsafe { is_in_main_thread() });
|
||||
let clip_id = ClipId::new(scroll_id, state.pipeline_id);
|
||||
state.frame_builder.dl_builder.push_clip_id(clip_id);
|
||||
}
|
||||
|
||||
|
|
|
@ -920,6 +920,13 @@ uint64_t wr_dp_define_clip(WrState *aState,
|
|||
const WrImageMask *aMask)
|
||||
WR_FUNC;
|
||||
|
||||
WR_INLINE
|
||||
void wr_dp_define_scroll_layer(WrState *aState,
|
||||
uint64_t aScrollId,
|
||||
LayoutRect aContentRect,
|
||||
LayoutRect aClipRect)
|
||||
WR_FUNC;
|
||||
|
||||
WR_INLINE
|
||||
void wr_dp_end(WrState *aState)
|
||||
WR_FUNC;
|
||||
|
@ -1087,9 +1094,7 @@ WR_FUNC;
|
|||
|
||||
WR_INLINE
|
||||
void wr_dp_push_scroll_layer(WrState *aState,
|
||||
uint64_t aScrollId,
|
||||
LayoutRect aContentRect,
|
||||
LayoutRect aClipRect)
|
||||
uint64_t aScrollId)
|
||||
WR_FUNC;
|
||||
|
||||
WR_INLINE
|
||||
|
|
|
@ -397,11 +397,7 @@ var Addons = {
|
|||
// Allow the options to use all the available width space.
|
||||
optionsBox.classList.remove("inner");
|
||||
|
||||
// WebExtensions are loaded asynchronously and the optionsURL
|
||||
// may not be available via listitem when the add-on has just been
|
||||
// installed, but it is available on the addon if one is set.
|
||||
detailItem.setAttribute("optionsURL", addon.optionsURL);
|
||||
this.createWebExtensionOptions(optionsBox, addon.optionsURL, addon.optionsBrowserStyle);
|
||||
this.createWebExtensionOptions(optionsBox, addon);
|
||||
break;
|
||||
case AddonManager.OPTIONS_TYPE_TAB:
|
||||
// Keep the usual layout for any options related the legacy (or system) add-ons
|
||||
|
@ -441,44 +437,58 @@ var Addons = {
|
|||
}
|
||||
|
||||
button.onclick = async () => {
|
||||
if (addon.isWebExtension) {
|
||||
// WebExtensions are loaded asynchronously and the optionsURL
|
||||
// may not be available until the addon has been started.
|
||||
await addon.startupPromise;
|
||||
}
|
||||
|
||||
const {optionsURL} = addon;
|
||||
openOptionsInTab(optionsURL);
|
||||
};
|
||||
},
|
||||
|
||||
createWebExtensionOptions: async function(destination, optionsURL, browserStyle) {
|
||||
let originalHeight;
|
||||
let frame = document.createElement("iframe");
|
||||
frame.setAttribute("id", "addon-options");
|
||||
frame.setAttribute("mozbrowser", "true");
|
||||
frame.setAttribute("style", "width: 100%; overflow: hidden;");
|
||||
createWebExtensionOptions: async function(destination, addon) {
|
||||
// WebExtensions are loaded asynchronously and the optionsURL
|
||||
// may not be available until the addon has been started.
|
||||
await addon.startupPromise;
|
||||
|
||||
// Adjust iframe height to the iframe content (also between navigation of multiple options
|
||||
// files).
|
||||
frame.onload = (evt) => {
|
||||
if (evt.target !== frame) {
|
||||
return;
|
||||
}
|
||||
const {optionsURL, optionsBrowserStyle} = addon;
|
||||
let frame = destination.querySelector("iframe#addon-options");
|
||||
|
||||
const {document} = frame.contentWindow;
|
||||
const bodyScrollHeight = document.body && document.body.scrollHeight;
|
||||
const documentScrollHeight = document.documentElement.scrollHeight;
|
||||
if (!frame) {
|
||||
let originalHeight;
|
||||
frame = document.createElement("iframe");
|
||||
frame.setAttribute("id", "addon-options");
|
||||
frame.setAttribute("mozbrowser", "true");
|
||||
frame.setAttribute("style", "width: 100%; overflow: hidden;");
|
||||
|
||||
// Set the iframe height to the maximum between the body and the document
|
||||
// scrollHeight values.
|
||||
frame.style.height = Math.max(bodyScrollHeight, documentScrollHeight) + "px";
|
||||
// Adjust iframe height to the iframe content (also between navigation of multiple options
|
||||
// files).
|
||||
frame.onload = (evt) => {
|
||||
if (evt.target !== frame) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Restore the original iframe height between option page loads,
|
||||
// so that we don't force the new document to have the same size
|
||||
// of the previosuly loaded option page.
|
||||
frame.contentWindow.addEventListener("unload", () => {
|
||||
frame.style.height = originalHeight + "px";
|
||||
}, {once: true});
|
||||
};
|
||||
const {document} = frame.contentWindow;
|
||||
const bodyScrollHeight = document.body && document.body.scrollHeight;
|
||||
const documentScrollHeight = document.documentElement.scrollHeight;
|
||||
|
||||
destination.appendChild(frame);
|
||||
// Set the iframe height to the maximum between the body and the document
|
||||
// scrollHeight values.
|
||||
frame.style.height = Math.max(bodyScrollHeight, documentScrollHeight) + "px";
|
||||
|
||||
originalHeight = frame.getBoundingClientRect().height;
|
||||
// Restore the original iframe height between option page loads,
|
||||
// so that we don't force the new document to have the same size
|
||||
// of the previosuly loaded option page.
|
||||
frame.contentWindow.addEventListener("unload", () => {
|
||||
frame.style.height = originalHeight + "px";
|
||||
}, {once: true});
|
||||
};
|
||||
|
||||
destination.appendChild(frame);
|
||||
originalHeight = frame.getBoundingClientRect().height;
|
||||
}
|
||||
|
||||
// Loading the URL this way prevents the native back
|
||||
// button from applying to the iframe.
|
||||
|
@ -585,6 +595,14 @@ var Addons = {
|
|||
detailItem.setAttribute("opType", opType);
|
||||
else
|
||||
detailItem.removeAttribute("opType");
|
||||
|
||||
// Remove any addon options iframe if the currently selected addon has been disabled.
|
||||
if (!aValue) {
|
||||
const addonOptionsIframe = document.querySelector("#addon-options");
|
||||
if (addonOptionsIframe) {
|
||||
addonOptionsIframe.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sync to the list item
|
||||
|
|
|
@ -84,6 +84,14 @@ function waitAboutAddonsLoaded() {
|
|||
return waitDOMContentLoaded(url => url === "about:addons");
|
||||
}
|
||||
|
||||
function clickAddonDisable() {
|
||||
content.document.querySelector("#disable-btn").click();
|
||||
}
|
||||
|
||||
function clickAddonEnable() {
|
||||
content.document.querySelector("#enable-btn").click();
|
||||
}
|
||||
|
||||
add_task(async function test_options_ui_iframe_height() {
|
||||
let addonID = "test-options-ui@mozilla.org";
|
||||
|
||||
|
@ -406,6 +414,86 @@ add_task(async function test_options_ui_open_in_tab() {
|
|||
await extension.unload();
|
||||
});
|
||||
|
||||
add_task(async function test_options_ui_on_disable_and_enable() {
|
||||
let addonID = "test-options-ui-disable-enable@mozilla.org";
|
||||
|
||||
function optionsScript() {
|
||||
browser.test.sendMessage("options-page-loaded", window.location.href);
|
||||
}
|
||||
|
||||
let extension = ExtensionTestUtils.loadExtension({
|
||||
useAddonManager: "temporary",
|
||||
manifest: {
|
||||
applications: {
|
||||
gecko: {id: addonID},
|
||||
},
|
||||
name: "Options UI open addon details Extension",
|
||||
description: "Longer addon description",
|
||||
options_ui: {
|
||||
page: "options.html",
|
||||
},
|
||||
},
|
||||
files: {
|
||||
"options.js": optionsScript,
|
||||
"options.html": `<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
</head>
|
||||
<body>
|
||||
<h1>Options page</h1>
|
||||
<script src="options.js"><\/script>
|
||||
</body>
|
||||
</html>
|
||||
`,
|
||||
},
|
||||
});
|
||||
|
||||
await extension.startup();
|
||||
|
||||
const {BrowserApp} = Services.wm.getMostRecentWindow("navigator:browser");
|
||||
|
||||
let onceAboutAddonsLoaded = waitAboutAddonsLoaded();
|
||||
|
||||
BrowserApp.addTab("about:addons", {
|
||||
selected: true,
|
||||
parentId: BrowserApp.selectedTab.id,
|
||||
});
|
||||
|
||||
await onceAboutAddonsLoaded;
|
||||
|
||||
const aboutAddonsTab = BrowserApp.selectedTab;
|
||||
|
||||
is(aboutAddonsTab.currentURI.spec, "about:addons",
|
||||
"about:addons is the currently selected tab");
|
||||
|
||||
info("Wait the addon details to have been loaded");
|
||||
await ContentTask.spawn(aboutAddonsTab.browser, addonID, waitAboutAddonsRendered);
|
||||
await ContentTask.spawn(aboutAddonsTab.browser, addonID, navigateToAddonDetails);
|
||||
|
||||
info("Wait the addon options page to have been loaded");
|
||||
await extension.awaitMessage("options-page-loaded");
|
||||
|
||||
info("Click the addon disable button");
|
||||
await ContentTask.spawn(aboutAddonsTab.browser, null, clickAddonDisable);
|
||||
|
||||
// NOTE: Currently after disabling the addon the extension.awaitMessage seems
|
||||
// to fail be able to receive events coming from the browser.test.sendMessage API
|
||||
// (nevertheless `await extension.unload()` seems to be able to remove the extension),
|
||||
// falling back to wait for the options page to be loaded here.
|
||||
const onceAddonOptionsLoaded = waitDOMContentLoaded(url => url.endsWith("options.html"));
|
||||
|
||||
info("Click the addon enable button");
|
||||
await ContentTask.spawn(aboutAddonsTab.browser, null, clickAddonEnable);
|
||||
|
||||
info("Wait the addon options page to have been loaded after clicking the addon enable button");
|
||||
await onceAddonOptionsLoaded;
|
||||
|
||||
BrowserApp.closeTab(BrowserApp.selectedTab);
|
||||
|
||||
await extension.unload();
|
||||
});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -1140,4 +1140,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
|
|||
|
||||
static const int32_t kUnknownId = -1;
|
||||
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1512494652111000);
|
||||
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1512667462291000);
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -2064,6 +2064,9 @@ class IDLType(IDLObject):
|
|||
def isRecord(self):
|
||||
return False
|
||||
|
||||
def isReadableStream(self):
|
||||
return False
|
||||
|
||||
def isArrayBuffer(self):
|
||||
return False
|
||||
|
||||
|
@ -2091,12 +2094,12 @@ class IDLType(IDLObject):
|
|||
|
||||
def isSpiderMonkeyInterface(self):
|
||||
""" Returns a boolean indicating whether this type is an 'interface'
|
||||
type that is implemented in Spidermonkey. At the moment, this
|
||||
only returns true for the types from the TypedArray spec. """
|
||||
type that is implemented in SpiderMonkey. """
|
||||
return self.isInterface() and (self.isArrayBuffer() or
|
||||
self.isArrayBufferView() or
|
||||
self.isSharedArrayBuffer() or
|
||||
self.isTypedArray())
|
||||
self.isTypedArray() or
|
||||
self.isReadableStream())
|
||||
|
||||
def isDictionary(self):
|
||||
return False
|
||||
|
@ -2289,6 +2292,9 @@ class IDLNullableType(IDLParametrizedType):
|
|||
def isRecord(self):
|
||||
return self.inner.isRecord()
|
||||
|
||||
def isReadableStream(self):
|
||||
return self.inner.isReadableStream()
|
||||
|
||||
def isArrayBuffer(self):
|
||||
return self.inner.isArrayBuffer()
|
||||
|
||||
|
@ -2656,6 +2662,9 @@ class IDLTypedefType(IDLType):
|
|||
def isRecord(self):
|
||||
return self.inner.isRecord()
|
||||
|
||||
def isReadableStream(self):
|
||||
return self.inner.isReadableStream()
|
||||
|
||||
def isDictionary(self):
|
||||
return self.inner.isDictionary()
|
||||
|
||||
|
@ -2970,7 +2979,8 @@ class IDLBuiltinType(IDLType):
|
|||
'Int32Array',
|
||||
'Uint32Array',
|
||||
'Float32Array',
|
||||
'Float64Array'
|
||||
'Float64Array',
|
||||
'ReadableStream',
|
||||
)
|
||||
|
||||
TagLookup = {
|
||||
|
@ -3005,7 +3015,8 @@ class IDLBuiltinType(IDLType):
|
|||
Types.Int32Array: IDLType.Tags.interface,
|
||||
Types.Uint32Array: IDLType.Tags.interface,
|
||||
Types.Float32Array: IDLType.Tags.interface,
|
||||
Types.Float64Array: IDLType.Tags.interface
|
||||
Types.Float64Array: IDLType.Tags.interface,
|
||||
Types.ReadableStream: IDLType.Tags.interface,
|
||||
}
|
||||
|
||||
def __init__(self, location, name, type):
|
||||
|
@ -3052,6 +3063,9 @@ class IDLBuiltinType(IDLType):
|
|||
return (self._typeTag >= IDLBuiltinType.Types.Int8Array and
|
||||
self._typeTag <= IDLBuiltinType.Types.Float64Array)
|
||||
|
||||
def isReadableStream(self):
|
||||
return self._typeTag == IDLBuiltinType.Types.ReadableStream
|
||||
|
||||
def isInterface(self):
|
||||
# TypedArray things are interface types per the TypedArray spec,
|
||||
# but we handle them as builtins because SpiderMonkey implements
|
||||
|
@ -3059,7 +3073,8 @@ class IDLBuiltinType(IDLType):
|
|||
return (self.isArrayBuffer() or
|
||||
self.isArrayBufferView() or
|
||||
self.isSharedArrayBuffer() or
|
||||
self.isTypedArray())
|
||||
self.isTypedArray() or
|
||||
self.isReadableStream())
|
||||
|
||||
def isNonCallbackInterface(self):
|
||||
# All the interfaces we can be are non-callback
|
||||
|
@ -3129,6 +3144,7 @@ class IDLBuiltinType(IDLType):
|
|||
# that's not an ArrayBuffer or a callback interface
|
||||
(self.isArrayBuffer() and not other.isArrayBuffer()) or
|
||||
(self.isSharedArrayBuffer() and not other.isSharedArrayBuffer()) or
|
||||
(self.isReadableStream() and not other.isReadableStream()) or
|
||||
# ArrayBufferView is distinguishable from everything
|
||||
# that's not an ArrayBufferView or typed array.
|
||||
(self.isArrayBufferView() and not other.isArrayBufferView() and
|
||||
|
@ -3238,7 +3254,10 @@ BuiltinTypes = {
|
|||
IDLBuiltinType.Types.Float32Array),
|
||||
IDLBuiltinType.Types.Float64Array:
|
||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "Float64Array",
|
||||
IDLBuiltinType.Types.Float64Array)
|
||||
IDLBuiltinType.Types.Float64Array),
|
||||
IDLBuiltinType.Types.ReadableStream:
|
||||
IDLBuiltinType(BuiltinLocation("<builtin type>"), "ReadableStream",
|
||||
IDLBuiltinType.Types.ReadableStream),
|
||||
}
|
||||
|
||||
|
||||
|
@ -5287,7 +5306,8 @@ class Tokenizer(object):
|
|||
"maplike": "MAPLIKE",
|
||||
"setlike": "SETLIKE",
|
||||
"iterable": "ITERABLE",
|
||||
"namespace": "NAMESPACE"
|
||||
"namespace": "NAMESPACE",
|
||||
"ReadableStream": "READABLESTREAM",
|
||||
}
|
||||
|
||||
tokens.extend(keywords.values())
|
||||
|
@ -6475,6 +6495,7 @@ class Parser(Tokenizer):
|
|||
NonAnyType : PrimitiveType Null
|
||||
| ARRAYBUFFER Null
|
||||
| SHAREDARRAYBUFFER Null
|
||||
| READABLESTREAM Null
|
||||
| OBJECT Null
|
||||
"""
|
||||
if p[1] == "object":
|
||||
|
@ -6483,6 +6504,8 @@ class Parser(Tokenizer):
|
|||
type = BuiltinTypes[IDLBuiltinType.Types.ArrayBuffer]
|
||||
elif p[1] == "SharedArrayBuffer":
|
||||
type = BuiltinTypes[IDLBuiltinType.Types.SharedArrayBuffer]
|
||||
elif p[1] == "ReadableStream":
|
||||
type = BuiltinTypes[IDLBuiltinType.Types.ReadableStream]
|
||||
else:
|
||||
type = BuiltinTypes[p[1]]
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
|||
Cu.import("chrome://marionette/content/assert.js");
|
||||
Cu.import("chrome://marionette/content/element.js");
|
||||
const {
|
||||
error,
|
||||
pprint,
|
||||
InvalidArgumentError,
|
||||
MoveTargetOutOfBoundsError,
|
||||
UnsupportedOperationError,
|
||||
|
@ -21,8 +21,6 @@ Cu.import("chrome://marionette/content/interaction.js");
|
|||
|
||||
this.EXPORTED_SYMBOLS = ["action"];
|
||||
|
||||
const {pprint} = error;
|
||||
|
||||
// TODO? With ES 2016 and Symbol you can make a safer approximation
|
||||
// to an enum e.g. https://gist.github.com/xmlking/e86e4f15ec32b12c4689
|
||||
/**
|
||||
|
|
|
@ -11,10 +11,10 @@ Cu.import("resource://gre/modules/Preferences.jsm");
|
|||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const {
|
||||
error,
|
||||
InvalidArgumentError,
|
||||
InvalidSessionIDError,
|
||||
NoSuchWindowError,
|
||||
pprint,
|
||||
UnexpectedAlertOpenError,
|
||||
UnsupportedOperationError,
|
||||
} = Cu.import("chrome://marionette/content/error.js", {});
|
||||
|
@ -174,7 +174,7 @@ assert.noUserPrompt = function(dialog, msg = "") {
|
|||
* If |obj| is not defined.
|
||||
*/
|
||||
assert.defined = function(obj, msg = "") {
|
||||
msg = msg || error.pprint`Expected ${obj} to be defined`;
|
||||
msg = msg || pprint`Expected ${obj} to be defined`;
|
||||
return assert.that(o => typeof o != "undefined", msg)(obj);
|
||||
};
|
||||
|
||||
|
@ -193,7 +193,7 @@ assert.defined = function(obj, msg = "") {
|
|||
* If |obj| is not a number.
|
||||
*/
|
||||
assert.number = function(obj, msg = "") {
|
||||
msg = msg || error.pprint`Expected ${obj} to be finite number`;
|
||||
msg = msg || pprint`Expected ${obj} to be finite number`;
|
||||
return assert.that(Number.isFinite, msg)(obj);
|
||||
};
|
||||
|
||||
|
@ -212,7 +212,7 @@ assert.number = function(obj, msg = "") {
|
|||
* If |obj| is not callable.
|
||||
*/
|
||||
assert.callable = function(obj, msg = "") {
|
||||
msg = msg || error.pprint`${obj} is not callable`;
|
||||
msg = msg || pprint`${obj} is not callable`;
|
||||
return assert.that(o => typeof o == "function", msg)(obj);
|
||||
};
|
||||
|
||||
|
@ -231,7 +231,7 @@ assert.callable = function(obj, msg = "") {
|
|||
* If |obj| is not an integer.
|
||||
*/
|
||||
assert.integer = function(obj, msg = "") {
|
||||
msg = msg || error.pprint`Expected ${obj} to be an integer`;
|
||||
msg = msg || pprint`Expected ${obj} to be an integer`;
|
||||
return assert.that(Number.isInteger, msg)(obj);
|
||||
};
|
||||
|
||||
|
@ -251,7 +251,7 @@ assert.integer = function(obj, msg = "") {
|
|||
*/
|
||||
assert.positiveInteger = function(obj, msg = "") {
|
||||
assert.integer(obj, msg);
|
||||
msg = msg || error.pprint`Expected ${obj} to be >= 0`;
|
||||
msg = msg || pprint`Expected ${obj} to be >= 0`;
|
||||
return assert.that(n => n >= 0, msg)(obj);
|
||||
};
|
||||
|
||||
|
@ -270,7 +270,7 @@ assert.positiveInteger = function(obj, msg = "") {
|
|||
* If |obj| is not a boolean.
|
||||
*/
|
||||
assert.boolean = function(obj, msg = "") {
|
||||
msg = msg || error.pprint`Expected ${obj} to be boolean`;
|
||||
msg = msg || pprint`Expected ${obj} to be boolean`;
|
||||
return assert.that(b => typeof b == "boolean", msg)(obj);
|
||||
};
|
||||
|
||||
|
@ -289,7 +289,7 @@ assert.boolean = function(obj, msg = "") {
|
|||
* If |obj| is not a string.
|
||||
*/
|
||||
assert.string = function(obj, msg = "") {
|
||||
msg = msg || error.pprint`Expected ${obj} to be a string`;
|
||||
msg = msg || pprint`Expected ${obj} to be a string`;
|
||||
return assert.that(s => typeof s == "string", msg)(obj);
|
||||
};
|
||||
|
||||
|
@ -308,7 +308,7 @@ assert.string = function(obj, msg = "") {
|
|||
* If |obj| is not an object.
|
||||
*/
|
||||
assert.object = function(obj, msg = "") {
|
||||
msg = msg || error.pprint`Expected ${obj} to be an object`;
|
||||
msg = msg || pprint`Expected ${obj} to be an object`;
|
||||
return assert.that(o => {
|
||||
// unable to use instanceof because LHS and RHS may come from
|
||||
// different globals
|
||||
|
@ -335,7 +335,7 @@ assert.object = function(obj, msg = "") {
|
|||
*/
|
||||
assert.in = function(prop, obj, msg = "") {
|
||||
assert.object(obj, msg);
|
||||
msg = msg || error.pprint`Expected ${prop} in ${obj}`;
|
||||
msg = msg || pprint`Expected ${prop} in ${obj}`;
|
||||
assert.that(p => obj.hasOwnProperty(p), msg)(prop);
|
||||
return obj[prop];
|
||||
};
|
||||
|
@ -355,7 +355,7 @@ assert.in = function(prop, obj, msg = "") {
|
|||
* If |obj| is not an Array.
|
||||
*/
|
||||
assert.array = function(obj, msg = "") {
|
||||
msg = msg || error.pprint`Expected ${obj} to be an Array`;
|
||||
msg = msg || pprint`Expected ${obj} to be an Array`;
|
||||
return assert.that(Array.isArray, msg)(obj);
|
||||
};
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||
|
||||
Cu.import("chrome://marionette/content/assert.js");
|
||||
const {
|
||||
error,
|
||||
InvalidCookieDomainError,
|
||||
pprint,
|
||||
} = Cu.import("chrome://marionette/content/error.js", {});
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["cookie"];
|
||||
|
@ -53,7 +53,7 @@ this.cookie = {
|
|||
cookie.fromJSON = function(json) {
|
||||
let newCookie = {};
|
||||
|
||||
assert.object(json, error.pprint`Expected cookie object, got ${json}`);
|
||||
assert.object(json, pprint`Expected cookie object, got ${json}`);
|
||||
|
||||
newCookie.name = assert.string(json.name, "Cookie name must be string");
|
||||
newCookie.value = assert.string(json.value, "Cookie value must be string");
|
||||
|
|
|
@ -12,10 +12,10 @@ Cu.import("resource://gre/modules/Log.jsm");
|
|||
Cu.import("chrome://marionette/content/assert.js");
|
||||
Cu.import("chrome://marionette/content/atom.js");
|
||||
const {
|
||||
error,
|
||||
InvalidSelectorError,
|
||||
JavaScriptError,
|
||||
NoSuchElementError,
|
||||
pprint,
|
||||
StaleElementReferenceError,
|
||||
} = Cu.import("chrome://marionette/content/error.js", {});
|
||||
Cu.import("chrome://marionette/content/wait.js");
|
||||
|
@ -180,7 +180,7 @@ element.Store = class {
|
|||
|
||||
if (element.isStale(el)) {
|
||||
throw new StaleElementReferenceError(
|
||||
error.pprint`The element reference of ${el} stale; ` +
|
||||
pprint`The element reference of ${el} stale; ` +
|
||||
"either the element is no longer attached to the DOM " +
|
||||
"or the document has been refreshed");
|
||||
}
|
||||
|
|
|
@ -45,7 +45,11 @@ const BUILTIN_ERRORS = new Set([
|
|||
"URIError",
|
||||
]);
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["error", "error.pprint"].concat(Array.from(ERRORS));
|
||||
this.EXPORTED_SYMBOLS = [
|
||||
"error",
|
||||
"pprint",
|
||||
"stack",
|
||||
].concat(Array.from(ERRORS));
|
||||
|
||||
/** @namespace */
|
||||
this.error = {};
|
||||
|
@ -158,7 +162,7 @@ error.stringify = function(err) {
|
|||
* pprint`Expected element ${htmlElement}`;
|
||||
* => 'Expected element <input id="foo" class="bar baz">'
|
||||
*/
|
||||
error.pprint = function(ss, ...values) {
|
||||
this.pprint = function(ss, ...values) {
|
||||
function prettyObject(obj) {
|
||||
let proto = Object.prototype.toString.call(obj);
|
||||
let s = "";
|
||||
|
@ -212,6 +216,14 @@ error.pprint = function(ss, ...values) {
|
|||
return res.join("");
|
||||
};
|
||||
|
||||
/** Create a stacktrace to the current line in the program. */
|
||||
this.stack = function() {
|
||||
let trace = new Error().stack;
|
||||
let sa = trace.split("\n");
|
||||
sa = sa.slice(1);
|
||||
return "stacktrace:\n" + sa.join("\n");
|
||||
};
|
||||
|
||||
/**
|
||||
* WebDriverError is the prototypal parent of all WebDriver errors.
|
||||
* It should not be used directly, as it does not correspond to a real
|
||||
|
@ -305,17 +317,17 @@ class ElementClickInterceptedError extends WebDriverError {
|
|||
|
||||
switch (obscuredEl.style.pointerEvents) {
|
||||
case "none":
|
||||
msg = error.pprint`Element ${obscuredEl} is not clickable ` +
|
||||
msg = pprint`Element ${obscuredEl} is not clickable ` +
|
||||
`at point (${coords.x},${coords.y}) ` +
|
||||
`because it does not have pointer events enabled, ` +
|
||||
error.pprint`and element ${overlayingEl} ` +
|
||||
pprint`and element ${overlayingEl} ` +
|
||||
`would receive the click instead`;
|
||||
break;
|
||||
|
||||
default:
|
||||
msg = error.pprint`Element ${obscuredEl} is not clickable ` +
|
||||
msg = pprint`Element ${obscuredEl} is not clickable ` +
|
||||
`at point (${coords.x},${coords.y}) ` +
|
||||
error.pprint`because another element ${overlayingEl} ` +
|
||||
pprint`because another element ${overlayingEl} ` +
|
||||
`obscures it`;
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ Cu.import("chrome://marionette/content/atom.js");
|
|||
const {
|
||||
ElementClickInterceptedError,
|
||||
ElementNotInteractableError,
|
||||
error,
|
||||
InvalidArgument,
|
||||
InvalidArgumentError,
|
||||
InvalidElementStateError,
|
||||
|
@ -178,7 +177,7 @@ async function webdriverClickElement(el, a11y) {
|
|||
// there is no point in checking if it is pointer-interactable
|
||||
if (!element.isInView(containerEl)) {
|
||||
throw new ElementNotInteractableError(
|
||||
error.pprint`Element ${el} could not be scrolled into view`);
|
||||
pprint`Element ${el} could not be scrolled into view`);
|
||||
}
|
||||
|
||||
// step 7
|
||||
|
|
|
@ -4,7 +4,36 @@
|
|||
|
||||
const {utils: Cu} = Components;
|
||||
|
||||
Cu.import("chrome://marionette/content/error.js");
|
||||
const {
|
||||
ElementClickInterceptedError,
|
||||
ElementNotAccessibleError,
|
||||
ElementNotInteractableError,
|
||||
error,
|
||||
InsecureCertificateError,
|
||||
InvalidArgumentError,
|
||||
InvalidCookieDomainError,
|
||||
InvalidElementStateError,
|
||||
InvalidSelectorError,
|
||||
InvalidSessionIDError,
|
||||
JavaScriptError,
|
||||
MoveTargetOutOfBoundsError,
|
||||
NoAlertOpenError,
|
||||
NoSuchElementError,
|
||||
NoSuchFrameError,
|
||||
NoSuchWindowError,
|
||||
pprint,
|
||||
ScriptTimeoutError,
|
||||
SessionNotCreatedError,
|
||||
stack,
|
||||
StaleElementReferenceError,
|
||||
TimeoutError,
|
||||
UnableToSetCookieError,
|
||||
UnexpectedAlertOpenError,
|
||||
UnknownCommandError,
|
||||
UnknownError,
|
||||
UnsupportedOperationError,
|
||||
WebDriverError,
|
||||
} = Cu.import("chrome://marionette/content/error.js", {});
|
||||
|
||||
function notok(condition) {
|
||||
ok(!(condition));
|
||||
|
@ -90,19 +119,19 @@ add_test(function test_stringify() {
|
|||
});
|
||||
|
||||
add_test(function test_pprint() {
|
||||
equal('[object Object] {"foo":"bar"}', error.pprint`${{foo: "bar"}}`);
|
||||
equal('[object Object] {"foo":"bar"}', pprint`${{foo: "bar"}}`);
|
||||
|
||||
equal("[object Number] 42", error.pprint`${42}`);
|
||||
equal("[object Boolean] true", error.pprint`${true}`);
|
||||
equal("[object Undefined] undefined", error.pprint`${undefined}`);
|
||||
equal("[object Null] null", error.pprint`${null}`);
|
||||
equal("[object Number] 42", pprint`${42}`);
|
||||
equal("[object Boolean] true", pprint`${true}`);
|
||||
equal("[object Undefined] undefined", pprint`${undefined}`);
|
||||
equal("[object Null] null", pprint`${null}`);
|
||||
|
||||
let complexObj = {toJSON: () => "foo"};
|
||||
equal('[object Object] "foo"', error.pprint`${complexObj}`);
|
||||
equal('[object Object] "foo"', pprint`${complexObj}`);
|
||||
|
||||
let cyclic = {};
|
||||
cyclic.me = cyclic;
|
||||
equal("[object Object] <cyclic object value>", error.pprint`${cyclic}`);
|
||||
equal("[object Object] <cyclic object value>", pprint`${cyclic}`);
|
||||
|
||||
let el = {
|
||||
nodeType: 1,
|
||||
|
@ -111,7 +140,15 @@ add_test(function test_pprint() {
|
|||
classList: {length: 1},
|
||||
className: "bar baz",
|
||||
};
|
||||
equal('<input id="foo" class="bar baz">', error.pprint`${el}`);
|
||||
equal('<input id="foo" class="bar baz">', pprint`${el}`);
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
||||
add_test(function test_stack() {
|
||||
equal("string", typeof stack());
|
||||
ok(stack().includes("test_stack"));
|
||||
ok(!stack().includes("add_test"));
|
||||
|
||||
run_next_test();
|
||||
});
|
||||
|
|
|
@ -217,19 +217,24 @@ class Talos(TestingMixin, MercurialScript, BlobUploadMixin, TooltoolMixin,
|
|||
opts = None
|
||||
|
||||
if opts:
|
||||
# In the case of a multi-line commit message, only examine
|
||||
# the first line for mozharness options
|
||||
opts = opts.split('\n')[0]
|
||||
opts = re.sub(r'\w+:.*', '', opts).strip().split(' ')
|
||||
if "--geckoProfile" in opts:
|
||||
# overwrite whatever was set here.
|
||||
self.gecko_profile = True
|
||||
try:
|
||||
idx = opts.index('--geckoProfileInterval')
|
||||
if len(opts) > idx + 1:
|
||||
self.gecko_profile_interval = opts[idx + 1]
|
||||
except ValueError:
|
||||
pass
|
||||
# In the case of a multi-line commit message, only examine
|
||||
# the first line for mozharness options
|
||||
opts = opts.split('\n')[0]
|
||||
opts = re.sub(r'\w+:.*', '', opts).strip().split(' ')
|
||||
if "--geckoProfile" in opts:
|
||||
# overwrite whatever was set here.
|
||||
self.gecko_profile = True
|
||||
try:
|
||||
idx = opts.index('--geckoProfileInterval')
|
||||
if len(opts) > idx + 1:
|
||||
self.gecko_profile_interval = opts[idx + 1]
|
||||
except ValueError:
|
||||
pass
|
||||
else:
|
||||
# no opts, check for '--geckoProfile' in try message text directly
|
||||
if self.try_message_has_flag('geckoProfile'):
|
||||
self.gecko_profile = True
|
||||
|
||||
# finally, if gecko_profile is set, we add that to the talos options
|
||||
if self.gecko_profile:
|
||||
gecko_results.append('--geckoProfile')
|
||||
|
|
|
@ -163,8 +163,14 @@ class TryToolsMixin(TransferMixin):
|
|||
repo_path = None
|
||||
if self.buildbot_config and 'properties' in self.buildbot_config:
|
||||
repo_path = self.buildbot_config['properties'].get('branch')
|
||||
return (self.config.get('branch', repo_path) == 'try' or
|
||||
'TRY_COMMIT_MSG' in os.environ)
|
||||
get_branch = self.config.get('branch', repo_path)
|
||||
if get_branch is not None:
|
||||
on_try = ('try' in get_branch or 'Try' in get_branch)
|
||||
elif os.environ is not None:
|
||||
on_try = ('TRY_COMMIT_MSG' in os.environ)
|
||||
else:
|
||||
on_try = False
|
||||
return on_try
|
||||
|
||||
@PostScriptAction('download-and-extract')
|
||||
def set_extra_try_arguments(self, action, success=None):
|
||||
|
|
|
@ -207,14 +207,15 @@ this.PlacesTestUtils = Object.freeze({
|
|||
* @resolves Returns the field value.
|
||||
* @rejects JavaScript exception.
|
||||
*/
|
||||
async fieldInDB(aURI, field) {
|
||||
fieldInDB(aURI, field) {
|
||||
let url = aURI instanceof Ci.nsIURI ? new URL(aURI.spec) : new URL(aURI);
|
||||
let db = await PlacesUtils.promiseDBConnection();
|
||||
let rows = await db.executeCached(
|
||||
`SELECT ${field} FROM moz_places
|
||||
WHERE url_hash = hash(:url) AND url = :url`,
|
||||
{ url: url.href });
|
||||
return rows[0].getResultByIndex(0);
|
||||
return PlacesUtils.withConnectionWrapper("PlacesTestUtils.jsm: fieldInDb", async db => {
|
||||
let rows = await db.executeCached(
|
||||
`SELECT ${field} FROM moz_places
|
||||
WHERE url_hash = hash(:url) AND url = :url`,
|
||||
{ url: url.href });
|
||||
return rows[0].getResultByIndex(0);
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -2639,6 +2639,46 @@ profiler_get_buffer_info_helper(uint32_t* aCurrentPosition,
|
|||
*aGeneration = ActivePS::Buffer(lock).mGeneration;
|
||||
}
|
||||
|
||||
static void
|
||||
PollJSSamplingForCurrentThread()
|
||||
{
|
||||
MOZ_RELEASE_ASSERT(CorePS::Exists());
|
||||
|
||||
PSAutoLock lock(gPSMutex);
|
||||
|
||||
ThreadInfo* info = TLSInfo::Info(lock);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
info->PollJSSampling();
|
||||
}
|
||||
|
||||
// When the profiler is started on a background thread, we can't synchronously
|
||||
// call PollJSSampling on the main thread's ThreadInfo. And the next regular
|
||||
// call to PollJSSampling on the main thread would only happen once the main
|
||||
// thread triggers a JS interrupt callback.
|
||||
// This means that all the JS execution between profiler_start() and the first
|
||||
// JS interrupt would happen with JS sampling disabled, and we wouldn't get any
|
||||
// JS function information for that period of time.
|
||||
// So in order to start JS sampling as soon as possible, we dispatch a runnable
|
||||
// to the main thread which manually calls PollJSSamplingForCurrentThread().
|
||||
// In some cases this runnable will lose the race with the next JS interrupt.
|
||||
// That's fine; PollJSSamplingForCurrentThread() is immune to redundant calls.
|
||||
static void
|
||||
TriggerPollJSSamplingOnMainThread()
|
||||
{
|
||||
nsCOMPtr<nsIThread> mainThread;
|
||||
nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
|
||||
if (NS_SUCCEEDED(rv) && mainThread) {
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableFunction("TriggerPollJSSamplingOnMainThread", []() {
|
||||
PollJSSamplingForCurrentThread();
|
||||
});
|
||||
SystemGroup::Dispatch(TaskCategory::Other, task.forget());
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
locked_profiler_start(PSLockRef aLock, int aEntries, double aInterval,
|
||||
uint32_t aFeatures,
|
||||
|
@ -2689,6 +2729,11 @@ locked_profiler_start(PSLockRef aLock, int aEntries, double aInterval,
|
|||
// We can manually poll the current thread so it starts sampling
|
||||
// immediately.
|
||||
info->PollJSSampling();
|
||||
} else if (info->IsMainThread()) {
|
||||
// Dispatch a runnable to the main thread to call PollJSSampling(),
|
||||
// so that we don't have wait for the next JS interrupt callback in
|
||||
// order to start profiling JS.
|
||||
TriggerPollJSSamplingOnMainThread();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3076,17 +3121,7 @@ void
|
|||
profiler_js_interrupt_callback()
|
||||
{
|
||||
// This function runs on JS threads being sampled.
|
||||
|
||||
MOZ_RELEASE_ASSERT(CorePS::Exists());
|
||||
|
||||
PSAutoLock lock(gPSMutex);
|
||||
|
||||
ThreadInfo* info = TLSInfo::Info(lock);
|
||||
if (!info) {
|
||||
return;
|
||||
}
|
||||
|
||||
info->PollJSSampling();
|
||||
PollJSSamplingForCurrentThread();
|
||||
}
|
||||
|
||||
double
|
||||
|
|
Загрузка…
Ссылка в новой задаче