зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to mozilla-inbound
This commit is contained in:
Коммит
eba6cadac2
|
@ -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);
|
||||
},
|
||||
|
|
Двоичные данные
browser/components/newtab/data/content/assets/cfr_pinnedtab_animated.png
Normal file
Двоичные данные
browser/components/newtab/data/content/assets/cfr_pinnedtab_animated.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 204 KiB |
Двоичные данные
browser/components/newtab/data/content/assets/cfr_pinnedtab_animated_darktheme.png
Normal file
Двоичные данные
browser/components/newtab/data/content/assets/cfr_pinnedtab_animated_darktheme.png
Normal file
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 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();
|
||||
}
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче