зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to inbound. a=merge CLOSED TREE
This commit is contained in:
Коммит
f774bd9752
|
@ -9,9 +9,9 @@
|
|||
"message": "https://rover.ebay.com/rover/1/1553-53471-19255-0/1"
|
||||
},
|
||||
"searchForm": {
|
||||
"message": "https://www.ebay.at/"
|
||||
"message": "https://www.befr.ebay.be/"
|
||||
},
|
||||
"searchUrlGetParams": {
|
||||
"message": "ff3=4&toolid=20004&campid=5338192028&customid=&mpre=https://www.befr.ebay.be/sch/{searchTerms}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,3 +38,13 @@
|
|||
font-weight: var(--caption-20-font-weight);
|
||||
color: var(--caption-20-color);
|
||||
}
|
||||
|
||||
.connect-page__troubleshoot {
|
||||
font-size: var(--body-10-font-size);
|
||||
font-weight: var(--body-10-font-weight);
|
||||
margin-block-start: calc(var(--base-unit) * 2);
|
||||
}
|
||||
|
||||
.connect-page__troubleshoot--network {
|
||||
padding-inline: calc(var(--base-unit) * 6);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,11 @@ const Types = require("../../types/index");
|
|||
const USB_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-usb-icon.svg";
|
||||
const GLOBE_ICON_SRC = "chrome://devtools/skin/images/aboutdebugging-globe-icon.svg";
|
||||
|
||||
const TROUBLESHOOT_USB_URL =
|
||||
"https://developer.mozilla.org/docs/Tools/Remote_Debugging/Debugging_over_USB";
|
||||
const TROUBLESHOOT_NETWORK_URL =
|
||||
"https://developer.mozilla.org/docs/Tools/Remote_Debugging/Debugging_over_a_network";
|
||||
|
||||
class ConnectPage extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
|
@ -145,18 +150,17 @@ class ConnectPage extends PureComponent {
|
|||
{
|
||||
steps: [
|
||||
{
|
||||
localizationId: "about-debugging-setup-usb-step-enable-dev-menu",
|
||||
url: "https://developer.mozilla.org/docs/Tools/Remote_Debugging/Debugging_over_USB",
|
||||
localizationId: "about-debugging-setup-usb-step-enable-dev-menu2",
|
||||
},
|
||||
{
|
||||
localizationId: "about-debugging-setup-usb-step-enable-debug",
|
||||
url: "https://developer.mozilla.org/docs/Tools/Remote_Debugging/Debugging_over_USB",
|
||||
localizationId: "about-debugging-setup-usb-step-enable-debug2",
|
||||
},
|
||||
{
|
||||
localizationId: "about-debugging-setup-usb-step-enable-debug-firefox",
|
||||
url: "https://developer.mozilla.org/docs/Tools/Remote_Debugging/Debugging_over_USB",
|
||||
localizationId: "about-debugging-setup-usb-step-enable-debug-firefox2",
|
||||
},
|
||||
{
|
||||
localizationId: "about-debugging-setup-usb-step-plug-device",
|
||||
},
|
||||
{ localizationId: "about-debugging-setup-usb-step-plug-device" },
|
||||
],
|
||||
}
|
||||
)
|
||||
|
@ -172,6 +176,7 @@ class ConnectPage extends PureComponent {
|
|||
"components to Firefox."
|
||||
)
|
||||
),
|
||||
this.renderTroubleshootText(RUNTIMES.USB),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -191,8 +196,44 @@ class ConnectPage extends PureComponent {
|
|||
{},
|
||||
NetworkLocationsList({ dispatch, networkLocations }),
|
||||
NetworkLocationsForm({ dispatch, networkLocations }),
|
||||
this.renderTroubleshootText(RUNTIMES.NETWORK),
|
||||
),
|
||||
})
|
||||
},
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
renderTroubleshootText(connectionType) {
|
||||
const localizationId = connectionType === RUNTIMES.USB
|
||||
? "about-debugging-setup-usb-troubleshoot"
|
||||
: "about-debugging-setup-network-troubleshoot";
|
||||
|
||||
const className = "connect-page__troubleshoot connect-page__troubleshoot--" +
|
||||
`${connectionType === RUNTIMES.USB ? "usb" : "network"}`;
|
||||
|
||||
const url = connectionType === RUNTIMES.USB
|
||||
? TROUBLESHOOT_USB_URL
|
||||
: TROUBLESHOOT_NETWORK_URL;
|
||||
|
||||
return dom.aside(
|
||||
{
|
||||
className,
|
||||
},
|
||||
Localized(
|
||||
{
|
||||
id: localizationId,
|
||||
a: dom.a(
|
||||
{
|
||||
href: url,
|
||||
target: "_blank",
|
||||
}
|
||||
),
|
||||
},
|
||||
dom.p(
|
||||
{},
|
||||
localizationId,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -221,21 +262,6 @@ class ConnectPage extends PureComponent {
|
|||
"Configure the connection method you wish to remotely debug your device with."
|
||||
)
|
||||
),
|
||||
dom.p(
|
||||
{},
|
||||
Localized(
|
||||
{
|
||||
id: "about-debugging-setup-link-android-devices",
|
||||
},
|
||||
dom.a(
|
||||
{
|
||||
href: "https://support.mozilla.org/kb/will-firefox-work-my-mobile-device#w_android-devices",
|
||||
target: "_blank",
|
||||
},
|
||||
"View list of supported android devices"
|
||||
)
|
||||
),
|
||||
),
|
||||
Localized(
|
||||
{
|
||||
id: "about-debugging-setup-this-firefox",
|
||||
|
@ -244,9 +270,7 @@ class ConnectPage extends PureComponent {
|
|||
}),
|
||||
},
|
||||
dom.p(
|
||||
{
|
||||
className: "connect-page__breather",
|
||||
},
|
||||
{},
|
||||
"about-debugging-setup-this-firefox",
|
||||
),
|
||||
),
|
||||
|
|
|
@ -17,7 +17,6 @@ class ConnectSteps extends PureComponent {
|
|||
steps: PropTypes.arrayOf(
|
||||
PropTypes.shape({
|
||||
localizationId: PropTypes.string.isRequired,
|
||||
url: PropTypes.string,
|
||||
}).isRequired,
|
||||
),
|
||||
};
|
||||
|
@ -32,17 +31,13 @@ class ConnectSteps extends PureComponent {
|
|||
Localized(
|
||||
{
|
||||
id: step.localizationId,
|
||||
a: step.url ? dom.a({
|
||||
href: step.url,
|
||||
target: "_blank",
|
||||
}) : null,
|
||||
},
|
||||
dom.li(
|
||||
{
|
||||
className: "connect-page__step",
|
||||
key: step,
|
||||
key: step.localizationId,
|
||||
},
|
||||
step
|
||||
step.localizationId
|
||||
)
|
||||
)
|
||||
)
|
||||
|
|
|
@ -528,6 +528,13 @@ body {
|
|||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
/* Invert text selection color in selected rows */
|
||||
.accessible .tree:focus .node.focused ::selection,
|
||||
.accessible .tree .tree-node-active .node.focused ::selection {
|
||||
color: var(--theme-selection-background);
|
||||
background-color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.accessible .tree:focus .node.focused .open-inspector,
|
||||
.accessible .tree .tree-node-active .node.focused .open-inspector {
|
||||
background-color: var(--grey-30);
|
||||
|
|
|
@ -39,10 +39,12 @@
|
|||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.debugger .tree-indent {
|
||||
width: 16px;
|
||||
margin-inline-start: 0px;
|
||||
border-inline-start: 0;
|
||||
.tree-node[data-expandable="false"] .tree-last-indent {
|
||||
/* The 13px value is taken from the total width and margins of the arrow
|
||||
element of expandables nodes (10px width + 3px margins). That way the
|
||||
node's text are indented the same for both expandable and non-expandable
|
||||
nodes */
|
||||
margin-inline-end: 13px;
|
||||
}
|
||||
|
||||
/* For non expandable root nodes, we don't have .tree-indent elements, so we declare
|
||||
|
@ -78,8 +80,14 @@ html[dir="rtl"] .tree-node button:not(.expanded) {
|
|||
}
|
||||
|
||||
.tree .tree-node.focused {
|
||||
color: white;
|
||||
background-color: var(--theme-selection-background, #0a84ff);
|
||||
color: var(--theme-selection-color);
|
||||
background-color: var(--theme-selection-background);
|
||||
}
|
||||
|
||||
/* Invert text selection color in selected rows */
|
||||
.tree .tree-node.focused ::selection {
|
||||
color: var(--theme-selection-background);
|
||||
background-color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.tree-node.focused button.arrow {
|
||||
|
|
|
@ -234,6 +234,7 @@ class ArrowExpander extends Component {
|
|||
}
|
||||
|
||||
const treeIndent = _reactDomFactories2.default.span({ className: "tree-indent" }, "\u200B");
|
||||
const treeLastIndent = _reactDomFactories2.default.span({ className: "tree-indent tree-last-indent" }, "\u200B");
|
||||
|
||||
class TreeNode extends Component {
|
||||
static get propTypes() {
|
||||
|
@ -359,7 +360,13 @@ class TreeNode extends Component {
|
|||
ariaExpanded = true;
|
||||
}
|
||||
|
||||
const indents = Array.from({ length: depth }).fill(treeIndent);
|
||||
const indents = Array.from({ length: depth }, (_, i) => {
|
||||
if (i == depth - 1) {
|
||||
return treeLastIndent;
|
||||
}
|
||||
return treeIndent;
|
||||
});
|
||||
|
||||
const items = indents.concat(renderItem(item, depth, focused, arrow, expanded));
|
||||
|
||||
return _reactDomFactories2.default.div({
|
||||
|
|
|
@ -39,10 +39,12 @@
|
|||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.debugger .tree-indent {
|
||||
width: 16px;
|
||||
margin-inline-start: 0px;
|
||||
border-inline-start: 0;
|
||||
.tree-node[data-expandable="false"] .tree-last-indent {
|
||||
/* The 13px value is taken from the total width and margins of the arrow
|
||||
element of expandables nodes (10px width + 3px margins). That way the
|
||||
node's text are indented the same for both expandable and non-expandable
|
||||
nodes */
|
||||
margin-inline-end: 13px;
|
||||
}
|
||||
|
||||
/* For non expandable root nodes, we don't have .tree-indent elements, so we declare
|
||||
|
@ -78,8 +80,14 @@ html[dir="rtl"] .tree-node button:not(.expanded) {
|
|||
}
|
||||
|
||||
.tree .tree-node.focused {
|
||||
color: white;
|
||||
background-color: var(--theme-selection-background, #0a84ff);
|
||||
color: var(--theme-selection-color);
|
||||
background-color: var(--theme-selection-background);
|
||||
}
|
||||
|
||||
/* Invert text selection color in selected rows */
|
||||
.tree .tree-node.focused ::selection {
|
||||
color: var(--theme-selection-background);
|
||||
background-color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.tree-node.focused button.arrow {
|
||||
|
|
|
@ -53,6 +53,10 @@ class ArrowExpander extends Component {
|
|||
}
|
||||
|
||||
const treeIndent = dom.span({ className: "tree-indent" }, "\u200B");
|
||||
const treeLastIndent = dom.span(
|
||||
{ className: "tree-indent tree-last-indent" },
|
||||
"\u200B"
|
||||
);
|
||||
|
||||
class TreeNode extends Component {
|
||||
static get propTypes() {
|
||||
|
@ -190,7 +194,13 @@ class TreeNode extends Component {
|
|||
ariaExpanded = true;
|
||||
}
|
||||
|
||||
const indents = Array.from({ length: depth }).fill(treeIndent);
|
||||
const indents = Array.from({length: depth}, (_, i) => {
|
||||
if (i == depth - 1) {
|
||||
return treeLastIndent;
|
||||
}
|
||||
return treeIndent;
|
||||
})
|
||||
|
||||
const items = indents.concat(
|
||||
renderItem(item, depth, focused, arrow, expanded)
|
||||
);
|
||||
|
|
|
@ -29,6 +29,12 @@ button:focus {
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.debugger .tree-indent {
|
||||
width: 16px;
|
||||
margin-inline-start: 0;
|
||||
border-inline-start: 0;
|
||||
}
|
||||
|
||||
.editor-pane {
|
||||
display: flex;
|
||||
position: relative;
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
}
|
||||
|
||||
.managed-tree .tree .node.focused {
|
||||
color: white;
|
||||
color: var(--theme-selection-color);
|
||||
background-color: var(--theme-selection-background);
|
||||
}
|
||||
|
||||
|
|
|
@ -101,10 +101,6 @@ about-debugging-setup-title = Setup
|
|||
# Introduction text in the Setup page to explain how to configure remote debugging.
|
||||
about-debugging-setup-intro = Configure the connection method you wish to remotely debug your device with.
|
||||
|
||||
# Link displayed in the Setup page that leads to MDN page with list of supported devices.
|
||||
# Temporarily leads to https://support.mozilla.org/en-US/kb/will-firefox-work-my-mobile-device#w_android-devices
|
||||
about-debugging-setup-link-android-devices = View list of supported Android devices
|
||||
|
||||
# Explanatory text in the Setup page about what the 'This Firefox' page is for
|
||||
about-debugging-setup-this-firefox = Use <a>{ about-debugging-this-firefox-runtime-name }</a> to debug tabs, extensions and service workers on this version of { -brand-shorter-name }.
|
||||
|
||||
|
@ -134,21 +130,29 @@ about-debugging-setup-usb-status-disabled = Disabled
|
|||
about-debugging-setup-usb-status-updating = Updating…
|
||||
|
||||
# USB section step by step guide
|
||||
about-debugging-setup-usb-step-enable-dev-menu = Enable Developer menu on your Android device. <a>Learn how</a>
|
||||
about-debugging-setup-usb-step-enable-dev-menu2 = Enable Developer menu on your Android device.
|
||||
|
||||
# USB section step by step guide
|
||||
about-debugging-setup-usb-step-enable-debug = Enable USB Debugging in the Android Developer Menu. <a>Learn how</a>
|
||||
about-debugging-setup-usb-step-enable-debug2 = Enable USB Debugging in the Android Developer Menu.
|
||||
|
||||
# USB section step by step guide
|
||||
about-debugging-setup-usb-step-enable-debug-firefox = Enable USB Debugging in Firefox on the Android device. <a>Learn how</a>
|
||||
about-debugging-setup-usb-step-enable-debug-firefox2 = Enable USB Debugging in Firefox on the Android device.
|
||||
|
||||
# USB section step by step guide
|
||||
about-debugging-setup-usb-step-plug-device = Connect the Android device to your computer.
|
||||
|
||||
# Text shown in the USB section of the setup page with a link to troubleshoot connection errors.
|
||||
# The link goes to https://developer.mozilla.org/docs/Tools/Remote_Debugging/Debugging_over_USB
|
||||
about-debugging-setup-usb-troubleshoot = Problems connecting to the USB device? <a>Troubleshoot</a>
|
||||
|
||||
# Network section of the Setup page
|
||||
about-debugging-setup-network =
|
||||
.title = Network Location
|
||||
|
||||
# Text shown in the Network section of the setup page with a link to troubleshoot connection errors.
|
||||
# The link goes to https://developer.mozilla.org/en-US/docs/Tools/Remote_Debugging/Debugging_over_a_network
|
||||
about-debugging-setup-network-troubleshoot = Problems connecting via network location? <a>Troubleshoot</a>
|
||||
|
||||
# Text of a button displayed after the network locations "Host" input.
|
||||
# Clicking on it will add the new network location to the list.
|
||||
about-debugging-network-locations-add-button = Add
|
||||
|
|
|
@ -129,6 +129,16 @@ class RequestListContent extends Component {
|
|||
// Uninstall the tooltip event handler
|
||||
this.tooltip.stopTogglingOnHover();
|
||||
window.removeEventListener("resize", this.onResize);
|
||||
|
||||
// Performance optimization. React is slow when removing long lists
|
||||
// of elements (i.e. the list of HTTP requests in this case), and so
|
||||
// let's clean up the content through `innerHTML` property in advance.
|
||||
// This significantly speeds up Network panel closing time.
|
||||
// This isn't React friendly since React has no way to know the DOM
|
||||
// has been modified. But, the panel is closing at this point anyway.
|
||||
// See also: Bug 1546513 - Closing the network panel with many
|
||||
// entries takes multiple seconds
|
||||
this.refs.rowGroupEl.innerHTML = "";
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -315,13 +315,18 @@ function parseQueryString(query) {
|
|||
return null;
|
||||
}
|
||||
|
||||
return query.replace(/^[?&]/, "").split("&").map(e => {
|
||||
const param = e.split("=");
|
||||
return {
|
||||
name: param[0] ? getUnicodeUrlPath(param[0]) : "",
|
||||
value: param[1] ? getUnicodeUrlPath(param.slice(1).join("=")) : "",
|
||||
};
|
||||
});
|
||||
return query
|
||||
.replace(/^[?&]/, "")
|
||||
.split("&")
|
||||
.map(e => {
|
||||
const param = e.split("=");
|
||||
return {
|
||||
name: param[0] ? getUnicodeUrlPath(param[0]) : "",
|
||||
value: param[1]
|
||||
? getUnicodeUrlPath(param.slice(1).join("=")).replace(/\+/g, " ")
|
||||
: "",
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -31,6 +31,7 @@ support-files =
|
|||
html_post-array-data-test-page.html
|
||||
html_post-json-test-page.html
|
||||
html_post-raw-test-page.html
|
||||
html_header-test-page.html
|
||||
html_post-raw-with-headers-test-page.html
|
||||
html_simple-test-page.html
|
||||
html_single-get-page.html
|
||||
|
@ -138,6 +139,8 @@ skip-if = (os == 'mac') || (os == 'win' && os_version == '10.0') # Bug 1479782
|
|||
[browser_net_filter-flags.js]
|
||||
[browser_net_footer-summary.js]
|
||||
[browser_net_header-ref-policy.js]
|
||||
[browser_net_decode-url.js]
|
||||
[browser_net_decode-params.js]
|
||||
[browser_net_headers-alignment.js]
|
||||
[browser_net_headers_filter.js]
|
||||
[browser_net_headers_sorted.js]
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests if "+" is replaces with spaces in the Params panel.
|
||||
*/
|
||||
add_task(async function() {
|
||||
const { tab, monitor } = await initNetMonitor(POST_RAW_URL_WITH_HASH);
|
||||
info("Starting test... ");
|
||||
|
||||
const { document, store, windowRequire } = monitor.panelWin;
|
||||
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
|
||||
store.dispatch(Actions.batchEnable(false));
|
||||
|
||||
// Execute request.
|
||||
await performRequests(monitor, tab, 1);
|
||||
|
||||
// Wait until the tab panel summary is displayed
|
||||
wait = waitUntil(() =>
|
||||
document.querySelectorAll(".tabpanel-summary-label")[0]);
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll(".request-list-item")[0]);
|
||||
await wait;
|
||||
|
||||
EventUtils.sendMouseEvent({ type: "click" },
|
||||
document.querySelector("#params-tab"));
|
||||
|
||||
// The Params panel should render the following:
|
||||
// Query String:
|
||||
// file foo # bar
|
||||
const keyValue = document.querySelectorAll(".treeTable .treeRow")[1];
|
||||
|
||||
is(keyValue.innerText,
|
||||
"file\tfoo # bar", "'+' in params in correctly decoded.");
|
||||
|
||||
return teardown(monitor);
|
||||
});
|
|
@ -0,0 +1,33 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Tests if "Request URL" containing "#" in its query is correctly decoded.
|
||||
*/
|
||||
add_task(async function() {
|
||||
const { tab, monitor } = await initNetMonitor(POST_RAW_URL_WITH_HASH);
|
||||
info("Starting test... ");
|
||||
|
||||
const { document, store, windowRequire } = monitor.panelWin;
|
||||
const Actions = windowRequire("devtools/client/netmonitor/src/actions/index");
|
||||
store.dispatch(Actions.batchEnable(false));
|
||||
|
||||
// Execute request.
|
||||
await performRequests(monitor, tab, 1);
|
||||
|
||||
// Wait until the tab panel summary is displayed
|
||||
wait = waitUntil(() =>
|
||||
document.querySelectorAll(".tabpanel-summary-label")[0]);
|
||||
EventUtils.sendMouseEvent({ type: "mousedown" },
|
||||
document.querySelectorAll(".request-list-item")[0]);
|
||||
await wait;
|
||||
|
||||
const requestURL = document.querySelectorAll(".tabpanel-summary-value")[0];
|
||||
|
||||
is(requestURL.textContent.endsWith("foo+%23+bar"),
|
||||
true, "\"Request URL\" containing '#' is correctly decoded.");
|
||||
|
||||
return teardown(monitor);
|
||||
});
|
|
@ -55,6 +55,7 @@ const POST_DATA_URL = EXAMPLE_URL + "html_post-data-test-page.html";
|
|||
const POST_ARRAY_DATA_URL = EXAMPLE_URL + "html_post-array-data-test-page.html";
|
||||
const POST_JSON_URL = EXAMPLE_URL + "html_post-json-test-page.html";
|
||||
const POST_RAW_URL = EXAMPLE_URL + "html_post-raw-test-page.html";
|
||||
const POST_RAW_URL_WITH_HASH = EXAMPLE_URL + "html_header-test-page.html";
|
||||
const POST_RAW_WITH_HEADERS_URL = EXAMPLE_URL + "html_post-raw-with-headers-test-page.html";
|
||||
const PARAMS_URL = EXAMPLE_URL + "html_params-test-page.html";
|
||||
const JSONP_URL = EXAMPLE_URL + "html_jsonp-test-page.html";
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||
<meta http-equiv="Pragma" content="no-cache" />
|
||||
<meta http-equiv="Expires" content="0" />
|
||||
<title>Network Monitor test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<p>POST raw test</p>
|
||||
|
||||
<script type="text/javascript">
|
||||
/* exported performRequests */
|
||||
"use strict";
|
||||
|
||||
function post(address, message, callback) {
|
||||
const xhr = new XMLHttpRequest();
|
||||
xhr.open("POST", address, true);
|
||||
xhr.setRequestHeader("content-type", "application/x-www-form-urlencoded");
|
||||
|
||||
xhr.onreadystatechange = function() {
|
||||
if (this.readyState == this.DONE) {
|
||||
callback();
|
||||
}
|
||||
};
|
||||
xhr.send(message);
|
||||
}
|
||||
|
||||
function performRequests() {
|
||||
const rawData = "";
|
||||
post("sjs_simple-test-server.sjs?file=foo+%23+bar#home", rawData, function() {
|
||||
// Done.
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
</html>
|
|
@ -39,10 +39,12 @@
|
|||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.debugger .tree-indent {
|
||||
width: 16px;
|
||||
margin-inline-start: 0px;
|
||||
border-inline-start: 0;
|
||||
.tree-node[data-expandable="false"] .tree-last-indent {
|
||||
/* The 13px value is taken from the total width and margins of the arrow
|
||||
element of expandables nodes (10px width + 3px margins). That way the
|
||||
node's text are indented the same for both expandable and non-expandable
|
||||
nodes */
|
||||
margin-inline-end: 13px;
|
||||
}
|
||||
|
||||
/* For non expandable root nodes, we don't have .tree-indent elements, so we declare
|
||||
|
@ -78,8 +80,14 @@ html[dir="rtl"] .tree-node button:not(.expanded) {
|
|||
}
|
||||
|
||||
.tree .tree-node.focused {
|
||||
color: white;
|
||||
background-color: var(--theme-selection-background, #0a84ff);
|
||||
color: var(--theme-selection-color);
|
||||
background-color: var(--theme-selection-background);
|
||||
}
|
||||
|
||||
/* Invert text selection color in selected rows */
|
||||
.tree .tree-node.focused ::selection {
|
||||
color: var(--theme-selection-background);
|
||||
background-color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.tree-node.focused button.arrow {
|
||||
|
|
|
@ -175,6 +175,7 @@ class ArrowExpander extends Component {
|
|||
}
|
||||
|
||||
const treeIndent = _reactDomFactories2.default.span({ className: "tree-indent" }, "\u200B");
|
||||
const treeLastIndent = _reactDomFactories2.default.span({ className: "tree-indent tree-last-indent" }, "\u200B");
|
||||
|
||||
class TreeNode extends Component {
|
||||
static get propTypes() {
|
||||
|
@ -300,7 +301,13 @@ class TreeNode extends Component {
|
|||
ariaExpanded = true;
|
||||
}
|
||||
|
||||
const indents = Array.from({ length: depth }).fill(treeIndent);
|
||||
const indents = Array.from({ length: depth }, (_, i) => {
|
||||
if (i == depth - 1) {
|
||||
return treeLastIndent;
|
||||
}
|
||||
return treeIndent;
|
||||
});
|
||||
|
||||
const items = indents.concat(renderItem(item, depth, focused, arrow, expanded));
|
||||
|
||||
return _reactDomFactories2.default.div({
|
||||
|
|
|
@ -94,6 +94,12 @@
|
|||
fill: currentColor;
|
||||
}
|
||||
|
||||
/* Invert text selection color in selected rows */
|
||||
.treeTable .treeRow.selected :not(input):not(textarea)::selection {
|
||||
color: var(--theme-selection-background);
|
||||
background-color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
/* Filtering */
|
||||
.treeTable .treeRow.hidden {
|
||||
display: none !important;
|
||||
|
|
|
@ -77,7 +77,7 @@ function getUnicodeUrlPath(urlPath) {
|
|||
* unreadable URI-encoded pathname, such as
|
||||
* http://xn--g6w.xn--8pv/%E8%A9%A6/%E6%B8%AC.js, then this function will return
|
||||
* the readable URL by decoding all its unreadable URL components to Unicode
|
||||
* characters.
|
||||
* characters. The character `#` is not decoded from escape sequences.
|
||||
*
|
||||
* If the `url` is a malformed URL, then this function will return the original
|
||||
* `url`.
|
||||
|
@ -100,7 +100,7 @@ function getUnicodeUrl(url) {
|
|||
return url;
|
||||
}
|
||||
const readableHostname = getUnicodeHostname(hostname);
|
||||
url = decodeURIComponent(url);
|
||||
url = decodeURI(url);
|
||||
return url.replace(hostname, readableHostname);
|
||||
} catch (err) {
|
||||
}
|
||||
|
|
|
@ -59,6 +59,11 @@
|
|||
scrollbar-color: var(--grey-40) var(--grey-20);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background-color: var(--theme-selection-background);
|
||||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.devtools-monospace {
|
||||
font-family: var(--monospace-font-family);
|
||||
font-size: var(--theme-code-font-size);
|
||||
|
|
|
@ -22,11 +22,6 @@ body {
|
|||
color: var(--theme-body-color);
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background-color: var(--theme-selection-background);
|
||||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.theme-selected,
|
||||
.CodeMirror-hint-active {
|
||||
background-color: var(--theme-selection-background);
|
||||
|
|
|
@ -22,11 +22,6 @@ body {
|
|||
color: var(--theme-body-color);
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background-color: var(--theme-selection-background);
|
||||
color: var(--theme-selection-color);
|
||||
}
|
||||
|
||||
.theme-selected,
|
||||
.CodeMirror-hint-active {
|
||||
background-color: var(--theme-selection-background);
|
||||
|
|
|
@ -1167,48 +1167,6 @@ nsHTMLCopyEncoder::SetSelection(Selection* aSelection) {
|
|||
mIsTextWidget = true;
|
||||
break;
|
||||
}
|
||||
#if defined(MOZ_THUNDERBIRD) || defined(MOZ_SUITE)
|
||||
else if (selContent->IsHTMLElement(nsGkAtoms::body)) {
|
||||
// Currently, setting mIsTextWidget to 'true' will result in the selection
|
||||
// being encoded/copied as pre-formatted plain text.
|
||||
// This is fine for copying pre-formatted plain text with Firefox, it is
|
||||
// already not correct for copying pre-formatted "rich" text (bold,
|
||||
// colour) with Firefox. As long as the serialisers aren't fixed, copying
|
||||
// pre-formatted text in Firefox is broken. If we set mIsTextWidget,
|
||||
// pre-formatted plain text is copied, but pre-formatted "rich" text loses
|
||||
// the "rich" formatting. If we don't set mIsTextWidget, "rich" text
|
||||
// attributes aren't lost, but white-space is lost.
|
||||
// So far the story for Firefox.
|
||||
//
|
||||
// Thunderbird has two *conflicting* requirements.
|
||||
// Case 1:
|
||||
// When selecting and copying text, even pre-formatted text, as a quote
|
||||
// to be placed into a reply, we *always* expect HTML to be copied.
|
||||
// Case 2:
|
||||
// When copying text in a so-called "plain text" message, that is
|
||||
// one where the body carries style "white-space:pre-wrap", the text
|
||||
// should be copied as pre-formatted plain text.
|
||||
//
|
||||
// Therefore the following code checks for "pre-wrap" on the body.
|
||||
// This is a terrible hack.
|
||||
//
|
||||
// The proper fix would be this:
|
||||
// For case 1:
|
||||
// Communicate the fact that HTML is required to EncodeToString(),
|
||||
// bug 1141786.
|
||||
// For case 2:
|
||||
// Wait for Firefox to get fixed to detect pre-formatting correctly,
|
||||
// bug 1174452.
|
||||
nsAutoString styleVal;
|
||||
if (selContent->IsElement() &&
|
||||
selContent->AsElement()->GetAttr(kNameSpaceID_None, nsGkAtoms::style,
|
||||
styleVal) &&
|
||||
styleVal.Find(NS_LITERAL_STRING("pre-wrap")) != kNotFound) {
|
||||
mIsTextWidget = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// normalize selection if we are not in a widget
|
||||
|
|
|
@ -200,7 +200,11 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
|||
|
||||
JAR_MANIFESTS += ['jar.mn']
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['tests/browser.ini']
|
||||
BROWSER_CHROME_MANIFESTS += [
|
||||
'tests/browser.ini',
|
||||
'tests/JSWindowActor/browser.ini',
|
||||
]
|
||||
|
||||
MOCHITEST_CHROME_MANIFESTS += ['tests/chrome.ini']
|
||||
MOCHITEST_MANIFESTS += ['tests/mochitest.ini']
|
||||
XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell.ini']
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
[DEFAULT]
|
||||
support-files =
|
||||
head.js
|
||||
|
||||
[browser_destroy_callbacks.js]
|
||||
[browser_event_listener.js]
|
||||
[browser_getActor.js]
|
||||
[browser_getActor_filter.js]
|
||||
[browser_observer_notification.js]
|
||||
[browser_registerWindowActor.js]
|
||||
[browser_sendAsyncMessage.js]
|
||||
[browser_sendQuery.js]
|
|
@ -0,0 +1,74 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
declTest("destroy actor by iframe remove", {
|
||||
allFrames: true,
|
||||
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
frame.id = "frame";
|
||||
content.document.body.appendChild(frame);
|
||||
await ContentTaskUtils.waitForEvent(frame, "load");
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
|
||||
let willDestroyPromise = new Promise(resolve => {
|
||||
const TOPIC = "test-js-window-actor-willdestroy";
|
||||
Services.obs.addObserver(function obs(subject, topic, data) {
|
||||
ok(data, "willDestroyCallback data should be true.");
|
||||
|
||||
Services.obs.removeObserver(obs, TOPIC);
|
||||
resolve();
|
||||
}, TOPIC);
|
||||
});
|
||||
|
||||
let didDestroyPromise = new Promise(resolve => {
|
||||
const TOPIC = "test-js-window-actor-diddestroy";
|
||||
Services.obs.addObserver(function obs(subject, topic, data) {
|
||||
ok(data, "didDestroyCallback data should be true.");
|
||||
|
||||
Services.obs.removeObserver(obs, TOPIC);
|
||||
resolve();
|
||||
}, TOPIC);
|
||||
});
|
||||
|
||||
info("Remove frame");
|
||||
content.document.getElementById("frame").remove();
|
||||
await Promise.all([willDestroyPromise, didDestroyPromise]);
|
||||
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/InvalidStateError/, "Should throw if frame destroy.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("destroy actor by page navigates", {
|
||||
allFrames: true,
|
||||
|
||||
async test(browser) {
|
||||
info("creating an in-process frame");
|
||||
await ContentTask.spawn(browser, URL, async function(url) {
|
||||
let frame = content.document.createElement("iframe");
|
||||
frame.src = url;
|
||||
content.document.body.appendChild(frame);
|
||||
});
|
||||
|
||||
info("navigating page");
|
||||
await ContentTask.spawn(browser, TEST_URL, async function(url) {
|
||||
let frame = content.document.querySelector("iframe");
|
||||
frame.contentWindow.location = url;
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
await ContentTaskUtils.waitForEvent(frame, "load");
|
||||
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/InvalidStateError/, "Should throw if frame destroy.");
|
||||
});
|
||||
},
|
||||
});
|
|
@ -0,0 +1,39 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
declTest("test event triggering actor creation", {
|
||||
async test(browser) {
|
||||
// Add a select element to the DOM of the loaded document.
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
content.document.body.innerHTML += `
|
||||
<select id="testSelect">
|
||||
<option>A</option>
|
||||
<option>B</option>
|
||||
</select>`;
|
||||
});
|
||||
|
||||
// Wait for the observer notification.
|
||||
let observePromise = new Promise(resolve => {
|
||||
const TOPIC = "test-js-window-actor-parent-event";
|
||||
Services.obs.addObserver(function obs(subject, topic, data) {
|
||||
is(topic, TOPIC, "topic matches");
|
||||
|
||||
Services.obs.removeObserver(obs, TOPIC);
|
||||
resolve({subject, data});
|
||||
}, TOPIC);
|
||||
});
|
||||
|
||||
// Click on the select to show the dropdown.
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("#testSelect", {}, browser);
|
||||
|
||||
// Wait for the observer notification to fire, and inspect the results.
|
||||
let {subject, data} = await observePromise;
|
||||
is(data, "mozshowdropdown");
|
||||
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
let actorParent = parent.getActor("Test");
|
||||
ok(actorParent, "JSWindowActorParent should have value.");
|
||||
is(subject.wrappedJSObject, actorParent, "Should have been recieved on the right actor");
|
||||
},
|
||||
});
|
|
@ -0,0 +1,22 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
declTest("getActor on both sides", {
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
ok(parent, "WindowGlobalParent should have value.");
|
||||
let actorParent = parent.getActor("Test");
|
||||
is(actorParent.show(), "TestParent", "actor show should have vaule.");
|
||||
is(actorParent.manager, parent, "manager should match WindowGlobalParent.");
|
||||
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
is(child.isInProcess, false, "Actor should be loaded in the content process.");
|
||||
let actorChild = child.getActor("Test");
|
||||
is(actorChild.show(), "TestChild", "actor show should have vaule.");
|
||||
is(actorChild.manager, child, "manager should match WindowGlobalChild.");
|
||||
});
|
||||
},
|
||||
});
|
|
@ -0,0 +1,163 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
declTest("getActor with mismatch", {
|
||||
matches: ["*://*/*"],
|
||||
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
ok(parent, "WindowGlobalParent should have value.");
|
||||
Assert.throws(() => parent.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if it doesn't match.");
|
||||
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if it doesn't match.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with matches", {
|
||||
matches: ["*://*/*"],
|
||||
url: TEST_URL,
|
||||
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
ok(parent.getActor("Test"), "JSWindowActorParent should have value.");
|
||||
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
ok(child.getActor("Test"), "JSWindowActorChild should have value.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with iframe matches", {
|
||||
allFrames: true,
|
||||
matches: ["*://*/*"],
|
||||
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, TEST_URL, async function(url) {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
frame.src = url;
|
||||
content.document.body.appendChild(frame);
|
||||
await ContentTaskUtils.waitForEvent(frame, "load");
|
||||
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
ok(child.getActor("Test"), "JSWindowActorChild should have value.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with iframe mismatch", {
|
||||
allFrames: true,
|
||||
matches: ["about:home"],
|
||||
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, TEST_URL, async function(url) {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
frame.src = url;
|
||||
content.document.body.appendChild(frame);
|
||||
await ContentTaskUtils.waitForEvent(frame, "load");
|
||||
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if it doesn't match.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with remoteType match", {
|
||||
remoteTypes: ["web"],
|
||||
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
ok(parent.getActor("Test"), "JSWindowActorParent should have value.");
|
||||
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
ok(child.getActor("Test"), "JSWindowActorChild should have value.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with remoteType mismatch", {
|
||||
remoteTypes: ["privileged"],
|
||||
url: TEST_URL,
|
||||
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
Assert.throws(() => parent.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if its remoteTypes don't match.");
|
||||
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if its remoteTypes don't match.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor without allFrames", {
|
||||
allFrames: false,
|
||||
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
content.document.body.appendChild(frame);
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if allFrames is false.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with allFrames", {
|
||||
allFrames: true,
|
||||
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
content.document.body.appendChild(frame);
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor without includeChrome", {
|
||||
includeChrome: false,
|
||||
|
||||
async test(_browser, win) {
|
||||
let parent = win.docShell.browsingContext.currentWindowGlobal;
|
||||
SimpleTest.doesThrow(() =>
|
||||
parent.getActor("Test"),
|
||||
"Should throw if includeChrome is false.");
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with includeChrome", {
|
||||
includeChrome: true,
|
||||
|
||||
async test(_browser, win) {
|
||||
let parent = win.docShell.browsingContext.currentWindowGlobal;
|
||||
let actorParent = parent.getActor("Test");
|
||||
ok(actorParent, "JSWindowActorParent should have value.");
|
||||
},
|
||||
});
|
|
@ -0,0 +1,52 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
declTest("test observer triggering actor creation", {
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
const TOPIC = "test-js-window-actor-child-observer";
|
||||
Services.obs.notifyObservers(content.window, TOPIC, "dataString");
|
||||
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
let {subject, topic, data} = actorChild.lastObserved;
|
||||
|
||||
is(subject.getWindowGlobalChild().getActor("Test"), actorChild, "Should have been recieved on the right actor");
|
||||
is(topic, TOPIC, "Topic matches");
|
||||
is(data, "dataString", "Data matches");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("test observers with null data", {
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
const TOPIC = "test-js-window-actor-child-observer";
|
||||
Services.obs.notifyObservers(content.window, TOPIC);
|
||||
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
let {subject, topic, data} = actorChild.lastObserved;
|
||||
|
||||
is(subject.getWindowGlobalChild().getActor("Test"), actorChild, "Should have been recieved on the right actor");
|
||||
is(topic, TOPIC, "Topic matches");
|
||||
is(data, null, "Data matches");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("observers don't notify with wrong window", {
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
const TOPIC = "test-js-window-actor-child-observer";
|
||||
Services.obs.notifyObservers(null, TOPIC);
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
is(actorChild.lastObserved, undefined, "Should not receive wrong window's observer notification!");
|
||||
});
|
||||
},
|
||||
});
|
|
@ -0,0 +1,11 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
declTest("double register", {
|
||||
async test() {
|
||||
SimpleTest.doesThrow(() =>
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions),
|
||||
"Should throw if register has duplicate name.");
|
||||
},
|
||||
});
|
|
@ -0,0 +1,51 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
declTest("asyncMessage testing", {
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
let actorParent = parent.getActor("Test");
|
||||
ok(actorParent, "JSWindowActorParent should have value.");
|
||||
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
|
||||
let promise = new Promise(resolve => {
|
||||
actorChild.sendAsyncMessage("init", {});
|
||||
actorChild.done = (data) => resolve(data);
|
||||
}).then(data => {
|
||||
ok(data.initial, "Initial should be true.");
|
||||
ok(data.toParent, "ToParent should be true.");
|
||||
ok(data.toChild, "ToChild should be true.");
|
||||
});
|
||||
|
||||
await promise;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("asyncMessage without both sides", {
|
||||
async test(browser) {
|
||||
// If we don't create a parent actor, make sure the parent actor
|
||||
// gets created by having sent the message.
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
|
||||
let promise = new Promise(resolve => {
|
||||
actorChild.sendAsyncMessage("init", {});
|
||||
actorChild.done = (data) => resolve(data);
|
||||
}).then(data => {
|
||||
ok(data.initial, "Initial should be true.");
|
||||
ok(data.toParent, "ToParent should be true.");
|
||||
ok(data.toChild, "ToChild should be true.");
|
||||
});
|
||||
|
||||
await promise;
|
||||
});
|
||||
},
|
||||
});
|
|
@ -0,0 +1,14 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
declTest("sendQuery testing", {
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
let actorParent = parent.getActor("Test");
|
||||
ok(actorParent, "JSWindowActorParent should have value.");
|
||||
|
||||
let {result} = await actorParent.sendQuery("asyncAdd", {a: 10, b: 20});
|
||||
is(result, 30);
|
||||
},
|
||||
});
|
|
@ -0,0 +1,75 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Provide infrastructure for JSWindowActor tests.
|
||||
*/
|
||||
|
||||
const URL = "about:blank";
|
||||
const TEST_URL = "http://test2.example.org/";
|
||||
let windowActorOptions = {
|
||||
parent: {
|
||||
moduleURI: "resource://testing-common/TestParent.jsm",
|
||||
},
|
||||
child: {
|
||||
moduleURI: "resource://testing-common/TestChild.jsm",
|
||||
|
||||
events: {
|
||||
"mozshowdropdown": {},
|
||||
},
|
||||
|
||||
observers: [
|
||||
"test-js-window-actor-child-observer",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
function declTest(name, cfg) {
|
||||
let {
|
||||
url = "about:blank",
|
||||
allFrames = false,
|
||||
includeChrome = false,
|
||||
matches,
|
||||
remoteTypes,
|
||||
fission,
|
||||
test,
|
||||
} = cfg;
|
||||
|
||||
// Build the actor options object which will be used to register & unregister our window actor.
|
||||
let actorOptions = {
|
||||
parent: Object.assign({}, windowActorOptions.parent),
|
||||
child: Object.assign({}, windowActorOptions.child),
|
||||
};
|
||||
actorOptions.allFrames = allFrames;
|
||||
actorOptions.includeChrome = includeChrome;
|
||||
if (matches !== undefined) {
|
||||
actorOptions.matches = matches;
|
||||
}
|
||||
if (remoteTypes !== undefined) {
|
||||
actorOptions.remoteTypes = remoteTypes;
|
||||
}
|
||||
|
||||
// Add a new task for the actor test declared here.
|
||||
add_task(async function() {
|
||||
info("Entering test: " + name);
|
||||
|
||||
// Create a fresh window with the correct settings, and register our actor.
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow({remote: true, fission});
|
||||
ChromeUtils.registerWindowActor("Test", actorOptions);
|
||||
|
||||
// Wait for the provided URL to load in our browser
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
BrowserTestUtils.loadURI(browser, url);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
// Run the provided test
|
||||
info("browser ready");
|
||||
await Promise.resolve(test(browser, win));
|
||||
|
||||
// Clean up after we're done.
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
||||
info("Exiting test: " + name);
|
||||
});
|
||||
}
|
|
@ -9,6 +9,5 @@ support-files =
|
|||
skip-if = !e10 # This is an e10s only probe.
|
||||
[browser_remote_navigation_delay_telemetry.js]
|
||||
skip-if = !e10s # This is an e10s only probe.
|
||||
[browser_JSWindowActor.js]
|
||||
[browser_cancel_content_js.js]
|
||||
skip-if = !e10s # This is an e10s only probe.
|
|
@ -1,479 +0,0 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
// This test opens and closes a large number of windows, which can be slow
|
||||
// especially on debug builds. This decreases the likelihood of the test timing
|
||||
// out.
|
||||
requestLongerTimeout(4);
|
||||
|
||||
const URL = "about:blank";
|
||||
const TEST_URL = "http://test2.example.org/";
|
||||
let windowActorOptions = {
|
||||
parent: {
|
||||
moduleURI: "resource://testing-common/TestParent.jsm",
|
||||
},
|
||||
child: {
|
||||
moduleURI: "resource://testing-common/TestChild.jsm",
|
||||
|
||||
events: {
|
||||
"mozshowdropdown": {},
|
||||
},
|
||||
|
||||
observers: [
|
||||
"test-js-window-actor-child-observer",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
function declTest(name, cfg) {
|
||||
let {
|
||||
url = "about:blank",
|
||||
allFrames = false,
|
||||
includeChrome = false,
|
||||
matches,
|
||||
remoteTypes,
|
||||
fission,
|
||||
test,
|
||||
} = cfg;
|
||||
|
||||
// Build the actor options object which will be used to register & unregister our window actor.
|
||||
let actorOptions = {
|
||||
parent: Object.assign({}, windowActorOptions.parent),
|
||||
child: Object.assign({}, windowActorOptions.child),
|
||||
};
|
||||
actorOptions.allFrames = allFrames;
|
||||
actorOptions.includeChrome = includeChrome;
|
||||
if (matches !== undefined) {
|
||||
actorOptions.matches = matches;
|
||||
}
|
||||
if (remoteTypes !== undefined) {
|
||||
actorOptions.remoteTypes = remoteTypes;
|
||||
}
|
||||
|
||||
// Add a new task for the actor test declared here.
|
||||
add_task(async function() {
|
||||
info("Entering test: " + name);
|
||||
|
||||
// Create a fresh window with the correct settings, and register our actor.
|
||||
let win = await BrowserTestUtils.openNewBrowserWindow({remote: true, fission});
|
||||
ChromeUtils.registerWindowActor("Test", actorOptions);
|
||||
|
||||
// Wait for the provided URL to load in our browser
|
||||
let browser = win.gBrowser.selectedBrowser;
|
||||
BrowserTestUtils.loadURI(browser, url);
|
||||
await BrowserTestUtils.browserLoaded(browser);
|
||||
|
||||
// Run the provided test
|
||||
info("browser ready");
|
||||
await Promise.resolve(test(browser, win));
|
||||
|
||||
// Clean up after we're done.
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
await BrowserTestUtils.closeWindow(win);
|
||||
|
||||
info("Exiting test: " + name);
|
||||
});
|
||||
}
|
||||
|
||||
declTest("double register", {
|
||||
async test() {
|
||||
SimpleTest.doesThrow(() =>
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions),
|
||||
"Should throw if register has duplicate name.");
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor on both sides", {
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
ok(parent, "WindowGlobalParent should have value.");
|
||||
let actorParent = parent.getActor("Test");
|
||||
is(actorParent.show(), "TestParent", "actor show should have vaule.");
|
||||
is(actorParent.manager, parent, "manager should match WindowGlobalParent.");
|
||||
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
is(child.isInProcess, false, "Actor should be loaded in the content process.");
|
||||
let actorChild = child.getActor("Test");
|
||||
is(actorChild.show(), "TestChild", "actor show should have vaule.");
|
||||
is(actorChild.manager, child, "manager should match WindowGlobalChild.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("asyncMessage testing", {
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
let actorParent = parent.getActor("Test");
|
||||
ok(actorParent, "JSWindowActorParent should have value.");
|
||||
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
|
||||
let promise = new Promise(resolve => {
|
||||
actorChild.sendAsyncMessage("init", {});
|
||||
actorChild.done = (data) => resolve(data);
|
||||
}).then(data => {
|
||||
ok(data.initial, "Initial should be true.");
|
||||
ok(data.toParent, "ToParent should be true.");
|
||||
ok(data.toChild, "ToChild should be true.");
|
||||
});
|
||||
|
||||
await promise;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("sendQuery testing", {
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
let actorParent = parent.getActor("Test");
|
||||
ok(actorParent, "JSWindowActorParent should have value.");
|
||||
|
||||
let {result} = await actorParent.sendQuery("asyncAdd", {a: 10, b: 20});
|
||||
is(result, 30);
|
||||
},
|
||||
});
|
||||
|
||||
declTest("asyncMessage without both sides", {
|
||||
async test(browser) {
|
||||
// If we don't create a parent actor, make sure the parent actor
|
||||
// gets created by having sent the message.
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
|
||||
let promise = new Promise(resolve => {
|
||||
actorChild.sendAsyncMessage("init", {});
|
||||
actorChild.done = (data) => resolve(data);
|
||||
}).then(data => {
|
||||
ok(data.initial, "Initial should be true.");
|
||||
ok(data.toParent, "ToParent should be true.");
|
||||
ok(data.toChild, "ToChild should be true.");
|
||||
});
|
||||
|
||||
await promise;
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("test event triggering actor creation", {
|
||||
async test(browser) {
|
||||
// Add a select element to the DOM of the loaded document.
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
content.document.body.innerHTML += `
|
||||
<select id="testSelect">
|
||||
<option>A</option>
|
||||
<option>B</option>
|
||||
</select>`;
|
||||
});
|
||||
|
||||
// Wait for the observer notification.
|
||||
let observePromise = new Promise(resolve => {
|
||||
const TOPIC = "test-js-window-actor-parent-event";
|
||||
Services.obs.addObserver(function obs(subject, topic, data) {
|
||||
is(topic, TOPIC, "topic matches");
|
||||
|
||||
Services.obs.removeObserver(obs, TOPIC);
|
||||
resolve({subject, data});
|
||||
}, TOPIC);
|
||||
});
|
||||
|
||||
// Click on the select to show the dropdown.
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter("#testSelect", {}, browser);
|
||||
|
||||
// Wait for the observer notification to fire, and inspect the results.
|
||||
let {subject, data} = await observePromise;
|
||||
is(data, "mozshowdropdown");
|
||||
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
let actorParent = parent.getActor("Test");
|
||||
ok(actorParent, "JSWindowActorParent should have value.");
|
||||
is(subject.wrappedJSObject, actorParent, "Should have been recieved on the right actor");
|
||||
},
|
||||
});
|
||||
|
||||
declTest("test observer triggering actor creation", {
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
const TOPIC = "test-js-window-actor-child-observer";
|
||||
Services.obs.notifyObservers(content.window, TOPIC, "dataString");
|
||||
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
let {subject, topic, data} = actorChild.lastObserved;
|
||||
|
||||
is(subject.getWindowGlobalChild().getActor("Test"), actorChild, "Should have been recieved on the right actor");
|
||||
is(topic, TOPIC, "Topic matches");
|
||||
is(data, "dataString", "Data matches");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("test observers with null data", {
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
const TOPIC = "test-js-window-actor-child-observer";
|
||||
Services.obs.notifyObservers(content.window, TOPIC);
|
||||
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
let {subject, topic, data} = actorChild.lastObserved;
|
||||
|
||||
is(subject.getWindowGlobalChild().getActor("Test"), actorChild, "Should have been recieved on the right actor");
|
||||
is(topic, TOPIC, "Topic matches");
|
||||
is(data, null, "Data matches");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("observers don't notify with wrong window", {
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
const TOPIC = "test-js-window-actor-child-observer";
|
||||
Services.obs.notifyObservers(null, TOPIC);
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
is(actorChild.lastObserved, undefined, "Should not receive wrong window's observer notification!");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with mismatch", {
|
||||
matches: ["*://*/*"],
|
||||
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
ok(parent, "WindowGlobalParent should have value.");
|
||||
Assert.throws(() => parent.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if it doesn't match.");
|
||||
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if it doesn't match.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with matches", {
|
||||
matches: ["*://*/*"],
|
||||
url: TEST_URL,
|
||||
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
ok(parent.getActor("Test"), "JSWindowActorParent should have value.");
|
||||
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
ok(child.getActor("Test"), "JSWindowActorChild should have value.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with iframe matches", {
|
||||
allFrames: true,
|
||||
matches: ["*://*/*"],
|
||||
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, TEST_URL, async function(url) {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
frame.src = url;
|
||||
content.document.body.appendChild(frame);
|
||||
await ContentTaskUtils.waitForEvent(frame, "load");
|
||||
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
ok(child.getActor("Test"), "JSWindowActorChild should have value.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with iframe mismatch", {
|
||||
allFrames: true,
|
||||
matches: ["about:home"],
|
||||
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, TEST_URL, async function(url) {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
frame.src = url;
|
||||
content.document.body.appendChild(frame);
|
||||
await ContentTaskUtils.waitForEvent(frame, "load");
|
||||
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if it doesn't match.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with remoteType match", {
|
||||
remoteTypes: ["web"],
|
||||
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
ok(parent.getActor("Test"), "JSWindowActorParent should have value.");
|
||||
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
ok(child.getActor("Test"), "JSWindowActorChild should have value.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with remoteType mismatch", {
|
||||
remoteTypes: ["privileged"],
|
||||
url: TEST_URL,
|
||||
|
||||
async test(browser) {
|
||||
let parent = browser.browsingContext.currentWindowGlobal;
|
||||
Assert.throws(() => parent.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if its remoteTypes don't match.");
|
||||
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if its remoteTypes don't match.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor without allFrames", {
|
||||
allFrames: false,
|
||||
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
content.document.body.appendChild(frame);
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/NS_ERROR_NOT_AVAILABLE/, "Should throw if allFrames is false.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with allFrames", {
|
||||
allFrames: true,
|
||||
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
content.document.body.appendChild(frame);
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor without includeChrome", {
|
||||
includeChrome: false,
|
||||
|
||||
async test(_browser, win) {
|
||||
let parent = win.docShell.browsingContext.currentWindowGlobal;
|
||||
SimpleTest.doesThrow(() =>
|
||||
parent.getActor("Test"),
|
||||
"Should throw if includeChrome is false.");
|
||||
},
|
||||
});
|
||||
|
||||
declTest("getActor with includeChrome", {
|
||||
includeChrome: true,
|
||||
|
||||
async test(_browser, win) {
|
||||
let parent = win.docShell.browsingContext.currentWindowGlobal;
|
||||
let actorParent = parent.getActor("Test");
|
||||
ok(actorParent, "JSWindowActorParent should have value.");
|
||||
},
|
||||
});
|
||||
|
||||
declTest("destroy actor by iframe remove", {
|
||||
allFrames: true,
|
||||
|
||||
async test(browser) {
|
||||
await ContentTask.spawn(browser, {}, async function() {
|
||||
// Create and append an iframe into the window's document.
|
||||
let frame = content.document.createElement("iframe");
|
||||
frame.id = "frame";
|
||||
content.document.body.appendChild(frame);
|
||||
await ContentTaskUtils.waitForEvent(frame, "load");
|
||||
is(content.window.frames.length, 1, "There should be an iframe.");
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
|
||||
let willDestroyPromise = new Promise(resolve => {
|
||||
const TOPIC = "test-js-window-actor-willdestroy";
|
||||
Services.obs.addObserver(function obs(subject, topic, data) {
|
||||
ok(data, "willDestroyCallback data should be true.");
|
||||
|
||||
Services.obs.removeObserver(obs, TOPIC);
|
||||
resolve();
|
||||
}, TOPIC);
|
||||
});
|
||||
|
||||
let didDestroyPromise = new Promise(resolve => {
|
||||
const TOPIC = "test-js-window-actor-diddestroy";
|
||||
Services.obs.addObserver(function obs(subject, topic, data) {
|
||||
ok(data, "didDestroyCallback data should be true.");
|
||||
|
||||
Services.obs.removeObserver(obs, TOPIC);
|
||||
resolve();
|
||||
}, TOPIC);
|
||||
});
|
||||
|
||||
info("Remove frame");
|
||||
content.document.getElementById("frame").remove();
|
||||
await Promise.all([willDestroyPromise, didDestroyPromise]);
|
||||
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/InvalidStateError/, "Should throw if frame destroy.");
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
declTest("destroy actor by page navigates", {
|
||||
allFrames: true,
|
||||
|
||||
async test(browser) {
|
||||
info("creating an in-process frame");
|
||||
await ContentTask.spawn(browser, URL, async function(url) {
|
||||
let frame = content.document.createElement("iframe");
|
||||
frame.src = url;
|
||||
content.document.body.appendChild(frame);
|
||||
});
|
||||
|
||||
info("navigating page");
|
||||
await ContentTask.spawn(browser, TEST_URL, async function(url) {
|
||||
let frame = content.document.querySelector("iframe");
|
||||
frame.contentWindow.location = url;
|
||||
let child = frame.contentWindow.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
await ContentTaskUtils.waitForEvent(frame, "load");
|
||||
|
||||
Assert.throws(() => child.getActor("Test"),
|
||||
/InvalidStateError/, "Should throw if frame destroy.");
|
||||
});
|
||||
},
|
||||
});
|
|
@ -4,5 +4,4 @@ support-files =
|
|||
process_error.xul
|
||||
|
||||
[test_process_error.xul]
|
||||
skip-if = !crashreporter
|
||||
[test_JSWindowActor.xul]
|
||||
skip-if = !crashreporter
|
|
@ -1,96 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
<window title="Test JSWindowActor"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
|
||||
<!-- test results are displayed in the html:body -->
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
</body>
|
||||
|
||||
<!-- test code goes here -->
|
||||
<script type="application/javascript"><![CDATA[
|
||||
const {Services} = ChromeUtils.import("resource://gre/modules/Services.jsm");
|
||||
const URL = "about:blank";
|
||||
let windowActorOptions = {
|
||||
allFrames: true,
|
||||
parent: {
|
||||
moduleURI: "resource://testing-common/TestParent.jsm",
|
||||
},
|
||||
child: {
|
||||
moduleURI: "resource://testing-common/TestChild.jsm",
|
||||
observers: [
|
||||
"test-js-window-actor-child-observer",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
add_task(async function registerWindowActor() {
|
||||
ok(ChromeUtils, "Should be able to get the ChromeUtils interface");
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
SimpleTest.doesThrow(() =>
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions),
|
||||
"Should throw if register has duplicate name.");
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
|
||||
add_task(async function getActor() {
|
||||
// Test in-process getActor function
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
let parent = this.window.docShell.browsingContext.currentWindowGlobal;
|
||||
ok(parent, "WindowGlobalParent should have value.");
|
||||
let actorParent = parent.getActor("Test");
|
||||
is(actorParent.show(), "TestParent", "actor show should have vaule.");
|
||||
is(actorParent.manager, parent, "manager should match WindowGlobalParent.");
|
||||
|
||||
let child = this.window.getWindowGlobalChild();
|
||||
ok(child, "WindowGlobalChild should have value.");
|
||||
is(child.isInProcess, true, "Actor should be in-process.");
|
||||
let actorChild = child.getActor("Test");
|
||||
|
||||
is(actorChild.show(), "TestChild", "actor show should have vaule.");
|
||||
is(actorChild.manager, child, "manager should match WindowGlobalChild.");
|
||||
ok(parent.childActor===child, "Actor should be the same.");
|
||||
ok(parent.childActor.getActor("Test")===child.getActor("Test"), "GetActor should be the same.");
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
|
||||
add_task(async function asyncMessage() {
|
||||
// Test in-process send/recvAsyncMessage function
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
let child = this.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
let promise = new Promise(resolve => {
|
||||
actorChild.sendAsyncMessage("init", {});
|
||||
actorChild.done = (data) => resolve(data);
|
||||
}).then(data => {
|
||||
ok(data.initial, "Initial should be true.");
|
||||
ok(data.toParent, "ToParent should be true.");
|
||||
ok(data.toChild, "ToChild should be true.");
|
||||
});
|
||||
|
||||
await promise;
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
|
||||
add_task(async function observers() {
|
||||
// Test in-process observers notification
|
||||
ChromeUtils.registerWindowActor("Test", windowActorOptions);
|
||||
const TOPIC = "test-js-window-actor-child-observer";
|
||||
Services.obs.notifyObservers(content.window, TOPIC, "dataString");
|
||||
|
||||
let child = content.window.getWindowGlobalChild();
|
||||
let actorChild = child.getActor("Test");
|
||||
ok(actorChild, "JSWindowActorChild should have value.");
|
||||
let {subject, topic, data} = actorChild.lastObserved;
|
||||
|
||||
is(subject.getWindowGlobalChild().getActor("Test"), actorChild, "Should have been recieved on the right actor");
|
||||
is(topic, TOPIC, "Topic matches");
|
||||
is(data, "dataString", "Data matches");
|
||||
ChromeUtils.unregisterWindowActor("Test");
|
||||
});
|
||||
|
||||
]]></script>
|
||||
</window>
|
|
@ -654,6 +654,17 @@ pub fn create_border_segments(
|
|||
size,
|
||||
);
|
||||
|
||||
let overlap = LayoutSize::new(
|
||||
(widths.left + widths.right - size.width).max(0.0),
|
||||
(widths.top + widths.bottom - size.height).max(0.0),
|
||||
);
|
||||
let non_overlapping_widths = LayoutSideOffsets::new(
|
||||
widths.top - overlap.height / 2.0,
|
||||
widths.right - overlap.width / 2.0,
|
||||
widths.bottom - overlap.height / 2.0,
|
||||
widths.left - overlap.width / 2.0,
|
||||
);
|
||||
|
||||
let local_size_tl = LayoutSize::new(
|
||||
border.radius.top_left.width.max(widths.left),
|
||||
border.radius.top_left.height.max(widths.top),
|
||||
|
@ -697,12 +708,12 @@ pub fn create_border_segments(
|
|||
LayoutRect::from_floats(
|
||||
rect.origin.x,
|
||||
rect.origin.y + local_size_tl.height + left_edge_info.local_offset,
|
||||
rect.origin.x + widths.left,
|
||||
rect.origin.x + non_overlapping_widths.left,
|
||||
rect.origin.y + local_size_tl.height + left_edge_info.local_offset + left_edge_info.local_size,
|
||||
),
|
||||
&left_edge_info,
|
||||
border.left,
|
||||
widths.left,
|
||||
non_overlapping_widths.left,
|
||||
BorderSegment::Left,
|
||||
EdgeAaSegmentMask::LEFT | EdgeAaSegmentMask::RIGHT,
|
||||
brush_segments,
|
||||
|
@ -714,11 +725,11 @@ pub fn create_border_segments(
|
|||
rect.origin.x + local_size_tl.width + top_edge_info.local_offset,
|
||||
rect.origin.y,
|
||||
rect.origin.x + local_size_tl.width + top_edge_info.local_offset + top_edge_info.local_size,
|
||||
rect.origin.y + widths.top,
|
||||
rect.origin.y + non_overlapping_widths.top,
|
||||
),
|
||||
&top_edge_info,
|
||||
border.top,
|
||||
widths.top,
|
||||
non_overlapping_widths.top,
|
||||
BorderSegment::Top,
|
||||
EdgeAaSegmentMask::TOP | EdgeAaSegmentMask::BOTTOM,
|
||||
brush_segments,
|
||||
|
@ -727,14 +738,14 @@ pub fn create_border_segments(
|
|||
);
|
||||
add_edge_segment(
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x + rect.size.width - widths.right,
|
||||
rect.origin.x + rect.size.width - non_overlapping_widths.right,
|
||||
rect.origin.y + local_size_tr.height + right_edge_info.local_offset,
|
||||
rect.origin.x + rect.size.width,
|
||||
rect.origin.y + local_size_tr.height + right_edge_info.local_offset + right_edge_info.local_size,
|
||||
),
|
||||
&right_edge_info,
|
||||
border.right,
|
||||
widths.right,
|
||||
non_overlapping_widths.right,
|
||||
BorderSegment::Right,
|
||||
EdgeAaSegmentMask::RIGHT | EdgeAaSegmentMask::LEFT,
|
||||
brush_segments,
|
||||
|
@ -744,13 +755,13 @@ pub fn create_border_segments(
|
|||
add_edge_segment(
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x + local_size_bl.width + bottom_edge_info.local_offset,
|
||||
rect.origin.y + rect.size.height - widths.bottom,
|
||||
rect.origin.y + rect.size.height - non_overlapping_widths.bottom,
|
||||
rect.origin.x + local_size_bl.width + bottom_edge_info.local_offset + bottom_edge_info.local_size,
|
||||
rect.origin.y + rect.size.height,
|
||||
),
|
||||
&bottom_edge_info,
|
||||
border.bottom,
|
||||
widths.bottom,
|
||||
non_overlapping_widths.bottom,
|
||||
BorderSegment::Bottom,
|
||||
EdgeAaSegmentMask::BOTTOM | EdgeAaSegmentMask::TOP,
|
||||
brush_segments,
|
||||
|
@ -768,8 +779,8 @@ pub fn create_border_segments(
|
|||
LayoutRect::from_floats(
|
||||
rect.origin.x,
|
||||
rect.origin.y,
|
||||
rect.max_x() - widths.right,
|
||||
rect.max_y() - widths.bottom
|
||||
rect.max_x() - non_overlapping_widths.right,
|
||||
rect.max_y() - non_overlapping_widths.bottom
|
||||
),
|
||||
border.left,
|
||||
border.top,
|
||||
|
@ -793,10 +804,10 @@ pub fn create_border_segments(
|
|||
rect.origin.y + local_size_tr.height,
|
||||
),
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x + widths.left,
|
||||
rect.origin.x + non_overlapping_widths.left,
|
||||
rect.origin.y,
|
||||
rect.max_x(),
|
||||
rect.max_y() - widths.bottom,
|
||||
rect.max_y() - non_overlapping_widths.bottom,
|
||||
),
|
||||
border.top,
|
||||
border.right,
|
||||
|
@ -820,8 +831,8 @@ pub fn create_border_segments(
|
|||
rect.origin.y + rect.size.height,
|
||||
),
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x + widths.left,
|
||||
rect.origin.y + widths.top,
|
||||
rect.origin.x + non_overlapping_widths.left,
|
||||
rect.origin.y + non_overlapping_widths.top,
|
||||
rect.max_x(),
|
||||
rect.max_y(),
|
||||
),
|
||||
|
@ -848,8 +859,8 @@ pub fn create_border_segments(
|
|||
),
|
||||
LayoutRect::from_floats(
|
||||
rect.origin.x,
|
||||
rect.origin.y + widths.top,
|
||||
rect.max_x() - widths.right,
|
||||
rect.origin.y + non_overlapping_widths.top,
|
||||
rect.max_x() - non_overlapping_widths.right,
|
||||
rect.max_y(),
|
||||
),
|
||||
border.bottom,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
---
|
||||
--- # Checks that corners are clipped correctly when they overlap with an adjacent corner
|
||||
root:
|
||||
items:
|
||||
- type: stacking-context
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
root:
|
||||
items:
|
||||
- type: stacking-context
|
||||
bounds: [0, 0, 120, 40]
|
||||
items:
|
||||
- type: rect
|
||||
bounds: [ 10, 10, 100, 20 ]
|
||||
color: [ 0, 0, 255, 0.5 ]
|
|
@ -0,0 +1,12 @@
|
|||
--- # Checks that segments are clipped correctly when opposite edges of the border overlap
|
||||
root:
|
||||
items:
|
||||
- type: stacking-context
|
||||
bounds: [0, 0, 120, 40]
|
||||
items:
|
||||
- type: border
|
||||
bounds: [ 10, 10, 100, 20 ]
|
||||
width: 15
|
||||
border-type: normal
|
||||
style: solid
|
||||
color: [ [0, 0, 255, 0.5] ]
|
|
@ -5,7 +5,8 @@ platform(linux,mac) == border-gradient-nine-patch.yaml border-gradient-nine-patc
|
|||
platform(linux,mac) == border-radial-gradient-nine-patch.yaml border-radial-gradient-nine-patch.png
|
||||
== border-radii.yaml border-radii.png
|
||||
== border-none.yaml border-none-ref.yaml
|
||||
fuzzy(1,68) == border-overlapping.yaml border-overlapping-ref.yaml
|
||||
fuzzy(1,68) == border-overlapping-corner.yaml border-overlapping-corner-ref.yaml
|
||||
== border-overlapping-edge.yaml border-overlapping-edge-ref.yaml
|
||||
== border-invisible.yaml border-invisible-ref.yaml
|
||||
platform(linux,mac) == border-suite.yaml border-suite.png
|
||||
platform(linux,mac) fuzzy(8,8) == border-suite-2.yaml border-suite-2.png
|
||||
|
|
|
@ -163,8 +163,7 @@ MethodStatus BaselineCompiler::compile() {
|
|||
AutoTraceLog logCompile(logger, TraceLogger_BaselineCompilation);
|
||||
|
||||
AutoKeepTypeScripts keepTypes(cx);
|
||||
if (!script->ensureHasTypes(cx, keepTypes) ||
|
||||
!script->ensureHasAnalyzedArgsUsage(cx)) {
|
||||
if (!script->ensureHasTypes(cx, keepTypes)) {
|
||||
return Method_Error;
|
||||
}
|
||||
|
||||
|
@ -416,7 +415,7 @@ static void LoadInlineValueOperand(MacroAssembler& masm, Register pc,
|
|||
// Note: the Value might be unaligned but as above we rely on all our
|
||||
// platforms having appropriate support for unaligned accesses (except for
|
||||
// floating point instructions on ARM).
|
||||
masm.loadValue(Address(pc, sizeof(jsbytecode)), dest);
|
||||
masm.loadUnalignedValue(Address(pc, sizeof(jsbytecode)), dest);
|
||||
}
|
||||
|
||||
template <>
|
||||
|
@ -797,6 +796,38 @@ void BaselineInterpreterCodeGen::emitIsDebuggeeCheck() {
|
|||
handler.setDebuggeeCheckOffset(toggleOffset);
|
||||
}
|
||||
|
||||
static void MaybeIncrementCodeCoverageCounter(MacroAssembler& masm,
|
||||
JSScript* script,
|
||||
jsbytecode* pc) {
|
||||
if (!script->hasScriptCounts()) {
|
||||
return;
|
||||
}
|
||||
PCCounts* counts = script->maybeGetPCCounts(pc);
|
||||
uint64_t* counterAddr = &counts->numExec();
|
||||
masm.inc64(AbsoluteAddress(counterAddr));
|
||||
}
|
||||
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::emitHandleCodeCoverageAtPrologue() {
|
||||
// If the main instruction is not a jump target, then we emit the
|
||||
// corresponding code coverage counter.
|
||||
JSScript* script = handler.script();
|
||||
jsbytecode* main = script->main();
|
||||
if (!BytecodeIsJumpTarget(JSOp(*main))) {
|
||||
MaybeIncrementCodeCoverageCounter(masm, script, main);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template <>
|
||||
bool BaselineInterpreterCodeGen::emitHandleCodeCoverageAtPrologue() {
|
||||
Label skipCoverage;
|
||||
CodeOffset toggleOffset = masm.toggledJump(&skipCoverage);
|
||||
masm.call(handler.codeCoverageAtPrologueLabel());
|
||||
masm.bind(&skipCoverage);
|
||||
return handler.codeCoverageOffsets().append(toggleOffset.offset());
|
||||
}
|
||||
|
||||
template <>
|
||||
void BaselineCompilerCodeGen::subtractScriptSlotsSize(Register reg,
|
||||
Register scratch) {
|
||||
|
@ -6111,13 +6142,7 @@ bool BaselineCodeGen<Handler>::emit_JSOP_IS_CONSTRUCTING() {
|
|||
|
||||
template <>
|
||||
bool BaselineCompilerCodeGen::emit_JSOP_JUMPTARGET() {
|
||||
JSScript* script = handler.script();
|
||||
if (!script->hasScriptCounts()) {
|
||||
return true;
|
||||
}
|
||||
PCCounts* counts = script->maybeGetPCCounts(handler.pc());
|
||||
uint64_t* counterAddr = &counts->numExec();
|
||||
masm.inc64(AbsoluteAddress(counterAddr));
|
||||
MaybeIncrementCodeCoverageCounter(masm, handler.script(), handler.pc());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6126,6 +6151,14 @@ bool BaselineInterpreterCodeGen::emit_JSOP_JUMPTARGET() {
|
|||
Register scratch1 = R0.scratchReg();
|
||||
Register scratch2 = R1.scratchReg();
|
||||
|
||||
Label skipCoverage;
|
||||
CodeOffset toggleOffset = masm.toggledJump(&skipCoverage);
|
||||
masm.call(handler.codeCoverageAtPCLabel());
|
||||
masm.bind(&skipCoverage);
|
||||
if (!handler.codeCoverageOffsets().append(toggleOffset.offset())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load icIndex in scratch1.
|
||||
LoadInt32Operand(masm, PCRegAtStart, scratch1);
|
||||
|
||||
|
@ -6467,6 +6500,10 @@ bool BaselineCodeGen<Handler>::emitPrologue() {
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!emitHandleCodeCoverageAtPrologue()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!emitWarmUpCounterIncrement()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -6586,14 +6623,6 @@ MethodStatus BaselineCompiler::emitBody() {
|
|||
|
||||
MOZ_ASSERT(masm.framePushed() == 0);
|
||||
|
||||
// If the main instruction is not a jump target, then we emit the
|
||||
// corresponding code coverage counter.
|
||||
if (handler.pc() == script->main() && !BytecodeIsJumpTarget(op)) {
|
||||
if (!emit_JSOP_JUMPTARGET()) {
|
||||
return Method_Error;
|
||||
}
|
||||
}
|
||||
|
||||
// Test if last instructions and stop emitting in that case.
|
||||
handler.moveToNextPC();
|
||||
if (handler.pc() >= script->codeEnd()) {
|
||||
|
@ -6630,11 +6659,149 @@ bool BaselineInterpreterGenerator::emitDebugTrap() {
|
|||
}
|
||||
|
||||
bool BaselineInterpreterGenerator::emitInterpreterLoop() {
|
||||
MOZ_CRASH("NYI: interpreter emitInterpreterLoop");
|
||||
Register scratch1 = R0.scratchReg();
|
||||
Register scratch2 = R1.scratchReg();
|
||||
|
||||
Address pcAddr = frame.addressOfInterpreterPC();
|
||||
|
||||
// Entry point for interpreting a bytecode op. No registers are live. PC is
|
||||
// loaded from frame->interpreterPC.
|
||||
masm.bind(handler.interpretOpLabel());
|
||||
interpretOpOffset_ = masm.currentOffset();
|
||||
|
||||
// Emit a patchable call for debugger breakpoints/stepping.
|
||||
if (!emitDebugTrap()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load pc, bytecode op.
|
||||
masm.loadPtr(pcAddr, PCRegAtStart);
|
||||
masm.load8ZeroExtend(Address(PCRegAtStart, 0), scratch1);
|
||||
|
||||
// Jump to table[op].
|
||||
{
|
||||
CodeOffset label = masm.movWithPatch(ImmWord(uintptr_t(-1)), scratch2);
|
||||
if (!tableLabels_.append(label)) {
|
||||
return false;
|
||||
}
|
||||
BaseIndex pointer(scratch2, scratch1, ScalePointer);
|
||||
masm.branchToComputedAddress(pointer);
|
||||
}
|
||||
|
||||
// At the end of each op, emit code to bump the pc and jump to the
|
||||
// next op (this is also known as a threaded interpreter).
|
||||
auto opEpilogue = [&](JSOp op, size_t opLength) -> bool {
|
||||
MOZ_ASSERT(masm.framePushed() == 0);
|
||||
|
||||
if (!BytecodeFallsThrough(op)) {
|
||||
// Nothing to do.
|
||||
masm.assumeUnreachable("unexpected fall through");
|
||||
return true;
|
||||
}
|
||||
|
||||
// Bump frame->interpreterICEntry if needed.
|
||||
if (BytecodeOpHasIC(op)) {
|
||||
masm.addPtr(Imm32(sizeof(ICEntry)), frame.addressOfInterpreterICEntry());
|
||||
}
|
||||
|
||||
// Bump frame->interpreterPC, keep pc in PCRegAtStart.
|
||||
masm.loadPtr(pcAddr, PCRegAtStart);
|
||||
masm.addPtr(Imm32(opLength), PCRegAtStart);
|
||||
masm.storePtr(PCRegAtStart, pcAddr);
|
||||
|
||||
if (!emitDebugTrap()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Load the opcode, jump to table[op].
|
||||
masm.load8ZeroExtend(Address(PCRegAtStart, 0), scratch1);
|
||||
CodeOffset label = masm.movWithPatch(ImmWord(uintptr_t(-1)), scratch2);
|
||||
if (!tableLabels_.append(label)) {
|
||||
return false;
|
||||
}
|
||||
BaseIndex pointer(scratch2, scratch1, ScalePointer);
|
||||
masm.branchToComputedAddress(pointer);
|
||||
return true;
|
||||
};
|
||||
|
||||
// Emit code for each bytecode op.
|
||||
Label opLabels[JSOP_LIMIT];
|
||||
#define EMIT_OP(OP) \
|
||||
{ \
|
||||
masm.bind(&opLabels[OP]); \
|
||||
if (!this->emit_##OP()) { \
|
||||
return false; \
|
||||
} \
|
||||
if (!opEpilogue(OP, OP##_LENGTH)) { \
|
||||
return false; \
|
||||
} \
|
||||
}
|
||||
OPCODE_LIST(EMIT_OP)
|
||||
#undef EMIT_OP
|
||||
|
||||
// Emit code for JSOP_UNUSED* ops.
|
||||
Label invalidOp;
|
||||
masm.bind(&invalidOp);
|
||||
masm.assumeUnreachable("Invalid op");
|
||||
|
||||
// Emit the table.
|
||||
masm.haltingAlign(sizeof(void*));
|
||||
|
||||
#if defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)
|
||||
size_t numInstructions = JSOP_LIMIT * (sizeof(uintptr_t) / sizeof(uint32_t));
|
||||
AutoForbidPoolsAndNops afp(&masm, numInstructions);
|
||||
#endif
|
||||
|
||||
tableOffset_ = masm.currentOffset();
|
||||
|
||||
for (size_t i = 0; i < JSOP_LIMIT; i++) {
|
||||
// Store a pointer to the code for the current op. If the op's label is not
|
||||
// bound it must be a JSOP_UNUSED* op and we use |invalidOp| instead.
|
||||
const Label& opLabel = opLabels[i];
|
||||
uint32_t opOffset = opLabel.bound() ? opLabel.offset() : invalidOp.offset();
|
||||
CodeLabel cl;
|
||||
masm.writeCodePointer(&cl);
|
||||
cl.target()->bind(opOffset);
|
||||
masm.addCodeLabel(cl);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void BaselineInterpreterGenerator::emitOutOfLineCodeCoverageInstrumentation() {
|
||||
masm.bind(handler.codeCoverageAtPrologueLabel());
|
||||
#ifdef JS_USE_LINK_REGISTER
|
||||
masm.pushReturnAddress();
|
||||
#endif
|
||||
|
||||
masm.Push(BaselineFrameReg);
|
||||
masm.setupUnalignedABICall(R0.scratchReg());
|
||||
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
|
||||
masm.passABIArg(R0.scratchReg());
|
||||
masm.callWithABI(
|
||||
JS_FUNC_TO_DATA_PTR(void*, jit::HandleCodeCoverageAtPrologue));
|
||||
masm.Pop(BaselineFrameReg);
|
||||
|
||||
masm.ret();
|
||||
|
||||
masm.bind(handler.codeCoverageAtPCLabel());
|
||||
#ifdef JS_USE_LINK_REGISTER
|
||||
masm.pushReturnAddress();
|
||||
#endif
|
||||
|
||||
masm.Push(BaselineFrameReg);
|
||||
masm.Push(PCRegAtStart);
|
||||
masm.setupUnalignedABICall(R0.scratchReg());
|
||||
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
|
||||
masm.passABIArg(R0.scratchReg());
|
||||
masm.passABIArg(PCRegAtStart);
|
||||
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, jit::HandleCodeCoverageAtPC));
|
||||
masm.Pop(PCRegAtStart);
|
||||
masm.Pop(BaselineFrameReg);
|
||||
|
||||
masm.ret();
|
||||
}
|
||||
|
||||
bool BaselineInterpreterGenerator::generate(BaselineInterpreter& interpreter) {
|
||||
if (!emitPrologue()) {
|
||||
return false;
|
||||
|
@ -6652,29 +6819,45 @@ bool BaselineInterpreterGenerator::generate(BaselineInterpreter& interpreter) {
|
|||
return false;
|
||||
}
|
||||
|
||||
Linker linker(masm, "BaselineInterpreter");
|
||||
if (masm.oom()) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
emitOutOfLineCodeCoverageInstrumentation();
|
||||
|
||||
JitCode* code = linker.newCode(cx, CodeKind::Other);
|
||||
if (!code) {
|
||||
return false;
|
||||
}
|
||||
{
|
||||
Linker linker(masm, "BaselineInterpreter");
|
||||
if (masm.oom()) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
|
||||
JitCode* code = linker.newCode(cx, CodeKind::Other);
|
||||
if (!code) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Patch loads now that we know the tableswitch base address.
|
||||
for (CodeOffset off : tableLabels_) {
|
||||
Assembler::PatchDataWithValueCheck(CodeLocationLabel(code, off),
|
||||
ImmPtr(code->raw() + tableOffset_),
|
||||
ImmPtr((void*)-1));
|
||||
}
|
||||
|
||||
#ifdef JS_ION_PERF
|
||||
writePerfSpewerJitCodeProfile(code, "BaselineInterpreter");
|
||||
writePerfSpewerJitCodeProfile(code, "BaselineInterpreter");
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_VTUNE
|
||||
vtune::MarkStub(code, "BaselineInterpreter");
|
||||
vtune::MarkStub(code, "BaselineInterpreter");
|
||||
#endif
|
||||
|
||||
interpreter.init(
|
||||
code, interpretOpOffset_, profilerEnterFrameToggleOffset_.offset(),
|
||||
profilerExitFrameToggleOffset_.offset(),
|
||||
handler.debuggeeCheckOffset().offset(), std::move(debugTrapOffsets_));
|
||||
interpreter.init(
|
||||
code, interpretOpOffset_, profilerEnterFrameToggleOffset_.offset(),
|
||||
profilerExitFrameToggleOffset_.offset(),
|
||||
handler.debuggeeCheckOffset().offset(), std::move(debugTrapOffsets_),
|
||||
std::move(handler.codeCoverageOffsets()));
|
||||
}
|
||||
|
||||
if (coverage::IsLCovEnabled()) {
|
||||
interpreter.toggleCodeCoverageInstrumentationUnchecked(true);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -6687,6 +6870,10 @@ JitCode* JitRuntime::generateDebugTrapHandler(JSContext* cx,
|
|||
regs.takeUnchecked(BaselineFrameReg);
|
||||
regs.takeUnchecked(ICStubReg);
|
||||
regs.takeUnchecked(PCRegAtStart);
|
||||
#ifdef JS_CODEGEN_ARM
|
||||
regs.takeUnchecked(BaselineSecondScratchReg);
|
||||
masm.setSecondScratchReg(BaselineSecondScratchReg);
|
||||
#endif
|
||||
Register scratch1 = regs.takeAny();
|
||||
Register scratch2 = regs.takeAny();
|
||||
Register scratch3 = regs.takeAny();
|
||||
|
|
|
@ -497,6 +497,8 @@ class BaselineCodeGen {
|
|||
MOZ_MUST_USE bool emitTraceLoggerEnter();
|
||||
MOZ_MUST_USE bool emitTraceLoggerExit();
|
||||
|
||||
MOZ_MUST_USE bool emitHandleCodeCoverageAtPrologue();
|
||||
|
||||
void emitInitFrameFields();
|
||||
void emitIsDebuggeeCheck();
|
||||
void emitInitializeLocals();
|
||||
|
@ -656,6 +658,12 @@ class BaselineInterpreterHandler {
|
|||
Label interpretOp_;
|
||||
CodeOffset debuggeeCheckOffset_;
|
||||
|
||||
// Offsets of toggled jumps for code coverage instrumentation.
|
||||
using CodeOffsetVector = Vector<uint32_t, 0, SystemAllocPolicy>;
|
||||
CodeOffsetVector codeCoverageOffsets_;
|
||||
Label codeCoverageAtPrologueLabel_;
|
||||
Label codeCoverageAtPCLabel_;
|
||||
|
||||
public:
|
||||
using FrameInfoT = InterpreterFrameInfo;
|
||||
|
||||
|
@ -664,6 +672,10 @@ class BaselineInterpreterHandler {
|
|||
InterpreterFrameInfo& frame() { return frame_; }
|
||||
|
||||
Label* interpretOpLabel() { return &interpretOp_; }
|
||||
Label* codeCoverageAtPrologueLabel() { return &codeCoverageAtPrologueLabel_; }
|
||||
Label* codeCoverageAtPCLabel() { return &codeCoverageAtPCLabel_; }
|
||||
|
||||
CodeOffsetVector& codeCoverageOffsets() { return codeCoverageOffsets_; }
|
||||
|
||||
// Interpreter doesn't know the script and pc statically.
|
||||
jsbytecode* maybePC() const { return nullptr; }
|
||||
|
@ -697,7 +709,13 @@ using BaselineInterpreterCodeGen = BaselineCodeGen<BaselineInterpreterHandler>;
|
|||
|
||||
class BaselineInterpreterGenerator final : private BaselineInterpreterCodeGen {
|
||||
// Offsets of patchable call instructions for debugger breakpoints/stepping.
|
||||
js::Vector<uint32_t, 0, SystemAllocPolicy> debugTrapOffsets_;
|
||||
Vector<uint32_t, 0, SystemAllocPolicy> debugTrapOffsets_;
|
||||
|
||||
// Offsets of move instructions for tableswitch base address.
|
||||
Vector<CodeOffset, 0, SystemAllocPolicy> tableLabels_;
|
||||
|
||||
// Offset of the first tableswitch entry.
|
||||
uint32_t tableOffset_ = 0;
|
||||
|
||||
// Offset of the code to start interpreting a bytecode op.
|
||||
uint32_t interpretOpOffset_ = 0;
|
||||
|
@ -710,6 +728,8 @@ class BaselineInterpreterGenerator final : private BaselineInterpreterCodeGen {
|
|||
private:
|
||||
MOZ_MUST_USE bool emitInterpreterLoop();
|
||||
MOZ_MUST_USE bool emitDebugTrap();
|
||||
|
||||
void emitOutOfLineCodeCoverageInstrumentation();
|
||||
};
|
||||
|
||||
} // namespace jit
|
||||
|
|
|
@ -1158,6 +1158,33 @@ void BaselineInterpreter::toggleDebuggerInstrumentation(bool enable) {
|
|||
}
|
||||
}
|
||||
|
||||
void BaselineInterpreter::toggleCodeCoverageInstrumentationUnchecked(
|
||||
bool enable) {
|
||||
if (!JitOptions.baselineInterpreter) {
|
||||
return;
|
||||
}
|
||||
|
||||
AutoWritableJitCode awjc(code_);
|
||||
|
||||
for (uint32_t offset : codeCoverageOffsets_) {
|
||||
CodeLocationLabel label(code_, CodeOffset(offset));
|
||||
if (enable) {
|
||||
Assembler::ToggleToCmp(label);
|
||||
} else {
|
||||
Assembler::ToggleToJmp(label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BaselineInterpreter::toggleCodeCoverageInstrumentation(bool enable) {
|
||||
if (coverage::IsLCovEnabled()) {
|
||||
// Instrumentation is enabled no matter what.
|
||||
return;
|
||||
}
|
||||
|
||||
toggleCodeCoverageInstrumentationUnchecked(enable);
|
||||
}
|
||||
|
||||
void ICScript::purgeOptimizedStubs(JSScript* script) {
|
||||
MOZ_ASSERT(script->icScript() == this);
|
||||
|
||||
|
@ -1426,13 +1453,15 @@ void BaselineInterpreter::init(JitCode* code, uint32_t interpretOpOffset,
|
|||
uint32_t profilerEnterToggleOffset,
|
||||
uint32_t profilerExitToggleOffset,
|
||||
uint32_t debuggeeCheckOffset,
|
||||
DebugTrapOffsets&& debugTrapOffsets) {
|
||||
CodeOffsetVector&& debugTrapOffsets,
|
||||
CodeOffsetVector&& codeCoverageOffsets) {
|
||||
code_ = code;
|
||||
interpretOpOffset_ = interpretOpOffset;
|
||||
profilerEnterToggleOffset_ = profilerEnterToggleOffset;
|
||||
profilerExitToggleOffset_ = profilerExitToggleOffset;
|
||||
debuggeeCheckOffset_ = debuggeeCheckOffset;
|
||||
debugTrapOffsets_ = std::move(debugTrapOffsets);
|
||||
codeCoverageOffsets_ = std::move(codeCoverageOffsets);
|
||||
}
|
||||
|
||||
bool jit::GenerateBaselineInterpreter(JSContext* cx,
|
||||
|
|
|
@ -669,8 +669,11 @@ class BaselineInterpreter {
|
|||
|
||||
// Offsets of toggled calls to the DebugTrapHandler trampoline (for
|
||||
// breakpoints and stepping).
|
||||
using DebugTrapOffsets = js::Vector<uint32_t, 0, SystemAllocPolicy>;
|
||||
DebugTrapOffsets debugTrapOffsets_;
|
||||
using CodeOffsetVector = Vector<uint32_t, 0, SystemAllocPolicy>;
|
||||
CodeOffsetVector debugTrapOffsets_;
|
||||
|
||||
// Offsets of toggled jumps for code coverage.
|
||||
CodeOffsetVector codeCoverageOffsets_;
|
||||
|
||||
public:
|
||||
BaselineInterpreter() = default;
|
||||
|
@ -681,7 +684,8 @@ class BaselineInterpreter {
|
|||
void init(JitCode* code, uint32_t interpretOpOffset,
|
||||
uint32_t profilerEnterToggleOffset,
|
||||
uint32_t profilerExitToggleOffset, uint32_t debuggeeCheckOffset,
|
||||
DebugTrapOffsets&& debugTrapOffsets);
|
||||
CodeOffsetVector&& debugTrapOffsets,
|
||||
CodeOffsetVector&& codeCoverageOffsets);
|
||||
|
||||
uint8_t* codeRaw() const { return code_->raw(); }
|
||||
|
||||
|
@ -691,6 +695,9 @@ class BaselineInterpreter {
|
|||
|
||||
void toggleProfilerInstrumentation(bool enable);
|
||||
void toggleDebuggerInstrumentation(bool enable);
|
||||
|
||||
void toggleCodeCoverageInstrumentationUnchecked(bool enable);
|
||||
void toggleCodeCoverageInstrumentation(bool enable);
|
||||
};
|
||||
|
||||
MOZ_MUST_USE bool GenerateBaselineInterpreter(JSContext* cx,
|
||||
|
|
|
@ -1053,14 +1053,6 @@ bool InitFunctionEnvironmentObjects(JSContext* cx, BaselineFrame* frame) {
|
|||
|
||||
bool NewArgumentsObject(JSContext* cx, BaselineFrame* frame,
|
||||
MutableHandleValue res) {
|
||||
// BaselineCompiler calls ensureHasAnalyzedArgsUsage at compile time. The
|
||||
// interpreters have to do this as part of JSOP_ARGUMENTS.
|
||||
if (frame->runningInInterpreter()) {
|
||||
if (!frame->script()->ensureHasAnalyzedArgsUsage(cx)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
ArgumentsObject* obj = ArgumentsObject::createExpected(cx, frame);
|
||||
if (!obj) {
|
||||
return false;
|
||||
|
@ -1915,6 +1907,42 @@ bool HasNativeElementPure(JSContext* cx, NativeObject* obj, int32_t index,
|
|||
return true;
|
||||
}
|
||||
|
||||
void HandleCodeCoverageAtPC(BaselineFrame* frame, jsbytecode* pc) {
|
||||
AutoUnsafeCallWithABI unsafe(UnsafeABIStrictness::AllowPendingExceptions);
|
||||
|
||||
MOZ_ASSERT(frame->runningInInterpreter());
|
||||
|
||||
JSScript* script = frame->script();
|
||||
MOZ_ASSERT(pc == script->main() || BytecodeIsJumpTarget(JSOp(*pc)));
|
||||
|
||||
if (!script->hasScriptCounts()) {
|
||||
if (!script->realm()->collectCoverageForDebug()) {
|
||||
return;
|
||||
}
|
||||
JSContext* cx = script->runtimeFromMainThread()->mainContextFromOwnThread();
|
||||
AutoEnterOOMUnsafeRegion oomUnsafe;
|
||||
if (!script->initScriptCounts(cx)) {
|
||||
oomUnsafe.crash("initScriptCounts");
|
||||
}
|
||||
}
|
||||
|
||||
PCCounts* counts = script->maybeGetPCCounts(pc);
|
||||
MOZ_ASSERT(counts);
|
||||
counts->numExec()++;
|
||||
}
|
||||
|
||||
void HandleCodeCoverageAtPrologue(BaselineFrame* frame) {
|
||||
AutoUnsafeCallWithABI unsafe;
|
||||
|
||||
MOZ_ASSERT(frame->runningInInterpreter());
|
||||
|
||||
JSScript* script = frame->script();
|
||||
jsbytecode* main = script->main();
|
||||
if (!BytecodeIsJumpTarget(JSOp(*main))) {
|
||||
HandleCodeCoverageAtPC(frame, main);
|
||||
}
|
||||
}
|
||||
|
||||
JSString* TypeOfObject(JSObject* obj, JSRuntime* rt) {
|
||||
AutoUnsafeCallWithABI unsafe;
|
||||
JSType type = js::TypeOfObject(obj);
|
||||
|
|
|
@ -1068,6 +1068,9 @@ MOZ_MUST_USE bool EqualStringsHelperPure(JSString* str1, JSString* str2);
|
|||
MOZ_MUST_USE bool CheckIsCallable(JSContext* cx, HandleValue v,
|
||||
CheckIsCallableKind kind);
|
||||
|
||||
void HandleCodeCoverageAtPC(BaselineFrame* frame, jsbytecode* pc);
|
||||
void HandleCodeCoverageAtPrologue(BaselineFrame* frame);
|
||||
|
||||
template <bool HandleMissing>
|
||||
bool GetNativeDataPropertyPure(JSContext* cx, JSObject* obj, PropertyName* name,
|
||||
Value* vp);
|
||||
|
|
|
@ -1866,7 +1866,6 @@ void MacroAssembler::branchTestMagic(Condition cond, const Address& valaddr,
|
|||
}
|
||||
|
||||
void MacroAssembler::branchToComputedAddress(const BaseIndex& addr) {
|
||||
MOZ_ASSERT(addr.base == pc, "Unsupported jump from any other addresses.");
|
||||
MOZ_ASSERT(
|
||||
addr.offset == 0,
|
||||
"NYI: offsets from pc should be shifted by the number of instructions.");
|
||||
|
@ -1875,9 +1874,12 @@ void MacroAssembler::branchToComputedAddress(const BaseIndex& addr) {
|
|||
uint32_t scale = Imm32::ShiftOf(addr.scale).value;
|
||||
|
||||
ma_ldr(DTRAddr(base, DtrRegImmShift(addr.index, LSL, scale)), pc);
|
||||
// When loading from pc, the pc is shifted to the next instruction, we
|
||||
// add one extra instruction to accomodate for this shifted offset.
|
||||
breakpoint();
|
||||
|
||||
if (base == pc) {
|
||||
// When loading from pc, the pc is shifted to the next instruction, we
|
||||
// add one extra instruction to accomodate for this shifted offset.
|
||||
breakpoint();
|
||||
}
|
||||
}
|
||||
|
||||
void MacroAssembler::cmp32Move32(Condition cond, Register lhs, Register rhs,
|
||||
|
|
|
@ -3050,9 +3050,6 @@ void MacroAssemblerARMCompat::loadValue(const BaseIndex& addr,
|
|||
}
|
||||
|
||||
void MacroAssemblerARMCompat::loadValue(Address src, ValueOperand val) {
|
||||
Address payload = ToPayload(src);
|
||||
Address type = ToType(src);
|
||||
|
||||
// TODO: copy this code into a generic function that acts on all sequences
|
||||
// of memory accesses
|
||||
if (isValueDTRDCandidate(val)) {
|
||||
|
@ -3096,16 +3093,25 @@ void MacroAssemblerARMCompat::loadValue(Address src, ValueOperand val) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
loadUnalignedValue(src, val);
|
||||
}
|
||||
|
||||
void MacroAssemblerARMCompat::loadUnalignedValue(const Address& src,
|
||||
ValueOperand dest) {
|
||||
Address payload = ToPayload(src);
|
||||
Address type = ToType(src);
|
||||
|
||||
// Ensure that loading the payload does not erase the pointer to the Value
|
||||
// in memory.
|
||||
if (type.base != val.payloadReg()) {
|
||||
if (type.base != dest.payloadReg()) {
|
||||
SecondScratchRegisterScope scratch2(asMasm());
|
||||
ma_ldr(payload, val.payloadReg(), scratch2);
|
||||
ma_ldr(type, val.typeReg(), scratch2);
|
||||
ma_ldr(payload, dest.payloadReg(), scratch2);
|
||||
ma_ldr(type, dest.typeReg(), scratch2);
|
||||
} else {
|
||||
SecondScratchRegisterScope scratch2(asMasm());
|
||||
ma_ldr(type, val.typeReg(), scratch2);
|
||||
ma_ldr(payload, val.payloadReg(), scratch2);
|
||||
ma_ldr(type, dest.typeReg(), scratch2);
|
||||
ma_ldr(payload, dest.payloadReg(), scratch2);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1060,6 +1060,11 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM {
|
|||
loadValue(dest.toAddress(), val);
|
||||
}
|
||||
void loadValue(const BaseIndex& addr, ValueOperand val);
|
||||
|
||||
// Like loadValue but guaranteed to not use LDRD or LDM instructions (these
|
||||
// don't support unaligned accesses).
|
||||
void loadUnalignedValue(const Address& src, ValueOperand dest);
|
||||
|
||||
void tagValue(JSValueType type, Register payload, ValueOperand dest);
|
||||
|
||||
void pushValue(ValueOperand val);
|
||||
|
|
|
@ -297,6 +297,9 @@ class MacroAssemblerCompat : public vixl::MacroAssembler {
|
|||
void loadValue(const BaseIndex& src, ValueOperand val) {
|
||||
doBaseIndex(ARMRegister(val.valueReg(), 64), src, vixl::LDR_x);
|
||||
}
|
||||
void loadUnalignedValue(const Address& src, ValueOperand dest) {
|
||||
loadValue(src, dest);
|
||||
}
|
||||
void tagValue(JSValueType type, Register payload, ValueOperand dest) {
|
||||
// This could be cleverer, but the first attempt had bugs.
|
||||
Orr(ARMRegister(dest.valueReg(), 64), ARMRegister(payload, 64),
|
||||
|
|
|
@ -518,6 +518,11 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS {
|
|||
loadValue(dest.toAddress(), val);
|
||||
}
|
||||
void loadValue(const BaseIndex& addr, ValueOperand val);
|
||||
|
||||
void loadUnalignedValue(const Address& src, ValueOperand dest) {
|
||||
loadValue(src, dest);
|
||||
}
|
||||
|
||||
void tagValue(JSValueType type, Register payload, ValueOperand dest);
|
||||
|
||||
void pushValue(ValueOperand val);
|
||||
|
|
|
@ -560,6 +560,11 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 {
|
|||
loadValue(dest.toAddress(), val);
|
||||
}
|
||||
void loadValue(const BaseIndex& addr, ValueOperand val);
|
||||
|
||||
void loadUnalignedValue(const Address& src, ValueOperand dest) {
|
||||
loadValue(src, dest);
|
||||
}
|
||||
|
||||
void tagValue(JSValueType type, Register payload, ValueOperand dest);
|
||||
|
||||
void pushValue(ValueOperand val);
|
||||
|
|
|
@ -289,6 +289,10 @@ class MacroAssemblerNone : public Assembler {
|
|||
void loadValue(T, S) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
template <typename T, typename S>
|
||||
void loadUnalignedValue(T, S) {
|
||||
MOZ_CRASH();
|
||||
}
|
||||
template <typename T>
|
||||
void pushValue(const T&) {
|
||||
MOZ_CRASH();
|
||||
|
|
|
@ -196,6 +196,9 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared {
|
|||
void loadValue(const BaseIndex& src, ValueOperand val) {
|
||||
loadValue(Operand(src), val);
|
||||
}
|
||||
void loadUnalignedValue(const Address& src, ValueOperand dest) {
|
||||
loadValue(src, dest);
|
||||
}
|
||||
void tagValue(JSValueType type, Register payload, ValueOperand dest) {
|
||||
ScratchRegisterScope scratch(asMasm());
|
||||
MOZ_ASSERT(dest.valueReg() != scratch);
|
||||
|
|
|
@ -218,6 +218,9 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared {
|
|||
void loadValue(const BaseIndex& src, ValueOperand val) {
|
||||
loadValue(Operand(src), val);
|
||||
}
|
||||
void loadUnalignedValue(const Address& src, ValueOperand dest) {
|
||||
loadValue(src, dest);
|
||||
}
|
||||
void tagValue(JSValueType type, Register payload, ValueOperand dest) {
|
||||
MOZ_ASSERT(dest.typeReg() != dest.payloadReg());
|
||||
if (payload != dest.payloadReg()) {
|
||||
|
|
|
@ -793,6 +793,9 @@ void Realm::setIsDebuggee() {
|
|||
|
||||
void Realm::unsetIsDebuggee() {
|
||||
if (isDebuggee()) {
|
||||
if (debuggerObservesCoverage()) {
|
||||
runtime_->decrementNumDebuggeeRealmsObservingCoverage();
|
||||
}
|
||||
debugModeBits_ &= ~DebuggerObservesMask;
|
||||
DebugEnvironments::onRealmUnsetIsDebuggee(this);
|
||||
runtimeFromMainThread()->decrementNumDebuggeeRealms();
|
||||
|
@ -815,9 +818,12 @@ void Realm::updateDebuggerObservesCoverage() {
|
|||
iter->asInterpreter()->enableInterruptsUnconditionally();
|
||||
}
|
||||
}
|
||||
runtime_->incrementNumDebuggeeRealmsObservingCoverage();
|
||||
return;
|
||||
}
|
||||
|
||||
runtime_->decrementNumDebuggeeRealmsObservingCoverage();
|
||||
|
||||
// If code coverage is enabled by any other means, keep it.
|
||||
if (collectCoverage()) {
|
||||
return;
|
||||
|
|
|
@ -122,6 +122,7 @@ JSRuntime::JSRuntime(JSRuntime* parentRuntime)
|
|||
heapState_(JS::HeapState::Idle),
|
||||
numRealms(0),
|
||||
numDebuggeeRealms_(0),
|
||||
numDebuggeeRealmsObservingCoverage_(0),
|
||||
localeCallbacks(nullptr),
|
||||
defaultLocale(nullptr),
|
||||
profilingScripts(false),
|
||||
|
@ -190,6 +191,7 @@ JSRuntime::~JSRuntime() {
|
|||
|
||||
MOZ_ASSERT(numRealms == 0);
|
||||
MOZ_ASSERT(numDebuggeeRealms_ == 0);
|
||||
MOZ_ASSERT(numDebuggeeRealmsObservingCoverage_ == 0);
|
||||
}
|
||||
|
||||
bool JSRuntime::init(JSContext* cx, uint32_t maxbytes,
|
||||
|
@ -787,6 +789,26 @@ void JSRuntime::decrementNumDebuggeeRealms() {
|
|||
}
|
||||
}
|
||||
|
||||
void JSRuntime::incrementNumDebuggeeRealmsObservingCoverage() {
|
||||
if (numDebuggeeRealmsObservingCoverage_ == 0) {
|
||||
jit::BaselineInterpreter& interp = jitRuntime()->baselineInterpreter();
|
||||
interp.toggleCodeCoverageInstrumentation(true);
|
||||
}
|
||||
|
||||
numDebuggeeRealmsObservingCoverage_++;
|
||||
MOZ_ASSERT(numDebuggeeRealmsObservingCoverage_ <= numRealms);
|
||||
}
|
||||
|
||||
void JSRuntime::decrementNumDebuggeeRealmsObservingCoverage() {
|
||||
MOZ_ASSERT(numDebuggeeRealmsObservingCoverage_ > 0);
|
||||
numDebuggeeRealmsObservingCoverage_--;
|
||||
|
||||
if (numDebuggeeRealmsObservingCoverage_ == 0) {
|
||||
jit::BaselineInterpreter& interp = jitRuntime()->baselineInterpreter();
|
||||
interp.toggleCodeCoverageInstrumentation(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool js::CurrentThreadCanAccessRuntime(const JSRuntime* rt) {
|
||||
return rt->mainContextFromAnyThread() == TlsContext.get();
|
||||
}
|
||||
|
|
|
@ -527,6 +527,9 @@ struct JSRuntime : public js::MallocProvider<JSRuntime> {
|
|||
// Number of debuggee realms in the runtime.
|
||||
js::MainThreadData<size_t> numDebuggeeRealms_;
|
||||
|
||||
// Number of debuggee realms in the runtime observing code coverage.
|
||||
js::MainThreadData<size_t> numDebuggeeRealmsObservingCoverage_;
|
||||
|
||||
public:
|
||||
void incrementNumDebuggeeRealms();
|
||||
void decrementNumDebuggeeRealms();
|
||||
|
@ -535,6 +538,9 @@ struct JSRuntime : public js::MallocProvider<JSRuntime> {
|
|||
return numDebuggeeRealms_;
|
||||
}
|
||||
|
||||
void incrementNumDebuggeeRealmsObservingCoverage();
|
||||
void decrementNumDebuggeeRealmsObservingCoverage();
|
||||
|
||||
/* Locale-specific callbacks for string conversion. */
|
||||
js::MainThreadData<const JSLocaleCallbacks*> localeCallbacks;
|
||||
|
||||
|
|
|
@ -3497,6 +3497,17 @@ bool JSScript::makeTypes(JSContext* cx) {
|
|||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
// Run the arguments-analysis if needed. Both the Baseline Interpreter and
|
||||
// Compiler rely on this.
|
||||
if (!ensureHasAnalyzedArgsUsage(cx)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If ensureHasAnalyzedArgsUsage allocated the TypeScript we're done.
|
||||
if (types_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
UniquePtr<jit::ICScript> icScript(jit::ICScript::create(cx, this));
|
||||
if (!icScript) {
|
||||
return false;
|
||||
|
@ -3526,6 +3537,7 @@ bool JSScript::makeTypes(JSContext* cx) {
|
|||
|
||||
prepareForDestruction.release();
|
||||
|
||||
MOZ_ASSERT(!types_);
|
||||
types_ = new (typeScript) TypeScript(this, std::move(icScript), numTypeSets);
|
||||
|
||||
// We have a TypeScript so we can set the script's jitCodeRaw_ pointer to the
|
||||
|
|
|
@ -10921,7 +10921,15 @@ void PresShell::SetIsUnderHiddenEmbedderElement(
|
|||
// Propagate to children.
|
||||
for (BrowsingContext* child : bc->GetChildren()) {
|
||||
Element* embedderElement = child->GetEmbedderElement();
|
||||
MOZ_ASSERT(embedderElement);
|
||||
if (!embedderElement) {
|
||||
// TODO: We shouldn't need to null check here since `child` and the
|
||||
// element returned by `child->GetEmbedderElement()` are in our
|
||||
// process (the actual browsing context represented by `child` may not
|
||||
// be, but that doesn't matter). However, there are currently a very
|
||||
// small number of crashes due to `embedderElement` being null, somehow
|
||||
// - see bug 1551241. For now we wallpaper the crash.
|
||||
continue;
|
||||
}
|
||||
|
||||
bool embedderFrameIsHidden = true;
|
||||
if (auto embedderFrame = embedderElement->GetPrimaryFrame()) {
|
||||
|
|
|
@ -491,14 +491,11 @@ mapped-generic-types = [
|
|||
{ generic = false, gecko = "mozilla::ServoVisitedStyle", servo = "Option<::servo_arc::RawOffsetArc<::properties::ComputedValues>>" },
|
||||
{ generic = false, gecko = "mozilla::ServoComputedValueFlags", servo = "::properties::computed_value_flags::ComputedValueFlags" },
|
||||
{ generic = true, gecko = "mozilla::ServoRawOffsetArc", servo = "::servo_arc::RawOffsetArc" },
|
||||
{ generic = true, gecko = "mozilla::ServoManuallyDrop", servo = "::std::mem::ManuallyDrop" },
|
||||
{ generic = false, gecko = "nsACString", servo = "nsstring::nsACString" },
|
||||
{ generic = false, gecko = "nsAString", servo = "nsstring::nsAString" },
|
||||
{ generic = false, gecko = "nsCString", servo = "nsstring::nsCString" },
|
||||
{ generic = false, gecko = "nsString", servo = "nsstring::nsStringRepr" },
|
||||
{ generic = false, gecko = "nsString", servo = "nsstring::nsString" },
|
||||
]
|
||||
|
||||
whitelist-functions = ["Servo_.*", "Gecko_.*"]
|
||||
|
||||
fixups = [
|
||||
{ pat = "\\broot\\s*::\\s*nsTString\\s*<\\s*u16\\s*>", rep = "::nsstring::nsStringRepr" },
|
||||
]
|
||||
|
|
|
@ -26,6 +26,15 @@ struct ServoRawOffsetArc {
|
|||
T* mPtr;
|
||||
};
|
||||
|
||||
// A wrapper that gets replaced by ManuallyDrop<T> by bindgen.
|
||||
//
|
||||
// NOTE(emilio): All this file is a bit gross, and most of this we make cleaner
|
||||
// using cbindgen and such.
|
||||
template <typename T>
|
||||
struct ServoManuallyDrop {
|
||||
T mInner;
|
||||
};
|
||||
|
||||
struct ServoWritingMode {
|
||||
uint8_t mBits;
|
||||
};
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
namespace mozilla {
|
||||
#define STYLE_STRUCT(name_) \
|
||||
struct Gecko##name_ { \
|
||||
nsStyle##name_ gecko; \
|
||||
ServoManuallyDrop<nsStyle##name_> gecko; \
|
||||
};
|
||||
#include "nsStyleStructList.h"
|
||||
#undef STYLE_STRUCT
|
||||
|
@ -21,7 +21,7 @@ namespace mozilla {
|
|||
|
||||
#define STYLE_STRUCT(name_) \
|
||||
const nsStyle##name_* ServoComputedData::GetStyle##name_() const { \
|
||||
return &name_.mPtr->gecko; \
|
||||
return &name_.mPtr->gecko.mInner; \
|
||||
}
|
||||
#include "nsStyleStructList.h"
|
||||
#undef STYLE_STRUCT
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.mozilla.gecko;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.v4.os.BuildCompat;
|
||||
|
||||
/**
|
||||
* A collection of constants that pertain to the build and runtime state of the
|
||||
|
@ -56,6 +57,8 @@ public class AppConstants {
|
|||
public static final boolean feature23Plus = MIN_SDK_VERSION >= 23 || (MAX_SDK_VERSION >= 23 && Build.VERSION.SDK_INT >= 23);
|
||||
public static final boolean feature24Plus = MIN_SDK_VERSION >= 24 || (MAX_SDK_VERSION >= 24 && Build.VERSION.SDK_INT >= 24);
|
||||
public static final boolean feature26Plus = MIN_SDK_VERSION >= 26 || (MAX_SDK_VERSION >= 26 && Build.VERSION.SDK_INT >= 26);
|
||||
// Given that Android Q is not yet released it shares API level 28 with Android P
|
||||
public static final boolean feature29Plus = BuildCompat.isAtLeastQ();
|
||||
|
||||
/*
|
||||
* If our MIN_SDK_VERSION is 14 or higher, we must be an ICS device.
|
||||
|
|
|
@ -42,9 +42,21 @@ public class GlobalConstants {
|
|||
public static final String[] DEFAULT_PROTOCOLS;
|
||||
|
||||
static {
|
||||
// Prioritize 128 over 256 as a tradeoff between device CPU/battery and the minor
|
||||
// increase in strength.
|
||||
if (Versions.feature26Plus) {
|
||||
// ChaCha20-Poly1305 seems fastest on mobile.
|
||||
// Otherwise prioritize 128 over 256 as a tradeoff between device CPU/battery
|
||||
// and the minor increase in strength.
|
||||
if (Versions.feature29Plus) {
|
||||
DEFAULT_CIPHER_SUITES = new String[]
|
||||
{
|
||||
"TLS_CHACHA20_POLY1305_SHA256", // 29+
|
||||
"TLS_AES_128_GCM_SHA256", // 29+
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", // 20+
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", // 20+
|
||||
"TLS_AES_256_GCM_SHA384", // 29+
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", // 20+
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", // 11+
|
||||
};
|
||||
} else if (Versions.feature26Plus) {
|
||||
DEFAULT_CIPHER_SUITES = new String[]
|
||||
{
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", // 20+
|
||||
|
@ -86,19 +98,19 @@ public class GlobalConstants {
|
|||
};
|
||||
}
|
||||
|
||||
if (Versions.feature16Plus) {
|
||||
if (Versions.feature29Plus) {
|
||||
DEFAULT_PROTOCOLS = new String[]
|
||||
{
|
||||
"TLSv1.3",
|
||||
"TLSv1.2",
|
||||
};
|
||||
} else {
|
||||
DEFAULT_PROTOCOLS = new String[]
|
||||
{
|
||||
"TLSv1.2",
|
||||
"TLSv1.1",
|
||||
"TLSv1", // We would like to remove this, and will do so when we can.
|
||||
};
|
||||
} else {
|
||||
// Fall back to TLSv1 if there's nothing better.
|
||||
DEFAULT_PROTOCOLS = new String[]
|
||||
{
|
||||
"TLSv1",
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -70,6 +70,20 @@ class Runtime extends ContentProcessDomain {
|
|||
return context.evaluate(request.expression);
|
||||
}
|
||||
|
||||
releaseObject({ objectId }) {
|
||||
let context = null;
|
||||
for (const ctx of this.contexts.values()) {
|
||||
if (ctx.hasRemoteObject(objectId)) {
|
||||
context = ctx;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!context) {
|
||||
throw new Error(`Unable to get execution context by ID: ${objectId}`);
|
||||
}
|
||||
context.releaseObject(objectId);
|
||||
}
|
||||
|
||||
callFunctionOn(request) {
|
||||
let context = null;
|
||||
// When an `objectId` is passed, we want to execute the function of a given object
|
||||
|
|
|
@ -48,6 +48,10 @@ class ExecutionContext {
|
|||
return this._remoteObjects.has(id);
|
||||
}
|
||||
|
||||
releaseObject(id) {
|
||||
return this._remoteObjects.delete(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate a Javascript expression.
|
||||
*
|
||||
|
@ -262,7 +266,7 @@ class ExecutionContext {
|
|||
subtype = "promise";
|
||||
} else if (TYPED_ARRAY_CLASSES.includes(cls)) {
|
||||
subtype = "typedarray";
|
||||
} else if (cls == "Object" && Node.isInstance(rawObj)) {
|
||||
} else if (Node.isInstance(rawObj)) {
|
||||
subtype = "node";
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ skip-if = debug || asan # bug 1546945
|
|||
[browser_page_frameNavigated.js]
|
||||
[browser_page_runtime_events.js]
|
||||
[browser_runtime_evaluate.js]
|
||||
[browser_runtime_remote_objects.js]
|
||||
[browser_runtime_callFunctionOn.js]
|
||||
[browser_runtime_executionContext.js]
|
||||
skip-if = os == "mac" || (verify && os == 'win') # bug 1547961
|
||||
|
|
|
@ -188,6 +188,9 @@ async function testObjectTypes(testFunction) {
|
|||
{ expression: "[1, 2]", type: "object", subtype: "array" },
|
||||
{ expression: "new Proxy({}, {})", type: "object", subtype: "proxy" },
|
||||
{ expression: "new Date()", type: "object", subtype: "date" },
|
||||
{ expression: "document", type: "object", subtype: "node" },
|
||||
{ expression: "document.documentElement", type: "object", subtype: "node" },
|
||||
{ expression: "document.createElement('div')", type: "object", subtype: "node" },
|
||||
];
|
||||
|
||||
for (const { expression, type, subtype } of expressions) {
|
||||
|
|
|
@ -0,0 +1,101 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test the Runtime remote object
|
||||
|
||||
const TEST_URI = "data:text/html;charset=utf-8,default-test-page";
|
||||
|
||||
add_task(async function() {
|
||||
// Open a test page, to prevent debugging the random default page
|
||||
await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_URI);
|
||||
|
||||
// Start the CDP server
|
||||
await RemoteAgent.listen(Services.io.newURI("http://localhost:9222"));
|
||||
|
||||
// Retrieve the chrome-remote-interface library object
|
||||
const CDP = await getCDP();
|
||||
|
||||
// Connect to the server
|
||||
const client = await CDP({
|
||||
target(list) {
|
||||
// Ensure debugging the right target, i.e. the one for our test tab.
|
||||
return list.find(target => target.url == TEST_URI);
|
||||
},
|
||||
});
|
||||
ok(true, "CDP client has been instantiated");
|
||||
|
||||
const firstContext = await testRuntimeEnable(client);
|
||||
const contextId = firstContext.id;
|
||||
|
||||
await testObjectRelease(client, contextId);
|
||||
|
||||
await client.close();
|
||||
ok(true, "The client is closed");
|
||||
|
||||
BrowserTestUtils.removeTab(gBrowser.selectedTab);
|
||||
|
||||
await RemoteAgent.close();
|
||||
});
|
||||
|
||||
async function testRuntimeEnable({ Runtime }) {
|
||||
// Enable watching for new execution context
|
||||
await Runtime.enable();
|
||||
ok(true, "Runtime domain has been enabled");
|
||||
|
||||
// Calling Runtime.enable will emit executionContextCreated for the existing contexts
|
||||
const { context } = await Runtime.executionContextCreated();
|
||||
ok(!!context.id, "The execution context has an id");
|
||||
ok(context.auxData.isDefault, "The execution context is the default one");
|
||||
ok(!!context.auxData.frameId, "The execution context has a frame id set");
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
async function testObjectRelease({ Runtime }, contextId) {
|
||||
const { result } = await Runtime.evaluate({ contextId, expression: "({ foo: 42 })" });
|
||||
is(result.subtype, null, "JS Object have no subtype");
|
||||
is(result.type, "object", "The type is correct");
|
||||
ok(!!result.objectId, "Got an object id");
|
||||
|
||||
const { result: result2 } = await Runtime.callFunctionOn({
|
||||
executionContextId: contextId,
|
||||
functionDeclaration: "obj => JSON.stringify(obj)",
|
||||
arguments: [{ objectId: result.objectId }],
|
||||
});
|
||||
is(result2.type, "string", "The type is correct");
|
||||
is(result2.value, JSON.stringify({ foo: 42 }), "Got the object's JSON");
|
||||
|
||||
const { result: result3 } = await Runtime.callFunctionOn({
|
||||
objectId: result.objectId,
|
||||
functionDeclaration: "function () { return this.foo; }",
|
||||
});
|
||||
is(result3.type, "number", "The type is correct");
|
||||
is(result3.value, 42, "Got the object's foo attribute");
|
||||
|
||||
await Runtime.releaseObject({
|
||||
objectId: result.objectId,
|
||||
});
|
||||
ok(true, "Object is released");
|
||||
|
||||
try {
|
||||
await Runtime.callFunctionOn({
|
||||
executionContextId: contextId,
|
||||
functionDeclaration: "() => {}",
|
||||
arguments: [{ objectId: result.objectId }],
|
||||
});
|
||||
ok(false, "callFunctionOn with a released object as argument should throw");
|
||||
} catch (e) {
|
||||
ok(e.message.includes("Cannot find object with ID:"), "callFunctionOn throws on released argument");
|
||||
}
|
||||
try {
|
||||
await Runtime.callFunctionOn({
|
||||
objectId: result.objectId,
|
||||
functionDeclaration: "() => {}",
|
||||
});
|
||||
ok(false, "callFunctionOn with a released object as target should throw");
|
||||
} catch (e) {
|
||||
ok(e.message.includes("Unable to get the context for object with id"), "callFunctionOn throws on released target");
|
||||
}
|
||||
}
|
|
@ -50,7 +50,7 @@ use crate::rule_tree::StrongRuleNode;
|
|||
use crate::selector_parser::PseudoElement;
|
||||
use servo_arc::{Arc, RawOffsetArc};
|
||||
use std::marker::PhantomData;
|
||||
use std::mem::{forget, uninitialized, zeroed};
|
||||
use std::mem::{forget, uninitialized, zeroed, ManuallyDrop};
|
||||
use std::{cmp, ops, ptr};
|
||||
use crate::values::{self, CustomIdent, Either, KeyframesName, None_};
|
||||
use crate::values::computed::{NonNegativeLength, Percentage, TransitionProperty};
|
||||
|
@ -1095,10 +1095,10 @@ pub fn clone_transform_from_list(
|
|||
impl ${style_struct.gecko_struct_name} {
|
||||
#[allow(dead_code, unused_variables)]
|
||||
pub fn default(document: &structs::Document) -> Arc<Self> {
|
||||
let mut result = Arc::new(${style_struct.gecko_struct_name} { gecko: unsafe { zeroed() } });
|
||||
let mut result = Arc::new(${style_struct.gecko_struct_name} { gecko: ManuallyDrop::new(unsafe { zeroed() }) });
|
||||
unsafe {
|
||||
Gecko_Construct_Default_${style_struct.gecko_ffi_name}(
|
||||
&mut Arc::get_mut(&mut result).unwrap().gecko,
|
||||
&mut *Arc::get_mut(&mut result).unwrap().gecko,
|
||||
document,
|
||||
);
|
||||
}
|
||||
|
@ -1108,15 +1108,15 @@ impl ${style_struct.gecko_struct_name} {
|
|||
impl Drop for ${style_struct.gecko_struct_name} {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
Gecko_Destroy_${style_struct.gecko_ffi_name}(&mut self.gecko);
|
||||
Gecko_Destroy_${style_struct.gecko_ffi_name}(&mut *self.gecko);
|
||||
}
|
||||
}
|
||||
}
|
||||
impl Clone for ${style_struct.gecko_struct_name} {
|
||||
fn clone(&self) -> Self {
|
||||
unsafe {
|
||||
let mut result = ${style_struct.gecko_struct_name} { gecko: zeroed() };
|
||||
Gecko_CopyConstruct_${style_struct.gecko_ffi_name}(&mut result.gecko, &self.gecko);
|
||||
let mut result = ${style_struct.gecko_struct_name} { gecko: ManuallyDrop::new(zeroed()) };
|
||||
Gecko_CopyConstruct_${style_struct.gecko_ffi_name}(&mut *result.gecko, &*self.gecko);
|
||||
result
|
||||
}
|
||||
}
|
||||
|
@ -1545,8 +1545,9 @@ fn static_assert() {
|
|||
|
||||
% for kind in ["rows", "columns"]:
|
||||
pub fn set_grid_auto_${kind}(&mut self, v: longhands::grid_auto_${kind}::computed_value::T) {
|
||||
v.to_gecko_style_coords(&mut self.gecko.mGridAuto${kind.title()}Min,
|
||||
&mut self.gecko.mGridAuto${kind.title()}Max)
|
||||
let gecko = &mut *self.gecko;
|
||||
v.to_gecko_style_coords(&mut gecko.mGridAuto${kind.title()}Min,
|
||||
&mut gecko.mGridAuto${kind.title()}Max)
|
||||
}
|
||||
|
||||
pub fn copy_grid_auto_${kind}_from(&mut self, other: &Self) {
|
||||
|
@ -1566,14 +1567,14 @@ fn static_assert() {
|
|||
pub fn set_grid_template_${kind}(&mut self, v: longhands::grid_template_${kind}::computed_value::T) {
|
||||
<% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %>
|
||||
use crate::gecko_bindings::structs::{nsTArray, nsStyleGridLine_kMaxLine};
|
||||
use nsstring::nsStringRepr;
|
||||
use nsstring::nsString;
|
||||
use std::usize;
|
||||
use crate::values::CustomIdent;
|
||||
use crate::values::generics::grid::TrackListType::Auto;
|
||||
use crate::values::generics::grid::{GridTemplateComponent, RepeatCount};
|
||||
|
||||
#[inline]
|
||||
fn set_line_names(servo_names: &[CustomIdent], gecko_names: &mut nsTArray<nsStringRepr>) {
|
||||
fn set_line_names(servo_names: &[CustomIdent], gecko_names: &mut nsTArray<nsString>) {
|
||||
unsafe {
|
||||
bindings::Gecko_ResizeTArrayForStrings(gecko_names, servo_names.len() as u32);
|
||||
}
|
||||
|
@ -1693,7 +1694,7 @@ fn static_assert() {
|
|||
pub fn clone_grid_template_${kind}(&self) -> longhands::grid_template_${kind}::computed_value::T {
|
||||
<% self_grid = "self.gecko.mGridTemplate%s" % kind.title() %>
|
||||
use crate::gecko_bindings::structs::nsTArray;
|
||||
use nsstring::nsStringRepr;
|
||||
use nsstring::nsString;
|
||||
use crate::values::CustomIdent;
|
||||
use crate::values::generics::grid::{GridTemplateComponent, LineNameList, RepeatCount};
|
||||
use crate::values::generics::grid::{TrackList, TrackListType, TrackListValue, TrackRepeat, TrackSize};
|
||||
|
@ -1704,7 +1705,7 @@ fn static_assert() {
|
|||
};
|
||||
|
||||
#[inline]
|
||||
fn to_boxed_customident_slice(gecko_names: &nsTArray<nsStringRepr>) -> Box<[CustomIdent]> {
|
||||
fn to_boxed_customident_slice(gecko_names: &nsTArray<nsString>) -> Box<[CustomIdent]> {
|
||||
let idents: Vec<CustomIdent> = gecko_names.iter().map(|gecko_name| {
|
||||
CustomIdent(Atom::from(gecko_name.to_string()))
|
||||
}).collect();
|
||||
|
@ -1712,7 +1713,7 @@ fn static_assert() {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
fn to_line_names_vec(gecko_line_names: &nsTArray<nsTArray<nsStringRepr>>)
|
||||
fn to_line_names_vec(gecko_line_names: &nsTArray<nsTArray<nsString>>)
|
||||
-> Vec<Box<[CustomIdent]>> {
|
||||
gecko_line_names.iter().map(|gecko_names| {
|
||||
to_boxed_customident_slice(gecko_names)
|
||||
|
@ -2129,14 +2130,14 @@ fn static_assert() {
|
|||
let ptr = v.0.as_ptr();
|
||||
forget(v);
|
||||
unsafe {
|
||||
Gecko_nsStyleFont_SetLang(&mut self.gecko, ptr);
|
||||
Gecko_nsStyleFont_SetLang(&mut *self.gecko, ptr);
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn copy__x_lang_from(&mut self, other: &Self) {
|
||||
unsafe {
|
||||
Gecko_nsStyleFont_CopyLangFrom(&mut self.gecko, &other.gecko);
|
||||
Gecko_nsStyleFont_CopyLangFrom(&mut *self.gecko, &*other.gecko);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2519,7 +2520,7 @@ fn static_assert() {
|
|||
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
|
||||
#[inline]
|
||||
pub fn generate_combined_transform(&mut self) {
|
||||
unsafe { bindings::Gecko_StyleDisplay_GenerateCombinedTransform(&mut self.gecko) };
|
||||
unsafe { bindings::Gecko_StyleDisplay_GenerateCombinedTransform(&mut *self.gecko) };
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -2836,12 +2837,12 @@ fn static_assert() {
|
|||
match v {
|
||||
WillChange::AnimateableFeatures { features, bits } => {
|
||||
unsafe {
|
||||
Gecko_ClearWillChange(&mut self.gecko, features.len());
|
||||
Gecko_ClearWillChange(&mut *self.gecko, features.len());
|
||||
}
|
||||
|
||||
for feature in features.iter() {
|
||||
unsafe {
|
||||
Gecko_AppendWillChange(&mut self.gecko, feature.0.as_ptr())
|
||||
Gecko_AppendWillChange(&mut *self.gecko, feature.0.as_ptr())
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2849,7 +2850,7 @@ fn static_assert() {
|
|||
},
|
||||
WillChange::Auto => {
|
||||
unsafe {
|
||||
Gecko_ClearWillChange(&mut self.gecko, 0);
|
||||
Gecko_ClearWillChange(&mut *self.gecko, 0);
|
||||
}
|
||||
self.gecko.mWillChangeBitField = WillChangeBits::empty();
|
||||
},
|
||||
|
@ -2861,7 +2862,7 @@ fn static_assert() {
|
|||
|
||||
self.gecko.mWillChangeBitField = other.gecko.mWillChangeBitField;
|
||||
unsafe {
|
||||
Gecko_CopyWillChangeFrom(&mut self.gecko, &other.gecko);
|
||||
Gecko_CopyWillChangeFrom(&mut *self.gecko, &*other.gecko);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3307,13 +3308,13 @@ fn static_assert() {
|
|||
match image {
|
||||
UrlOrNone::None => {
|
||||
unsafe {
|
||||
Gecko_SetListStyleImageNone(&mut self.gecko);
|
||||
Gecko_SetListStyleImageNone(&mut *self.gecko);
|
||||
}
|
||||
}
|
||||
UrlOrNone::Url(ref url) => {
|
||||
unsafe {
|
||||
Gecko_SetListStyleImageImageValue(
|
||||
&mut self.gecko,
|
||||
&mut *self.gecko,
|
||||
url.url_value_ptr(),
|
||||
);
|
||||
}
|
||||
|
@ -3322,7 +3323,7 @@ fn static_assert() {
|
|||
}
|
||||
|
||||
pub fn copy_list_style_image_from(&mut self, other: &Self) {
|
||||
unsafe { Gecko_CopyListStyleImageFrom(&mut self.gecko, &other.gecko); }
|
||||
unsafe { Gecko_CopyListStyleImageFrom(&mut *self.gecko, &*other.gecko); }
|
||||
}
|
||||
|
||||
pub fn reset_list_style_image(&mut self, other: &Self) {
|
||||
|
@ -3644,7 +3645,7 @@ fn static_assert() {
|
|||
|
||||
let v = v.into_iter();
|
||||
unsafe {
|
||||
Gecko_ResetFilters(&mut self.gecko, v.len());
|
||||
Gecko_ResetFilters(&mut *self.gecko, v.len());
|
||||
}
|
||||
debug_assert_eq!(v.len(), self.gecko.mFilters.len());
|
||||
|
||||
|
@ -3690,7 +3691,7 @@ fn static_assert() {
|
|||
|
||||
pub fn copy_filter_from(&mut self, other: &Self) {
|
||||
unsafe {
|
||||
Gecko_CopyFiltersFrom(&other.gecko as *const _ as *mut _, &mut self.gecko);
|
||||
Gecko_CopyFiltersFrom(&other.gecko as *const _ as *mut _, &mut *self.gecko);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4139,7 +4140,7 @@ clip-path
|
|||
let v = v.into_iter();
|
||||
self.gecko.mContextFlags &= !CONTEXT_VALUE;
|
||||
unsafe {
|
||||
bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut self.gecko, v.len() as u32);
|
||||
bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut *self.gecko, v.len() as u32);
|
||||
}
|
||||
for (gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v) {
|
||||
*gecko = servo;
|
||||
|
@ -4148,7 +4149,7 @@ clip-path
|
|||
SVGStrokeDashArray::ContextValue => {
|
||||
self.gecko.mContextFlags |= CONTEXT_VALUE;
|
||||
unsafe {
|
||||
bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut self.gecko, 0);
|
||||
bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut *self.gecko, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4157,7 +4158,7 @@ clip-path
|
|||
pub fn copy_stroke_dasharray_from(&mut self, other: &Self) {
|
||||
use crate::gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE;
|
||||
unsafe {
|
||||
bindings::Gecko_nsStyleSVG_CopyDashArray(&mut self.gecko, &other.gecko);
|
||||
bindings::Gecko_nsStyleSVG_CopyDashArray(&mut *self.gecko, &*other.gecko);
|
||||
}
|
||||
self.gecko.mContextFlags =
|
||||
(self.gecko.mContextFlags & !CONTEXT_VALUE) |
|
||||
|
@ -4204,19 +4205,20 @@ clip-path
|
|||
{
|
||||
let v = v.into_iter();
|
||||
unsafe {
|
||||
bindings::Gecko_nsStyleSVG_SetContextPropertiesLength(&mut self.gecko, v.len() as u32);
|
||||
bindings::Gecko_nsStyleSVG_SetContextPropertiesLength(&mut *self.gecko, v.len() as u32);
|
||||
}
|
||||
|
||||
self.gecko.mContextPropsBits = 0;
|
||||
for (gecko, servo) in self.gecko.mContextProps.iter_mut().zip(v) {
|
||||
let s = &mut *self.gecko;
|
||||
s.mContextPropsBits = 0;
|
||||
for (gecko, servo) in s.mContextProps.iter_mut().zip(v) {
|
||||
if (servo.0).0 == atom!("fill") {
|
||||
self.gecko.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_FILL as u8;
|
||||
s.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_FILL as u8;
|
||||
} else if (servo.0).0 == atom!("stroke") {
|
||||
self.gecko.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_STROKE as u8;
|
||||
s.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_STROKE as u8;
|
||||
} else if (servo.0).0 == atom!("fill-opacity") {
|
||||
self.gecko.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_FILL_OPACITY as u8;
|
||||
s.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_FILL_OPACITY as u8;
|
||||
} else if (servo.0).0 == atom!("stroke-opacity") {
|
||||
self.gecko.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_STROKE_OPACITY as u8;
|
||||
s.mContextPropsBits |= structs::NS_STYLE_CONTEXT_PROPERTY_STROKE_OPACITY as u8;
|
||||
}
|
||||
gecko.mRawPtr = (servo.0).0.into_addrefed();
|
||||
}
|
||||
|
@ -4225,7 +4227,7 @@ clip-path
|
|||
#[allow(non_snake_case)]
|
||||
pub fn copy__moz_context_properties_from(&mut self, other: &Self) {
|
||||
unsafe {
|
||||
bindings::Gecko_nsStyleSVG_CopyContextProperties(&mut self.gecko, &other.gecko);
|
||||
bindings::Gecko_nsStyleSVG_CopyContextProperties(&mut *self.gecko, &*other.gecko);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4242,7 +4244,7 @@ clip-path
|
|||
pub fn set_cursor(&mut self, v: longhands::cursor::computed_value::T) {
|
||||
self.gecko.mCursor = v.keyword;
|
||||
unsafe {
|
||||
Gecko_SetCursorArrayLength(&mut self.gecko, v.images.len());
|
||||
Gecko_SetCursorArrayLength(&mut *self.gecko, v.images.len());
|
||||
}
|
||||
for i in 0..v.images.len() {
|
||||
unsafe {
|
||||
|
@ -4268,7 +4270,7 @@ clip-path
|
|||
pub fn copy_cursor_from(&mut self, other: &Self) {
|
||||
self.gecko.mCursor = other.gecko.mCursor;
|
||||
unsafe {
|
||||
Gecko_CopyCursorArrayFrom(&mut self.gecko, &other.gecko);
|
||||
Gecko_CopyCursorArrayFrom(&mut *self.gecko, &*other.gecko);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4387,20 +4389,20 @@ clip-path
|
|||
// Ensure destructors run, otherwise we could leak.
|
||||
if !self.gecko.mContents.is_empty() {
|
||||
unsafe {
|
||||
Gecko_ClearAndResizeStyleContents(&mut self.gecko, 0);
|
||||
Gecko_ClearAndResizeStyleContents(&mut *self.gecko, 0);
|
||||
}
|
||||
}
|
||||
},
|
||||
Content::MozAltContent => {
|
||||
unsafe {
|
||||
Gecko_ClearAndResizeStyleContents(&mut self.gecko, 1);
|
||||
Gecko_ClearAndResizeStyleContents(&mut *self.gecko, 1);
|
||||
*self.gecko.mContents[0].mContent.mString.as_mut() = ptr::null_mut();
|
||||
}
|
||||
self.gecko.mContents[0].mType = StyleContentType::AltContent;
|
||||
},
|
||||
Content::Items(items) => {
|
||||
unsafe {
|
||||
Gecko_ClearAndResizeStyleContents(&mut self.gecko,
|
||||
Gecko_ClearAndResizeStyleContents(&mut *self.gecko,
|
||||
items.len() as u32);
|
||||
}
|
||||
for (i, item) in items.into_vec().into_iter().enumerate() {
|
||||
|
@ -4481,7 +4483,7 @@ clip-path
|
|||
pub fn copy_content_from(&mut self, other: &Self) {
|
||||
use crate::gecko_bindings::bindings::Gecko_CopyStyleContentsFrom;
|
||||
unsafe {
|
||||
Gecko_CopyStyleContentsFrom(&mut self.gecko, &other.gecko)
|
||||
Gecko_CopyStyleContentsFrom(&mut *self.gecko, &*other.gecko)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4575,7 +4577,7 @@ clip-path
|
|||
v: longhands::counter_${counter_property.lower()}::computed_value::T
|
||||
) {
|
||||
unsafe {
|
||||
bindings::Gecko_ClearAndResizeCounter${counter_property}s(&mut self.gecko, v.len() as u32);
|
||||
bindings::Gecko_ClearAndResizeCounter${counter_property}s(&mut *self.gecko, v.len() as u32);
|
||||
for (i, pair) in v.0.into_vec().into_iter().enumerate() {
|
||||
self.gecko.m${counter_property}s[i].mCounter.set_move(
|
||||
RefPtr::from_addrefed(pair.name.0.into_addrefed())
|
||||
|
@ -4587,7 +4589,7 @@ clip-path
|
|||
|
||||
pub fn copy_counter_${counter_property.lower()}_from(&mut self, other: &Self) {
|
||||
unsafe {
|
||||
bindings::Gecko_CopyCounter${counter_property}sFrom(&mut self.gecko, &other.gecko)
|
||||
bindings::Gecko_CopyCounter${counter_property}sFrom(&mut *self.gecko, &*other.gecko)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use super::stylesheet_loader::{AsyncStylesheetParser, StylesheetLoader};
|
|||
use cssparser::ToCss as ParserToCss;
|
||||
use cssparser::{ParseErrorKind, Parser, ParserInput, SourceLocation, UnicodeRange};
|
||||
use malloc_size_of::MallocSizeOfOps;
|
||||
use nsstring::{nsCString, nsString, nsStringRepr};
|
||||
use nsstring::{nsCString, nsString};
|
||||
use selectors::matching::{matches_selector, MatchingContext, MatchingMode};
|
||||
use selectors::{NthIndexCache, SelectorList};
|
||||
use servo_arc::{Arc, ArcBorrow, RawOffsetArc};
|
||||
|
@ -1148,9 +1148,7 @@ pub unsafe extern "C" fn Servo_Property_GetCSSValuesForProperty(
|
|||
|
||||
let result = result.as_mut().unwrap();
|
||||
let len = extras.len() + values.len();
|
||||
// FIXME(emilio): This is one place where our nsString -> nsStringRepr
|
||||
// conversion during bindgen goes bad.
|
||||
bindings::Gecko_ResizeTArrayForStrings(result as *mut _ as *mut nsTArray<nsStringRepr>, len as u32);
|
||||
bindings::Gecko_ResizeTArrayForStrings(result as *mut _ as *mut nsTArray<nsString>, len as u32);
|
||||
|
||||
for (src, dest) in extras.iter().chain(values.iter()).zip(result.iter_mut()) {
|
||||
dest.write_str(src).unwrap();
|
||||
|
|
|
@ -292,8 +292,13 @@ raptor-tp6m-1-fenix:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -307,8 +312,13 @@ raptor-tp6m-1-refbrow:
|
|||
treeherder-symbol: Rap-refbrow(tp6m-1)
|
||||
run-on-projects: ['try']
|
||||
target:
|
||||
index: project.mobile.reference-browser.signed-nightly.nightly.latest
|
||||
name: target.arm.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.reference-browser.signed-nightly.nightly.latest
|
||||
name: target.aarch64.apk
|
||||
default:
|
||||
index: project.mobile.reference-browser.signed-nightly.nightly.latest
|
||||
name: target.arm.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -738,8 +748,13 @@ raptor-tp6m-1-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -755,8 +770,13 @@ raptor-tp6m-2-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -772,8 +792,13 @@ raptor-tp6m-3-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -789,8 +814,13 @@ raptor-tp6m-4-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -806,8 +836,13 @@ raptor-tp6m-5-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -823,8 +858,13 @@ raptor-tp6m-6-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -840,8 +880,13 @@ raptor-tp6m-7-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -857,8 +902,13 @@ raptor-tp6m-8-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -874,8 +924,13 @@ raptor-tp6m-9-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -891,8 +946,13 @@ raptor-tp6m-10-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -908,8 +968,13 @@ raptor-tp6m-11-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -925,8 +990,13 @@ raptor-tp6m-12-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -942,8 +1012,13 @@ raptor-tp6m-13-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -959,8 +1034,13 @@ raptor-tp6m-14-fenix-cold:
|
|||
run-on-projects: ['try']
|
||||
e10s: true
|
||||
target:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.release-raptor.aarch64
|
||||
name: target.apk
|
||||
default:
|
||||
index: project.mobile.fenix.v2.branch.master.latest.raptor.arm
|
||||
name: target.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -1091,8 +1171,13 @@ raptor-speedometer-refbrow:
|
|||
treeherder-symbol: Rap-refbrow(sp)
|
||||
run-on-projects: ['try']
|
||||
target:
|
||||
index: project.mobile.reference-browser.signed-nightly.nightly.latest
|
||||
name: target.arm.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.reference-browser.signed-nightly.nightly.latest
|
||||
name: target.aarch64.apk
|
||||
default:
|
||||
index: project.mobile.reference-browser.signed-nightly.nightly.latest
|
||||
name: target.arm.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
@ -1254,8 +1339,13 @@ raptor-unity-webgl-refbrow:
|
|||
treeherder-symbol: Rap-refbrow(ugl)
|
||||
run-on-projects: ['try']
|
||||
target:
|
||||
index: project.mobile.reference-browser.signed-nightly.nightly.latest
|
||||
name: target.arm.apk
|
||||
by-test-platform:
|
||||
android-hw.*-aarch64.*/.*:
|
||||
index: project.mobile.reference-browser.signed-nightly.nightly.latest
|
||||
name: target.aarch64.apk
|
||||
default:
|
||||
index: project.mobile.reference-browser.signed-nightly.nightly.latest
|
||||
name: target.arm.apk
|
||||
tier: 2
|
||||
mozharness:
|
||||
extra-options:
|
||||
|
|
|
@ -861,6 +861,7 @@ def handle_keyed_by(config, tests):
|
|||
'virtualization',
|
||||
'fetches.fetch',
|
||||
'fetches.toolchain',
|
||||
'target',
|
||||
]
|
||||
for test in tests:
|
||||
for field in fields:
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
XPCSHELL_TESTS_MANIFESTS += [
|
||||
'tests/xpcshell/searchconfigs/xpcshell.ini',
|
||||
'tests/xpcshell/searchconfigs/xpcshell-1.ini',
|
||||
'tests/xpcshell/searchconfigs/xpcshell-2.ini',
|
||||
'tests/xpcshell/searchconfigs/xpcshell-3.ini',
|
||||
'tests/xpcshell/searchconfigs/xpcshell-4.ini',
|
||||
'tests/xpcshell/xpcshell.ini',
|
||||
]
|
||||
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* import-globals-from head_searchconfig.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
Services.prefs.setIntPref("browser.search.config.test.section", 1);
|
|
@ -0,0 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* import-globals-from head_searchconfig.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
Services.prefs.setIntPref("browser.search.config.test.section", 2);
|
|
@ -0,0 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* import-globals-from head_searchconfig.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
Services.prefs.setIntPref("browser.search.config.test.section", 3);
|
|
@ -0,0 +1,8 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/* import-globals-from head_searchconfig.js */
|
||||
|
||||
"use strict";
|
||||
|
||||
Services.prefs.setIntPref("browser.search.config.test.section", 4);
|
|
@ -13,6 +13,9 @@ XPCOMUtils.defineLazyModuleGetters(this, {
|
|||
|
||||
const GLOBAL_SCOPE = this;
|
||||
|
||||
const URLTYPE_SUGGEST_JSON = "application/x-suggestions+json";
|
||||
const URLTYPE_SEARCH_HTML = "text/html";
|
||||
|
||||
/**
|
||||
* This class implements the test harness for search configuration tests.
|
||||
* These tests are designed to ensure that the correct search engines are
|
||||
|
@ -82,6 +85,8 @@ class SearchConfigTest {
|
|||
await AddonTestUtils.promiseStartupManager();
|
||||
await Services.search.init();
|
||||
|
||||
// Note: we don't use the helper function here, so that we have at least
|
||||
// one message output per process.
|
||||
Assert.ok(Services.search.isInitialized,
|
||||
"Should have correctly initialized the search service");
|
||||
}
|
||||
|
@ -101,11 +106,15 @@ class SearchConfigTest {
|
|||
await this._reinit(region, locale);
|
||||
|
||||
this._assertDefaultEngines(region, locale);
|
||||
await this._assertAvailableEngines(region, locale);
|
||||
const engines = await Services.search.getVisibleEngines();
|
||||
const isPresent = this._assertAvailableEngines(region, locale, engines);
|
||||
if (isPresent) {
|
||||
this._assertCorrectDomains(region, locale, engines);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assert.ok(!this._testDebug, "Should not have test debug turned on in production");
|
||||
this.assertOk(!this._testDebug, "Should not have test debug turned on in production");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,7 +134,7 @@ class SearchConfigTest {
|
|||
Services.search.reInit();
|
||||
await reinitCompletePromise;
|
||||
|
||||
Assert.ok(Services.search.isInitialized,
|
||||
this.assertOk(Services.search.isInitialized,
|
||||
"Should have completely re-initialization, if it fails check logs for if reinit was successful");
|
||||
}
|
||||
|
||||
|
@ -136,7 +145,11 @@ class SearchConfigTest {
|
|||
if (this._testDebug) {
|
||||
return new Set(["by", "cn", "kz", "us", "ru", "tr"]);
|
||||
}
|
||||
return Services.intl.getAvailableLocaleDisplayNames("region");
|
||||
const chunk = Services.prefs.getIntPref("browser.search.config.test.section", -1) - 1;
|
||||
const regions = Services.intl.getAvailableLocaleDisplayNames("region");
|
||||
const chunkSize = Math.ceil(regions.length / 4);
|
||||
const startPoint = chunk * chunkSize;
|
||||
return regions.slice(startPoint, startPoint + chunkSize);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -201,7 +214,7 @@ class SearchConfigTest {
|
|||
}
|
||||
|
||||
/**
|
||||
* Helper function to determine if an engine matches within a list.
|
||||
* Helper function to find an engine from within a list.
|
||||
* Due to Amazon's current complex setup with three different identifiers,
|
||||
* if the identifier is 'amazon', then we do a startsWith match. Otherwise
|
||||
* we expect the names to equal.
|
||||
|
@ -210,14 +223,14 @@ class SearchConfigTest {
|
|||
* The list of engines to check.
|
||||
* @param {string} identifier
|
||||
* The identifier to look for in the list.
|
||||
* @returns {boolean}
|
||||
* Returns true if the engine is found within the list.
|
||||
* @returns {Engine}
|
||||
* Returns the engine if found, null otherwise.
|
||||
*/
|
||||
_enginesMatch(engines, identifier) {
|
||||
_findEngine(engines, identifier) {
|
||||
if (identifier == "amazon") {
|
||||
return !!engines.find(engine => engine.startsWith(identifier));
|
||||
return engines.find(engine => engine.identifier.startsWith(identifier));
|
||||
}
|
||||
return engines.includes(identifier);
|
||||
return engines.find(engine => engine.identifier == identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -231,20 +244,22 @@ class SearchConfigTest {
|
|||
* The two-letter locale code.
|
||||
* @param {string} section
|
||||
* The section of the configuration to check.
|
||||
* @returns {boolean}
|
||||
* Returns true if the engine is expected to be present, false otherwise.
|
||||
*/
|
||||
_assertEngineRules(engines, region, locale, section) {
|
||||
const infoString = `region: "${region}" locale: "${locale}"`;
|
||||
const config = this._config[section];
|
||||
const hasIncluded = "included" in config;
|
||||
const hasExcluded = "excluded" in config;
|
||||
const identifierIncluded = this._enginesMatch(engines, this._config.identifier);
|
||||
const identifierIncluded = !!this._findEngine(engines, this._config.identifier);
|
||||
|
||||
// If there's not included/excluded, then this shouldn't be the default anywhere.
|
||||
if (section == "default" && !hasIncluded && !hasExcluded) {
|
||||
Assert.ok(!identifierIncluded,
|
||||
this.assertOk(!identifierIncluded,
|
||||
`Should not be ${section} for any locale/region,
|
||||
currently set for ${infoString}`);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
// If there's no included section, we assume the engine is default everywhere
|
||||
|
@ -256,10 +271,11 @@ class SearchConfigTest {
|
|||
!this._localeRegionInSection(config.excluded, region, locale));
|
||||
|
||||
if (included || notExcluded) {
|
||||
Assert.ok(identifierIncluded, `Should be ${section} for ${infoString}`);
|
||||
return;
|
||||
this.assertOk(identifierIncluded, `Should be ${section} for ${infoString}`);
|
||||
return true;
|
||||
}
|
||||
Assert.ok(!identifierIncluded, `Should not be ${section} for ${infoString}`);
|
||||
this.assertOk(!identifierIncluded, `Should not be ${section} for ${infoString}`);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -271,8 +287,8 @@ class SearchConfigTest {
|
|||
* The two-letter locale code.
|
||||
*/
|
||||
_assertDefaultEngines(region, locale) {
|
||||
const identifier = Services.search.originalDefaultEngine.identifier;
|
||||
this._assertEngineRules([identifier], region, locale, "default");
|
||||
this._assertEngineRules([Services.search.originalDefaultEngine], region,
|
||||
locale, "default");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -282,10 +298,72 @@ class SearchConfigTest {
|
|||
* The two-letter region code.
|
||||
* @param {string} locale
|
||||
* The two-letter locale code.
|
||||
* @param {array} engines
|
||||
* The current visible engines.
|
||||
* @returns {boolean}
|
||||
* Returns true if the engine is expected to be present, false otherwise.
|
||||
*/
|
||||
async _assertAvailableEngines(region, locale) {
|
||||
const engines = await Services.search.getVisibleEngines();
|
||||
const engineNames = engines.map(engine => engine._shortName);
|
||||
this._assertEngineRules(engineNames, region, locale, "available");
|
||||
_assertAvailableEngines(region, locale, engines) {
|
||||
return this._assertEngineRules(engines, region, locale, "available");
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts whether the engine is using the correct domains or not.
|
||||
*
|
||||
* @param {string} region
|
||||
* The two-letter region code.
|
||||
* @param {string} locale
|
||||
* The two-letter locale code.
|
||||
* @param {array} engines
|
||||
* The current visible engines.
|
||||
*/
|
||||
_assertCorrectDomains(region, locale, engines) {
|
||||
const [expectedDomain, domainConfig] =
|
||||
Object.entries(this._config.domains).find(([key, value]) =>
|
||||
this._localeRegionInSection(value.included, region, locale));
|
||||
|
||||
this.assertOk(expectedDomain,
|
||||
`Should have an expectedDomain for the engine in region: "${region}" locale: "${locale}"`);
|
||||
|
||||
const engine = this._findEngine(engines, this._config.identifier);
|
||||
this.assertOk(engine, "Should have an engine present");
|
||||
|
||||
const searchForm = new URL(engine.searchForm);
|
||||
this.assertOk(searchForm.host.endsWith(expectedDomain),
|
||||
`Should have the correct search form domain for region: "${region}" locale: "${locale}".
|
||||
Got "${searchForm.host}", expected to end with "${expectedDomain}".`);
|
||||
|
||||
for (const urlType of [URLTYPE_SUGGEST_JSON, URLTYPE_SEARCH_HTML]) {
|
||||
const submission = engine.getSubmission("test", urlType);
|
||||
if (urlType == URLTYPE_SUGGEST_JSON &&
|
||||
(this._config.noSuggestionsURL || domainConfig.noSuggestionsURL)) {
|
||||
this.assertOk(!submission, "Should not have a submission url");
|
||||
} else if (this._config.searchUrlBase) {
|
||||
this.assertEqual(submission.uri.prePath + submission.uri.filePath,
|
||||
this._config.searchUrlBase + domainConfig.searchUrlEnd,
|
||||
`Should have the correct domain for type: ${urlType} region: "${region}" locale: "${locale}".`);
|
||||
} else {
|
||||
this.assertOk(submission.uri.host.endsWith(expectedDomain),
|
||||
`Should have the correct domain for type: ${urlType} region: "${region}" locale: "${locale}".
|
||||
Got "${submission.uri.host}", expected to end with "${expectedDomain}".`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper functions which avoid outputting test results when there are no
|
||||
* failures. These help the tests to run faster, and avoid clogging up the
|
||||
* python test runner process.
|
||||
*/
|
||||
assertOk(value, message) {
|
||||
if (!value || this._testDebug) {
|
||||
Assert.ok(value, message);
|
||||
}
|
||||
}
|
||||
|
||||
assertEqual(actual, expected, message) {
|
||||
if (actual != expected || this._testDebug) {
|
||||
Assert.equal(actual, expected, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,147 @@ const test = new SearchConfigTest({
|
|||
},
|
||||
}],
|
||||
},
|
||||
domains: {
|
||||
// Note: These should be based on region, but we don't currently enforce that.
|
||||
// Note: the order here is important. A region/locale match higher up in the
|
||||
// list will override a region/locale match lower down.
|
||||
"amazon.com.au": {
|
||||
included: [{
|
||||
regions: ["au"],
|
||||
locales: {
|
||||
matches: [
|
||||
"ach", "af", "ar", "as", "az", "bg", "bn-IN", "cak", "eo", "en-US",
|
||||
"en-ZA", "es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km", "lt",
|
||||
"mk", "ms", "my", "ro", "si", "th", "tl", "trs", "uz",
|
||||
],
|
||||
},
|
||||
}, {
|
||||
regions: ["au"],
|
||||
locales: {
|
||||
matches: [
|
||||
"cy", "da", "el", "en-GB", "eu", "ga-IE", "gd", "gl", "hr", "nb-NO",
|
||||
"nn-NO", "pt-PT", "sq", "sr",
|
||||
],
|
||||
},
|
||||
}],
|
||||
noSuggestionsURL: true,
|
||||
},
|
||||
"amazon.ca": {
|
||||
included: [{
|
||||
locales: {
|
||||
matches: ["ca", "en-CA"],
|
||||
},
|
||||
}, {
|
||||
regions: ["ca"],
|
||||
locales: {
|
||||
matches: [
|
||||
"ach", "af", "ar", "as", "az", "bg", "bn-IN", "cak", "eo", "en-US",
|
||||
"en-ZA", "es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km", "lt",
|
||||
"mk", "ms", "my", "ro", "si", "th", "tl", "trs", "uz",
|
||||
],
|
||||
},
|
||||
}, {
|
||||
regions: ["ca"],
|
||||
locales: {
|
||||
matches: [
|
||||
"br", "fr", "ff", "son", "wo",
|
||||
],
|
||||
},
|
||||
}],
|
||||
noSuggestionsURL: true,
|
||||
},
|
||||
"amazon.fr": {
|
||||
included: [{
|
||||
locales: {
|
||||
matches: ["br", "fr", "ff", "son", "wo"],
|
||||
},
|
||||
}, {
|
||||
regions: ["fr"],
|
||||
locales: {
|
||||
matches: [
|
||||
"ach", "af", "ar", "as", "az", "bg", "bn-IN", "cak", "eo", "en-US",
|
||||
"en-ZA", "es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km", "lt",
|
||||
"mk", "ms", "my", "ro", "si", "th", "tl", "trs", "uz",
|
||||
],
|
||||
},
|
||||
}],
|
||||
noSuggestionsURL: true,
|
||||
},
|
||||
"amazon.co.uk": {
|
||||
included: [{
|
||||
locales: {
|
||||
matches: [
|
||||
"cy", "da", "el", "en-GB", "eu", "ga-IE", "gd", "gl", "hr", "nb-NO",
|
||||
"nn-NO", "pt-PT", "sq", "sr",
|
||||
],
|
||||
},
|
||||
}, {
|
||||
regions: ["gb"],
|
||||
locales: {
|
||||
matches: [
|
||||
"ach", "af", "ar", "as", "az", "bg", "bn-IN", "cak", "eo", "en-US",
|
||||
"en-ZA", "es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km", "lt",
|
||||
"mk", "ms", "my", "ro", "si", "th", "tl", "trs", "uz",
|
||||
],
|
||||
},
|
||||
}],
|
||||
noSuggestionsURL: true,
|
||||
},
|
||||
"amazon.com": {
|
||||
included: [{
|
||||
locales: {
|
||||
matches: [
|
||||
"ach", "af", "ar", "as", "az", "bg", "bn-IN", "cak", "eo", "en-US",
|
||||
"en-ZA", "es-AR", "fa", "gn", "hy-AM", "ia", "is", "ka", "km", "lt",
|
||||
"mk", "ms", "my", "ro", "si", "th", "tl", "trs", "uz",
|
||||
],
|
||||
},
|
||||
}],
|
||||
},
|
||||
"amazon.cn": {
|
||||
included: [{
|
||||
locales: {
|
||||
matches: ["zh-CN"],
|
||||
},
|
||||
}],
|
||||
noSuggestionsURL: true,
|
||||
},
|
||||
"amazon.co.jp": {
|
||||
included: [{
|
||||
locales: {
|
||||
startsWith: ["ja"],
|
||||
},
|
||||
}],
|
||||
noSuggestionsURL: true,
|
||||
},
|
||||
"amazon.de": {
|
||||
included: [{
|
||||
locales: {
|
||||
matches: ["de", "dsb", "hsb"],
|
||||
},
|
||||
}],
|
||||
noSuggestionsURL: true,
|
||||
},
|
||||
"amazon.in": {
|
||||
included: [{
|
||||
locales: {
|
||||
matches: [
|
||||
"bn", "gu-IN", "kn", "mai", "ml", "mr", "or", "pa-IN", "ta",
|
||||
"te", "ur",
|
||||
],
|
||||
},
|
||||
}],
|
||||
noSuggestionsURL: true,
|
||||
},
|
||||
"amazon.it": {
|
||||
included: [{
|
||||
locales: {
|
||||
matches: ["it", "lij"],
|
||||
},
|
||||
}],
|
||||
noSuggestionsURL: true,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
add_task(async function setup() {
|
||||
|
|
|
@ -22,6 +22,11 @@ const test = new SearchConfigTest({
|
|||
},
|
||||
}],
|
||||
},
|
||||
domains: {
|
||||
"baidu.com": {
|
||||
included: [{}],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
add_task(async function setup() {
|
||||
|
|
|
@ -32,6 +32,11 @@ const test = new SearchConfigTest({
|
|||
},
|
||||
}],
|
||||
},
|
||||
domains: {
|
||||
"bing.com": {
|
||||
included: [{}],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
add_task(async function setup() {
|
||||
|
|
|
@ -13,6 +13,11 @@ const test = new SearchConfigTest({
|
|||
// Should be available everywhere.
|
||||
],
|
||||
},
|
||||
domains: {
|
||||
"duckduckgo.com": {
|
||||
included: [{}],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
add_task(async function setup() {
|
||||
|
|
|
@ -19,6 +19,103 @@ const test = new SearchConfigTest({
|
|||
},
|
||||
}],
|
||||
},
|
||||
searchUrlBase: "https://rover.ebay.com/rover/1/",
|
||||
domains: {
|
||||
// Note: These should be based on region, but we don't currently enforce that.
|
||||
// Note: the order here is important. A region/locale match higher up in the
|
||||
// list will override a region/locale match lower down.
|
||||
"befr.ebay.be": {
|
||||
included: [{
|
||||
regions: ["be"],
|
||||
locales: { matches: ["br", "fr", "fy-NL", "nl", "wo"]},
|
||||
}],
|
||||
searchUrlEnd: "1553-53471-19255-0/1",
|
||||
},
|
||||
"ebay.at": {
|
||||
included: [{
|
||||
regions: ["at"],
|
||||
locales: { matches: ["de", "dsb", "hsb"]},
|
||||
}],
|
||||
searchUrlEnd: "5221-53469-19255-0/1",
|
||||
},
|
||||
"ebay.ca": {
|
||||
included: [{
|
||||
locales: { matches: ["en-CA"] },
|
||||
}, {
|
||||
regions: ["ca"],
|
||||
locales: { matches: ["br", "fr", "wo"]},
|
||||
}],
|
||||
searchUrlEnd: "706-53473-19255-0/1",
|
||||
},
|
||||
"ebay.ch": {
|
||||
included: [{
|
||||
locales: { matches: ["rm"] },
|
||||
}, {
|
||||
regions: ["ch"],
|
||||
locales: { matches: ["br", "de", "dsb", "fr", "hsb", "wo"]},
|
||||
}],
|
||||
searchUrlEnd: "5222-53480-19255-0/1",
|
||||
},
|
||||
"ebay.com": {
|
||||
included: [{
|
||||
locales: { matches: ["en-US"] },
|
||||
}],
|
||||
searchUrlEnd: "711-53200-19255-0/1",
|
||||
},
|
||||
"ebay.com.au": {
|
||||
included: [{
|
||||
regions: ["au"],
|
||||
locales: { matches: ["cy", "en-GB", "gd"]},
|
||||
}],
|
||||
searchUrlEnd: "705-53470-19255-0/1",
|
||||
},
|
||||
"ebay.ie": {
|
||||
included: [{
|
||||
locales: { matches: ["ga-IE", "ie"] },
|
||||
}, {
|
||||
regions: ["ie"],
|
||||
locales: { matches: ["cy", "en-GB", "gd"]},
|
||||
}],
|
||||
searchUrlEnd: "5282-53468-19255-0/1",
|
||||
},
|
||||
"ebay.co.uk": {
|
||||
included: [{
|
||||
locales: { matches: ["cy", "en-GB", "gd"] },
|
||||
}],
|
||||
searchUrlEnd: "710-53481-19255-0/1",
|
||||
},
|
||||
"ebay.de": {
|
||||
included: [{
|
||||
locales: { matches: ["de", "dsb", "hsb"] },
|
||||
}],
|
||||
searchUrlEnd: "707-53477-19255-0/1",
|
||||
},
|
||||
"ebay.es": {
|
||||
included: [{
|
||||
locales: { matches: ["an", "ast", "ca", "es-ES", "eu", "gl"] },
|
||||
}],
|
||||
searchUrlEnd: "1185-53479-19255-0/1",
|
||||
},
|
||||
"ebay.fr": {
|
||||
included: [{
|
||||
locales: { matches: ["br", "fr", "wo"] },
|
||||
}],
|
||||
searchUrlEnd: "709-53476-19255-0/1",
|
||||
},
|
||||
"ebay.it": {
|
||||
included: [{
|
||||
locales: { matches: ["it", "lij"] },
|
||||
}],
|
||||
searchUrlEnd: "724-53478-19255-0/1",
|
||||
},
|
||||
"ebay.nl": {
|
||||
included: [{
|
||||
locales: { matches: ["fy-NL", "nl"] },
|
||||
}],
|
||||
searchUrlEnd: "1346-53482-19255-0/1",
|
||||
},
|
||||
},
|
||||
noSuggestionsURL: true,
|
||||
});
|
||||
|
||||
add_task(async function setup() {
|
||||
|
|
|
@ -29,6 +29,11 @@ const test = new SearchConfigTest({
|
|||
// Should be available everywhere.
|
||||
],
|
||||
},
|
||||
domains: {
|
||||
"google.com": {
|
||||
included: [{}],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
add_task(async function setup() {
|
||||
|
|
|
@ -24,6 +24,38 @@ const test = new SearchConfigTest({
|
|||
},
|
||||
}],
|
||||
},
|
||||
domains: {
|
||||
"yandex.az": {
|
||||
included: [{
|
||||
locales: { matches: ["az"] },
|
||||
}],
|
||||
},
|
||||
"yandex.com": {
|
||||
included: [{
|
||||
locales: { startsWith: ["en"] },
|
||||
}],
|
||||
},
|
||||
"yandex.ru": {
|
||||
included: [{
|
||||
locales: { matches: ["ru"] },
|
||||
}],
|
||||
},
|
||||
"yandex.by": {
|
||||
included: [{
|
||||
locales: { matches: ["be"] },
|
||||
}],
|
||||
},
|
||||
"yandex.kz": {
|
||||
included: [{
|
||||
locales: { matches: ["kk"] },
|
||||
}],
|
||||
},
|
||||
"yandex.com.tr": {
|
||||
included: [{
|
||||
locales: { matches: ["tr"] },
|
||||
}],
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
add_task(async function setup() {
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
[DEFAULT]
|
||||
firefox-appdir = browser
|
||||
head = head_searchconfig.js head_chunk1.js
|
||||
dupe-manifest =
|
||||
support-files =
|
||||
../../../../../../browser/locales/all-locales
|
||||
tags=searchconfig searchconfig1
|
||||
|
||||
[include:xpcshell-common.ini]
|
||||
skip-if = toolkit == 'android'
|
|
@ -0,0 +1,10 @@
|
|||
[DEFAULT]
|
||||
firefox-appdir = browser
|
||||
head = head_searchconfig.js head_chunk2.js
|
||||
dupe-manifest =
|
||||
support-files =
|
||||
../../../../../../browser/locales/all-locales
|
||||
tags=searchconfig searchconfig2
|
||||
|
||||
[include:xpcshell-common.ini]
|
||||
skip-if = toolkit == 'android'
|
|
@ -0,0 +1,10 @@
|
|||
[DEFAULT]
|
||||
firefox-appdir = browser
|
||||
head = head_searchconfig.js head_chunk3.js
|
||||
dupe-manifest =
|
||||
support-files =
|
||||
../../../../../../browser/locales/all-locales
|
||||
tags=searchconfig searchconfig3
|
||||
|
||||
[include:xpcshell-common.ini]
|
||||
skip-if = toolkit == 'android'
|
|
@ -0,0 +1,10 @@
|
|||
[DEFAULT]
|
||||
firefox-appdir = browser
|
||||
head = head_searchconfig.js head_chunk4.js
|
||||
dupe-manifest =
|
||||
support-files =
|
||||
../../../../../../browser/locales/all-locales
|
||||
tags=searchconfig searchconfig4
|
||||
|
||||
[include:xpcshell-common.ini]
|
||||
skip-if = toolkit == 'android'
|
|
@ -1,44 +1,36 @@
|
|||
[DEFAULT]
|
||||
firefox-appdir = browser
|
||||
head = head_searchconfig.js
|
||||
skip-if = toolkit == 'android'
|
||||
support-files =
|
||||
../../../../../../browser/locales/all-locales
|
||||
tags=searchconfig
|
||||
|
||||
[test_amazon.js]
|
||||
# This is an extensive test and currently takes a long time. Therefore skip on
|
||||
# debug/asan and extend the timeout length otherwise.
|
||||
skip-if = debug || asan
|
||||
requesttimeoutfactor = 2
|
||||
requesttimeoutfactor = 3
|
||||
[test_baidu.js]
|
||||
# This is an extensive test and currently takes a long time. Therefore skip on
|
||||
# debug/asan and extend the timeout length otherwise.
|
||||
skip-if = debug || asan
|
||||
requesttimeoutfactor = 2
|
||||
requesttimeoutfactor = 3
|
||||
[test_bing.js]
|
||||
# This is an extensive test and currently takes a long time. Therefore skip on
|
||||
# debug/asan and extend the timeout length otherwise.
|
||||
skip-if = debug || asan
|
||||
requesttimeoutfactor = 2
|
||||
requesttimeoutfactor = 3
|
||||
[test_duckduckgo.js]
|
||||
# This is an extensive test and currently takes a long time. Therefore skip on
|
||||
# debug/asan and extend the timeout length otherwise.
|
||||
skip-if = debug || asan
|
||||
requesttimeoutfactor = 2
|
||||
requesttimeoutfactor = 3
|
||||
[test_ebay.js]
|
||||
# This is an extensive test and currently takes a long time. Therefore skip on
|
||||
# debug/asan and extend the timeout length otherwise.
|
||||
# Thunderbird doesn't provide eBay search engines.
|
||||
skip-if = debug || asan || appname == "thunderbird"
|
||||
requesttimeoutfactor = 2
|
||||
requesttimeoutfactor = 3
|
||||
[test_google.js]
|
||||
# This is an extensive test and currently takes a long time. Therefore skip on
|
||||
# debug/asan and extend the timeout length otherwise.
|
||||
skip-if = debug || asan
|
||||
requesttimeoutfactor = 2
|
||||
requesttimeoutfactor = 3
|
||||
[test_yandex.js]
|
||||
# This is an extensive test and currently takes a long time. Therefore skip on
|
||||
# debug/asan and extend the timeout length otherwise.
|
||||
skip-if = debug || asan
|
||||
requesttimeoutfactor = 2
|
||||
requesttimeoutfactor = 3
|
Загрузка…
Ссылка в новой задаче