Merge m-c to inbound, a=merge

MozReview-Commit-ID: 77Uz3uceUmk
This commit is contained in:
Wes Kocher 2017-08-31 16:56:23 -07:00
commit 6472928439
50 changed files with 794 additions and 543 deletions

View File

@ -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);
},
/**

View File

@ -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;
});

View File

@ -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);
});
},

View File

@ -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);

View File

@ -509,7 +509,7 @@ CssComputedView.prototype = {
);
this._refreshProcess.schedule();
});
}).catch((err) => console.error(err));
}).catch(console.error);
},
/**

View File

@ -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",

View File

@ -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) {

View File

@ -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);
}
},

View File

@ -184,7 +184,7 @@ MarkupView.prototype = {
_onToolboxPickerHover: function (event, nodeFront) {
this.showNode(nodeFront).then(() => {
this._showContainerAsHovered(nodeFront);
}, e => console.error(e));
}, console.error);
},
/**

View File

@ -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);
},

View File

@ -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 {

View File

@ -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);
}
},

View File

@ -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;

View File

@ -189,7 +189,7 @@ const ResponsiveUIManager = exports.ResponsiveUIManager = {
break;
default:
}
completed.catch(e => console.error(e));
completed.catch(console.error);
},
handleMenuCheck({target}) {

View File

@ -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();

View File

@ -314,7 +314,7 @@ var ShadersListView = Heritage.extend(WidgetMethods, {
getShaders()
.then(getSources)
.then(showSources)
.catch(e => console.error(e));
.catch(console.error);
},
/**

View File

@ -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);
}
};

View File

@ -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();

View File

@ -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);
}
/**

View File

@ -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);
},
/**

View File

@ -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);
},
/**

View File

@ -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);
},
/**

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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.

View File

@ -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);
},
/**

View File

@ -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);
}
},

View File

@ -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;
}

View File

@ -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);

View File

@ -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

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -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]]

View File

@ -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
/**

View File

@ -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);
};

View File

@ -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");

View File

@ -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");
}

View File

@ -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;
}

View File

@ -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

View File

@ -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();
});

View File

@ -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')

View File

@ -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):

View File

@ -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);
});
},
/**

View File

@ -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