зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-central to mozilla-inbound. r=merge a=merge
This commit is contained in:
Коммит
75303aec29
|
@ -1134,6 +1134,7 @@ toolbarpaletteitem[place="palette"] > #downloads-button[indicator] > #downloads-
|
|||
-moz-image-region: auto;
|
||||
}
|
||||
|
||||
%ifdef MOZ_PHOTON_ANIMATIONS
|
||||
%ifdef MOZ_WIDGET_COCOA
|
||||
|
||||
/* On Mac, use the properties "-moz-window-transform" and "-moz-window-opacity"
|
||||
|
@ -1144,6 +1145,61 @@ toolbarpaletteitem[place="palette"] > #downloads-button[indicator] > #downloads-
|
|||
lot faster. In fact, Gecko no longer triggers shadow shape recomputations
|
||||
for repaints.
|
||||
These properties are not implemented on other platforms. */
|
||||
#BMB_bookmarksPopup:not([animate="false"]) {
|
||||
-moz-window-opacity: 0;
|
||||
-moz-window-transform: translateY(-70px);
|
||||
transition-property: -moz-window-transform, -moz-window-opacity;
|
||||
transition-duration: 0.18s, 0.18s;
|
||||
transition-timing-function:
|
||||
var(--animation-easing-function), ease-out;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[side="bottom"]:not([animate="false"]) {
|
||||
-moz-window-transform: translateY(70px);
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[side][animate="open"] {
|
||||
-moz-window-opacity: 1.0;
|
||||
transition-duration: 0.18s, 0.18s;
|
||||
-moz-window-transform: none;
|
||||
transition-timing-function:
|
||||
var(--animation-easing-function), ease-in-out;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[animate="cancel"] {
|
||||
-moz-window-transform: none;
|
||||
}
|
||||
|
||||
%elifndef MOZ_WIDGET_GTK
|
||||
|
||||
#BMB_bookmarksPopup:not([animate="false"]) {
|
||||
opacity: 0;
|
||||
transform: translateY(-70px);
|
||||
transition-property: transform, opacity;
|
||||
transition-duration: 0.18s, 0.18s;
|
||||
transition-timing-function:
|
||||
var(--animation-easing-function), ease-out;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[side="bottom"]:not([animate="false"]) {
|
||||
transform: translateY(70px);
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[side][animate="open"] {
|
||||
opacity: 1.0;
|
||||
transition-duration: 0.18s, 0.18s;
|
||||
transform: none;
|
||||
transition-timing-function:
|
||||
var(--animation-easing-function), ease-in-out;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[animate="cancel"] {
|
||||
transform: none;
|
||||
}
|
||||
%endif
|
||||
|
||||
%else
|
||||
%ifdef MOZ_WIDGET_COCOA
|
||||
#BMB_bookmarksPopup {
|
||||
-moz-window-transform: scale(.4);
|
||||
-moz-window-opacity: 0;
|
||||
|
@ -1220,6 +1276,7 @@ toolbarpaletteitem[place="palette"] > #downloads-button[indicator] > #downloads-
|
|||
transform-origin: calc(100% - 20px) bottom;
|
||||
}
|
||||
%endif
|
||||
%endif
|
||||
|
||||
/* Customize mode */
|
||||
%ifndef MOZ_PHOTON_THEME
|
||||
|
|
|
@ -1452,6 +1452,11 @@ var gBrowserInit = {
|
|||
gIdentityHandler.refreshIdentityBlock();
|
||||
});
|
||||
|
||||
// Get the service so that it initializes and registers listeners for new
|
||||
// tab pages in order to be ready for any early-loading about:newtab pages,
|
||||
// e.g., start/home page, command line / startup uris to load, sessionstore
|
||||
gAboutNewTabService.QueryInterface(Ci.nsISupports);
|
||||
|
||||
let uriToLoad = this._getUriToLoad();
|
||||
if (uriToLoad && uriToLoad != "about:blank") {
|
||||
if (uriToLoad instanceof Ci.nsIArray) {
|
||||
|
|
|
@ -188,7 +188,7 @@ CustomizeMode.prototype = {
|
|||
|
||||
win.gBrowser.setTabTitle(gTab);
|
||||
win.gBrowser.setIcon(gTab,
|
||||
"chrome://browser/skin/customizableui/customizeFavicon.ico");
|
||||
"chrome://browser/skin/customize.svg");
|
||||
|
||||
gTab.addEventListener("TabClose", unregisterGlobalTab);
|
||||
|
||||
|
|
|
@ -19,13 +19,13 @@ const kSmallWidth = 400;
|
|||
function bookmarksMenuPanelShown() {
|
||||
return new Promise(resolve => {
|
||||
let bookmarksMenuPopup = document.getElementById("BMB_bookmarksPopup");
|
||||
let onTransitionEnd = (e) => {
|
||||
let onPopupShown = (e) => {
|
||||
if (e.target == bookmarksMenuPopup) {
|
||||
bookmarksMenuPopup.removeEventListener("transitionend", onTransitionEnd);
|
||||
bookmarksMenuPopup.removeEventListener("popupshown", onPopupShown);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
bookmarksMenuPopup.addEventListener("transitionend", onTransitionEnd);
|
||||
bookmarksMenuPopup.addEventListener("popupshown", onPopupShown);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ const {utils: Cu, interfaces: Ci} = Components;
|
|||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
|
||||
"resource://gre/modules/Preferences.jsm");
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AboutNewTab",
|
||||
"resource:///modules/AboutNewTab.jsm");
|
||||
|
||||
const LOCAL_NEWTAB_URL = "chrome://browser/content/newtab/newTab.xhtml";
|
||||
|
||||
|
@ -19,12 +19,18 @@ const ACTIVITY_STREAM_URL = "resource://activity-stream/data/content/activity-st
|
|||
|
||||
const ABOUT_URL = "about:newtab";
|
||||
|
||||
const IS_MAIN_PROCESS = Services.appinfo.processType === Services.appinfo.PROCESS_TYPE_DEFAULT;
|
||||
|
||||
// Pref that tells if activity stream is enabled
|
||||
const PREF_ACTIVITY_STREAM_ENABLED = "browser.newtabpage.activity-stream.enabled";
|
||||
|
||||
function AboutNewTabService() {
|
||||
Preferences.observe(PREF_ACTIVITY_STREAM_ENABLED, this._handleToggleEvent.bind(this));
|
||||
this.toggleActivityStream(Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_ENABLED));
|
||||
Services.obs.addObserver(this, "quit-application-granted");
|
||||
Services.prefs.addObserver(PREF_ACTIVITY_STREAM_ENABLED, this);
|
||||
this.toggleActivityStream();
|
||||
if (IS_MAIN_PROCESS) {
|
||||
AboutNewTab.init();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -68,14 +74,28 @@ AboutNewTabService.prototype = {
|
|||
_overridden: false,
|
||||
|
||||
classID: Components.ID("{dfcd2adc-7867-4d3a-ba70-17501f208142}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIAboutNewTabService]),
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsIAboutNewTabService,
|
||||
Ci.nsIObserver
|
||||
]),
|
||||
_xpcom_categories: [{
|
||||
service: true
|
||||
}],
|
||||
|
||||
_handleToggleEvent(stateEnabled) {
|
||||
if (this.toggleActivityStream(stateEnabled)) {
|
||||
Services.obs.notifyObservers(null, "newtab-url-changed", ABOUT_URL);
|
||||
observe(subject, topic, data) {
|
||||
switch (topic) {
|
||||
case "nsPref:changed":
|
||||
if (this.toggleActivityStream()) {
|
||||
Services.obs.notifyObservers(null, "newtab-url-changed", ABOUT_URL);
|
||||
}
|
||||
break;
|
||||
case "quit-application-granted":
|
||||
Services.obs.removeObserver(this, "quit-application-granted");
|
||||
Services.prefs.removeObserver(PREF_ACTIVITY_STREAM_ENABLED, this);
|
||||
if (IS_MAIN_PROCESS) {
|
||||
AboutNewTab.uninit();
|
||||
}
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -93,7 +113,8 @@ AboutNewTabService.prototype = {
|
|||
* @param {Boolean} stateEnabled activity stream enabled state to set to
|
||||
* @param {Boolean} forceState force state change
|
||||
*/
|
||||
toggleActivityStream(stateEnabled, forceState = false) {
|
||||
toggleActivityStream(stateEnabled = Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_ENABLED),
|
||||
forceState = false) {
|
||||
|
||||
if (!forceState && (this.overridden || stateEnabled === this.activityStreamEnabled)) {
|
||||
// exit there is no change of state
|
||||
|
@ -158,7 +179,7 @@ AboutNewTabService.prototype = {
|
|||
resetNewTabURL() {
|
||||
this._overridden = false;
|
||||
this._newTabURL = ABOUT_URL;
|
||||
this.toggleActivityStream(Services.prefs.getBoolPref(PREF_ACTIVITY_STREAM_ENABLED), true);
|
||||
this.toggleActivityStream(undefined, true);
|
||||
Services.obs.notifyObservers(null, "newtab-url-changed", this._newTabURL);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -25,7 +25,7 @@ XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
|
|||
|
||||
// lazy module getters
|
||||
|
||||
/* global AboutHome:false, AboutNewTab:false, AddonManager:false, AppMenuNotifications:false,
|
||||
/* global AboutHome:false, AddonManager:false, AppMenuNotifications:false,
|
||||
AsyncPrefs: false, AsyncShutdown:false, AutoCompletePopup:false, BookmarkHTMLUtils:false,
|
||||
BookmarkJSONUtils:false, BrowserUITelemetry:false, BrowserUsageTelemetry:false,
|
||||
ContentClick:false, ContentPrefServiceParent:false, ContentSearch:false,
|
||||
|
@ -54,7 +54,6 @@ let initializedModules = {};
|
|||
|
||||
[
|
||||
["AboutHome", "resource:///modules/AboutHome.jsm", "init"],
|
||||
["AboutNewTab", "resource:///modules/AboutNewTab.jsm"],
|
||||
["AddonManager", "resource://gre/modules/AddonManager.jsm"],
|
||||
["AppMenuNotifications", "resource://gre/modules/AppMenuNotifications.jsm"],
|
||||
["AsyncPrefs", "resource://gre/modules/AsyncPrefs.jsm"],
|
||||
|
@ -969,7 +968,6 @@ BrowserGlue.prototype = {
|
|||
DirectoryLinksProvider.init();
|
||||
NewTabUtils.init();
|
||||
NewTabUtils.links.addProvider(DirectoryLinksProvider);
|
||||
AboutNewTab.init();
|
||||
|
||||
PageActions.init();
|
||||
|
||||
|
@ -1030,7 +1028,6 @@ BrowserGlue.prototype = {
|
|||
BrowserUsageTelemetry.uninit();
|
||||
|
||||
PageThumbs.uninit();
|
||||
AboutNewTab.uninit();
|
||||
NewTabUtils.uninit();
|
||||
AutoCompletePopup.uninit();
|
||||
DateTimePickerHelper.uninit();
|
||||
|
|
|
@ -605,7 +605,7 @@
|
|||
]]></handler>
|
||||
<handler event="transitionend"><![CDATA[
|
||||
if (event.originalTarget.getAttribute("anonid") == "container" &&
|
||||
event.propertyName == "transform") {
|
||||
(event.propertyName == "transform" || event.propertyName == "-moz-window-transform")) {
|
||||
this.style.removeProperty("pointer-events");
|
||||
}
|
||||
]]></handler>
|
||||
|
|
|
@ -133,6 +133,13 @@ this.ActivityStreamMessageChannel = class ActivityStreamMessageChannel {
|
|||
this.channel.addMessageListener("RemotePage:Load", this.onNewTabLoad);
|
||||
this.channel.addMessageListener("RemotePage:Unload", this.onNewTabUnload);
|
||||
this.channel.addMessageListener(this.incomingMessageName, this.onMessage);
|
||||
|
||||
// Some pages might have already loaded, so we won't get the usual message
|
||||
for (const {loaded, portID} of this.channel.messagePorts) {
|
||||
if (loaded) {
|
||||
this.onNewTabLoad({target: {portID}});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,7 +21,7 @@ const TEST_THRESHOLD = {
|
|||
// If a user qualifies for the e10s-multi experiement, this is how many
|
||||
// content processes to use and whether to allow addons for the experiment.
|
||||
const MULTI_EXPERIMENT = {
|
||||
"beta": { buckets: { 1: .5, 4: 1, }, // 1 process: 50%, 4 processes: 50%
|
||||
"beta": { buckets: { 4: 1, }, // 4 processes: 100%
|
||||
|
||||
// When on the "beta" channel, getAddonsDisqualifyForMulti
|
||||
// will return true if any addon installed is not a web extension.
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
<Description about="urn:mozilla:install-manifest">
|
||||
<em:id>e10srollout@mozilla.org</em:id>
|
||||
<em:version>2.1</em:version>
|
||||
<em:version>2.15</em:version>
|
||||
<em:type>2</em:type>
|
||||
<em:bootstrap>true</em:bootstrap>
|
||||
<em:multiprocessCompatible>true</em:multiprocessCompatible>
|
||||
|
|
Двоичные данные
browser/themes/shared/customizableui/customizeFavicon.ico
Двоичные данные
browser/themes/shared/customizableui/customizeFavicon.ico
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 1.1 KiB |
|
@ -357,7 +357,7 @@ photonpanelmultiview panelview {
|
|||
}
|
||||
|
||||
photonpanelmultiview .panel-subview-body {
|
||||
margin: 4px 0;
|
||||
padding: 6px 0;
|
||||
}
|
||||
|
||||
/* END photonpanelview adjustments */
|
||||
|
@ -1222,10 +1222,11 @@ panelview:not([mainView]) .subviewbutton.panel-subview-footer > .toolbarbutton-t
|
|||
content: url(chrome://browser/skin/back-12.svg);
|
||||
fill: GrayText;
|
||||
float: right;
|
||||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
.PanelUI-subView .subviewbutton-nav:-moz-locale-dir(ltr)::after {
|
||||
transform: scaleX(-1);
|
||||
transform: scaleX(-1) translateY(1px);
|
||||
}
|
||||
|
||||
.subviewbutton[shortcut]::after,
|
||||
|
@ -1408,7 +1409,7 @@ menuitem.subviewbutton@menuStateActive@,
|
|||
}
|
||||
|
||||
.subviewbutton.panel-subview-footer {
|
||||
margin: 4px -4px -4px;
|
||||
margin: 0;
|
||||
background-color: var(--arrowpanel-dimmed);
|
||||
border-top: 1px solid var(--panel-separator-color);
|
||||
border-radius: 0;
|
||||
|
@ -1501,8 +1502,8 @@ menuitem.panel-subview-footer@menuStateActive@,
|
|||
border-inline-start: 1px solid var(--panel-separator-color);
|
||||
border-top: none;
|
||||
margin: 0;
|
||||
margin-inline-start: 4px;
|
||||
margin-inline-end: 5px;
|
||||
margin-inline-start: 6px;
|
||||
margin-inline-end: 7px;
|
||||
}
|
||||
|
||||
.subviewbutton > .menu-accel-container {
|
||||
|
|
|
@ -31,7 +31,6 @@
|
|||
* skin/classic/browser/controlcenter/tracking-protection.svg (../shared/controlcenter/tracking-protection.svg)
|
||||
skin/classic/browser/controlcenter/warning-gray.svg (../shared/controlcenter/warning-gray.svg)
|
||||
skin/classic/browser/controlcenter/warning-yellow.svg (../shared/controlcenter/warning-yellow.svg)
|
||||
skin/classic/browser/customizableui/customizeFavicon.ico (../shared/customizableui/customizeFavicon.ico)
|
||||
skin/classic/browser/customizableui/menuPanel-customizeFinish.png (../shared/customizableui/menuPanel-customizeFinish.png)
|
||||
skin/classic/browser/customizableui/menuPanel-customizeFinish@2x.png (../shared/customizableui/menuPanel-customizeFinish@2x.png)
|
||||
#ifdef MOZ_PHOTON_THEME
|
||||
|
|
|
@ -8,7 +8,7 @@ this.EXPORTED_SYMBOLS = ["Tabs"];
|
|||
|
||||
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
|
||||
|
||||
const CUST_TAB = "chrome://browser/skin/customizableui/customizeFavicon.ico";
|
||||
const CUST_TAB = "chrome://browser/skin/customize.svg";
|
||||
const PREFS_TAB = "chrome://browser/skin/settings.svg";
|
||||
const DEFAULT_FAVICON_TAB = `data:text/html,<meta charset="utf-8">
|
||||
<title>No favicon</title>`;
|
||||
|
|
|
@ -16,12 +16,15 @@ support-files =
|
|||
code_binary_search.map
|
||||
code_binary_search_absolute.js
|
||||
code_binary_search_absolute.map
|
||||
code_bundle_cross_domain.js
|
||||
code_bundle_cross_domain.js.map
|
||||
code_bundle_no_race.js
|
||||
code_bundle_no_race.js.map
|
||||
code_bundle_reload_1.js
|
||||
code_bundle_reload_1.js.map
|
||||
code_bundle_reload_2.js
|
||||
code_bundle_reload_2.js.map
|
||||
code_cross_domain.js
|
||||
code_inline_bundle.js
|
||||
code_inline_original.js
|
||||
code_math.js
|
||||
|
@ -59,6 +62,7 @@ skip-if = debug # Bug 1282269
|
|||
[browser_new_activation_workflow.js]
|
||||
[browser_source_map-01.js]
|
||||
[browser_source_map-absolute.js]
|
||||
[browser_source_map-cross-domain.js]
|
||||
[browser_source_map-inline.js]
|
||||
[browser_source_map-no-race.js]
|
||||
[browser_source_map-reload.js]
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Test that the source map service can fetch a source map from a
|
||||
// different domain.
|
||||
|
||||
"use strict";
|
||||
|
||||
const JS_URL = URL_ROOT + "code_bundle_cross_domain.js";
|
||||
|
||||
const PAGE_URL = `data:text/html,
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Empty test page to test cross domain source map</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script src="${JS_URL}"></script>
|
||||
</body>
|
||||
|
||||
</html>`;
|
||||
|
||||
const ORIGINAL_URL = "webpack:///code_cross_domain.js";
|
||||
|
||||
const GENERATED_LINE = 82;
|
||||
const ORIGINAL_LINE = 12;
|
||||
|
||||
add_task(function* () {
|
||||
const toolbox = yield openNewTabAndToolbox(PAGE_URL, "webconsole");
|
||||
const service = toolbox.sourceMapURLService;
|
||||
|
||||
info(`checking original location for ${JS_URL}:${GENERATED_LINE}`);
|
||||
let newLoc = yield service.originalPositionFor(JS_URL, GENERATED_LINE);
|
||||
is(newLoc.sourceUrl, ORIGINAL_URL, "check mapped URL");
|
||||
is(newLoc.line, ORIGINAL_LINE, "check mapped line number");
|
||||
});
|
|
@ -0,0 +1,93 @@
|
|||
/******/ (function(modules) { // webpackBootstrap
|
||||
/******/ // The module cache
|
||||
/******/ var installedModules = {};
|
||||
/******/
|
||||
/******/ // The require function
|
||||
/******/ function __webpack_require__(moduleId) {
|
||||
/******/
|
||||
/******/ // Check if module is in cache
|
||||
/******/ if(installedModules[moduleId]) {
|
||||
/******/ return installedModules[moduleId].exports;
|
||||
/******/ }
|
||||
/******/ // Create a new module (and put it into the cache)
|
||||
/******/ var module = installedModules[moduleId] = {
|
||||
/******/ i: moduleId,
|
||||
/******/ l: false,
|
||||
/******/ exports: {}
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Execute the module function
|
||||
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
|
||||
/******/
|
||||
/******/ // Flag the module as loaded
|
||||
/******/ module.l = true;
|
||||
/******/
|
||||
/******/ // Return the exports of the module
|
||||
/******/ return module.exports;
|
||||
/******/ }
|
||||
/******/
|
||||
/******/
|
||||
/******/ // expose the modules object (__webpack_modules__)
|
||||
/******/ __webpack_require__.m = modules;
|
||||
/******/
|
||||
/******/ // expose the module cache
|
||||
/******/ __webpack_require__.c = installedModules;
|
||||
/******/
|
||||
/******/ // define getter function for harmony exports
|
||||
/******/ __webpack_require__.d = function(exports, name, getter) {
|
||||
/******/ if(!__webpack_require__.o(exports, name)) {
|
||||
/******/ Object.defineProperty(exports, name, {
|
||||
/******/ configurable: false,
|
||||
/******/ enumerable: true,
|
||||
/******/ get: getter
|
||||
/******/ });
|
||||
/******/ }
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // getDefaultExport function for compatibility with non-harmony modules
|
||||
/******/ __webpack_require__.n = function(module) {
|
||||
/******/ var getter = module && module.__esModule ?
|
||||
/******/ function getDefault() { return module['default']; } :
|
||||
/******/ function getModuleExports() { return module; };
|
||||
/******/ __webpack_require__.d(getter, 'a', getter);
|
||||
/******/ return getter;
|
||||
/******/ };
|
||||
/******/
|
||||
/******/ // Object.prototype.hasOwnProperty.call
|
||||
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
|
||||
/******/
|
||||
/******/ // __webpack_public_path__
|
||||
/******/ __webpack_require__.p = "";
|
||||
/******/
|
||||
/******/ // Load entry module and return exports
|
||||
/******/ return __webpack_require__(__webpack_require__.s = 0);
|
||||
/******/ })
|
||||
/************************************************************************/
|
||||
/******/ ([
|
||||
/* 0 */
|
||||
/***/ (function(module, exports, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Original source code for the cross-domain source map test.
|
||||
// The generated file was made with
|
||||
// webpack --devtool source-map code_cross_domain.js code_bundle_cross_domain.js
|
||||
// ... and then edited to replace the generated sourceMappingURL.
|
||||
|
||||
|
||||
|
||||
function f() {
|
||||
console.log("anything will do");
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
// Avoid script GC.
|
||||
window.f = f;
|
||||
|
||||
|
||||
/***/ })
|
||||
/******/ ]);
|
||||
//# sourceMappingURL=http://test2.mochi.test:8888/browser/devtools/client/framework/test/code_bundle_cross_domain.js.map
|
|
@ -0,0 +1 @@
|
|||
{"version":3,"sources":["webpack:///webpack/bootstrap 7b928b82bd207211f478","webpack:///./code_cross_domain.js"],"names":[],"mappings":";AAAA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAK;AACL;AACA;;AAEA;AACA;AACA;AACA,mCAA2B,0BAA0B,EAAE;AACvD,yCAAiC,eAAe;AAChD;AACA;AACA;;AAEA;AACA,8DAAsD,+DAA+D;;AAErH;AACA;;AAEA;AACA;;;;;;;;AC7DA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA","file":"code_bundle_cross_domain.js","sourcesContent":[" \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, {\n \t\t\t\tconfigurable: false,\n \t\t\t\tenumerable: true,\n \t\t\t\tget: getter\n \t\t\t});\n \t\t}\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n\n\n\n// WEBPACK FOOTER //\n// webpack/bootstrap 7b928b82bd207211f478","/* Any copyright is dedicated to the Public Domain.\n http://creativecommons.org/publicdomain/zero/1.0/ */\n\n// Original source code for the cross-domain source map test.\n// The generated file was made with\n// webpack --devtool source-map code_cross_domain.js code_bundle_cross_domain.js\n// ... and then edited to replace the generated sourceMappingURL.\n\n\"use strict\";\n\nfunction f() {\n console.log(\"anything will do\");\n}\n\nf();\n\n// Avoid script GC.\nwindow.f = f;\n\n\n\n//////////////////\n// WEBPACK FOOTER\n// ./code_cross_domain.js\n// module id = 0\n// module chunks = 0"],"sourceRoot":""}
|
|
@ -0,0 +1,19 @@
|
|||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
// Original source code for the cross-domain source map test.
|
||||
// The generated file was made with
|
||||
// webpack --devtool source-map code_cross_domain.js code_bundle_cross_domain.js
|
||||
// ... and then the bundle was edited to replace the generated
|
||||
// sourceMappingURL.
|
||||
|
||||
"use strict";
|
||||
|
||||
function f() {
|
||||
console.log("anything will do");
|
||||
}
|
||||
|
||||
f();
|
||||
|
||||
// Avoid script GC.
|
||||
window.f = f;
|
|
@ -551,7 +551,12 @@ Toolbox.prototype = {
|
|||
get: (target, name) => {
|
||||
if (name === "getOriginalURLs") {
|
||||
return (urlInfo) => {
|
||||
return target.getOriginalURLs(urlInfo).catch(console.error);
|
||||
return target.getOriginalURLs(urlInfo)
|
||||
.catch(text => {
|
||||
let message = L10N.getFormatStr("toolbox.sourceMapFailure",
|
||||
text, urlInfo.url, urlInfo.sourceMapURL);
|
||||
this.target.logErrorInPage(message, "source map");
|
||||
});
|
||||
};
|
||||
}
|
||||
return target[name];
|
||||
|
|
|
@ -177,3 +177,10 @@ toolbox.closebutton.tooltip=Close Developer Tools
|
|||
# LOCALIZATION NOTE (toolbox.allToolsButton.tooltip): This is the tooltip for the
|
||||
# "all tools" button displayed when some tools are hidden by overflow of the toolbar.
|
||||
toolbox.allToolsButton.tooltip=Select another tool
|
||||
|
||||
# LOCALIZATION NOTE (toolbox.sourceMapFailure): This is shown in the web console
|
||||
# when there is a failure to fetch or parse a source map.
|
||||
# The text of the error: %1$S
|
||||
# The URL that caused DevTools to try to fetch a source map: %2$S
|
||||
# The URL of the source map itself: %3$S
|
||||
toolbox.sourceMapFailure=Source map error: %1$S\nResource URL: %2$S\nSource Map URL: %3$S
|
||||
|
|
|
@ -148,7 +148,7 @@ a {
|
|||
display: flex;
|
||||
}
|
||||
|
||||
.message-body > * {
|
||||
.message-body {
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ var styleSheets = [
|
|||
// on the right CSS strategy FIXME.
|
||||
// It would also be nice to include them using @import.
|
||||
styleSheets.forEach(url => {
|
||||
loadSheet(this, url, "author");
|
||||
loadSheet(window, url, "author");
|
||||
});
|
||||
|
||||
// Localization API used by React components
|
||||
|
|
|
@ -267,7 +267,6 @@ stubPreparedMessages.set("console.assert(false, {message: 'foobar'})", new Conso
|
|||
"columnNumber": 27,
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "triggerPacket",
|
||||
"language": 2,
|
||||
"lineNumber": 1
|
||||
}
|
||||
],
|
||||
|
@ -666,21 +665,18 @@ stubPreparedMessages.set("console.trace()", new ConsoleMessage({
|
|||
"columnNumber": 3,
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "testStacktraceFiltering",
|
||||
"language": 2,
|
||||
"lineNumber": 3
|
||||
},
|
||||
{
|
||||
"columnNumber": 3,
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "foo",
|
||||
"language": 2,
|
||||
"lineNumber": 6
|
||||
},
|
||||
{
|
||||
"columnNumber": 1,
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "triggerPacket",
|
||||
"language": 2,
|
||||
"lineNumber": 9
|
||||
}
|
||||
],
|
||||
|
@ -1462,7 +1458,6 @@ stubPackets.set("console.assert(false, {message: 'foobar'})", {
|
|||
"columnNumber": 27,
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "triggerPacket",
|
||||
"language": 2,
|
||||
"lineNumber": 1
|
||||
}
|
||||
],
|
||||
|
@ -1841,21 +1836,18 @@ stubPackets.set("console.trace()", {
|
|||
"columnNumber": 3,
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "testStacktraceFiltering",
|
||||
"language": 2,
|
||||
"lineNumber": 3
|
||||
},
|
||||
{
|
||||
"columnNumber": 3,
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "foo",
|
||||
"language": 2,
|
||||
"lineNumber": 6
|
||||
},
|
||||
{
|
||||
"columnNumber": 1,
|
||||
"filename": "http://example.com/browser/devtools/client/webconsole/new-console-output/test/fixtures/stub-generators/test-console-api.html",
|
||||
"functionName": "triggerPacket",
|
||||
"language": 2,
|
||||
"lineNumber": 9
|
||||
}
|
||||
],
|
||||
|
|
|
@ -15,6 +15,10 @@ support-files =
|
|||
test-location-styleeditor-link-2.css
|
||||
test-location-styleeditor-link.html
|
||||
test-network-request.html
|
||||
test-sourcemap-error-01.html
|
||||
test-sourcemap-error-02.html
|
||||
test-sourcemap-error-01.js
|
||||
test-sourcemap-error-02.js
|
||||
test-stacktrace-location-debugger-link.html
|
||||
!/devtools/client/framework/test/shared-head.js
|
||||
|
||||
|
@ -48,7 +52,9 @@ skip-if = (os == 'linux' && bits == 32 && debug) # bug 1328915, disable linux32
|
|||
[browser_webconsole_object_inspector.js]
|
||||
[browser_webconsole_observer_notifications.js]
|
||||
[browser_webconsole_shows_reqs_in_netmonitor.js]
|
||||
[browser_webconsole_sourcemap_error.js]
|
||||
[browser_webconsole_stacktrace_location_debugger_link.js]
|
||||
[browser_webconsole_stacktrace_location_scratchpad_link.js]
|
||||
[browser_webconsole_string.js]
|
||||
[browser_webconsole_timestamps.js]
|
||||
[browser_webconsole_warn_about_replaced_api.js]
|
||||
|
|
|
@ -32,7 +32,7 @@ add_task(async function task() {
|
|||
}]
|
||||
});
|
||||
|
||||
await loadDocument(currentTab.linkedBrowser, TEST_PATH);
|
||||
await loadDocument(TEST_PATH);
|
||||
info("Document loaded.");
|
||||
|
||||
await onMessageAdded;
|
||||
|
|
|
@ -27,7 +27,7 @@ add_task(async function task() {
|
|||
let toolbox = gDevTools.getToolbox(target);
|
||||
|
||||
const documentUrl = TEST_PATH + TEST_FILE;
|
||||
await loadDocument(currentTab.linkedBrowser, documentUrl);
|
||||
await loadDocument(documentUrl);
|
||||
info("Document loaded.");
|
||||
|
||||
await testNetmonitorLink(toolbox, hud, documentUrl);
|
||||
|
|
|
@ -21,10 +21,9 @@ registerCleanupFunction(() => {
|
|||
|
||||
add_task(async function () {
|
||||
const toolbox = await openNewTabAndToolbox(TEST_URI, "netmonitor");
|
||||
const currentTab = gBrowser.selectedTab;
|
||||
info("Network panel is open.");
|
||||
|
||||
await loadDocument(currentTab.linkedBrowser, TEST_PATH);
|
||||
await loadDocument(TEST_PATH);
|
||||
info("Document loaded.");
|
||||
|
||||
// Test that the request appears in the network panel.
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Test that a missing source map is reported.
|
||||
|
||||
const BASE = "http://example.com/browser/devtools/client/webconsole/new-console-output/test/mochitest/";
|
||||
|
||||
add_task(async function () {
|
||||
for (let test of ["test-sourcemap-error-01.html", "test-sourcemap-error-02.html"]) {
|
||||
const hud = await openNewTabAndConsole(BASE + test);
|
||||
|
||||
const node = await waitFor(() => findMessage(hud, "here"));
|
||||
ok(node, "logged text is displayed in web console");
|
||||
|
||||
const node2 = await waitFor(() => findMessage(hud, "Source map error"));
|
||||
ok(node2, "source map error is displayed in web console");
|
||||
}
|
||||
});
|
|
@ -0,0 +1,54 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
const TEST_URI_REPLACED =
|
||||
"data:text/html;charset=utf8,<script>console = {log: () => ''}</script>";
|
||||
const TEST_URI_NOT_REPLACED =
|
||||
"data:text/html;charset=utf8,<script>console.log('foo')</script>";
|
||||
|
||||
add_task(async function () {
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["devtools.webconsole.persistlog", true]
|
||||
]});
|
||||
|
||||
let hud = await openNewTabAndConsole(TEST_URI_NOT_REPLACED);
|
||||
|
||||
await testWarningNotPresent(hud);
|
||||
await closeToolbox();
|
||||
|
||||
await loadDocument(TEST_URI_REPLACED);
|
||||
|
||||
let toolbox = await openToolboxForTab(gBrowser.selectedTab, "webconsole");
|
||||
hud = toolbox.getCurrentPanel().hud;
|
||||
await testWarningPresent(hud);
|
||||
});
|
||||
|
||||
async function testWarningNotPresent(hud) {
|
||||
ok(!findMessage(hud, "logging API"), "no warning displayed");
|
||||
|
||||
// Bug 862024: make sure the warning doesn't show after page reload.
|
||||
info("wait for the page to refresh and make sure the warning still isn't there");
|
||||
await refreshTab();
|
||||
await waitFor(() => {
|
||||
// We need to wait for 3 messages because there are two logs, plus the
|
||||
// navigation message since messages are persisted
|
||||
return findMessages(hud, "foo").length === 3;
|
||||
});
|
||||
|
||||
ok(!findMessage(hud, "logging API"), "no warning displayed");
|
||||
}
|
||||
|
||||
async function testWarningPresent(hud) {
|
||||
info("wait for the warning to show");
|
||||
await waitFor(() => findMessage(hud, "logging API"));
|
||||
|
||||
info("reload the test page and wait for the warning to show");
|
||||
await refreshTab();
|
||||
await waitFor(() => {
|
||||
return findMessages(hud, "logging API").length === 2;
|
||||
});
|
||||
}
|
|
@ -179,7 +179,7 @@ function hideContextMenu(hud) {
|
|||
return onPopupHidden;
|
||||
}
|
||||
|
||||
function loadDocument(browser, url) {
|
||||
function loadDocument(url, browser = gBrowser.selectedBrowser) {
|
||||
return new Promise(resolve => {
|
||||
browser.addEventListener("load", resolve, {capture: true, once: true});
|
||||
BrowserTestUtils.loadURI(gBrowser.selectedBrowser, url);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test that a missing source map is reported to the console</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript" src="test-sourcemap-error-01.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Web Console test for source map failure.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
window.qqz = function () {
|
||||
console.log("here");
|
||||
};
|
||||
window.qqz();
|
||||
/* eslint-disable spaced-comment */
|
||||
//# sourceMappingURL=no-such-file.js.map
|
|
@ -0,0 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test that an invalid source map URL is reported to the console</title>
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<script type="text/javascript" src="test-sourcemap-error-02.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p>Web Console test for source map failure.</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,7 @@
|
|||
"use strict";
|
||||
window.qqz = function () {
|
||||
console.log("here");
|
||||
};
|
||||
window.qqz();
|
||||
/* eslint-disable spaced-comment */
|
||||
//# sourceMappingURL=data:invalid
|
|
@ -139,7 +139,8 @@ NewWebConsoleFrame.prototype = {
|
|||
},
|
||||
|
||||
logWarningAboutReplacedAPI() {
|
||||
|
||||
this.owner.target.logErrorInPage(l10n.getStr("ConsoleAPIDisabled"),
|
||||
"ConsoleAPIDisabled");
|
||||
},
|
||||
|
||||
handleNetworkEventUpdate() {
|
||||
|
|
|
@ -37,28 +37,24 @@ add_task(function* () {
|
|||
columnNumber: 3,
|
||||
filename: TEST_URI,
|
||||
functionName: "window.foobar585956c",
|
||||
language: 2,
|
||||
lineNumber: 9
|
||||
},
|
||||
{
|
||||
columnNumber: 10,
|
||||
filename: TEST_URI,
|
||||
functionName: "foobar585956b",
|
||||
language: 2,
|
||||
lineNumber: 14
|
||||
},
|
||||
{
|
||||
columnNumber: 10,
|
||||
filename: TEST_URI,
|
||||
functionName: "foobar585956a",
|
||||
language: 2,
|
||||
lineNumber: 18
|
||||
},
|
||||
{
|
||||
columnNumber: 1,
|
||||
filename: TEST_URI,
|
||||
functionName: "",
|
||||
language: 2,
|
||||
lineNumber: 21
|
||||
}
|
||||
];
|
||||
|
|
|
@ -46,7 +46,6 @@ add_task(function* runTest() {
|
|||
columnNumber: 3,
|
||||
filename: TEST_URI,
|
||||
functionName: "inner",
|
||||
language: 2,
|
||||
lineNumber: 9
|
||||
},
|
||||
{
|
||||
|
@ -54,7 +53,6 @@ add_task(function* runTest() {
|
|||
columnNumber: 3,
|
||||
filename: TEST_URI,
|
||||
functionName: "time1",
|
||||
language: 2,
|
||||
lineNumber: 13,
|
||||
},
|
||||
{
|
||||
|
@ -62,7 +60,6 @@ add_task(function* runTest() {
|
|||
columnNumber: 1,
|
||||
filename: TEST_URI,
|
||||
functionName: "",
|
||||
language: 2,
|
||||
lineNumber: 18,
|
||||
}
|
||||
];
|
||||
|
|
|
@ -267,9 +267,9 @@ WebConsoleConnectionProxy.prototype = {
|
|||
this.dispatchMessagesAdd(messages);
|
||||
} else {
|
||||
this.webConsoleFrame.displayCachedMessages(messages);
|
||||
if (!this._hasNativeConsoleAPI) {
|
||||
this.webConsoleFrame.logWarningAboutReplacedAPI();
|
||||
}
|
||||
}
|
||||
if (!this._hasNativeConsoleAPI) {
|
||||
this.webConsoleFrame.logWarningAboutReplacedAPI();
|
||||
}
|
||||
|
||||
this.connected = true;
|
||||
|
|
|
@ -160,6 +160,11 @@ XPCOMUtils.defineLazyGetter(this, "KeyShortcuts", function () {
|
|||
function DevToolsStartup() {}
|
||||
|
||||
DevToolsStartup.prototype = {
|
||||
/**
|
||||
* Flag that indicates if the developer toggle was already added to customizableUI.
|
||||
*/
|
||||
developerToggleCreated: false,
|
||||
|
||||
handle: function (cmdLine) {
|
||||
let consoleFlag = cmdLine.handleFlag("jsconsole", false);
|
||||
let debuggerFlag = cmdLine.handleFlag("jsdebugger", false);
|
||||
|
@ -206,15 +211,19 @@ DevToolsStartup.prototype = {
|
|||
* We do that to prevent loading any DevTools module until the user intent to use them.
|
||||
*/
|
||||
hookWindow(window) {
|
||||
// Key Shortcuts need to be added on all the created windows.
|
||||
this.hookKeyShortcuts(window);
|
||||
|
||||
// All the other hooks are only necessary if the tools aren't loaded yet.
|
||||
if (this.initialized) {
|
||||
return;
|
||||
if (!this.developerToggleCreated) {
|
||||
this.hookDeveloperToggle();
|
||||
this.developerToggleCreated = true;
|
||||
}
|
||||
|
||||
this.hookWebDeveloperMenu(window);
|
||||
this.hookDeveloperToggle(window);
|
||||
// The developer menu hook only needs to be added if devtools have not been
|
||||
// initialized yet.
|
||||
if (!this.initialized) {
|
||||
this.hookWebDeveloperMenu(window);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -233,7 +242,7 @@ DevToolsStartup.prototype = {
|
|||
* devtools/client/framework/browser-menu to create the items for real,
|
||||
* initDevTools, from onViewShowing is also calling browser-menu.
|
||||
*/
|
||||
hookDeveloperToggle(window) {
|
||||
hookDeveloperToggle() {
|
||||
let id = "developer-button";
|
||||
let widget = CustomizableUI.getWidget(id);
|
||||
if (widget && widget.provider == CustomizableUI.PROVIDER_API) {
|
||||
|
|
|
@ -80,13 +80,18 @@ NodeIsInTraversalRange(nsINode* aNode, bool aIsPreMode,
|
|||
NS_WARNING_ASSERTION(indx != -1, "bad indx");
|
||||
|
||||
if (!aIsPreMode) {
|
||||
++indx;
|
||||
// Post mode: start < node <= end.
|
||||
return nsContentUtils::ComparePoints(aStartContainer, aStartOffset,
|
||||
parent, indx + 1) < 0 &&
|
||||
nsContentUtils::ComparePoints(aEndContainer, aEndOffset,
|
||||
parent, indx + 1) >= 0;
|
||||
}
|
||||
|
||||
// Pre mode: start <= node < end.
|
||||
return nsContentUtils::ComparePoints(aStartContainer, aStartOffset,
|
||||
parent, indx) <= 0 &&
|
||||
nsContentUtils::ComparePoints(aEndContainer, aEndOffset,
|
||||
parent, indx) >= 0;
|
||||
parent, indx) > 0;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -277,6 +277,8 @@
|
|||
#endif // MOZ_WEBRTC
|
||||
|
||||
#include "nsIURIClassifier.h"
|
||||
#include "mozilla/DocumentStyleRootIterator.h"
|
||||
#include "mozilla/ServoRestyleManager.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -1350,6 +1352,7 @@ nsIDocument::nsIDocument()
|
|||
mFrameRequestCallbacksScheduled(false),
|
||||
mIsTopLevelContentDocument(false),
|
||||
mIsContentDocument(false),
|
||||
mMightHaveStaleServoData(false),
|
||||
mIsScopedStyleEnabled(eScopedStyle_Unknown),
|
||||
mCompatMode(eCompatibility_FullStandards),
|
||||
mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
|
||||
|
@ -3907,6 +3910,9 @@ nsDocument::CreateShell(nsPresContext* aContext, nsViewManager* aViewManager,
|
|||
|
||||
FillStyleSet(aStyleSet);
|
||||
|
||||
// Ensure we start with no stale data in the tree.
|
||||
ClearStaleServoDataFromDocument();
|
||||
|
||||
RefPtr<PresShell> shell = new PresShell;
|
||||
shell->Init(this, aContext, aViewManager, aStyleSet);
|
||||
|
||||
|
@ -4026,6 +4032,18 @@ nsDocument::DeleteShell()
|
|||
mPresShell = nullptr;
|
||||
UpdateFrameRequestCallbackSchedulingState(oldShell);
|
||||
mStyleSetFilled = false;
|
||||
|
||||
// Record that the tree might have stale Servo element data in it
|
||||
// that would need to be cleared if we ever get a new pres shell
|
||||
// or if we call ServoStyleSet style resolving functions on
|
||||
// elements in the document. Most of the time this lazy clearing
|
||||
// of Servo element data saves us work, since it's not often that a
|
||||
// document gets a new pres shell after its old one is destroyed.
|
||||
// In those cases we rely on the data being cleared in UnbindFromTree
|
||||
// and save this additional traversal.
|
||||
if (IsStyledByServo()) {
|
||||
mMightHaveStaleServoData = true;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -12686,7 +12704,7 @@ nsIDocument::InlineScriptAllowedByCSP()
|
|||
nsresult rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
|
||||
EmptyString(), // aNonce
|
||||
true, // aParserCreated
|
||||
EmptyString(), // FIXME get script sample (bug 1314567)
|
||||
nullptr, // FIXME get script sample (bug 1314567)
|
||||
0, // aLineNumber
|
||||
&allowsInlineScript);
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
@ -13549,3 +13567,17 @@ nsIDocument::IsScopedStyleEnabled()
|
|||
}
|
||||
return mIsScopedStyleEnabled == eScopedStyle_Enabled;
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::ClearStaleServoDataFromDocument()
|
||||
{
|
||||
if (!mMightHaveStaleServoData) {
|
||||
return;
|
||||
}
|
||||
|
||||
DocumentStyleRootIterator iter(this);
|
||||
while (Element* root = iter.GetNextStyleRoot()) {
|
||||
ServoRestyleManager::ClearServoDataFromSubtree(root);
|
||||
}
|
||||
mMightHaveStaleServoData = false;
|
||||
}
|
||||
|
|
|
@ -812,6 +812,10 @@ nsFrameMessageManager::ReleaseCachedProcesses()
|
|||
NS_IMETHODIMP
|
||||
nsFrameMessageManager::Dump(const nsAString& aStr)
|
||||
{
|
||||
if (!nsContentUtils::DOMWindowDumpEnabled()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
__android_log_print(ANDROID_LOG_INFO, "Gecko", "%s", NS_ConvertUTF16toUTF8(aStr).get());
|
||||
#endif
|
||||
|
|
|
@ -860,6 +860,11 @@ public:
|
|||
return GetBFCacheEntry() ? nullptr : mPresShell;
|
||||
}
|
||||
|
||||
bool HasShellOrBFCacheEntry() const
|
||||
{
|
||||
return mPresShell || mBFCacheEntry;
|
||||
}
|
||||
|
||||
// Instead using this method, what you probably want is
|
||||
// RemoveFromBFCacheSync() as we do in MessagePort and BroadcastChannel.
|
||||
void DisallowBFCaching()
|
||||
|
@ -1701,6 +1706,18 @@ public:
|
|||
mIsContentDocument = aIsContentDocument;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if this document has no pres shell, and if so, clears any Servo
|
||||
* element data stored on Elements in the document.
|
||||
*/
|
||||
void ClearStaleServoDataFromDocument();
|
||||
|
||||
/**
|
||||
* Returns true if there may be Servo element data on Elements in the document
|
||||
* that were created for a pres shell that no longer exists.
|
||||
*/
|
||||
bool MightHaveStaleServoData() const { return mMightHaveStaleServoData; }
|
||||
|
||||
/**
|
||||
* Create an element with the specified name, prefix and namespace ID.
|
||||
* Returns null if element name parsing failed.
|
||||
|
@ -3285,6 +3302,10 @@ protected:
|
|||
|
||||
bool mIsContentDocument : 1;
|
||||
|
||||
// True if there may be Servo element data on Elements in the document that
|
||||
// were created for a pres shell that no longer exists.
|
||||
bool mMightHaveStaleServoData : 1;
|
||||
|
||||
// Whether <style scoped> support is enabled in this document.
|
||||
enum { eScopedStyle_Unknown, eScopedStyle_Disabled, eScopedStyle_Enabled };
|
||||
unsigned int mIsScopedStyleEnabled : 2;
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMException.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "nsIProgrammingLanguage.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
@ -318,18 +317,6 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JSStackFrame)
|
|||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMETHODIMP JSStackFrame::GetLanguage(uint32_t* aLanguage)
|
||||
{
|
||||
*aLanguage = nsIProgrammingLanguage::JAVASCRIPT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP JSStackFrame::GetLanguageName(nsACString& aLanguageName)
|
||||
{
|
||||
aLanguageName.AssignLiteral("JavaScript");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Helper method to get the value of a stack property, if it's not already
|
||||
// cached. This will make sure we skip the cache if the access is happening
|
||||
// over Xrays.
|
||||
|
|
|
@ -2879,13 +2879,13 @@ GetFontStyleForServo(Element* aElement, const nsAString& aFont,
|
|||
if (aElement && aElement->IsInUncomposedDoc()) {
|
||||
// Inherit from the canvas element.
|
||||
aPresShell->FlushPendingNotifications(FlushType::Style);
|
||||
// We need to use ResolveTransientServoStyle, which involves traversal,
|
||||
// instead of ResolveServoStyle() because we need up-to-date style even if
|
||||
// We need to use ResolveStyleLazily, which involves traversal,
|
||||
// instead of ResolvestyleFor() because we need up-to-date style even if
|
||||
// the canvas element is display:none.
|
||||
parentStyle =
|
||||
styleSet->ResolveTransientServoStyle(aElement,
|
||||
CSSPseudoElementType::NotPseudo,
|
||||
nullptr);
|
||||
styleSet->ResolveStyleLazily(aElement,
|
||||
CSSPseudoElementType::NotPseudo,
|
||||
nullptr);
|
||||
} else {
|
||||
RefPtr<RawServoDeclarationBlock> declarations =
|
||||
CreateFontDeclarationForServo(NS_LITERAL_STRING("10px sans-serif"),
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
#include "nsIDOMWindowUtils.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsILoadContext.h"
|
||||
#include "nsIProgrammingLanguage.h"
|
||||
#include "nsISensitiveInfoHiddenURI.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
|
@ -1151,7 +1150,6 @@ StackFrameToStackEntry(JSContext* aCx, nsIStackFrame* aStackFrame,
|
|||
aStackEntry.mAsyncCause.Construct(cause);
|
||||
}
|
||||
|
||||
aStackEntry.mLanguage = nsIProgrammingLanguage::JAVASCRIPT;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@
|
|||
#include "nsIDOMEventListener.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsISupports.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsJSUtils.h"
|
||||
#include "nsNameSpaceManager.h"
|
||||
|
@ -876,12 +877,16 @@ EventListenerManager::SetEventHandler(nsIAtom* aName,
|
|||
scriptSample.AppendLiteral(" attribute on ");
|
||||
scriptSample.Append(tagName);
|
||||
scriptSample.AppendLiteral(" element");
|
||||
nsCOMPtr<nsISupportsString> sampleIString(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
|
||||
if (sampleIString) {
|
||||
sampleIString->SetData(scriptSample);
|
||||
}
|
||||
|
||||
bool allowsInlineScript = true;
|
||||
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
|
||||
EmptyString(), // aNonce
|
||||
true, // aParserCreated (true because attribute event handler)
|
||||
scriptSample,
|
||||
sampleIString,
|
||||
0, // aLineNumber
|
||||
&allowsInlineScript);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
|
|
@ -3033,7 +3033,15 @@ IsOrHasAncestorWithDisplayNone(Element* aElement, nsIPresShell* aPresShell)
|
|||
RefPtr<nsStyleContext> sc;
|
||||
for (auto* element : Reversed(elementsToCheck)) {
|
||||
if (sc) {
|
||||
sc = styleSet->ResolveStyleFor(element, sc, LazyComputeBehavior::Assert);
|
||||
if (styleSet->IsGecko()) {
|
||||
sc = styleSet->ResolveStyleFor(element, sc,
|
||||
LazyComputeBehavior::Assert);
|
||||
} else {
|
||||
// Call ResolveStyleLazily to protect against stale element data in
|
||||
// the tree when styled by Servo.
|
||||
sc = styleSet->AsServo()->ResolveStyleLazily(
|
||||
element, CSSPseudoElementType::NotPseudo, nullptr);
|
||||
}
|
||||
} else {
|
||||
sc = nsComputedDOMStyle::GetStyleContextNoFlush(element,
|
||||
nullptr, aPresShell);
|
||||
|
|
|
@ -81,7 +81,7 @@ interface nsITabParent : nsISupports
|
|||
/**
|
||||
* Notify APZ to start autoscrolling.
|
||||
* (aAnchorX, aAnchorY) are the coordinates of the autoscroll anchor,
|
||||
* in LayoutDevice coordinates relative to the screen. aScrollId and
|
||||
* in CSS coordinates relative to the screen. aScrollId and
|
||||
* aPresShellId identify the scroll frame that content chose to scroll.
|
||||
*/
|
||||
void startApzAutoscroll(in float aAnchorX, in float aAnchorY,
|
||||
|
|
|
@ -11,6 +11,7 @@ interface nsIDocShell;
|
|||
interface nsIDOMDocument;
|
||||
interface nsIEventTarget;
|
||||
interface nsIPrincipal;
|
||||
interface nsIScriptElement;
|
||||
interface nsIURI;
|
||||
|
||||
/**
|
||||
|
@ -138,7 +139,8 @@ interface nsIContentSecurityPolicy : nsISerializable
|
|||
* @param aContentPolicyType Either TYPE_SCRIPT or TYPE_STYLESHEET
|
||||
* @param aNonce The nonce string to check against the policy
|
||||
* @param aParserCreated If the script element was created by the HTML Parser
|
||||
* @param aContent The content of the inline resource to hash
|
||||
* @param aElementOrContent The script element of the inline resource to hash
|
||||
* or the content of the psuedo-script to compare to hash
|
||||
* (and compare to the hashes listed in the policy)
|
||||
* @param aLineNumber The line number of the inline resource
|
||||
* (used for reporting)
|
||||
|
@ -149,7 +151,7 @@ interface nsIContentSecurityPolicy : nsISerializable
|
|||
boolean getAllowsInline(in nsContentPolicyType aContentPolicyType,
|
||||
in AString aNonce,
|
||||
in boolean aParserCreated,
|
||||
in AString aContent,
|
||||
in nsISupports aElementOrContent,
|
||||
in unsigned long aLineNumber);
|
||||
|
||||
/**
|
||||
|
|
|
@ -3283,7 +3283,8 @@ TabParent::StartApzAutoscroll(float aAnchorX, float aAnchorY,
|
|||
// The anchor coordinates that are passed in are relative to the origin
|
||||
// of the screen, but we are sending them to APZ which only knows about
|
||||
// coordinates relative to the widget, so convert them accordingly.
|
||||
LayoutDeviceIntPoint anchor = RoundedToInt(LayoutDevicePoint{aAnchorX, aAnchorY});
|
||||
CSSPoint anchorCss{aAnchorX, aAnchorY};
|
||||
LayoutDeviceIntPoint anchor = RoundedToInt(anchorCss * widget->GetDefaultScale());
|
||||
anchor -= widget->WidgetToScreenOffset();
|
||||
|
||||
widget->StartAsyncAutoscroll(
|
||||
|
|
|
@ -182,7 +182,7 @@ nsresult nsJSThunk::EvaluateScript(nsIChannel *aChannel,
|
|||
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
|
||||
EmptyString(), // aNonce
|
||||
true, // aParserCreated
|
||||
EmptyString(), // aContent
|
||||
nullptr, // aContent
|
||||
0, // aLineNumber
|
||||
&allowsInlineScript);
|
||||
|
||||
|
|
|
@ -1110,13 +1110,9 @@ CSPAllowsInlineScript(nsIScriptElement* aElement, nsIDocument* aDocument)
|
|||
scriptContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
|
||||
bool parserCreated = aElement->GetParserCreated() != mozilla::dom::NOT_FROM_PARSER;
|
||||
|
||||
// query the scripttext
|
||||
nsAutoString scriptText;
|
||||
aElement->GetScriptText(scriptText);
|
||||
|
||||
bool allowInlineScript = false;
|
||||
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_SCRIPT,
|
||||
nonce, parserCreated, scriptText,
|
||||
nonce, parserCreated, aElement,
|
||||
aElement->GetScriptLineNumber(),
|
||||
&allowInlineScript);
|
||||
return allowInlineScript;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "nsIObserver.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIStringStream.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIUploadChannel.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
|
@ -505,7 +506,7 @@ NS_IMETHODIMP
|
|||
nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
|
||||
const nsAString& aNonce,
|
||||
bool aParserCreated,
|
||||
const nsAString& aContent,
|
||||
nsISupports* aElementOrContent,
|
||||
uint32_t aLineNumber,
|
||||
bool* outAllowsInline)
|
||||
{
|
||||
|
@ -520,12 +521,36 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
nsAutoString content(EmptyString());
|
||||
|
||||
// always iterate all policies, otherwise we might not send out all reports
|
||||
for (uint32_t i = 0; i < mPolicies.Length(); i++) {
|
||||
bool allowed =
|
||||
mPolicies[i]->allows(aContentType, CSP_UNSAFE_INLINE, EmptyString(), aParserCreated) ||
|
||||
mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce, aParserCreated) ||
|
||||
mPolicies[i]->allows(aContentType, CSP_HASH, aContent, aParserCreated);
|
||||
mPolicies[i]->allows(aContentType, CSP_NONCE, aNonce, aParserCreated);
|
||||
|
||||
// If the inlined script or style is allowed by either unsafe-inline or the
|
||||
// nonce, go ahead and shortcut this loop so we can avoid allocating
|
||||
// unecessary strings
|
||||
if (allowed) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check the content length to ensure the content is not allocated more than
|
||||
// once. Even though we are in a for loop, it is probable that there is only one
|
||||
// policy, so this check may be unnecessary.
|
||||
if (content.Length() == 0) {
|
||||
// postpone the allocation until absolutely necessary.
|
||||
nsCOMPtr<nsISupportsString> stringContent = do_QueryInterface(aElementOrContent);
|
||||
nsCOMPtr<nsIScriptElement> element = do_QueryInterface(aElementOrContent);
|
||||
if (stringContent) {
|
||||
Unused << stringContent->GetData(content);
|
||||
} else if (element) {
|
||||
element->GetScriptText(content);
|
||||
}
|
||||
}
|
||||
|
||||
allowed = mPolicies[i]->allows(aContentType, CSP_HASH, content, aParserCreated);
|
||||
|
||||
if (!allowed) {
|
||||
// policy is violoated: deny the load unless policy is report only and
|
||||
|
@ -537,7 +562,7 @@ nsCSPContext::GetAllowsInline(nsContentPolicyType aContentType,
|
|||
mPolicies[i]->getDirectiveStringForContentType(aContentType, violatedDirective);
|
||||
reportInlineViolation(aContentType,
|
||||
aNonce,
|
||||
aContent,
|
||||
content,
|
||||
violatedDirective,
|
||||
i,
|
||||
aLineNumber);
|
||||
|
|
|
@ -107,6 +107,9 @@ function run_test() {
|
|||
":" + REPORT_SERVER_PORT +
|
||||
"/foo/self");
|
||||
|
||||
let content = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
content.data = "";
|
||||
// test that inline script violations cause a report.
|
||||
makeTest(0, {"blocked-uri": "self"}, false,
|
||||
function(csp) {
|
||||
|
@ -114,7 +117,7 @@ function run_test() {
|
|||
inlineOK = csp.getAllowsInline(Ci.nsIContentPolicy.TYPE_SCRIPT,
|
||||
"", // aNonce
|
||||
false, // aParserCreated
|
||||
"", // aContent
|
||||
content, // aContent
|
||||
0); // aLineNumber
|
||||
|
||||
// this is not a report only policy, so it better block inline scripts
|
||||
|
@ -158,10 +161,13 @@ function run_test() {
|
|||
makeTest(3, {"blocked-uri": "self"}, true,
|
||||
function(csp) {
|
||||
let inlineOK = true;
|
||||
let content = Cc["@mozilla.org/supports-string;1"].
|
||||
createInstance(Ci.nsISupportsString);
|
||||
content.data = "";
|
||||
inlineOK = csp.getAllowsInline(Ci.nsIContentPolicy.TYPE_SCRIPT,
|
||||
"", // aNonce
|
||||
false, // aParserCreated
|
||||
"", // aContent
|
||||
content, // aContent
|
||||
0); // aLineNumber
|
||||
|
||||
// this is a report only policy, so it better allow inline scripts
|
||||
|
|
|
@ -267,10 +267,10 @@ async function startTraceTest(browser) {
|
|||
dump("Observer attached\n");
|
||||
gLevel = "trace";
|
||||
gArgs = [
|
||||
{columnNumber: 9, filename: TEST_URI, functionName: "window.foobar585956c", language: 2, lineNumber: 6},
|
||||
{columnNumber: 16, filename: TEST_URI, functionName: "foobar585956b", language: 2, lineNumber: 11},
|
||||
{columnNumber: 16, filename: TEST_URI, functionName: "foobar585956a", language: 2, lineNumber: 15},
|
||||
{columnNumber: 1, filename: TEST_URI, functionName: "onclick", language: 2, lineNumber: 1}
|
||||
{columnNumber: 9, filename: TEST_URI, functionName: "window.foobar585956c", lineNumber: 6},
|
||||
{columnNumber: 16, filename: TEST_URI, functionName: "foobar585956b", lineNumber: 11},
|
||||
{columnNumber: 16, filename: TEST_URI, functionName: "foobar585956a", lineNumber: 15},
|
||||
{columnNumber: 1, filename: TEST_URI, functionName: "onclick", lineNumber: 1}
|
||||
];
|
||||
|
||||
});
|
||||
|
|
|
@ -85,7 +85,6 @@ dictionary ConsoleStackEntry {
|
|||
unsigned long lineNumber = 0;
|
||||
unsigned long columnNumber = 0;
|
||||
DOMString functionName = "";
|
||||
unsigned long language = 0;
|
||||
DOMString? asyncCause;
|
||||
};
|
||||
|
||||
|
|
|
@ -352,12 +352,16 @@ struct BaseRect {
|
|||
T Area() const { return width * height; }
|
||||
|
||||
// Helper methods for computing the extents
|
||||
T X() const { return x; }
|
||||
T Y() const { return y; }
|
||||
T Width() const { return width; }
|
||||
T Height() const { return height; }
|
||||
T XMost() const { return x + width; }
|
||||
T YMost() const { return y + height; }
|
||||
MOZ_ALWAYS_INLINE T X() const { return x; }
|
||||
MOZ_ALWAYS_INLINE T Y() const { return y; }
|
||||
MOZ_ALWAYS_INLINE T Width() const { return width; }
|
||||
MOZ_ALWAYS_INLINE T Height() const { return height; }
|
||||
MOZ_ALWAYS_INLINE T XMost() const { return x + width; }
|
||||
MOZ_ALWAYS_INLINE T YMost() const { return y + height; }
|
||||
|
||||
// Set width and height. SizeTo() sets them together.
|
||||
MOZ_ALWAYS_INLINE void SetWidth(T aWidth) { width = aWidth; }
|
||||
MOZ_ALWAYS_INLINE void SetHeight(T aHeight) { height = aHeight; }
|
||||
|
||||
// Get the coordinate of the edge on the given side.
|
||||
T Edge(mozilla::Side aSide) const
|
||||
|
@ -390,6 +394,10 @@ struct BaseRect {
|
|||
MOZ_ASSERT(aYMost >= y);
|
||||
height = aYMost - y;
|
||||
}
|
||||
void Swap() {
|
||||
std::swap(x, y);
|
||||
std::swap(width, height);
|
||||
}
|
||||
|
||||
// Round the rectangle edges to integer coordinates, such that the rounded
|
||||
// rectangle has the same set of pixel centers as the original rectangle.
|
||||
|
|
|
@ -21,7 +21,7 @@ TestConstructors()
|
|||
|
||||
// Make sure the rectangle was properly initialized
|
||||
EXPECT_TRUE(rect1.x == 10 && rect1.y == 20 &&
|
||||
rect1.width == 30 && rect1.height == 40) <<
|
||||
rect1.Width() == 30 && rect1.Height() == 40) <<
|
||||
"[1] Make sure the rectangle was properly initialized with constructor";
|
||||
|
||||
// Create a second rect using the copy constructor
|
||||
|
@ -29,7 +29,7 @@ TestConstructors()
|
|||
|
||||
// Make sure the rectangle was properly initialized
|
||||
EXPECT_TRUE(rect2.x == rect1.x && rect2.y == rect2.y &&
|
||||
rect2.width == rect2.width && rect2.height == rect2.height) <<
|
||||
rect2.Width() == rect2.Width() && rect2.Height() == rect2.Height()) <<
|
||||
"[2] Make sure the rectangle was properly initialized with copy constructor";
|
||||
|
||||
|
||||
|
@ -73,7 +73,7 @@ TestContainment()
|
|||
//
|
||||
|
||||
// Basic test of a point in the middle of the rect
|
||||
EXPECT_FALSE(!rect1.Contains(rect1.x + rect1.width/2, rect1.y + rect1.height/2)) <<
|
||||
EXPECT_FALSE(!rect1.Contains(rect1.x + rect1.Width()/2, rect1.y + rect1.Height()/2)) <<
|
||||
"[1] Basic test of a point in the middle of the rect";
|
||||
|
||||
// Test against a point at the left/top edges
|
||||
|
@ -149,10 +149,10 @@ TestIntersects()
|
|||
rect2.x++;
|
||||
|
||||
// Test against a rect that's outside of rect1 on the left
|
||||
rect2.x -= rect2.width;
|
||||
rect2.x -= rect2.Width();
|
||||
EXPECT_FALSE(rect1.Intersects(rect2)) <<
|
||||
"[5] Test against a rect that's outside of rect1 on the left";
|
||||
rect2.x += rect2.width;
|
||||
rect2.x += rect2.Width();
|
||||
|
||||
// Test against a rect that overlaps the top edge of rect1
|
||||
rect2.y--;
|
||||
|
@ -161,10 +161,10 @@ TestIntersects()
|
|||
rect2.y++;
|
||||
|
||||
// Test against a rect that's outside of rect1 on the top
|
||||
rect2.y -= rect2.height;
|
||||
rect2.y -= rect2.Height();
|
||||
EXPECT_FALSE(rect1.Intersects(rect2)) <<
|
||||
"[7] Test against a rect that's outside of rect1 on the top";
|
||||
rect2.y += rect2.height;
|
||||
rect2.y += rect2.Height();
|
||||
|
||||
// Test against a rect that overlaps the right edge of rect1
|
||||
rect2.x++;
|
||||
|
@ -173,10 +173,10 @@ TestIntersects()
|
|||
rect2.x--;
|
||||
|
||||
// Test against a rect that's outside of rect1 on the right
|
||||
rect2.x += rect2.width;
|
||||
rect2.x += rect2.Width();
|
||||
EXPECT_FALSE(rect1.Intersects(rect2)) <<
|
||||
"[9] Test against a rect that's outside of rect1 on the right";
|
||||
rect2.x -= rect2.width;
|
||||
rect2.x -= rect2.Width();
|
||||
|
||||
// Test against a rect that overlaps the bottom edge of rect1
|
||||
rect2.y++;
|
||||
|
@ -185,10 +185,10 @@ TestIntersects()
|
|||
rect2.y--;
|
||||
|
||||
// Test against a rect that's outside of rect1 on the bottom
|
||||
rect2.y += rect2.height;
|
||||
rect2.y += rect2.Height();
|
||||
EXPECT_FALSE(rect1.Intersects(rect2)) <<
|
||||
"[11] Test against a rect that's outside of rect1 on the bottom";
|
||||
rect2.y -= rect2.height;
|
||||
rect2.y -= rect2.Height();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -215,72 +215,72 @@ TestIntersection()
|
|||
// Test against a rect that overlaps the left edge of rect1
|
||||
rect2.x--;
|
||||
EXPECT_FALSE(!dest.IntersectRect(rect1, rect2) ||
|
||||
!(dest.IsEqualInterior(RectType(rect1.x, rect1.y, rect1.width - 1, rect1.height)))) <<
|
||||
!(dest.IsEqualInterior(RectType(rect1.x, rect1.y, rect1.Width() - 1, rect1.Height())))) <<
|
||||
"[3] Test against a rect that overlaps the left edge of rect1";
|
||||
rect2.x++;
|
||||
|
||||
// Test against a rect that's outside of rect1 on the left
|
||||
rect2.x -= rect2.width;
|
||||
rect2.x -= rect2.Width();
|
||||
EXPECT_FALSE(dest.IntersectRect(rect1, rect2)) <<
|
||||
"[4] Test against a rect that's outside of rect1 on the left";
|
||||
// Make sure an empty rect is returned
|
||||
EXPECT_FALSE(!dest.IsEmpty()) <<
|
||||
"[4] Make sure an empty rect is returned";
|
||||
EXPECT_TRUE(dest.IsFinite()) << "[4b] Should be finite";
|
||||
rect2.x += rect2.width;
|
||||
rect2.x += rect2.Width();
|
||||
|
||||
// Test against a rect that overlaps the top edge of rect1
|
||||
rect2.y--;
|
||||
EXPECT_FALSE(!dest.IntersectRect(rect1, rect2) ||
|
||||
!(dest.IsEqualInterior(RectType(rect1.x, rect1.y, rect1.width, rect1.height - 1)))) <<
|
||||
!(dest.IsEqualInterior(RectType(rect1.x, rect1.y, rect1.Width(), rect1.Height() - 1)))) <<
|
||||
"[5] Test against a rect that overlaps the top edge of rect1";
|
||||
EXPECT_TRUE(dest.IsFinite()) << "[5b] Should be finite";
|
||||
rect2.y++;
|
||||
|
||||
// Test against a rect that's outside of rect1 on the top
|
||||
rect2.y -= rect2.height;
|
||||
rect2.y -= rect2.Height();
|
||||
EXPECT_FALSE(dest.IntersectRect(rect1, rect2)) <<
|
||||
"[6] Test against a rect that's outside of rect1 on the top";
|
||||
// Make sure an empty rect is returned
|
||||
EXPECT_FALSE(!dest.IsEmpty()) <<
|
||||
"[6] Make sure an empty rect is returned";
|
||||
EXPECT_TRUE(dest.IsFinite()) << "[6b] Should be finite";
|
||||
rect2.y += rect2.height;
|
||||
rect2.y += rect2.Height();
|
||||
|
||||
// Test against a rect that overlaps the right edge of rect1
|
||||
rect2.x++;
|
||||
EXPECT_FALSE(!dest.IntersectRect(rect1, rect2) ||
|
||||
!(dest.IsEqualInterior(RectType(rect1.x + 1, rect1.y, rect1.width - 1, rect1.height)))) <<
|
||||
!(dest.IsEqualInterior(RectType(rect1.x + 1, rect1.y, rect1.Width() - 1, rect1.Height())))) <<
|
||||
"[7] Test against a rect that overlaps the right edge of rect1";
|
||||
rect2.x--;
|
||||
|
||||
// Test against a rect that's outside of rect1 on the right
|
||||
rect2.x += rect2.width;
|
||||
rect2.x += rect2.Width();
|
||||
EXPECT_FALSE(dest.IntersectRect(rect1, rect2)) <<
|
||||
"[8] Test against a rect that's outside of rect1 on the right";
|
||||
// Make sure an empty rect is returned
|
||||
EXPECT_FALSE(!dest.IsEmpty()) <<
|
||||
"[8] Make sure an empty rect is returned";
|
||||
EXPECT_TRUE(dest.IsFinite()) << "[8b] Should be finite";
|
||||
rect2.x -= rect2.width;
|
||||
rect2.x -= rect2.Width();
|
||||
|
||||
// Test against a rect that overlaps the bottom edge of rect1
|
||||
rect2.y++;
|
||||
EXPECT_FALSE(!dest.IntersectRect(rect1, rect2) ||
|
||||
!(dest.IsEqualInterior(RectType(rect1.x, rect1.y + 1, rect1.width, rect1.height - 1)))) <<
|
||||
!(dest.IsEqualInterior(RectType(rect1.x, rect1.y + 1, rect1.Width(), rect1.Height() - 1)))) <<
|
||||
"[9] Test against a rect that overlaps the bottom edge of rect1";
|
||||
EXPECT_TRUE(dest.IsFinite()) << "[9b] Should be finite";
|
||||
rect2.y--;
|
||||
|
||||
// Test against a rect that's outside of rect1 on the bottom
|
||||
rect2.y += rect2.height;
|
||||
rect2.y += rect2.Height();
|
||||
EXPECT_FALSE(dest.IntersectRect(rect1, rect2)) <<
|
||||
"[10] Test against a rect that's outside of rect1 on the bottom";
|
||||
// Make sure an empty rect is returned
|
||||
EXPECT_FALSE(!dest.IsEmpty()) <<
|
||||
"[10] Make sure an empty rect is returned";
|
||||
EXPECT_TRUE(dest.IsFinite()) << "[10b] Should be finite";
|
||||
rect2.y -= rect2.height;
|
||||
rect2.y -= rect2.Height();
|
||||
|
||||
// Test against a rect with zero width or height
|
||||
rect1.SetRect(100, 100, 100, 100);
|
||||
|
@ -412,12 +412,40 @@ TestBug1135677()
|
|||
dest = rect1.Intersect(rect2);
|
||||
|
||||
EXPECT_TRUE(dest.x == 1073741820 && dest.y == 1073741820 &&
|
||||
dest.width == 14400 && dest.height == 77640) <<
|
||||
dest.Width() == 14400 && dest.Height() == 77640) <<
|
||||
"[1] Operation should not overflow internally.";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class RectType>
|
||||
static bool
|
||||
TestSetWH()
|
||||
{
|
||||
RectType rect(1, 2, 3, 4);
|
||||
EXPECT_TRUE(rect.X() == 1 && rect.Y() == 2 && rect.Width() == 3 && rect.Height() == 4);
|
||||
rect.SetWidth(13);
|
||||
EXPECT_TRUE(rect.X() == 1 && rect.Y() == 2 && rect.Width() == 13 && rect.Height() == 4);
|
||||
rect.SetHeight(14);
|
||||
EXPECT_TRUE(rect.X() == 1 && rect.Y() == 2 && rect.Width() == 13 && rect.Height() == 14);
|
||||
rect.SizeTo(23, 24);
|
||||
EXPECT_TRUE(rect.X() == 1 && rect.Y() == 2 && rect.Width() == 23 && rect.Height() == 24);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class RectType>
|
||||
static bool
|
||||
TestSwap()
|
||||
{
|
||||
RectType rect(1, 2, 3, 4);
|
||||
EXPECT_TRUE(rect.X() == 1 && rect.Y() == 2 && rect.Width() == 3 && rect.Height() == 4);
|
||||
rect.Swap();
|
||||
EXPECT_TRUE(rect.X() == 2 && rect.Y() == 1 && rect.Width() == 4 && rect.Height() == 3);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
TEST(Gfx, nsRect) {
|
||||
TestConstructors<nsRect>();
|
||||
TestEqualityOperator<nsRect>();
|
||||
|
@ -426,6 +454,8 @@ TEST(Gfx, nsRect) {
|
|||
TestIntersection<nsRect>();
|
||||
TestUnion<nsRect>();
|
||||
TestBug1135677<nsRect>();
|
||||
TestSetWH<nsRect>();
|
||||
TestSwap<nsRect>();
|
||||
}
|
||||
|
||||
TEST(Gfx, nsIntRect) {
|
||||
|
@ -436,6 +466,8 @@ TEST(Gfx, nsIntRect) {
|
|||
TestIntersection<nsIntRect>();
|
||||
TestUnion<nsIntRect>();
|
||||
TestBug1135677<nsIntRect>();
|
||||
TestSetWH<nsIntRect>();
|
||||
TestSwap<nsIntRect>();
|
||||
}
|
||||
|
||||
TEST(Gfx, gfxRect) {
|
||||
|
@ -447,4 +479,6 @@ TEST(Gfx, gfxRect) {
|
|||
TestUnion<gfxRect>();
|
||||
TestBug1135677<gfxRect>();
|
||||
TestFiniteGfx();
|
||||
TestSetWH<gfxRect>();
|
||||
TestSwap<gfxRect>();
|
||||
}
|
||||
|
|
|
@ -758,6 +758,7 @@ BytecodeEmitter::EmitterScope::searchInEnclosingScope(JSAtom* name, Scope* scope
|
|||
case ScopeKind::NonSyntactic:
|
||||
return NameLocation::Dynamic();
|
||||
|
||||
case ScopeKind::WasmInstance:
|
||||
case ScopeKind::WasmFunction:
|
||||
MOZ_CRASH("No direct eval inside wasm functions");
|
||||
}
|
||||
|
@ -1458,6 +1459,7 @@ BytecodeEmitter::EmitterScope::leave(BytecodeEmitter* bce, bool nonLocal)
|
|||
case ScopeKind::Module:
|
||||
break;
|
||||
|
||||
case ScopeKind::WasmInstance:
|
||||
case ScopeKind::WasmFunction:
|
||||
MOZ_CRASH("No wasm function scopes in JS");
|
||||
}
|
||||
|
|
|
@ -1285,9 +1285,14 @@ ModuleScope::Data::trace(JSTracer* trc)
|
|||
TraceBindingNames(trc, names, length);
|
||||
}
|
||||
void
|
||||
WasmInstanceScope::Data::trace(JSTracer* trc)
|
||||
{
|
||||
TraceNullableEdge(trc, &instance, "wasm instance");
|
||||
TraceBindingNames(trc, names, length);
|
||||
}
|
||||
void
|
||||
WasmFunctionScope::Data::trace(JSTracer* trc)
|
||||
{
|
||||
TraceNullableEdge(trc, &instance, "wasm function");
|
||||
TraceBindingNames(trc, names, length);
|
||||
}
|
||||
void
|
||||
|
@ -1323,6 +1328,9 @@ Scope::traceChildren(JSTracer* trc)
|
|||
break;
|
||||
case ScopeKind::With:
|
||||
break;
|
||||
case ScopeKind::WasmInstance:
|
||||
reinterpret_cast<WasmInstanceScope::Data*>(data_)->trace(trc);
|
||||
break;
|
||||
case ScopeKind::WasmFunction:
|
||||
reinterpret_cast<WasmFunctionScope::Data*>(data_)->trace(trc);
|
||||
break;
|
||||
|
@ -1392,9 +1400,16 @@ js::GCMarker::eagerlyMarkChildren(Scope* scope)
|
|||
case ScopeKind::With:
|
||||
break;
|
||||
|
||||
case ScopeKind::WasmInstance: {
|
||||
WasmInstanceScope::Data* data = reinterpret_cast<WasmInstanceScope::Data*>(scope->data_);
|
||||
traverseEdge(scope, static_cast<JSObject*>(data->instance));
|
||||
names = data->names;
|
||||
length = data->length;
|
||||
break;
|
||||
}
|
||||
|
||||
case ScopeKind::WasmFunction: {
|
||||
WasmFunctionScope::Data* data = reinterpret_cast<WasmFunctionScope::Data*>(scope->data_);
|
||||
traverseEdge(scope, static_cast<JSObject*>(data->instance));
|
||||
names = data->names;
|
||||
length = data->length;
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
// |jit-test| test-also-wasm-baseline
|
||||
// Tests that wasm module scripts has inspectable globals and memory.
|
||||
|
||||
load(libdir + "wasm.js");
|
||||
load(libdir + 'eqArrayHelper.js');
|
||||
|
||||
function monitorGlobalValues(wast, lib, expected) {
|
||||
function setupFrame(frame) {
|
||||
var globals = {};
|
||||
framesGlobals.push(globals);
|
||||
// Environment with globals follow function scope enviroment
|
||||
var globalEnv = frame.environment.parent;
|
||||
globalEnv.names().forEach(n => {
|
||||
globals[n] = [globalEnv.getVariable(n)];
|
||||
});
|
||||
frame.onStep = function () {
|
||||
var globalEnv = frame.environment.parent;
|
||||
globalEnv.names().forEach(n => {
|
||||
var prevValues = globals[n];
|
||||
if (!prevValues)
|
||||
globals[n] = prevValues = [void 0];
|
||||
var value = globalEnv.getVariable(n);
|
||||
if (prevValues[prevValues.length - 1] !== value)
|
||||
prevValues.push(value);
|
||||
});
|
||||
}
|
||||
}
|
||||
var framesGlobals = [];
|
||||
wasmRunWithDebugger(wast, lib,
|
||||
function ({dbg}) {
|
||||
dbg.onEnterFrame = function(frame) {
|
||||
if (frame.type == "wasmcall")
|
||||
setupFrame(frame);
|
||||
}
|
||||
},
|
||||
function ({error}) {
|
||||
assertEq(error, undefined);
|
||||
}
|
||||
);
|
||||
assertEq(framesGlobals.length, expected.length);
|
||||
for (var i = 0; i < framesGlobals.length; i++) {
|
||||
var frameGlobals = framesGlobals[i];
|
||||
var expectedGlobals = expected[i];
|
||||
var globalsNames = Object.keys(frameGlobals);
|
||||
assertEq(globalsNames.length, Object.keys(expectedGlobals).length);
|
||||
globalsNames.forEach(n => {
|
||||
if (typeof expectedGlobals[n][0] === "function") {
|
||||
// expectedGlobals are assert functions
|
||||
expectedGlobals[n].forEach((assertFn, i) => {
|
||||
assertFn(frameGlobals[n][i]);
|
||||
});
|
||||
return;
|
||||
}
|
||||
assertEqArray(frameGlobals[n], expectedGlobals[n]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
monitorGlobalValues(
|
||||
'(module (func (export "test") (nop)))',
|
||||
undefined,
|
||||
[{}]
|
||||
);
|
||||
monitorGlobalValues(
|
||||
'(module (memory (export "memory") 1 1) (func (export "test") (nop) (nop)))',
|
||||
undefined,
|
||||
[{
|
||||
memory0: [
|
||||
function (actual) {
|
||||
var bufferProp = actual.proto.getOwnPropertyDescriptor("buffer");
|
||||
assertEq(!!bufferProp, true, "wasm memory buffer property");
|
||||
var buffer = bufferProp.get.call(actual).return;
|
||||
var bufferLengthProp = buffer.proto.getOwnPropertyDescriptor("byteLength");
|
||||
var bufferLength = bufferLengthProp.get.call(buffer).return;
|
||||
assertEq(bufferLength, 65536, "wasm memory size");
|
||||
}
|
||||
]
|
||||
}]
|
||||
);
|
||||
monitorGlobalValues(
|
||||
'(module\
|
||||
(global i32 (i32.const 1))(global i64 (i64.const 2))(global f32 (f32.const 3.5))(global f64 (f64.const 42.25))\
|
||||
(func (export "test") (nop)))',
|
||||
undefined,
|
||||
[{global0: [1], global1: [2], global2: [3.5], global3: [42.25]}]
|
||||
);
|
||||
monitorGlobalValues(
|
||||
'(module (global (mut i32) (i32.const 1))(global (mut i64) (i64.const 2))\
|
||||
(global (mut f32) (f32.const 3.5))(global (mut f64) (f64.const 42.25))\
|
||||
(func (export "test")\
|
||||
(i32.const 2)(set_global 0)(i64.const 1)(set_global 1)\
|
||||
(f32.const 42.25)(set_global 2)(f64.const 3.5)(set_global 3)))',
|
||||
undefined,
|
||||
[{global0: [1, 2], global1: [2, 1], global2: [3.5, 42.25], global3: [42.25, 3.5]}]
|
||||
)
|
|
@ -0,0 +1,45 @@
|
|||
// |jit-test| test-also-wasm-baseline
|
||||
// Tests that JS can be evaluated on wasm module scripts frames.
|
||||
|
||||
load(libdir + "wasm.js");
|
||||
|
||||
wasmRunWithDebugger(
|
||||
'(module (memory 1 1)\
|
||||
(global (mut f64) (f64.const 0.5))\
|
||||
(global f32 (f32.const 3.5))\
|
||||
(func (param i32) (local f64) (f64.const 1.0) (tee_local 1) (set_global 0) (nop))\
|
||||
(export "test" 0)\
|
||||
(data (i32.const 0) "Abc\\x2A"))',
|
||||
undefined,
|
||||
function ({dbg}) {
|
||||
dbg.onEnterFrame = function (frame) {
|
||||
if (frame.type != 'wasmcall') return;
|
||||
|
||||
var memoryContent = frame.eval('new DataView(memory0.buffer).getUint8(3)').return;
|
||||
assertEq(memoryContent, 42, 'valid memory content is expected (0x2A)');
|
||||
|
||||
var global1AndParamSum = frame.eval('global1 + var0').return;
|
||||
assertEq(global1AndParamSum, 3.5);
|
||||
|
||||
var stepNumber = 0;
|
||||
frame.onStep = function () {
|
||||
switch (stepNumber) {
|
||||
case 1: // after i64.const 1.0
|
||||
assertEq(frame.eval('global0').return, 0.5);
|
||||
assertEq(frame.eval('var1').return, 0.0);
|
||||
break;
|
||||
case 2: // after tee_local $var1
|
||||
assertEq(frame.eval('var1').return, 1.0);
|
||||
break;
|
||||
case 3: // after set_global $global0
|
||||
assertEq(frame.eval('global0').return, 1.0);
|
||||
break;
|
||||
}
|
||||
stepNumber++;
|
||||
};
|
||||
};
|
||||
},
|
||||
function ({error}) {
|
||||
assertEq(error, undefined);
|
||||
}
|
||||
);
|
|
@ -244,3 +244,20 @@ testInitExpr('f64', 13.37, 0.1989, x => +x);
|
|||
|
||||
setJitCompilerOption('wasm.test-mode', 0);
|
||||
}
|
||||
|
||||
// Custom NaN.
|
||||
{
|
||||
let dv = new DataView(new ArrayBuffer(8));
|
||||
module = wasmEvalText(`(module
|
||||
(global $g f64 (f64.const -nan:0xe7ffff1591120))
|
||||
(global $h f32 (f32.const -nan:0x651234))
|
||||
(export "nan64" (global $g))(export "nan32" (global $h))
|
||||
)`, {}).exports;
|
||||
|
||||
dv.setFloat64(0, module.nan64, true);
|
||||
assertEq(dv.getUint32(4, true), 0x7ff80000);
|
||||
assertEq(dv.getUint32(0, true), 0x00000000);
|
||||
|
||||
dv.setFloat32(0, module.nan32, true);
|
||||
assertEq(dv.getUint32(0, true), 0x7fc00000);
|
||||
}
|
||||
|
|
|
@ -790,6 +790,7 @@ js::XDRScript(XDRState<mode>* xdr, HandleScope scriptEnclosingScope,
|
|||
return false;
|
||||
break;
|
||||
case ScopeKind::Module:
|
||||
case ScopeKind::WasmInstance:
|
||||
MOZ_CRASH("NYI");
|
||||
break;
|
||||
case ScopeKind::WasmFunction:
|
||||
|
|
|
@ -8170,11 +8170,10 @@ DebuggerFrame::getArguments(JSContext *cx, HandleDebuggerFrame frame,
|
|||
*/
|
||||
static bool
|
||||
EvaluateInEnv(JSContext* cx, Handle<Env*> env, AbstractFramePtr frame,
|
||||
jsbytecode* pc, mozilla::Range<const char16_t> chars, const char* filename,
|
||||
mozilla::Range<const char16_t> chars, const char* filename,
|
||||
unsigned lineno, MutableHandleValue rval)
|
||||
{
|
||||
assertSameCompartment(cx, env, frame);
|
||||
MOZ_ASSERT_IF(frame, pc);
|
||||
|
||||
CompileOptions options(cx);
|
||||
options.setIsRunOnce(true)
|
||||
|
@ -8182,8 +8181,8 @@ EvaluateInEnv(JSContext* cx, Handle<Env*> env, AbstractFramePtr frame,
|
|||
.setFileAndLine(filename, lineno)
|
||||
.setCanLazilyParse(false)
|
||||
.setIntroductionType("debugger eval")
|
||||
.maybeMakeStrictMode(frame ? frame.script()->strict() : false);
|
||||
RootedScript callerScript(cx, frame ? frame.script() : nullptr);
|
||||
.maybeMakeStrictMode(frame && frame.hasScript() ? frame.script()->strict() : false);
|
||||
RootedScript callerScript(cx, frame && frame.hasScript() ? frame.script() : nullptr);
|
||||
SourceBufferHolder srcBuf(chars.begin().get(), chars.length(), SourceBufferHolder::NoOwnership);
|
||||
RootedScript script(cx);
|
||||
|
||||
|
@ -8298,9 +8297,8 @@ DebuggerGenericEval(JSContext* cx, const mozilla::Range<const char16_t> chars,
|
|||
LeaveDebuggeeNoExecute nnx(cx);
|
||||
RootedValue rval(cx);
|
||||
AbstractFramePtr frame = iter ? iter->abstractFramePtr() : NullFramePtr();
|
||||
jsbytecode* pc = iter ? iter->pc() : nullptr;
|
||||
|
||||
bool ok = EvaluateInEnv(cx, env, frame, pc, chars,
|
||||
bool ok = EvaluateInEnv(cx, env, frame, chars,
|
||||
options.filename() ? options.filename() : "debugger eval code",
|
||||
options.lineno(), &rval);
|
||||
Debugger::resultToCompletion(cx, ok, rval, &status, value);
|
||||
|
@ -8314,8 +8312,6 @@ DebuggerFrame::eval(JSContext* cx, HandleDebuggerFrame frame, mozilla::Range<con
|
|||
MutableHandleValue value)
|
||||
{
|
||||
MOZ_ASSERT(frame->isLive());
|
||||
if (!requireScriptReferent(cx, frame))
|
||||
return false;
|
||||
|
||||
Debugger* dbg = frame->owner();
|
||||
|
||||
|
|
|
@ -636,13 +636,46 @@ ModuleEnvironmentObject::newEnumerate(JSContext* cx, HandleObject obj, AutoIdVec
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
const Class WasmInstanceEnvironmentObject::class_ = {
|
||||
"WasmInstance",
|
||||
JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(WasmInstanceEnvironmentObject::RESERVED_SLOTS)
|
||||
};
|
||||
|
||||
/* static */ WasmInstanceEnvironmentObject*
|
||||
WasmInstanceEnvironmentObject::createHollowForDebug(JSContext* cx, Handle<WasmInstanceScope*> scope)
|
||||
{
|
||||
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
|
||||
if (!group)
|
||||
return nullptr;
|
||||
|
||||
RootedShape shape(cx, scope->getEmptyEnvironmentShape(cx));
|
||||
if (!shape)
|
||||
return nullptr;
|
||||
|
||||
gc::AllocKind kind = gc::GetGCObjectKind(shape->numFixedSlots());
|
||||
MOZ_ASSERT(CanBeFinalizedInBackground(kind, &class_));
|
||||
kind = gc::GetBackgroundAllocKind(kind);
|
||||
|
||||
JSObject* obj;
|
||||
JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, gc::DefaultHeap, shape, group));
|
||||
|
||||
Rooted<WasmInstanceEnvironmentObject*> callobj(cx, &obj->as<WasmInstanceEnvironmentObject>());
|
||||
callobj->initEnclosingEnvironment(&cx->global()->lexicalEnvironment());
|
||||
callobj->initReservedSlot(SCOPE_SLOT, PrivateGCThingValue(scope));
|
||||
|
||||
return callobj;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
const Class WasmFunctionCallObject::class_ = {
|
||||
"WasmCall",
|
||||
JSCLASS_IS_ANONYMOUS | JSCLASS_HAS_RESERVED_SLOTS(WasmFunctionCallObject::RESERVED_SLOTS)
|
||||
};
|
||||
|
||||
/* static */ WasmFunctionCallObject*
|
||||
WasmFunctionCallObject::createHollowForDebug(JSContext* cx, Handle<WasmFunctionScope*> scope)
|
||||
WasmFunctionCallObject::createHollowForDebug(JSContext* cx, HandleObject enclosing,
|
||||
Handle<WasmFunctionScope*> scope)
|
||||
{
|
||||
RootedObjectGroup group(cx, ObjectGroup::defaultNewGroup(cx, &class_, TaggedProto(nullptr)));
|
||||
if (!group)
|
||||
|
@ -660,7 +693,7 @@ WasmFunctionCallObject::createHollowForDebug(JSContext* cx, Handle<WasmFunctionS
|
|||
JS_TRY_VAR_OR_RETURN_NULL(cx, obj, NativeObject::create(cx, kind, gc::DefaultHeap, shape, group));
|
||||
|
||||
Rooted<WasmFunctionCallObject*> callobj(cx, &obj->as<WasmFunctionCallObject>());
|
||||
callobj->initEnclosingEnvironment(&cx->global()->lexicalEnvironment());
|
||||
callobj->initEnclosingEnvironment(enclosing);
|
||||
callobj->initReservedSlot(SCOPE_SLOT, PrivateGCThingValue(scope));
|
||||
|
||||
return callobj;
|
||||
|
@ -1673,6 +1706,38 @@ class DebugEnvironmentProxyHandler : public BaseProxyHandler
|
|||
return true;
|
||||
}
|
||||
|
||||
if (env->is<WasmInstanceEnvironmentObject>()) {
|
||||
RootedScope scope(cx, getEnvironmentScope(*env));
|
||||
MOZ_ASSERT(scope->is<WasmInstanceScope>());
|
||||
uint32_t index = 0;
|
||||
for (BindingIter bi(scope); bi; bi++) {
|
||||
if (JSID_IS_ATOM(id, bi.name()))
|
||||
break;
|
||||
MOZ_ASSERT(!bi.isLast());
|
||||
index++;
|
||||
}
|
||||
Rooted<WasmInstanceScope*> instanceScope(cx, &scope->as<WasmInstanceScope>());
|
||||
wasm::Instance& instance = instanceScope->instance()->instance();
|
||||
|
||||
if (action == GET) {
|
||||
if (instanceScope->memoriesStart() <= index && index < instanceScope->globalsStart()) {
|
||||
MOZ_ASSERT(instanceScope->memoriesStart() + 1 == instanceScope->globalsStart());
|
||||
vp.set(ObjectValue(*instance.memory()));
|
||||
}
|
||||
if (instanceScope->globalsStart() <= index) {
|
||||
MOZ_ASSERT(index < instanceScope->namesCount());
|
||||
if (!instance.debug().getGlobal(instance, index - instanceScope->globalsStart(), vp)) {
|
||||
ReportOutOfMemory(cx);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*accessResult = ACCESS_UNALIASED;
|
||||
} else { // if (action == SET)
|
||||
// TODO
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* The rest of the internal scopes do not have unaliased vars. */
|
||||
MOZ_ASSERT(!IsSyntacticEnvironment(env) ||
|
||||
env->is<WithEnvironmentObject>());
|
||||
|
@ -1707,6 +1772,8 @@ class DebugEnvironmentProxyHandler : public BaseProxyHandler
|
|||
return &env.as<LexicalEnvironmentObject>().scope();
|
||||
if (env.is<VarEnvironmentObject>())
|
||||
return &env.as<VarEnvironmentObject>().scope();
|
||||
if (env.is<WasmInstanceEnvironmentObject>())
|
||||
return &env.as<WasmInstanceEnvironmentObject>().scope();
|
||||
if (env.is<WasmFunctionCallObject>())
|
||||
return &env.as<WasmFunctionCallObject>().scope();
|
||||
return nullptr;
|
||||
|
@ -2311,6 +2378,7 @@ DebugEnvironmentProxy::isForDeclarative() const
|
|||
return e.is<CallObject>() ||
|
||||
e.is<VarEnvironmentObject>() ||
|
||||
e.is<ModuleEnvironmentObject>() ||
|
||||
e.is<WasmInstanceEnvironmentObject>() ||
|
||||
e.is<WasmFunctionCallObject>() ||
|
||||
e.is<LexicalEnvironmentObject>();
|
||||
}
|
||||
|
@ -2957,6 +3025,7 @@ GetDebugEnvironmentForMissing(JSContext* cx, const EnvironmentIter& ei)
|
|||
MOZ_ASSERT(!ei.hasSyntacticEnvironment() &&
|
||||
(ei.scope().is<FunctionScope>() ||
|
||||
ei.scope().is<LexicalScope>() ||
|
||||
ei.scope().is<WasmInstanceScope>() ||
|
||||
ei.scope().is<WasmFunctionScope>() ||
|
||||
ei.scope().is<VarScope>()));
|
||||
|
||||
|
@ -3000,10 +3069,20 @@ GetDebugEnvironmentForMissing(JSContext* cx, const EnvironmentIter& ei)
|
|||
if (!env)
|
||||
return nullptr;
|
||||
|
||||
debugEnv = DebugEnvironmentProxy::create(cx, *env, enclosingDebug);
|
||||
} else if (ei.scope().is<WasmInstanceScope>()) {
|
||||
Rooted<WasmInstanceScope*> wasmInstanceScope(cx, &ei.scope().as<WasmInstanceScope>());
|
||||
Rooted<WasmInstanceEnvironmentObject*> env(cx,
|
||||
WasmInstanceEnvironmentObject::createHollowForDebug(cx, wasmInstanceScope));
|
||||
if (!env)
|
||||
return nullptr;
|
||||
|
||||
debugEnv = DebugEnvironmentProxy::create(cx, *env, enclosingDebug);
|
||||
} else if (ei.scope().is<WasmFunctionScope>()) {
|
||||
Rooted<WasmFunctionScope*> wasmFunctionScope(cx, &ei.scope().as<WasmFunctionScope>());
|
||||
Rooted<WasmFunctionCallObject*> callobj(cx, WasmFunctionCallObject::createHollowForDebug(cx, wasmFunctionScope));
|
||||
RootedObject enclosing(cx, &enclosingDebug->as<DebugEnvironmentProxy>().environment());
|
||||
Rooted<WasmFunctionCallObject*> callobj(cx,
|
||||
WasmFunctionCallObject::createHollowForDebug(cx, enclosing, wasmFunctionScope));
|
||||
if (!callobj)
|
||||
return nullptr;
|
||||
|
||||
|
@ -3053,6 +3132,7 @@ GetDebugEnvironment(JSContext* cx, const EnvironmentIter& ei)
|
|||
|
||||
if (ei.scope().is<FunctionScope>() ||
|
||||
ei.scope().is<LexicalScope>() ||
|
||||
ei.scope().is<WasmInstanceScope>() ||
|
||||
ei.scope().is<WasmFunctionScope>() ||
|
||||
ei.scope().is<VarScope>())
|
||||
{
|
||||
|
|
|
@ -427,6 +427,28 @@ typedef Rooted<ModuleEnvironmentObject*> RootedModuleEnvironmentObject;
|
|||
typedef Handle<ModuleEnvironmentObject*> HandleModuleEnvironmentObject;
|
||||
typedef MutableHandle<ModuleEnvironmentObject*> MutableHandleModuleEnvironmentObject;
|
||||
|
||||
class WasmInstanceEnvironmentObject : public EnvironmentObject
|
||||
{
|
||||
// Currently WasmInstanceScopes do not use their scopes in a
|
||||
// meaningful way. However, it is an invariant of DebugEnvironments that
|
||||
// environments kept in those maps have live scopes, thus this strong
|
||||
// reference.
|
||||
static const uint32_t SCOPE_SLOT = 1;
|
||||
|
||||
public:
|
||||
static const Class class_;
|
||||
|
||||
static const uint32_t RESERVED_SLOTS = 2;
|
||||
|
||||
static WasmInstanceEnvironmentObject* createHollowForDebug(JSContext* cx,
|
||||
Handle<WasmInstanceScope*> scope);
|
||||
WasmInstanceScope& scope() const {
|
||||
Value v = getReservedSlot(SCOPE_SLOT);
|
||||
MOZ_ASSERT(v.isPrivateGCThing());
|
||||
return *static_cast<WasmInstanceScope*>(v.toGCThing());
|
||||
}
|
||||
};
|
||||
|
||||
class WasmFunctionCallObject : public EnvironmentObject
|
||||
{
|
||||
// Currently WasmFunctionCallObjects do not use their scopes in a
|
||||
|
@ -440,7 +462,7 @@ class WasmFunctionCallObject : public EnvironmentObject
|
|||
|
||||
static const uint32_t RESERVED_SLOTS = 2;
|
||||
|
||||
static WasmFunctionCallObject* createHollowForDebug(JSContext* cx,
|
||||
static WasmFunctionCallObject* createHollowForDebug(JSContext* cx, HandleObject enclosing,
|
||||
Handle<WasmFunctionScope*> scope);
|
||||
WasmFunctionScope& scope() const {
|
||||
Value v = getReservedSlot(SCOPE_SLOT);
|
||||
|
@ -1015,6 +1037,7 @@ JSObject::is<js::EnvironmentObject>() const
|
|||
return is<js::CallObject>() ||
|
||||
is<js::VarEnvironmentObject>() ||
|
||||
is<js::ModuleEnvironmentObject>() ||
|
||||
is<js::WasmInstanceEnvironmentObject>() ||
|
||||
is<js::WasmFunctionCallObject>() ||
|
||||
is<js::LexicalEnvironmentObject>() ||
|
||||
is<js::WithEnvironmentObject>() ||
|
||||
|
|
|
@ -1071,6 +1071,7 @@ PopEnvironment(JSContext* cx, EnvironmentIter& ei)
|
|||
case ScopeKind::NonSyntactic:
|
||||
case ScopeKind::Module:
|
||||
break;
|
||||
case ScopeKind::WasmInstance:
|
||||
case ScopeKind::WasmFunction:
|
||||
MOZ_CRASH("wasm is not interpreted");
|
||||
break;
|
||||
|
|
|
@ -77,6 +77,8 @@ js::ScopeKindString(ScopeKind kind)
|
|||
return "non-syntactic";
|
||||
case ScopeKind::Module:
|
||||
return "module";
|
||||
case ScopeKind::WasmInstance:
|
||||
return "wasm instance";
|
||||
case ScopeKind::WasmFunction:
|
||||
return "wasm function";
|
||||
}
|
||||
|
@ -427,6 +429,7 @@ Scope::clone(JSContext* cx, HandleScope scope, HandleScope enclosing)
|
|||
break;
|
||||
|
||||
case ScopeKind::Module:
|
||||
case ScopeKind::WasmInstance:
|
||||
MOZ_CRASH("NYI");
|
||||
break;
|
||||
|
||||
|
@ -514,6 +517,9 @@ LexicalScope::nextFrameSlot(Scope* scope)
|
|||
return 0;
|
||||
case ScopeKind::Module:
|
||||
return si.scope()->as<ModuleScope>().nextFrameSlot();
|
||||
case ScopeKind::WasmInstance:
|
||||
// TODO return si.scope()->as<WasmInstanceScope>().nextFrameSlot();
|
||||
return 0;
|
||||
case ScopeKind::WasmFunction:
|
||||
// TODO return si.scope()->as<WasmFunctionScope>().nextFrameSlot();
|
||||
return 0;
|
||||
|
@ -1235,16 +1241,16 @@ ModuleScope::script() const
|
|||
return module()->script();
|
||||
}
|
||||
|
||||
// TODO Check what Debugger behavior should be when it evaluates a
|
||||
// var declaration.
|
||||
static const uint32_t WasmFunctionEnvShapeFlags =
|
||||
static const uint32_t WasmInstanceEnvShapeFlags =
|
||||
BaseShape::NOT_EXTENSIBLE | BaseShape::DELEGATE;
|
||||
|
||||
|
||||
template <size_t ArrayLength>
|
||||
static JSAtom*
|
||||
GenerateWasmVariableName(JSContext* cx, uint32_t index)
|
||||
GenerateWasmName(JSContext* cx, const char (&prefix)[ArrayLength], uint32_t index)
|
||||
{
|
||||
StringBuffer sb(cx);
|
||||
if (!sb.append("var"))
|
||||
if (!sb.append(prefix))
|
||||
return nullptr;
|
||||
if (!NumberValueToStringBuffer(cx, Int32Value(index), sb))
|
||||
return nullptr;
|
||||
|
@ -1252,45 +1258,109 @@ GenerateWasmVariableName(JSContext* cx, uint32_t index)
|
|||
return sb.finishAtom();
|
||||
}
|
||||
|
||||
/* static */ WasmFunctionScope*
|
||||
WasmFunctionScope::create(JSContext* cx, WasmInstanceObject* instance, uint32_t funcIndex)
|
||||
/* static */ WasmInstanceScope*
|
||||
WasmInstanceScope::create(JSContext* cx, WasmInstanceObject* instance)
|
||||
{
|
||||
// WasmFunctionScope::Data has GCManagedDeletePolicy because it contains a
|
||||
// WasmInstanceScope::Data has GCManagedDeletePolicy because it contains a
|
||||
// GCPtr. Destruction of |data| below may trigger calls into the GC.
|
||||
Rooted<WasmFunctionScope*> wasmFunctionScope(cx);
|
||||
Rooted<WasmInstanceScope*> wasmInstanceScope(cx);
|
||||
|
||||
{
|
||||
// TODO pull the local variable names from the wasm function definition.
|
||||
wasm::ValTypeVector locals;
|
||||
size_t argsLength;
|
||||
if (!instance->instance().debug().debugGetLocalTypes(funcIndex, &locals, &argsLength))
|
||||
return nullptr;
|
||||
uint32_t namesCount = locals.length();
|
||||
size_t namesCount = 0;
|
||||
if (instance->instance().memory()) {
|
||||
namesCount++;
|
||||
}
|
||||
size_t globalsStart = namesCount;
|
||||
size_t globalsCount = instance->instance().metadata().globals.length();
|
||||
namesCount += globalsCount;
|
||||
|
||||
Rooted<UniquePtr<Data>> data(cx, NewEmptyScopeData<WasmFunctionScope>(cx, namesCount));
|
||||
Rooted<UniquePtr<Data>> data(cx, NewEmptyScopeData<WasmInstanceScope>(cx, namesCount));
|
||||
if (!data)
|
||||
return nullptr;
|
||||
|
||||
Rooted<Scope*> enclosingScope(cx, &cx->global()->emptyGlobalScope());
|
||||
|
||||
data->instance.init(instance);
|
||||
data->funcIndex = funcIndex;
|
||||
data->length = namesCount;
|
||||
for (size_t i = 0; i < namesCount; i++) {
|
||||
RootedAtom name(cx, GenerateWasmVariableName(cx, i));
|
||||
size_t nameIndex = 0;
|
||||
if (instance->instance().memory()) {
|
||||
RootedAtom name(cx, GenerateWasmName(cx, "memory", /* index = */ 0));
|
||||
if (!name)
|
||||
return nullptr;
|
||||
data->names[i] = BindingName(name, false);
|
||||
data->names[nameIndex] = BindingName(name, false);
|
||||
nameIndex++;
|
||||
}
|
||||
for (size_t i = 0; i < globalsCount; i++) {
|
||||
RootedAtom name(cx, GenerateWasmName(cx, "global", i));
|
||||
if (!name)
|
||||
return nullptr;
|
||||
data->names[nameIndex] = BindingName(name, false);
|
||||
nameIndex++;
|
||||
}
|
||||
MOZ_ASSERT(nameIndex == namesCount);
|
||||
|
||||
Scope* scope = Scope::create(cx, ScopeKind::WasmFunction, enclosingScope, /* envShape = */ nullptr);
|
||||
data->instance.init(instance);
|
||||
data->memoriesStart = 0;
|
||||
data->globalsStart = globalsStart;
|
||||
data->length = namesCount;
|
||||
|
||||
Rooted<Scope*> enclosingScope(cx, &cx->global()->emptyGlobalScope());
|
||||
|
||||
Scope* scope = Scope::create(cx, ScopeKind::WasmInstance, enclosingScope, /* envShape = */ nullptr);
|
||||
if (!scope)
|
||||
return nullptr;
|
||||
|
||||
wasmFunctionScope = &scope->as<WasmFunctionScope>();
|
||||
wasmFunctionScope->initData(Move(data.get()));
|
||||
wasmInstanceScope = &scope->as<WasmInstanceScope>();
|
||||
wasmInstanceScope->initData(Move(data.get()));
|
||||
}
|
||||
|
||||
return wasmInstanceScope;
|
||||
}
|
||||
|
||||
/* static */ Shape*
|
||||
WasmInstanceScope::getEmptyEnvironmentShape(JSContext* cx)
|
||||
{
|
||||
const Class* cls = &WasmInstanceEnvironmentObject::class_;
|
||||
return EmptyEnvironmentShape(cx, cls, JSSLOT_FREE(cls), WasmInstanceEnvShapeFlags);
|
||||
}
|
||||
|
||||
// TODO Check what Debugger behavior should be when it evaluates a
|
||||
// var declaration.
|
||||
static const uint32_t WasmFunctionEnvShapeFlags =
|
||||
BaseShape::NOT_EXTENSIBLE | BaseShape::DELEGATE;
|
||||
|
||||
/* static */ WasmFunctionScope*
|
||||
WasmFunctionScope::create(JSContext* cx, HandleScope enclosing, uint32_t funcIndex)
|
||||
{
|
||||
MOZ_ASSERT(enclosing->is<WasmInstanceScope>());
|
||||
|
||||
Rooted<WasmFunctionScope*> wasmFunctionScope(cx);
|
||||
|
||||
Rooted<WasmInstanceObject*> instance(cx, enclosing->as<WasmInstanceScope>().instance());
|
||||
|
||||
// TODO pull the local variable names from the wasm function definition.
|
||||
wasm::ValTypeVector locals;
|
||||
size_t argsLength;
|
||||
if (!instance->instance().debug().debugGetLocalTypes(funcIndex, &locals, &argsLength))
|
||||
return nullptr;
|
||||
uint32_t namesCount = locals.length();
|
||||
|
||||
Rooted<UniquePtr<Data>> data(cx, NewEmptyScopeData<WasmFunctionScope>(cx, namesCount));
|
||||
if (!data)
|
||||
return nullptr;
|
||||
|
||||
data->funcIndex = funcIndex;
|
||||
data->length = namesCount;
|
||||
for (size_t i = 0; i < namesCount; i++) {
|
||||
RootedAtom name(cx, GenerateWasmName(cx, "var", i));
|
||||
if (!name)
|
||||
return nullptr;
|
||||
data->names[i] = BindingName(name, false);
|
||||
}
|
||||
|
||||
Scope* scope = Scope::create(cx, ScopeKind::WasmFunction, enclosing, /* envShape = */ nullptr);
|
||||
if (!scope)
|
||||
return nullptr;
|
||||
|
||||
wasmFunctionScope = &scope->as<WasmFunctionScope>();
|
||||
wasmFunctionScope->initData(Move(data.get()));
|
||||
|
||||
return wasmFunctionScope;
|
||||
}
|
||||
|
||||
|
@ -1352,6 +1422,9 @@ BindingIter::BindingIter(Scope* scope)
|
|||
case ScopeKind::Module:
|
||||
init(scope->as<ModuleScope>().data());
|
||||
break;
|
||||
case ScopeKind::WasmInstance:
|
||||
init(scope->as<WasmInstanceScope>().data());
|
||||
break;
|
||||
case ScopeKind::WasmFunction:
|
||||
init(scope->as<WasmFunctionScope>().data());
|
||||
break;
|
||||
|
@ -1485,6 +1558,22 @@ BindingIter::init(ModuleScope::Data& data)
|
|||
data.names, data.length);
|
||||
}
|
||||
|
||||
void
|
||||
BindingIter::init(WasmInstanceScope::Data& data)
|
||||
{
|
||||
// imports - [0, 0)
|
||||
// positional formals - [0, 0)
|
||||
// other formals - [0, 0)
|
||||
// top-level funcs - [0, 0)
|
||||
// vars - [0, data.length)
|
||||
// lets - [data.length, data.length)
|
||||
// consts - [data.length, data.length)
|
||||
init(0, 0, 0, 0, data.length, data.length,
|
||||
CanHaveFrameSlots | CanHaveEnvironmentSlots,
|
||||
UINT32_MAX, UINT32_MAX,
|
||||
data.names, data.length);
|
||||
}
|
||||
|
||||
void
|
||||
BindingIter::init(WasmFunctionScope::Data& data)
|
||||
{
|
||||
|
|
|
@ -73,6 +73,9 @@ enum class ScopeKind : uint8_t
|
|||
// ModuleScope
|
||||
Module,
|
||||
|
||||
// WasmInstanceScope
|
||||
WasmInstance,
|
||||
|
||||
// WasmFunctionScope
|
||||
WasmFunction
|
||||
};
|
||||
|
@ -949,21 +952,19 @@ class ModuleScope : public Scope
|
|||
static Shape* getEmptyEnvironmentShape(JSContext* cx);
|
||||
};
|
||||
|
||||
// Scope corresponding to the wasm function. A WasmFunctionScope is used by
|
||||
// Debugger only, and not for wasm execution.
|
||||
//
|
||||
class WasmFunctionScope : public Scope
|
||||
class WasmInstanceScope : public Scope
|
||||
{
|
||||
friend class BindingIter;
|
||||
friend class Scope;
|
||||
static const ScopeKind classScopeKind_ = ScopeKind::WasmFunction;
|
||||
static const ScopeKind classScopeKind_ = ScopeKind::WasmInstance;
|
||||
|
||||
public:
|
||||
struct Data
|
||||
{
|
||||
uint32_t memoriesStart;
|
||||
uint32_t globalsStart;
|
||||
uint32_t length;
|
||||
uint32_t nextFrameSlot;
|
||||
uint32_t funcIndex;
|
||||
|
||||
// The wasm instance of the scope.
|
||||
GCPtr<WasmInstanceObject*> instance;
|
||||
|
@ -973,7 +974,7 @@ class WasmFunctionScope : public Scope
|
|||
void trace(JSTracer* trc);
|
||||
};
|
||||
|
||||
static WasmFunctionScope* create(JSContext* cx, WasmInstanceObject* instance, uint32_t funcIndex);
|
||||
static WasmInstanceScope* create(JSContext* cx, WasmInstanceObject* instance);
|
||||
|
||||
static size_t sizeOfData(uint32_t length) {
|
||||
return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
|
||||
|
@ -993,6 +994,58 @@ class WasmFunctionScope : public Scope
|
|||
return data().instance;
|
||||
}
|
||||
|
||||
uint32_t memoriesStart() const {
|
||||
return data().memoriesStart;
|
||||
}
|
||||
|
||||
uint32_t globalsStart() const {
|
||||
return data().globalsStart;
|
||||
}
|
||||
|
||||
uint32_t namesCount() const {
|
||||
return data().length;
|
||||
}
|
||||
|
||||
static Shape* getEmptyEnvironmentShape(JSContext* cx);
|
||||
};
|
||||
|
||||
// Scope corresponding to the wasm function. A WasmFunctionScope is used by
|
||||
// Debugger only, and not for wasm execution.
|
||||
//
|
||||
class WasmFunctionScope : public Scope
|
||||
{
|
||||
friend class BindingIter;
|
||||
friend class Scope;
|
||||
static const ScopeKind classScopeKind_ = ScopeKind::WasmFunction;
|
||||
|
||||
public:
|
||||
struct Data
|
||||
{
|
||||
uint32_t length;
|
||||
uint32_t nextFrameSlot;
|
||||
uint32_t funcIndex;
|
||||
|
||||
BindingName names[1];
|
||||
|
||||
void trace(JSTracer* trc);
|
||||
};
|
||||
|
||||
static WasmFunctionScope* create(JSContext* cx, HandleScope enclosing, uint32_t funcIndex);
|
||||
|
||||
static size_t sizeOfData(uint32_t length) {
|
||||
return sizeof(Data) + (length ? length - 1 : 0) * sizeof(BindingName);
|
||||
}
|
||||
|
||||
private:
|
||||
Data& data() {
|
||||
return *reinterpret_cast<Data*>(data_);
|
||||
}
|
||||
|
||||
const Data& data() const {
|
||||
return *reinterpret_cast<Data*>(data_);
|
||||
}
|
||||
|
||||
public:
|
||||
uint32_t funcIndex() const {
|
||||
return data().funcIndex;
|
||||
}
|
||||
|
@ -1109,6 +1162,7 @@ class BindingIter
|
|||
void init(GlobalScope::Data& data);
|
||||
void init(EvalScope::Data& data, bool strict);
|
||||
void init(ModuleScope::Data& data);
|
||||
void init(WasmInstanceScope::Data& data);
|
||||
void init(WasmFunctionScope::Data& data);
|
||||
|
||||
bool hasFormalParameterExprs() const {
|
||||
|
|
|
@ -45,14 +45,15 @@ InterpreterFrame::initExecuteFrame(JSContext* cx, HandleScript script,
|
|||
RootedValue newTarget(cx, newTargetValue);
|
||||
if (script->isDirectEvalInFunction()) {
|
||||
FrameIter iter(cx);
|
||||
MOZ_ASSERT(!iter.isWasm());
|
||||
if (newTarget.isNull() &&
|
||||
iter.hasScript() &&
|
||||
iter.script()->bodyScope()->hasOnChain(ScopeKind::Function))
|
||||
{
|
||||
newTarget = iter.newTarget();
|
||||
}
|
||||
} else if (evalInFramePrev) {
|
||||
if (newTarget.isNull() &&
|
||||
evalInFramePrev.hasScript() &&
|
||||
evalInFramePrev.script()->bodyScope()->hasOnChain(ScopeKind::Function))
|
||||
{
|
||||
newTarget = evalInFramePrev.newTarget();
|
||||
|
@ -159,6 +160,10 @@ AssertScopeMatchesEnvironment(Scope* scope, JSObject* originalEnv)
|
|||
env = &env->as<ModuleEnvironmentObject>().enclosingEnvironment();
|
||||
break;
|
||||
|
||||
case ScopeKind::WasmInstance:
|
||||
env = &env->as<WasmInstanceEnvironmentObject>().enclosingEnvironment();
|
||||
break;
|
||||
|
||||
case ScopeKind::WasmFunction:
|
||||
env = &env->as<WasmFunctionCallObject>().enclosingEnvironment();
|
||||
break;
|
||||
|
@ -1188,7 +1193,6 @@ FrameIter::environmentChain(JSContext* cx) const
|
|||
{
|
||||
switch (data_.state_) {
|
||||
case DONE:
|
||||
case WASM:
|
||||
break;
|
||||
case JIT:
|
||||
if (data_.jitFrames_.isIonScripted()) {
|
||||
|
@ -1198,6 +1202,8 @@ FrameIter::environmentChain(JSContext* cx) const
|
|||
return data_.jitFrames_.baselineFrame()->environmentChain();
|
||||
case INTERP:
|
||||
return interpFrame()->environmentChain();
|
||||
case WASM:
|
||||
return data_.wasmFrames_.debugFrame()->environmentChain();
|
||||
}
|
||||
MOZ_CRASH("Unexpected state");
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "vm/Debugger.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
#include "wasm/WasmBinaryToText.h"
|
||||
#include "wasm/WasmInstance.h"
|
||||
#include "wasm/WasmValidate.h"
|
||||
|
||||
using namespace js;
|
||||
|
@ -549,6 +550,61 @@ DebugState::debugGetResultType(uint32_t funcIndex)
|
|||
return metadata().debugFuncReturnTypes[funcIndex];
|
||||
}
|
||||
|
||||
bool
|
||||
DebugState::getGlobal(Instance& instance, uint32_t globalIndex, MutableHandleValue vp)
|
||||
{
|
||||
const GlobalDesc& global = metadata().globals[globalIndex];
|
||||
|
||||
if (global.isConstant()) {
|
||||
Val value = global.constantValue();
|
||||
switch (value.type()) {
|
||||
case ValType::I32:
|
||||
vp.set(Int32Value(value.i32()));
|
||||
break;
|
||||
case ValType::I64:
|
||||
// Just display as a Number; it's ok if we lose some precision
|
||||
vp.set(NumberValue((double)value.i64()));
|
||||
break;
|
||||
case ValType::F32:
|
||||
vp.set(NumberValue(JS::CanonicalizeNaN(value.f32())));
|
||||
break;
|
||||
case ValType::F64:
|
||||
vp.set(NumberValue(JS::CanonicalizeNaN(value.f64())));
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("Global constant type");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t* globalData = instance.globalSegment().globalData();
|
||||
void* dataPtr = globalData + global.offset();
|
||||
switch (global.type()) {
|
||||
case ValType::I32: {
|
||||
vp.set(Int32Value(*static_cast<int32_t*>(dataPtr)));
|
||||
break;
|
||||
}
|
||||
case ValType::I64: {
|
||||
// Just display as a Number; it's ok if we lose some precision
|
||||
vp.set(NumberValue((double)*static_cast<int64_t*>(dataPtr)));
|
||||
break;
|
||||
}
|
||||
case ValType::F32: {
|
||||
vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<float*>(dataPtr))));
|
||||
break;
|
||||
}
|
||||
case ValType::F64: {
|
||||
vp.set(NumberValue(JS::CanonicalizeNaN(*static_cast<double*>(dataPtr))));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Global variable type");
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
JSString*
|
||||
DebugState::debugDisplayURL(JSContext* cx) const
|
||||
{
|
||||
|
|
|
@ -143,6 +143,7 @@ class DebugState
|
|||
|
||||
bool debugGetLocalTypes(uint32_t funcIndex, ValTypeVector* locals, size_t* argsLength);
|
||||
ExprType debugGetResultType(uint32_t funcIndex);
|
||||
bool getGlobal(Instance& instance, uint32_t globalIndex, MutableHandleValue vp);
|
||||
|
||||
// Debug URL helpers.
|
||||
|
||||
|
|
|
@ -523,6 +523,12 @@ Instance::trace(JSTracer* trc)
|
|||
TraceEdge(trc, &object_, "wasm instance object");
|
||||
}
|
||||
|
||||
WasmMemoryObject*
|
||||
Instance::memory() const
|
||||
{
|
||||
return memory_;
|
||||
}
|
||||
|
||||
SharedMem<uint8_t*>
|
||||
Instance::memoryBase() const
|
||||
{
|
||||
|
|
|
@ -116,6 +116,7 @@ class Instance
|
|||
bool isAsmJS() const { return metadata().isAsmJS(); }
|
||||
const SharedTableVector& tables() const { return tables_; }
|
||||
SharedMem<uint8_t*> memoryBase() const;
|
||||
WasmMemoryObject* memory() const;
|
||||
size_t memoryLength() const;
|
||||
size_t memoryMappedSize() const;
|
||||
bool memoryAccessInGuardRegion(uint8_t* addr, unsigned numBytes) const;
|
||||
|
|
|
@ -1035,6 +1035,7 @@ WasmInstanceObject::create(JSContext* cx,
|
|||
|
||||
obj->setReservedSlot(EXPORTS_SLOT, PrivateValue(exports.release()));
|
||||
obj->setReservedSlot(SCOPES_SLOT, PrivateValue(scopes.release()));
|
||||
obj->setReservedSlot(INSTANCE_SCOPE_SLOT, UndefinedValue());
|
||||
MOZ_ASSERT(obj->isNewborn());
|
||||
|
||||
MOZ_ASSERT(obj->isTenured(), "assumed by WasmTableObject write barriers");
|
||||
|
@ -1213,6 +1214,21 @@ WasmInstanceObject::getExportedFunctionCodeRange(HandleFunction fun, Tier tier)
|
|||
return instance().metadata(tier).codeRanges[funcExport.codeRangeIndex()];
|
||||
}
|
||||
|
||||
/* static */ WasmInstanceScope*
|
||||
WasmInstanceObject::getScope(JSContext* cx, HandleWasmInstanceObject instanceObj)
|
||||
{
|
||||
if (!instanceObj->getReservedSlot(INSTANCE_SCOPE_SLOT).isUndefined())
|
||||
return (WasmInstanceScope*)instanceObj->getReservedSlot(INSTANCE_SCOPE_SLOT).toGCThing();
|
||||
|
||||
Rooted<WasmInstanceScope*> instanceScope(cx, WasmInstanceScope::create(cx, instanceObj));
|
||||
if (!instanceScope)
|
||||
return nullptr;
|
||||
|
||||
instanceObj->setReservedSlot(INSTANCE_SCOPE_SLOT, PrivateGCThingValue(instanceScope));
|
||||
|
||||
return instanceScope;
|
||||
}
|
||||
|
||||
/* static */ WasmFunctionScope*
|
||||
WasmInstanceObject::getFunctionScope(JSContext* cx, HandleWasmInstanceObject instanceObj,
|
||||
uint32_t funcIndex)
|
||||
|
@ -1220,7 +1236,11 @@ WasmInstanceObject::getFunctionScope(JSContext* cx, HandleWasmInstanceObject ins
|
|||
if (ScopeMap::Ptr p = instanceObj->scopes().lookup(funcIndex))
|
||||
return p->value();
|
||||
|
||||
Rooted<WasmFunctionScope*> funcScope(cx, WasmFunctionScope::create(cx, instanceObj, funcIndex));
|
||||
Rooted<WasmInstanceScope*> instanceScope(cx, WasmInstanceObject::getScope(cx, instanceObj));
|
||||
if (!instanceScope)
|
||||
return nullptr;
|
||||
|
||||
Rooted<WasmFunctionScope*> funcScope(cx, WasmFunctionScope::create(cx, instanceScope, funcIndex));
|
||||
if (!funcScope)
|
||||
return nullptr;
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ namespace js {
|
|||
|
||||
class TypedArrayObject;
|
||||
class WasmFunctionScope;
|
||||
class WasmInstanceScope;
|
||||
|
||||
namespace wasm {
|
||||
|
||||
|
@ -147,6 +148,7 @@ class WasmInstanceObject : public NativeObject
|
|||
static const unsigned EXPORTS_OBJ_SLOT = 1;
|
||||
static const unsigned EXPORTS_SLOT = 2;
|
||||
static const unsigned SCOPES_SLOT = 3;
|
||||
static const unsigned INSTANCE_SCOPE_SLOT = 4;
|
||||
static const ClassOps classOps_;
|
||||
static bool exportsGetterImpl(JSContext* cx, const CallArgs& args);
|
||||
static bool exportsGetter(JSContext* cx, unsigned argc, Value* vp);
|
||||
|
@ -174,7 +176,7 @@ class WasmInstanceObject : public NativeObject
|
|||
ScopeMap& scopes() const;
|
||||
|
||||
public:
|
||||
static const unsigned RESERVED_SLOTS = 4;
|
||||
static const unsigned RESERVED_SLOTS = 5;
|
||||
static const Class class_;
|
||||
static const JSPropertySpec properties[];
|
||||
static const JSFunctionSpec methods[];
|
||||
|
@ -202,6 +204,7 @@ class WasmInstanceObject : public NativeObject
|
|||
|
||||
const wasm::CodeRange& getExportedFunctionCodeRange(HandleFunction fun, wasm::Tier tier);
|
||||
|
||||
static WasmInstanceScope* getScope(JSContext* cx, HandleWasmInstanceObject instanceObj);
|
||||
static WasmFunctionScope* getFunctionScope(JSContext* cx,
|
||||
HandleWasmInstanceObject instanceObj,
|
||||
uint32_t funcIndex);
|
||||
|
|
|
@ -852,7 +852,7 @@ GetGlobalExport(JSContext* cx, const GlobalDescVector& globals, uint32_t globalI
|
|||
jsval.set(ObjectValue(*obj));
|
||||
return true;
|
||||
}
|
||||
jsval.set(DoubleValue(double(f)));
|
||||
jsval.set(DoubleValue(JS::CanonicalizeNaN(double(f))));
|
||||
return true;
|
||||
}
|
||||
case ValType::F64: {
|
||||
|
@ -864,7 +864,7 @@ GetGlobalExport(JSContext* cx, const GlobalDescVector& globals, uint32_t globalI
|
|||
jsval.set(ObjectValue(*obj));
|
||||
return true;
|
||||
}
|
||||
jsval.set(DoubleValue(d));
|
||||
jsval.set(DoubleValue(JS::CanonicalizeNaN(d)));
|
||||
return true;
|
||||
}
|
||||
default: {
|
||||
|
|
|
@ -86,6 +86,10 @@ static LazyLogModule gJSCLLog("JSComponentLoader");
|
|||
static bool
|
||||
Dump(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
if (!nsContentUtils::DOMWindowDumpEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (args.length() == 0)
|
||||
|
|
|
@ -114,6 +114,10 @@ xpc::NewSandboxConstructor()
|
|||
static bool
|
||||
SandboxDump(JSContext* cx, unsigned argc, Value* vp)
|
||||
{
|
||||
if (!nsContentUtils::DOMWindowDumpEnabled()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CallArgs args = CallArgsFromVp(argc, vp);
|
||||
|
||||
if (args.length() == 0)
|
||||
|
|
|
@ -33,6 +33,7 @@ fuzzy-if(webrender,1,27) == compound-1a.html compound-1-ref.html
|
|||
== translate-1d.html translate-1-ref.html
|
||||
== translate-1e.html translate-1-ref.html
|
||||
== translate-2a.html translate-2-ref.html
|
||||
== translate-3.html translate-3-ref.html
|
||||
# rotate: Several rotations of the same object should be idempotent. These
|
||||
# tests are currently disabled because of subpixel (< 0.00001 gfx units)
|
||||
# rounding errors.
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
div {
|
||||
width: 100px; height: 100px;
|
||||
background: green;
|
||||
}
|
||||
</style>
|
||||
<div></div>
|
|
@ -0,0 +1,18 @@
|
|||
<!DOCTYPE html>
|
||||
<style>
|
||||
div {
|
||||
width: 100px; height: 100px;
|
||||
}
|
||||
#outer {
|
||||
background: green;
|
||||
overflow: hidden;
|
||||
}
|
||||
#inner {
|
||||
background: red;
|
||||
transform: translateX(calc(100px));
|
||||
}
|
||||
</style>
|
||||
<div id="outer">
|
||||
<div id="inner">
|
||||
</div>
|
||||
</div>
|
|
@ -539,7 +539,8 @@ SERVO_BINDING_FUNC(Servo_ResolveStyleLazily, ServoStyleContextStrong,
|
|||
mozilla::CSSPseudoElementType pseudo_type,
|
||||
mozilla::StyleRuleInclusion rule_inclusion,
|
||||
const mozilla::ServoElementSnapshotTable* snapshots,
|
||||
RawServoStyleSetBorrowed set)
|
||||
RawServoStyleSetBorrowed set,
|
||||
bool ignore_existing_styles)
|
||||
|
||||
// Reparents style to the new parents.
|
||||
SERVO_BINDING_FUNC(Servo_ReparentStyle, ServoStyleContextStrong,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
#include "mozilla/ServoStyleContext.h"
|
||||
|
||||
#include "nsCSSAnonBoxes.h"
|
||||
#include "nsStyleConsts.h"
|
||||
#include "nsStyleStruct.h"
|
||||
#include "nsPresContext.h"
|
||||
|
@ -31,4 +32,24 @@ ServoStyleContext::ServoStyleContext(
|
|||
// producing the ServoComputedData.
|
||||
}
|
||||
|
||||
ServoStyleContext*
|
||||
ServoStyleContext::GetCachedInheritingAnonBoxStyle(nsIAtom* aAnonBox) const
|
||||
{
|
||||
MOZ_ASSERT(nsCSSAnonBoxes::IsInheritingAnonBox(aAnonBox));
|
||||
|
||||
// See the reasoning in SetCachedInheritingAnonBoxStyle to understand why we
|
||||
// can't use the cache in this case.
|
||||
if (IsInheritingAnonBox()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto* current = mNextInheritingAnonBoxStyle.get();
|
||||
|
||||
while (current && current->GetPseudo() != aAnonBox) {
|
||||
current = current->mNextInheritingAnonBoxStyle.get();
|
||||
}
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -34,6 +34,28 @@ public:
|
|||
return ComputedData()->visited_style.mPtr;
|
||||
}
|
||||
|
||||
ServoStyleContext* GetCachedInheritingAnonBoxStyle(nsIAtom* aAnonBox) const;
|
||||
|
||||
void SetCachedInheritedAnonBoxStyle(nsIAtom* aAnonBox,
|
||||
ServoStyleContext& aStyle)
|
||||
{
|
||||
MOZ_ASSERT(!GetCachedInheritingAnonBoxStyle(aAnonBox));
|
||||
MOZ_ASSERT(!aStyle.mNextInheritingAnonBoxStyle);
|
||||
|
||||
// NOTE(emilio): Since we use it to cache inheriting anon boxes in a linked
|
||||
// list, we can't use that cache if the style we're inheriting from is an
|
||||
// inheriting anon box itself, since otherwise our parent would mistakenly
|
||||
// think that the style we're caching inherits from it.
|
||||
//
|
||||
// See the documentation of mNextInheritingAnonBoxStyle.
|
||||
if (IsInheritingAnonBox()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mNextInheritingAnonBoxStyle.swap(aStyle.mNextInheritingAnonBoxStyle);
|
||||
mNextInheritingAnonBoxStyle = &aStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes this context match |aOther| in terms of which style structs have
|
||||
* been resolved.
|
||||
|
@ -43,6 +65,13 @@ public:
|
|||
private:
|
||||
nsPresContext* mPresContext;
|
||||
ServoComputedData mSource;
|
||||
|
||||
// A linked-list cache of inheriting anon boxes inheriting from this style _if
|
||||
// the style isn't an inheriting anon-box_.
|
||||
//
|
||||
// Otherwise it represents the next entry in the cache of the parent style
|
||||
// context.
|
||||
RefPtr<ServoStyleContext> mNextInheritingAnonBoxStyle;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -191,13 +191,51 @@ ServoStyleSet::ResolveStyleFor(Element* aElement,
|
|||
RefPtr<ServoStyleContext> computedValues;
|
||||
if (aMayCompute == LazyComputeBehavior::Allow) {
|
||||
PreTraverseSync();
|
||||
return ResolveStyleLazily(
|
||||
return ResolveStyleLazilyInternal(
|
||||
aElement, CSSPseudoElementType::NotPseudo, nullptr, aParentContext);
|
||||
}
|
||||
|
||||
return ResolveServoStyle(aElement, ServoTraversalFlags::Empty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any stale Servo element data that might existing in the specified
|
||||
* element's document. Upon destruction, asserts that the element and all
|
||||
* its ancestors still have no element data, if the document has no pres shell.
|
||||
*/
|
||||
class MOZ_STACK_CLASS AutoClearStaleData
|
||||
{
|
||||
public:
|
||||
explicit AutoClearStaleData(Element* aElement)
|
||||
#ifdef DEBUG
|
||||
: mElement(aElement)
|
||||
#endif
|
||||
{
|
||||
aElement->OwnerDoc()->ClearStaleServoDataFromDocument();
|
||||
}
|
||||
|
||||
~AutoClearStaleData()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
// Assert that the element and its ancestors are all unstyled, if the
|
||||
// document has no pres shell.
|
||||
if (mElement->OwnerDoc()->HasShellOrBFCacheEntry()) {
|
||||
// We must check whether we're in the bfcache because its presence
|
||||
// means we have a "hidden" pres shell with up-to-date data in the
|
||||
// tree.
|
||||
return;
|
||||
}
|
||||
for (Element* e = mElement; e; e = e->GetParentElement()) {
|
||||
MOZ_ASSERT(!e->HasServoData(), "expected element to be unstyled");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
private:
|
||||
#ifdef DEBUG
|
||||
Element* mElement;
|
||||
#endif
|
||||
};
|
||||
|
||||
const ServoElementSnapshotTable&
|
||||
ServoStyleSet::Snapshots()
|
||||
|
@ -352,6 +390,32 @@ ServoStyleSet::PrepareAndTraverseSubtree(
|
|||
return postTraversalRequired;
|
||||
}
|
||||
|
||||
static inline already_AddRefed<ServoStyleContext>
|
||||
ResolveStyleForTextOrFirstLetterContinuation(
|
||||
RawServoStyleSetBorrowed aStyleSet,
|
||||
ServoStyleContext& aParent,
|
||||
nsIAtom* aAnonBox)
|
||||
{
|
||||
MOZ_ASSERT(aAnonBox == nsCSSAnonBoxes::mozText ||
|
||||
aAnonBox == nsCSSAnonBoxes::firstLetterContinuation);
|
||||
auto inheritTarget = aAnonBox == nsCSSAnonBoxes::mozText
|
||||
? InheritTarget::Text
|
||||
: InheritTarget::FirstLetterContinuation;
|
||||
|
||||
RefPtr<ServoStyleContext> style =
|
||||
aParent.GetCachedInheritingAnonBoxStyle(aAnonBox);
|
||||
if (!style) {
|
||||
style = Servo_ComputedValues_Inherit(aStyleSet,
|
||||
aAnonBox,
|
||||
&aParent,
|
||||
inheritTarget).Consume();
|
||||
MOZ_ASSERT(style);
|
||||
aParent.SetCachedInheritedAnonBoxStyle(aAnonBox, *style);
|
||||
}
|
||||
|
||||
return style.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ServoStyleContext>
|
||||
ServoStyleSet::ResolveStyleForText(nsIContent* aTextNode,
|
||||
ServoStyleContext* aParentContext)
|
||||
|
@ -360,29 +424,17 @@ ServoStyleSet::ResolveStyleForText(nsIContent* aTextNode,
|
|||
MOZ_ASSERT(aTextNode->GetParent());
|
||||
MOZ_ASSERT(aParentContext);
|
||||
|
||||
// Gecko expects text node style contexts to be like elements that match no
|
||||
// rules: inherit the inherit structs, reset the reset structs. This is cheap
|
||||
// enough to do on the main thread, which means that the parallel style system
|
||||
// can avoid worrying about text nodes.
|
||||
RefPtr<ServoStyleContext> computedValues =
|
||||
Servo_ComputedValues_Inherit(mRawSet.get(),
|
||||
nsCSSAnonBoxes::mozText,
|
||||
aParentContext,
|
||||
InheritTarget::Text).Consume();
|
||||
return computedValues.forget();
|
||||
return ResolveStyleForTextOrFirstLetterContinuation(
|
||||
mRawSet.get(), *aParentContext, nsCSSAnonBoxes::mozText);
|
||||
}
|
||||
|
||||
already_AddRefed<ServoStyleContext>
|
||||
ServoStyleSet::ResolveStyleForFirstLetterContinuation(ServoStyleContext* aParentContext)
|
||||
{
|
||||
RefPtr<ServoStyleContext> computedValues =
|
||||
Servo_ComputedValues_Inherit(mRawSet.get(),
|
||||
nsCSSAnonBoxes::firstLetterContinuation,
|
||||
aParentContext,
|
||||
InheritTarget::FirstLetterContinuation)
|
||||
.Consume();
|
||||
MOZ_ASSERT(computedValues);
|
||||
return computedValues.forget();
|
||||
MOZ_ASSERT(aParentContext);
|
||||
|
||||
return ResolveStyleForTextOrFirstLetterContinuation(
|
||||
mRawSet.get(), *aParentContext, nsCSSAnonBoxes::firstLetterContinuation);
|
||||
}
|
||||
|
||||
already_AddRefed<ServoStyleContext>
|
||||
|
@ -439,25 +491,33 @@ ServoStyleSet::ResolvePseudoElementStyle(Element* aOriginatingElement,
|
|||
}
|
||||
|
||||
already_AddRefed<ServoStyleContext>
|
||||
ServoStyleSet::ResolveTransientStyle(Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsIAtom* aPseudoTag,
|
||||
StyleRuleInclusion aRuleInclusion)
|
||||
ServoStyleSet::ResolveStyleLazily(Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsIAtom* aPseudoTag,
|
||||
StyleRuleInclusion aRuleInclusion)
|
||||
{
|
||||
RefPtr<ServoStyleContext> result =
|
||||
ResolveTransientServoStyle(aElement, aPseudoType, aPseudoTag, aRuleInclusion);
|
||||
return result.forget();
|
||||
}
|
||||
// Lazy style computation avoids storing any new data in the tree.
|
||||
// If the tree has stale data in it, then the AutoClearStaleData below
|
||||
// will ensure it's cleared so we don't use it. But if the document is
|
||||
// in the bfcache, then we will have valid, usable data in the tree,
|
||||
// but we don't want to use it. Instead we want to pretend as if the
|
||||
// document has no pres shell and no styles.
|
||||
//
|
||||
// If we don't do this, then we can very easily mix styles from different
|
||||
// style sets in the tree. For example, calling getComputedStyle on an
|
||||
// element in a display:none iframe (which has no pres shell) will use the
|
||||
// caller's style set for any styling. If we allowed this to re-use any
|
||||
// existing styles in the DOM, then we would do selector matching on the
|
||||
// undisplayed element with the caller's style set's rules, but inherit from
|
||||
// values that were computed with the style set from the target element's
|
||||
// hidden-by-the-bfcache-entry pres shell.
|
||||
bool ignoreExistingStyles = aElement->OwnerDoc()->GetBFCacheEntry();
|
||||
|
||||
already_AddRefed<ServoStyleContext>
|
||||
ServoStyleSet::ResolveTransientServoStyle(
|
||||
Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsIAtom* aPseudoTag,
|
||||
StyleRuleInclusion aRuleInclusion)
|
||||
{
|
||||
AutoClearStaleData guard(aElement);
|
||||
PreTraverseSync();
|
||||
return ResolveStyleLazily(aElement, aPseudoType, aPseudoTag, nullptr, aRuleInclusion);
|
||||
return ResolveStyleLazilyInternal(aElement, aPseudoType, aPseudoTag,
|
||||
nullptr, aRuleInclusion,
|
||||
ignoreExistingStyles);
|
||||
}
|
||||
|
||||
already_AddRefed<ServoStyleContext>
|
||||
|
@ -466,24 +526,28 @@ ServoStyleSet::ResolveInheritingAnonymousBoxStyle(nsIAtom* aPseudoTag,
|
|||
{
|
||||
MOZ_ASSERT(nsCSSAnonBoxes::IsAnonBox(aPseudoTag) &&
|
||||
!nsCSSAnonBoxes::IsNonInheritingAnonBox(aPseudoTag));
|
||||
MOZ_ASSERT_IF(aParentContext, !StylistNeedsUpdate());
|
||||
|
||||
UpdateStylistIfNeeded();
|
||||
|
||||
RefPtr<ServoStyleContext> computedValues =
|
||||
Servo_ComputedValues_GetForAnonymousBox(aParentContext,
|
||||
aPseudoTag,
|
||||
mRawSet.get()).Consume();
|
||||
#ifdef DEBUG
|
||||
if (!computedValues) {
|
||||
nsString pseudo;
|
||||
aPseudoTag->ToString(pseudo);
|
||||
NS_ERROR(nsPrintfCString("stylo: could not get anon-box: %s",
|
||||
NS_ConvertUTF16toUTF8(pseudo).get()).get());
|
||||
MOZ_CRASH();
|
||||
}
|
||||
#endif
|
||||
RefPtr<ServoStyleContext> style = nullptr;
|
||||
|
||||
return computedValues.forget();
|
||||
if (aParentContext) {
|
||||
style = aParentContext->GetCachedInheritingAnonBoxStyle(aPseudoTag);
|
||||
}
|
||||
|
||||
if (!style) {
|
||||
style =
|
||||
Servo_ComputedValues_GetForAnonymousBox(aParentContext,
|
||||
aPseudoTag,
|
||||
mRawSet.get()).Consume();
|
||||
MOZ_ASSERT(style);
|
||||
if (aParentContext) {
|
||||
aParentContext->SetCachedInheritedAnonBoxStyle(aPseudoTag, *style);
|
||||
}
|
||||
}
|
||||
|
||||
return style.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<ServoStyleContext>
|
||||
|
@ -920,6 +984,12 @@ ServoStyleSet::GetComputedKeyframeValuesFor(
|
|||
Element* aElement,
|
||||
const ServoStyleContext* aContext)
|
||||
{
|
||||
// Servo_GetComputedKeyframeValues below won't handle ignoring existing
|
||||
// element data for bfcached documents. (See comment in ResolveStyleLazily
|
||||
// about these bfcache issues.)
|
||||
MOZ_RELEASE_ASSERT(!aElement->OwnerDoc()->GetBFCacheEntry());
|
||||
|
||||
AutoClearStaleData guard(aElement);
|
||||
nsTArray<ComputedKeyframeValues> result(aKeyframes.Length());
|
||||
|
||||
// Construct each nsTArray<PropertyStyleAnimationValuePair> here.
|
||||
|
@ -940,6 +1010,12 @@ ServoStyleSet::GetAnimationValues(
|
|||
const ServoStyleContext* aStyleContext,
|
||||
nsTArray<RefPtr<RawServoAnimationValue>>& aAnimationValues)
|
||||
{
|
||||
// Servo_GetAnimationValues below won't handle ignoring existing element
|
||||
// data for bfcached documents. (See comment in ResolveStyleLazily
|
||||
// about these bfcache issues.)
|
||||
MOZ_RELEASE_ASSERT(!aElement->OwnerDoc()->GetBFCacheEntry());
|
||||
|
||||
AutoClearStaleData guard(aElement);
|
||||
Servo_GetAnimationValues(aDeclarations,
|
||||
aElement,
|
||||
aStyleContext,
|
||||
|
@ -956,6 +1032,14 @@ ServoStyleSet::GetBaseContextForElement(
|
|||
CSSPseudoElementType aPseudoType,
|
||||
const ServoStyleContext* aStyle)
|
||||
{
|
||||
// Servo_StyleSet_GetBaseComputedValuesForElement below won't handle ignoring
|
||||
// existing element data for bfcached documents. (See comment in
|
||||
// ResolveStyleLazily about these bfcache issues.)
|
||||
MOZ_RELEASE_ASSERT(!aElement->OwnerDoc()->GetBFCacheEntry(),
|
||||
"GetBaseContextForElement does not support documents in the "
|
||||
"bfcache");
|
||||
|
||||
AutoClearStaleData guard(aElement);
|
||||
return Servo_StyleSet_GetBaseComputedValuesForElement(mRawSet.get(),
|
||||
aElement,
|
||||
aStyle,
|
||||
|
@ -969,6 +1053,12 @@ ServoStyleSet::ComputeAnimationValue(
|
|||
RawServoDeclarationBlock* aDeclarations,
|
||||
const ServoStyleContext* aContext)
|
||||
{
|
||||
// Servo_AnimationValue_Compute below won't handle ignoring existing element
|
||||
// data for bfcached documents. (See comment in ResolveStyleLazily about
|
||||
// these bfcache issues.)
|
||||
MOZ_RELEASE_ASSERT(!aElement->OwnerDoc()->GetBFCacheEntry());
|
||||
|
||||
AutoClearStaleData guard(aElement);
|
||||
return Servo_AnimationValue_Compute(aElement,
|
||||
aDeclarations,
|
||||
aContext,
|
||||
|
@ -1068,11 +1158,12 @@ ServoStyleSet::ClearNonInheritingStyleContexts()
|
|||
}
|
||||
|
||||
already_AddRefed<ServoStyleContext>
|
||||
ServoStyleSet::ResolveStyleLazily(Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsIAtom* aPseudoTag,
|
||||
const ServoStyleContext* aParentContext,
|
||||
StyleRuleInclusion aRuleInclusion)
|
||||
ServoStyleSet::ResolveStyleLazilyInternal(Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsIAtom* aPseudoTag,
|
||||
const ServoStyleContext* aParentContext,
|
||||
StyleRuleInclusion aRuleInclusion,
|
||||
bool aIgnoreExistingStyles)
|
||||
{
|
||||
mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoType);
|
||||
MOZ_ASSERT(!StylistNeedsUpdate());
|
||||
|
@ -1109,7 +1200,8 @@ ServoStyleSet::ResolveStyleLazily(Element* aElement,
|
|||
pseudoTypeForStyleResolution,
|
||||
aRuleInclusion,
|
||||
&Snapshots(),
|
||||
mRawSet.get()).Consume();
|
||||
mRawSet.get(),
|
||||
aIgnoreExistingStyles).Consume();
|
||||
|
||||
if (mPresContext->EffectCompositor()->PreTraverse(aElement, aPseudoType)) {
|
||||
computedValues =
|
||||
|
@ -1117,7 +1209,8 @@ ServoStyleSet::ResolveStyleLazily(Element* aElement,
|
|||
pseudoTypeForStyleResolution,
|
||||
aRuleInclusion,
|
||||
&Snapshots(),
|
||||
mRawSet.get()).Consume();
|
||||
mRawSet.get(),
|
||||
aIgnoreExistingStyles).Consume();
|
||||
}
|
||||
|
||||
if (aPseudoType == CSSPseudoElementType::NotPseudo) {
|
||||
|
|
|
@ -174,24 +174,15 @@ public:
|
|||
dom::Element* aPseudoElement);
|
||||
|
||||
// Resolves style for a (possibly-pseudo) Element without assuming that the
|
||||
// style has been resolved, and without worrying about setting the style
|
||||
// context up to live in the style context tree (a null parent is used).
|
||||
// |aPeudoTag| and |aPseudoType| must match.
|
||||
// style has been resolved. If the element was unstyled and a new style
|
||||
// context was resolved, it is not stored in the DOM. (That is, the element
|
||||
// remains unstyled.) |aPeudoTag| and |aPseudoType| must match.
|
||||
already_AddRefed<ServoStyleContext>
|
||||
ResolveTransientStyle(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsIAtom* aPseudoTag,
|
||||
StyleRuleInclusion aRules =
|
||||
StyleRuleInclusion::All);
|
||||
|
||||
// Similar to ResolveTransientStyle() but doesn't update the context state
|
||||
// Unlike ResolveServoStyle() this function calls PreTraverseSync().
|
||||
already_AddRefed<ServoStyleContext>
|
||||
ResolveTransientServoStyle(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsIAtom* aPseudoTag,
|
||||
StyleRuleInclusion aRules =
|
||||
StyleRuleInclusion::All);
|
||||
ResolveStyleLazily(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsIAtom* aPseudoTag,
|
||||
StyleRuleInclusion aRules =
|
||||
StyleRuleInclusion::All);
|
||||
|
||||
// Get a style context for an anonymous box. aPseudoTag is the pseudo-tag to
|
||||
// use and must be non-null. It must be an anon box, and must be one that
|
||||
|
@ -554,12 +545,13 @@ private:
|
|||
void UpdateStylist();
|
||||
|
||||
already_AddRefed<ServoStyleContext>
|
||||
ResolveStyleLazily(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsIAtom* aPseudoTag,
|
||||
const ServoStyleContext* aParentContext,
|
||||
StyleRuleInclusion aRules =
|
||||
StyleRuleInclusion::All);
|
||||
ResolveStyleLazilyInternal(dom::Element* aElement,
|
||||
CSSPseudoElementType aPseudoType,
|
||||
nsIAtom* aPseudoTag,
|
||||
const ServoStyleContext* aParentContext,
|
||||
StyleRuleInclusion aRules =
|
||||
StyleRuleInclusion::All,
|
||||
bool aIgnoreExistingStyles = false);
|
||||
|
||||
void RunPostTraversalTasks();
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<style>
|
||||
textarea {
|
||||
min-height: 100px;
|
||||
}
|
||||
</style>
|
||||
<div>
|
||||
<iframe src="about:blank"></iframe>
|
||||
</div>
|
||||
<script>
|
||||
let div = document.querySelector('div');
|
||||
let iframe = document.querySelector('iframe');
|
||||
iframe.onload = function() {
|
||||
let doc = iframe.contentDocument;
|
||||
let e = doc.createElement('textarea');
|
||||
doc.body.appendChild(e);
|
||||
setTimeout(function() {
|
||||
getComputedStyle(e).minHeight;
|
||||
div.style.display = 'none';
|
||||
setTimeout(function() {
|
||||
getComputedStyle(e).minHeight;
|
||||
document.documentElement.className = "";
|
||||
}, 0);
|
||||
}, 0);
|
||||
};
|
||||
</script>
|
|
@ -0,0 +1,31 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<style>
|
||||
textarea {
|
||||
min-height: 100px;
|
||||
}
|
||||
</style>
|
||||
<div>
|
||||
<iframe src="about:blank"></iframe>
|
||||
</div>
|
||||
<script>
|
||||
let div = document.querySelector('div');
|
||||
let iframe = document.querySelector('iframe');
|
||||
iframe.onload = function() {
|
||||
let doc = iframe.contentDocument;
|
||||
let e = doc.createElement('textarea');
|
||||
doc.body.appendChild(e);
|
||||
setTimeout(function() {
|
||||
var cs = getComputedStyle(e);
|
||||
cs.minHeight;
|
||||
div.style.display = 'none';
|
||||
setTimeout(function() {
|
||||
div.style.display = 'block';
|
||||
setTimeout(function() {
|
||||
cs.minHeight;
|
||||
document.documentElement.className = "";
|
||||
}, 0);
|
||||
}, 0);
|
||||
}, 0);
|
||||
};
|
||||
</script>
|
|
@ -196,3 +196,5 @@ load link-transition-before.html
|
|||
load long-url-list-stack-overflow.html
|
||||
load 1383981.html
|
||||
load 1383981-2.html
|
||||
load 1384824-1.html
|
||||
load 1384824-2.html
|
||||
|
|
|
@ -59,6 +59,22 @@ public:
|
|||
false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
// NOTE(emilio): DEBUG only because this does a pretty slow linear search. Try
|
||||
// to use IsNonInheritingAnonBox if you know the atom is an anon box already
|
||||
// or, even better, nothing like this.
|
||||
static bool IsInheritingAnonBox(nsIAtom* aPseudo)
|
||||
{
|
||||
return
|
||||
#define CSS_ANON_BOX(_name, _value) _name == aPseudo ||
|
||||
#define CSS_NON_INHERITING_ANON_BOX(_name, _value) /* nothing */
|
||||
#include "nsCSSAnonBoxList.h"
|
||||
#undef CSS_NON_INHERITING_ANON_BOX
|
||||
#undef CSS_ANON_BOX
|
||||
false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get the NonInheriting type for a given pseudo tag. The pseudo tag must
|
||||
// test true for IsNonInheritingAnonBox.
|
||||
static NonInheriting NonInheritingTypeForPseudoTag(nsIAtom* aPseudo);
|
||||
|
|
|
@ -873,7 +873,7 @@ nsCSSValue::GetCalcValue() const
|
|||
nsStyleCoord::CalcValue result;
|
||||
|
||||
if (rootValue.GetUnit() == eCSSUnit_Pixel) {
|
||||
result.mLength = rootValue.GetFloatValue();
|
||||
result.mLength = rootValue.GetPixelLength();
|
||||
result.mPercent = 0.0f;
|
||||
result.mHasPercent = false;
|
||||
} else {
|
||||
|
@ -890,7 +890,7 @@ nsCSSValue::GetCalcValue() const
|
|||
"The first value should be eCSSUnit_Pixel");
|
||||
MOZ_ASSERT(percent.GetUnit() == eCSSUnit_Percent,
|
||||
"The first value should be eCSSUnit_Percent");
|
||||
result.mLength = length.GetFloatValue();
|
||||
result.mLength = length.GetPixelLength();
|
||||
result.mPercent = percent.GetPercentValue();
|
||||
result.mHasPercent = true;
|
||||
}
|
||||
|
|
|
@ -588,6 +588,15 @@ nsComputedDOMStyle::DoGetStyleContextNoFlush(Element* aElement,
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// We do this check to avoid having to add too much special casing of
|
||||
// Servo functions we call to explicitly ignore any element data in
|
||||
// the tree. (See comment in ServoStyleSet::ResolveStyleLazily.)
|
||||
MOZ_RELEASE_ASSERT((aStyleType == eAll && aAnimationFlag == eWithAnimation) ||
|
||||
!aElement->OwnerDoc()->GetBFCacheEntry(),
|
||||
"nsComputedDOMStyle doesn't support getting styles without "
|
||||
"document rules or without animation for documents in the "
|
||||
"bfcache");
|
||||
|
||||
auto pseudoType = CSSPseudoElementType::NotPseudo;
|
||||
if (aPseudo) {
|
||||
pseudoType = nsCSSPseudoElements::
|
||||
|
@ -657,7 +666,7 @@ nsComputedDOMStyle::DoGetStyleContextNoFlush(Element* aElement,
|
|||
? StyleRuleInclusion::DefaultOnly
|
||||
: StyleRuleInclusion::All;
|
||||
RefPtr<ServoStyleContext> result =
|
||||
servoSet->ResolveTransientStyle(aElement, pseudoType, aPseudo, rules);
|
||||
servoSet->ResolveStyleLazily(aElement, pseudoType, aPseudo, rules);
|
||||
if (aAnimationFlag == eWithAnimation) {
|
||||
return result.forget();
|
||||
}
|
||||
|
|
|
@ -94,11 +94,18 @@ public:
|
|||
mBits >> NS_STYLE_CONTEXT_TYPE_SHIFT);
|
||||
}
|
||||
|
||||
bool IsAnonBox() const {
|
||||
return
|
||||
GetPseudoType() == mozilla::CSSPseudoElementType::InheritingAnonBox ||
|
||||
GetPseudoType() == mozilla::CSSPseudoElementType::NonInheritingAnonBox;
|
||||
bool IsInheritingAnonBox() const {
|
||||
return GetPseudoType() == mozilla::CSSPseudoElementType::InheritingAnonBox;
|
||||
}
|
||||
|
||||
bool IsNonInheritingAnonBox() const {
|
||||
return GetPseudoType() == mozilla::CSSPseudoElementType::NonInheritingAnonBox;
|
||||
}
|
||||
|
||||
bool IsAnonBox() const {
|
||||
return IsInheritingAnonBox() || IsNonInheritingAnonBox();
|
||||
}
|
||||
|
||||
bool IsPseudoElement() const { return mPseudoTag && !IsAnonBox(); }
|
||||
|
||||
|
||||
|
|
|
@ -125,6 +125,14 @@ class nsStyleSet final
|
|||
return ResolveStyleFor(aElement, aParentContext);
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::GeckoStyleContext>
|
||||
ResolveCleanStyleFor(mozilla::dom::Element* aElement,
|
||||
mozilla::GeckoStyleContext* aParentContext,
|
||||
mozilla::LazyComputeBehavior)
|
||||
{
|
||||
return ResolveStyleFor(aElement, aParentContext);
|
||||
}
|
||||
|
||||
already_AddRefed<mozilla::GeckoStyleContext>
|
||||
ResolveStyleFor(mozilla::dom::Element* aElement,
|
||||
mozilla::GeckoStyleContext* aParentContext,
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "nsIContentPolicy.h"
|
||||
#include "nsIContentSecurityPolicy.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include <cctype>
|
||||
|
||||
|
@ -849,11 +850,16 @@ nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent,
|
|||
aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupportsString> styleText(do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID));
|
||||
if (styleText) {
|
||||
styleText->SetData(aStyleText);
|
||||
}
|
||||
|
||||
bool allowInlineStyle = true;
|
||||
rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_STYLESHEET,
|
||||
nonce,
|
||||
false, // aParserCreated only applies to scripts
|
||||
aStyleText, aLineNumber,
|
||||
styleText, aLineNumber,
|
||||
&allowInlineStyle);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
|
|
|
@ -46,8 +46,6 @@ to mochitest command.
|
|||
|
||||
## Need Gecko change
|
||||
|
||||
* test_specified_value_serialization.html `-webkit-radial-gradient`: bug 1380259 [1]
|
||||
|
||||
## Unknown / Unsure
|
||||
|
||||
## Ignore
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче