Merge mozilla-central to inbound. a=merge CLOSED TREE

This commit is contained in:
Gurzau Raul 2019-05-15 19:02:08 +03:00
Родитель 234190dbe4 5192e34081
Коммит f774bd9752
100 изменённых файлов: 2116 добавлений и 922 удалений

Просмотреть файл

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

20
devtools/client/debugger/dist/vendors.css поставляемый
Просмотреть файл

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

9
devtools/client/debugger/dist/vendors.js поставляемый
Просмотреть файл

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