Merge mozilla-central to mozilla-inbound

This commit is contained in:
arthur.iakab 2019-03-08 00:19:35 +02:00
Родитель 1c7ca16c50 85ad02d41a
Коммит eba6cadac2
839 изменённых файлов: 30012 добавлений и 7014 удалений

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

@ -96,14 +96,16 @@
<description id="cfr-notification-author"></description>
</popupnotificationcontent>
<popupnotificationfooter id="cfr-notification-footer" orient="vertical">
<description id="cfr-notification-footer-text"/>
<hbox id="cfr-notification-footer-addon-info">
<hbox id="cfr-notification-footer-filled-stars"/>
<hbox id="cfr-notification-footer-empty-stars"/>
<label id="cfr-notification-footer-users"/>
<spacer id="cfr-notification-footer-spacer" hidden="true"/>
<label id="cfr-notification-footer-learn-more-link" is="text-link"/>
</hbox>
<vbox id="cfr-notification-footer-text-and-addon-info">
<description id="cfr-notification-footer-text"/>
<hbox id="cfr-notification-footer-addon-info">
<hbox id="cfr-notification-footer-filled-stars"/>
<hbox id="cfr-notification-footer-empty-stars"/>
<label id="cfr-notification-footer-users"/>
<spacer id="cfr-notification-footer-spacer" hidden="true"/>
<label id="cfr-notification-footer-learn-more-link" is="text-link"/>
</hbox>
</vbox>
</popupnotificationfooter>
</popupnotification>

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

@ -621,6 +621,7 @@ window._gBrowser = {
this.moveTabTo(aTab, this._numPinnedTabs - 1);
aTab.removeAttribute("pinned");
aTab.style.marginInlineStart = "";
aTab._pinnedUnscrollable = false;
this._updateTabBarForPinnedTabs();
this._notifyPinnedStatus(aTab);
},

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 204 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 107 KiB

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 5.3 KiB

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

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 12"><g fill="none" fill-rule="evenodd" transform="translate(-3 -2)"><path d="M0 0h16v16H0z"/><rect width="3" height="12" x="9.5" y="2" fill="context-fill" rx="1.5"/><rect width="3" height="12" x="3.5" y="2" fill="context-fill" rx="1.5"/></g></svg>

После

Ширина:  |  Высота:  |  Размер: 304 B

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

@ -679,6 +679,11 @@ class SearchOneOffs {
}
_buttonForEngine(engine) {
if (this.telemetryOrigin == "urlbar" && !UrlbarPrefs.get("quantumbar")) {
return this._popup &&
document.getAnonymousElementByAttribute(this._popup, "id", this._buttonIDForEngine(engine));
}
let id = this._buttonIDForEngine(engine);
return this._popup && document.getElementById(id);
}

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

@ -15,10 +15,6 @@ BROWSER_CHROME_MANIFESTS += [
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
TESTING_JS_MODULES += [
'test/browser/SearchTestUtils.jsm',
]
JAR_MANIFESTS += ['jar.mn']
with Files('**'):

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

@ -62,11 +62,13 @@
</hbox>
#endif
<stack>
<!-- if width and height are not present, they default to 300x150 and stretch the stack -->
<html:canvas id="screen" width="1" height="1" role="presentation"/>
<image id="monitor"/>
</stack>
<vbox align="center">
<stack>
<!-- if width and height are not present, they default to 300x150 and stretch the stack -->
<html:canvas id="screen" width="1" height="1" role="presentation"/>
<image id="monitor"/>
</stack>
</vbox>
#ifdef XP_MACOSX
<separator/>

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

@ -6,3 +6,4 @@ skip-if = os != "linux"
skip-if = os != "linux"
[browser_1119088.js]
skip-if = os != "mac" || verify
[browser_setDesktopBackgroundPreview.js]

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

@ -3,84 +3,109 @@ const DG_IMAGE_KEY = DG_BACKGROUND + "/picture_filename";
const DG_OPTION_KEY = DG_BACKGROUND + "/picture_options";
const DG_DRAW_BG_KEY = DG_BACKGROUND + "/draw_background";
function onPageLoad() {
gBrowser.selectedBrowser.removeEventListener("load", onPageLoad, true);
const GS_BG_SCHEMA = "org.gnome.desktop.background";
const GS_IMAGE_KEY = "picture-uri";
const GS_OPTION_KEY = "picture-options";
const GS_DRAW_BG_KEY = "draw-background";
var brandName = Services.strings.createBundle("chrome://branding/locale/brand.properties").
GetStringFromName("brandShortName");
add_task(async function() {
await BrowserTestUtils.withNewTab({
gBrowser,
url: "about:logo",
}, (browser) => {
var brandName = Services.strings.createBundle("chrome://branding/locale/brand.properties").
GetStringFromName("brandShortName");
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIDirectoryServiceProvider);
var homeDir = dirSvc.getFile("Home", {});
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIDirectoryServiceProvider);
var homeDir = dirSvc.getFile("Home", {});
var wpFile = homeDir.clone();
wpFile.append(brandName + "_wallpaper.png");
var wpFile = homeDir.clone();
wpFile.append(brandName + "_wallpaper.png");
// Backup the existing wallpaper so that this test doesn't change the user's
// settings.
var wpFileBackup = homeDir.clone();
wpFileBackup.append(brandName + "_wallpaper.png.backup");
// Backup the existing wallpaper so that this test doesn't change the user's
// settings.
var wpFileBackup = homeDir.clone();
wpFileBackup.append(brandName + "_wallpaper.png.backup");
if (wpFileBackup.exists())
wpFileBackup.remove(false);
if (wpFileBackup.exists())
wpFileBackup.remove(false);
if (wpFile.exists())
wpFile.copyTo(null, wpFileBackup.leafName);
if (wpFile.exists())
wpFile.copyTo(null, wpFileBackup.leafName);
var shell = Cc["@mozilla.org/browser/shell-service;1"].
getService(Ci.nsIShellService);
var gconf = Cc["@mozilla.org/gnome-gconf-service;1"].
getService(Ci.nsIGConfService);
var shell = Cc["@mozilla.org/browser/shell-service;1"].
getService(Ci.nsIShellService);
var prevImageKey = gconf.getString(DG_IMAGE_KEY);
var prevOptionKey = gconf.getString(DG_OPTION_KEY);
var prevDrawBgKey = gconf.getBool(DG_DRAW_BG_KEY);
// For simplicity, we're going to reach in and access the image on the
// page directly, which means the page shouldn't be running in a remote
// browser. Thankfully, about:logo runs in the parent process for now.
Assert.ok(!gBrowser.selectedBrowser.isRemoteBrowser,
"image can be accessed synchronously from the parent process");
var image = content.document.images[0];
var image = content.document.images[0];
function checkWallpaper(position, expectedGConfPosition) {
shell.setDesktopBackground(image, position, "");
ok(wpFile.exists(), "Wallpaper was written to disk");
is(gconf.getString(DG_IMAGE_KEY), wpFile.path,
"Wallpaper file GConf key is correct");
is(gconf.getString(DG_OPTION_KEY), expectedGConfPosition,
"Wallpaper position GConf key is correct");
}
let checkWallpaper, restoreSettings;
try {
// Try via GSettings first
const gsettings = Cc["@mozilla.org/gsettings-service;1"].
getService(Ci.nsIGSettingsService).
getCollectionForSchema(GS_BG_SCHEMA);
checkWallpaper(Ci.nsIShellService.BACKGROUND_TILE, "wallpaper");
checkWallpaper(Ci.nsIShellService.BACKGROUND_STRETCH, "stretched");
checkWallpaper(Ci.nsIShellService.BACKGROUND_CENTER, "centered");
checkWallpaper(Ci.nsIShellService.BACKGROUND_FILL, "zoom");
checkWallpaper(Ci.nsIShellService.BACKGROUND_FIT, "scaled");
const prevImage = gsettings.getString(GS_IMAGE_KEY);
const prevOption = gsettings.getString(GS_OPTION_KEY);
const prevDrawBG = gsettings.getBoolean(GS_DRAW_BG_KEY);
// Restore GConf and wallpaper
checkWallpaper = function(position, expectedGSettingsPosition) {
shell.setDesktopBackground(image, position, "");
ok(wpFile.exists(), "Wallpaper was written to disk");
is(gsettings.getString(GS_IMAGE_KEY), "file://" + wpFile.path,
"Wallpaper file GSettings key is correct");
is(gsettings.getString(GS_OPTION_KEY), expectedGSettingsPosition,
"Wallpaper position GSettings key is correct");
};
gconf.setString(DG_IMAGE_KEY, prevImageKey);
gconf.setString(DG_OPTION_KEY, prevOptionKey);
gconf.setBool(DG_DRAW_BG_KEY, prevDrawBgKey);
restoreSettings = function() {
gsettings.setString(GS_IMAGE_KEY, prevImage);
gsettings.setString(GS_OPTION_KEY, prevOption);
gsettings.setBoolean(GS_DRAW_BG_KEY, prevDrawBG);
};
} catch (e) {
// Fallback to GConf
var gconf = Cc["@mozilla.org/gnome-gconf-service;1"].
getService(Ci.nsIGConfService);
wpFile.remove(false);
if (wpFileBackup.exists())
wpFileBackup.moveTo(null, wpFile.leafName);
var prevImageKey = gconf.getString(DG_IMAGE_KEY);
var prevOptionKey = gconf.getString(DG_OPTION_KEY);
var prevDrawBgKey = gconf.getBool(DG_DRAW_BG_KEY);
gBrowser.removeCurrentTab();
finish();
}
checkWallpaper = function(position, expectedGConfPosition) {
shell.setDesktopBackground(image, position, "");
ok(wpFile.exists(), "Wallpaper was written to disk");
is(gconf.getString(DG_IMAGE_KEY), wpFile.path,
"Wallpaper file GConf key is correct");
is(gconf.getString(DG_OPTION_KEY), expectedGConfPosition,
"Wallpaper position GConf key is correct");
wpFile.remove(false);
};
function test() {
try {
// If GSettings is available, then the GConf tests
// will fail
Cc["@mozilla.org/gsettings-service;1"].
getService(Ci.nsIGSettingsService).
getCollectionForSchema("org.gnome.desktop.background");
todo(false, "This test doesn't work when GSettings is available");
return;
} catch (e) { }
restoreSettings = function() {
gconf.setString(DG_IMAGE_KEY, prevImageKey);
gconf.setString(DG_OPTION_KEY, prevOptionKey);
gconf.setBool(DG_DRAW_BG_KEY, prevDrawBgKey);
};
}
gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
gBrowser.selectedBrowser.addEventListener("load", onPageLoad, true);
content.location = "about:logo";
checkWallpaper(Ci.nsIShellService.BACKGROUND_TILE, "wallpaper");
checkWallpaper(Ci.nsIShellService.BACKGROUND_STRETCH, "stretched");
checkWallpaper(Ci.nsIShellService.BACKGROUND_CENTER, "centered");
checkWallpaper(Ci.nsIShellService.BACKGROUND_FILL, "zoom");
checkWallpaper(Ci.nsIShellService.BACKGROUND_FIT, "scaled");
waitForExplicitFinish();
}
restoreSettings();
// Restore files
if (wpFileBackup.exists())
wpFileBackup.moveTo(null, wpFile.leafName);
});
});

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

@ -0,0 +1,60 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Check whether the preview image for setDesktopBackground is rendered
* correctly, without stretching
*/
add_task(async function() {
await BrowserTestUtils.withNewTab({
gBrowser,
url: "about:logo",
}, async (browser) => {
const dialogLoad = BrowserTestUtils.domWindowOpened(
null,
async win => {
await BrowserTestUtils.waitForEvent(win, "load");
Assert.equal(
win.document.documentElement.getAttribute("windowtype"),
"Shell:SetDesktopBackground",
"Opened correct window"
);
return true;
}
);
const image = content.document.images[0];
EventUtils.synthesizeMouseAtCenter(image, { type: "contextmenu" });
const menu = document.getElementById("contentAreaContextMenu");
await BrowserTestUtils.waitForPopupEvent(menu, "shown");
document.getElementById("context-setDesktopBackground").click();
// Need to explicitly close the menu (and wait for it), otherwise it fails
// verify/later tests
const menuClosed = BrowserTestUtils.waitForPopupEvent(menu, "hidden");
menu.hidePopup();
const win = await dialogLoad;
/* setDesktopBackground.js does a setTimeout to wait for correct
dimensions. If we don't wait here we could read the monitor image
URL before it's changed to the widescreen version */
await TestUtils.waitForTick();
const img = win.document.getElementById("monitor");
const measure = new Image();
const measureLoad = BrowserTestUtils.waitForEvent(measure, "load");
measure.src =
getComputedStyle(img).listStyleImage.slice(4, -1).replace(/"/g, "");
await measureLoad;
Assert.equal(img.clientWidth, measure.naturalWidth, "Monitor image correct width");
Assert.equal(img.clientHeight, measure.naturalHeight, "Monitor image correct height");
win.close();
await menuClosed;
});
});

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

@ -1004,7 +1004,11 @@ class UrlbarInput {
_on_blur(event) {
this.formatValue();
this.view.close(UrlbarUtils.CANCEL_REASON.BLUR);
// Respect the autohide preference for easier inspecting/debugging via
// the browser toolbox.
if (!UrlbarPrefs.get("ui.popup.disable_autohide")) {
this.view.close(UrlbarUtils.CANCEL_REASON.BLUR);
}
}
_on_focus(event) {

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

@ -140,6 +140,7 @@ const PREF_URLBAR_DEFAULTS = new Map([
const PREF_OTHER_DEFAULTS = new Map([
["keyword.enabled", true],
["browser.search.suggest.enabled", true],
["ui.popup.disable_autohide", false],
]);
// Maps preferences under browser.urlbar.suggest to behavior names, as defined

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

@ -119,15 +119,19 @@ subsuite = clipboard
[browser_UrlbarInput_unit.js]
support-files = empty.xul
[browser_UrlbarLoadRace.js]
[browser_urlbarOneOffs_contextMenu.js]
support-files =
searchSuggestionEngine.xml
searchSuggestionEngine.sjs
[browser_urlbarOneOffs_searchSuggestions.js]
support-files =
../browser/searchSuggestionEngine.xml
../browser/searchSuggestionEngine.sjs
searchSuggestionEngine.xml
searchSuggestionEngine.sjs
[browser_urlbarOneOffs_settings.js]
[browser_urlbarOneOffs.js]
support-files =
../browser/searchSuggestionEngine.xml
../browser/searchSuggestionEngine.sjs
searchSuggestionEngine.xml
searchSuggestionEngine.sjs
[browser_urlbarPlaceholder.js]
support-files =
searchSuggestionEngine.xml

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

@ -0,0 +1,139 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* Tests that the right-click menu works correctly for the one-off buttons.
*/
const TEST_ENGINE_BASENAME = "searchSuggestionEngine.xml";
let gMaxResults;
XPCOMUtils.defineLazyGetter(this, "oneOffSearchButtons", () => {
return UrlbarTestUtils.getOneOffSearchButtons(window);
});
let originalEngine;
let newEngine;
add_task(async function setup() {
SpecialPowers.pushPrefEnv({
"set": [
["browser.urlbar.oneOffSearches", true],
// Avoid hitting the network with search suggestions.
["browser.urlbar.suggest.searches", false],
["browser.tabs.loadInBackground", true],
],
});
gMaxResults = Services.prefs.getIntPref("browser.urlbar.maxRichResults");
// Add a search suggestion engine and move it to the front so that it appears
// as the first one-off.
originalEngine = await Services.search.getDefault();
newEngine = await SearchTestUtils.promiseNewSearchEngine(
getRootDirectory(gTestPath) + TEST_ENGINE_BASENAME);
await Services.search.moveEngine(newEngine, 0);
registerCleanupFunction(async function() {
await PlacesUtils.history.clear();
await Services.search.setDefault(originalEngine);
});
await PlacesUtils.history.clear();
let visits = [];
for (let i = 0; i < gMaxResults; i++) {
visits.push({
uri: makeURI("http://example.com/browser_urlbarOneOffs.js/?" + i),
// TYPED so that the visit shows up when the urlbar's drop-down arrow is
// pressed.
transition: Ci.nsINavHistoryService.TRANSITION_TYPED,
});
}
await PlacesTestUtils.addVisits(visits);
});
async function searchInTab(checkFn) {
// Ensure we've got a different engine selected to the one we added. so that
// it is a different engine to select.
await Services.search.setDefault(originalEngine);
await BrowserTestUtils.withNewTab({gBrowser}, async testBrowser => {
await promiseAutocompleteResultPopup("foo");
let contextMenu = oneOffSearchButtons.querySelector(".search-one-offs-context-menu");
let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
let oneOffs = oneOffSearchButtons.getSelectableButtons(true);
EventUtils.synthesizeMouseAtCenter(oneOffs[0], {type: "contextmenu", button: 2});
await popupShownPromise;
let tabOpenAndLoaded = BrowserTestUtils.waitForNewTab(gBrowser, null, true);
let openInTab = oneOffSearchButtons.querySelector(".search-one-offs-context-open-in-new-tab");
EventUtils.synthesizeMouseAtCenter(openInTab, {});
let newTab = await tabOpenAndLoaded;
checkFn(testBrowser, newTab);
BrowserTestUtils.removeTab(newTab);
});
}
add_task(async function searchInNewTab_opensBackground() {
Services.prefs.setBoolPref("browser.tabs.loadInBackground", true);
await searchInTab((testBrowser, newTab) => {
Assert.equal(newTab.linkedBrowser.currentURI.spec,
"http://mochi.test:8888/?terms=foo",
"Should have loaded the expected URI in a new tab.");
Assert.equal(testBrowser.currentURI.spec,
"about:blank",
"Should not have touched the original tab");
Assert.equal(testBrowser, gBrowser.selectedTab.linkedBrowser,
"Should not have changed the selected tab");
});
});
add_task(async function searchInNewTab_opensForeground() {
Services.prefs.setBoolPref("browser.tabs.loadInBackground", false);
await searchInTab((testBrowser, newTab) => {
Assert.equal(newTab.linkedBrowser.currentURI.spec,
"http://mochi.test:8888/?terms=foo",
"Should have loaded the expected URI in a new tab.");
Assert.equal(testBrowser.currentURI.spec,
"about:blank",
"Should not have touched the original tab");
Assert.equal(newTab, gBrowser.selectedTab,
"Should have changed the selected tab");
});
});
add_task(async function switchDefaultEngine() {
await Services.search.setDefault(originalEngine);
await BrowserTestUtils.withNewTab({gBrowser}, async () => {
await promiseAutocompleteResultPopup("foo");
let contextMenu = oneOffSearchButtons.querySelector(".search-one-offs-context-menu");
let popupShownPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
let oneOffs = oneOffSearchButtons.getSelectableButtons(true);
EventUtils.synthesizeMouseAtCenter(oneOffs[0], {type: "contextmenu", button: 2});
await popupShownPromise;
let engineChangedPromise =
SearchTestUtils.promiseSearchNotification("engine-default", "browser-search-engine-modified");
let setDefault = oneOffSearchButtons.querySelector(".search-one-offs-context-set-default");
EventUtils.synthesizeMouseAtCenter(setDefault, {});
await engineChangedPromise;
Assert.equal(await Services.search.getDefault(), newEngine,
"Should have correctly changed the engine to the new one");
});
});

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

@ -122,6 +122,10 @@ skip-if = os == "linux" # Bug 1073339 - Investigate autocomplete test unreliabil
[../browser/browser_urlbar_whereToOpen.js]
[../browser/browser_urlbarFocusedCmdK.js]
[../browser/browser_urlbarHashChangeProxyState.js]
[../browser/browser_urlbarOneOffs_contextMenu.js]
support-files =
../browser/searchSuggestionEngine.xml
../browser/searchSuggestionEngine.sjs
[../browser/browser_urlbarOneOffs_searchSuggestions.js]
support-files =
../browser/searchSuggestionEngine.xml

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

@ -232,7 +232,8 @@
margin-bottom: 0;
}
#cfr-notification-footer {
#cfr-notification-footer-text-and-addon-info {
display: block;
padding: 10px var(--arrowpanel-padding);
}
@ -294,6 +295,60 @@
flex-grow: 1;
}
#cfr-notification-footer-pintab-animation-container {
background-image: url("resource://activity-stream/data/content/assets/cfr_pinnedtab_animated.png");
background-position: top center;
background-repeat: no-repeat;
height: 173px;
width: 343px;
}
#contextual-feature-recommendation-notification[data-notification-category="cfrAddons"] #cfr-notification-footer-pintab-animation-container {
display: none;
}
#cfr-notification-footer-pintab-animation-container:not([animate]),
#cfr-notification-footer-pintab-animation-container[paused],
:root[lwt-popup-brighttext] #cfr-notification-footer-pintab-animation-container:not([animate]),
:root[lwt-popup-brighttext] #cfr-notification-footer-pintab-animation-container[paused] {
background-image: url("resource://activity-stream/data/content/assets/cfr_pinnedtab_static.png");
}
:root[lwt-popup-brighttext] #cfr-notification-footer-pintab-animation-container {
background-image: url("resource://activity-stream/data/content/assets/cfr_pinnedtab_animated_darktheme.png");
}
#cfr-notification-footer-animation-controls {
background: linear-gradient(transparent 0%, rgba(255, 255, 255, 0.95) 35%);
padding: 20px var(--arrowpanel-padding) 10px;
}
:root[lwt-popup-brighttext] #cfr-notification-footer-animation-controls {
margin-left: 13px;
}
#cfr-notification-footer-pintab-animation-container:not([animate]) #cfr-notification-footer-animation-controls,
#cfr-notification-footer-pintab-animation-container[paused] #cfr-notification-footer-animation-controls {
visibility: hidden;
}
#cfr-notification-footer-pause-button,
#cfr-notification-footer-pause-label {
color: rgba(12, 12, 13, 0.8);
cursor: pointer;
}
#cfr-notification-footer-pause-icon {
background-image: url("resource://activity-stream/data/content/assets/glyph-pause-12.svg");
background-position: center center;
background-repeat: no-repeat;
background-size: 12px;
-moz-context-properties: fill;
fill: rgba(12, 12, 13, 0.8);
height: 12px;
width: 12px;
}
#content-mask {
background: rgba(0, 0, 0, 0.5);
}

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

@ -4017,6 +4017,42 @@ html[dir="rtl"] .event-listeners-content .arrow.expanded {
* 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/>. */
.scopes-content .toggle-map-scopes {
border-bottom: 1px solid var(--theme-splitter-color);
margin-bottom: 3px;
margin-left: 10px;
padding: 0.5em 0;
}
.scopes-content .toggle-map-scopes input {
padding-inline-start: 2px;
margin-inline-start: 0;
vertical-align: text-bottom;
}
.scopes-content .toggle-map-scopes-label {
padding-inline-start: 2px;
padding-inline-end: 8px;
cursor: default;
flex-grow: 1;
-moz-user-select: none;
}
.scopes-content .toggle-map-scopes a.mdn {
padding-inline-end: 10px;
}
.scopes-content .toggle-map-scopes .img.shortcuts {
background: var(--theme-comment);
}
.scopes-content .toggle-map-scopes {
display: flex;
align-items: center;
}
.object-node.default-property {
opacity: 0.6;
}

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

@ -30,3 +30,4 @@ export { setPopupObjectProperties } from "./setPopupObjectProperties";
export { pauseOnExceptions } from "./pauseOnExceptions";
export { selectFrame } from "./selectFrame";
export { toggleSkipPausing } from "./skipPausing";
export { toggleMapScopes } from "./mapScopes";

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

@ -4,7 +4,14 @@
// @flow
import { getCurrentThread, getSource } from "../../selectors";
import {
getCurrentThread,
getSource,
getMapScopes,
getSelectedFrame,
getSelectedGeneratedScope,
getSelectedOriginalScope
} from "../../selectors";
import { loadSourceText } from "../sources/loadSourceText";
import { PROMISE } from "../utils/middleware/promise";
@ -17,6 +24,28 @@ import type { ThunkArgs } from "../types";
import { buildMappedScopes } from "../../utils/pause/mapScopes";
export function toggleMapScopes() {
return async function({ dispatch, getState, client, sourceMaps }: ThunkArgs) {
if (getMapScopes(getState())) {
return dispatch({ type: "TOGGLE_MAP_SCOPES", mapScopes: false });
}
dispatch({ type: "TOGGLE_MAP_SCOPES", mapScopes: true });
if (getSelectedOriginalScope(getState())) {
return;
}
const scopes = getSelectedGeneratedScope(getState());
const frame = getSelectedFrame(getState());
if (!scopes || !frame) {
return;
}
dispatch(mapScopes(Promise.resolve(scopes.scope), frame));
};
}
export function mapScopes(scopes: Promise<Scope>, frame: Frame) {
return async function({ dispatch, getState, client, sourceMaps }: ThunkArgs) {
const generatedSource = getSource(

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

@ -15,8 +15,8 @@ import { simpleMockThreadClient } from "./helpers/threadClient.js";
import { asyncStore } from "../../utils/prefs";
function loadInitialState(opts = {}) {
const mockedPendingBreakpoint = mockPendingBreakpoint({...opts, column: 2});
const id = makePendingLocationId(mockedPendingBreakpoint.location)
const mockedPendingBreakpoint = mockPendingBreakpoint({ ...opts, column: 2 });
const id = makePendingLocationId(mockedPendingBreakpoint.location);
asyncStore.pendingBreakpoints = { [id]: mockedPendingBreakpoint };
return { pendingBreakpoints: asyncStore.pendingBreakpoints };
@ -61,7 +61,11 @@ function mockClient(bpPos = {}) {
function mockSourceMaps() {
return {
...sourceMaps,
getOriginalSourceText: async (source) => ({id: source.id, text: "", contentType: "text/javascript"}),
getOriginalSourceText: async source => ({
id: source.id,
text: "",
contentType: "text/javascript"
}),
getGeneratedRangesForOriginal: async () => [
{ start: { line: 0, column: 0 }, end: { line: 10, column: 10 } }
]
@ -364,23 +368,19 @@ describe("adding sources", () => {
it("corresponding breakpoints are added to the original source", async () => {
const source = makeOriginalSource("bar.js", { sourceMapURL: "foo" });
const store = createStore(
mockClient({ "5": [2] }),
loadInitialState(),
{
getOriginalURLs: async () => [source.url],
getOriginalSourceText: async () => ({ source: "" }),
getGeneratedLocation: async (location, _source) => ({
line: location.line,
column: location.column,
sourceId: _source.id
}),
getOriginalLocation: async location => location,
getGeneratedRangesForOriginal: async () => [
{ start: { line: 0, column: 0 }, end: { line: 10, column: 10 } }
]
}
);
const store = createStore(mockClient({ "5": [2] }), loadInitialState(), {
getOriginalURLs: async () => [source.url],
getOriginalSourceText: async () => ({ source: "" }),
getGeneratedLocation: async (location, _source) => ({
line: location.line,
column: location.column,
sourceId: _source.id
}),
getOriginalLocation: async location => location,
getGeneratedRangesForOriginal: async () => [
{ start: { line: 0, column: 0 }, end: { line: 10, column: 10 } }
]
});
const { getState, dispatch } = store;

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

@ -130,4 +130,8 @@ export type PauseAction =
+type: "TOGGLE_SKIP_PAUSING",
+thread: string,
skipPausing: boolean
|}
| {|
+type: "TOGGLE_MAP_SCOPES",
+mapScopes: boolean
|};

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

@ -72,8 +72,8 @@ function releaseActor(actor: String) {
return debuggerClient.release(actor);
}
function sendPacket(packet: Object, callback?: Function = r => r) {
return debuggerClient.request(packet).then(callback);
function sendPacket(packet: Object) {
return debuggerClient.request(packet)
}
function lookupThreadClient(thread: string) {

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

@ -2,6 +2,42 @@
* 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/>. */
.scopes-content .toggle-map-scopes {
border-bottom: 1px solid var(--theme-splitter-color);
margin-bottom: 3px;
margin-left: 10px;
padding: 0.5em 0;
}
.scopes-content .toggle-map-scopes input {
padding-inline-start: 2px;
margin-inline-start: 0;
vertical-align: text-bottom;
}
.scopes-content .toggle-map-scopes-label {
padding-inline-start: 2px;
padding-inline-end: 8px;
cursor: default;
flex-grow: 1;
-moz-user-select: none;
}
.scopes-content .toggle-map-scopes a.mdn {
padding-inline-end: 10px;
}
.scopes-content .toggle-map-scopes .img.shortcuts {
background: var(--theme-comment);
}
.scopes-content .toggle-map-scopes {
display: flex;
align-items: center;
}
.object-node.default-property {
opacity: 0.6;
}

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

@ -4,7 +4,9 @@
// @flow
import React, { PureComponent } from "react";
import { isGeneratedId } from "devtools-source-map";
import { connect } from "../../utils/connect";
import { features } from "../../utils/prefs";
import actions from "../../actions";
import { createObjectClient } from "../../client/firefox";
@ -14,17 +16,21 @@ import {
getGeneratedFrameScope,
getOriginalFrameScope,
isPaused as getIsPaused,
getPauseReason
getPauseReason,
getMapScopes
} from "../../selectors";
import { getScopes } from "../../utils/pause/scopes";
import { objectInspector } from "devtools-reps";
import AccessibleImage from "../shared/AccessibleImage";
import type { Why } from "../../types";
import type { NamedValue } from "../../utils/pause/scopes/types";
import "./Scopes.css";
const mdnLink = "https://developer.mozilla.org/en-US/docs/Tools/Debugger";
const { ObjectInspector } = objectInspector;
type Props = {
@ -34,8 +40,10 @@ type Props = {
originalFrameScopes: Object | null,
isLoading: boolean,
why: Why,
shouldMapScopes: boolean,
openLink: typeof actions.openLink,
openElementInInspector: typeof actions.openElementInInspectorCommand
openElementInInspector: typeof actions.openElementInInspectorCommand,
toggleMapScopes: typeof actions.toggleMapScopes
};
type State = {
@ -97,16 +105,46 @@ class Scopes extends PureComponent<Props, State> {
}
}
render() {
onToggleMapScopes = () => {
this.props.toggleMapScopes();
};
renderMapScopes() {
const { selectedFrame, shouldMapScopes } = this.props;
if (!features.mapScopes || isGeneratedId(selectedFrame.location.sourceId)) {
return null;
}
return (
<div className="toggle-map-scopes" onClick={this.onToggleMapScopes}>
<input
type="checkbox"
checked={shouldMapScopes ? "checked" : ""}
onChange={e => e.stopPropagation() && this.onToggleMapScopes()}
/>
<div className="toggle-map-scopes-label">
<span>{L10N.getStr("scopes.mapScopes")}</span>
</div>
<a className="mdn" target="_blank" href={mdnLink}>
<AccessibleImage className="shortcuts" />
</a>
</div>
);
}
renderScopesList() {
const {
isPaused,
isLoading,
openLink,
openElementInInspector
openElementInInspector,
shouldMapScopes
} = this.props;
const { originalScopes, generatedScopes, showOriginal } = this.state;
const scopes = (showOriginal && originalScopes) || generatedScopes;
const scopes =
(showOriginal && shouldMapScopes && originalScopes) || generatedScopes;
if (scopes && !isLoading) {
return (
@ -122,7 +160,7 @@ class Scopes extends PureComponent<Props, State> {
onDOMNodeClick={grip => openElementInInspector(grip)}
onInspectIconClick={grip => openElementInInspector(grip)}
/>
{originalScopes ? (
{originalScopes && shouldMapScopes ? (
<div className="scope-type-toggle">
<button
onClick={e => {
@ -155,6 +193,15 @@ class Scopes extends PureComponent<Props, State> {
</div>
);
}
render() {
return (
<div className="scopes-content">
{this.renderMapScopes()}
{this.renderScopesList()}
</div>
);
}
}
const mapStateToProps = state => {
@ -180,6 +227,7 @@ const mapStateToProps = state => {
return {
selectedFrame,
shouldMapScopes: getMapScopes(state),
isPaused: getIsPaused(state),
isLoading: generatedPending || originalPending,
why: getPauseReason(state),
@ -192,6 +240,7 @@ export default connect(
mapStateToProps,
{
openLink: actions.openLink,
openElementInInspector: actions.openElementInInspectorCommand
openElementInInspector: actions.openElementInInspectorCommand,
toggleMapScopes: actions.toggleMapScopes
}
)(Scopes);

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

@ -13,7 +13,7 @@
import { createSelector } from "reselect";
import { isGeneratedId } from "devtools-source-map";
import { prefs } from "../utils/prefs";
import { getSelectedSource } from "./sources";
import { getSelectedSourceId } from "./sources";
import type { OriginalScope } from "../utils/pause/mapScopes";
import type { Action } from "../actions/types";
@ -78,14 +78,16 @@ export type PauseState = {
currentThread: string,
canRewind: boolean,
threads: { [string]: ThreadPauseState },
skipPausing: boolean
skipPausing: boolean,
mapScopes: boolean
};
export const createPauseState = (): PauseState => ({
currentThread: "UnknownThread",
threads: {},
canRewind: false,
skipPausing: prefs.skipPausing
skipPausing: prefs.skipPausing,
mapScopes: prefs.mapScopes
});
const resumedPauseState = {
@ -306,6 +308,12 @@ function update(
return { ...state, skipPausing };
}
case "TOGGLE_MAP_SCOPES": {
const { mapScopes } = action;
prefs.mapScopes = mapScopes;
return { ...state, mapScopes };
}
}
return state;
@ -503,14 +511,10 @@ export function getFrameScope(
}
export function getSelectedScope(state: OuterState) {
const source = getSelectedSource(state);
const sourceId = getSelectedSourceId(state);
const frameId = getSelectedFrameId(state);
if (!source) {
return null;
}
const frameScope = getFrameScope(state, source.id, frameId);
const frameScope = getFrameScope(state, sourceId, frameId);
if (!frameScope) {
return null;
}
@ -518,6 +522,17 @@ export function getSelectedScope(state: OuterState) {
return frameScope.scope || null;
}
export function getSelectedOriginalScope(state: OuterState) {
const sourceId = getSelectedSourceId(state);
const frameId = getSelectedFrameId(state);
return getOriginalFrameScope(state, sourceId, frameId);
}
export function getSelectedGeneratedScope(state: OuterState) {
const frameId = getSelectedFrameId(state);
return getGeneratedFrameScope(state, frameId);
}
export function getSelectedScopeMappings(
state: OuterState
): {
@ -556,6 +571,10 @@ export function getSkipPausing(state: OuterState) {
return state.pause.skipPausing;
}
export function getMapScopes(state: OuterState) {
return state.pause.mapScopes;
}
// NOTE: currently only used for chrome
export function getChromeScopes(state: OuterState) {
const frame: ?ChromeFrame = (getSelectedFrame(state): any);

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

@ -539,6 +539,11 @@ export const getSelectedSource: Selector<?Source> = createSelector(
}
);
export function getSelectedSourceId(state: OuterState) {
const source = getSelectedSource((state: any));
return source && source.id;
}
export function getProjectDirectoryRoot(state: OuterState): string {
return state.sources.projectDirectoryRoot;
}

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

@ -18,20 +18,19 @@ function findSources(dbg: any, url: string) {
return sources.filter(s => (s.url || "").includes(url));
}
function sendPacket(dbg: any, packet: any, callback: () => void) {
dbg.client.sendPacket(packet, callback || console.log);
function sendPacket(dbg: any, packet: any) {
return dbg.client.sendPacket(packet);
}
function sendPacketToThread(dbg: Object, packet: any, callback: Function = () => {}) {
sendPacket(
dbg,
{ to: dbg.connection.tabConnection.threadClient.actor, ...packet },
callback
);
function sendPacketToThread(dbg: Object, packet: any) {
return sendPacket(dbg, {
to: dbg.connection.tabConnection.threadClient.actor,
...packet
});
}
function evaluate(dbg: Object, expression: any, callback: () => void) {
dbg.client.evaluate(expression).then(callback || console.log);
function evaluate(dbg: Object, expression: any) {
return dbg.client.evaluate(expression);
}
function bindSelectors(obj: Object): Object {
@ -68,9 +67,9 @@ export function setupHelper(obj: Object) {
helpers: {
findSource: url => findSource(dbg, url),
findSources: url => findSources(dbg, url),
evaluate: (expression, cbk) => evaluate(dbg, expression, cbk),
sendPacketToThread: (packet, cbk) => sendPacketToThread(dbg, packet, cbk),
sendPacket: (packet, cbk) => sendPacket(dbg, packet, cbk),
evaluate: expression => evaluate(dbg, expression),
sendPacketToThread: packet => sendPacketToThread(dbg, packet),
sendPacket: packet => sendPacket(dbg, packet),
dumpThread: () => sendPacketToThread(dbg, { type: "dumpThread" })
},
formatters: {

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

@ -42,6 +42,7 @@ if (isDevelopment()) {
pref("devtools.debugger.file-search-whole-word", false);
pref("devtools.debugger.file-search-regex-match", false);
pref("devtools.debugger.project-directory-root", "");
pref("devtools.debugger.map-scopes-enabled", false);
pref("devtools.debugger.prefs-schema-version", "1.0.1");
pref("devtools.debugger.skip-pausing", false);
pref("devtools.debugger.features.workers", true);
@ -97,7 +98,8 @@ export const prefs = new PrefsHelper("devtools", {
fileSearchRegexMatch: ["Bool", "debugger.file-search-regex-match"],
debuggerPrefsSchemaVersion: ["Char", "debugger.prefs-schema-version"],
projectDirectoryRoot: ["Char", "debugger.project-directory-root", ""],
skipPausing: ["Bool", "debugger.skip-pausing"]
skipPausing: ["Bool", "debugger.skip-pausing"],
mapScopes: ["Bool", "debugger.map-scopes-enabled"]
});
export const features = new PrefsHelper("devtools.debugger.features", {

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

@ -515,6 +515,7 @@ function clearDebuggerPreferences() {
Services.prefs.clearUserPref("devtools.debugger.call-stack-visible");
Services.prefs.clearUserPref("devtools.debugger.scopes-visible");
Services.prefs.clearUserPref("devtools.debugger.skip-pausing");
pushPref("devtools.debugger.map-scopes-enabled", true);
}
/**

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

@ -1550,7 +1550,8 @@ CssRuleView.prototype = {
* @param {Element|null} declaration
* Optional. The declaration to scroll to.
* @param {String} scrollBehavior
* Optional. The transition animation when scrolling.
* Optional. The transition animation when scrolling. If prefers-reduced-motion
* system pref is set, then the scroll behavior will be overridden to "auto".
*/
_scrollToElement(rule, declaration, scrollBehavior = "smooth") {
let elementToScrollTo = rule;
@ -1566,6 +1567,11 @@ CssRuleView.prototype = {
}
}
// Ensure that smooth scrolling is disabled when the user prefers reduced motion.
const win = elementToScrollTo.ownerGlobal;
const reducedMotion = win.matchMedia("(prefers-reduced-motion)").matches;
scrollBehavior = reducedMotion ? "auto" : scrollBehavior;
elementToScrollTo.scrollIntoView({ behavior: scrollBehavior });
},

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

@ -31,6 +31,7 @@ const testData = [
["VK_TAB", {}, "none", !OPEN, !SELECTED, CHANGE],
["r", {}, "rebeccapurple", OPEN, SELECTED, CHANGE],
["VK_DOWN", {}, "red", OPEN, SELECTED, CHANGE],
["VK_DOWN", {}, "revert", OPEN, SELECTED, CHANGE],
["VK_DOWN", {}, "rgb", OPEN, SELECTED, CHANGE],
["VK_DOWN", {}, "rgba", OPEN, SELECTED, CHANGE],
["VK_DOWN", {}, "rosybrown", OPEN, SELECTED, CHANGE],

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

@ -37,7 +37,8 @@ const newAreaTestData = [
["c", {}, "col1-start", OPEN, SELECTED, CHANGE],
["VK_BACK_SPACE", {}, "c", !OPEN, !SELECTED, CHANGE],
["VK_BACK_SPACE", {}, "", !OPEN, !SELECTED, CHANGE],
["r", {}, "row1-start", OPEN, SELECTED, CHANGE],
["r", {}, "revert", OPEN, SELECTED, CHANGE],
["VK_DOWN", {}, "row1-start", OPEN, SELECTED, CHANGE],
["r", {}, "rr", !OPEN, !SELECTED, CHANGE],
["VK_BACK_SPACE", {}, "r", !OPEN, !SELECTED, CHANGE],
["o", {}, "row1-start", OPEN, SELECTED, CHANGE],
@ -57,7 +58,8 @@ const newRowTestData = [
"grid-line-names-updated",
["c", {}, "c", !OPEN, !SELECTED, CHANGE],
["VK_BACK_SPACE", {}, "", !OPEN, !SELECTED, CHANGE],
["r", {}, "row1-start", OPEN, SELECTED, CHANGE],
["r", {}, "revert", OPEN, SELECTED, CHANGE],
["VK_DOWN", {}, "row1-start", OPEN, SELECTED, CHANGE],
["VK_TAB", {}, "", !OPEN, !SELECTED, CHANGE],
];

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

@ -713,6 +713,9 @@ sources.header=Sources
# LOCALIZATION NOTE (outline.header): Outline left sidebar header
outline.header=Outline
# LOCALIZATION NOTE (scopes.mapScopes): Label for toggling scope mappings
scopes.mapScopes=Map Scopes
# LOCALIZATION NOTE (outline.placeholder): Placeholder text for the filter input
# element
outline.placeholder=Filter functions

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

@ -52,6 +52,7 @@ pref("devtools.debugger.file-search-regex-match", false);
pref("devtools.debugger.project-directory-root", "");
pref("devtools.debugger.skip-pausing", false);
pref("devtools.debugger.logging", false);
pref("devtools.debugger.map-scopes-enabled", false);
pref("devtools.debugger.features.wasm", true);
pref("devtools.debugger.features.shortcuts", true);

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

@ -1,11 +1,11 @@
{
"description": [
"Test states to be tested for css state machine in css-autocompelter.js file.",
"Test states to be tested for css state machine in css-autocompleter.js file.",
"Test cases are of the following format:",
"[",
" [",
" line, # The line location of the cursor",
" ch # The column locaiton of the cursor",
" ch # The column location of the cursor",
" ],",
" suggestions # Array of expected results",
"]"
@ -25,7 +25,7 @@
"background-clip", "background-color", "background-image",
"background-origin", "background-position", "background-position-x",
"background-position-y", "background-repeat", "background-size"]],
[[21, 9], ["auto", "inherit", "initial","unset"]],
[[21, 9], ["auto", "inherit", "initial", "revert", "unset" ]],
[[25, 26], [".devtools-toolbarbutton > tab",
".devtools-toolbarbutton > hbox",
".devtools-toolbarbutton > .toolbarbutton-menubutton-button"]],

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

@ -18,6 +18,9 @@ loader.lazyRequireGetter(this, "TabboxPanel", "devtools/client/netmonitor/src/co
const { getHTTPStatusCodeURL } = require("devtools/client/netmonitor/src/utils/mdn-utils");
const LEARN_MORE = l10n.getStr("webConsoleMoreInfoLabel");
const Services = require("Services");
const isMacOS = Services.appinfo.OS === "Darwin";
NetworkEventMessage.displayName = "NetworkEventMessage";
NetworkEventMessage.propTypes = {
@ -94,8 +97,12 @@ function NetworkEventMessage({
);
}
const toggle = () => {
if (open) {
const toggle = (e) => {
const shouldOpenLink = (isMacOS && e.metaKey) || (!isMacOS && e.ctrlKey);
if (shouldOpenLink) {
serviceContainer.openLink(request.url, e);
e.stopPropagation();
} else if (open) {
dispatch(actions.messageClose(id));
} else {
dispatch(actions.messageOpen(id));

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

@ -317,6 +317,7 @@ skip-if = true # Bug 1404382
[browser_webconsole_network_exceptions.js]
[browser_webconsole_network_messages_expand.js]
skip-if = true # Bug 1438979
[browser_webconsole_network_message_ctrl_click.js]
[browser_webconsole_network_messages_openinnet.js]
[browser_webconsole_network_messages_status_code.js]
[browser_webconsole_network_requests_from_chrome.js]

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

@ -0,0 +1,57 @@
// Test that URL opens in a new tab when click while
// pressing CTR (or CMD in MacOS) as expected.
"use strict";
const TEST_URI = "http://example.com/browser/devtools/client/webconsole/" +
"test/mochitest/test-console.html";
add_task(async function() {
// Enable net messages in the console for this test.
await pushPref("devtools.webconsole.filter.net", true);
const isMacOS = Services.appinfo.OS === "Darwin";
// We open the console
const hud = await openNewTabAndConsole(TEST_URI);
info("Reload the content window to produce a network log");
await ContentTask.spawn(gBrowser.selectedBrowser, null, () => {
content.wrappedJSObject.location.reload();
});
const message = await waitFor(() => findMessage(hud, "test-console.html"));
ok(message, "Network log found in the console");
const currentTab = gBrowser.selectedTab;
const tabLoaded = listenToTabLoad();
info("Cmd/Ctrl click on the message");
const urlObject = message.querySelector(".url");
EventUtils.sendMouseEvent({
type: "click",
[isMacOS ? "metaKey" : "ctrlKey"]: true,
}, urlObject, hud.ui.window);
info("Opening the URL of the message on a new tab");
const newTab = await tabLoaded;
const newTabHref = newTab.linkedBrowser.currentURI.spec;
is(newTabHref, TEST_URI, "Tab was opened with the expected URL");
info("Remove the new tab and select the previous tab back");
gBrowser.removeTab(newTab);
gBrowser.selectedTab = currentTab;
}
);
/**
* Simple helper to wrap a tab load listener in a promise.
*/
function listenToTabLoad() {
return new Promise((resolve) => {
gBrowser.tabContainer.addEventListener("TabOpen", function(evt) {
const newTab = evt.target;
BrowserTestUtils.browserLoaded(newTab.linkedBrowser).then(() => resolve(newTab));
}, {capture: true, once: true});
});
}

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

@ -1759,6 +1759,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
pauseOnExceptions: this._options.pauseOnExceptions,
ignoreCaughtExceptions: this._options.ignoreCaughtExceptions,
skipBreakpoints: this.skipBreakpoints,
breakpoints: this.breakpointActorMap.listKeys(),
};
},
});

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

@ -31,6 +31,10 @@ BreakpointActorMap.prototype = {
return Object.values(this._actors);
},
listKeys() {
return Object.keys(this._actors);
},
/**
* Return the BreakpointActor at the given location in this
* BreakpointActorMap.

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

@ -65,7 +65,7 @@ window.onload = function() {
"A CSS variable with spaces fails");
is(toSortedString(cssProperties.getValues("margin")),
toSortedString(["auto", "inherit", "initial", "unset"]),
toSortedString(["auto", "inherit", "initial", "unset", "revert"]),
"Can get values for the CSS margin.");
is(cssProperties.getValues("foobar").length, 0,
"Unknown values return an empty array.");

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -5,6 +5,13 @@
"use strict";
const Services = require("Services");
const { XPCOMUtils } = require("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyServiceGetter(
this, "swm",
"@mozilla.org/serviceworkers/manager;1",
"nsIServiceWorkerManager"
);
/**
* This helper provides info on whether we are in multi e10s mode or not.
@ -39,11 +46,19 @@ function removeMultiE10sListener(listener) {
Services.prefs.removeObserver(MULTI_OPTOUT_PREF, listener);
}
// TODO to be refactored as `canDebugServiceWorkers` (and
// logic in the consumers of the function to be changed)
// See Bug 1531349
function isMultiE10s() {
const isE10s = Services.appinfo.browserTabsRemoteAutostart;
const processCount = Services.appinfo.maxWebProcessCount;
const multiE10s = isE10s && processCount > 1;
const isNewSWImplementation = swm.isParentInterceptEnabled();
return isE10s && processCount > 1;
// When can we debug Service Workers?
// If we're running the new implementation, OR if not in multiprocess mode
const canDebugSW = isNewSWImplementation || !multiE10s;
return !canDebugSW;
}
module.exports = {

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

@ -2870,6 +2870,21 @@ void EventStateManager::PostHandleKeyboardEvent(
RefPtr<TabParent> remote =
aTargetFrame ? TabParent::GetFrom(aTargetFrame->GetContent())
: nullptr;
if (remote && aKeyboardEvent->mLayersId.IsValid()) {
// remote is null-checked above in order to let pre-existing event
// targeting code's chrome vs. content decision override APZ if they
// disagree in order not to disrupt non-Fission e10s mode in case
// there are still bugs in the Fission-mode code. That is, if remote
// is nullptr, the pre-existing event targeting code has deemed this
// event to belong to chrome rather than content.
TabParent* preciseRemote =
TabParent::GetTabParentFromLayersId(aKeyboardEvent->mLayersId);
if (preciseRemote) {
remote = preciseRemote;
}
// else there was a race between APZ and the chrome-process LayersId
// to TabParent mapping.
}
if (remote && !remote->IsReadyToHandleInputEvents()) {
// We need to dispatch the event to the browser element again if we were
// waiting for the key reply but the event wasn't sent to the content

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

@ -41,7 +41,7 @@ GraphDriver::GraphDriver(MediaStreamGraphImpl* aGraphImpl)
void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver,
GraphTime aLastSwitchNextIterationStart,
GraphTime aLastSwitchNextIterationEnd) {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
// We set mIterationEnd here, because the first thing a driver do when it
// does an iteration is to update graph times, so we are in fact setting
@ -63,7 +63,7 @@ void GraphDriver::SetGraphTime(GraphDriver* aPreviousDriver,
}
void GraphDriver::SwitchAtNextIteration(GraphDriver* aNextDriver) {
MOZ_ASSERT(OnThread());
MOZ_ASSERT(OnGraphThread());
MOZ_ASSERT(aNextDriver);
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
@ -87,14 +87,20 @@ GraphTime GraphDriver::StateComputedTime() const {
void GraphDriver::EnsureNextIteration() { GraphImpl()->EnsureNextIteration(); }
#ifdef DEBUG
bool GraphDriver::OnGraphThread() {
return GraphImpl()->RunByGraphDriver(this);
}
#endif
bool GraphDriver::Switching() {
MOZ_ASSERT(OnThread());
MOZ_ASSERT(OnGraphThread());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
return mNextDriver || mPreviousDriver;
}
void GraphDriver::SwitchToNextDriver() {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
MOZ_ASSERT(NextDriver());
@ -105,19 +111,19 @@ void GraphDriver::SwitchToNextDriver() {
}
GraphDriver* GraphDriver::NextDriver() {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
return mNextDriver;
}
GraphDriver* GraphDriver::PreviousDriver() {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
return mPreviousDriver;
}
void GraphDriver::SetNextDriver(GraphDriver* aNextDriver) {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
MOZ_ASSERT(aNextDriver != this);
MOZ_ASSERT(aNextDriver != mNextDriver);
@ -133,7 +139,7 @@ void GraphDriver::SetNextDriver(GraphDriver* aNextDriver) {
}
void GraphDriver::SetPreviousDriver(GraphDriver* aPreviousDriver) {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
GraphImpl()->GetMonitor().AssertCurrentThreadOwns();
mPreviousDriver = aPreviousDriver;
}
@ -659,7 +665,7 @@ bool AudioCallbackDriver::Init() {
void AudioCallbackDriver::Start() {
MOZ_ASSERT(!IsStarted());
MOZ_ASSERT(NS_IsMainThread() || OnCubebOperationThread() ||
(PreviousDriver() && PreviousDriver()->OnThread()));
(PreviousDriver() && PreviousDriver()->OnGraphThread()));
if (mPreviousDriver) {
if (mPreviousDriver->AsAudioCallbackDriver()) {
LOG(LogLevel::Debug, ("Releasing audio driver off main thread."));
@ -723,7 +729,7 @@ void AudioCallbackDriver::Revive() {
}
void AudioCallbackDriver::RemoveMixerCallback() {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
if (mAddedMixer) {
GraphImpl()->mMixer.RemoveCallback(this);
@ -732,7 +738,7 @@ void AudioCallbackDriver::RemoveMixerCallback() {
}
void AudioCallbackDriver::AddMixerCallback() {
MOZ_ASSERT(OnThread());
MOZ_ASSERT(OnGraphThread());
if (!mAddedMixer) {
mGraphImpl->mMixer.AddCallback(this);
@ -949,7 +955,7 @@ long AudioCallbackDriver::DataCallback(const AudioDataValue* aInputBuffer,
}
void AudioCallbackDriver::StateCallback(cubeb_state aState) {
MOZ_ASSERT(!OnThread());
MOZ_ASSERT(!OnGraphThread());
LOG(LogLevel::Debug, ("AudioCallbackDriver State: %d", aState));
// Clear the flag for the not running
@ -972,7 +978,7 @@ void AudioCallbackDriver::MixerCallback(AudioDataValue* aMixedBuffer,
AudioSampleFormat aFormat,
uint32_t aChannels, uint32_t aFrames,
uint32_t aSampleRate) {
MOZ_ASSERT(OnThread());
MOZ_ASSERT(OnGraphThread());
uint32_t toWrite = mBuffer.Available();
if (!mBuffer.Available()) {
@ -1028,7 +1034,7 @@ void AudioCallbackDriver::PanOutputIfNeeded(bool aMicrophoneActive) {
}
void AudioCallbackDriver::DeviceChangedCallback() {
MOZ_ASSERT(!OnThread());
MOZ_ASSERT(!OnGraphThread());
// Tell the audio engine the device has changed, it might want to reset some
// state.
MonitorAutoLock mon(mGraphImpl->GetMonitor());
@ -1039,7 +1045,7 @@ void AudioCallbackDriver::DeviceChangedCallback() {
}
uint32_t AudioCallbackDriver::IterationDuration() {
MOZ_ASSERT(OnThread());
MOZ_ASSERT(OnGraphThread());
// The real fix would be to have an API in cubeb to give us the number. Short
// of that, we approximate it here. bug 1019507
return mIterationDurationMS;
@ -1050,7 +1056,7 @@ bool AudioCallbackDriver::IsStarted() { return mStarted; }
void AudioCallbackDriver::EnqueueStreamAndPromiseForOperation(
MediaStream* aStream, void* aPromise,
dom::AudioContextOperation aOperation) {
MOZ_ASSERT(OnThread() || !ThreadRunning());
MOZ_ASSERT(OnGraphThread() || !ThreadRunning());
MonitorAutoLock mon(mGraphImpl->GetMonitor());
mPromisesForOperation.AppendElement(
StreamAndPromiseForOperation(aStream, aPromise, aOperation));

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

@ -55,12 +55,17 @@ static const int SCHEDULE_SAFETY_MARGIN_MS = 10;
static const int AUDIO_TARGET_MS =
2 * MEDIA_GRAPH_TARGET_PERIOD_MS + SCHEDULE_SAFETY_MARGIN_MS;
class MediaStream;
class MediaStreamGraphImpl;
class AudioCallbackDriver;
class OfflineClockDriver;
class SystemClockDriver;
namespace dom {
enum class AudioContextOperation;
}
/**
* A driver is responsible for the scheduling of the processing, the thread
* management, and give the different clocks to a MediaStreamGraph. This is an
@ -180,18 +185,15 @@ class GraphDriver {
*/
void EnsureNextIteration();
/**
* Same thing, but not locked.
*/
void EnsureNextIterationLocked();
MediaStreamGraphImpl* GraphImpl() const { return mGraphImpl; }
#ifdef DEBUG
// True if the current thread is driving the MSG.
bool OnGraphThread();
#endif
// True if the current thread is the GraphDriver's thread.
// This is the thread that drives the MSG.
virtual bool OnThread() = 0;
// GraphDriver's thread has started and the thread is running.
// This is the thread that drives the MSG.
virtual bool ThreadRunning() = 0;
protected:
@ -251,6 +253,8 @@ class ThreadedDriver : public GraphDriver {
friend class MediaStreamGraphInitThreadRunnable;
uint32_t IterationDuration() override { return MEDIA_GRAPH_TARGET_PERIOD_MS; }
nsIThread* Thread() { return mThread; }
bool OnThread() override {
return !mThread || mThread->EventTarget()->IsOnCurrentThread();
}
@ -412,6 +416,8 @@ class AudioCallbackDriver : public GraphDriver,
MediaStream* aStream, void* aPromise,
dom::AudioContextOperation aOperation);
std::thread::id ThreadId() { return mAudioThreadId.load(); }
bool OnThread() override {
return mAudioThreadId.load() == std::this_thread::get_id();
}

120
dom/media/GraphRunner.cpp Normal file
Просмотреть файл

@ -0,0 +1,120 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 https://mozilla.org/MPL/2.0/. */
#include "GraphRunner.h"
#include "GraphDriver.h"
#include "MediaStreamGraph.h"
#include "MediaStreamGraphImpl.h"
#include "nsISupportsImpl.h"
#include "prthread.h"
#include "Tracing.h"
namespace mozilla {
static void Start(void* aArg) {
GraphRunner* th = static_cast<GraphRunner*>(aArg);
th->Run();
}
GraphRunner::GraphRunner(MediaStreamGraphImpl* aGraph)
: mMonitor("GraphRunner::mMonitor"),
mGraph(aGraph),
mThread(PR_CreateThread(PR_SYSTEM_THREAD, &Start, this,
PR_PRIORITY_URGENT, PR_GLOBAL_THREAD,
PR_JOINABLE_THREAD, 0)) {
MOZ_COUNT_CTOR(GraphRunner);
}
GraphRunner::~GraphRunner() {
MOZ_COUNT_DTOR(GraphRunner);
#ifdef DEBUG
{
MonitorAutoLock lock(mMonitor);
MOZ_ASSERT(mShutdown);
}
#endif
PR_JoinThread(mThread);
}
void GraphRunner::Shutdown() {
MonitorAutoLock lock(mMonitor);
mShutdown = true;
mMonitor.Notify();
}
bool GraphRunner::OneIteration(GraphTime aStateEnd) {
TRACE_AUDIO_CALLBACK();
MonitorAutoLock lock(mMonitor);
MOZ_ASSERT(!mShutdown);
mStateEnd = aStateEnd;
if (!mStarted) {
mMonitor.Wait();
MOZ_ASSERT(mStarted);
}
#ifdef DEBUG
if (auto audioDriver = mGraph->CurrentDriver()->AsAudioCallbackDriver()) {
mAudioDriverThreadId = audioDriver->ThreadId();
} else if (auto clockDriver =
mGraph->CurrentDriver()->AsSystemClockDriver()) {
mClockDriverThread = clockDriver->Thread();
} else {
MOZ_CRASH("Unknown GraphDriver");
}
#endif
mMonitor.Notify(); // Signal that mStateEnd was updated
mMonitor.Wait(); // Wait for mStillProcessing to update
#ifdef DEBUG
mAudioDriverThreadId = std::thread::id();
mClockDriverThread = nullptr;
#endif
return mStillProcessing;
}
void GraphRunner::Run() {
PR_SetCurrentThreadName("GraphRunner");
MonitorAutoLock lock(mMonitor);
mStarted = true;
mMonitor.Notify(); // Signal that mStarted was set, in case the audio
// callback is already waiting for us
while (true) {
mMonitor.Wait(); // Wait for mStateEnd or mShutdown to update
if (mShutdown) {
break;
}
TRACE();
mStillProcessing = mGraph->OneIterationImpl(mStateEnd);
mMonitor.Notify(); // Signal that mStillProcessing was updated
}
}
bool GraphRunner::OnThread() { return PR_GetCurrentThread() == mThread; }
#ifdef DEBUG
bool GraphRunner::RunByGraphDriver(GraphDriver* aDriver) {
if (!OnThread()) {
return false;
}
if (auto audioDriver = aDriver->AsAudioCallbackDriver()) {
return audioDriver->ThreadId() == mAudioDriverThreadId;
}
if (auto clockDriver = aDriver->AsSystemClockDriver()) {
return clockDriver->Thread() == mClockDriverThread;
}
MOZ_CRASH("Unknown driver");
}
#endif
} // namespace mozilla

88
dom/media/GraphRunner.h Normal file
Просмотреть файл

@ -0,0 +1,88 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* 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 https://mozilla.org/MPL/2.0/. */
#ifndef mozilla_GraphRunner_h
#define mozilla_GraphRunner_h
#include "MediaSegment.h"
#include "mozilla/Monitor.h"
#include <thread>
struct PRThread;
namespace mozilla {
class GraphDriver;
class MediaStreamGraphImpl;
class GraphRunner {
public:
explicit GraphRunner(MediaStreamGraphImpl* aGraph);
~GraphRunner();
/**
* Marks us as shut down and signals mThread, so that it runs until the end.
*/
void Shutdown();
/**
* Signals one iteration of mGraph. Hands aStateEnd over to mThread and runs
* the iteration there.
*/
bool OneIteration(GraphTime aStateEnd);
/**
* Runs mGraph until it shuts down.
*/
void Run();
/**
* Returns true if called on mThread.
*/
bool OnThread();
#ifdef DEBUG
/**
* Returns true if called on mThread, and aDriver was the driver that called
* OneIteration() last.
*/
bool RunByGraphDriver(GraphDriver* aDriver);
#endif
private:
// Monitor used for yielding mThread through Wait(), and scheduling mThread
// through Signal() from a GraphDriver.
Monitor mMonitor;
// The MediaStreamGraph we're running. Weakptr beecause this graph owns us and
// guarantees that our lifetime will not go beyond that of itself.
MediaStreamGraphImpl* const mGraph;
// The thread running mGraph.
PRThread* const mThread;
// GraphTime being handed over to the graph through OneIteration. Protected by
// mMonitor.
GraphTime mStateEnd = 0;
// Reply from mGraph's OneIteration. Protected by mMonitor.
bool mStillProcessing = true;
// True after Shutdown(). Protected by mMonitor.
bool mShutdown = false;
// True after mThread has started running and has entered its main loop.
// Protected by mMonitor.
bool mStarted = false;
#ifdef DEBUG
// Set to mGraph's audio callback driver's thread id, if run by an
// AudioCallbackDriver, while OneIteration() is running.
std::thread::id mAudioDriverThreadId = std::thread::id();
// Set to mGraph's system clock driver's thread, if run by a
// SystemClockDriver, while OneIteration() is running.
nsIThread* mClockDriverThread = nullptr;
#endif
};
} // namespace mozilla
#endif

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

@ -32,6 +32,7 @@
#include "mozilla/Unused.h"
#include "mtransport/runnable_utils.h"
#include "VideoUtils.h"
#include "GraphRunner.h"
#include "Tracing.h"
#include "webaudio/blink/DenormalDisabler.h"
@ -1011,22 +1012,20 @@ void MediaStreamGraphImpl::ReevaluateInputDevice() {
}
}
bool MediaStreamGraph::OnGraphThreadOrNotRunning() const {
bool MediaStreamGraphImpl::OnGraphThreadOrNotRunning() const {
// either we're on the right thread (and calling CurrentDriver() is safe),
// or we're going to fail the assert anyway, so don't cross-check
// via CurrentDriver().
MediaStreamGraphImpl const* graph =
static_cast<MediaStreamGraphImpl const*>(this);
return graph->mDetectedNotRunning ? NS_IsMainThread()
: graph->mDriver->OnThread();
return mDetectedNotRunning ? NS_IsMainThread() : OnGraphThread();
}
bool MediaStreamGraph::OnGraphThread() const {
bool MediaStreamGraphImpl::OnGraphThread() const {
// we're on the right thread (and calling mDriver is safe),
MediaStreamGraphImpl const* graph =
static_cast<MediaStreamGraphImpl const*>(this);
MOZ_ASSERT(graph->mDriver);
return graph->mDriver->OnThread();
MOZ_ASSERT(mDriver);
if (mGraphRunner && mGraphRunner->OnThread()) {
return true;
}
return mDriver->OnThread();
}
bool MediaStreamGraphImpl::ShouldUpdateMainThread() {
@ -1379,13 +1378,23 @@ bool MediaStreamGraphImpl::UpdateMainThreadState() {
}
bool MediaStreamGraphImpl::OneIteration(GraphTime aStateEnd) {
if (mGraphRunner) {
return mGraphRunner->OneIteration(aStateEnd);
}
return OneIterationImpl(aStateEnd);
}
bool MediaStreamGraphImpl::OneIterationImpl(GraphTime aStateEnd) {
TRACE_AUDIO_CALLBACK();
// Changes to LIFECYCLE_RUNNING occur before starting or reviving the graph
// thread, and so the monitor need not be held to check mLifecycleState.
// LIFECYCLE_THREAD_NOT_STARTED is possible when shutting down offline
// graphs that have not started.
MOZ_DIAGNOSTIC_ASSERT(mLifecycleState <= LIFECYCLE_RUNNING);
MOZ_ASSERT(OnGraphThread());
WebCore::DenormalDisabler disabler;
// Process graph message from the main thread for this iteration.
@ -1499,6 +1508,10 @@ class MediaStreamGraphShutDownRunnable : public Runnable {
}
#endif
if (mGraph->mGraphRunner) {
mGraph->mGraphRunner->Shutdown();
}
mGraph->mDriver
->Shutdown(); // This will wait until it's shutdown since
// we'll start tearing down the graph after this
@ -3160,9 +3173,12 @@ void ProcessedMediaStream::DestroyImpl() {
}
MediaStreamGraphImpl::MediaStreamGraphImpl(GraphDriverType aDriverRequested,
GraphRunType aRunTypeRequested,
TrackRate aSampleRate,
AbstractThread* aMainThread)
: MediaStreamGraph(aSampleRate),
mGraphRunner(aRunTypeRequested == SINGLE_THREAD ? new GraphRunner(this)
: nullptr),
mFirstCycleBreaker(0)
// An offline graph is not initially processing.
,
@ -3217,6 +3233,13 @@ AbstractThread* MediaStreamGraph::AbstractMainThread() {
return static_cast<MediaStreamGraphImpl*>(this)->mAbstractMainThread;
}
#ifdef DEBUG
bool MediaStreamGraphImpl::RunByGraphDriver(GraphDriver* aDriver) {
return aDriver->OnThread() ||
(mGraphRunner && mGraphRunner->RunByGraphDriver(aDriver));
}
#endif
void MediaStreamGraphImpl::Destroy() {
// First unregister from memory reporting.
UnregisterWeakMemoryReporter(this);
@ -3298,8 +3321,14 @@ MediaStreamGraph* MediaStreamGraph::GetInstance(
// Uncommon case, only for some old configuration of webspeech.
mainThread = AbstractThread::MainThread();
}
graph =
new MediaStreamGraphImpl(aGraphDriverRequested, sampleRate, mainThread);
GraphRunType runType = DIRECT_DRIVER;
if (aGraphDriverRequested != OFFLINE_THREAD_DRIVER &&
Preferences::GetBool("dom.audioworklet.enabled", false)) {
runType = SINGLE_THREAD;
}
graph = new MediaStreamGraphImpl(aGraphDriverRequested, runType, sampleRate,
mainThread);
uint32_t hashkey = WindowToHash(aWindow, sampleRate);
gGraphs.Put(hashkey, graph);
@ -3316,7 +3345,7 @@ MediaStreamGraph* MediaStreamGraph::CreateNonRealtimeInstance(
MOZ_ASSERT(NS_IsMainThread(), "Main thread only");
MediaStreamGraphImpl* graph = new MediaStreamGraphImpl(
OFFLINE_THREAD_DRIVER, aSampleRate,
OFFLINE_THREAD_DRIVER, DIRECT_DRIVER, aSampleRate,
aWindow->AsGlobal()->AbstractMainThreadFor(TaskCategory::Other));
LOG(LogLevel::Debug, ("Starting up Offline MediaStreamGraph %p", graph));

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

@ -1205,6 +1205,14 @@ class MediaStreamGraph {
SYSTEM_THREAD_DRIVER,
OFFLINE_THREAD_DRIVER
};
// A MediaStreamGraph running an AudioWorklet must always be run from the
// same thread, in order to run js. To acheive this, create the graph with
// a SINGLE_THREAD RunType. DIRECT_DRIVER will run the graph directly off
// the GraphDriver's thread.
enum GraphRunType {
DIRECT_DRIVER,
SINGLE_THREAD,
};
static const uint32_t AUDIO_CALLBACK_DRIVER_SHUTDOWN_TIMEOUT = 20 * 1000;
static const TrackRate REQUEST_DEFAULT_SAMPLE_RATE = 0;
@ -1324,8 +1332,8 @@ class MediaStreamGraph {
// Intended only for assertions, either on graph thread or not running (in
// which case we must be on the main thread).
bool OnGraphThreadOrNotRunning() const;
bool OnGraphThread() const;
virtual bool OnGraphThreadOrNotRunning() const = 0;
virtual bool OnGraphThread() const = 0;
/**
* Sample rate at which this graph runs. For real time graphs, this is

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

@ -31,6 +31,7 @@ class ShutdownTicket;
template <typename T>
class LinkedList;
class GraphRunner;
/**
* A per-stream update message passed from the media graph thread to the
@ -109,8 +110,22 @@ class MediaStreamGraphImpl : public MediaStreamGraph,
* implement OfflineAudioContext. They do not support MediaStream inputs.
*/
explicit MediaStreamGraphImpl(GraphDriverType aGraphDriverRequested,
GraphRunType aRunTypeRequested,
TrackRate aSampleRate, AbstractThread* aWindow);
// Intended only for assertions, either on graph thread or not running (in
// which case we must be on the main thread).
bool OnGraphThreadOrNotRunning() const override;
bool OnGraphThread() const override;
#ifdef DEBUG
/**
* True if we're on aDriver's thread, or if we're on mGraphRunner's thread
* and mGraphRunner is currently run by aDriver.
*/
bool RunByGraphDriver(GraphDriver* aDriver);
#endif
/**
* Unregisters memory reporting and deletes this instance. This should be
* called instead of calling the destructor directly.
@ -180,10 +195,18 @@ class MediaStreamGraphImpl : public MediaStreamGraph,
bool UpdateMainThreadState();
/**
* Returns true if this MediaStreamGraph should keep running
* Proxy method called by GraphDriver to iterate the graph.
* If this graph was created with GraphRunType SINGLE_THREAD, mGraphRunner
* will take care of calling OneIterationImpl from its thread. Otherwise,
* OneIterationImpl is called directly.
*/
bool OneIteration(GraphTime aStateEnd);
/**
* Returns true if this MediaStreamGraph should keep running
*/
bool OneIterationImpl(GraphTime aStateEnd);
/**
* Called from the driver, when the graph thread is about to stop, to tell
* the main thread to attempt to begin cleanup. The main thread may either
@ -242,7 +265,7 @@ class MediaStreamGraphImpl : public MediaStreamGraph,
void UpdateGraph(GraphTime aEndBlockingDecisions);
void SwapMessageQueues() {
MOZ_ASSERT(CurrentDriver()->OnThread());
MOZ_ASSERT(OnGraphThread());
MOZ_ASSERT(mFrontMessageQueue.IsEmpty());
mMonitor.AssertCurrentThreadOwns();
mFrontMessageQueue.SwapElements(mBackMessageQueue);
@ -504,7 +527,7 @@ class MediaStreamGraphImpl : public MediaStreamGraph,
* We can also switch from Revive() (on MainThread). Monitor must be held.
*/
void SetCurrentDriver(GraphDriver* aDriver) {
MOZ_ASSERT(mDriver->OnThread() || !mDriver->ThreadRunning());
MOZ_ASSERT(RunByGraphDriver(mDriver) || !mDriver->ThreadRunning());
#ifdef DEBUG
mMonitor.AssertCurrentThreadOwns();
#endif
@ -588,7 +611,13 @@ class MediaStreamGraphImpl : public MediaStreamGraph,
StreamSet AllStreams() { return StreamSet(*this); }
// Data members
//
/*
* If set, the GraphRunner class handles handing over data from audio
* callbacks to a common single thread, shared across GraphDrivers.
*/
const UniquePtr<GraphRunner> mGraphRunner;
/**
* Graphs own owning references to their driver, until shutdown. When a driver
* switch occur, previous driver is either deleted, or it's ownership is

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

@ -240,6 +240,7 @@ UNIFIED_SOURCES += [
'FileMediaResource.cpp',
'GetUserMediaRequest.cpp',
'GraphDriver.cpp',
'GraphRunner.cpp',
'ImageToI420.cpp',
'MediaCache.cpp',
'MediaContainerType.cpp',

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

@ -654,7 +654,7 @@ AudioInputProcessing::AudioInputProcessing(
void AudioInputProcessing::Disconnect(MediaStreamGraphImpl* aGraph) {
// This method is just for asserts.
MOZ_ASSERT(aGraph->CurrentDriver()->OnThread());
MOZ_ASSERT(aGraph->OnGraphThread());
}
void MediaEngineWebRTCMicrophoneSource::Shutdown() {
@ -671,7 +671,7 @@ void MediaEngineWebRTCMicrophoneSource::Shutdown() {
}
bool AudioInputProcessing::PassThrough(MediaStreamGraphImpl* aGraph) const {
MOZ_ASSERT(aGraph->CurrentDriver()->OnThread());
MOZ_ASSERT(aGraph->OnGraphThread());
return mSkipProcessing;
}
@ -851,7 +851,7 @@ void AudioInputProcessing::NotifyOutputData(MediaStreamGraphImpl* aGraph,
AudioDataValue* aBuffer,
size_t aFrames, TrackRate aRate,
uint32_t aChannels) {
MOZ_ASSERT(aGraph->CurrentDriver()->OnThread());
MOZ_ASSERT(aGraph->OnGraphThread());
MOZ_ASSERT(mEnabled);
if (!mPacketizerOutput || mPacketizerOutput->PacketSize() != aRate / 100u ||
@ -1096,7 +1096,7 @@ void AudioInputProcessing::NotifyInputData(MediaStreamGraphImpl* aGraph,
const AudioDataValue* aBuffer,
size_t aFrames, TrackRate aRate,
uint32_t aChannels) {
MOZ_ASSERT(aGraph->CurrentDriver()->OnThread());
MOZ_ASSERT(aGraph->OnGraphThread());
TRACE_AUDIO_CALLBACK();
MOZ_ASSERT(mEnabled);
@ -1132,7 +1132,7 @@ void AudioInputProcessing::NotifyInputData(MediaStreamGraphImpl* aGraph,
} while (0)
void AudioInputProcessing::DeviceChanged(MediaStreamGraphImpl* aGraph) {
MOZ_ASSERT(aGraph->CurrentDriver()->OnThread());
MOZ_ASSERT(aGraph->OnGraphThread());
// Reset some processing
ResetProcessingIfNeeded(gain_control);
ResetProcessingIfNeeded(echo_cancellation);

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

@ -15,6 +15,10 @@
#include "nsNetUtil.h"
#include "nsURLParsers.h"
#ifdef OS_WIN
#include "WinWebAuthnManager.h"
#endif
using namespace mozilla::ipc;
// Forward decl because of nsHTMLDocument.h's complex dependency on
@ -253,7 +257,13 @@ void U2F::Register(const nsAString& aAppId,
return;
}
#ifdef OS_WIN
if (!WinWebAuthnManager::AreWebAuthNApisAvailable()) {
ListenForVisibilityEvents();
}
#else
ListenForVisibilityEvents();
#endif
NS_ConvertUTF16toUTF8 clientData(clientDataJSON);
uint32_t adjustedTimeoutMillis = AdjustedTimeoutMillis(opt_aTimeoutSeconds);
@ -391,7 +401,13 @@ void U2F::Sign(const nsAString& aAppId, const nsAString& aChallenge,
return;
}
#ifdef OS_WIN
if (!WinWebAuthnManager::AreWebAuthNApisAvailable()) {
ListenForVisibilityEvents();
}
#else
ListenForVisibilityEvents();
#endif
// Always blank for U2F
nsTArray<WebAuthnExtension> extensions;

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

@ -203,8 +203,14 @@ void AnimationInfo::EnumerateGenerationOnFrame(
}
for (auto displayItem : LayerAnimationInfo::sDisplayItemTypes) {
// For transform animations, the animation is on the primary frame but
// |aFrame| is the style frame.
const nsIFrame* frameToQuery =
displayItem == DisplayItemType::TYPE_TRANSFORM
? nsLayoutUtils::GetPrimaryFrameFromStyleFrame(aFrame)
: aFrame;
RefPtr<WebRenderAnimationData> animationData =
GetWebRenderUserData<WebRenderAnimationData>(aFrame,
GetWebRenderUserData<WebRenderAnimationData>(frameToQuery,
(uint32_t)displayItem);
Maybe<uint64_t> generation;
if (animationData) {
@ -215,8 +221,7 @@ void AnimationInfo::EnumerateGenerationOnFrame(
return;
}
FrameLayerBuilder::EnumerateGenerationForDedicatedLayers(
aFrame, LayerAnimationInfo::sDisplayItemTypes, aCallback);
FrameLayerBuilder::EnumerateGenerationForDedicatedLayers(aFrame, aCallback);
}
} // namespace layers

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

@ -520,6 +520,9 @@ pub struct Texture {
/// configurations). But that would complicate a lot of logic in this module,
/// and FBOs are cheap enough to create.
fbos_with_depth: Vec<FBOId>,
/// If we are unable to blit directly to a texture array then we need
/// an intermediate renderbuffer.
blit_workaround_buffer: Option<(RBOId, FBOId)>,
last_frame_used: GpuFrameId,
}
@ -876,6 +879,11 @@ pub struct Capabilities {
pub supports_multisampling: bool,
/// Whether the function glCopyImageSubData is available.
pub supports_copy_image_sub_data: bool,
/// Whether we are able to use glBlitFramebuffers with the draw fbo
/// bound to a non-0th layer of a texture array. This is buggy on
/// Adreno devices.
pub supports_blit_to_texture_array: bool,
}
#[derive(Clone, Debug)]
@ -987,6 +995,11 @@ pub enum DrawTarget<'a> {
/// Whether to draw with the texture's associated depth target.
with_depth: bool,
},
/// Use an FBO attached to an external texture.
External {
fbo: FBOId,
size: FramebufferIntSize,
},
}
impl<'a> DrawTarget<'a> {
@ -1010,6 +1023,7 @@ impl<'a> DrawTarget<'a> {
match *self {
DrawTarget::Default { total_size, .. } => DeviceIntSize::from_untyped(&total_size.to_untyped()),
DrawTarget::Texture { texture, .. } => texture.get_dimensions(),
DrawTarget::External { size, .. } => DeviceIntSize::from_untyped(&size.to_untyped()),
}
}
@ -1021,7 +1035,7 @@ impl<'a> DrawTarget<'a> {
fb_rect.origin.y = rect.origin.y + rect.size.height - fb_rect.origin.y - fb_rect.size.height;
fb_rect.origin.x += rect.origin.x;
}
DrawTarget::Texture { .. } => (),
DrawTarget::Texture { .. } | DrawTarget::External { .. } => (),
}
fb_rect
}
@ -1043,7 +1057,7 @@ impl<'a> DrawTarget<'a> {
.intersection(rect)
.unwrap_or_else(FramebufferIntRect::zero)
}
DrawTarget::Texture { .. } => {
DrawTarget::Texture { .. } | DrawTarget::External { .. } => {
FramebufferIntRect::from_untyped(&scissor_rect.to_untyped())
}
}
@ -1068,7 +1082,11 @@ pub enum ReadTarget<'a> {
texture: &'a Texture,
/// The slice within the texture array to read from.
layer: LayerIndex,
}
},
/// Use an FBO attached to an external texture.
External {
fbo: FBOId,
},
}
impl<'a> From<DrawTarget<'a>> for ReadTarget<'a> {
@ -1077,6 +1095,8 @@ impl<'a> From<DrawTarget<'a>> for ReadTarget<'a> {
DrawTarget::Default { .. } => ReadTarget::Default,
DrawTarget::Texture { texture, layer, .. } =>
ReadTarget::Texture { texture, layer },
DrawTarget::External { fbo, .. } =>
ReadTarget::External { fbo },
}
}
}
@ -1198,6 +1218,10 @@ impl Device {
let supports_copy_image_sub_data = supports_extension(&extensions, "GL_EXT_copy_image") ||
supports_extension(&extensions, "GL_ARB_copy_image");
// Due to a bug on Adreno devices, blitting to an fbo bound to
// a non-0th layer of a texture array is not supported.
let supports_blit_to_texture_array = !renderer_name.starts_with("Adreno");
// On Adreno GPUs PBO texture upload is only performed asynchronously
// if the stride of the data in the PBO is a multiple of 256 bytes.
// Other platforms may have similar requirements and should be added
@ -1218,6 +1242,7 @@ impl Device {
capabilities: Capabilities {
supports_multisampling: false, //TODO
supports_copy_image_sub_data,
supports_blit_to_texture_array,
},
bgra_format_internal,
@ -1418,6 +1443,7 @@ impl Device {
let fbo_id = match target {
ReadTarget::Default => self.default_read_fbo,
ReadTarget::Texture { texture, layer } => texture.fbos[layer],
ReadTarget::External { fbo } => fbo,
};
self.bind_read_target_impl(fbo_id)
@ -1460,7 +1486,8 @@ impl Device {
} else {
(texture.fbos[layer], rect, false)
}
}
},
DrawTarget::External { fbo, size } => (fbo, size.into(), false),
};
self.depth_available = depth_available;
@ -1683,6 +1710,7 @@ impl Device {
filter,
fbos: vec![],
fbos_with_depth: vec![],
blit_workaround_buffer: None,
last_frame_used: self.frame_id,
flags: TextureFlags::default(),
};
@ -1769,6 +1797,28 @@ impl Device {
}
}
// Set up intermediate buffer for blitting to texture, if required.
if texture.layer_count > 1 && !self.capabilities.supports_blit_to_texture_array {
let rbo = RBOId(self.gl.gen_renderbuffers(1)[0]);
let fbo = FBOId(self.gl.gen_framebuffers(1)[0]);
self.gl.bind_renderbuffer(gl::RENDERBUFFER, rbo.0);
self.gl.renderbuffer_storage(
gl::RENDERBUFFER,
self.matching_renderbuffer_format(texture.format),
texture.size.width as _,
texture.size.height as _
);
self.bind_draw_target_impl(fbo);
self.gl.framebuffer_renderbuffer(
gl::DRAW_FRAMEBUFFER,
gl::COLOR_ATTACHMENT0,
gl::RENDERBUFFER,
rbo.0
);
texture.blit_workaround_buffer = Some((rbo, fbo));
}
record_gpu_alloc(texture.size_in_bytes());
texture
@ -1819,15 +1869,18 @@ impl Device {
src.size.width as _, src.size.height as _, src.layer_count);
}
} else {
// Note that zip() truncates to the shorter of the two iterators.
let rect = FramebufferIntRect::new(
FramebufferIntPoint::zero(),
FramebufferIntSize::from_untyped(&src.get_dimensions().to_untyped()),
);
for (read_fbo, draw_fbo) in src.fbos.iter().zip(&dst.fbos) {
self.bind_read_target_impl(*read_fbo);
self.bind_draw_target_impl(*draw_fbo);
self.blit_render_target(rect, rect, TextureFilter::Linear);
for layer in 0..src.layer_count.min(dst.layer_count) as LayerIndex {
self.blit_render_target(
ReadTarget::Texture { texture: src, layer },
rect,
DrawTarget::Texture { texture: dst, layer, with_depth: false },
rect,
TextureFilter::Linear
);
}
self.reset_draw_target();
self.reset_read_target();
@ -1978,7 +2031,8 @@ impl Device {
}
}
pub fn blit_render_target(
/// Perform a blit between self.bound_read_fbo and self.bound_draw_fbo.
fn blit_render_target_impl(
&mut self,
src_rect: FramebufferIntRect,
dest_rect: FramebufferIntRect,
@ -2005,26 +2059,93 @@ impl Device {
);
}
/// Perform a blit between src_target and dest_target.
/// This will overwrite self.bound_read_fbo and self.bound_draw_fbo.
pub fn blit_render_target(
&mut self,
src_target: ReadTarget,
src_rect: FramebufferIntRect,
dest_target: DrawTarget,
dest_rect: FramebufferIntRect,
filter: TextureFilter,
) {
debug_assert!(self.inside_frame);
self.bind_read_target(src_target);
match dest_target {
DrawTarget::Texture { texture, layer, .. } if layer != 0 &&
!self.capabilities.supports_blit_to_texture_array =>
{
// This should have been initialized in create_texture().
let (_rbo, fbo) = texture.blit_workaround_buffer.expect("Blit workaround buffer has not been initialized.");
// Blit from read target to intermediate buffer.
self.bind_draw_target_impl(fbo);
self.blit_render_target_impl(
src_rect,
dest_rect,
filter
);
// dest_rect may be inverted, so min_x/y() might actually be the
// bottom-right, max_x/y() might actually be the top-left,
// and width/height might be negative. See servo/euclid#321.
// Calculate the non-inverted rect here.
let dest_bounds = DeviceIntRect::new(
DeviceIntPoint::new(
dest_rect.min_x().min(dest_rect.max_x()),
dest_rect.min_y().min(dest_rect.max_y()),
),
DeviceIntSize::new(
dest_rect.size.width.abs(),
dest_rect.size.height.abs(),
),
).intersection(&texture.size.into()).unwrap_or(DeviceIntRect::zero());
self.bind_read_target_impl(fbo);
self.bind_texture(DEFAULT_TEXTURE, texture);
// Copy from intermediate buffer to the texture layer.
self.gl.copy_tex_sub_image_3d(
texture.target, 0,
dest_bounds.origin.x, dest_bounds.origin.y,
layer as _,
dest_bounds.origin.x, dest_bounds.origin.y,
dest_bounds.size.width, dest_bounds.size.height,
);
}
_ => {
self.bind_draw_target(dest_target);
self.blit_render_target_impl(src_rect, dest_rect, filter);
}
}
}
/// Performs a blit while flipping vertically. Useful for blitting textures
/// (which use origin-bottom-left) to the main framebuffer (which uses
/// origin-top-left).
pub fn blit_render_target_invert_y(
&mut self,
src_target: ReadTarget,
src_rect: FramebufferIntRect,
dest_target: DrawTarget,
dest_rect: FramebufferIntRect,
) {
debug_assert!(self.inside_frame);
self.gl.blit_framebuffer(
src_rect.origin.x,
src_rect.origin.y,
src_rect.origin.x + src_rect.size.width,
src_rect.origin.y + src_rect.size.height,
dest_rect.origin.x,
dest_rect.origin.y + dest_rect.size.height,
dest_rect.origin.x + dest_rect.size.width,
dest_rect.origin.y,
gl::COLOR_BUFFER_BIT,
gl::LINEAR,
let mut inverted_dest_rect = dest_rect;
inverted_dest_rect.origin.y = dest_rect.max_y();
inverted_dest_rect.size.height *= -1;
self.blit_render_target(
src_target,
src_rect,
dest_target,
inverted_dest_rect,
TextureFilter::Linear,
);
}
@ -2037,6 +2158,10 @@ impl Device {
if had_depth {
self.release_depth_target(texture.get_dimensions());
}
if let Some((rbo, fbo)) = texture.blit_workaround_buffer {
self.gl.delete_framebuffers(&[fbo.0]);
self.gl.delete_renderbuffers(&[rbo.0]);
}
self.gl.delete_textures(&[texture.id]);
@ -2870,6 +2995,20 @@ impl Device {
}
}
/// Returns a GL format matching an ImageFormat suitable for a renderbuffer.
fn matching_renderbuffer_format(&self, format: ImageFormat) -> gl::GLenum {
match format {
ImageFormat::R8 => gl::R8,
ImageFormat::R16 => gl::R16UI,
// BGRA8 is not usable with renderbuffers so use RGBA8.
ImageFormat::BGRA8 => gl::RGBA8,
ImageFormat::RGBAF32 => gl::RGBA32F,
ImageFormat::RG8 => gl::RG8,
ImageFormat::RGBAI32 => gl::RGBA32I,
ImageFormat::RGBA8 => gl::RGBA8,
}
}
/// Generates a memory report for the resources managed by the device layer.
pub fn report_memory(&self) -> MemoryReport {
let mut report = MemoryReport::default();

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

@ -3122,9 +3122,10 @@ impl Renderer {
.expect("BUG: invalid source texture");
let read_target = DrawTarget::Texture { texture, layer, with_depth: false };
device.bind_read_target(read_target.into());
device.blit_render_target(
read_target.into(),
read_target.to_framebuffer_rect(source_rect),
draw_target,
draw_target.to_framebuffer_rect(blit.target_rect.translate(&-content_origin.to_vector())),
TextureFilter::Linear,
);
@ -3223,7 +3224,7 @@ impl Renderer {
// on a mostly-unused last slice of a large texture array).
Some(draw_target.to_framebuffer_rect(target.used_rect()))
}
DrawTarget::Texture { .. } => {
DrawTarget::Texture { .. } | DrawTarget::External { .. } => {
None
}
};
@ -3472,8 +3473,6 @@ impl Renderer {
if !alpha_batch_container.tile_blits.is_empty() {
let _timer = self.gpu_profile.start_timer(GPU_TAG_BLIT);
self.device.bind_read_target(draw_target.into());
for blit in &alpha_batch_container.tile_blits {
let texture = self.texture_resolver
.resolve(&blit.target.texture_id)
@ -3484,7 +3483,6 @@ impl Renderer {
layer: blit.target.texture_layer as usize,
with_depth: false,
};
self.device.bind_draw_target(blit_target);
let src_rect = draw_target.to_framebuffer_rect(DeviceIntRect::new(
blit.src_offset - content_origin.to_vector(),
@ -3499,7 +3497,9 @@ impl Renderer {
));
self.device.blit_render_target_invert_y(
draw_target.into(),
src_rect,
blit_target,
dest_rect,
);
}
@ -3531,10 +3531,10 @@ impl Renderer {
}
};
let (src_rect, _) = render_tasks[output.task_id].get_target_rect();
self.device.bind_read_target(draw_target.into());
self.device.bind_external_draw_target(fbo_id);
self.device.blit_render_target_invert_y(
draw_target.into(),
draw_target.to_framebuffer_rect(src_rect.translate(&-content_origin.to_vector())),
DrawTarget::External { fbo: fbo_id, size: output_size.into() },
output_size.into(),
);
handler.unlock(output.pipeline_id);
@ -4447,26 +4447,26 @@ impl Renderer {
// Copy frame buffer into the zoom texture
let read_target = DrawTarget::new_default(framebuffer_size);
self.device.bind_read_target(read_target.into());
self.device.bind_draw_target(DrawTarget::Texture {
texture: self.zoom_debug_texture.as_ref().unwrap(),
layer: 0,
with_depth: false,
});
self.device.blit_render_target(
read_target.into(),
read_target.to_framebuffer_rect(source_rect),
DrawTarget::Texture {
texture: self.zoom_debug_texture.as_ref().unwrap(),
layer: 0,
with_depth: false,
},
texture_rect,
TextureFilter::Nearest,
);
// Draw the zoom texture back to the framebuffer
self.device.bind_read_target(ReadTarget::Texture {
texture: self.zoom_debug_texture.as_ref().unwrap(),
layer: 0,
});
self.device.bind_draw_target(read_target);
self.device.blit_render_target(
ReadTarget::Texture {
texture: self.zoom_debug_texture.as_ref().unwrap(),
layer: 0,
},
texture_rect,
read_target,
read_target.to_framebuffer_rect(target_rect),
TextureFilter::Nearest,
);
@ -4544,8 +4544,6 @@ impl Renderer {
let layer_count = texture.get_layer_count() as usize;
for layer in 0 .. layer_count {
device.bind_read_target(ReadTarget::Texture { texture, layer});
let x = fb_width - (spacing + size) * (i as i32 + 1);
// If we have more targets than fit on one row in screen, just early exit.
@ -4585,7 +4583,9 @@ impl Renderer {
// use different conventions.
let dest_rect = rect(x, y + tag_height, size, size);
device.blit_render_target_invert_y(
ReadTarget::Texture { texture, layer },
src_rect,
DrawTarget::new_default(framebuffer_size),
FramebufferIntRect::from_untyped(&dest_rect),
);
i += 1;

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

@ -656,8 +656,11 @@ union alignas(8) Value {
bool isMagic() const { return toTag() == JSVAL_TAG_MAGIC; }
bool isMagic(JSWhyMagic why) const {
MOZ_ASSERT_IF(isMagic(), s_.payload_.why_ == why);
return isMagic();
if (!isMagic()) {
return false;
}
MOZ_RELEASE_ASSERT(s_.payload_.why_ == why);
return true;
}
JS::TraceKind traceKind() const {

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

@ -611,6 +611,8 @@ class NodeBuilder {
MOZ_MUST_USE bool classMethod(HandleValue name, HandleValue body,
PropKind kind, bool isStatic, TokenPos* pos,
MutableHandleValue dst);
MOZ_MUST_USE bool classField(HandleValue name, HandleValue body,
TokenPos* pos, MutableHandleValue dst);
/*
* expressions
@ -1528,6 +1530,17 @@ bool NodeBuilder::classMethod(HandleValue name, HandleValue body, PropKind kind,
kindName, "static", isStaticVal, dst);
}
bool NodeBuilder::classField(HandleValue name, HandleValue initializer,
TokenPos* pos, MutableHandleValue dst) {
RootedValue cb(cx, callbacks[AST_CLASS_FIELD]);
if (!cb.isNull()) {
return callback(cb, name, initializer, pos, dst);
}
return newNode(AST_CLASS_FIELD, pos, "name", name, "initializer", initializer,
dst);
}
bool NodeBuilder::classMembers(NodeVector& members, MutableHandleValue dst) {
return newArray(members, dst);
}
@ -1649,6 +1662,7 @@ class ASTSerializer {
bool property(ParseNode* pn, MutableHandleValue dst);
bool classMethod(ClassMethod* classMethod, MutableHandleValue dst);
bool classField(ClassField* classField, MutableHandleValue dst);
bool optIdentifier(HandleAtom atom, TokenPos* pos, MutableHandleValue dst) {
if (!atom) {
@ -2457,18 +2471,24 @@ bool ASTSerializer::statement(ParseNode* pn, MutableHandleValue dst) {
for (ParseNode* item : memberList->contents()) {
if (item->is<ClassField>()) {
// TODO(khyperia): Implement private field access.
return false;
}
ClassField* field = &item->as<ClassField>();
MOZ_ASSERT(memberList->pn_pos.encloses(field->pn_pos));
ClassMethod* method = &item->as<ClassMethod>();
MOZ_ASSERT(memberList->pn_pos.encloses(method->pn_pos));
RootedValue prop(cx);
if (!classField(field, &prop)) {
return false;
}
members.infallibleAppend(prop);
} else {
ClassMethod* method = &item->as<ClassMethod>();
MOZ_ASSERT(memberList->pn_pos.encloses(method->pn_pos));
RootedValue prop(cx);
if (!classMethod(method, &prop)) {
return false;
RootedValue prop(cx);
if (!classMethod(method, &prop)) {
return false;
}
members.infallibleAppend(prop);
}
members.infallibleAppend(prop);
}
return builder.classMembers(members, dst);
@ -2507,6 +2527,29 @@ bool ASTSerializer::classMethod(ClassMethod* classMethod,
dst);
}
bool ASTSerializer::classField(ClassField* classField, MutableHandleValue dst) {
RootedValue key(cx), val(cx);
// Dig through the lambda and get to the actual expression
if (classField->hasInitializer()) {
ParseNode* value = classField->initializer()
.body()
->head()
->as<LexicalScopeNode>()
.scopeBody()
->as<ListNode>()
.head()
->as<UnaryNode>()
.kid()
->as<AssignmentNode>()
.right();
if (!expression(value, &val)) {
return false;
}
}
return propertyName(&classField->name(), &key) &&
builder.classField(key, val, &classField->pn_pos, dst);
}
bool ASTSerializer::leftAssociate(ListNode* node, MutableHandleValue dst) {
MOZ_ASSERT(!node->empty());

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

@ -7103,7 +7103,7 @@ GeneralParser<ParseHandler, Unit>::synthesizeConstructor(
HandleAtom className, uint32_t classNameOffset) {
FunctionSyntaxKind functionSyntaxKind = FunctionSyntaxKind::ClassConstructor;
// Create the function object
// Create the function object.
RootedFunction fun(cx_, newFunction(className, functionSyntaxKind,
GeneratorKind::NotGenerator,
FunctionAsyncKind::SyncFunction));
@ -7111,7 +7111,7 @@ GeneralParser<ParseHandler, Unit>::synthesizeConstructor(
return null();
}
// Create the top-level field initializer node
// Create the top-level field initializer node.
FunctionNodeType funNode = handler_.newFunction(functionSyntaxKind, pos());
if (!funNode) {
return null();
@ -7129,14 +7129,14 @@ GeneralParser<ParseHandler, Unit>::synthesizeConstructor(
handler_.setFunctionBox(funNode, funbox);
funbox->setEnd(anyChars);
// push a SourceParseContext on to the stack.
// Push a SourceParseContext on to the stack.
SourceParseContext funpc(this, funbox, /* newDirectives = */ nullptr);
if (!funpc.init()) {
return null();
}
TokenPos synthesizedBodyPos = TokenPos(classNameOffset, classNameOffset + 1);
// Create a ListNode for the parameters + body (there are no parameters)
// Create a ListNode for the parameters + body (there are no parameters).
ListNodeType argsbody =
handler_.newList(ParseNodeKind::ParamsBody, synthesizedBodyPos);
if (!argsbody) {
@ -7146,7 +7146,7 @@ GeneralParser<ParseHandler, Unit>::synthesizeConstructor(
funbox->function()->setArgCount(0);
tokenStream.setFunctionStart(funbox);
// push a LexicalScope on to the stack
// Push a LexicalScope on to the stack.
ParseContext::Scope lexicalScope(this);
if (!lexicalScope.init(pc_)) {
return null();
@ -7166,7 +7166,6 @@ GeneralParser<ParseHandler, Unit>::synthesizeConstructor(
return null();
}
// Set the function's body to the field assignment.
auto initializerBody = finishLexicalScope(lexicalScope, stmtList);
if (!initializerBody) {
return null();
@ -7191,9 +7190,9 @@ template <class ParseHandler, typename Unit>
typename ParseHandler::FunctionNodeType
GeneralParser<ParseHandler, Unit>::fieldInitializer(YieldHandling yieldHandling,
HandleAtom propAtom) {
TokenPos fieldPos = pos();
TokenPos firstTokenPos = pos();
// Create the function object
// Create the function object.
RootedFunction fun(cx_, newFunction(propAtom, FunctionSyntaxKind::Expression,
GeneratorKind::NotGenerator,
FunctionAsyncKind::SyncFunction));
@ -7201,52 +7200,43 @@ GeneralParser<ParseHandler, Unit>::fieldInitializer(YieldHandling yieldHandling,
return null();
}
// Create the top-level field initializer node
// Create the top-level field initializer node.
FunctionNodeType funNode =
handler_.newFunction(FunctionSyntaxKind::Expression, fieldPos);
handler_.newFunction(FunctionSyntaxKind::Expression, firstTokenPos);
if (!funNode) {
return null();
}
// Create the FunctionBox and link it to the function object.
Directives directives(true);
FunctionBox* funbox = newFunctionBox(funNode, fun, fieldPos.begin, directives,
GeneratorKind::NotGenerator,
FunctionBox* funbox = newFunctionBox(funNode, fun, firstTokenPos.begin,
directives, GeneratorKind::NotGenerator,
FunctionAsyncKind::SyncFunction);
if (!funbox) {
return null();
}
funbox->initWithEnclosingParseContext(pc_, FunctionSyntaxKind::Expression);
handler_.setFunctionBox(funNode, funbox);
tokenStream.setFunctionStart(funbox);
// push a SourceParseContext on to the stack.
// Push a SourceParseContext on to the stack.
SourceParseContext funpc(this, funbox, /* newDirectives = */ nullptr);
if (!funpc.init()) {
return null();
}
// push a VarScope on to the stack
// Push a VarScope on to the stack.
ParseContext::VarScope varScope(this);
if (!varScope.init(pc_)) {
return null();
}
// push a LexicalScope on to the stack
// Push a LexicalScope on to the stack.
ParseContext::Scope lexicalScope(this);
if (!lexicalScope.init(pc_)) {
return null();
}
// Create a ListNode for the parameters + body (there are no parameters)
ListNodeType argsbody = handler_.newList(ParseNodeKind::ParamsBody, fieldPos);
if (!argsbody) {
return null();
}
handler_.setFunctionFormalParametersAndBody(funNode, argsbody);
funbox->function()->setArgCount(0);
tokenStream.setFunctionStart(funbox);
// Parse the expression for the field initializer.
Node initializerExpr =
assignExpr(InAllowed, yieldHandling, TripledotProhibited);
@ -7254,6 +7244,15 @@ GeneralParser<ParseHandler, Unit>::fieldInitializer(YieldHandling yieldHandling,
return null();
}
// Create a ListNode for the parameters + body (there are no parameters).
ListNodeType argsbody =
handler_.newList(ParseNodeKind::ParamsBody, firstTokenPos);
if (!argsbody) {
return null();
}
handler_.setFunctionFormalParametersAndBody(funNode, argsbody);
funbox->function()->setArgCount(0);
funbox->setEnd(anyChars);
funbox->usesThis = true;
@ -7262,14 +7261,15 @@ GeneralParser<ParseHandler, Unit>::fieldInitializer(YieldHandling yieldHandling,
return null();
}
// build `this.field` expression
ThisLiteralType propAssignThis = handler_.newThisLiteral(fieldPos, thisName);
// Build `this.field` expression.
ThisLiteralType propAssignThis =
handler_.newThisLiteral(firstTokenPos, thisName);
if (!propAssignThis) {
return null();
}
NameNodeType propAssignName =
handler_.newPropertyName(propAtom->asPropertyName(), fieldPos);
handler_.newPropertyName(propAtom->asPropertyName(), firstTokenPos);
if (!propAssignName) {
return null();
}
@ -7279,8 +7279,6 @@ GeneralParser<ParseHandler, Unit>::fieldInitializer(YieldHandling yieldHandling,
if (!propAssignFieldAccess) {
return null();
}
handler_.setBeginPosition(propAssignFieldAccess, propAssignName);
handler_.setEndPosition(propAssignFieldAccess, propAssignName);
// Synthesize an assignment expression for the property.
AssignmentNodeType initializerAssignment = handler_.newAssignment(
@ -7288,22 +7286,30 @@ GeneralParser<ParseHandler, Unit>::fieldInitializer(YieldHandling yieldHandling,
if (!initializerAssignment) {
return null();
}
handler_.setBeginPosition(initializerAssignment, initializerExpr);
handler_.setEndPosition(initializerAssignment, initializerExpr);
bool canSkipLazyClosedOverBindings = handler_.canSkipLazyClosedOverBindings();
if (!pc_->declareFunctionThis(usedNames_, canSkipLazyClosedOverBindings)) {
return null();
}
UnaryNodeType exprStatement =
handler_.newExprStatement(initializerAssignment, pos().end);
if (!exprStatement) {
return null();
}
ListNodeType statementList = handler_.newStatementList(firstTokenPos);
if (!argsbody) {
return null();
}
handler_.addStatementToList(statementList, exprStatement);
// Set the function's body to the field assignment.
LexicalScopeNodeType initializerBody =
finishLexicalScope(lexicalScope, initializerAssignment);
finishLexicalScope(lexicalScope, statementList);
if (!initializerBody) {
return null();
}
handler_.setBeginPosition(initializerBody, initializerAssignment);
handler_.setEndPosition(initializerBody, initializerAssignment);
handler_.setFunctionBody(funNode, initializerBody);

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

@ -4904,8 +4904,12 @@ bool jit::AnalyzeArgumentsUsage(JSContext* cx, JSScript* scriptArg) {
// formals which may be stored as part of a call object, don't use lazy
// arguments. The compiler can then assume that accesses through
// arguments[i] will be on unaliased variables.
if (script->funHasAnyAliasedFormal() && argumentsContentsObserved) {
return true;
if (argumentsContentsObserved) {
for (PositionalFormalParameterIter fi(script); fi; fi++) {
if (fi.closedOver()) {
return true;
}
}
}
script->setNeedsArgsObj(false);

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

@ -58,9 +58,12 @@ Adjusting when and how a test runs
used). Only the following two forms are supported:
<failure-type> include <relative_path>
<failure-type> script <relative_path>
include <relative_path>
The <type> "include" indicates that <failure-type> should apply to all test
cases within a directory. A statement for a nested directory or script
overrides one for an enclosing directory.
overrides one for an enclosing directory. The <type> "include" without a
<failure-type> recursively loads another jstests.list file for further
processing.
Running tests
-------------

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

@ -19,6 +19,14 @@ skip script non262/fields/field_types.js
skip script non262/fields/literal.js
skip script non262/fields/mixed_methods.js
skip script non262/fields/quirks.js
skip script non262/reflect-parse/class-fields.js
###########################################################################
# Generated jstests.list for test262 when inline |reftest| isn't possible #
###########################################################################
include test262/jstests.list
#################################################################
@ -133,7 +141,6 @@ skip script test262/built-ins/TypedArray/prototype/map/BigInt/speciesctor-get-sp
skip script test262/built-ins/TypedArray/prototype/map/BigInt/speciesctor-get-species-abrupt.js
skip script test262/built-ins/TypedArray/prototype/map/BigInt/speciesctor-get-ctor-abrupt.js
# Anonymous functions have own name property in SpiderMonkey
skip script test262/language/expressions/assignment/fn-name-lhs-cover.js
skip script test262/language/expressions/assignment/fn-name-lhs-member.js
@ -1127,16 +1134,6 @@ skip script test262/annexB/language/eval-code/indirect/global-if-decl-else-decl-
skip script test262/annexB/language/eval-code/indirect/global-block-decl-eval-global-existing-global-init.js
skip script test262/annexB/language/eval-code/indirect/global-switch-case-eval-global-existing-global-init.js
# Need to fix increment/decrement of arguments or eval -- bug 1530883.
skip script test262/language/expressions/postfix-increment/eval.js
skip script test262/language/expressions/postfix-increment/arguments.js
skip script test262/language/expressions/prefix-decrement/eval.js
skip script test262/language/expressions/prefix-decrement/arguments.js
skip script test262/language/expressions/prefix-increment/eval.js
skip script test262/language/expressions/prefix-increment/arguments.js
skip script test262/language/expressions/postfix-decrement/eval.js
skip script test262/language/expressions/postfix-decrement/arguments.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1340307
skip script test262/language/module-code/instn-resolve-empty-export.js
skip script test262/language/module-code/instn-resolve-empty-import.js
@ -1208,9 +1205,6 @@ skip script test262/annexB/built-ins/Function/createdynfn-html-close-comment-par
# https://bugzilla.mozilla.org/show_bug.cgi?id=1462745
skip script test262/annexB/language/function-code/block-decl-nested-blocks-with-fun-decl.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1406171
skip script test262/built-ins/Reflect/ownKeys/return-on-corresponding-order-large-index.js
# https://bugzilla.mozilla.org/show_bug.cgi?id=1473229
skip include test262/intl402/RelativeTimeFormat/prototype/formatToParts/jstests.list
@ -1238,6 +1232,7 @@ skip script test262/language/expressions/import.meta/syntax/invalid-assignment-t
# before we can run the updated test -- bug 1531091.
skip script test262/intl402/Collator/missing-unicode-ext-value-defaults-to-true.js
###########################################################
# Tests disabled due to issues in test262 importer script #
###########################################################
@ -1245,44 +1240,7 @@ skip script test262/intl402/Collator/missing-unicode-ext-value-defaults-to-true.
# test262 importer merges all includes in a per directory shell.js file, breaking this harness test case.
skip script test262/harness/detachArrayBuffer.js
# The hashbang tests are usually raw tests -- which means they must be run
# with no alterations. (This because "#!" only denotes a single-line comment if
# it appears at the very start of the script, and nowhere else.) But jstests.py
# expects to be told how tests should run, and what to expect from them, per the
# // |reftest| comment on the first line -- exactly where the "#!" must appear
# if it is to appear. (Same for the various fake hashbangs that aren't
# *actually* hashbangs, if they are to test what they were intended to test.)
#
# So for now -- until we can figure out a way to encode "this is a negative
# test" in a way that doesn't require changing the raw source of the test --
# these tests must be explicitly skipped. See bug 1531202.
skip script test262/language/comments/hashbang/escaped-hashbang.js
skip script test262/language/comments/hashbang/preceding-hashbang.js
skip script test262/language/comments/hashbang/escaped-hash-043.js
skip script test262/language/comments/hashbang/preceding-line-comment.js
skip script test262/language/comments/hashbang/escaped-hash-x23.js
skip script test262/language/comments/hashbang/escaped-hash-u0023.js
skip script test262/language/comments/hashbang/escaped-bang-u0021.js
skip script test262/language/comments/hashbang/preceding-empty-statement.js
skip script test262/language/comments/hashbang/escaped-bang-x21.js
skip script test262/language/comments/hashbang/multi-line-comment.js
skip script test262/language/comments/hashbang/escaped-bang-041.js
skip script test262/language/comments/hashbang/preceding-directive-prologue.js
skip script test262/language/comments/hashbang/preceding-multi-line-comment.js
skip script test262/language/comments/hashbang/escaped-hash-u23.js
skip script test262/language/comments/hashbang/escaped-bang-u21.js
skip script test262/language/comments/hashbang/preceding-directive-prologue-sc.js
skip script test262/language/comments/hashbang/preceding-whitespace.js
####################################################
# Tests disabled due to invalid test expectations #
####################################################
# https://github.com/tc39/test262/pull/1965
skip script test262/language/expressions/dynamic-import/indirect-resolution.js
skip script test262/language/expressions/dynamic-import/namespace/default-property-not-set-own.js
# https://github.com/tc39/test262/pull/2023
skip script test262/language/statements/try/early-catch-var.js
skip script test262/language/eval-code/direct/var-env-lower-lex-catch-non-strict.js

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

@ -331,7 +331,8 @@ def _parse_external_manifest(filename, relpath):
entries = []
with open(filename, 'r') as fp:
manifest_re = re.compile(r'^\s*(.*)\s+(include|script)\s+(\S+)$')
manifest_re = re.compile(r'^\s*(?P<terms>.*)\s+(?P<type>include|script)\s+(?P<path>\S+)$')
include_re = re.compile(r'^\s*include\s+(?P<path>\S+)$')
for line in fp:
line, _, comment = line.partition('#')
line = line.strip()
@ -339,12 +340,21 @@ def _parse_external_manifest(filename, relpath):
continue
matches = manifest_re.match(line)
if not matches:
print('warning: unrecognized line in jstests.list:'
' {0}'.format(line))
matches = include_re.match(line)
if not matches:
print('warning: unrecognized line in jstests.list:'
' {0}'.format(line))
continue
include_file = matches.group('path')
include_filename = os.path.join(os.path.dirname(filename), include_file)
include_relpath = os.path.join(relpath, os.path.dirname(include_file))
include_entries = _parse_external_manifest(include_filename, include_relpath)
entries.extend(include_entries)
continue
path = os.path.normpath(os.path.join(relpath, matches.group(3)))
if matches.group(2) == 'include':
path = os.path.normpath(os.path.join(relpath, matches.group('path')))
if matches.group('type') == 'include':
# The manifest spec wants a reference to another manifest here,
# but we need just the directory. We do need the trailing
# separator so we don't accidentally match other paths of which
@ -352,7 +362,7 @@ def _parse_external_manifest(filename, relpath):
assert(path.endswith('jstests.list'))
path = path[:-len('jstests.list')]
entries.append({'path': path, 'terms': matches.group(1),
entries.append({'path': path, 'terms': matches.group('terms'),
'comment': comment.strip()})
# if one directory name is a prefix of another, we want the shorter one

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

@ -153,6 +153,11 @@ function classMethod(id, body, kind, static) {
kind: kind,
static: static });
}
function classField(id, initializer) {
return Pattern({ type: "ClassField",
name: id,
initializer: initializer });
}
function funExpr(id, args, body, gen) {
return Pattern({ type: "FunctionExpression",

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

@ -0,0 +1,19 @@
// |reftest| skip-if(!xulRuntime.shell)
// Classes
function testClassFields() {
function constructor_(name) {
let body = blockStmt([]);
let method = funExpr(ident(name), [], body);
return classMethod(ident("constructor"), method, "method", false);
}
let genConstructor = constructor_("C");
assertExpr("(class C { x = 2; })", classExpr(ident("C"), null, [classField(ident("x"), lit(2)), genConstructor]));
assertExpr("(class C { x = x; })", classExpr(ident("C"), null, [classField(ident("x"), ident("x")), genConstructor]))
assertExpr("(class C { x; })", classExpr(ident("C"), null, [classField(ident("x"), undefined)]))
assertExpr("(class C { x; y = 2; })", classExpr(ident("C"), null, [classField(ident("x"), undefined), classField(ident("y"), lit(2)), genConstructor]))
assertExpr("(class C { x = 2; constructor(){} })", classExpr(ident("C"), null, [classField(ident("x"), lit(2)), genConstructor]))
}
runtest(testClassFields);

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

@ -16,6 +16,7 @@ import sys
from functools import partial
from itertools import chain
from operator import itemgetter
# Skip all tests which use features not supported in SpiderMonkey.
UNSUPPORTED_FEATURES = set([
@ -91,8 +92,8 @@ def tryParseTestFile(test262parser, source, testName):
def createRefTestEntry(skip, skipIf, error, isModule):
"""
Creates the |reftest| entry from the input list. Or the empty string if no
reftest entry is required.
Returns the |reftest| tuple (terms, comments) from the input arguments. Or a
tuple of empty strings if no reftest entry is required.
"""
terms = []
@ -112,11 +113,18 @@ def createRefTestEntry(skip, skipIf, error, isModule):
if isModule:
terms.append("module")
line = " ".join(terms)
if comments:
line += " -- " + ", ".join(comments)
return (" ".join(terms), ", ".join(comments))
return line
def createRefTestLine(terms, comments):
"""
Creates the |reftest| line using the given terms and comments.
"""
refTest = terms
if comments:
refTest += " -- " + comments
return refTest
def createSource(testSource, refTest, prologue, epilogue):
@ -201,7 +209,7 @@ def writeShellAndBrowserFiles(test262OutDir, harnessDir, includesMap, localInclu
# Write the concatenated include sources to shell.js.
with io.open(os.path.join(test262OutDir, relPath, "shell.js"), "wb") as shellFile:
if includeSource:
shellFile.write("// GENERATED, DO NOT EDIT\n")
shellFile.write(b"// GENERATED, DO NOT EDIT\n")
shellFile.write(includeSource)
# The browser.js file is always empty for test262 tests.
@ -214,10 +222,6 @@ def pathStartsWith(path, *args):
return os.path.commonprefix([path, prefix]) == prefix
def fileNameEndsWith(filePath, suffix):
return os.path.splitext(os.path.basename(filePath))[0].endswith(suffix)
def convertTestFile(test262parser, testSource, testName, includeSet, strictTests):
"""
Convert a test262 test to a compatible jstests test file.
@ -273,11 +277,6 @@ def convertTestFile(test262parser, testSource, testName, includeSet, strictTests
if "CanBlockIsTrue" in testRec:
refTestSkipIf.append(("!xulRuntime.shell", "browser cannot block main thread"))
# Skip non-test files.
isSupportFile = fileNameEndsWith(testName, "FIXTURE")
if isSupportFile:
refTestSkip.append("not a test file")
# Skip tests with unsupported features.
if "features" in testRec:
unsupported = [f for f in testRec["features"] if f in UNSUPPORTED_FEATURES]
@ -309,15 +308,21 @@ def convertTestFile(test262parser, testSource, testName, includeSet, strictTests
includeSet.update(testRec["includes"])
# Add reportCompare() after all positive, synchronous tests.
if not isNegative and not async and not isSupportFile:
if not isNegative and not async:
testEpilogue = "reportCompare(0, 0);"
else:
testEpilogue = ""
refTest = createRefTestEntry(refTestSkip, refTestSkipIf, errorType, isModule)
(terms, comments) = createRefTestEntry(refTestSkip, refTestSkipIf, errorType, isModule)
if raw:
refTest = ""
externRefTest = (terms, comments)
else:
refTest = createRefTestLine(terms, comments)
externRefTest = None
# Don't write a strict-mode variant for raw, module or support files.
noStrictVariant = raw or isModule or isSupportFile
# Don't write a strict-mode variant for raw or module files.
noStrictVariant = raw or isModule
assert not (noStrictVariant and (onlyStrict or noStrict)),\
"Unexpected onlyStrict or noStrict attribute: %s" % testName
@ -326,7 +331,7 @@ def convertTestFile(test262parser, testSource, testName, includeSet, strictTests
testPrologue = ""
nonStrictSource = createSource(testSource, refTest, testPrologue, testEpilogue)
testFileName = testName
yield (testFileName, nonStrictSource)
yield (testFileName, nonStrictSource, externRefTest)
# Write strict mode test.
if not noStrictVariant and (onlyStrict or (not noStrict and strictTests)):
@ -335,10 +340,29 @@ def convertTestFile(test262parser, testSource, testName, includeSet, strictTests
testFileName = testName
if not noStrict:
testFileName = addSuffixToFileName(testFileName, "-strict")
yield (testFileName, strictSource)
yield (testFileName, strictSource, externRefTest)
def process_test262(test262Dir, test262OutDir, strictTests):
def convertFixtureFile(fixtureSource, fixtureName):
"""
Convert a test262 fixture file to a compatible jstests test file.
"""
# jsreftest meta data
refTestSkip = ["not a test file"]
refTestSkipIf = []
errorType = None
isModule = False
(terms, comments) = createRefTestEntry(refTestSkip, refTestSkipIf, errorType, isModule)
refTest = createRefTestLine(terms, comments)
source = createSource(fixtureSource, refTest, "", "")
externRefTest = None
yield (fixtureName, source, externRefTest)
def process_test262(test262Dir, test262OutDir, strictTests, externManifests):
"""
Process all test262 files and converts them into jstests compatible tests.
"""
@ -407,14 +431,29 @@ def process_test262(test262Dir, test262OutDir, strictTests):
shutil.copyfile(filePath, os.path.join(test262OutDir, testName))
continue
# Files ending with "_FIXTURE.js" are fixture files:
# https://github.com/tc39/test262/blob/master/INTERPRETING.md#modules
isFixtureFile = fileName.endswith("_FIXTURE.js")
# Read the original test source and preprocess it for the jstests harness.
with io.open(filePath, "rb") as testFile:
testSource = testFile.read()
for (newFileName, newSource) in convertTestFile(test262parser, testSource, testName,
includeSet, strictTests):
if isFixtureFile:
convert = convertFixtureFile(testSource, testName)
else:
convert = convertTestFile(test262parser, testSource, testName,
includeSet, strictTests)
for (newFileName, newSource, externRefTest) in convert:
writeTestFile(test262OutDir, newFileName, newSource)
if externRefTest is not None:
externManifests.append({
"name": newFileName,
"reftest": externRefTest,
})
# Add shell.js and browers.js files for the current directory.
writeShellAndBrowserFiles(test262OutDir, harnessDir,
includesMap, localIncludesMap, relPath)
@ -506,7 +545,7 @@ def fetch_local_changes(inDir, outDir, srcDir, strictTests):
shutil.rmtree(outDir)
os.makedirs(outDir)
process_test262(inDir, outDir, strictTests)
process_test262(inDir, outDir, strictTests, [])
def fetch_pr_files(inDir, outDir, prNumber, strictTests):
@ -560,7 +599,7 @@ def fetch_pr_files(inDir, outDir, prNumber, strictTests):
with io.open(os.path.join(inDir, *filename.split("/")), "wb") as output_file:
output_file.write(fileText.encode('utf8'))
process_test262(inDir, prTestsOutDir, strictTests)
process_test262(inDir, prTestsOutDir, strictTests, [])
def general_update(inDir, outDir, strictTests):
@ -595,7 +634,21 @@ def general_update(inDir, outDir, strictTests):
subprocess.check_call(["git", "-C", inDir, "log", "-1"], stdout=info)
# Copy the test files.
process_test262(inDir, outDir, strictTests)
externManifests = []
process_test262(inDir, outDir, strictTests, externManifests)
# Create the external reftest manifest file.
with io.open(os.path.join(outDir, "jstests.list"), "wb") as manifestFile:
manifestFile.write(b"# GENERATED, DO NOT EDIT\n\n")
for externManifest in sorted(externManifests, key=itemgetter("name")):
(terms, comments) = externManifest["reftest"]
if terms:
entry = "%s script %s%s\n" % (
terms,
externManifest["name"],
(" # %s" % comments) if comments else ""
)
manifestFile.write(entry.encode("utf-8"))
# Move test262/local back.
if restoreLocalTestsDir:

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

@ -1,7 +1,5 @@
commit 59b89a1c834faadc359aecc882587b513877b59b
Author: Leo Balter <leonardo.balter@gmail.com>
Date: Tue Feb 26 11:01:57 2019 -0500
commit c822f4c92914333d197191b2b3dec4e923acb4a3
Author: André Bargull <andre.bargull@gmail.com>
Date: Wed Mar 6 09:24:44 2019 -0800
Merge pull request #2083 from leobalter/2034/yaml-extra-lines
Add lint check for leading empty lines in description and info blocks
Fix existing linting errors, update error phase, and add a new flags linter (#2086)

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

@ -0,0 +1,25 @@
# GENERATED, DO NOT EDIT
error:SyntaxError script language/comments/hashbang/escaped-bang-041.js
error:SyntaxError script language/comments/hashbang/escaped-bang-u0021.js
error:SyntaxError script language/comments/hashbang/escaped-bang-u21.js
error:SyntaxError script language/comments/hashbang/escaped-bang-x21.js
error:SyntaxError script language/comments/hashbang/escaped-hash-043.js
error:SyntaxError script language/comments/hashbang/escaped-hash-u0023.js
error:SyntaxError script language/comments/hashbang/escaped-hash-u23.js
error:SyntaxError script language/comments/hashbang/escaped-hash-x23.js
error:SyntaxError script language/comments/hashbang/escaped-hashbang.js
module script language/comments/hashbang/module.js
error:SyntaxError script language/comments/hashbang/multi-line-comment.js
error:SyntaxError script language/comments/hashbang/preceding-directive-prologue-sc.js
error:SyntaxError script language/comments/hashbang/preceding-directive-prologue.js
error:SyntaxError script language/comments/hashbang/preceding-empty-statement.js
error:SyntaxError script language/comments/hashbang/preceding-hashbang.js
error:SyntaxError script language/comments/hashbang/preceding-line-comment.js
error:SyntaxError script language/comments/hashbang/preceding-multi-line-comment.js
error:SyntaxError script language/comments/hashbang/preceding-whitespace.js
error:SyntaxError script language/directive-prologue/10.1.1-2gs.js
error:SyntaxError script language/directive-prologue/10.1.1-5gs.js
error:SyntaxError script language/directive-prologue/10.1.1-8gs.js
error:SyntaxError script language/directive-prologue/14.1-4gs.js
error:SyntaxError script language/directive-prologue/14.1-5gs.js

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

@ -1,4 +1,8 @@
#\041
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -14,5 +18,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,4 +1,8 @@
#\u0021
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -14,5 +18,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,4 +1,8 @@
#\u{21}
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -14,5 +18,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,4 +1,8 @@
#\x21
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -14,5 +18,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,4 +1,8 @@
\043!
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -14,5 +18,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,4 +1,8 @@
\u0023!
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -14,5 +18,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,4 +1,8 @@
\u{23}!
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -14,5 +18,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,4 +1,8 @@
\x23!
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -14,5 +18,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,4 +1,8 @@
\u0023\u0021
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -14,5 +18,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,3 +1,6 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >

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

@ -1,3 +1,6 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >

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

@ -1,4 +1,7 @@
// |reftest| error:SyntaxError
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >

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

@ -1,3 +1,6 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >

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

@ -1,4 +1,8 @@
#!
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >

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

@ -2,6 +2,10 @@
throw "Test262: This statement should not be evaluated.";
these characters should not be considered within a comment
*/
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -15,5 +19,3 @@ negative:
type: SyntaxError
features: [hashbang]
---*/
reportCompare(0, 0);

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

@ -1,3 +1,6 @@
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >

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

@ -1,4 +1,8 @@
#! these characters should be treated as a comment
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >

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

@ -1,5 +1,9 @@
"use strict";
#!
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -15,5 +19,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,5 +1,9 @@
"use strict"
#!
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -15,5 +19,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,4 +1,8 @@
;#!
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -14,5 +18,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,5 +1,9 @@
#!
#!
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -15,5 +19,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,5 +1,9 @@
//
#!
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -15,5 +19,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,5 +1,9 @@
/*
*/#!
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -15,5 +19,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,4 +1,8 @@
#!
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -14,5 +18,3 @@ features: [hashbang]
---*/
throw "Test262: This statement should not be evaluated.";
reportCompare(0, 0);

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

@ -1,4 +1,7 @@
// |reftest| error:SyntaxError
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >

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

@ -1,4 +1,8 @@
#!"use strict"
// Copyright (C) 2019 Leo Balter. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: pending
description: >
@ -6,7 +10,7 @@ description: >
info: |
HashbangComment::
#! SingleLineCommentChars[opt]
flags: [raw, noStrict]
flags: [raw]
features: [hashbang]
---*/

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

@ -1,4 +1,3 @@
// |reftest| error:SyntaxError
// Copyright (c) 2012 Ecma International. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
@ -14,5 +13,5 @@ flags: [raw]
---*/
"use strict"
throw new Error("This code should not execute");
throw "Test262: This statement should not be evaluated.";
var public = 1;

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

@ -1,4 +1,3 @@
// |reftest| error:SyntaxError
// Copyright (c) 2012 Ecma International. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
@ -14,5 +13,5 @@ flags: [raw]
---*/
"use strict";
throw new Error("This code should not execute");
throw "Test262: This statement should not be evaluated.";
var public = 1;

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

@ -1,4 +1,3 @@
// |reftest| error:SyntaxError
// Copyright (c) 2012 Ecma International. All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
@ -15,5 +14,5 @@ flags: [raw]
"use strict";
"use strict";
throw new Error("This code should not execute");
throw "Test262: This statement should not be evaluated.";
var public = 1;

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше