Update On Tue Dec 3 19:21:39 CET 2024

This commit is contained in:
github-action[bot] 2024-12-03 19:21:39 +01:00
parent 3ebe7961ce
commit 9410b96786
487 changed files with 26230 additions and 19985 deletions

View file

@ -463,7 +463,7 @@ const CacheDomain = {
};
function accessibleTask(doc, task, options = {}) {
return async function () {
const wrapped = async function () {
let cacheDomains;
if (!("cacheDomains" in options)) {
cacheDomains = CacheDomain.All;
@ -615,6 +615,16 @@ function accessibleTask(doc, task, options = {}) {
await runPython(`__reset__`);
}
};
// Propagate the name of the task function to our wrapper function so it shows
// up in test run output. For example:
// 0:39.16 INFO Entering test bound testProtected
// Even if the name is empty, we still propagate it here to override the
// implicit "wrapped" name derived from the assignment at the top of this
// function.
// The "name" property of functions is not writable, but we can override that
// using Object.defineProperty.
Object.defineProperty(wrapped, "name", { value: task.name });
return wrapped;
}
/**

View file

@ -2021,6 +2021,12 @@ pref("pdfjs.handleOctetStream", true);
// Is the sidebar positioned ahead of the content browser
pref("sidebar.position_start", true);
pref("sidebar.revamp", false);
// This is nightly only for now, as we need to address bug 1933527 and bug 1934039.
#ifdef NIGHTLY_BUILD
pref("sidebar.revamp.round-content-area", true);
#else
pref("sidebar.revamp.round-content-area", false);
#endif
pref("sidebar.animation.enabled", true);
pref("sidebar.animation.duration-ms", 200);
pref("sidebar.main.tools", "aichat,syncedtabs,history");

View file

@ -5,6 +5,7 @@
"use strict";
/* import-globals-from aboutDialog-appUpdater.js */
/* import-globals-from utilityOverlay.js */
// Services = object with smart getters for common XPCOM services
var { AppConstants } = ChromeUtils.importESModule(
@ -117,6 +118,38 @@ function init() {
if (AppConstants.IS_ESR) {
document.getElementById("release").hidden = false;
}
document
.getElementById("aboutDialogEscapeKey")
.addEventListener("command", () => {
window.close();
});
if (AppConstants.MOZ_UPDATER) {
document
.getElementById("aboutDialogHelpLink")
.addEventListener("click", () => {
openHelpLink("firefox-help");
});
document
.getElementById("submit-feedback")
.addEventListener("click", openFeedbackPage);
document
.getElementById("checkForUpdatesButton")
.addEventListener("command", () => {
gAppUpdater.checkForUpdates();
});
document
.getElementById("downloadAndInstallButton")
.addEventListener("command", () => {
gAppUpdater.startDownload();
});
document.getElementById("updateButton").addEventListener("command", () => {
gAppUpdater.buttonRestartAfterDownload();
});
window.addEventListener("unload", e => {
onUnload(e);
});
}
}
init();

View file

@ -8,9 +8,6 @@
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="aboutDialog"
windowtype="Browser:About"
#ifdef MOZ_UPDATER
onunload="onUnload(event);"
#endif
#ifndef XP_MACOSX
data-l10n-id="aboutDialog-title"
#endif
@ -65,18 +62,14 @@
<deck id="updateDeck" orient="vertical">
<description id="checkForUpdates">
<button id="checkForUpdatesButton"
data-l10n-id="update-checkForUpdatesButton"
oncommand="gAppUpdater.checkForUpdates();"/>
data-l10n-id="update-checkForUpdatesButton"/>
</description>
<description id="downloadAndInstall">
<button id="downloadAndInstallButton"
oncommand="gAppUpdater.startDownload();"/>
<!-- label and accesskey will be filled by JS -->
<button id="downloadAndInstallButton"/>
</description>
<description id="apply">
<button id="updateButton"
data-l10n-id="update-updateButton"
oncommand="gAppUpdater.buttonRestartAfterDownload();"/>
data-l10n-id="update-updateButton"/>
</description>
<description id="checkingForUpdates" data-l10n-id="update-checkingForUpdates"/>
<description id="downloading" data-l10n-id="aboutdialog-update-downloading" data-l10n-args='{"transfer":""}'>
@ -108,8 +101,8 @@
<label id="releasenotes" is="text-link" hidden="true" data-l10n-id="releaseNotes-link"/>
</hbox>
<description class="text-blurb">
<label is="text-link" onclick="openHelpLink('firefox-help')" data-l10n-id="aboutdialog-help-user"/>
<label id="submit-feedback" is="text-link" onclick="openFeedbackPage()" data-l10n-id="aboutdialog-submit-feedback"/>
<label id="aboutDialogHelpLink" is="text-link" data-l10n-id="aboutdialog-help-user"/>
<label id="submit-feedback" is="text-link" data-l10n-id="aboutdialog-submit-feedback"/>
</description>
</vbox>
#endif
@ -151,7 +144,7 @@
</html:div>
<keyset>
<key keycode="VK_ESCAPE" oncommand="window.close();"/>
<key id="aboutDialogEscapeKey" keycode="VK_ESCAPE"/>
</keyset>
<script src="chrome://browser/content/aboutDialog.js"/>

View file

@ -134,16 +134,17 @@ document.addEventListener(
BookmarksEventHandler.onMouseUp(event);
});
mainMenuBar.addEventListener("dragover", event =>
const bookmarksMenu = document.getElementById("bookmarksMenu");
bookmarksMenu.addEventListener("dragover", event =>
PlacesMenuDNDHandler.onDragOver(event)
);
mainMenuBar.addEventListener("dragenter", event =>
bookmarksMenu.addEventListener("dragenter", event =>
PlacesMenuDNDHandler.onDragEnter(event)
);
mainMenuBar.addEventListener("dragleave", event =>
bookmarksMenu.addEventListener("dragleave", event =>
PlacesMenuDNDHandler.onDragLeave(event)
);
mainMenuBar.addEventListener("drop", event =>
bookmarksMenu.addEventListener("drop", event =>
PlacesMenuDNDHandler.onDrop(event)
);

View file

@ -5787,6 +5787,13 @@ export var DefaultBrowserCheck = {
win.MozXULElement.insertFTLIfNeeded(
"browser/defaultBrowserNotification.ftl"
);
// Record default prompt impression
let now = Math.floor(Date.now() / 1000).toString();
Services.prefs.setCharPref(
"browser.shell.mostRecentDefaultPromptSeen",
now
);
// Resolve the translations for the prompt elements and return only the
// string values
@ -5867,6 +5874,7 @@ export var DefaultBrowserCheck = {
}
if (checkboxState) {
shellService.shouldCheckDefaultBrowser = false;
Services.prefs.setCharPref("browser.shell.userDisabledDefaultCheck", now);
}
try {

View file

@ -1,16 +1,85 @@
# Remote CFR Messages
Starting in Firefox 68, CFR messages will be defined using [Remote Settings](https://remote-settings.readthedocs.io/en/latest/index.html). In this document, we'll cover how to set up a dev environment.
Starting in Firefox 68, CFR messages will be defined using [Remote Settings](https://remote-settings.readthedocs.io/en/latest/index.html).
## Using a dev server for Remote CFR
> Note: Since Novembre 2021, Remote Settings has a proper DEV instance, which is
> reachable without VPN, but has the same config (openid, multi-signoff, ...)
> and collections as STAGE/PROD.
## Environments
There are three environments available for Remote Settings:
* DEV - `https://remote-settings-dev.allizom.org/v1/`
* STAGING - `https://remote-settings.allizom.org/v1/`
* PROD - `https://remote-settings.mozilla.org/v1/`
DEV is primarily used for testing the Remote Settings API and exploring new use cases. Messaging validation and QA are conducted in the STAGING environment, while finalized and validated messages are delivered in the PROD environment. Both STAGING and PROD follow the [Multi Signoff Workflow](https://remote-settings.readthedocs.io/en/latest/tutorial-multi-signoff.html). During the review process, messages are served in the `main-preview` bucket. Once reviewed, they are moved to the `main` bucket.
Access to STAGING and PROD environments requires VPN (using "Viscosity VPN," which can be requested via the Jira Service Desk). However, the DEV environment is accessible without VPN.
To switch between environments more easily, you can use the [remote-settings-devtools](https://github.com/mozilla-extensions/remote-settings-devtools) extension. After installation, click on the extension in your browser to open its UI. The devtools provide a dropdown menu to switch between environments (`prod`, `prod-preview`, `staging`, `staging-preview`, `dev`, and `dev-preview`) and automatically update the necessary preferences for each environment.
To easily change between these environments, the [remote-settings-devtools](https://github.com/mozilla-extensions/remote-settings-devtools) extension is available. Once installed, you can click on the extensions list in the browser, select `remote-settings-devtools` to interact with the devtools UI. The devtools allows you to switch between environments on your profile through the drop-down menu and will take care of correctly flipping all the required prefs. Specifically, it will allow you to point to `prod`, `prod-preview`, `staging`, `staging-preview`, `dev` and `dev-preview`.
Alternatively, it is possible to switch between environments by updating the following prefs in `about:config`:
* `services.settings.default_bucket`: `main` or `main-preview`
* `services.settings.server`: the applicable environment URL
For release and ESR, for security reasons, you will also need to run the application through the command line with `MOZ_REMOTE_SETTINGS_DEVTOOLS=1` environment variable for the preferences to be taken into account. Note that toggling the preference wont have any effect until restart.
## Add Message using Remote Settings Admin UI
1. **Log in to the Remote Settings Admin UI**
- Use your LDAP identity to log in and start testing in [STAGING](https://remote-settings.allizom.org/v1/admin/#/).
2. **Add Messaging System JSON**
- On the left-hand side, under the **Workspace** bucket, click on the `cfr` collection.
- Select `Create record` to open a text field.
- Paste valid [Messaging System JSON](https://firefox-source-docs.mozilla.org/toolkit/components/messaging-system/docs/index.html) into the text field.
- Ensure the following fields are accurate:
- `id`: Unique identifier for the message.
- `last_modified`: Current date and time in milliseconds.
- These fields will be visible in the **Records** column.
3. **Preview testing**
- Follow the [Multi Signoff Workflow](https://remote-settings.readthedocs.io/en/latest/tutorial-multi-signoff.html), add the message into preview by putting into review, it will be served in the `main-preview` bucket.
- Install the [Remote Settings DevTools](https://github.com/mozilla-extensions/remote-settings-devtools).
- Use the dev tools to point to `staging-preview`.
- In `about:config`, enable the following preference:
```
browser.newtabpage.activity-stream.asrouter.devtoolsEnabled
```
- Go to `about:asrouter`.
- Under the **Message** tab:
- Filter the **Providers** for `cfr` to view the message in ASRouter.
4. **Main testing**
- If the message looks good, switch to the **Review** tab in Remote Settings.
- Have a peer review the changes.
- Once the review has been approved, we can test the message again, pointing to `staging` instead of `staging-preview`.
5. **Deploy to PROD**
- Follow the same steps for the [PROD Environment](https://remote-settings.mozilla.org/v1/admin/#/).
- Use the `prod-preview` and `prod` buckets for final testing and deployment.
## Remote l10n
By default, all CFR messages are localized with the remote Fluent files hosted in `ms-language-packs` collection on Remote Settings using the [ms-language-packs script](https://github.com/mozilla-services/ms-language-packs?tab=readme-ov-file#messaging-system-language-packs-for-remote-settings).
We can check which components of the messages are hooked up to RemoteL10n with the following [Searchfox regex query](https://searchfox.org/mozilla-central/search?q=lazy%5C.RemoteL10n%5C.%28formatLocalizableText%7CcreateElement%29&path=&case=false&regexp=true). For example Infobar buttons are currently not Remotel10n configurable, see [Bug 1933819](https://bugzilla.mozilla.org/show_bug.cgi?id=1933819).
For local testing and development, we can force ASRouter to use the local Fluent files by flipping the pref `browser.newtabpage.activity-stream.asrouter.useRemoteL10n` in `about:config`. A note that [RemoteL10n uses the `main` bucket](https://searchfox.org/mozilla-central/source/browser/components/asrouter/modules/ASRouter.sys.mjs#297) so we cannot test using `main-preview`.
## The following are steps on how to authenticate and add messages manually
**1. Obtain your Bearer Token**
This can be done through browser-based authentication or through the Admin portal.
Until [Bug 1630651](https://bugzilla.mozilla.org/show_bug.cgi?id=1630651) happens, the easiest way to obtain your OpenID credentials is to use the admin interface.
### Browser-based authentication
1. Ensure you have [kinto-http](https://pypi.org/project/kinto-http/) python library installed
2. In your terminal, run `python` with the following:
```python
>>> import kinto_http
>>> c = kinto_http.Client(server_url='https://remote-settings-dev.allizom.org/v1', auth=kinto_http.BrowserOAuth())
>>> c.server_info()["user"]
```
3. This will open the browser with a login successful page with your credentials in the terminal
### Admin portal
1. [Login on the Admin UI](https://remote-settings-dev.allizom.org/v1/admin/) using your LDAP identity
2. Copy the authentication header (📋 icon in the top bar)
3. Test your credentials with ``curl``. When reaching out the server root URL with this bearer token you should see a ``user`` entry whose ``id`` field is ``ldap:<you>@mozilla.com``.
@ -24,8 +93,6 @@ curl -s ${SERVER}/ -H "Authorization:${BEARER_TOKEN}" | jq .user
**2. Create/Update/Delete CFR entries**
> The messages can also be created manually using the [admin interface](https://settings.dev.mozaws.net/v1/admin/).
In following example, we will create a new entry using the REST API (reusing `SERVER` and `BEARER_TOKEN` from previous step).
```bash
@ -72,11 +139,3 @@ Services.prefs.setBoolPref("browser.newtabpage.activity-stream.asrouter.devtools
**4. Go to `about:asrouter`**
There should be a "cfr-remote" provider listed.
## Using the staging server for Remote CFR
If your message is published in the staging environment the easiest way to test is using the [Remote Settings Devtools](https://github.com/mozilla/remote-settings-devtools/releases) addon. You can install this by going to `about:debugging` and using the `Load Temporary Addon` feature.
The devtools allow you to switch your profile between production and staging and takes care of correctly flipping all the required preferences.
## Remote l10n
By default, all CFR messages are localized with the remote Fluent files hosted in `ms-language-packs` on Remote Settings. For local test and development, you can force ASRouter to use the local Fluent files by flipping the pref `browser.newtabpage.activity-stream.asrouter.useRemoteL10n`.

View file

@ -40,7 +40,7 @@ export class _CustomizeMenu extends React.PureComponent {
className="icon icon-settings personalize-button"
onClick={() => this.props.onOpen()}
onKeyDown={e => {
if (e.key === 13) {
if (e.key === "Enter") {
this.props.onOpen();
}
}}

View file

@ -10772,7 +10772,7 @@ class _CustomizeMenu extends (external_React_default()).PureComponent {
className: "icon icon-settings personalize-button",
onClick: () => this.props.onOpen(),
onKeyDown: e => {
if (e.key === 13) {
if (e.key === "Enter") {
this.props.onOpen();
}
},

View file

@ -422,6 +422,20 @@ export const PREFS_CONFIG = new Map([
value: false,
},
],
[
"newtabAdSize.leaderboard",
{
title: "Boolean flag to turn the leaderboard ad size on and off",
value: false,
},
],
[
"newtabAdSize.billboard",
{
title: "Boolean flag to turn the billboard ad size on and off",
value: false,
},
],
[
"newtabLayouts.variant-a",
{

View file

@ -31,6 +31,8 @@ https_first_disabled = true
["browser_customize_menu_render.js"]
["browser_customize_menu_key_open.js"]
["browser_discovery_card.js"]
["browser_discovery_render.js"]

View file

@ -0,0 +1,32 @@
"use strict";
// Test that the customization menu is rendered.
test_newtab({
async before() {
gBrowser.selectedBrowser.focus();
},
test: async function test_open_customizeMenu() {
await ContentTaskUtils.waitForCondition(
() => content.document.querySelector(".personalize-button"),
"Wait for personalize button to load on the newtab page"
);
let defaultPos = "matrix(1, 0, 0, 1, 0, 0)";
Assert.notStrictEqual(
content.getComputedStyle(
content.document.querySelector(".customize-menu")
).transform,
defaultPos,
"Customize Menu should be rendered, but not visible"
);
let customizeButton = content.document.querySelector(".personalize-button");
customizeButton.focus();
await EventUtils.synthesizeKey("KEY_Enter", {}, content.window);
await ContentTaskUtils.waitForCondition(
() => content.document.querySelector(".customize-animate-enter-done"),
"Customize Menu should be rendered now"
);
},
});

View file

@ -21,7 +21,7 @@ test_newtab({
customizeButton.click();
await ContentTaskUtils.waitForCondition(
() => content.document.querySelector(".customize-menu"),
() => content.document.querySelector(".customize-animate-enter-done"),
"Customize Menu should be rendered now"
);
},

View file

@ -209,14 +209,14 @@ class SessionStoreTestCase(WindowManagerMixin, MarionetteTestCase):
return opened_windows
def _close_tab_shortcut(self):
self.marionette.actions.sequence("key", "keyboard_id").key_down(
self.accelKey
).key_down("w").key_up("w").key_up(self.accelKey).perform()
def _close_last_tab(self):
# "self.marionette.close" cannot be used because it doesn't
# allow closing the very last tab.
self.marionette.execute_script("window.close()")
def close_all_tabs_and_restart(self):
self.close_all_tabs()
self.marionette.quit(callback=self._close_tab_shortcut)
self.marionette.quit(callback=self._close_last_tab)
self.marionette.start_session()
def simulate_os_shutdown(self):

View file

@ -207,6 +207,35 @@ add_task(async function showDefaultPrompt() {
await BrowserTestUtils.closeWindow(win2);
});
add_task(async function promptStoresImpressionAndDisableTimestamps() {
await showAndWaitForModal(win => {
const dialog = win.document.querySelector("dialog");
dialog.querySelector("checkbox").click();
dialog.getButton("cancel").click();
});
const impressionTimestamp = Services.prefs.getCharPref(
"browser.shell.mostRecentDefaultPromptSeen"
);
const disabledTimestamp = Services.prefs.getCharPref(
"browser.shell.userDisabledDefaultCheck"
);
const now = Math.floor(Date.now() / 1000);
const oneHourInMs = 60 * 60 * 1000;
Assert.ok(
impressionTimestamp &&
now - parseInt(impressionTimestamp, 10) <= oneHourInMs,
"Prompt impression timestamp is stored"
);
Assert.ok(
disabledTimestamp && now - parseInt(disabledTimestamp, 10) <= oneHourInMs,
"Selecting checkbox stores timestamp of when user disabled the prompt"
);
});
add_task(async function showPromptStyleSpotlight() {
let sandbox = sinon.createSandbox();

View file

@ -1120,7 +1120,7 @@ suggest_relevance:
notification_emails:
- disco-team@mozilla.com
- najiang@mozilla.com
expires: 136
expires: 139
data_sensitivity:
- technical
outcome:
@ -1140,7 +1140,7 @@ suggest_relevance:
notification_emails:
- disco-team@mozilla.com
- najiang@mozilla.com
expires: 136
expires: 139
data_sensitivity:
- technical

View file

@ -2,4 +2,4 @@ ${DEB_PKG_NAME} (${DEB_PKG_VERSION}) UNRELEASED; urgency=medium
* N/A
-- Mozilla Releng <release@mozilla.com> ${DEB_CHANGELOG_DATE}
-- Mozilla <release@mozilla.com> ${DEB_CHANGELOG_DATE}

View file

@ -1,5 +1,5 @@
Source: ${DEB_PKG_NAME}
Maintainer: Mozilla Releng <release@mozilla.com>
Maintainer: Mozilla <release@mozilla.com>
Priority: optional
Section: web
Build-Depends: debhelper (>= 9)

View file

@ -2,4 +2,4 @@ ${DEB_PKG_NAME} (${DEB_PKG_VERSION}) UNRELEASED; urgency=medium
* N/A
-- Mozilla Releng <release@mozilla.com> ${DEB_CHANGELOG_DATE}
-- Mozilla <release@mozilla.com> ${DEB_CHANGELOG_DATE}

View file

@ -1,5 +1,5 @@
Source: ${DEB_PKG_NAME}
Maintainer: Mozilla Releng <release@mozilla.com>
Maintainer: Mozilla <release@mozilla.com>
Priority: optional
Section: web
Build-Depends: debhelper (>= 9)

View file

@ -16,7 +16,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"af": {
"pin": false,
@ -35,7 +35,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"an": {
"pin": false,
@ -54,7 +54,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ar": {
"pin": false,
@ -73,7 +73,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ast": {
"pin": false,
@ -92,7 +92,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"az": {
"pin": false,
@ -111,7 +111,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"be": {
"pin": false,
@ -130,7 +130,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"bg": {
"pin": false,
@ -149,7 +149,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"bn": {
"pin": false,
@ -168,7 +168,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"bo": {
"pin": false,
@ -187,7 +187,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"br": {
"pin": false,
@ -206,7 +206,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"brx": {
"pin": false,
@ -225,7 +225,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"bs": {
"pin": false,
@ -244,7 +244,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ca": {
"pin": false,
@ -263,7 +263,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ca-valencia": {
"pin": false,
@ -282,7 +282,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"cak": {
"pin": false,
@ -301,7 +301,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ckb": {
"pin": false,
@ -320,7 +320,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"cs": {
"pin": false,
@ -339,7 +339,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"cy": {
"pin": false,
@ -358,7 +358,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"da": {
"pin": false,
@ -377,7 +377,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"de": {
"pin": false,
@ -396,7 +396,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"dsb": {
"pin": false,
@ -415,7 +415,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"el": {
"pin": false,
@ -434,7 +434,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"en-CA": {
"pin": false,
@ -453,7 +453,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"en-GB": {
"pin": false,
@ -472,7 +472,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"eo": {
"pin": false,
@ -491,7 +491,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"es-AR": {
"pin": false,
@ -510,7 +510,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"es-CL": {
"pin": false,
@ -529,7 +529,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"es-ES": {
"pin": false,
@ -548,7 +548,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"es-MX": {
"pin": false,
@ -567,7 +567,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"et": {
"pin": false,
@ -586,7 +586,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"eu": {
"pin": false,
@ -605,7 +605,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"fa": {
"pin": false,
@ -624,7 +624,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ff": {
"pin": false,
@ -643,7 +643,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"fi": {
"pin": false,
@ -662,7 +662,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"fr": {
"pin": false,
@ -681,7 +681,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"fur": {
"pin": false,
@ -700,7 +700,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"fy-NL": {
"pin": false,
@ -719,7 +719,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ga-IE": {
"pin": false,
@ -738,7 +738,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"gd": {
"pin": false,
@ -757,7 +757,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"gl": {
"pin": false,
@ -776,7 +776,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"gn": {
"pin": false,
@ -795,7 +795,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"gu-IN": {
"pin": false,
@ -814,7 +814,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"he": {
"pin": false,
@ -833,7 +833,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"hi-IN": {
"pin": false,
@ -852,7 +852,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"hr": {
"pin": false,
@ -871,7 +871,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"hsb": {
"pin": false,
@ -890,7 +890,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"hu": {
"pin": false,
@ -909,7 +909,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"hy-AM": {
"pin": false,
@ -928,7 +928,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"hye": {
"pin": false,
@ -947,7 +947,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ia": {
"pin": false,
@ -966,7 +966,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"id": {
"pin": false,
@ -985,7 +985,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"is": {
"pin": false,
@ -1004,7 +1004,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"it": {
"pin": false,
@ -1023,7 +1023,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ja": {
"pin": false,
@ -1040,7 +1040,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ja-JP-mac": {
"pin": false,
@ -1048,7 +1048,7 @@
"macosx64",
"macosx64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ka": {
"pin": false,
@ -1067,7 +1067,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"kab": {
"pin": false,
@ -1086,7 +1086,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"kk": {
"pin": false,
@ -1105,7 +1105,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"km": {
"pin": false,
@ -1124,7 +1124,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"kn": {
"pin": false,
@ -1143,7 +1143,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ko": {
"pin": false,
@ -1162,7 +1162,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"lij": {
"pin": false,
@ -1181,7 +1181,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"lo": {
"pin": false,
@ -1200,7 +1200,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"lt": {
"pin": false,
@ -1219,7 +1219,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ltg": {
"pin": false,
@ -1238,7 +1238,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"lv": {
"pin": false,
@ -1257,7 +1257,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"meh": {
"pin": false,
@ -1276,7 +1276,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"mk": {
"pin": false,
@ -1295,7 +1295,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"mr": {
"pin": false,
@ -1314,7 +1314,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ms": {
"pin": false,
@ -1333,7 +1333,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"my": {
"pin": false,
@ -1352,7 +1352,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"nb-NO": {
"pin": false,
@ -1371,7 +1371,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ne-NP": {
"pin": false,
@ -1390,7 +1390,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"nl": {
"pin": false,
@ -1409,7 +1409,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"nn-NO": {
"pin": false,
@ -1428,7 +1428,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"oc": {
"pin": false,
@ -1447,7 +1447,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"pa-IN": {
"pin": false,
@ -1466,7 +1466,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"pl": {
"pin": false,
@ -1485,7 +1485,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"pt-BR": {
"pin": false,
@ -1504,7 +1504,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"pt-PT": {
"pin": false,
@ -1523,7 +1523,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"rm": {
"pin": false,
@ -1542,7 +1542,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ro": {
"pin": false,
@ -1561,7 +1561,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ru": {
"pin": false,
@ -1580,7 +1580,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"sat": {
"pin": false,
@ -1599,7 +1599,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"sc": {
"pin": false,
@ -1618,7 +1618,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"scn": {
"pin": false,
@ -1637,7 +1637,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"sco": {
"pin": false,
@ -1656,7 +1656,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"si": {
"pin": false,
@ -1675,7 +1675,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"sk": {
"pin": false,
@ -1694,7 +1694,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"skr": {
"pin": false,
@ -1713,7 +1713,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"sl": {
"pin": false,
@ -1732,7 +1732,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"son": {
"pin": false,
@ -1751,7 +1751,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"sq": {
"pin": false,
@ -1770,7 +1770,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"sr": {
"pin": false,
@ -1789,7 +1789,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"sv-SE": {
"pin": false,
@ -1808,7 +1808,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"szl": {
"pin": false,
@ -1827,7 +1827,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ta": {
"pin": false,
@ -1846,7 +1846,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"te": {
"pin": false,
@ -1865,7 +1865,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"tg": {
"pin": false,
@ -1884,7 +1884,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"th": {
"pin": false,
@ -1903,7 +1903,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"tl": {
"pin": false,
@ -1922,7 +1922,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"tr": {
"pin": false,
@ -1941,7 +1941,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"trs": {
"pin": false,
@ -1960,7 +1960,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"uk": {
"pin": false,
@ -1979,7 +1979,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"ur": {
"pin": false,
@ -1998,7 +1998,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"uz": {
"pin": false,
@ -2017,7 +2017,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"vi": {
"pin": false,
@ -2036,7 +2036,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"wo": {
"pin": false,
@ -2055,7 +2055,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"xh": {
"pin": false,
@ -2074,7 +2074,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"zh-CN": {
"pin": false,
@ -2093,7 +2093,7 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
},
"zh-TW": {
"pin": false,
@ -2112,6 +2112,6 @@
"win64-aarch64-devedition",
"win64-devedition"
],
"revision": "075b103699fb2a73e322f2e3698297b14624b3ed"
"revision": "c78c0710ab06c5911899748bf91d019673912d10"
}
}

View file

@ -71,14 +71,17 @@
outline: 0.01px solid var(--chrome-content-separator-color);
box-shadow: var(--content-area-shadow);
:root:not([inDOMFullscreen]) &[sidebar-shown] {
overflow: clip;
border-start-end-radius: var(--border-radius-medium);
/* stylelint-disable-next-line media-query-no-invalid */
@media (-moz-bool-pref: "sidebar.revamp.round-content-area") {
:root:not([inDOMFullscreen]) &[sidebar-shown] {
overflow: clip;
border-start-end-radius: var(--border-radius-medium);
/* stylelint-disable-next-line media-query-no-invalid */
@media (-moz-bool-pref: "sidebar.position_start") {
border-start-start-radius: var(--border-radius-medium);
border-start-end-radius: 0;
/* stylelint-disable-next-line media-query-no-invalid */
@media (-moz-bool-pref: "sidebar.position_start") {
border-start-start-radius: var(--border-radius-medium);
border-start-end-radius: 0;
}
}
}
}

View file

@ -3,5 +3,5 @@
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<svg xmlns="http://www.w3.org/2000/svg"
width="16" height="16" viewBox="0 0 16 16">
<rect width="16" height="16" rx="4" stroke="context-stroke" stroke-width="1" fill="context-fill"/>
<rect width="15" height="15" x="0.5" y="0.5" rx="4" stroke="context-stroke" stroke-width="1" fill="context-fill"/>
</svg>

Before

Width:  |  Height:  |  Size: 409 B

After

Width:  |  Height:  |  Size: 425 B

Before After
Before After

View file

@ -1550,7 +1550,7 @@ toolbar:not(#TabsToolbar) #firefox-view-button {
list-style-image: url("chrome://browser/skin/tabbrowser/tab-group-chicklet.svg");
-moz-context-properties: fill, stroke;
fill: light-dark(var(--tab-group-color), var(--tab-group-color-invert));
stroke: transparent;
stroke: light-dark(var(--tab-group-color), var(--tab-group-color-invert));
}
.menu-iconic.tab-group-icon-collapsed,

View file

@ -162,6 +162,13 @@ add_task(async function testWebExtensionsToolboxWebConsole() {
clickOnAddonWidget(ADDON_ID);
await onPopupMessage;
info("Assert the context of the evaluation context selector");
const contextLabels = getContextLabels(toolbox);
is(contextLabels.length, 3);
is(contextLabels[0], "Web Extension Fallback Document");
is(contextLabels[1], "/_generated_background_page.html");
is(contextLabels[2], "/popup.html");
info("Wait a bit to catch unexpected duplicates or mixed up messages");
await wait(1000);
@ -463,3 +470,12 @@ add_task(async function testWebExtensionTwoReloads() {
await removeTemporaryExtension(BACKGROUND_ADDON_NAME, document);
await removeTab(tab);
});
function getContextLabels(toolbox) {
// Note that the context menu is in the top level chrome document (toolbox.xhtml)
// instead of webconsole.xhtml.
const labels = toolbox.doc.querySelectorAll(
"#webconsole-console-evaluation-context-selector-menu-list li .label"
);
return Array.from(labels).map(item => item.textContent);
}

View file

@ -61,6 +61,15 @@ add_task(async function testOpenDebuggerReload() {
"isWebExtension flag in sourcesTree is true"
);
const descriptorTitle = devtoolsWindow.document.querySelector(
".qa-descriptor-title"
);
is(
descriptorTitle.textContent,
EXTENSION_NAME,
"The add-on name is displayed in the toolbox header"
);
info("Check whether the element displays correctly");
let sourceList = panelWin.document.querySelector(".sources-list");
ok(sourceList, "Source list element displays correctly");
@ -132,6 +141,24 @@ add_task(async function testAddAndRemoveBreakpoint() {
const toolbox = getToolbox(devtoolsWindow);
const dbg = createDebuggerContext(toolbox);
info("Assert the threads displayed in Source Tree as well as Threads pane");
const sourceTreeThreads = findAllElements(dbg, "sourceTreeThreads");
is(
sourceTreeThreads.length,
1,
"There is only one thread with source in the Source Tree"
);
is(
sourceTreeThreads[0].textContent,
"/_generated_background_page.html",
"That thread is the background page"
);
const threadLabels = findAllElements(dbg, "threadsPaneItems");
is(threadLabels.length, 2, "But there are two threads in the thread panel");
is(threadLabels[0].textContent, "Web Extension Fallback Document");
is(threadLabels[1].textContent, "/_generated_background_page.html");
info("Select the source and add a breakpoint");
// Note: the background script filename is dynamically generated id, so we
// simply get the first source from the list.

View file

@ -50,7 +50,11 @@ add_task(async function testWebExtensionsToolboxNoBackgroundPage() {
"Toolbox is debugging an addon"
);
const targetName = toolbox.target.name;
is(targetName, ADDON_NOBG_NAME, "Toolbox has the expected target");
is(
targetName,
"Web Extension Fallback Document",
"Toolbox has the expected target"
);
const inspector = await toolbox.selectTool("inspector");

View file

@ -39088,14 +39088,6 @@ Please specify the "importAttributesKeyword" generator option, whose value can b
extractFunctionSymbol(path, state, symbols);
}
if (libExports$2.isJSXElement(path)) {
symbols.hasJsx = true;
}
if (libExports$2.isGenericTypeAnnotation(path)) {
symbols.hasTypes = true;
}
if (libExports$2.isClassDeclaration(path)) {
symbols.classes.push(getClassDeclarationSymbol(path.node));
}
@ -39132,6 +39124,27 @@ Please specify the "importAttributesKeyword" generator option, whose value can b
}
function extractSymbols(sourceId) {
// This is used in the main thread by:
// * The `getFunctionSymbols` function which is used by the Outline, QuickOpen panels.
// * The `getClosestFunctionName` function used in the mapping of frame function names.
// * The `findOutOfScopeLocations` function use to determine in scope lines.
// functions: symbols.functions,
// The three following attributes are only used by `findBestMatchExpression` within the worker thread
// `memberExpressions`, `literals`, `identifiers`
//
// These three memberExpressions, literals and identifiers attributes are arrays containing objects whose attributes are:
// * name: string
// * location: object {start: number, end: number}
// * expression: string
// * computed: boolean (only for memberExpressions)
//
// `findBestMatchExpression` uses `location`, `computed` and `expression` (not name).
// `expression` isn't used from the worker thread implementation of `findBestMatchExpression`.
// The main thread only uses `expression` and `location`.
// This is used by the `getClassSymbols` function in the Outline panel
// `classes`
// This is only used by `findOutOfScopeLocations`:
// `comments`
const symbols = {
functions: [],
memberExpressions: [],
@ -39142,8 +39155,6 @@ Please specify the "importAttributesKeyword" generator option, whose value can b
identifiersKeys: new Set(),
classes: [],
literals: [],
hasJsx: false,
hasTypes: false,
importsReact: false,
};
@ -39431,38 +39442,10 @@ Please specify the "importAttributesKeyword" generator option, whose value can b
}
// This is only called from the main thread and we return a subset of attributes
// Note: This is now used just to trigger the parser
function getSymbols(sourceId) {
const symbols = getInternalSymbols(sourceId);
return {
// This is used in the main thread by:
// * The `getFunctionSymbols` function which is used by the Outline, QuickOpen panels.
// * The `getClosestFunctionName` function used in the mapping of frame function names.
// * The `findOutOfScopeLocations` function use to determine in scope lines.
// functions: symbols.functions,
// The three following attributes are only used by `findBestMatchExpression` within the worker thread
// `memberExpressions`, `literals`, `identifiers`
//
// These three memberExpressions, literals and identifiers attributes are arrays containing objects whose attributes are:
// * name: string
// * location: object {start: number, end: number}
// * expression: string
// * computed: boolean (only for memberExpressions)
//
// `findBestMatchExpression` uses `location`, `computed` and `expression` (not name).
// `expression` isn't used from the worker thread implementation of `findBestMatchExpression`.
// The main thread only uses `expression` and `location`.
// This is used by the `getClassSymbols` function in the Outline panel
// `classes`
// The two following are only used by the main thread for computing CodeMirror "mode"
hasJsx: symbols.hasJsx,
hasTypes: symbols.hasTypes,
// This is only used by `findOutOfScopeLocations`:
// `comments`
};
getInternalSymbols(sourceId);
return {};
}
function getMemberExpressionSymbol(path) {

View file

@ -390,9 +390,14 @@ export async function createPause(threadActorID, pausedThreadState) {
}
export function createThread(targetFront) {
const name = targetFront.isTopLevel
? L10N.getStr("mainThread")
: targetFront.name;
// When debugging a Web Extension, the top level target is always the fallback document.
// It isn't really a top level document as it won't be the parent of any other.
// So only print its name.
const name =
targetFront.isTopLevel &&
!targetFront.commands.descriptorFront.isWebExtension
? L10N.getStr("mainThread")
: targetFront.name;
return {
actor: targetFront.targetForm.threadActor,

View file

@ -24,7 +24,6 @@ import {
getSelectedSourceTextContent,
getSelectedBreakableLines,
getConditionalPanelLocation,
getSymbols,
getIsCurrentThreadPaused,
getSkipPausing,
getInlinePreview,
@ -113,7 +112,6 @@ class Editor extends PureComponent {
updateCursorPosition: PropTypes.func.isRequired,
jumpToMappedLocation: PropTypes.func.isRequired,
selectedLocation: PropTypes.object,
symbols: PropTypes.object,
startPanelSize: PropTypes.number.isRequired,
endPanelSize: PropTypes.number.isRequired,
searchInFileEnabled: PropTypes.bool.isRequired,
@ -140,6 +138,7 @@ class Editor extends PureComponent {
// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507
UNSAFE_componentWillReceiveProps(nextProps) {
let { editor } = this.state;
const prevEditor = editor;
if (!editor) {
// See Bug 1913061
@ -158,7 +157,7 @@ class Editor extends PureComponent {
if (shouldUpdateSize) {
editor.codeMirror.setSize();
}
this.setTextContent(nextProps, editor);
this.setTextContent(nextProps, editor, prevEditor);
endOperation();
if (this.props.selectedSource != nextProps.selectedSource) {
@ -168,16 +167,17 @@ class Editor extends PureComponent {
}
} else {
// For codemirror 6
this.setTextContent(nextProps, editor);
this.setTextContent(nextProps, editor, prevEditor);
}
}
async setTextContent(nextProps, editor) {
async setTextContent(nextProps, editor, prevEditor) {
const shouldUpdateText =
nextProps.selectedSource !== this.props.selectedSource ||
nextProps.selectedSourceTextContent?.value !==
this.props.selectedSourceTextContent?.value ||
nextProps.symbols !== this.props.symbols;
// If the selectedSource gets set before the editor get selected, make sure we update the text
prevEditor !== editor;
const shouldScroll =
nextProps.selectedLocation &&
@ -727,9 +727,8 @@ class Editor extends PureComponent {
!selectedSourceTextContent?.value &&
nextProps.selectedSourceTextContent?.value;
const locationChanged = selectedLocation !== nextProps.selectedLocation;
const symbolsChanged = nextProps.symbols != this.props.symbols;
return contentChanged || locationChanged || symbolsChanged;
return contentChanged || locationChanged;
}
scrollToLocation(nextProps, editor) {
@ -746,7 +745,7 @@ class Editor extends PureComponent {
}
async setText(props, editor) {
const { selectedSource, selectedSourceTextContent, symbols } = props;
const { selectedSource, selectedSourceTextContent } = props;
if (!editor) {
return;
@ -776,12 +775,7 @@ class Editor extends PureComponent {
}
if (!features.codemirrorNext) {
showSourceText(
editor,
selectedSource,
selectedSourceTextContent,
symbols
);
showSourceText(editor, selectedSource, selectedSourceTextContent);
} else {
await editor.setText(
selectedSourceTextContent.value.value,
@ -1038,7 +1032,6 @@ const mapStateToProps = state => {
isSourceOnSourceMapIgnoreList(state, selectedSource),
searchInFileEnabled: getActiveSearch(state) === "file",
conditionalPanelLocation: getConditionalPanelLocation(state),
symbols: getSymbols(state, selectedLocation),
isPaused: getIsCurrentThreadPaused(state),
isTraceSelected: getSelectedTraceIndex(state) != null,
skipPausing: getSkipPausing(state),

View file

@ -1,70 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`visible column breakpoints doesnt show breakpoints to the right in CM5 1`] = `
Array [
Object {
"breakpoint": Object {
"disabled": false,
"generatedLocation": Object {
"column": 1,
"line": 1,
"source": Object {
"displayURL": Object {
"fileExtension": "",
"filename": "url",
"group": "",
"path": "url",
"search": "",
},
"extensionName": null,
"id": "foo",
"isExtension": false,
"isOriginal": false,
"isPrettyPrinted": false,
"isWasm": false,
"longName": "url",
"shortName": "url",
"thread": "FakeThread",
"url": "url",
},
},
"id": "breakpoint",
"location": Object {
"column": 1,
"line": 1,
"source": Object {
"displayURL": Object {
"fileExtension": "",
"filename": "url",
"group": "",
"path": "url",
"search": "",
},
"extensionName": null,
"id": "foo",
"isExtension": false,
"isOriginal": false,
"isPrettyPrinted": false,
"isWasm": false,
"longName": "url",
"shortName": "url",
"thread": "FakeThread",
"url": "url",
},
},
"options": Object {},
"originalText": "text",
"text": "text",
},
"location": Object {
"column": 1,
"line": 1,
"sourceId": "foo",
},
},
]
`;
exports[`visible column breakpoints ignores single breakpoints 1`] = `
Array [
Object {
@ -211,6 +146,131 @@ Array [
]
`;
exports[`visible column breakpoints show all breakpoints including those to the right in CM6 1`] = `
Array [
Object {
"breakpoint": Object {
"disabled": false,
"generatedLocation": Object {
"column": 1,
"line": 1,
"source": Object {
"displayURL": Object {
"fileExtension": "",
"filename": "url",
"group": "",
"path": "url",
"search": "",
},
"extensionName": null,
"id": "foo",
"isExtension": false,
"isOriginal": false,
"isPrettyPrinted": false,
"isWasm": false,
"longName": "url",
"shortName": "url",
"thread": "FakeThread",
"url": "url",
},
},
"id": "breakpoint",
"location": Object {
"column": 1,
"line": 1,
"source": Object {
"displayURL": Object {
"fileExtension": "",
"filename": "url",
"group": "",
"path": "url",
"search": "",
},
"extensionName": null,
"id": "foo",
"isExtension": false,
"isOriginal": false,
"isPrettyPrinted": false,
"isWasm": false,
"longName": "url",
"shortName": "url",
"thread": "FakeThread",
"url": "url",
},
},
"options": Object {},
"originalText": "text",
"text": "text",
},
"location": Object {
"column": 1,
"line": 1,
"sourceId": "foo",
},
},
Object {
"breakpoint": Object {
"disabled": false,
"generatedLocation": Object {
"column": 15,
"line": 1,
"source": Object {
"displayURL": Object {
"fileExtension": "",
"filename": "url",
"group": "",
"path": "url",
"search": "",
},
"extensionName": null,
"id": "foo",
"isExtension": false,
"isOriginal": false,
"isPrettyPrinted": false,
"isWasm": false,
"longName": "url",
"shortName": "url",
"thread": "FakeThread",
"url": "url",
},
},
"id": "breakpoint",
"location": Object {
"column": 15,
"line": 1,
"source": Object {
"displayURL": Object {
"fileExtension": "",
"filename": "url",
"group": "",
"path": "url",
"search": "",
},
"extensionName": null,
"id": "foo",
"isExtension": false,
"isOriginal": false,
"isPrettyPrinted": false,
"isWasm": false,
"longName": "url",
"shortName": "url",
"thread": "FakeThread",
"url": "url",
},
},
"options": Object {},
"originalText": "text",
"text": "text",
},
"location": Object {
"column": 15,
"line": 1,
"sourceId": "foo",
},
},
]
`;
exports[`visible column breakpoints simple 1`] = `
Array [
Object {

View file

@ -91,7 +91,7 @@ const nonJSLanguageExtensionMap = new Map([
* Returns Code Mirror mode for source content type
*/
// eslint-disable-next-line complexity
export function getMode(source, sourceTextContent, symbols) {
export function getMode(source, sourceTextContent) {
const content = sourceTextContent.value;
// Disable modes for minified files with 1+ million characters (See Bug 1569829).
if (
@ -107,18 +107,15 @@ export function getMode(source, sourceTextContent, symbols) {
}
const extension = source.displayURL.fileExtension;
if (extension === "jsx" || (symbols && symbols.hasJsx)) {
if (symbols && symbols.hasTypes) {
return contentTypeModeMap.get("text/typescript-jsx");
}
if (extension === "jsx") {
return contentTypeModeMap.get("text/jsx");
}
if (symbols && symbols.hasTypes) {
if (symbols.hasJsx) {
return contentTypeModeMap.get("text/typescript-jsx");
}
if (extension === "tsx") {
return contentTypeModeMap.get("text/typescript-jsx");
}
if (extension === "ts") {
return contentTypeModeMap.get("text/typescript");
}
@ -159,8 +156,8 @@ export function getMode(source, sourceTextContent, symbols) {
return contentTypeModeMap.get("text/plain");
}
function setMode(editor, source, sourceTextContent, symbols) {
const mode = getMode(source, sourceTextContent, symbols);
function setMode(editor, source, sourceTextContent) {
const mode = getMode(source, sourceTextContent);
const currentMode = editor.codeMirror.getOption("mode");
if (!currentMode || currentMode.name != mode.name) {
editor.setMode(mode);
@ -171,17 +168,17 @@ function setMode(editor, source, sourceTextContent, symbols) {
* Handle getting the source document or creating a new
* document with the correct mode and text.
*/
export function showSourceText(editor, source, sourceTextContent, symbols) {
export function showSourceText(editor, source, sourceTextContent) {
if (hasDocument(source.id)) {
const doc = getDocument(source.id);
if (editor.codeMirror.doc === doc) {
setMode(editor, source, sourceTextContent, symbols);
setMode(editor, source, sourceTextContent);
return;
}
editor.replaceDocument(doc);
updateLineNumberFormat(editor, source.id);
setMode(editor, source, sourceTextContent, symbols);
setMode(editor, source, sourceTextContent);
return;
}
@ -191,7 +188,7 @@ export function showSourceText(editor, source, sourceTextContent, symbols) {
// We can set wasm text content directly from the constructor, so we pass an empty string
// here, and set the text after replacing the document.
content.type !== "wasm" ? content.value : "",
getMode(source, sourceTextContent, symbols)
getMode(source, sourceTextContent)
);
setDocument(source.id, doc);

View file

@ -9,18 +9,6 @@ import {
makeMockWasmSourceWithContent,
} from "../../test-mockup";
const defaultSymbolDeclarations = {
classes: [],
functions: [],
memberExpressions: [],
objectProperties: [],
identifiers: [],
comments: [],
literals: [],
hasJsx: false,
hasTypes: false,
};
describe("source-documents", () => {
describe("getMode", () => {
it("//", () => {
@ -79,21 +67,6 @@ describe("source-documents", () => {
expect(getMode(source, source.content)).toEqual({ name: "jsx" });
});
it("returns jsx if sourceMetaData says it's a react component", () => {
const source = makeMockSourceWithContent(
undefined,
undefined,
"",
"<h1></h1>"
);
expect(
getMode(source, source.content, {
...defaultSymbolDeclarations,
hasJsx: true,
})
).toEqual({ name: "jsx" });
});
it("returns jsx if the fileExtension is .jsx", () => {
const source = makeMockSourceWithContent(
"myComponent.jsx",

View file

@ -48,14 +48,6 @@ function extractSymbol(path, symbols, state) {
extractFunctionSymbol(path, state, symbols);
}
if (t.isJSXElement(path)) {
symbols.hasJsx = true;
}
if (t.isGenericTypeAnnotation(path)) {
symbols.hasTypes = true;
}
if (t.isClassDeclaration(path)) {
symbols.classes.push(getClassDeclarationSymbol(path.node));
}
@ -92,6 +84,27 @@ function extractSymbol(path, symbols, state) {
}
function extractSymbols(sourceId) {
// This is used in the main thread by:
// * The `getFunctionSymbols` function which is used by the Outline, QuickOpen panels.
// * The `getClosestFunctionName` function used in the mapping of frame function names.
// * The `findOutOfScopeLocations` function use to determine in scope lines.
// functions: symbols.functions,
// The three following attributes are only used by `findBestMatchExpression` within the worker thread
// `memberExpressions`, `literals`, `identifiers`
//
// These three memberExpressions, literals and identifiers attributes are arrays containing objects whose attributes are:
// * name: string
// * location: object {start: number, end: number}
// * expression: string
// * computed: boolean (only for memberExpressions)
//
// `findBestMatchExpression` uses `location`, `computed` and `expression` (not name).
// `expression` isn't used from the worker thread implementation of `findBestMatchExpression`.
// The main thread only uses `expression` and `location`.
// This is used by the `getClassSymbols` function in the Outline panel
// `classes`
// This is only used by `findOutOfScopeLocations`:
// `comments`
const symbols = {
functions: [],
memberExpressions: [],
@ -102,8 +115,6 @@ function extractSymbols(sourceId) {
identifiersKeys: new Set(),
classes: [],
literals: [],
hasJsx: false,
hasTypes: false,
importsReact: false,
};
@ -391,38 +402,10 @@ export function getClosestFunctionName(location) {
}
// This is only called from the main thread and we return a subset of attributes
// Note: This is now used just to trigger the parser
export function getSymbols(sourceId) {
const symbols = getInternalSymbols(sourceId);
return {
// This is used in the main thread by:
// * The `getFunctionSymbols` function which is used by the Outline, QuickOpen panels.
// * The `getClosestFunctionName` function used in the mapping of frame function names.
// * The `findOutOfScopeLocations` function use to determine in scope lines.
// functions: symbols.functions,
// The three following attributes are only used by `findBestMatchExpression` within the worker thread
// `memberExpressions`, `literals`, `identifiers`
//
// These three memberExpressions, literals and identifiers attributes are arrays containing objects whose attributes are:
// * name: string
// * location: object {start: number, end: number}
// * expression: string
// * computed: boolean (only for memberExpressions)
//
// `findBestMatchExpression` uses `location`, `computed` and `expression` (not name).
// `expression` isn't used from the worker thread implementation of `findBestMatchExpression`.
// The main thread only uses `expression` and `location`.
// This is used by the `getClassSymbols` function in the Outline panel
// `classes`
// The two following are only used by the main thread for computing CodeMirror "mode"
hasJsx: symbols.hasJsx,
hasTypes: symbols.hasTypes,
// This is only used by `findOutOfScopeLocations`:
// `comments`
};
getInternalSymbols(sourceId);
return {};
}
function getMemberExpressionSymbol(path) {

View file

@ -1,127 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Parser.getSymbols allSymbols 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols call expression 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols call sites 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols class 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols component 1`] = `
"hasJsx: true
hasTypes: false"
`;
exports[`Parser.getSymbols destruct 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols es6 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols expression 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols finds symbols in an html file 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols flow 1`] = `
"hasJsx: false
hasTypes: true"
`;
exports[`Parser.getSymbols func 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols function names 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols jsx 1`] = `
"hasJsx: true
hasTypes: false"
`;
exports[`Parser.getSymbols math 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols object expressions 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols optional chaining 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols private fields 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols proto 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols react component 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols regexp 1`] = `
"hasJsx: false
hasTypes: false"
`;
exports[`Parser.getSymbols var 1`] = `
"hasJsx: false
hasTypes: false"
`;

View file

@ -1,51 +0,0 @@
/* eslint max-nested-callbacks: ["error", 4]*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
import { formatSymbols } from "../utils/formatSymbols";
import { populateSource, populateOriginalSource } from "./helpers";
import cases from "jest-in-case";
cases(
"Parser.getSymbols",
({ file, original, type }) => {
const source = original
? populateOriginalSource(file, type)
: populateSource(file, type);
expect(formatSymbols(source.id)).toMatchSnapshot();
},
[
{ name: "es6", file: "es6", original: true },
{ name: "func", file: "func", original: true },
{ name: "function names", file: "functionNames", original: true },
{ name: "math", file: "math" },
{ name: "proto", file: "proto" },
{ name: "class", file: "class", original: true },
{ name: "var", file: "var" },
{ name: "expression", file: "expression" },
{ name: "allSymbols", file: "allSymbols" },
{ name: "call sites", file: "call-sites" },
{ name: "call expression", file: "callExpressions" },
{ name: "object expressions", file: "object-expressions" },
{ name: "optional chaining", file: "optional-chaining" },
{ name: "private fields", file: "private-fields" },
{
name: "finds symbols in an html file",
file: "parseScriptTags",
type: "html",
},
{ name: "component", file: "component", original: true },
{
name: "react component",
file: "frameworks/reactComponent",
original: true,
},
{ name: "flow", file: "flow", original: true },
{ name: "jsx", file: "jsx", original: true },
{ name: "destruct", file: "destructuring" },
{ name: "regexp", file: "regexp" },
]
);

View file

@ -1,56 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
import { getSymbols } from "../getSymbols";
function formatLocation(loc) {
if (!loc) {
return "";
}
const { start, end } = loc;
const startLoc = `(${start.line}, ${start.column})`;
const endLoc = `(${end.line}, ${end.column})`;
return `[${startLoc}, ${endLoc}]`;
}
function summarize(symbol) {
if (typeof symbol == "boolean") {
return symbol ? "true" : "false";
}
const loc = formatLocation(symbol.location);
const params = symbol.parameterNames
? `(${symbol.parameterNames.join(", ")})`
: "";
const expression = symbol.expression || "";
const klass = symbol.klass || "";
const name = symbol.name == undefined ? "" : symbol.name;
const names = symbol.specifiers ? symbol.specifiers.join(", ") : "";
const values = symbol.values ? symbol.values.join(", ") : "";
const index = symbol.index ? symbol.index : "";
return `${loc} ${expression} ${name}${params} ${klass} ${names} ${values} ${index}`.trim(); // eslint-disable-line max-len
}
const bools = ["hasJsx", "hasTypes"];
function formatBool(name, symbols) {
return `${name}: ${symbols[name] ? "true" : "false"}`;
}
function formatKey(name, symbols) {
if (bools.includes(name)) {
return formatBool(name, symbols);
}
return `${name}:\n${symbols[name].map(summarize).join("\n")}`;
}
export function formatSymbols(sourceId) {
const symbols = getSymbols(sourceId);
return Object.keys(symbols)
.map(name => formatKey(name, symbols))
.join("\n\n");
}

View file

@ -193,11 +193,17 @@ add_task(async function () {
});
is(keyTrace.textContent, "DOM | global.keypress");
is(
tracerTree.querySelectorAll(".trace-line").length,
8,
"The key event adds two elements in the tree. The DOM Event and its top frame"
);
info("Wait for the key listener function to be displayed");
await waitFor(() => {
// Scroll to bottom to ensure rendering the last elements (otherwise they are not because of VirtualizedTree)
tracerTree.scrollTop = tracerTree.scrollHeight;
const elements = tracerTree.querySelectorAll(".trace-line");
// Wait for the expected element to be rendered
if (elements[elements.length - 1].textContent.includes("keyListener")) {
return true;
}
return false;
});
info("Trigger a DOM Mutation");
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async function () {

View file

@ -19,7 +19,7 @@ requestLongerTimeout(4);
*/
add_task(async function () {
const ToolboxTask = await initBrowserToolboxTask();
await ToolboxTask.importFunctions({ clickMeatballItem });
await ToolboxTask.importFunctions({ waitUntil, clickMeatballItem });
is(getPseudoLocale(), "", "Starts out as empty");
@ -61,28 +61,25 @@ function getPseudoLocale() {
*
* @param {"accented" | "bidi"} type
*/
function clickMeatballItem(type) {
return new Promise(resolve => {
/* global gToolbox */
async function clickMeatballItem(type) {
/* global gToolbox */
dump(`Opening the meatball menu in the browser toolbox.\n`);
gToolbox.doc.getElementById("toolbox-meatball-menu-button").click();
gToolbox.doc.addEventListener(
"popupshown",
async () => {
const menuItem = gToolbox.doc.getElementById(
"toolbox-meatball-menu-pseudo-locale-" + type
);
dump(`Clicking the meatball menu item: "${type}".\n`);
menuItem.click();
// Request the pseudo-locale so that we know the preference actor is fully
// done setting the debuggee browser.
await gToolbox.getPseudoLocale();
resolve();
},
{ once: true }
);
const onPopupShown = new Promise(resolve => {
gToolbox.doc.addEventListener("popupshown", resolve, { once: true });
});
dump(`Opening the meatball menu in the browser toolbox.\n`);
gToolbox.doc.getElementById("toolbox-meatball-menu-button").click();
await onPopupShown;
const menuItem = gToolbox.doc.getElementById(
"toolbox-meatball-menu-pseudo-locale-" + type
);
dump(`Clicking the meatball menu item: "${type}".\n`);
const checked = menuItem.getAttribute("aria-checked");
menuItem.click();
dump(
"Wait for the new setting to be applied by waiting for the UI to be updated after the action is done\n"
);
await waitUntil(() => menuItem.getAttribute("aria-checked") != checked);
}

View file

@ -37,6 +37,7 @@ class DebugTargetInfo extends PureComponent {
}).isRequired,
descriptorType: PropTypes.oneOf(Object.values(DESCRIPTOR_TYPES))
.isRequired,
descriptorName: PropTypes.string.isRequired,
}).isRequired,
L10N: PropTypes.object.isRequired,
toolbox: PropTypes.object.isRequired,
@ -234,18 +235,21 @@ class DebugTargetInfo extends PureComponent {
);
}
renderTargetTitle() {
const title = this.props.toolbox.target.name;
renderDescriptorName() {
const name = this.props.debugTargetData.descriptorName;
const { image, l10nId } = this.getAssetsForDebugDescriptorType();
return dom.span(
{
className: "iconized-label debug-target-title",
className: "iconized-label debug-descriptor-title",
},
dom.img({ src: image, alt: this.props.L10N.getStr(l10nId) }),
title
? dom.b({ className: "devtools-ellipsis-text qa-target-title" }, title)
name
? dom.b(
{ className: "devtools-ellipsis-text qa-descriptor-title" },
name
)
: null
);
}
@ -401,7 +405,7 @@ class DebugTargetInfo extends PureComponent {
},
this.shallRenderConnection() ? this.renderConnection() : null,
this.renderRuntime(),
this.renderTargetTitle(),
this.renderDescriptorName(),
this.renderNavigation(),
this.renderTargetURI(),
...this.renderAlwaysOnTopButton()

View file

@ -32,16 +32,16 @@ exports[`DebugTargetInfo component Connection info renders the expected snapshot
</span>
</span>
<span
className="iconized-label debug-target-title"
className="iconized-label debug-descriptor-title"
>
<img
alt="toolbox.debugTargetInfo.targetType.tab"
src="chrome://devtools/skin/images/globe.svg"
/>
<b
className="devtools-ellipsis-text qa-target-title"
className="devtools-ellipsis-text qa-descriptor-title"
>
Test Tab Name
Usb debugging context
</b>
</span>
<div
@ -128,16 +128,16 @@ exports[`DebugTargetInfo component Target icon renders the expected snapshot for
</span>
</span>
<span
className="iconized-label debug-target-title"
className="iconized-label debug-descriptor-title"
>
<img
alt="toolbox.debugTargetInfo.targetType.process"
src="chrome://devtools/skin/images/settings.svg"
/>
<b
className="devtools-ellipsis-text qa-target-title"
className="devtools-ellipsis-text qa-descriptor-title"
>
Test Tab Name
Usb debugging context
</b>
</span>
<span
@ -184,16 +184,16 @@ exports[`DebugTargetInfo component Target icon renders the expected snapshot for
</span>
</span>
<span
className="iconized-label debug-target-title"
className="iconized-label debug-descriptor-title"
>
<img
alt="toolbox.debugTargetInfo.targetType.tab"
src="chrome://devtools/skin/images/globe.svg"
/>
<b
className="devtools-ellipsis-text qa-target-title"
className="devtools-ellipsis-text qa-descriptor-title"
>
Test Tab Name
Usb debugging context
</b>
</span>
<div
@ -280,16 +280,16 @@ exports[`DebugTargetInfo component Target icon renders the expected snapshot for
</span>
</span>
<span
className="iconized-label debug-target-title"
className="iconized-label debug-descriptor-title"
>
<img
alt="toolbox.debugTargetInfo.targetType.worker"
src="chrome://devtools/skin/images/debugging-workers.svg"
/>
<b
className="devtools-ellipsis-text qa-target-title"
className="devtools-ellipsis-text qa-descriptor-title"
>
Test Tab Name
Usb debugging context
</b>
</span>
<span
@ -336,16 +336,16 @@ exports[`DebugTargetInfo component Target icon renders the expected snapshot for
</span>
</span>
<span
className="iconized-label debug-target-title"
className="iconized-label debug-descriptor-title"
>
<img
alt="toolbox.debugTargetInfo.targetType.extension"
src="chrome://devtools/skin/images/debugging-addons.svg"
/>
<b
className="devtools-ellipsis-text qa-target-title"
className="devtools-ellipsis-text qa-descriptor-title"
>
Test Tab Name
Usb debugging context
</b>
</span>
<div
@ -373,16 +373,16 @@ exports[`DebugTargetInfo component Target icon renders the expected snapshot for
className="debug-target-info qa-debug-target-info"
>
<span
className="iconized-label debug-target-title"
className="iconized-label debug-descriptor-title"
>
<img
alt="toolbox.debugTargetInfo.targetType.extension"
src="chrome://devtools/skin/images/debugging-addons.svg"
/>
<b
className="devtools-ellipsis-text qa-target-title"
className="devtools-ellipsis-text qa-descriptor-title"
>
Test Tab Name
This firefox first tab
</b>
</span>
<div
@ -429,16 +429,16 @@ exports[`DebugTargetInfo component Target title renders the expected snapshot fo
/>
</span>
<span
className="iconized-label debug-target-title"
className="iconized-label debug-descriptor-title"
>
<img
alt="toolbox.debugTargetInfo.targetType.tab"
src="chrome://devtools/skin/images/globe.svg"
/>
<b
className="devtools-ellipsis-text qa-target-title"
className="devtools-ellipsis-text qa-descriptor-title"
>
Test Tab Name
This firefox first tab
</b>
</span>
<div
@ -514,7 +514,7 @@ exports[`DebugTargetInfo component Target title renders the expected snapshot fo
/>
</span>
<span
className="iconized-label debug-target-title"
className="iconized-label debug-descriptor-title"
>
<img
alt="toolbox.debugTargetInfo.targetType.tab"

View file

@ -86,6 +86,7 @@ const USB_TARGET_INFO = {
connectionType: CONNECTION_TYPES.USB,
runtimeInfo: USB_DEVICE_DESCRIPTION,
descriptorType: DESCRIPTOR_TYPES.TAB,
descriptorName: "Usb debugging context",
},
toolbox: TEST_TOOLBOX,
L10N: stubL10N,
@ -96,6 +97,7 @@ const THIS_FIREFOX_TARGET_INFO = {
connectionType: CONNECTION_TYPES.THIS_FIREFOX,
runtimeInfo: THIS_FIREFOX_DEVICE_DESCRIPTION,
descriptorType: DESCRIPTOR_TYPES.TAB,
descriptorName: "This firefox first tab",
},
toolbox: TEST_TOOLBOX,
L10N: stubL10N,
@ -106,6 +108,7 @@ const THIS_FIREFOX_NO_NAME_TARGET_INFO = {
connectionType: CONNECTION_TYPES.THIS_FIREFOX,
runtimeInfo: THIS_FIREFOX_DEVICE_DESCRIPTION,
descriptorType: DESCRIPTOR_TYPES.TAB,
/* Avoid passing a name via 'descriptorName' attribute */
},
toolbox: TEST_TOOLBOX_NO_NAME,
L10N: stubL10N,
@ -140,9 +143,9 @@ describe("DebugTargetInfo component", () => {
const component = renderer.create(
DebugTargetInfo(THIS_FIREFOX_TARGET_INFO)
);
expect(findByClassName(component.root, "qa-target-title").length).toEqual(
1
);
expect(
findByClassName(component.root, "qa-descriptor-title").length
).toEqual(1);
});
it("renders the expected snapshot for This Firefox target", () => {
@ -156,9 +159,9 @@ describe("DebugTargetInfo component", () => {
const component = renderer.create(
DebugTargetInfo(THIS_FIREFOX_NO_NAME_TARGET_INFO)
);
expect(findByClassName(component.root, "qa-target-title").length).toEqual(
0
);
expect(
findByClassName(component.root, "qa-descriptor-title").length
).toEqual(0);
});
it("renders the expected snapshot for a Toolbox with an unnamed target", () => {

View file

@ -1416,6 +1416,7 @@ Toolbox.prototype = {
connectionType,
runtimeInfo,
descriptorType: this._descriptorFront.descriptorType,
descriptorName: this._descriptorFront.name,
};
},
@ -3338,16 +3339,23 @@ Toolbox.prototype = {
selectedTargetFront.name &&
selectedTargetFront.name != selectedTargetFront.url
) {
// Only display the target `URL` when it isn't already the target `name`
// For Web Extension, we remove the `moz-extension://${addon-uid}` from the URL
const url = this._descriptorFront.isWebExtensionDescriptor
? this.getExtensionPathName(selectedTargetFront.url)
: getUnicodeUrl(selectedTargetFront.url);
title = L10N.getFormatStr(
"toolbox.titleTemplate2",
selectedTargetFront.name,
url
);
// For Web Extensions, the target name may only be the pathname of the target URL.
// In such case, only print the absolute target url.
if (
this._descriptorFront.isWebExtensionDescriptor &&
selectedTargetFront.url.includes(selectedTargetFront.name)
) {
title = L10N.getFormatStr(
"toolbox.titleTemplate1",
getUnicodeUrl(selectedTargetFront.url)
);
} else {
title = L10N.getFormatStr(
"toolbox.titleTemplate2",
selectedTargetFront.name,
getUnicodeUrl(selectedTargetFront.url)
);
}
} else {
title = L10N.getFormatStr(
"toolbox.titleTemplate1",

View file

@ -277,7 +277,23 @@ function TargetMixin(parentClass) {
return this.typeName === "windowGlobalTarget";
}
/**
* Return the name to be displayed in the debugger and console context selector.
*/
get name() {
// When debugging Web Extensions, all documents have moz-extension://${uuid}/... URL
// When the developer don't set a custom title, fallback on displaying the pathname
// to avoid displaying long URL prefix with the addon internal UUID.
if (this.commands.descriptorFront.isWebExtensionDescriptor) {
if (this._title) {
return this._title;
}
return URL.canParse(this._url)
? new URL(this._url).pathname
: // If document URL can't be parsed, fallback to the raw URL.
this._url;
}
if (this.isWebExtension || this.isContentProcess) {
return this.targetForm.name;
}

View file

@ -33,15 +33,6 @@ class PauseResumeButton extends PureComponent {
this.onKeyDown = this.onKeyDown.bind(this);
this.pauseResumeButtonRef = createRef();
this.state = {
isRunning: false,
};
}
// FIXME: https://bugzilla.mozilla.org/show_bug.cgi?id=1774507
UNSAFE_componentWillMount() {
this.updateState(this.props);
}
componentDidMount() {
@ -49,10 +40,6 @@ class PauseResumeButton extends PureComponent {
targetEl.addEventListener("keydown", this.onKeyDown);
}
componentDidUpdate() {
this.updateState();
}
componentWillUnount() {
const targetEl = this.getKeyEventTarget();
targetEl.removeEventListener("keydown", this.onKeyDown);
@ -64,8 +51,8 @@ class PauseResumeButton extends PureComponent {
onToggleAnimationsPlayState(event) {
event.stopPropagation();
const { setAnimationsPlayState } = this.props;
const { isRunning } = this.state;
const { setAnimationsPlayState, animations } = this.props;
const isRunning = hasRunningAnimation(animations);
setAnimationsPlayState(!isRunning);
}
@ -80,14 +67,8 @@ class PauseResumeButton extends PureComponent {
}
}
updateState() {
const { animations } = this.props;
const isRunning = hasRunningAnimation(animations);
this.setState({ isRunning });
}
render() {
const { isRunning } = this.state;
const isRunning = hasRunningAnimation(this.props.animations);
return dom.button({
className:

View file

@ -18,7 +18,6 @@ support-files = [
["browser_fontinspector.js"]
["browser_fontinspector_all-fonts.js"]
fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and/or labeled
["browser_fontinspector_copy-URL.js"]
fail-if = ["a11y_checks"] # Bug 1849028 clicked element may not be focusable and/or labeled

View file

@ -125,7 +125,7 @@
/*
* XXX: This was added to match the padding 8px used by the reload button.
* This padding makes the debug target component taller and also creates
* spacing with the debug-target-title separator.
* spacing with the debug-descriptor-title separator.
* See Bug 1641920 for improving the CSS of the DebugTargetInfo component.
*/
.debug-target-info .debug-target-url-readonly {

View file

@ -110,9 +110,13 @@ class EvaluationContextSelector extends Component {
renderMenuItem(target) {
const { selectTarget, selectedTarget } = this.props;
const label = target.isTopLevel
? l10n.getStr("webconsole.input.selector.top")
: target.name;
// When debugging a Web Extension, the top level target is always the fallback document.
// It isn't really a top level document as it won't be the parent of any other.
// So only print its name.
const label =
target.isTopLevel && !target.commands.descriptorFront.isWebExtension
? l10n.getStr("webconsole.input.selector.top")
: target.name;
return MenuItem({
key: `webconsole-evaluation-selector-item-${target.actorID}`,
@ -227,7 +231,14 @@ class EvaluationContextSelector extends Component {
getLabel() {
const { selectedTarget } = this.props;
if (!selectedTarget || selectedTarget.isTopLevel) {
// When debugging a Web Extension, the top level target is always the fallback document.
// It isn't really a top level document as it won't be the parent of any other.
// So only print its name.
if (
!selectedTarget ||
(selectedTarget.isTopLevel &&
!selectedTarget.commands.descriptorFront.isWebExtension)
) {
return l10n.getStr("webconsole.input.selector.top");
}

View file

@ -33,7 +33,7 @@ For quick reference, here are some of the main code style rules:
* getters / setters require { },
* only import specific, explicitly-declared symbols into your namespace:
* `const { foo, bar } = require("foo/bar");`,
* `const { foo, bar } = ChromeUtils.import("...");`,
* `const { foo, bar } = ChromeUtils.importESModule("...");`,
* use Maps, Sets, WeakMaps when possible,
* use [template strings](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) whenever possible to avoid concatenation, allow multi-line strings, and interpolation.

View file

@ -36,11 +36,12 @@ Example:
* `loader.lazyRequireGetter(this, "layout", "devtools/server/actors/layout")`
* `require("devtools/server/actors/layout")`
### `ChromeUtils.import()`
### `ChromeUtils.importESModule()`
Some older DevTools JS modules use the Gecko JavaScript code module format with the file extension `.jsm`. We are trying to move away from this format, so it's unlikely you would add a new one, but you might need to import an existing one in your code.
Some DevTools modules use a variant of the standard ECMAScript module, with
the file extension `.sys.mjs`.
These modules are loaded using `ChromeUtils.import()`. To `import()` a file, you provide a `resource://` URL, which is exactly the source tree path.
These modules are loaded using `ChromeUtils.importESModule()`. To `importESModule()` a file, you provide a `resource://` URL, which is exactly the source tree path.
In more detail:
@ -56,10 +57,10 @@ Example:
Example:
* File: `/toolkit/mozapps/extensions/AddonManager.jsm`
* File: `/toolkit/mozapps/extensions/AddonManager.sys.mjs`
* Usage (prefer lazy in most cases):
* `const lazy = {}; ChromeUtils.defineModuleGetter(lazy, "AddonManager", "resource://gre/modules/AddonManager.jsm")`
* `const { AddonManager } = ChromeUtils.import("resource://gre/modules/AddonManager.jsm")`
* `const lazy = {}; ChromeUtils.defineESModuleGetter(lazy, "AddonManager", "resource://gre/modules/AddonManager.sys.mjs")`
* `const { AddonManager } = ChromeUtils.importESModule("resource://gre/modules/AddonManager.sys.mjs")`
## Chrome Content

View file

@ -610,14 +610,8 @@ class WindowGlobalTargetActor extends BaseTargetActor {
/**
* Getter for the window global's title.
* For Web Extension it will ignore the document title and refer to the addon one.
*/
get title() {
if (this.sessionContext.type == "webextension") {
const policy = WebExtensionPolicy.getByID(this.sessionContext.addonId);
// Note that the policy may be null if we query the title while the add-on is reloading
return policy?.name;
}
return this.contentDocument.title;
}

View file

@ -4,7 +4,7 @@
export const Census = {};
function dumpn(msg) {
dump("DBG-TEST: Census.jsm: " + msg + "\n");
dump("DBG-TEST: Census.sys.mjs: " + msg + "\n");
}
// Census.walkCensus(subject, name, walker)

View file

@ -32,7 +32,7 @@ var gNextLoaderID = 0;
* If true, the modules will be forced to be loaded in a distinct
* compartment. It is typically used to load the modules in a distinct
* system compartment, different from the main one, which is shared by
* all JSMs, XPCOMs and modules loaded with this flag set to true.
* all ESMs, XPCOMs and modules loaded with this flag set to true.
* We use this in order to debug modules loaded in this shared system
* compartment. The debugger actor has to be running in a distinct
* compartment than the context it is debugging.
@ -166,7 +166,7 @@ export function DevToolsLoader({
);
// Define the loader id for these two usecases:
// * access via the JSM (this.id)
// * access via the ESM (this.id)
// let { loader } = ChromeUtils.importESModule("resource://devtools/shared/loader/Loader.sys.mjs");
// loader.id
this.id = gNextLoaderID++;
@ -176,7 +176,7 @@ export function DevToolsLoader({
globals.loader.invisibleToDebugger = invisibleToDebugger;
// Expose lazy helpers on `loader`
// ie. when you use it like that from a JSM:
// ie. when you use it like that from a ESM:
// let { loader } = ChromeUtils.importESModule("resource://devtools/shared/loader/Loader.sys.mjs");
// loader.lazyGetter(...);
this.lazyGetter = globals.loader.lazyGetter;

View file

@ -2,9 +2,6 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// This module does import many attributes from the global object
/* eslint-disable mozilla/reject-global-this */
// A CommonJS module loader that is designed to run inside a worker debugger.
// We can't simply use the SDK module loader, because it relies heavily on
// Components, which isn't available in workers.
@ -368,7 +365,7 @@ var {
loadSubScript,
setImmediate,
xpcInspector,
} = function () {
} = (function () {
// Main thread
if (typeof Components === "object") {
const principal = Components.Constructor(
@ -477,7 +474,7 @@ addDebuggerToGlobal(globalThis);
setImmediate: globalThis.setImmediate,
xpcInspector,
};
}.call(this);
})();
/* eslint-enable no-shadow */
// Create the default instance of the worker loader, using the APIs we defined

View file

@ -3,4 +3,5 @@
- file, You can obtain one at https://mozilla.org/MPL/2.0/. -->
<!doctype html>
<meta charset="utf-8" />
<title>Web Extension Fallback Document</title>
<h1>Your addon does not have any document opened yet.</h1>

View file

@ -1041,9 +1041,12 @@ DevToolsStartup.prototype = {
if (pauseOnStartup) {
// Spin the event loop until the debugger connects.
const tm = Cc["@mozilla.org/thread-manager;1"].getService();
tm.spinEventLoopUntil("DevToolsStartup.jsm:handleDebuggerFlag", () => {
return devtoolsThreadResumed;
});
tm.spinEventLoopUntil(
"DevToolsStartup.sys.mjs:handleDebuggerFlag",
() => {
return devtoolsThreadResumed;
}
);
}
if (cmdLine.state == Ci.nsICommandLine.STATE_REMOTE_AUTO) {

View file

@ -1131,7 +1131,8 @@ nsresult ChromeTooltipListener::MouseMove(Event* aMouseEvent) {
// within the timer callback. On win32, we'll get a MouseMove event even when
// a popup goes away -- even when the mouse doesn't change position! To get
// around this, we make sure the mouse has really moved before proceeding.
CSSIntPoint newMouseClientPoint = mouseEvent->ClientPoint();
const CSSIntPoint newMouseClientPoint =
RoundedToInt(mouseEvent->ClientPoint());
if (mMouseClientPoint == newMouseClientPoint) {
return NS_OK;
}

View file

@ -25,6 +25,8 @@
#include "mozilla/dom/BindingUtils.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/ScriptSettings.h"
#include "mozilla/dom/TrustedTypeUtils.h"
#include "mozilla/dom/TrustedTypesConstants.h"
using namespace mozilla;
using namespace mozilla::dom;
@ -53,9 +55,8 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMParser, mOwner)
NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMParser)
NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMParser)
already_AddRefed<Document> DOMParser::ParseFromString(const nsAString& aStr,
SupportedType aType,
ErrorResult& aRv) {
already_AddRefed<Document> DOMParser::ParseFromStringInternal(
const nsAString& aStr, SupportedType aType, ErrorResult& aRv) {
if (aType == SupportedType::Text_html) {
nsCOMPtr<Document> document = SetUpDocument(DocumentFlavorHTML, aRv);
if (NS_WARN_IF(aRv.Failed())) {
@ -99,6 +100,24 @@ already_AddRefed<Document> DOMParser::ParseFromString(const nsAString& aStr,
return ParseFromStream(stream, u"UTF-8"_ns, utf8str.Length(), aType, aRv);
}
already_AddRefed<Document> DOMParser::ParseFromString(
const TrustedHTMLOrString& aStr, SupportedType aType, ErrorResult& aRv) {
constexpr nsLiteralString sink = u"DOMParser parseFromString"_ns;
MOZ_ASSERT(mOwner);
nsCOMPtr<nsIGlobalObject> pinnedOwner = mOwner;
Maybe<nsAutoString> compliantStringHolder;
const nsAString* compliantString =
TrustedTypeUtils::GetTrustedTypesCompliantString(
aStr, sink, kTrustedTypesOnlySinkGroup, *pinnedOwner,
compliantStringHolder, aRv);
if (aRv.Failed()) {
return nullptr;
}
return ParseFromStringInternal(*compliantString, aType, aRv);
}
already_AddRefed<Document> DOMParser::ParseFromSafeString(const nsAString& aStr,
SupportedType aType,
ErrorResult& aRv) {
@ -111,7 +130,7 @@ already_AddRefed<Document> DOMParser::ParseFromSafeString(const nsAString& aStr,
mPrincipal = mOwner->PrincipalOrNull();
}
RefPtr<Document> ret = ParseFromString(aStr, aType, aRv);
RefPtr<Document> ret = ParseFromStringInternal(aStr, aType, aRv);
mPrincipal = docPrincipal;
return ret.forget();
}

View file

@ -21,6 +21,8 @@ class ErrorResult;
namespace dom {
class TrustedHTMLOrString;
class DOMParser final : public nsISupports, public nsWrapperCache {
typedef mozilla::dom::GlobalObject GlobalObject;
@ -34,9 +36,12 @@ class DOMParser final : public nsISupports, public nsWrapperCache {
static already_AddRefed<DOMParser> Constructor(const GlobalObject& aOwner,
mozilla::ErrorResult& rv);
already_AddRefed<Document> ParseFromString(const nsAString& aStr,
SupportedType aType,
ErrorResult& aRv);
already_AddRefed<Document> ParseFromStringInternal(const nsAString& aStr,
SupportedType aType,
ErrorResult& aRv);
MOZ_CAN_RUN_SCRIPT already_AddRefed<Document> ParseFromString(
const TrustedHTMLOrString& aStr, SupportedType aType, ErrorResult& aRv);
// ChromeOnly API
already_AddRefed<Document> ParseFromSafeString(const nsAString& aStr,

View file

@ -28,7 +28,7 @@ nsTArray<RefPtr<nsRange>> TextDirectiveFinder::FindTextDirectivesInDocument() {
: nsCString();
TEXT_FRAGMENT_LOG("Trying to find text directives in document '%s'.",
uri.Data());
mDocument.FlushPendingNotifications(FlushType::Frames);
mDocument.FlushPendingNotifications(FlushType::Layout);
// https://wicg.github.io/scroll-to-text-fragment/#invoke-text-directives
// To invoke text directives, given as input a list of text directives text
// directives and a Document document, run these steps:

View file

@ -7,6 +7,7 @@
#include "nsComputedDOMStyle.h"
#include "nsDOMAttributeMap.h"
#include "nsFind.h"
#include "nsFrameSelection.h"
#include "nsGkAtoms.h"
#include "nsIFrame.h"
#include "nsINode.h"
@ -18,6 +19,7 @@
#include "fragmentdirectives_ffi_generated.h"
#include "Text.h"
#include "mozilla/intl/WordBreaker.h"
#include "mozilla/SelectionMovementUtils.h"
namespace mozilla::dom {
LazyLogModule sFragmentDirectiveLog("FragmentDirective");
@ -67,73 +69,19 @@ LazyLogModule sFragmentDirectiveLog("FragmentDirective");
/* static */ RangeBoundary TextDirectiveUtil::MoveRangeBoundaryOneWord(
const RangeBoundary& aRangeBoundary, TextScanDirection aDirection) {
MOZ_ASSERT(aRangeBoundary.IsSetAndValid());
RefPtr<nsINode> curNode = aRangeBoundary.Container();
uint32_t offset = *aRangeBoundary.Offset(
RangeBoundary::OffsetFilter::kValidOrInvalidOffsets);
const int offsetIncrement = int(aDirection);
// Get the text node of the start of the range and the offset.
// This is the current position of the start of the range.
nsAutoString textContent;
if (NodeIsVisibleTextNode(*curNode)) {
const Text* textNode = Text::FromNode(curNode);
// Assuming that the current position might not be at a word boundary,
// advance to the word boundary at word begin/end.
if (!IsWhitespaceAtPosition(textNode, offset)) {
textNode->GetData(textContent);
const intl::WordRange wordRange =
intl::WordBreaker::FindWord(textContent, offset);
if (aDirection == TextScanDirection::Right &&
offset != wordRange.mBegin) {
offset = wordRange.mEnd;
} else if (aDirection == TextScanDirection::Left &&
offset != wordRange.mEnd) {
// The additional -1 is necessary to move to offset to *before* the
// start of the word.
offset = wordRange.mBegin - 1;
}
}
}
// Now, skip any whitespace, so that `offset` points to the word boundary of
// the next word (which is the one this algorithm actually aims to move over).
while (curNode) {
if (!NodeIsVisibleTextNode(*curNode) || NodeIsSearchInvisible(*curNode) ||
offset >= curNode->Length()) {
curNode = aDirection == TextScanDirection::Left ? curNode->GetPrevNode()
: curNode->GetNextNode();
if (!curNode) {
break;
}
offset =
aDirection == TextScanDirection::Left ? curNode->Length() - 1 : 0;
continue;
}
const Text* textNode = Text::FromNode(curNode);
if (IsWhitespaceAtPosition(textNode, offset)) {
offset += offsetIncrement;
continue;
}
// At this point, the caret has been moved to the next non-whitespace
// position.
// find word boundaries at the current position
textNode->GetData(textContent);
const intl::WordRange wordRange =
intl::WordBreaker::FindWord(textContent, offset);
offset = aDirection == TextScanDirection::Left ? wordRange.mBegin
: wordRange.mEnd;
bool allPunctuation = true;
for (uint32_t ch = wordRange.mBegin; ch != wordRange.mEnd && allPunctuation;
++ch) {
allPunctuation = mozilla::IsPunctuationForWordSelect(textContent[ch]);
}
if (!allPunctuation) {
return {curNode, offset};
}
offset += int(aDirection);
}
return {};
PeekOffsetOptions options = {PeekOffsetOption::JumpLines,
PeekOffsetOption::StopAtScroller,
PeekOffsetOption::IsKeyboardSelect};
Result<RangeBoundary, nsresult> newBoundary =
SelectionMovementUtils::MoveRangeBoundaryToSomewhere(
aRangeBoundary,
aDirection == TextScanDirection::Left ? nsDirection::eDirPrevious
: nsDirection::eDirNext,
aDirection == TextScanDirection::Left ? CaretAssociationHint::Before
: CaretAssociationHint::After,
intl::BidiEmbeddingLevel::DefaultLTR(),
nsSelectionAmount::eSelectWord, options);
return newBoundary.unwrapOr({});
}
/* static */ bool TextDirectiveUtil::IsWhitespaceAtPosition(const Text* aText,

View file

@ -15,6 +15,7 @@
#include "mozilla/intl/LineBreaker.h" // for LineBreaker::ComputeBreakPositions
#include "mozilla/intl/Locale.h"
#include "mozilla/intl/UnicodeProperties.h"
#include "mozilla/ScopeExit.h"
#include "mozilla/StaticPrefs_intl.h"
using mozilla::AutoRestore;
@ -150,6 +151,15 @@ static void SetupCapitalization(const char16_t* aWord, uint32_t aLength,
}
nsresult nsLineBreaker::FlushCurrentWord() {
auto cleanup = mozilla::MakeScopeExit([&] {
mCurrentWord.Clear();
mTextItems.Clear();
mCurrentWordMightBeBreakable = false;
mCurrentWordContainsMixedLang = false;
mCurrentWordLanguage = nullptr;
mWordContinuation = false;
});
uint32_t length = mCurrentWord.Length();
AutoTArray<uint8_t, 4000> breakState;
if (!breakState.AppendElements(length, mozilla::fallible)) {
@ -232,12 +242,6 @@ nsresult nsLineBreaker::FlushCurrentWord() {
offset += ti->mLength;
}
mCurrentWord.Clear();
mTextItems.Clear();
mCurrentWordMightBeBreakable = false;
mCurrentWordContainsMixedLang = false;
mCurrentWordLanguage = nullptr;
mWordContinuation = false;
return NS_OK;
}

View file

@ -29,7 +29,7 @@ TEST(TestParser, TestParserMain)
RefPtr<mozilla::dom::DOMParser> parser =
mozilla::dom::DOMParser::CreateWithoutGlobal(rv2);
if (rv2.Failed()) break;
nsCOMPtr<mozilla::dom::Document> document = parser->ParseFromString(
nsCOMPtr<mozilla::dom::Document> document = parser->ParseFromStringInternal(
htmlInput, mozilla::dom::SupportedType::Text_html, rv2);
if (rv2.Failed()) break;

View file

@ -37,7 +37,8 @@ TEST(TestXMLSerializerNoBreakLink, TestXMLSerializerNoBreakLinkMain)
IgnoredErrorResult rv;
RefPtr<DOMParser> parser = DOMParser::CreateWithoutGlobal(rv);
ASSERT_FALSE(rv.Failed());
document = parser->ParseFromString(htmlInput, SupportedType::Text_html, rv);
document = parser->ParseFromStringInternal(htmlInput,
SupportedType::Text_html, rv);
ASSERT_FALSE(rv.Failed());
}

View file

@ -20,6 +20,8 @@ support-files = ["file_self_close.html"]
["test_popup_blocker_link_target_blank.html"]
support-files = ["file_self_close.html"]
["test_popup_blocker_microtask.html"]
["test_popup_blocker_mouse_event.html"]
["test_popup_blocker_pointer_event.html"]

View file

@ -0,0 +1,56 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Test for triggering popup in microtask</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="target" style="width: 50px; height: 50px; background: green"></div>
<script>
add_setup(async function() {
await SpecialPowers.pushPrefEnv({"set": [
// Enable popup blocker
["dom.disable_open_during_load", true],
]});
});
// Test for bug 1863217
add_task(async function window_open_in_microtask() {
let target = document.getElementById("target");
let testPromise = new Promise(resolve => {
target.addEventListener("click", () => {
queueMicrotask(() => {
let w = window.open("about:blank");
ok(!!w, "Should allow popup");
if (w) {
w.close();
}
w = window.open("about:blank");
ok(!w, "Should block popup");
if (w) {
w.close();
}
resolve();
});
}, { once: true });
});
SpecialPowers.wrap(document).notifyUserGestureActivation();
// Dispatch an untrusted click event.
SimpleTest.executeSoon(() => {
target.dispatchEvent(new MouseEvent("click", {
bubbles: true,
cancelable: true,
view: window,
}));
});
await testPromise;
});
</script>
</body>
</html>

View file

@ -65,7 +65,7 @@ A review of the pre-Fission Message Manager mechanism
.. note::
There are actually several types of Message Managers: Frame Message Managers, Window Message Managers, Group Message Managers and Process Message Managers. For the purposes of this documentation, it's simplest to refer to all of these mechanisms altogether as the "Message Manager mechanism". Most of the examples in this document will be operating on the assumption that the Message Manager is a Frame Message Manager, which is the most commonly used one.
Currently, in the post `Electrolysis Project`_ Firefox codebase, we have code living in the parent process (UI) that is in plain JS (.js files) or in JS modules (.jsm files). In the child process (hosting the content), we use framescripts (.js) and also JS modules. The framescripts are instantiated once per top-level frame (or, in simpler terms, once per tab). This code has access to all of the DOM from the web content, including all iframes within it.
Currently, in the post `Electrolysis Project`_ Firefox codebase, we have code living in the parent process (UI) that is in plain JS (.js files) or in ES modules (.sys.mjs files). In the child process (hosting the content), we use framescripts (.js) and also ES modules. The framescripts are instantiated once per top-level frame (or, in simpler terms, once per tab). This code has access to all of the DOM from the web content, including all iframes within it.
The two processes communicate via the Frame Message Manager (mm) using the ``sendAsyncMessage`` / ``receiveMessage`` API, and any code in the parent can communicate with any code in the child (and vice versa), by just listening to the messages of interest.
@ -373,7 +373,7 @@ Your best bet for storing state is in the parent process.
.. hint::
If each individual frame needs state, consider using a ``WeakMap`` in the parent process, mapping ``CanonicalBrowsingContext``'s with that state. That way, if the associates frames ever go away, you don't have to do any cleaning up yourself.
If you have state that you want multiple ``JSWindowActorParent``'s to have access to, consider having a "manager" of those ``JSWindowActorParent``'s inside of the same .jsm file to hold that state.
If you have state that you want multiple ``JSWindowActorParent``'s to have access to, consider having a "manager" of those ``JSWindowActorParent``'s inside of the same .sys.mjs file to hold that state.
Registering a new actor
-----------------------
@ -422,7 +422,7 @@ Let's examine parent registration:
Here, we're declaring that class ``PluginParent`` (here, a subclass of ``JSWindowActorParent``) is defined and exported from module ``PluginParent.sys.mjs``. That's all we have to say for the parent (main process) side of things.
.. note::
It's not sufficient to just add a new .jsm file to the actors subdirectories. You also need to update the ``moz.build`` files in the same directory to get the ``resource://`` linkages set up correctly.
It's not sufficient to just add a new .sys.mjs file to the actors subdirectories. You also need to update the ``moz.build`` files in the same directory to get the ``resource://`` linkages set up correctly.
Let's look at the second chunk:
@ -459,7 +459,7 @@ Design considerations when adding a new actor
A few things worth bearing in mind when adding your own actor registration:
- Any ``child`` or ``parent`` side you register **must** have a ``moduleURI`` property.
- Any ``child`` or ``parent`` side you register **must** have a ``esModuleURI`` property.
- You do not need to have both ``child`` and ``parent`` modules, and should avoid having actor sides that do nothing but send messages. The process without a defined module will still get an actor, and you can send messages from that side, but cannot receive them via ``receiveMessage``. Note that you **can** also use ``sendQuery`` from this side, enabling you to handle a response from the other process despite not having a ``receiveMessage`` method.
- If you are writing a JSWindowActor, consider whether you really need ``allFrames`` - it'll save memory and CPU time if we don't need to instantiate the actor for subframes.
- When copying/moving "Legacy" :ref:`fission.message-manager-actors`, remove their ``messages`` properties. They are no longer necessary.
@ -475,17 +475,15 @@ Get a JSWindowActor
.. code-block:: javascript
// resource://testing-common/TestWindowParent.jsm
var EXPORTED_SYMBOLS = ["TestWindowParent"];
class TestParent extends JSWindowActorParent {
// resource://testing-common/TestWindowParent.sys.mjs
export class TestParent extends JSWindowActorParent {
...
}
.. code-block:: javascript
// resource://testing-common/TestWindowChild.jsm
var EXPORTED_SYMBOLS = ["TestWindowChild"];
class TestChild extends JSWindowActorChild {
// resource://testing-common/TestWindowChild.sys.mjs
export class TestChild extends JSWindowActorChild {
...
}
@ -507,17 +505,15 @@ Get a JSProcessActor
.. code-block:: javascript
// resource://testing-common/TestProcessParent.jsm
var EXPORTED_SYMBOLS = ["TestProcessParent"];
class TestParent extends JSProcessActorParent {
// resource://testing-common/TestProcessParent.sys.mjs
export class TestParent extends JSProcessActorParent {
...
}
.. code-block:: javascript
// resource://testing-common/TestProcessChild.jsm
var EXPORTED_SYMBOLS = ["TestProcessChild"];
class TestChild extends JSProcessActorChild {
// resource://testing-common/TestProcessChild.sys.mjs
export class TestChild extends JSProcessActorChild {
...
}
@ -546,5 +542,5 @@ And more
.. _Context Menu Fission Port: https://hg.mozilla.org/mozilla-central/rev/adc60720b7b8
.. _JSProcessActor.webidl: https://searchfox.org/mozilla-central/source/dom/chrome-webidl/JSProcessActor.webidl
.. _JSWindowActor.webidl: https://searchfox.org/mozilla-central/source/dom/chrome-webidl/JSWindowActor.webidl
.. _BrowserElementParent.jsm: https://searchfox.org/mozilla-central/rev/ec806131cb7bcd1c26c254d25cd5ab8a61b2aeb6/toolkit/actors/BrowserElementParent.jsm
.. _BrowserElementParent.sys.mjs: https://searchfox.org/mozilla-central/source/toolkit/actors/BrowserElementParent.sys.mjs
.. _Transferable: https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Transferable_objects

View file

@ -4,12 +4,12 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/DragEvent.h"
#include "DragEvent.h"
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/ImageInputTelemetry.h"
#include "mozilla/MouseEvents.h"
#include "nsContentUtils.h"
#include "prtime.h"
namespace mozilla::dom {
@ -28,20 +28,18 @@ DragEvent::DragEvent(EventTarget* aOwner, nsPresContext* aPresContext,
}
}
void DragEvent::InitDragEvent(const nsAString& aType, bool aCanBubble,
bool aCancelable, nsGlobalWindowInner* aView,
int32_t aDetail, int32_t aScreenX,
int32_t aScreenY, int32_t aClientX,
int32_t aClientY, bool aCtrlKey, bool aAltKey,
bool aShiftKey, bool aMetaKey, uint16_t aButton,
EventTarget* aRelatedTarget,
DataTransfer* aDataTransfer) {
void DragEvent::InitDragEventInternal(
const nsAString& aType, bool aCanBubble, bool aCancelable,
nsGlobalWindowInner* aView, int32_t aDetail, double aScreenX,
double aScreenY, double aClientX, double aClientY, bool aCtrlKey,
bool aAltKey, bool aShiftKey, bool aMetaKey, uint16_t aButton,
EventTarget* aRelatedTarget, DataTransfer* aDataTransfer) {
NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
MouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView, aDetail,
aScreenX, aScreenY, aClientX, aClientY, aCtrlKey,
aAltKey, aShiftKey, aMetaKey, aButton,
aRelatedTarget);
MouseEvent::InitMouseEventInternal(aType, aCanBubble, aCancelable, aView,
aDetail, aScreenX, aScreenY, aClientX,
aClientY, aCtrlKey, aAltKey, aShiftKey,
aMetaKey, aButton, aRelatedTarget);
if (mEventIsInternal) {
mEvent->AsDragEvent()->mDataTransfer = aDataTransfer;
}
@ -86,11 +84,11 @@ already_AddRefed<DragEvent> DragEvent::Constructor(
nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
RefPtr<DragEvent> e = new DragEvent(t, nullptr, nullptr);
bool trusted = e->Init(t);
e->InitDragEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
aParam.mDetail, aParam.mScreenX, aParam.mScreenY,
aParam.mClientX, aParam.mClientY, aParam.mCtrlKey,
aParam.mAltKey, aParam.mShiftKey, aParam.mMetaKey,
aParam.mButton, aParam.mRelatedTarget, aParam.mDataTransfer);
e->InitDragEventInternal(
aType, aParam.mBubbles, aParam.mCancelable, aParam.mView, aParam.mDetail,
aParam.mScreenX, aParam.mScreenY, aParam.mClientX, aParam.mClientY,
aParam.mCtrlKey, aParam.mAltKey, aParam.mShiftKey, aParam.mMetaKey,
aParam.mButton, aParam.mRelatedTarget, aParam.mDataTransfer);
e->InitializeExtraMouseEventDictionaryMembers(aParam);
e->SetTrusted(trusted);
e->SetComposed(aParam.mComposed);

View file

@ -36,7 +36,12 @@ class DragEvent : public MouseEvent {
int32_t aScreenX, int32_t aScreenY, int32_t aClientX,
int32_t aClientY, bool aCtrlKey, bool aAltKey,
bool aShiftKey, bool aMetaKey, uint16_t aButton,
EventTarget* aRelatedTarget, DataTransfer* aDataTransfer);
EventTarget* aRelatedTarget, DataTransfer* aDataTransfer) {
InitDragEventInternal(aType, aCanBubble, aCancelable, aView, aDetail,
aScreenX, aScreenY, aClientX, aClientY, aCtrlKey,
aAltKey, aShiftKey, aMetaKey, aButton, aRelatedTarget,
aDataTransfer);
}
static already_AddRefed<DragEvent> Constructor(const GlobalObject& aGlobal,
const nsAString& aType,
@ -47,6 +52,14 @@ class DragEvent : public MouseEvent {
protected:
~DragEvent() = default;
void InitDragEventInternal(const nsAString& aType, bool aCanBubble,
bool aCancelable, nsGlobalWindowInner* aView,
int32_t aDetail, double aScreenX, double aScreenY,
double aClientX, double aClientY, bool aCtrlKey,
bool aAltKey, bool aShiftKey, bool aMetaKey,
uint16_t aButton, EventTarget* aRelatedTarget,
DataTransfer* aDataTransfer);
};
} // namespace mozilla::dom

View file

@ -4,6 +4,8 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "Event.h"
#include "AccessCheck.h"
#include "base/basictypes.h"
#include "ipc/IPCMessageUtils.h"
@ -27,7 +29,6 @@
#include "mozilla/ViewportUtils.h"
#include "mozilla/dom/Document.h"
#include "mozilla/dom/DocumentInlines.h"
#include "mozilla/dom/Event.h"
#include "mozilla/dom/ShadowRoot.h"
#include "mozilla/dom/WorkerScope.h"
#include "mozilla/ScrollContainerFrame.h"
@ -582,28 +583,22 @@ bool Event::IsDispatchStopped() { return mEvent->PropagationStopped(); }
WidgetEvent* Event::WidgetEventPtr() { return mEvent; }
// static
Maybe<CSSIntPoint> Event::GetScreenCoords(nsPresContext* aPresContext,
WidgetEvent* aEvent,
LayoutDeviceIntPoint aPoint) {
Maybe<CSSDoublePoint> Event::GetScreenCoords(
nsPresContext* aPresContext, WidgetEvent* aEvent,
const LayoutDeviceDoublePoint& aWidgetRelativePoint) {
if (PointerLockManager::IsLocked()) {
return Some(EventStateManager::sLastScreenPoint);
}
if (!aEvent || (aEvent->mClass != eMouseEventClass &&
aEvent->mClass != eMouseScrollEventClass &&
aEvent->mClass != eWheelEventClass &&
aEvent->mClass != ePointerEventClass &&
aEvent->mClass != eTouchEventClass &&
aEvent->mClass != eDragEventClass &&
aEvent->mClass != eSimpleGestureEventClass)) {
if (!aEvent || !aEvent->DOMEventSupportsCoords()) {
return Nothing();
}
// Doing a straight conversion from LayoutDeviceIntPoint to CSSIntPoint
// Doing a straight conversion from LayoutDeviceDoublePoint to CSSDoublePoint
// seem incorrect, but it is needed to maintain legacy functionality.
WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
if (!aPresContext || !(guiEvent && guiEvent->mWidget)) {
return Some(CSSIntPoint(aPoint.x, aPoint.y));
const WidgetGUIEvent* guiEvent = aEvent->AsGUIEvent();
if (MOZ_UNLIKELY(!aPresContext) || !(guiEvent && guiEvent->mWidget)) {
return Some(CSSDoublePoint(aWidgetRelativePoint.x, aWidgetRelativePoint.y));
}
// (Potentially) transform the point from the coordinate space of an
@ -611,120 +606,126 @@ Maybe<CSSIntPoint> Event::GetScreenCoords(nsPresContext* aPresContext,
// window. The transform can only be applied to a point whose components
// are floating-point values, so convert the integer point first, then
// transform, and then round the result back to an integer point.
LayoutDevicePoint floatPoint(aPoint);
LayoutDevicePoint topLevelPoint =
const LayoutDeviceIntPoint topLevelPoint = LayoutDeviceIntPoint::Round(
guiEvent->mWidget->WidgetToTopLevelWidgetTransform().TransformPoint(
floatPoint);
LayoutDeviceIntPoint rounded = RoundedToInt(topLevelPoint);
nsPoint pt = LayoutDevicePixel::ToAppUnits(
rounded, aPresContext->DeviceContext()->AppUnitsPerDevPixel());
pt += LayoutDevicePixel::ToAppUnits(
guiEvent->mWidget->TopLevelWidgetToScreenOffset(),
aPresContext->DeviceContext()->AppUnitsPerDevPixel());
return Some(CSSPixel::FromAppUnitsRounded(pt));
aWidgetRelativePoint));
const CSSPoint pt = CSSPixel::FromAppUnits(
LayoutDevicePixel::ToAppUnits(
topLevelPoint, aPresContext->DeviceContext()->AppUnitsPerDevPixel()) +
LayoutDevicePixel::ToAppUnits(
guiEvent->mWidget->TopLevelWidgetToScreenOffset(),
aPresContext->DeviceContext()->AppUnitsPerDevPixel()));
return Some(CSSDoublePoint(pt.x, pt.y));
}
// static
CSSIntPoint Event::GetPageCoords(nsPresContext* aPresContext,
WidgetEvent* aEvent,
LayoutDeviceIntPoint aPoint,
CSSIntPoint aDefaultPoint) {
CSSIntPoint pagePoint =
Event::GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
CSSDoublePoint Event::GetPageCoords(
nsPresContext* aPresContext, WidgetEvent* aEvent,
const LayoutDeviceDoublePoint& aWidgetRelativePoint,
const CSSDoublePoint& aDefaultClientPoint) {
const CSSDoublePoint clientCoords = Event::GetClientCoords(
aPresContext, aEvent, aWidgetRelativePoint, aDefaultClientPoint);
// If there is some scrolling, add scroll info to client point.
if (aPresContext && aPresContext->GetPresShell()) {
PresShell* presShell = aPresContext->PresShell();
if (ScrollContainerFrame* sf = presShell->GetRootScrollContainerFrame()) {
pagePoint += CSSIntPoint::FromAppUnitsRounded(sf->GetScrollPosition());
const CSSPoint scrollPoint = CSSPixel::FromAppUnits([&]() {
if (aPresContext && aPresContext->GetPresShell()) {
if (const ScrollContainerFrame* const sf =
aPresContext->PresShell()->GetRootScrollContainerFrame()) {
return sf->GetScrollPosition();
}
}
}
return pagePoint;
return nsPoint{};
}());
return clientCoords + CSSDoublePoint(scrollPoint.x, scrollPoint.y);
}
// static
CSSIntPoint Event::GetClientCoords(nsPresContext* aPresContext,
WidgetEvent* aEvent,
LayoutDeviceIntPoint aPoint,
CSSIntPoint aDefaultPoint) {
CSSDoublePoint Event::GetClientCoords(
nsPresContext* aPresContext, WidgetEvent* aEvent,
const LayoutDeviceDoublePoint& aWidgetRelativePoint,
const CSSDoublePoint& aDefaultClientPoint) {
if (PointerLockManager::IsLocked()) {
return EventStateManager::sLastClientPoint;
}
if (!aEvent ||
(aEvent->mClass != eMouseEventClass &&
aEvent->mClass != eMouseScrollEventClass &&
aEvent->mClass != eWheelEventClass &&
aEvent->mClass != eTouchEventClass &&
aEvent->mClass != eDragEventClass &&
aEvent->mClass != ePointerEventClass &&
aEvent->mClass != eSimpleGestureEventClass) ||
!aPresContext || !aEvent->AsGUIEvent()->mWidget) {
return aDefaultPoint;
if (MOZ_UNLIKELY(!aPresContext) || MOZ_UNLIKELY(!aEvent) ||
!aEvent->DOMEventSupportsCoords() ||
MOZ_UNLIKELY(!aEvent->AsGUIEvent()->mWidget)) {
return aDefaultClientPoint;
}
PresShell* presShell = aPresContext->GetPresShell();
if (!presShell) {
return CSSIntPoint(0, 0);
const PresShell* const presShell = aPresContext->GetPresShell();
if (MOZ_UNLIKELY(!presShell)) {
return CSSDoublePoint(0, 0);
}
nsIFrame* rootFrame = presShell->GetRootFrame();
if (!rootFrame) {
return CSSIntPoint(0, 0);
// XXX Why don't we flush pending notifications before computing the offset
// from the root frame?
const nsIFrame* const rootFrame = presShell->GetRootFrame();
if (MOZ_UNLIKELY(!rootFrame)) {
return CSSDoublePoint(0, 0);
}
nsPoint pt = nsLayoutUtils::GetEventCoordinatesRelativeTo(
aEvent, aPoint, RelativeTo{rootFrame});
return CSSIntPoint::FromAppUnitsRounded(pt);
const CSSPoint pt =
CSSPixel::FromAppUnits(nsLayoutUtils::GetEventCoordinatesRelativeTo(
aEvent, LayoutDeviceIntPoint::Round(aWidgetRelativePoint),
RelativeTo{rootFrame}));
return CSSDoublePoint(pt.x, pt.y);
}
// static
CSSIntPoint Event::GetOffsetCoords(nsPresContext* aPresContext,
WidgetEvent* aEvent,
LayoutDeviceIntPoint aPoint,
CSSIntPoint aDefaultPoint) {
if (!aEvent->mTarget) {
return GetPageCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
nsIFrame* Event::GetPrimaryFrameOfEventTarget(const nsPresContext& aPresContext,
const WidgetEvent& aEvent) {
const nsCOMPtr<nsIContent> content =
nsIContent::FromEventTargetOrNull(aEvent.mTarget);
if (!content) {
return nullptr;
}
nsCOMPtr<nsIContent> content = nsIContent::FromEventTarget(aEvent->mTarget);
if (!content || !aPresContext) {
return CSSIntPoint();
// XXX Even after the event target content is moved to different document, we
// may get its primary frame. In this case, should we return nullptr here?
nsIFrame* const frame = content->GetPrimaryFrame(FlushType::Layout);
if (MOZ_UNLIKELY(!frame)) {
return nullptr;
}
RefPtr<PresShell> presShell = aPresContext->GetPresShell();
if (!presShell) {
return CSSIntPoint();
}
presShell->FlushPendingNotifications(FlushType::Layout);
nsIFrame* frame = content->GetPrimaryFrame();
if (!frame) {
return CSSIntPoint();
}
// For compat, see https://github.com/w3c/csswg-drafts/issues/1508. In SVG we
// just return the coordinates of the outer SVG box. This is all kinda
// For compat, see https://github.com/w3c/csswg-drafts/issues/1508. In SVG
// we just return the coordinates of the outer SVG box. This is all kinda
// unfortunate.
if (frame->HasAnyStateBits(NS_FRAME_SVG_LAYOUT) &&
StaticPrefs::dom_events_offset_in_svg_relative_to_svg_root()) {
frame = SVGUtils::GetOuterSVGFrame(frame);
if (!frame) {
return CSSIntPoint();
}
return SVGUtils::GetOuterSVGFrame(frame);
}
nsIFrame* rootFrame = presShell->GetRootFrame();
if (!rootFrame) {
return CSSIntPoint();
return frame;
}
// static
CSSDoublePoint Event::GetOffsetCoords(
nsPresContext* aPresContext, WidgetEvent* aEvent,
const LayoutDeviceDoublePoint& aWidgetRelativePoint,
const CSSDoublePoint& aDefaultClientPoint) {
if (!aEvent->mTarget) {
return GetPageCoords(aPresContext, aEvent, aWidgetRelativePoint,
aDefaultClientPoint);
}
CSSIntPoint clientCoords =
GetClientCoords(aPresContext, aEvent, aPoint, aDefaultPoint);
nsPoint pt = CSSPixel::ToAppUnits(clientCoords);
if (nsLayoutUtils::TransformPoint(RelativeTo{rootFrame}, RelativeTo{frame},
pt) == nsLayoutUtils::TRANSFORM_SUCCEEDED) {
pt -= frame->GetPaddingRectRelativeToSelf().TopLeft();
return CSSPixel::FromAppUnitsRounded(pt);
if (!nsIContent::FromEventTarget(aEvent->mTarget) || !aPresContext) {
return CSSDoublePoint();
}
return CSSIntPoint();
const nsIFrame* const frame =
GetPrimaryFrameOfEventTarget(*aPresContext, *aEvent);
if (MOZ_UNLIKELY(!frame)) {
return CSSDoublePoint();
}
MOZ_ASSERT(aPresContext->PresShell()->GetRootFrame());
const CSSDoublePoint clientCoords = GetClientCoords(
aPresContext, aEvent, aWidgetRelativePoint, aDefaultClientPoint);
nsPoint ptInAppUnits = CSSPixel::ToAppUnits(CSSPoint(
static_cast<float>(clientCoords.x), static_cast<float>(clientCoords.y)));
if (nsLayoutUtils::TransformPoint(
RelativeTo{aPresContext->PresShell()->GetRootFrame()},
RelativeTo{frame},
ptInAppUnits) != nsLayoutUtils::TRANSFORM_SUCCEEDED) {
return CSSDoublePoint();
}
ptInAppUnits -= frame->GetPaddingRectRelativeToSelf().TopLeft();
const CSSPoint pt = CSSPixel::FromAppUnits(ptInAppUnits);
return CSSDoublePoint(pt.x, pt.y);
}
// To be called ONLY by Event::GetType (which has the additional

View file

@ -174,22 +174,82 @@ class Event : public nsISupports, public nsWrapperCache {
bool Init(EventTarget* aGlobal);
static const char16_t* GetEventName(EventMessage aEventType);
static CSSIntPoint GetClientCoords(nsPresContext* aPresContext,
WidgetEvent* aEvent,
LayoutDeviceIntPoint aPoint,
CSSIntPoint aDefaultPoint);
static CSSIntPoint GetPageCoords(nsPresContext* aPresContext,
WidgetEvent* aEvent,
LayoutDeviceIntPoint aPoint,
CSSIntPoint aDefaultPoint);
static Maybe<CSSIntPoint> GetScreenCoords(nsPresContext* aPresContext,
WidgetEvent* aEvent,
LayoutDeviceIntPoint aPoint);
MOZ_CAN_RUN_SCRIPT_BOUNDARY
static CSSIntPoint GetOffsetCoords(nsPresContext* aPresContext,
WidgetEvent* aEvent,
LayoutDeviceIntPoint aPoint,
CSSIntPoint aDefaultPoint);
/**
* Return clientX and clientY values for aEvent fired at aWidgetRelativePoint.
* If you do not want fractional values as the result, you should floor
* aWidgetRelativePoint and aDefaultClientPoint before calling this method
* like defined by the Pointer Events spec.
* https://w3c.github.io/pointerevents/#event-coordinates
* And finally round the result to the integer.
* Note that if you want fractional values and the source of
* aWidgetRelativePoint and aDefaultClientPoint is an untrusted event, the
* result may not be representable with floats, i.e., CSSPoint. However, if
* it's trusted point, the result is representable with floats because we use
* CSSPoint to convert to/from app units.
*/
static CSSDoublePoint GetClientCoords(
nsPresContext* aPresContext, WidgetEvent* aEvent,
const LayoutDeviceDoublePoint& aWidgetRelativePoint,
const CSSDoublePoint& aDefaultClientPoint);
/**
* Return pageX and pageY values for aEvent fired at aWidgetRelativePoint,
* which are client point + scroll position of the root scrollable frame. If
* you do not want fractional values as the result, you should floor
* aWidgetRelativePoint and aDefaultClientPoint before calling this method
* like defined by the Pointer Events spec.
* https://w3c.github.io/pointerevents/#event-coordinates
* And finally round the result to the integer.
* Note that if you want fractional values and the source of
* aWidgetRelativePoint and aDefaultClientPoint is an untrusted event, the
* result may not be representable with floats, i.e., CSSPoint. However, if
* it's trusted point, the result is representable with floats because we use
* CSSPoint to convert to/from app units.
*/
static CSSDoublePoint GetPageCoords(
nsPresContext* aPresContext, WidgetEvent* aEvent,
const LayoutDeviceDoublePoint& aWidgetRelativePoint,
const CSSDoublePoint& aDefaultClientPoint);
/**
* Return screenX and screenY values for aEvent fired at aWidgetRelativePoint.
* If aEvent does not support exposing the ref point, this returns Nothing. If
* you do not want fractional values as the result, you should floor
* aWidgetRelativePoint and aDefaultClientPoint before calling this method
* like defined by the Pointer Events spec.
* https://w3c.github.io/pointerevents/#event-coordinates
* And finally round the result to the integer.
* Note that if you want fractional values and the source of
* aWidgetRelativePoint and aDefaultClientPoint is an untrusted event, the
* result may not be representable with floats, i.e., CSSPoint. However, if
* it's trusted point, the result is representable with floats because we use
* CSSPoint to convert to/from app units.
*/
static Maybe<CSSDoublePoint> GetScreenCoords(
nsPresContext* aPresContext, WidgetEvent* aEvent,
const LayoutDeviceDoublePoint& aWidgetRelativePoint);
/**
* Return offsetX and offsetY values for aEvent fired at aWidgetRelativePoint,
* which are offset in the target element. If you do not want fractional
* values as the result, you should floor aWidgetRelativePoint and
* aDefaultClientPoint before calling this method like defined by the Pointer
* Events spec. https://w3c.github.io/pointerevents/#event-coordinates
* And finally round the result to the integer. Note that if you want
* fractional values and the source of aWidgetRelativePoint and
* aDefaultClientPoint is an untrusted event, the result may not be
* representable with floats, i.e., CSSPoint. However, if it's trusted point,
* the result is representable with floats because we use CSSPoint to convert
* to/from app units.
*
* Be aware, this may flush the layout.
*/
MOZ_CAN_RUN_SCRIPT
static CSSDoublePoint GetOffsetCoords(
nsPresContext* aPresContext, WidgetEvent* aEvent,
const LayoutDeviceDoublePoint& aWidgetRelativePoint,
const CSSDoublePoint& aDefaultClientPoint);
static already_AddRefed<Event> Constructor(EventTarget* aEventTarget,
const nsAString& aType,
@ -341,6 +401,10 @@ class Event : public nsISupports, public nsWrapperCache {
already_AddRefed<EventTarget> EnsureWebAccessibleRelatedTarget(
EventTarget* aRelatedTarget);
[[nodiscard]] MOZ_CAN_RUN_SCRIPT static nsIFrame*
GetPrimaryFrameOfEventTarget(const nsPresContext& aPresContext,
const WidgetEvent& aEvent);
mozilla::WidgetEvent* mEvent;
RefPtr<nsPresContext> mPresContext;
nsCOMPtr<EventTarget> mExplicitOriginalTarget;

View file

@ -942,11 +942,11 @@ nsresult EventStateManager::PreHandleEvent(nsPresContext* aPresContext,
// XXX Probably doesn't matter much, but storing these in CSS pixels instead
// of device pixels means behavior can be a bit odd if you zoom while
// pointer-locked.
sLastScreenPoint =
sLastScreenPoint = RoundedToInt(
Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
.extract();
sLastClientPoint = Event::GetClientCoords(
aPresContext, aEvent, aEvent->mRefPoint, CSSIntPoint(0, 0));
.extract());
sLastClientPoint = RoundedToInt(Event::GetClientCoords(
aPresContext, aEvent, aEvent->mRefPoint, CSSDoublePoint{0, 0}));
}
*aStatus = nsEventStatus_eIgnore;
@ -4420,9 +4420,9 @@ nsresult EventStateManager::PostHandleEvent(nsPresContext* aPresContext,
// to set drag end point in such case (you hit assersion if you do
// it).
if (sourceWC) {
CSSIntPoint dropPointInScreen =
const CSSIntPoint dropPointInScreen = RoundedToInt(
Event::GetScreenCoords(aPresContext, aEvent, aEvent->mRefPoint)
.extract();
.extract());
dragSession->SetDragEndPointForTests(dropPointInScreen.x,
dropPointInScreen.y);
}

View file

@ -4,16 +4,27 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/MouseEvent.h"
#include "mozilla/MouseEvents.h"
#include "MouseEvent.h"
#include "mozilla/BasePrincipal.h"
#include "mozilla/EventForwards.h"
#include "mozilla/MouseEvents.h"
#include "mozilla/PresShell.h"
#include "mozilla/StaticPrefs_dom.h"
#include "mozilla/ViewportUtils.h"
#include "nsContentUtils.h"
#include "nsIContent.h"
#include "nsIFrame.h"
#include "nsIScreenManager.h"
#include "prtime.h"
#include "nsLayoutUtils.h"
namespace mozilla::dom {
static nsIntPoint DevPixelsToCSSPixels(const LayoutDeviceIntPoint& aPoint,
nsPresContext* aContext) {
return nsIntPoint(aContext->DevPixelsToIntCSSPixels(aPoint.x),
aContext->DevPixelsToIntCSSPixels(aPoint.y));
}
MouseEvent::MouseEvent(EventTarget* aOwner, nsPresContext* aPresContext,
WidgetMouseEventBase* aEvent)
: UIEvent(aOwner, aPresContext,
@ -24,29 +35,32 @@ MouseEvent::MouseEvent(EventTarget* aOwner, nsPresContext* aPresContext,
// It's not that important, though, since a scroll event is not a real
// DOM event.
WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent();
WidgetMouseEventBase* const mouseEventBase = mEvent->AsMouseEventBase();
MOZ_ASSERT(mouseEventBase);
if (aEvent) {
mEventIsInternal = false;
} else {
mEventIsInternal = true;
mEvent->mRefPoint = LayoutDeviceIntPoint(0, 0);
mouseEvent->mInputSource = MouseEvent_Binding::MOZ_SOURCE_UNKNOWN;
mouseEventBase->mInputSource = MouseEvent_Binding::MOZ_SOURCE_UNKNOWN;
}
if (mouseEvent) {
mUseFractionalCoords = mouseEventBase->DOMEventShouldUseFractionalCoords();
mWidgetRelativePoint = mEvent->mRefPoint;
if (const WidgetMouseEvent* mouseEvent = mouseEventBase->AsMouseEvent()) {
MOZ_ASSERT(mouseEvent->mReason != WidgetMouseEvent::eSynthesized,
"Don't dispatch DOM events from synthesized mouse events");
mDetail = mouseEvent->mClickCount;
mDetail = static_cast<int32_t>(mouseEvent->mClickCount);
}
}
void MouseEvent::InitMouseEvent(const nsAString& aType, bool aCanBubble,
bool aCancelable, nsGlobalWindowInner* aView,
int32_t aDetail, int32_t aScreenX,
int32_t aScreenY, int32_t aClientX,
int32_t aClientY, bool aCtrlKey, bool aAltKey,
bool aShiftKey, bool aMetaKey, uint16_t aButton,
EventTarget* aRelatedTarget) {
void MouseEvent::InitMouseEventInternal(
const nsAString& aType, bool aCanBubble, bool aCancelable,
nsGlobalWindowInner* aView, int32_t aDetail, double aScreenX,
double aScreenY, double aClientX, double aClientY, bool aCtrlKey,
bool aAltKey, bool aShiftKey, bool aMetaKey, uint16_t aButton,
EventTarget* aRelatedTarget) {
NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
UIEvent::InitUIEvent(aType, aCanBubble, aCancelable, aView, aDetail);
@ -63,15 +77,29 @@ void MouseEvent::InitMouseEvent(const nsAString& aType, bool aCanBubble,
mouseEventBase->mButton = aButton;
mouseEventBase->InitBasicModifiers(aCtrlKey, aAltKey, aShiftKey,
aMetaKey);
mDefaultClientPoint.x = aClientX;
mDefaultClientPoint.y = aClientY;
mouseEventBase->mRefPoint.x = aScreenX;
mouseEventBase->mRefPoint.y = aScreenY;
mDefaultClientPoint = CSSDoublePoint(aClientX, aClientY);
mWidgetRelativePoint = LayoutDeviceDoublePoint(aScreenX, aScreenY);
mouseEventBase->mRefPoint =
LayoutDeviceIntPoint::Floor(mWidgetRelativePoint);
WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent();
if (mouseEvent) {
mouseEvent->mClickCount = aDetail;
}
mUseFractionalCoords =
mouseEventBase->DOMEventShouldUseFractionalCoords();
if (!mUseFractionalCoords) {
// If we should not use fractional coordinates for this event, we need
// to drop the fractional part as defined for the backward compatibility
// when we treated the input values are integer coordinates. These
// values will be exposed as screenX, screenY, clientX and clientY as-is
// too. That matches with the Pointer Events spec definitions too.
// https://w3c.github.io/pointerevents/#event-coordinates
mDefaultClientPoint = CSSIntPoint::Floor(mDefaultClientPoint);
mWidgetRelativePoint =
LayoutDeviceIntPoint::Floor(mWidgetRelativePoint);
}
break;
}
default:
@ -79,18 +107,16 @@ void MouseEvent::InitMouseEvent(const nsAString& aType, bool aCanBubble,
}
}
void MouseEvent::InitMouseEvent(const nsAString& aType, bool aCanBubble,
bool aCancelable, nsGlobalWindowInner* aView,
int32_t aDetail, int32_t aScreenX,
int32_t aScreenY, int32_t aClientX,
int32_t aClientY, int16_t aButton,
EventTarget* aRelatedTarget,
const nsAString& aModifiersList) {
void MouseEvent::InitMouseEventInternal(
const nsAString& aType, bool aCanBubble, bool aCancelable,
nsGlobalWindowInner* aView, int32_t aDetail, double aScreenX,
double aScreenY, double aClientX, double aClientY, int16_t aButton,
EventTarget* aRelatedTarget, const nsAString& aModifiersList) {
NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
Modifiers modifiers = ComputeModifierState(aModifiersList);
InitMouseEvent(
InitMouseEventInternal(
aType, aCanBubble, aCancelable, aView, aDetail, aScreenX, aScreenY,
aClientX, aClientY, (modifiers & MODIFIER_CONTROL) != 0,
(modifiers & MODIFIER_ALT) != 0, (modifiers & MODIFIER_SHIFT) != 0,
@ -124,11 +150,11 @@ already_AddRefed<MouseEvent> MouseEvent::Constructor(
nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
RefPtr<MouseEvent> e = new MouseEvent(t, nullptr, nullptr);
bool trusted = e->Init(t);
e->InitMouseEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
aParam.mDetail, aParam.mScreenX, aParam.mScreenY,
aParam.mClientX, aParam.mClientY, aParam.mCtrlKey,
aParam.mAltKey, aParam.mShiftKey, aParam.mMetaKey,
aParam.mButton, aParam.mRelatedTarget);
e->InitMouseEventInternal(
aType, aParam.mBubbles, aParam.mCancelable, aParam.mView, aParam.mDetail,
aParam.mScreenX, aParam.mScreenY, aParam.mClientX, aParam.mClientY,
aParam.mCtrlKey, aParam.mAltKey, aParam.mShiftKey, aParam.mMetaKey,
aParam.mButton, aParam.mRelatedTarget);
e->InitializeExtraMouseEventDictionaryMembers(aParam);
e->SetTrusted(trusted);
e->SetComposed(aParam.mComposed);
@ -147,16 +173,47 @@ void MouseEvent::InitNSMouseEvent(const nsAString& aType, bool aCanBubble,
float aPressure, uint16_t aInputSource) {
NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
MouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView, aDetail,
aScreenX, aScreenY, aClientX, aClientY, aCtrlKey,
aAltKey, aShiftKey, aMetaKey, aButton,
aRelatedTarget);
InitMouseEventInternal(aType, aCanBubble, aCancelable, aView, aDetail,
aScreenX, aScreenY, aClientX, aClientY, aCtrlKey,
aAltKey, aShiftKey, aMetaKey, aButton, aRelatedTarget);
WidgetMouseEventBase* mouseEventBase = mEvent->AsMouseEventBase();
mouseEventBase->mPressure = aPressure;
mouseEventBase->mInputSource = aInputSource;
}
void MouseEvent::DuplicatePrivateData() {
// If this is a event not created from WidgetMouseEventBase or its subclasses
// (i.e., created by JS), mDefaultClientPoint and mMovementPoint are
// initialized as expected values. Therefore, we don't need to recompute it.
if (!mEventIsInternal) {
mDefaultClientPoint = ClientPoint();
mMovementPoint = GetMovementPoint();
}
// However, mPagePoint needs to include the scroll position. Therefore, we
// need to compute here.
mPagePoint = PagePoint();
// mEvent->mRefPoint is computed by UIEvent::DuplicatePrivateData() with
// the device pixel scale, but if we need to store fractional values to
// mWidgetRelativePoint, we need to do same thing by ourselves.
Maybe<const CSSDoublePoint> maybeScreenPoint;
if (mUseFractionalCoords) {
maybeScreenPoint.emplace(ScreenPoint(CallerType::System));
}
UIEvent::DuplicatePrivateData();
if (maybeScreenPoint.isSome()) {
CSSToLayoutDeviceScale scale = mPresContext
? mPresContext->CSSToDevPixelScale()
: CSSToLayoutDeviceScale(1);
mWidgetRelativePoint = maybeScreenPoint.ref() * scale;
} else {
// As mentioned above, mEvent->mRefPoint is already computed by UIEvent, so,
// do not need to compute the scale.
mWidgetRelativePoint = mEvent->mRefPoint;
}
}
void MouseEvent::PreventClickEvent() {
if (WidgetMouseEvent* mouseEvent = mEvent->AsMouseEvent()) {
mouseEvent->mClickEventPrevented = true;
@ -217,32 +274,42 @@ already_AddRefed<EventTarget> MouseEvent::GetRelatedTarget() {
return EnsureWebAccessibleRelatedTarget(relatedTarget);
}
CSSIntPoint MouseEvent::ScreenPoint(CallerType aCallerType) const {
CSSDoublePoint MouseEvent::ScreenPoint(CallerType aCallerType) const {
if (mEvent->mFlags.mIsPositionless) {
return {};
}
// If this is a trusted event, mWidgetRelativeOffset is a copy of
// mEvent->mRefPoint, so, the values are integer.
// If this is an untrusted event, mWidgetRelativeOffset should be floored when
// it's initialized.
MOZ_ASSERT_IF(!mUseFractionalCoords,
mWidgetRelativePoint ==
LayoutDeviceIntPoint::Floor(mWidgetRelativePoint));
if (nsContentUtils::ShouldResistFingerprinting(
aCallerType, GetParentObject(), RFPTarget::MouseEventScreenPoint)) {
// Sanitize to something sort of like client cooords, but not quite
// Sanitize to something sort of like client coords, but not quite
// (defaulting to (0,0) instead of our pre-specified client coords).
return Event::GetClientCoords(mPresContext, mEvent, mEvent->mRefPoint,
CSSIntPoint(0, 0));
const CSSDoublePoint clientPoint = Event::GetClientCoords(
mPresContext, mEvent, mWidgetRelativePoint, CSSDoublePoint{0, 0});
return mUseFractionalCoords ? clientPoint : RoundedToInt(clientPoint);
}
return Event::GetScreenCoords(mPresContext, mEvent, mEvent->mRefPoint)
.extract();
const CSSDoublePoint screenPoint =
Event::GetScreenCoords(mPresContext, mEvent, mWidgetRelativePoint)
.extract();
return mUseFractionalCoords ? screenPoint : RoundedToInt(screenPoint);
}
LayoutDeviceIntPoint MouseEvent::ScreenPointLayoutDevicePix() const {
const CSSIntPoint point = ScreenPoint(CallerType::System);
const CSSDoublePoint point = ScreenPoint(CallerType::System);
auto scale = mPresContext ? mPresContext->CSSToDevPixelScale()
: CSSToLayoutDeviceScale();
return LayoutDeviceIntPoint::Round(point * scale);
}
DesktopIntPoint MouseEvent::ScreenPointDesktopPix() const {
const CSSIntPoint point = ScreenPoint(CallerType::System);
const CSSDoublePoint point = ScreenPoint(CallerType::System);
auto scale =
mPresContext
? mPresContext->CSSToDevPixelScale() /
@ -261,35 +328,104 @@ already_AddRefed<nsIScreen> MouseEvent::GetScreen() {
DesktopIntRect(ScreenPointDesktopPix(), DesktopIntSize(1, 1)));
}
CSSIntPoint MouseEvent::PagePoint() const {
CSSDoublePoint MouseEvent::PagePoint() const {
if (mEvent->mFlags.mIsPositionless) {
return {};
}
if (mPrivateDataDuplicated) {
// mPagePoint should be floored when it started to cache the values after
// the propagation.
MOZ_ASSERT_IF(!mUseFractionalCoords,
mPagePoint == CSSIntPoint::Floor(mPagePoint));
return mPagePoint;
}
return Event::GetPageCoords(mPresContext, mEvent, mEvent->mRefPoint,
mDefaultClientPoint);
// If this is a trusted event, mWidgetRelativeOffset is a copy of
// mEvent->mRefPoint, so, the values are integer.
// If this is an untrusted event, mWidgetRelativeOffset should be floored when
// it's initialized.
MOZ_ASSERT_IF(!mUseFractionalCoords,
mWidgetRelativePoint ==
LayoutDeviceIntPoint::Floor(mWidgetRelativePoint));
// If this is a trusted event, mDefaultClientPoint should be floored when
// it started to cache the values after the propagation.
// If this is an untrusted event, mDefaultClientPoint should be floored when
// it's initialized.
MOZ_ASSERT_IF(!mUseFractionalCoords,
mDefaultClientPoint == CSSIntPoint::Floor(mDefaultClientPoint));
const CSSDoublePoint pagePoint = Event::GetPageCoords(
mPresContext, mEvent, mWidgetRelativePoint, mDefaultClientPoint);
return mUseFractionalCoords ? pagePoint : RoundedToInt(pagePoint);
}
CSSIntPoint MouseEvent::ClientPoint() const {
CSSDoublePoint MouseEvent::ClientPoint() const {
if (mEvent->mFlags.mIsPositionless) {
return {};
}
return Event::GetClientCoords(mPresContext, mEvent, mEvent->mRefPoint,
mDefaultClientPoint);
// If this is a trusted event, mWidgetRelativeOffset is a copy of
// mEvent->mRefPoint, so, the values are integer.
// If this is an untrusted event, mWidgetRelativeOffset should be floored when
// it's initialized.
MOZ_ASSERT_IF(!mUseFractionalCoords,
mWidgetRelativePoint ==
LayoutDeviceIntPoint::Floor(mWidgetRelativePoint));
// If this is a trusted event, mDefaultClientPoint should be floored when
// it started to cache the values after the propagation.
// If this is an untrusted event, mDefaultClientPoint should be floored when
// it's initialized.
MOZ_ASSERT_IF(!mUseFractionalCoords,
mDefaultClientPoint == CSSIntPoint::Floor(mDefaultClientPoint));
const CSSDoublePoint clientPoint = Event::GetClientCoords(
mPresContext, mEvent, mWidgetRelativePoint, mDefaultClientPoint);
return mUseFractionalCoords ? clientPoint : RoundedToInt(clientPoint);
}
CSSIntPoint MouseEvent::OffsetPoint() const {
CSSDoublePoint MouseEvent::OffsetPoint() const {
if (mEvent->mFlags.mIsPositionless) {
return {};
}
return Event::GetOffsetCoords(mPresContext, mEvent, mEvent->mRefPoint,
mDefaultClientPoint);
// If this is a trusted event, mWidgetRelativeOffset is a copy of
// mEvent->mRefPoint, so, the values are integer.
// If this is an untrusted event, mWidgetRelativeOffset should be floored when
// it's initialized.
MOZ_ASSERT_IF(!mUseFractionalCoords,
mWidgetRelativePoint ==
LayoutDeviceIntPoint::Floor(mWidgetRelativePoint));
// If this is a trusted event, mDefaultClientPoint should be floored when
// it started to cache the values after the propagation.
// If this is an untrusted event, mDefaultClientPoint should be floored when
// it's initialized.
MOZ_ASSERT_IF(!mUseFractionalCoords,
mDefaultClientPoint == CSSIntPoint::Floor(mDefaultClientPoint));
RefPtr<nsPresContext> presContext(mPresContext);
const CSSDoublePoint offsetPoint = Event::GetOffsetCoords(
presContext, mEvent, mWidgetRelativePoint, mDefaultClientPoint);
return mUseFractionalCoords ? offsetPoint : RoundedToInt(offsetPoint);
}
nsIntPoint MouseEvent::GetMovementPoint() const {
if (mEvent->mFlags.mIsPositionless) {
return nsIntPoint(0, 0);
}
if (mPrivateDataDuplicated || mEventIsInternal) {
return mMovementPoint;
}
if (!mEvent || !mEvent->AsGUIEvent()->mWidget ||
(mEvent->mMessage != eMouseMove && mEvent->mMessage != ePointerMove)) {
// Pointer Lock spec defines that movementX/Y must be zero for all mouse
// events except mousemove.
return nsIntPoint(0, 0);
}
// Calculate the delta between the last screen point and the current one.
nsIntPoint current = DevPixelsToCSSPixels(mEvent->mRefPoint, mPresContext);
nsIntPoint last = DevPixelsToCSSPixels(mEvent->mLastRefPoint, mPresContext);
return current - last;
}
bool MouseEvent::AltKey() { return mEvent->AsInputEvent()->IsAlt(); }

View file

@ -28,6 +28,8 @@ class MouseEvent : public UIEvent {
virtual MouseEvent* AsMouseEvent() override { return this; }
MOZ_CAN_RUN_SCRIPT_BOUNDARY void DuplicatePrivateData() override;
// Web IDL binding methods
virtual uint32_t Which(CallerType aCallerType) override {
return Button() + 1;
@ -35,28 +37,67 @@ class MouseEvent : public UIEvent {
already_AddRefed<nsIScreen> GetScreen();
// In CSS coords.
CSSIntPoint ScreenPoint(CallerType) const;
int32_t ScreenX(CallerType aCallerType) const {
/**
* Return screenX and screenY values for this event in CSS pixels.
* If current setting allows to expose fractional coordinates for the event,
* this returns the fractional values as-is. Otherwise, this returns
* integer values with rounding the computed values. Note that if this
* event is untrusted one and should not expose fractional values, the
* initialized values are floored before computing the values as defined by
* Pointer Events spec.
*/
CSSDoublePoint ScreenPoint(CallerType) const;
double ScreenX(CallerType aCallerType) const {
return ScreenPoint(aCallerType).x;
}
int32_t ScreenY(CallerType aCallerType) const {
double ScreenY(CallerType aCallerType) const {
return ScreenPoint(aCallerType).y;
}
LayoutDeviceIntPoint ScreenPointLayoutDevicePix() const;
DesktopIntPoint ScreenPointDesktopPix() const;
CSSIntPoint PagePoint() const;
int32_t PageX() const { return PagePoint().x; }
int32_t PageY() const { return PagePoint().y; }
/**
* Return pageX and pageY values for this event in CSS pixels which are
* client point + scroll position of the root scrollable frame.
* If current setting allows to expose fractional coordinates for the event,
* this returns the fractional values as-is. Otherwise, this returns
* integer values with rounding the computed values. Note that if this
* event is untrusted one and should not expose fractional values, the
* initialized values are floored before computing the values as defined by
* Pointer Events spec.
*/
CSSDoublePoint PagePoint() const;
double PageX() const { return PagePoint().x; }
double PageY() const { return PagePoint().y; }
CSSIntPoint ClientPoint() const;
int32_t ClientX() const { return ClientPoint().x; }
int32_t ClientY() const { return ClientPoint().y; }
/**
* Return clientX and clientY values for this event in CSS pixels.
* If current setting allows to expose fractional coordinates for the event,
* this returns the fractional values as-is. Otherwise, this returns
* integer values with rounding the computed values. Note that if this
* event is untrusted one and should not expose fractional values, the
* initialized values are floored before computing the values as defined by
* Pointer Events spec.
*/
CSSDoublePoint ClientPoint() const;
double ClientX() const { return ClientPoint().x; }
double ClientY() const { return ClientPoint().y; }
CSSIntPoint OffsetPoint() const;
int32_t OffsetX() const { return OffsetPoint().x; }
int32_t OffsetY() const { return OffsetPoint().y; }
/**
* Return offsetX and offsetY values for this event in CSS pixels which are
* offset in the target element.
* If current setting allows to expose fractional coordinates for the event,
* this returns the fractional values as-is. Otherwise, this returns
* integer values with rounding the computed values. Note that if this
* event is untrusted one and should not expose fractional values, the
* initialized values are floored before computing the values as defined by
* Pointer Events spec.
*
* Note that this may flush the pending layout.
*/
MOZ_CAN_RUN_SCRIPT_BOUNDARY CSSDoublePoint OffsetPoint() const;
double OffsetX() const { return OffsetPoint().x; }
double OffsetY() const { return OffsetPoint().y; }
bool CtrlKey();
bool ShiftKey();
@ -70,7 +111,12 @@ class MouseEvent : public UIEvent {
int32_t aScreenX, int32_t aScreenY, int32_t aClientX,
int32_t aClientY, bool aCtrlKey, bool aAltKey,
bool aShiftKey, bool aMetaKey, uint16_t aButton,
EventTarget* aRelatedTarget);
EventTarget* aRelatedTarget) {
InitMouseEventInternal(aType, aCanBubble, aCancelable, aView, aDetail,
aScreenX, aScreenY, aClientX, aClientY, aCtrlKey,
aAltKey, aShiftKey, aMetaKey, aButton,
aRelatedTarget);
}
void InitializeExtraMouseEventDictionaryMembers(const MouseEventInit& aParam);
@ -97,12 +143,49 @@ class MouseEvent : public UIEvent {
protected:
~MouseEvent() = default;
void InitMouseEvent(const nsAString& aType, bool aCanBubble, bool aCancelable,
nsGlobalWindowInner* aView, int32_t aDetail,
int32_t aScreenX, int32_t aScreenY, int32_t aClientX,
int32_t aClientY, int16_t aButton,
EventTarget* aRelatedTarget,
const nsAString& aModifiersList);
nsIntPoint GetMovementPoint() const;
void InitMouseEventInternal(const nsAString& aType, bool aCanBubble,
bool aCancelable, nsGlobalWindowInner* aView,
int32_t aDetail, double aScreenX, double aScreenY,
double aClientX, double aClientY, bool aCtrlKey,
bool aAltKey, bool aShiftKey, bool aMetaKey,
uint16_t aButton, EventTarget* aRelatedTarget);
void InitMouseEventInternal(const nsAString& aType, bool aCanBubble,
bool aCancelable, nsGlobalWindowInner* aView,
int32_t aDetail, double aScreenX, double aScreenY,
double aClientX, double aClientY, int16_t aButton,
EventTarget* aRelatedTarget,
const nsAString& aModifiersList);
// mWidgetRelativePoint stores the reference point of the event within the
// double coordinates. If this is a trusted event, the values are copied from
// mEvent->mRefPoint whose type is LayoutDeviceIntPoint. Therefore, the
// values are always integer. On the other hand, if this is an untrusted
// event, this may store fractional values if and only if the event should
// expose fractional coordinates. Otherwise, this is floored values for the
// backward compatibility.
LayoutDeviceDoublePoint mWidgetRelativePoint;
// If this is a trusted event and after dispatching this, mDefaultClientPoint
// stores the clientX and clientY values at duplicating the data.
// If this is an untrusted event, mDefaultClientPoint stores the clientX and
// clientY inputs. If this event should expose fractional coordinates, the
// values are set as-is. Otherwise, this stores floored input values for
// the backward compatibility.
CSSDoublePoint mDefaultClientPoint;
// If this is a trusted event and after dispatching this, mPagePoint stores
// the pageX and pageY values at duplicating the data.
// If this is an untrusted event, mPagePoint stores the pageX and pageY
// inputs. If this event should expose fractional coordinates, the values are
// set as-is. Otherwise, this stores floored input values for the backward
// compatibility.
CSSDoublePoint mPagePoint;
nsIntPoint mMovementPoint;
bool mUseFractionalCoords = false;
};
} // namespace mozilla::dom

View file

@ -4,10 +4,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "mozilla/dom/MouseScrollEvent.h"
#include "MouseScrollEvent.h"
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/MouseEvents.h"
#include "prtime.h"
namespace mozilla::dom {
@ -30,18 +30,18 @@ MouseScrollEvent::MouseScrollEvent(EventTarget* aOwner,
mDetail = mEvent->AsMouseScrollEvent()->mDelta;
}
void MouseScrollEvent::InitMouseScrollEvent(
void MouseScrollEvent::InitMouseScrollEventInternal(
const nsAString& aType, bool aCanBubble, bool aCancelable,
nsGlobalWindowInner* aView, int32_t aDetail, int32_t aScreenX,
int32_t aScreenY, int32_t aClientX, int32_t aClientY, bool aCtrlKey,
nsGlobalWindowInner* aView, int32_t aDetail, double aScreenX,
double aScreenY, double aClientX, double aClientY, bool aCtrlKey,
bool aAltKey, bool aShiftKey, bool aMetaKey, uint16_t aButton,
EventTarget* aRelatedTarget, int32_t aAxis) {
NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
MouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView, aDetail,
aScreenX, aScreenY, aClientX, aClientY, aCtrlKey,
aAltKey, aShiftKey, aMetaKey, aButton,
aRelatedTarget);
MouseEvent::InitMouseEventInternal(aType, aCanBubble, aCancelable, aView,
aDetail, aScreenX, aScreenY, aClientX,
aClientY, aCtrlKey, aAltKey, aShiftKey,
aMetaKey, aButton, aRelatedTarget);
mEvent->AsMouseScrollEvent()->mIsHorizontal =
(aAxis == MouseScrollEvent_Binding::HORIZONTAL_AXIS);
}

View file

@ -32,10 +32,24 @@ class MouseScrollEvent : public MouseEvent {
int32_t aClientX, int32_t aClientY, bool aCtrlKey,
bool aAltKey, bool aShiftKey, bool aMetaKey,
uint16_t aButton, EventTarget* aRelatedTarget,
int32_t aAxis);
int32_t aAxis) {
InitMouseScrollEventInternal(aType, aCanBubble, aCancelable, aView, aDetail,
aScreenX, aScreenY, aClientX, aClientY,
aCtrlKey, aAltKey, aShiftKey, aMetaKey,
aButton, aRelatedTarget, aAxis);
}
protected:
~MouseScrollEvent() = default;
void InitMouseScrollEventInternal(const nsAString& aType, bool aCanBubble,
bool aCancelable,
nsGlobalWindowInner* aView, int32_t aDetail,
double aScreenX, double aScreenY,
double aClientX, double aClientY,
bool aCtrlKey, bool aAltKey, bool aShiftKey,
bool aMetaKey, uint16_t aButton,
EventTarget* aRelatedTarget, int32_t aAxis);
};
} // namespace mozilla::dom

View file

@ -117,10 +117,10 @@ already_AddRefed<PointerEvent> PointerEvent::Constructor(
RefPtr<PointerEvent> e = new PointerEvent(aOwner, nullptr, nullptr);
bool trusted = e->Init(aOwner);
e->InitMouseEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
aParam.mDetail, aParam.mScreenX, aParam.mScreenY,
aParam.mClientX, aParam.mClientY, false, false, false,
false, aParam.mButton, aParam.mRelatedTarget);
e->InitMouseEventInternal(
aType, aParam.mBubbles, aParam.mCancelable, aParam.mView, aParam.mDetail,
aParam.mScreenX, aParam.mScreenY, aParam.mClientX, aParam.mClientY, false,
false, false, false, aParam.mButton, aParam.mRelatedTarget);
e->InitializeExtraMouseEventDictionaryMembers(aParam);
e->mPointerType = Some(aParam.mPointerType);
@ -246,12 +246,12 @@ int32_t PointerEvent::PointerId() {
: mEvent->AsPointerEvent()->pointerId;
}
int32_t PointerEvent::Width() {
return ShouldResistFingerprinting() ? 1 : mEvent->AsPointerEvent()->mWidth;
double PointerEvent::Width() const {
return ShouldResistFingerprinting() ? 1.0 : mEvent->AsPointerEvent()->mWidth;
}
int32_t PointerEvent::Height() {
return ShouldResistFingerprinting() ? 1 : mEvent->AsPointerEvent()->mHeight;
double PointerEvent::Height() const {
return ShouldResistFingerprinting() ? 1.0 : mEvent->AsPointerEvent()->mHeight;
}
float PointerEvent::Pressure() {

View file

@ -41,8 +41,8 @@ class PointerEvent : public MouseEvent {
PointerEvent* AsPointerEvent() final { return this; }
int32_t PointerId();
int32_t Width();
int32_t Height();
double Width() const;
double Height() const;
float Pressure();
float TangentialPressure();
int32_t TiltX();

View file

@ -4,10 +4,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SimpleGestureEvent.h"
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/dom/SimpleGestureEvent.h"
#include "mozilla/TouchEvents.h"
#include "prtime.h"
namespace mozilla::dom {
@ -51,19 +51,19 @@ uint32_t SimpleGestureEvent::ClickCount() const {
return mEvent->AsSimpleGestureEvent()->mClickCount;
}
void SimpleGestureEvent::InitSimpleGestureEvent(
void SimpleGestureEvent::InitSimpleGestureEventInternal(
const nsAString& aTypeArg, bool aCanBubbleArg, bool aCancelableArg,
nsGlobalWindowInner* aViewArg, int32_t aDetailArg, int32_t aScreenX,
int32_t aScreenY, int32_t aClientX, int32_t aClientY, bool aCtrlKeyArg,
nsGlobalWindowInner* aViewArg, int32_t aDetailArg, double aScreenX,
double aScreenY, double aClientX, double aClientY, bool aCtrlKeyArg,
bool aAltKeyArg, bool aShiftKeyArg, bool aMetaKeyArg, uint16_t aButton,
EventTarget* aRelatedTarget, uint32_t aAllowedDirectionsArg,
uint32_t aDirectionArg, double aDeltaArg, uint32_t aClickCountArg) {
NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
MouseEvent::InitMouseEvent(aTypeArg, aCanBubbleArg, aCancelableArg, aViewArg,
aDetailArg, aScreenX, aScreenY, aClientX, aClientY,
aCtrlKeyArg, aAltKeyArg, aShiftKeyArg, aMetaKeyArg,
aButton, aRelatedTarget);
MouseEvent::InitMouseEventInternal(
aTypeArg, aCanBubbleArg, aCancelableArg, aViewArg, aDetailArg, aScreenX,
aScreenY, aClientX, aClientY, aCtrlKeyArg, aAltKeyArg, aShiftKeyArg,
aMetaKeyArg, aButton, aRelatedTarget);
WidgetSimpleGestureEvent* simpleGestureEvent = mEvent->AsSimpleGestureEvent();
simpleGestureEvent->mAllowedDirections = aAllowedDirectionsArg;

View file

@ -41,10 +41,23 @@ class SimpleGestureEvent : public MouseEvent {
bool aShiftKey, bool aMetaKey, uint16_t aButton,
EventTarget* aRelatedTarget,
uint32_t aAllowedDirections, uint32_t aDirection,
double aDelta, uint32_t aClickCount);
double aDelta, uint32_t aClickCount) {
InitSimpleGestureEventInternal(
aType, aCanBubble, aCancelable, aView, aDetail, aScreenX, aScreenY,
aClientX, aClientY, aCtrlKey, aAltKey, aShiftKey, aMetaKey, aButton,
aRelatedTarget, aAllowedDirections, aDirection, aDelta, aClickCount);
}
protected:
~SimpleGestureEvent() = default;
void InitSimpleGestureEventInternal(
const nsAString& aType, bool aCanBubble, bool aCancelable,
nsGlobalWindowInner* aView, int32_t aDetail, double aScreenX,
double aScreenY, double aClientX, double aClientY, bool aCtrlKey,
bool aAltKey, bool aShiftKey, bool aMetaKey, uint16_t aButton,
EventTarget* aRelatedTarget, uint32_t aAllowedDirections,
uint32_t aDirection, double aDelta, uint32_t aClickCount);
};
} // namespace mozilla::dom

View file

@ -187,12 +187,12 @@ void Touch::InitializePoints(nsPresContext* aPresContext, WidgetEvent* aEvent) {
if (mPointsInitialized) {
return;
}
mClientPoint =
Event::GetClientCoords(aPresContext, aEvent, mRefPoint, mClientPoint);
mPagePoint =
Event::GetPageCoords(aPresContext, aEvent, mRefPoint, mClientPoint);
mScreenPoint =
Event::GetScreenCoords(aPresContext, aEvent, mRefPoint).extract();
mClientPoint = RoundedToInt(
Event::GetClientCoords(aPresContext, aEvent, mRefPoint, mClientPoint));
mPagePoint = RoundedToInt(
Event::GetPageCoords(aPresContext, aEvent, mRefPoint, mClientPoint));
mScreenPoint = RoundedToInt(
Event::GetScreenCoords(aPresContext, aEvent, mRefPoint).extract());
mPointsInitialized = true;
}

View file

@ -30,10 +30,7 @@ UIEvent::UIEvent(EventTarget* aOwner, nsPresContext* aPresContext,
WidgetGUIEvent* aEvent)
: Event(aOwner, aPresContext,
aEvent ? aEvent : new InternalUIEvent(false, eVoidEvent, nullptr)),
mDefaultClientPoint(0, 0),
mLayerPoint(0, 0),
mPagePoint(0, 0),
mMovementPoint(0, 0) {
mLayerPoint(0, 0) {
if (aEvent) {
mEventIsInternal = false;
} else {
@ -90,34 +87,6 @@ NS_IMPL_RELEASE_INHERITED(UIEvent, Event)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(UIEvent)
NS_INTERFACE_MAP_END_INHERITING(Event)
static nsIntPoint DevPixelsToCSSPixels(const LayoutDeviceIntPoint& aPoint,
nsPresContext* aContext) {
return nsIntPoint(aContext->DevPixelsToIntCSSPixels(aPoint.x),
aContext->DevPixelsToIntCSSPixels(aPoint.y));
}
nsIntPoint UIEvent::GetMovementPoint() {
if (mEvent->mFlags.mIsPositionless) {
return nsIntPoint(0, 0);
}
if (mPrivateDataDuplicated || mEventIsInternal) {
return mMovementPoint;
}
if (!mEvent || !mEvent->AsGUIEvent()->mWidget ||
(mEvent->mMessage != eMouseMove && mEvent->mMessage != ePointerMove)) {
// Pointer Lock spec defines that movementX/Y must be zero for all mouse
// events except mousemove.
return nsIntPoint(0, 0);
}
// Calculate the delta between the last screen point and the current one.
nsIntPoint current = DevPixelsToCSSPixels(mEvent->mRefPoint, mPresContext);
nsIntPoint last = DevPixelsToCSSPixels(mEvent->mLastRefPoint, mPresContext);
return current - last;
}
void UIEvent::InitUIEvent(const nsAString& typeArg, bool canBubbleArg,
bool cancelableArg, nsGlobalWindowInner* viewArg,
int32_t detailArg) {
@ -187,16 +156,12 @@ nsIntPoint UIEvent::GetLayerPoint() const {
}
void UIEvent::DuplicatePrivateData() {
mDefaultClientPoint = Event::GetClientCoords(
mPresContext, mEvent, mEvent->mRefPoint, mDefaultClientPoint);
mMovementPoint = GetMovementPoint();
mLayerPoint = GetLayerPoint();
mPagePoint = Event::GetPageCoords(mPresContext, mEvent, mEvent->mRefPoint,
mDefaultClientPoint);
// GetScreenPoint converts mEvent->mRefPoint to right coordinates.
CSSIntPoint screenPoint =
const CSSIntPoint screenPoint = RoundedToInt(
Event::GetScreenCoords(mPresContext, mEvent, mEvent->mRefPoint)
.valueOr(CSSIntPoint{0, 0});
.valueOr(CSSIntPoint{0, 0}));
Event::DuplicatePrivateData();

View file

@ -97,16 +97,11 @@ class UIEvent : public Event {
~UIEvent() = default;
// Internal helper functions
nsIntPoint GetMovementPoint();
nsIntPoint GetLayerPoint() const;
nsCOMPtr<nsPIDOMWindowOuter> mView;
int32_t mDetail;
CSSIntPoint mDefaultClientPoint;
// Screenpoint is mEvent->mRefPoint.
nsIntPoint mLayerPoint;
CSSIntPoint mPagePoint;
nsIntPoint mMovementPoint;
static Modifiers ComputeModifierState(const nsAString& aModifiersList);
bool GetModifierStateInternal(const nsAString& aKey);

View file

@ -4,10 +4,10 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WheelEvent.h"
#include "mozilla/dom/MouseEventBinding.h"
#include "mozilla/dom/WheelEvent.h"
#include "mozilla/MouseEvents.h"
#include "prtime.h"
namespace mozilla::dom {
@ -35,17 +35,17 @@ WheelEvent::WheelEvent(EventTarget* aOwner, nsPresContext* aPresContext,
}
}
void WheelEvent::InitWheelEvent(
void WheelEvent::InitWheelEventInternal(
const nsAString& aType, bool aCanBubble, bool aCancelable,
nsGlobalWindowInner* aView, int32_t aDetail, int32_t aScreenX,
int32_t aScreenY, int32_t aClientX, int32_t aClientY, uint16_t aButton,
nsGlobalWindowInner* aView, int32_t aDetail, double aScreenX,
double aScreenY, double aClientX, double aClientY, uint16_t aButton,
EventTarget* aRelatedTarget, const nsAString& aModifiersList,
double aDeltaX, double aDeltaY, double aDeltaZ, uint32_t aDeltaMode) {
NS_ENSURE_TRUE_VOID(!mEvent->mFlags.mIsBeingDispatched);
MouseEvent::InitMouseEvent(aType, aCanBubble, aCancelable, aView, aDetail,
aScreenX, aScreenY, aClientX, aClientY, aButton,
aRelatedTarget, aModifiersList);
MouseEvent::InitMouseEventInternal(
aType, aCanBubble, aCancelable, aView, aDetail, aScreenX, aScreenY,
aClientX, aClientY, aButton, aRelatedTarget, aModifiersList);
WidgetWheelEvent* wheelEvent = mEvent->AsWheelEvent();
// When specified by the caller (for JS-created events), don't mess with the
@ -154,11 +154,11 @@ already_AddRefed<WheelEvent> WheelEvent::Constructor(
nsCOMPtr<EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
RefPtr<WheelEvent> e = new WheelEvent(t, nullptr, nullptr);
bool trusted = e->Init(t);
e->InitWheelEvent(aType, aParam.mBubbles, aParam.mCancelable, aParam.mView,
aParam.mDetail, aParam.mScreenX, aParam.mScreenY,
aParam.mClientX, aParam.mClientY, aParam.mButton,
aParam.mRelatedTarget, u""_ns, aParam.mDeltaX,
aParam.mDeltaY, aParam.mDeltaZ, aParam.mDeltaMode);
e->InitWheelEventInternal(
aType, aParam.mBubbles, aParam.mCancelable, aParam.mView, aParam.mDetail,
aParam.mScreenX, aParam.mScreenY, aParam.mClientX, aParam.mClientY,
aParam.mButton, aParam.mRelatedTarget, u""_ns, aParam.mDeltaX,
aParam.mDeltaY, aParam.mDeltaZ, aParam.mDeltaMode);
e->InitializeExtraMouseEventDictionaryMembers(aParam);
e->SetTrusted(trusted);
e->SetComposed(aParam.mComposed);

View file

@ -61,11 +61,25 @@ class WheelEvent : public MouseEvent {
int32_t aClientY, uint16_t aButton,
EventTarget* aRelatedTarget,
const nsAString& aModifiersList, double aDeltaX,
double aDeltaY, double aDeltaZ, uint32_t aDeltaMode);
double aDeltaY, double aDeltaZ, uint32_t aDeltaMode) {
InitWheelEventInternal(aType, aCanBubble, aCancelable, aView, aDetail,
aScreenX, aScreenY, aClientX, aClientY, aButton,
aRelatedTarget, aModifiersList, aDeltaX, aDeltaY,
aDeltaZ, aDeltaMode);
}
protected:
~WheelEvent() = default;
void InitWheelEventInternal(const nsAString& aType, bool aCanBubble,
bool aCancelable, nsGlobalWindowInner* aView,
int32_t aDetail, double aScreenX, double aScreenY,
double aClientX, double aClientY,
uint16_t aButton, EventTarget* aRelatedTarget,
const nsAString& aModifiersList, double aDeltaX,
double aDeltaY, double aDeltaZ,
uint32_t aDeltaMode);
double ToWebExposedDelta(WidgetWheelEvent&, double aDelta,
nscoord aLineOrPageAmount, CallerType);

View file

@ -11,8 +11,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1303957
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1303957">Mozilla Bug 1303957</a>
<p id="display"></p>
<!-- DO NOT PUT any text before the test target to avoid fractional coordinates! -->
<div id="target0" style="width: 50px; height: 50px; background: green"></div>
<script type="text/javascript">
/** Test for Bug 1303957 **/
@ -33,8 +32,24 @@ SimpleTest.waitForFocus(async () => {
ok(length >= 1, "Coalesced events should >= 1, got " + length);
let rect = target0.getBoundingClientRect();
let prevOffsetX = 0;
let prevOffsetY = 0;
let prevOffsetX = undefined;
let prevOffsetY = undefined;
function isExpectedOffset(aNewOffset, aPrevOffset) {
if (aPrevOffset === undefined) {
const roundedOffset = 5 * Math.max(Math.round(aNewOffset / 5), 1);
return aNewOffset >= roundedOffset - 1 && aNewOffset <= roundedOffset + 1;
}
let candidateOffset = aPrevOffset + 5;
while (candidateOffset < 25) {
// Allow rounding issue.
if (aNewOffset >= candidateOffset - 0.1 && aNewOffset <= candidateOffset + 0.1) {
return true;
}
candidateOffset += 5;
}
return false;
}
for (let i = 0; i < length; ++i) {
let coalescedEvent = ev.getCoalescedEvents()[i];
@ -49,13 +64,18 @@ SimpleTest.waitForFocus(async () => {
is(coalescedEvent.cancelable, false, "getCoalescedEvents()[" + i + "].cancelable");
is(coalescedEvent.bubbles, false, "getCoalescedEvents()[" + i + "].bubbles");
ok(coalescedEvent.offsetX >= prevOffsetX, "getCoalescedEvents()[" + i + "].offsetX = " + coalescedEvent.offsetX);
ok(coalescedEvent.offsetX == 5 || coalescedEvent.offsetX == 10 ||
coalescedEvent.offsetX == 15 || coalescedEvent.offsetX == 20, "expected offsetX");
ok(coalescedEvent.offsetY >= prevOffsetY, "getCoalescedEvents()[" + i + "].offsetY = " + coalescedEvent.offsetY);
ok(coalescedEvent.offsetY == 5 || coalescedEvent.offsetY == 10 ||
coalescedEvent.offsetY == 15 || coalescedEvent.offsetY == 20, "expected offsetY");
ok(
isExpectedOffset(coalescedEvent.offsetX, prevOffsetX),
`getCoalescedEvents()[${i}].offsetX (${
coalescedEvent.offsetX
}) should be 5 * n + previous offsetX (${prevOffsetX})`
);
ok(
isExpectedOffset(coalescedEvent.offsetY, prevOffsetY),
`getCoalescedEvents()[${i}].offsetY (${
coalescedEvent.offsetY
}) should be 5 * n + previous offsetY (${prevOffsetY})`
);
prevOffsetX = coalescedEvent.offsetX;
prevOffsetY = coalescedEvent.offsetY;
@ -70,6 +90,14 @@ SimpleTest.waitForFocus(async () => {
}, { once: true });
});
info(`mozInnerScreen={${SpecialPowers.wrap(window).mozInnerScreenX}, ${SpecialPowers.wrap(window).mozInnerScreenY}}`);
info(`devicePixelRatio=${window.devicePixelRatio}`);
try {
info(`top.mozInnerScreen={${SpecialPowers.wrap(window.top).mozInnerScreenX}, ${SpecialPowers.wrap(window.top).mozInnerScreenY}}`);
info(`top.getResolution()=${SpecialPowers.wrap(window.top).windowUtils.getResolution()}`);
} catch (e) {}
info(`target0.getBoundingClientRect()={${target0.getBoundingClientRect().x}, ${target0.getBoundingClientRect().y}}`);
info("Synthesizing native mouse moves....");
await promiseNativeMouseEvent({ type: "mousemove", target: target0, offsetX: 5, offsetY: 5 });
await promiseNativeMouseEvent({ type: "mousemove", target: target0, offsetX: 10, offsetY: 10 });

View file

@ -58,6 +58,7 @@
#include "mozilla/Unused.h"
#include "Fetch.h"
#include "FetchLog.h"
#include "FetchUtil.h"
#include "InternalRequest.h"
#include "InternalResponse.h"
@ -261,6 +262,8 @@ AlternativeDataStreamListener::OnDataAvailable(nsIRequest* aRequest,
nsIInputStream* aInputStream,
uint64_t aOffset,
uint32_t aCount) {
FETCH_LOG(
("FetchDriver::OnDataAvailable this=%p, request=%p", this, aRequest));
if (mStatus == AlternativeDataStreamListener::LOADING) {
MOZ_ASSERT(mPipeAlternativeOutputStream);
uint32_t read = 0;
@ -1047,6 +1050,8 @@ void FetchDriver::FailWithNetworkError(nsresult rv) {
NS_IMETHODIMP
FetchDriver::OnStartRequest(nsIRequest* aRequest) {
FETCH_LOG(
("FetchDriver::OnStartRequest this=%p, request=%p", this, aRequest));
AssertIsOnMainThread();
// Note, this can be called multiple times if we are doing an opaqueredirect.
@ -1353,6 +1358,19 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest) {
return NS_OK;
}
// Only retarget if not already retargeted
nsCOMPtr<nsISerialEventTarget> target;
nsCOMPtr<nsIThreadRetargetableRequest> req = do_QueryInterface(aRequest);
if (req) {
rv = req->GetDeliveryTarget(getter_AddRefs(target));
if (NS_SUCCEEDED(rv) && target && !target->IsOnCurrentThread()) {
FETCH_LOG(
("FetchDriver::OnStartRequest this=%p, request=%p already retargeted",
this, aRequest));
return NS_OK;
}
}
nsCOMPtr<nsIEventTarget> sts =
do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -1361,6 +1379,7 @@ FetchDriver::OnStartRequest(nsIRequest* aRequest) {
return rv;
}
FETCH_LOG(("FetchDriver retargeting: request %p", aRequest));
// Try to retarget off main thread.
if (nsCOMPtr<nsIThreadRetargetableRequest> rr = do_QueryInterface(aRequest)) {
RefPtr<TaskQueue> queue =
@ -1510,6 +1529,7 @@ FetchDriver::OnDataAvailable(nsIRequest* aRequest, nsIInputStream* aInputStream,
NS_IMETHODIMP
FetchDriver::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
FETCH_LOG(("FetchDriver::OnStopRequest this=%p, request=%p", this, aRequest));
AssertIsOnMainThread();
MOZ_DIAGNOSTIC_ASSERT(!mOnStopRequestCalled);

View file

@ -3361,7 +3361,7 @@ void HTMLInputElement::LegacyPreActivationBehavior(
if (aVisitor.mDOMEvent) {
if (auto* mouseEvent = aVisitor.mDOMEvent->AsMouseEvent()) {
CSSIntPoint pt = mouseEvent->OffsetPoint();
const CSSIntPoint pt = RoundedToInt(mouseEvent->OffsetPoint());
if (auto* imageClickedPoint = static_cast<CSSIntPoint*>(
GetProperty(nsGkAtoms::imageClickedPoint))) {
// Ensures that a dispatched event's clicked point is not the default

View file

@ -1574,8 +1574,15 @@ MediaResult FFmpegVideoDecoder<LIBAV_VER>::CreateImageVAAPI(
return MediaResult(NS_ERROR_DOM_MEDIA_DECODE_ERR,
RESULT_DETAIL("VAAPI dmabuf allocation error"));
}
surface->SetYUVColorSpace(GetFrameColorSpace());
surface->SetColorRange(GetFrameColorRange());
if (mInfo.mColorPrimaries) {
surface->SetColorPrimaries(mInfo.mColorPrimaries.value());
}
if (mInfo.mTransferFunction) {
surface->SetTransferFunction(mInfo.mTransferFunction.value());
}
RefPtr<VideoData> vp = VideoData::CreateFromImage(
mInfo.mDisplay, aOffset, TimeUnit::FromMicroseconds(aPts),

View file

@ -71,6 +71,12 @@ class VideoFrameSurface<LIBAV_VER> {
void SetColorRange(mozilla::gfx::ColorRange aColorRange) {
mSurface->GetAsDMABufSurfaceYUV()->SetColorRange(aColorRange);
}
void SetColorPrimaries(mozilla::gfx::ColorSpace2 aColorPrimaries) {
mSurface->GetAsDMABufSurfaceYUV()->SetColorPrimaries(aColorPrimaries);
}
void SetTransferFunction(mozilla::gfx::TransferFunction aTransferFunction) {
mSurface->GetAsDMABufSurfaceYUV()->SetTransferFunction(aTransferFunction);
}
RefPtr<DMABufSurfaceYUV> GetDMABufSurface() {
return mSurface->GetAsDMABufSurfaceYUV();

View file

@ -0,0 +1,240 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
import argparse
import hashlib
import re
from datetime import datetime
from urllib.parse import urlparse
from xml.etree import ElementTree
import requests
def check_hash(plugin, url, valid_urls):
if url in valid_urls:
return
valid_urls[url] = True
response = requests.get(url)
response.raise_for_status()
if "hashValue" in plugin.attrib:
hashValue = hashlib.sha512(response.content).hexdigest()
if hashValue != plugin.attrib["hashValue"]:
raise Exception(
"Given hash {} and calculated hash {} differ",
plugin.attrib["hashValue"],
hashValue,
)
if "size" in plugin.attrib:
size = len(response.content)
if size != int(plugin.attrib["size"]):
raise Exception(
"Given size {} and calculated size {} differ",
int(plugin.attrib["size"]),
size,
)
def fetch_balrog_xml(
url_base: str, plugin_id, version: str, buildid: str, channels, targets, checkHash
) -> str:
url = "{url_base}/{version}/{buildid}/{target}/en-US/{channel}/default/default/default/update.xml"
valid_urls = {}
results = {}
for channel in channels:
results[channel] = {}
for target in targets:
balrog_url = url.format_map(
{
"url_base": url_base,
"buildid": buildid,
"channel": channel,
"version": version,
"target": target,
}
)
response = requests.get(balrog_url)
response.raise_for_status()
plugin_urls = []
tree = ElementTree.fromstring(response.content)
for plugin in tree.findall("./addons/addon"):
if not "id" in plugin.attrib:
continue
if plugin.attrib["id"] != plugin_id:
continue
if "URL" in plugin.attrib:
if checkHash:
check_hash(plugin, plugin.attrib["URL"], valid_urls)
plugin_urls.append(plugin.attrib["URL"])
for mirror in plugin.findall("./mirror"):
if "URL" in mirror.attrib:
if checkHash:
check_hash(plugin, plugin.attrib["URL"], valid_urls)
plugin_urls.append(mirror.attrib["URL"])
results[channel][target] = plugin_urls
matching_channels = {}
for channel in channels:
matching_channels[channel] = [channel]
for other_channel in channels:
if (
channel == other_channel
or channel not in results
or other_channel not in results
):
continue
if results[channel] == results[other_channel]:
matching_channels[channel].append(other_channel)
del results[other_channel]
for channel in results:
print(", ".join(matching_channels[channel]))
for target in targets:
print("\t{}".format(target))
for url in results[channel][target]:
print("\t\t{}".format(url))
def main():
examples = """examples:
python dom/media/tools/checkGmpBalrog.py widevine 133.0
python dom/media/tools/checkGmpBalrog.py widevine 133.0 --target Darwin_aarch64-gcc3 Darwin_x86_64-gcc3
python dom/media/tools/checkGmpBalrog.py --url http://localhost:8080 openh264 125.0
python dom/media/tools/checkGmpBalrog.py widevine_l1 115.14.0 --staging --channel nightly beta"""
parser = argparse.ArgumentParser(
description="Check Balrog XML for GMP plugin updates",
epilog=examples,
formatter_class=argparse.RawDescriptionHelpFormatter,
)
parser.add_argument(
"plugin",
help="which plugin: openh264, widevine, widevine_l1",
)
parser.add_argument("version", help="version of Firefox")
parser.add_argument(
"--channel", action="extend", nargs="+", help="check specific channel(s)"
)
parser.add_argument(
"--list-channels", action="store_true", help="list the supported channels"
)
parser.add_argument(
"--target", action="extend", nargs="+", help="check specific target(s)"
)
parser.add_argument(
"--list-targets", action="store_true", help="list the supported targets"
)
parser.add_argument("--buildid", help="override generated build ID to be specific")
parser.add_argument(
"--url", help="override base URL from which to fetch the balrog configuration"
)
parser.add_argument(
"--staging",
action="store_true",
help="using the balrog staging URL instead of production",
)
parser.add_argument(
"--checkHash",
action="store_true",
help="download plugins and validate the size/hash",
)
args = parser.parse_args()
valid_channels = ["esr", "release", "beta", "nightly", "nightlytest"]
if args.list_channels:
for channel in valid_channels:
print(channel)
return
if args.channel is not None:
for channel in args.channel:
if channel not in valid_channels:
parser.error("`%s` is invalid, see --list-channels" % channel)
return
channels = args.channel
else:
channels = valid_channels
valid_targets = [
"Darwin_aarch64-gcc3",
"Darwin_x86_64-gcc3",
"Linux_aarch64-gcc3",
"Linux_x86-gcc3",
"Linux_x86_64-gcc3",
"WINNT_aarch64-msvc-aarch64",
"WINNT_x86-msvc",
"WINNT_x86_64-msvc",
]
valid_aliases = [
"Linux_x86_64-gcc3-asan",
"WINNT_x86-msvc-x64",
"WINNT_x86-msvc-x86",
"WINNT_x86_64-msvc-x64",
"WINNT_x86_64-msvc-x64-asan",
]
if args.list_targets:
for target in valid_targets:
print(target)
for target in valid_aliases:
print("%s (alias)" % target)
return
if args.target is not None:
for target in args.target:
if target not in valid_targets and target not in valid_aliases:
parser.error("`%s` is invalid, see --list-targets" % target)
return
targets = args.target
else:
targets = valid_targets
if args.buildid is not None:
if not re.match(r"^\d{14}$", args.buildid):
parser.error("`%s` is invalid, build id must be 14 digits")
return
buildid = args.buildid
else:
buildid = datetime.today().strftime("%y%m%d%H%M%S")
url_base = "https://aus5.mozilla.org"
if args.staging:
url_base = "https://stage.balrog.nonprod.cloudops.mozgcp.net"
if args.url is not None:
url_base = args.url
if url_base[-1] == "/":
url_base = url_base[:-1]
url_base += "/update/3/GMP"
parsed_url = urlparse(url_base)
if parsed_url.scheme not in ("http", "https"):
parser.error("expected http(s) scheme, got `%s`" % parsed_url.scheme)
return
if parsed_url.path != "/update/3/GMP":
parser.error("expected url path of `/update/3/GMP`, got `%s`" % parsed_url.path)
return
if args.plugin == "openh264":
plugin = "gmp-gmpopenh264"
elif args.plugin == "widevine":
plugin = "gmp-widevinecdm"
elif args.plugin == "widevine_l1":
plugin = "gmp-widevinecdm-l1"
else:
parser.error("plugin not recognized")
return
if not re.match(r"^\d+\.\d+(\.\d+)?$", args.version):
parser.error("version must be of the form ###.###(.###)")
return
fetch_balrog_xml(
url_base, plugin, args.version, buildid, channels, targets, args.checkHash
)
main()

View file

@ -1491,17 +1491,6 @@ bool nsContentSecurityUtils::ValidateScriptFilename(JSContext* cx,
}
}
auto kAllowedFilenamesExact = {
// Allow through the injection provided by about:sync addon
"data:,new function() {\n const { AboutSyncRedirector } = ChromeUtils.import(\"chrome://aboutsync/content/AboutSyncRedirector.js\");\n AboutSyncRedirector.register();\n}"_ns,
};
for (auto allowedFilename : kAllowedFilenamesExact) {
if (filename == allowedFilename) {
return true;
}
}
auto kAllowedFilenamesPrefix = {
// Until 371900 is fixed, we need to do something about about:downloads
// and this is the most reasonable. See 1727770

View file

@ -198,6 +198,13 @@ static bool WindowCannotReceiveSensorEvent(nsPIDOMWindowInner* aWindow) {
nsPIDOMWindowOuter* windowOuter = aWindow->GetOuterWindow();
BrowsingContext* topBC = aWindow->GetBrowsingContext()->Top();
if (windowOuter->IsBackground() || !topBC->GetIsActiveBrowserWindow()) {
nsGlobalWindowInner* win = nsGlobalWindowInner::Cast(aWindow);
nsIPrincipal* principal = win->GetPrincipal();
if (principal &&
principal->Equals(
nsContentUtils::GetFingerprintingProtectionPrincipal())) {
return false;
}
return true;
}

View file

@ -328,6 +328,7 @@ nsTArray<uint8_t> NSDataToArray(NSData* data) {
switch (platformCredential.attachment) {
case ASAuthorizationPublicKeyCredentialAttachmentCrossPlatform:
authenticatorAttachment.emplace(u"cross-platform"_ns);
transports.AppendElement(u"hybrid"_ns);
break;
case ASAuthorizationPublicKeyCredentialAttachmentPlatform:
authenticatorAttachment.emplace(u"platform"_ns);

View file

@ -299,9 +299,11 @@ WinWebAuthnService::MakeCredential(uint64_t aTransactionId,
DWORD winUserVerificationReq =
WEBAUTHN_USER_VERIFICATION_REQUIREMENT_ANY;
// Resident Key
BOOL winRequireResidentKey = FALSE;
BOOL winPreferResidentKey = FALSE;
// Resident Key Requirement.
BOOL winRequireResidentKey = FALSE; // Will be set to TRUE if and only
// if residentKey = "required"
BOOL winPreferResidentKey = FALSE; // Will be set to TRUE if and only
// if residentKey = "preferred"
// AttestationConveyance
DWORD winAttestation = WEBAUTHN_ATTESTATION_CONVEYANCE_PREFERENCE_ANY;
@ -391,7 +393,7 @@ WinWebAuthnService::MakeCredential(uint64_t aTransactionId,
if (residentKey.EqualsLiteral(
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_REQUIRED)) {
winRequireResidentKey = TRUE;
winPreferResidentKey = TRUE;
winPreferResidentKey = FALSE;
} else if (residentKey.EqualsLiteral(
MOZ_WEBAUTHN_RESIDENT_KEY_REQUIREMENT_PREFERRED)) {
winRequireResidentKey = FALSE;

View file

@ -24,7 +24,7 @@ interface DOMParser {
constructor();
[NewObject, Throws, UseCounter]
Document parseFromString(DOMString str, SupportedType type);
Document parseFromString((TrustedHTML or DOMString) str, SupportedType type);
[NewObject, ChromeOnly, Throws]
Document parseFromSafeString(DOMString str, SupportedType type);

View file

@ -19,23 +19,23 @@ interface MouseEvent : UIEvent {
optional MouseEventInit mouseEventInitDict = {});
[NeedsCallerType]
readonly attribute long screenX;
readonly attribute double screenX;
[NeedsCallerType]
readonly attribute long screenY;
readonly attribute double screenY;
[ChromeOnly]
readonly attribute nsIScreen? screen;
readonly attribute long pageX;
readonly attribute long pageY;
readonly attribute long clientX;
readonly attribute long clientY;
readonly attribute double pageX;
readonly attribute double pageY;
readonly attribute double clientX;
readonly attribute double clientY;
[BinaryName="clientX"]
readonly attribute long x;
readonly attribute double x;
[BinaryName="clientY"]
readonly attribute long y;
readonly attribute long offsetX;
readonly attribute long offsetY;
readonly attribute double y;
readonly attribute double offsetX;
readonly attribute double offsetY;
readonly attribute boolean ctrlKey;
readonly attribute boolean shiftKey;
readonly attribute boolean altKey;
@ -72,10 +72,10 @@ interface MouseEvent : UIEvent {
// Suggested initMouseEvent replacement initializer:
dictionary MouseEventInit : EventModifierInit {
// Attributes for MouseEvent:
long screenX = 0;
long screenY = 0;
long clientX = 0;
long clientY = 0;
double screenX = 0.0;
double screenY = 0.0;
double clientX = 0.0;
double clientY = 0.0;
short button = 0;
// Note: "buttons" was not previously initializable through initMouseEvent!
unsigned short buttons = 0;

View file

@ -14,8 +14,8 @@ interface PointerEvent : MouseEvent
readonly attribute long pointerId;
readonly attribute long width;
readonly attribute long height;
readonly attribute double width;
readonly attribute double height;
readonly attribute float pressure;
readonly attribute float tangentialPressure;
readonly attribute long tiltX;
@ -35,8 +35,8 @@ interface PointerEvent : MouseEvent
dictionary PointerEventInit : MouseEventInit
{
long pointerId = 0;
long width = 1;
long height = 1;
double width = 1.0;
double height = 1.0;
float pressure = 0;
float tangentialPressure = 0;
long tiltX;

View file

@ -274,7 +274,8 @@ nsresult nsXULPopupListener::LaunchPopup(MouseEvent* aEvent) {
pm->ShowPopup(mPopupContent, mElement, u""_ns, 0, 0, false, true, false,
aEvent);
} else {
CSSIntPoint pos = aEvent->ScreenPoint(CallerType::System);
const CSSIntPoint pos =
RoundedToInt(aEvent->ScreenPoint(CallerType::System));
pm->ShowPopupAtScreen(mPopupContent, pos.x, pos.y, mIsContext, aEvent);
}

Some files were not shown because too many files have changed in this diff Show more