зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to mozilla-central a=merge
This commit is contained in:
Коммит
da14c413ef
|
@ -1212,7 +1212,6 @@ pref("services.sync.prefs.sync.browser.safebrowsing.downloads.enabled", true);
|
|||
pref("services.sync.prefs.sync.browser.safebrowsing.passwords.enabled", true);
|
||||
pref("services.sync.prefs.sync.browser.search.update", true);
|
||||
pref("services.sync.prefs.sync.browser.search.widget.inNavBar", true);
|
||||
pref("services.sync.prefs.sync.browser.sessionstore.restore_on_demand", true);
|
||||
pref("services.sync.prefs.sync.browser.startup.homepage", true);
|
||||
pref("services.sync.prefs.sync.browser.startup.page", true);
|
||||
pref("services.sync.prefs.sync.browser.tabs.loadInBackground", true);
|
||||
|
|
|
@ -1946,6 +1946,10 @@ var gBrowserInit = {
|
|||
DownloadsCommon.initializeAllDataLinks();
|
||||
ChromeUtils.import("resource:///modules/DownloadsTaskbar.jsm", {})
|
||||
.DownloadsTaskbar.registerIndicator(window);
|
||||
if (AppConstants.platform == "macosx") {
|
||||
ChromeUtils.import("resource:///modules/DownloadsMacFinderProgress.jsm")
|
||||
.DownloadsMacFinderProgress.register();
|
||||
}
|
||||
} catch (ex) {
|
||||
Cu.reportError(ex);
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ const {RemotePages} = ChromeUtils.import("resource://gre/modules/remotepagemanag
|
|||
var AboutProtectionsHandler = {
|
||||
_inited: false,
|
||||
_topics: [
|
||||
"ArrivedOnPage",
|
||||
"openContentBlockingPreferences",
|
||||
],
|
||||
|
||||
init() {
|
||||
|
@ -33,11 +33,11 @@ var AboutProtectionsHandler = {
|
|||
},
|
||||
|
||||
receiveMessage(aMessage) {
|
||||
let win = aMessage.target.browser.ownerGlobal;
|
||||
switch (aMessage.name) {
|
||||
case "ArrivedOnPage": {
|
||||
// Successfully recieved a message
|
||||
case "openContentBlockingPreferences":
|
||||
win.openPreferences("privacy-trackingprotection", {origin: "about-protections"});
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
|
|
@ -0,0 +1,87 @@
|
|||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80 filetype=javascript: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Handles the download progress indicator of the macOS Finder.
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
var EXPORTED_SYMBOLS = [
|
||||
"DownloadsMacFinderProgress",
|
||||
];
|
||||
|
||||
const {XPCOMUtils} = ChromeUtils.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetters(this, {
|
||||
Downloads: "resource://gre/modules/Downloads.jsm",
|
||||
});
|
||||
|
||||
var DownloadsMacFinderProgress = {
|
||||
/**
|
||||
* Maps the path of the download, to the according progress indicator instance.
|
||||
*/
|
||||
_finderProgresses: null,
|
||||
|
||||
/**
|
||||
* This method is called after a new browser window on macOS is opened, it
|
||||
* registers for receiving download events for the progressbar of the Finder.
|
||||
*/
|
||||
register() {
|
||||
// Ensure to register only once per process and not for every window.
|
||||
if (!this._finderProgresses) {
|
||||
this._finderProgresses = new Map();
|
||||
Downloads.getList(Downloads.ALL).then(list => list.addView(this));
|
||||
}
|
||||
},
|
||||
|
||||
onDownloadAdded(download) {
|
||||
if (download.stopped) {
|
||||
return;
|
||||
}
|
||||
|
||||
let finderProgress = Cc["@mozilla.org/widget/macfinderprogress;1"]
|
||||
.createInstance(Ci.nsIMacFinderProgress);
|
||||
|
||||
let path = download.target.path;
|
||||
|
||||
finderProgress.init(path, () => {
|
||||
download.cancel().catch(Cu.reportError);
|
||||
download.removePartialData().catch(Cu.reportError);
|
||||
});
|
||||
|
||||
if (download.hasProgress) {
|
||||
finderProgress.updateProgress(download.currentBytes, download.totalBytes);
|
||||
} else {
|
||||
finderProgress.updateProgress(0, 0);
|
||||
}
|
||||
this._finderProgresses.set(path, finderProgress);
|
||||
},
|
||||
|
||||
onDownloadChanged(download) {
|
||||
let path = download.target.path;
|
||||
let finderProgress = this._finderProgresses.get(path);
|
||||
if (!finderProgress) {
|
||||
// The download is not tracked, it may have been restarted,
|
||||
// thus forward the call to onDownloadAdded to check if it should be tracked.
|
||||
this.onDownloadAdded(download);
|
||||
} else if (download.stopped) {
|
||||
finderProgress.end();
|
||||
this._finderProgresses.delete(path);
|
||||
} else {
|
||||
finderProgress.updateProgress(download.currentBytes, download.totalBytes);
|
||||
}
|
||||
},
|
||||
|
||||
onDownloadRemoved(download) {
|
||||
let path = download.target.path;
|
||||
let finderProgress = this._finderProgresses.get(path);
|
||||
if (finderProgress) {
|
||||
finderProgress.end();
|
||||
this._finderProgresses.delete(path);
|
||||
}
|
||||
},
|
||||
};
|
|
@ -18,5 +18,10 @@ EXTRA_JS_MODULES += [
|
|||
'DownloadsViewUI.jsm',
|
||||
]
|
||||
|
||||
toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
|
||||
|
||||
if toolkit == 'cocoa':
|
||||
EXTRA_JS_MODULES += ['DownloadsMacFinderProgress.jsm']
|
||||
|
||||
with Files('**'):
|
||||
BUG_COMPONENT = ('Firefox', 'Downloads Panel')
|
||||
|
|
|
@ -107,7 +107,6 @@ Preferences.addAll([
|
|||
{ id: "browser.tabs.loadInBackground", type: "bool", inverted: true },
|
||||
{ id: "browser.tabs.warnOnClose", type: "bool" },
|
||||
{ id: "browser.tabs.warnOnOpen", type: "bool" },
|
||||
{ id: "browser.sessionstore.restore_on_demand", type: "bool" },
|
||||
{ id: "browser.ctrlTab.recentlyUsedOrder", type: "bool" },
|
||||
|
||||
// CFR
|
||||
|
|
|
@ -1,12 +1,94 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
.under-construction {
|
||||
background-image: url("chrome://browser/content/illustrations/under-construction.svg");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
min-height: 300px;
|
||||
min-width: 300px;
|
||||
/* Move the image down a bit - should be slightly higher than halfway down the page */
|
||||
margin-top: -10%;
|
||||
:root {
|
||||
--card-box-shadow: 0 1px 4px 0 rgba(12,12,13,0.1), 0 1px 0 0 rgba(0,0,0,0.05);
|
||||
--card-background: #FFF;
|
||||
--clickable-text-hover: hsla(0,0%,70%,.2);
|
||||
--clickable-text-active: hsla(0,0%,70%,.3);
|
||||
--card-divider: rgba(12,12,13,0.1) 1px solid;
|
||||
--report-background: #FAFAFC;
|
||||
--card-padding: 22px;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--report-background);
|
||||
font: message-box;
|
||||
margin-top: 82px;
|
||||
}
|
||||
|
||||
#report-title {
|
||||
font-size: 20px;
|
||||
font-weight: 300;
|
||||
margin-bottom: 22px;
|
||||
}
|
||||
|
||||
#report-content {
|
||||
width: 763px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.etp-card .icon {
|
||||
width: 60px;
|
||||
height: 60px;
|
||||
background: url("chrome://browser/skin/controlcenter/tracking-protection.svg") no-repeat center/cover;
|
||||
grid-column: 1;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.report-card {
|
||||
display: grid;
|
||||
grid-template-columns: 100%;
|
||||
grid-template-rows: 20% auto;
|
||||
border-radius: 3px;
|
||||
background-color: var(--card-background);
|
||||
box-shadow: var(--card-box-shadow);
|
||||
}
|
||||
|
||||
.report-card .card-header {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 7fr;
|
||||
padding: var(--card-padding);
|
||||
grid-gap: var(--card-padding);
|
||||
}
|
||||
|
||||
.report-card .card-title {
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
margin: 0;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.report-card .content {
|
||||
margin-bottom: 24px;
|
||||
margin-top: 5px;
|
||||
font-size: 14px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#protection-details {
|
||||
background: url("chrome://browser/skin/settings.svg") no-repeat 3px 3px;
|
||||
padding: 4px 4px 4px 24px;
|
||||
font-size: 12px;
|
||||
display: inline;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
#protection-details:hover {
|
||||
background-color: var(--clickable-text-hover);
|
||||
}
|
||||
|
||||
#protection-details:hover:active {
|
||||
background-color: var(--clickable-text-active);
|
||||
}
|
||||
|
||||
#protection-details span {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
border-top: var(--card-divider);
|
||||
grid-column: span 2;
|
||||
grid-row: 2;
|
||||
margin-bottom: 24px;
|
||||
}
|
||||
|
|
|
@ -7,8 +7,6 @@
|
|||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src chrome: blob:">
|
||||
<link rel="stylesheet" media="screen, projection" type="text/css"
|
||||
href="chrome://global/skin/in-content/info-pages.css" title="infop">
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="chrome://browser/content/protections.css">
|
||||
<link rel="icon" href="chrome://global/skin/icons/warning.svg">
|
||||
|
@ -17,6 +15,26 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<div class="under-construction"><div/>
|
||||
<div id="report-content">
|
||||
<h2 id="report-title">Privacy Protections</h2>
|
||||
<div class="report-card etp-card">
|
||||
<div class="card-header">
|
||||
<div class="icon"></div>
|
||||
<div class="wrapper">
|
||||
<h3 class="card-title">
|
||||
Enhanced Tracking Protection
|
||||
</h3>
|
||||
<p class="content">
|
||||
Trackers follow you around online to collect information about your browsing habits and interests. Firefox blocks many of these trackers and other malicious scripts.
|
||||
</p>
|
||||
<p id="protection-details">
|
||||
Protection Level is set to <span>Standard</span>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -5,5 +5,8 @@
|
|||
/* eslint-env mozilla/frame-script */
|
||||
|
||||
document.addEventListener("DOMContentLoaded", (e) => {
|
||||
RPMSendAsyncMessage("ArrivedOnPage");
|
||||
let protectionDetails = document.getElementById("protection-details");
|
||||
protectionDetails.addEventListener("click", () => {
|
||||
RPMSendAsyncMessage("openContentBlockingPreferences");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,10 +17,14 @@ var RemotePrompt = {
|
|||
receiveMessage(message) {
|
||||
switch (message.name) {
|
||||
case "Prompt:Open":
|
||||
if (message.data.uri) {
|
||||
this.openModalWindow(message.data, message.target);
|
||||
} else {
|
||||
const COMMON_DIALOG = "chrome://global/content/commonDialog.xul";
|
||||
const SELECT_DIALOG = "chrome://global/content/selectDialog.xul";
|
||||
|
||||
if (message.data.tabPrompt) {
|
||||
this.openTabPrompt(message.data, message.target);
|
||||
} else {
|
||||
let uri = (message.data.promptType == "select") ? SELECT_DIALOG : COMMON_DIALOG;
|
||||
this.openModalWindow(uri, message.data, message.target);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -85,13 +89,13 @@ var RemotePrompt = {
|
|||
}
|
||||
},
|
||||
|
||||
openModalWindow(args, browser) {
|
||||
openModalWindow(uri, args, browser) {
|
||||
let window = browser.ownerGlobal;
|
||||
try {
|
||||
PromptUtils.fireDialogEvent(window, "DOMWillOpenModalDialog", browser);
|
||||
let bag = PromptUtils.objectToPropBag(args);
|
||||
|
||||
Services.ww.openWindow(window, args.uri, "_blank",
|
||||
Services.ww.openWindow(window, uri, "_blank",
|
||||
"centerscreen,chrome,modal,titlebar", bag);
|
||||
|
||||
PromptUtils.propBagToObject(bag, args);
|
||||
|
|
|
@ -1122,7 +1122,7 @@ panelview .toolbarbutton-1,
|
|||
transform: translateY(1px);
|
||||
}
|
||||
|
||||
#main-window:not([customizing]) .subviewbutton-nav[disabled=true]::after {
|
||||
:root:not([customizing]) .subviewbutton-nav[disabled=true]::after {
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ async function updateBreakpoints(dispatch, client, newEvents: string[]) {
|
|||
active: newEvents,
|
||||
};
|
||||
|
||||
client.setEventListenerBreakpoints(newEvents);
|
||||
await client.setEventListenerBreakpoints(newEvents);
|
||||
}
|
||||
|
||||
async function updateExpanded(dispatch, newExpanded: string[]) {
|
||||
|
@ -46,7 +46,7 @@ export function addEventListenerBreakpoints(eventsToAdd: string[]) {
|
|||
|
||||
const newEvents = uniq([...eventsToAdd, ...activeListenerBreakpoints]);
|
||||
|
||||
updateBreakpoints(dispatch, client, newEvents);
|
||||
await updateBreakpoints(dispatch, client, newEvents);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -59,7 +59,7 @@ export function removeEventListenerBreakpoints(eventsToRemove: string[]) {
|
|||
event => !eventsToRemove.includes(event)
|
||||
);
|
||||
|
||||
updateBreakpoints(dispatch, client, newEvents);
|
||||
await updateBreakpoints(dispatch, client, newEvents);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,11 @@ export async function onConnect(connection: any, actions: Object) {
|
|||
});
|
||||
|
||||
// Retrieve possible event listener breakpoints
|
||||
actions.getEventListenerBreakpointTypes();
|
||||
actions.getEventListenerBreakpointTypes().catch(e => console.error(e));
|
||||
|
||||
// Initialize the event breakpoints on the thread up front so that
|
||||
// they are active once attached.
|
||||
actions.addEventListenerBreakpoints([]).catch(e => console.error(e));
|
||||
|
||||
// In Firefox, we need to initially request all of the sources. This
|
||||
// usually fires off individual `newSource` notifications as the
|
||||
|
|
|
@ -35,7 +35,10 @@ import type {
|
|||
SourcesPacket,
|
||||
} from "./types";
|
||||
|
||||
import type { EventListenerCategoryList } from "../../actions/types";
|
||||
import type {
|
||||
EventListenerCategoryList,
|
||||
EventListenerActiveList,
|
||||
} from "../../actions/types";
|
||||
|
||||
let workerClients: Object;
|
||||
let threadClient: ThreadClient;
|
||||
|
@ -43,6 +46,7 @@ let tabTarget: TabTarget;
|
|||
let debuggerClient: DebuggerClient;
|
||||
let sourceActors: { [ActorId]: SourceId };
|
||||
let breakpoints: { [string]: Object };
|
||||
let eventBreakpoints: ?EventListenerActiveList;
|
||||
let supportsWasm: boolean;
|
||||
|
||||
let shouldWaitForWorkers = false;
|
||||
|
@ -363,6 +367,8 @@ function interrupt(thread: string): Promise<*> {
|
|||
}
|
||||
|
||||
async function setEventListenerBreakpoints(ids: string[]) {
|
||||
eventBreakpoints = ids;
|
||||
|
||||
await threadClient.setActiveEventBreakpoints(ids);
|
||||
await forEachWorkerThread(thread => thread.setActiveEventBreakpoints(ids));
|
||||
}
|
||||
|
@ -371,8 +377,7 @@ async function setEventListenerBreakpoints(ids: string[]) {
|
|||
async function getEventListenerBreakpointTypes(): Promise<
|
||||
EventListenerCategoryList
|
||||
> {
|
||||
const { value } = await threadClient.getAvailableEventBreakpoints();
|
||||
return value;
|
||||
return threadClient.getAvailableEventBreakpoints();
|
||||
}
|
||||
|
||||
function pauseGrip(thread: string, func: Function): ObjectClient {
|
||||
|
@ -406,6 +411,7 @@ async function fetchWorkers(): Promise<Worker[]> {
|
|||
if (features.windowlessWorkers) {
|
||||
const options = {
|
||||
breakpoints,
|
||||
eventBreakpoints,
|
||||
observeAsmJS: true,
|
||||
};
|
||||
|
||||
|
|
|
@ -368,9 +368,7 @@ export type ThreadClient = {
|
|||
request: (payload: Object) => Promise<*>,
|
||||
url: string,
|
||||
setActiveEventBreakpoints: (string[]) => void,
|
||||
getAvailableEventBreakpoints: () => Promise<{|
|
||||
value: EventListenerCategoryList,
|
||||
|}>,
|
||||
getAvailableEventBreakpoints: () => Promise<EventListenerCategoryList>,
|
||||
skipBreakpoints: boolean => Promise<{| skip: boolean |}>,
|
||||
};
|
||||
|
||||
|
|
|
@ -91,7 +91,14 @@ class EventListeners extends Component<Props> {
|
|||
<input
|
||||
type="checkbox"
|
||||
value={category.name}
|
||||
onChange={e => this.onCategoryClick(category, e.target.checked)}
|
||||
onChange={e => {
|
||||
this.onCategoryClick(
|
||||
category,
|
||||
// Clicking an indeterminate checkbox should always have the
|
||||
// effect of disabling any selected items.
|
||||
indeterminate ? false : e.target.checked
|
||||
);
|
||||
}}
|
||||
checked={checked}
|
||||
ref={el => el && (el.indeterminate = indeterminate)}
|
||||
/>
|
||||
|
|
|
@ -46,19 +46,19 @@ function update(
|
|||
}
|
||||
|
||||
export function getActiveEventListeners(state: State): EventListenerActiveList {
|
||||
return state.eventListenerBreakpoints.active;
|
||||
return state.eventListenerBreakpoints.active || [];
|
||||
}
|
||||
|
||||
export function getEventListenerBreakpointTypes(
|
||||
state: State
|
||||
): EventListenerCategoryList {
|
||||
return state.eventListenerBreakpoints.categories;
|
||||
return state.eventListenerBreakpoints.categories || [];
|
||||
}
|
||||
|
||||
export function getEventListenerExpanded(
|
||||
state: State
|
||||
): EventListenerExpandedList {
|
||||
return state.eventListenerBreakpoints.expanded;
|
||||
return state.eventListenerBreakpoints.expanded || [];
|
||||
}
|
||||
|
||||
export default update;
|
||||
|
|
|
@ -16,6 +16,7 @@ const reasons = {
|
|||
exception: "whyPaused.exception",
|
||||
resumeLimit: "whyPaused.resumeLimit",
|
||||
breakpointConditionThrown: "whyPaused.breakpointConditionThrown",
|
||||
eventBreakpoint: "whyPaused.eventBreakpoint",
|
||||
|
||||
// V8
|
||||
DOM: "whyPaused.breakpoint",
|
||||
|
|
|
@ -593,6 +593,8 @@ support-files =
|
|||
examples/html-breakpoints-slow.js
|
||||
examples/sjs_slow-load.sjs
|
||||
examples/fetch.js
|
||||
examples/doc-event-breakpoints.html
|
||||
examples/event-breakpoints.js
|
||||
examples/doc-xhr.html
|
||||
examples/doc-xhr-run-to-completion.html
|
||||
examples/doc-scroll-run-to-completion.html
|
||||
|
@ -806,6 +808,7 @@ skip-if = true
|
|||
[browser_dbg-worker-scopes.js]
|
||||
skip-if = (os == 'linux' && debug) || ccov #Bug 1456013
|
||||
[browser_dbg-event-handler.js]
|
||||
[browser_dbg-event-breakpoints.js]
|
||||
[browser_dbg-eval-throw.js]
|
||||
[browser_dbg-sourceURL-breakpoint.js]
|
||||
[browser_dbg-old-breakpoint.js]
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
function assertPauseLocation(dbg, line) {
|
||||
const { location } = dbg.selectors.getVisibleSelectedFrame();
|
||||
|
||||
const source = findSource(dbg, "event-breakpoints.js");
|
||||
|
||||
is(location.sourceId, source.id, `correct sourceId`);
|
||||
is(location.line, line, `correct line`);
|
||||
|
||||
assertPausedLocation(dbg);
|
||||
}
|
||||
|
||||
add_task(async function() {
|
||||
await pushPref("devtools.debugger.features.event-listeners-breakpoints", true);
|
||||
|
||||
const dbg = await initDebugger("doc-event-breakpoints.html", "event-breakpoints");
|
||||
await selectSource(dbg, "event-breakpoints");
|
||||
await waitForSelectedSource(dbg, "event-breakpoints");
|
||||
|
||||
await dbg.actions.addEventListenerBreakpoints([
|
||||
"event.mouse.click",
|
||||
"event.xhr.load",
|
||||
"timer.timeout.set",
|
||||
"timer.timeout.fire",
|
||||
]);
|
||||
|
||||
invokeInTab("clickHandler");
|
||||
await waitForPaused(dbg);
|
||||
assertPauseLocation(dbg, 12);
|
||||
await resume(dbg);
|
||||
|
||||
invokeInTab("xhrHandler");
|
||||
await waitForPaused(dbg);
|
||||
assertPauseLocation(dbg, 20);
|
||||
await resume(dbg);
|
||||
|
||||
invokeInTab("timerHandler");
|
||||
await waitForPaused(dbg);
|
||||
assertPauseLocation(dbg, 27);
|
||||
await resume(dbg);
|
||||
|
||||
await waitForPaused(dbg);
|
||||
assertPauseLocation(dbg, 29);
|
||||
await resume(dbg);
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
||||
- License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Debugger event bp test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<button id="click-button">Run Click Handler</button>
|
||||
<button id="xhr-button">Run XHR Handler</button>
|
||||
<button id="timer-button">Run Timer Handler</button>
|
||||
<div id="click-target" style="margin: 50px; background-color: green;">
|
||||
Click Target
|
||||
</div>
|
||||
<script src="event-breakpoints.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,34 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at <http://mozilla.org/MPL/2.0/>. */
|
||||
|
||||
document.getElementById("click-button").onmousedown = clickHandler;
|
||||
function clickHandler() {
|
||||
document.getElementById("click-target").click();
|
||||
}
|
||||
|
||||
document.getElementById("click-target").onclick = clickTargetClicked;
|
||||
function clickTargetClicked() {
|
||||
console.log("clicked");
|
||||
}
|
||||
|
||||
document.getElementById("xhr-button").onmousedown = xhrHandler;
|
||||
function xhrHandler() {
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.open("GET", "doc-event-breakpoints.html", true);
|
||||
xhr.onload = function(){
|
||||
console.log("xhr load");
|
||||
};
|
||||
xhr.send();
|
||||
}
|
||||
|
||||
document.getElementById("timer-button").onmousedown = timerHandler;
|
||||
function timerHandler() {
|
||||
setTimeout(
|
||||
() => {
|
||||
console.log("timer callback");
|
||||
},
|
||||
50
|
||||
);
|
||||
console.log("timer set");
|
||||
}
|
|
@ -983,6 +983,11 @@ whyPaused.debuggerStatement=Paused on debugger statement
|
|||
# in a info block explaining how the debugger is currently paused on a breakpoint
|
||||
whyPaused.breakpoint=Paused on breakpoint
|
||||
|
||||
# LOCALIZATION NOTE (whyPaused.eventBreakpoint): The text that is displayed
|
||||
# in a info block explaining how the debugger is currently paused on an event
|
||||
# breakpoint.
|
||||
whyPaused.eventBreakpoint=Paused on event breakpoint
|
||||
|
||||
# LOCALIZATION NOTE (whyPaused.exception): The text that is displayed
|
||||
# in a info block explaining how the debugger is currently paused on an exception
|
||||
whyPaused.exception=Paused on exception
|
||||
|
|
|
@ -66,6 +66,10 @@ headersEmptyText=No headers for this request
|
|||
# headers tab of the network details pane for the filtering input.
|
||||
headersFilterText=Filter headers
|
||||
|
||||
# LOCALIZATION NOTE (webSocketsEmptyText): This is the text displayed in the
|
||||
# WebSockets tab of the network details pane when there are no frames available.
|
||||
webSocketsEmptyText=No WebSocket frames for this request
|
||||
|
||||
# LOCALIZATION NOTE (cookiesEmptyText): This is the text displayed in the
|
||||
# cookies tab of the network details pane when there are no cookies available.
|
||||
cookiesEmptyText=No cookies for this request
|
||||
|
@ -637,6 +641,10 @@ netmonitor.toolbar.waterfall=Timeline
|
|||
# in the network details pane identifying the headers tab.
|
||||
netmonitor.tab.headers=Headers
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.tab.webSockets): This is the label displayed
|
||||
# in the network details pane identifying the webSockets tab.
|
||||
netmonitor.tab.webSockets=WebSockets
|
||||
|
||||
# LOCALIZATION NOTE (netmonitor.tab.cookies): This is the label displayed
|
||||
# in the network details pane identifying the cookies tab.
|
||||
netmonitor.tab.cookies=Cookies
|
||||
|
|
|
@ -11,6 +11,7 @@ const selection = require("./selection");
|
|||
const sort = require("./sort");
|
||||
const timingMarkers = require("./timing-markers");
|
||||
const ui = require("./ui");
|
||||
const webSockets = require("./web-sockets");
|
||||
|
||||
Object.assign(exports,
|
||||
batching,
|
||||
|
@ -19,5 +20,6 @@ Object.assign(exports,
|
|||
selection,
|
||||
sort,
|
||||
timingMarkers,
|
||||
ui
|
||||
ui,
|
||||
webSockets,
|
||||
);
|
||||
|
|
|
@ -11,4 +11,5 @@ DevToolsModules(
|
|||
'sort.js',
|
||||
'timing-markers.js',
|
||||
'ui.js',
|
||||
'web-sockets.js',
|
||||
)
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { WS_ADD_FRAME } = require("../constants");
|
||||
|
||||
function addFrame(httpChannelId, data) {
|
||||
return {
|
||||
type: WS_ADD_FRAME,
|
||||
httpChannelId,
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
addFrame,
|
||||
};
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const Services = require("Services");
|
||||
const {
|
||||
Component,
|
||||
createFactory,
|
||||
|
@ -17,6 +18,7 @@ const Tabbar = createFactory(require("devtools/client/shared/components/tabs/Tab
|
|||
const TabPanel = createFactory(require("devtools/client/shared/components/tabs/Tabs").TabPanel);
|
||||
const CookiesPanel = createFactory(require("./CookiesPanel"));
|
||||
const HeadersPanel = createFactory(require("./HeadersPanel"));
|
||||
const WebSocketsPanel = createFactory(require("./WebSocketsPanel"));
|
||||
const ParamsPanel = createFactory(require("./ParamsPanel"));
|
||||
const CachePanel = createFactory(require("./CachePanel"));
|
||||
const ResponsePanel = createFactory(require("./ResponsePanel"));
|
||||
|
@ -28,6 +30,7 @@ const COLLAPSE_DETAILS_PANE = L10N.getStr("collapseDetailsPane");
|
|||
const CACHE_TITLE = L10N.getStr("netmonitor.tab.cache");
|
||||
const COOKIES_TITLE = L10N.getStr("netmonitor.tab.cookies");
|
||||
const HEADERS_TITLE = L10N.getStr("netmonitor.tab.headers");
|
||||
const WEBSOCKETS_TITLE = L10N.getStr("netmonitor.tab.webSockets");
|
||||
const PARAMS_TITLE = L10N.getStr("netmonitor.tab.params");
|
||||
const RESPONSE_TITLE = L10N.getStr("netmonitor.tab.response");
|
||||
const SECURITY_TITLE = L10N.getStr("netmonitor.tab.security");
|
||||
|
@ -87,6 +90,11 @@ class TabboxPanel extends Component {
|
|||
return null;
|
||||
}
|
||||
|
||||
const channelId = request.channelId;
|
||||
const showWebSocketsPanel =
|
||||
request.cause.type === "websocket" &&
|
||||
Services.prefs.getBoolPref(
|
||||
"devtools.netmonitor.features.webSockets");
|
||||
return (
|
||||
Tabbar({
|
||||
activeTabId,
|
||||
|
@ -113,6 +121,14 @@ class TabboxPanel extends Component {
|
|||
request,
|
||||
}),
|
||||
),
|
||||
showWebSocketsPanel && TabPanel({
|
||||
id: PANELS.WEBSOCKETS,
|
||||
title: WEBSOCKETS_TITLE,
|
||||
},
|
||||
WebSocketsPanel({
|
||||
channelId,
|
||||
}),
|
||||
),
|
||||
TabPanel({
|
||||
id: PANELS.COOKIES,
|
||||
title: COOKIES_TITLE,
|
||||
|
|
|
@ -0,0 +1,85 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const { Component } = require("devtools/client/shared/vendor/react");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const {
|
||||
connect,
|
||||
} = require("devtools/client/shared/redux/visibility-handler-connect");
|
||||
const { getFramesByChannelId } = require("../selectors/index");
|
||||
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const { table, tbody, thead, tr, td, th, div } = dom;
|
||||
|
||||
const { L10N } = require("../utils/l10n");
|
||||
const FRAMES_EMPTY_TEXT = L10N.getStr("webSocketsEmptyText");
|
||||
|
||||
class WebSocketsPanel extends Component {
|
||||
static get propTypes() {
|
||||
return {
|
||||
channelId: PropTypes.number,
|
||||
frames: PropTypes.array,
|
||||
};
|
||||
}
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
}
|
||||
|
||||
render() {
|
||||
const { frames } = this.props;
|
||||
|
||||
if (!frames) {
|
||||
return div({ className: "empty-notice" },
|
||||
FRAMES_EMPTY_TEXT
|
||||
);
|
||||
}
|
||||
|
||||
const rows = [];
|
||||
frames.forEach((frame, index) => {
|
||||
rows.push(
|
||||
tr(
|
||||
{ key: index,
|
||||
className: "frames-row" },
|
||||
td({ className: "frames-cell" }, frame.type),
|
||||
td({ className: "frames-cell" }, frame.httpChannelId),
|
||||
td({ className: "frames-cell" }, frame.payload),
|
||||
td({ className: "frames-cell" }, frame.opCode),
|
||||
td({ className: "frames-cell" }, frame.maskBit.toString()),
|
||||
td({ className: "frames-cell" }, frame.finBit.toString()),
|
||||
td({ className: "frames-cell" }, frame.timeStamp)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
return table(
|
||||
{ className: "frames-list-table" },
|
||||
thead(
|
||||
{ className: "frames-head" },
|
||||
tr(
|
||||
{ className: "frames-row" },
|
||||
th({ className: "frames-headerCell" }, "Type"),
|
||||
th({ className: "frames-headerCell" }, "Channel ID"),
|
||||
th({ className: "frames-headerCell" }, "Payload"),
|
||||
th({ className: "frames-headerCell" }, "OpCode"),
|
||||
th({ className: "frames-headerCell" }, "MaskBit"),
|
||||
th({ className: "frames-headerCell" }, "FinBit"),
|
||||
th({ className: "frames-headerCell" }, "Time")
|
||||
)
|
||||
),
|
||||
tbody(
|
||||
{
|
||||
className: "frames-list-tableBody",
|
||||
},
|
||||
rows
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = connect((state, props) => ({
|
||||
frames: getFramesByChannelId(state, props.channelId),
|
||||
}))(WebSocketsPanel);
|
|
@ -47,4 +47,5 @@ DevToolsModules(
|
|||
'TabboxPanel.js',
|
||||
'TimingsPanel.js',
|
||||
'Toolbar.js',
|
||||
'WebSocketsPanel.js',
|
||||
)
|
||||
|
|
|
@ -79,6 +79,7 @@ class FirefoxDataProvider {
|
|||
isThirdPartyTrackingResource,
|
||||
referrerPolicy,
|
||||
blockedReason,
|
||||
channelId,
|
||||
} = data;
|
||||
|
||||
// Insert blocked reason in the payload queue as well, as we'll need it later
|
||||
|
@ -106,6 +107,7 @@ class FirefoxDataProvider {
|
|||
isThirdPartyTrackingResource,
|
||||
referrerPolicy,
|
||||
blockedReason,
|
||||
channelId,
|
||||
}, true);
|
||||
}
|
||||
|
||||
|
@ -343,6 +345,7 @@ class FirefoxDataProvider {
|
|||
isThirdPartyTrackingResource,
|
||||
referrerPolicy,
|
||||
blockedReason,
|
||||
channelId,
|
||||
} = networkInfo;
|
||||
|
||||
await this.addRequest(actor, {
|
||||
|
@ -356,6 +359,7 @@ class FirefoxDataProvider {
|
|||
isThirdPartyTrackingResource,
|
||||
referrerPolicy,
|
||||
blockedReason,
|
||||
channelId,
|
||||
});
|
||||
|
||||
this.emit(EVENTS.NETWORK_EVENT, actor);
|
||||
|
@ -426,11 +430,6 @@ class FirefoxDataProvider {
|
|||
* @param {string} extensions
|
||||
*/
|
||||
async onWebSocketOpened(httpChannelId, effectiveURI, protocols, extensions) {
|
||||
console.log("FirefoxDataProvider onWebSocketOpened: " +
|
||||
" httpChannelId: " + httpChannelId +
|
||||
" effectiveURI: " + effectiveURI +
|
||||
" protocols: " + protocols +
|
||||
" extensions: " + extensions);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -441,10 +440,6 @@ class FirefoxDataProvider {
|
|||
* @param {string} reason
|
||||
*/
|
||||
async onWebSocketClosed(wasClean, code, reason) {
|
||||
console.log("FirefoxDataProvider onWebSocketClosed: " +
|
||||
" wasClean: " + wasClean +
|
||||
" code: " + code +
|
||||
" reason: " + reason);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -454,11 +449,7 @@ class FirefoxDataProvider {
|
|||
* @param {object} data websocket frame information
|
||||
*/
|
||||
async onFrameSent(httpChannelId, data) {
|
||||
await this.getLongString(data.payload).then(payload => {
|
||||
console.log("FirefoxDataProvider onFrameSent: " +
|
||||
" httpChannelId: " + httpChannelId +
|
||||
" onFrameSent: " + payload);
|
||||
});
|
||||
this.addFrame(httpChannelId, data);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -468,11 +459,20 @@ class FirefoxDataProvider {
|
|||
* @param {object} data websocket frame information
|
||||
*/
|
||||
async onFrameReceived(httpChannelId, data) {
|
||||
await this.getLongString(data.payload).then(payload => {
|
||||
console.log("FirefoxDataProvider onFrameReceived: " +
|
||||
" httpChannelId: " + httpChannelId +
|
||||
" onFrameSent: " + payload);
|
||||
});
|
||||
this.addFrame(httpChannelId, data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new WebSocket frame to application state.
|
||||
*
|
||||
* @param {number} httpChannelId the channel ID
|
||||
* @param {object} data websocket frame information
|
||||
*/
|
||||
async addFrame(httpChannelId, data) {
|
||||
if (this.actionsEnabled && this.actions.addFrame) {
|
||||
await this.actions.addFrame(httpChannelId, data);
|
||||
}
|
||||
// TODO: Emit an event for test here
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -34,6 +34,7 @@ const actionTypes = {
|
|||
UPDATE_REQUEST: "UPDATE_REQUEST",
|
||||
WATERFALL_RESIZE: "WATERFALL_RESIZE",
|
||||
SET_COLUMNS_WIDTH: "SET_COLUMNS_WIDTH",
|
||||
WS_ADD_FRAME: "WS_ADD_FRAME",
|
||||
};
|
||||
|
||||
// Descriptions for what this frontend is currently doing.
|
||||
|
@ -154,11 +155,13 @@ const UPDATE_PROPS = [
|
|||
"isThirdPartyTrackingResource",
|
||||
"referrerPolicy",
|
||||
"blockedReason",
|
||||
"channelId",
|
||||
];
|
||||
|
||||
const PANELS = {
|
||||
COOKIES: "cookies",
|
||||
HEADERS: "headers",
|
||||
WEBSOCKETS: "webSockets",
|
||||
PARAMS: "params",
|
||||
RESPONSE: "response",
|
||||
CACHE: "cache",
|
||||
|
|
|
@ -27,6 +27,7 @@ const { Requests } = require("./reducers/requests");
|
|||
const { Sort } = require("./reducers/sort");
|
||||
const { TimingMarkers } = require("./reducers/timing-markers");
|
||||
const { UI, Columns, ColumnsData } = require("./reducers/ui");
|
||||
const { WebSockets } = require("./reducers/web-sockets");
|
||||
|
||||
/**
|
||||
* Configure state and middleware for the Network monitor tool.
|
||||
|
@ -44,6 +45,7 @@ function configureStore(connector, telemetry) {
|
|||
columns: getColumnState(),
|
||||
columnsData: getColumnsData(),
|
||||
}),
|
||||
webSockets: new WebSockets(),
|
||||
};
|
||||
|
||||
// Prepare middleware.
|
||||
|
|
|
@ -11,12 +11,14 @@ const { sortReducer } = require("./sort");
|
|||
const { filters } = require("./filters");
|
||||
const { timingMarkers } = require("./timing-markers");
|
||||
const { ui } = require("./ui");
|
||||
const { webSocketsReducer } = require("./web-sockets");
|
||||
const networkThrottling = require("devtools/client/shared/components/throttling/reducer");
|
||||
|
||||
module.exports = batchingReducer(
|
||||
combineReducers({
|
||||
requests: requestsReducer,
|
||||
sort: sortReducer,
|
||||
webSockets: webSocketsReducer,
|
||||
filters,
|
||||
timingMarkers,
|
||||
ui,
|
||||
|
|
|
@ -10,4 +10,5 @@ DevToolsModules(
|
|||
'sort.js',
|
||||
'timing-markers.js',
|
||||
'ui.js',
|
||||
'web-sockets.js',
|
||||
)
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
const {
|
||||
WS_ADD_FRAME,
|
||||
} = require("../constants");
|
||||
|
||||
/**
|
||||
* This structure stores list of all WebSocket frames received
|
||||
* from the backend.
|
||||
*/
|
||||
function WebSockets() {
|
||||
return {
|
||||
// Map with all requests (key = channelId, value = array of frame objects)
|
||||
frames: new Map(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This reducer is responsible for maintaining list of
|
||||
* WebSocket frames within the Network panel.
|
||||
*/
|
||||
function webSocketsReducer(state = WebSockets(), action) {
|
||||
switch (action.type) {
|
||||
// Appending new frame into the map.
|
||||
case WS_ADD_FRAME: {
|
||||
const nextState = { ...state };
|
||||
|
||||
const newFrame = {
|
||||
httpChannelId: action.httpChannelId,
|
||||
...action.data,
|
||||
};
|
||||
|
||||
nextState.frames = mapSet(state.frames, newFrame.httpChannelId, newFrame);
|
||||
|
||||
return nextState;
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Append new item into existing map and return new map.
|
||||
*/
|
||||
function mapSet(map, key, value) {
|
||||
const newMap = new Map(map);
|
||||
if (newMap.has(key)) {
|
||||
const framesArray = [...newMap.get(key)];
|
||||
framesArray.push(value);
|
||||
newMap.set(key, framesArray);
|
||||
return newMap;
|
||||
}
|
||||
return newMap.set(key, [value]);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
WebSockets,
|
||||
webSocketsReducer,
|
||||
};
|
|
@ -7,9 +7,11 @@
|
|||
const requests = require("./requests");
|
||||
const timingMarkers = require("./timing-markers");
|
||||
const ui = require("./ui");
|
||||
const webSockets = require("./web-sockets");
|
||||
|
||||
Object.assign(exports,
|
||||
requests,
|
||||
timingMarkers,
|
||||
ui
|
||||
ui,
|
||||
webSockets,
|
||||
);
|
||||
|
|
|
@ -7,4 +7,5 @@ DevToolsModules(
|
|||
'requests.js',
|
||||
'timing-markers.js',
|
||||
'ui.js',
|
||||
'web-sockets.js',
|
||||
)
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
function getFramesByChannelId(state, channelId) {
|
||||
return state.webSockets.frames.get(channelId);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getFramesByChannelId,
|
||||
};
|
|
@ -71,7 +71,7 @@ body {
|
|||
.variable-or-property .token-number,
|
||||
.variable-or-property[return] > .title > .name,
|
||||
.variable-or-property[scope] > .title > .name {
|
||||
color: #6B89FF;
|
||||
color: #709AFF;
|
||||
}
|
||||
|
||||
.CodeMirror-Tern-completion-number:before {
|
||||
|
@ -124,7 +124,7 @@ body {
|
|||
.cm-s-mozilla .cm-string-2,
|
||||
.variable-or-property .token-string,
|
||||
.CodeMirror-Tern-farg {
|
||||
color: #6B89FF;
|
||||
color: #709AFF;
|
||||
}
|
||||
|
||||
.CodeMirror-Tern-completion-string:before,
|
||||
|
|
|
@ -75,6 +75,10 @@ function getCleanedPacket(key, packet) {
|
|||
res.actor = existingPacket.actor;
|
||||
}
|
||||
|
||||
if (res.channelId) {
|
||||
res.channelId = existingPacket.channelId;
|
||||
}
|
||||
|
||||
if (res.message) {
|
||||
// Clean timeStamp on the message prop.
|
||||
res.message.timeStamp = existingPacket.message.timeStamp;
|
||||
|
|
|
@ -265,6 +265,7 @@ stubPackets.set(`GET request`, {
|
|||
"private": false,
|
||||
"isThirdPartyTrackingResource": false,
|
||||
"referrerPolicy": "no-referrer-when-downgrade",
|
||||
"channelId": 22673132355586,
|
||||
"from": "server1.conn0.child1/consoleActor2"
|
||||
});
|
||||
|
||||
|
@ -315,6 +316,7 @@ stubPackets.set(`XHR GET request`, {
|
|||
"private": false,
|
||||
"isThirdPartyTrackingResource": false,
|
||||
"referrerPolicy": "no-referrer-when-downgrade",
|
||||
"channelId": 22673132355587,
|
||||
"from": "server1.conn1.child1/consoleActor2"
|
||||
});
|
||||
|
||||
|
@ -365,6 +367,7 @@ stubPackets.set(`XHR POST request`, {
|
|||
"private": false,
|
||||
"isThirdPartyTrackingResource": false,
|
||||
"referrerPolicy": "no-referrer-when-downgrade",
|
||||
"channelId": 22673132355588,
|
||||
"from": "server1.conn2.child1/consoleActor2"
|
||||
});
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ const NetworkEventActor = protocol.ActorClassWithSpec(networkEventSpec, {
|
|||
isThirdPartyTrackingResource: this._isThirdPartyTrackingResource,
|
||||
referrerPolicy: this._referrerPolicy,
|
||||
blockedReason: this._blockedReason,
|
||||
channelId: this._channelId,
|
||||
};
|
||||
},
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
const DebuggerNotificationObserver = require("DebuggerNotificationObserver");
|
||||
const Services = require("Services");
|
||||
const { Cr, Ci } = require("chrome");
|
||||
const { ActorPool } = require("devtools/server/actors/common");
|
||||
|
@ -16,6 +17,8 @@ const { assert, dumpn } = DevToolsUtils;
|
|||
const { threadSpec } = require("devtools/shared/specs/thread");
|
||||
const {
|
||||
getAvailableEventBreakpoints,
|
||||
eventBreakpointForNotification,
|
||||
makeEventBreakpointMessage,
|
||||
} = require("devtools/server/actors/utils/event-breakpoints");
|
||||
|
||||
loader.lazyRequireGetter(this, "EnvironmentActor", "devtools/server/actors/environment", true);
|
||||
|
@ -61,7 +64,8 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
this._scripts = null;
|
||||
this._xhrBreakpoints = [];
|
||||
this._observingNetwork = false;
|
||||
this._eventBreakpoints = [];
|
||||
this._activeEventBreakpoints = new Set();
|
||||
this._activeEventPause = null;
|
||||
|
||||
this._priorPause = null;
|
||||
|
||||
|
@ -94,6 +98,10 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
this.objectGrip = this.objectGrip.bind(this);
|
||||
this.pauseObjectGrip = this.pauseObjectGrip.bind(this);
|
||||
this._onOpeningRequest = this._onOpeningRequest.bind(this);
|
||||
this._onNewDebuggee = this._onNewDebuggee.bind(this);
|
||||
this._eventBreakpointListener = this._eventBreakpointListener.bind(this);
|
||||
|
||||
this._debuggerNotificationObserver = new DebuggerNotificationObserver();
|
||||
|
||||
if (Services.obs) {
|
||||
// Set a wrappedJSObject property so |this| can be sent via the observer svc
|
||||
|
@ -112,6 +120,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
this._dbg.uncaughtExceptionHook = this.uncaughtExceptionHook;
|
||||
this._dbg.onDebuggerStatement = this.onDebuggerStatement;
|
||||
this._dbg.onNewScript = this.onNewScript;
|
||||
this._dbg.onNewDebuggee = this._onNewDebuggee;
|
||||
if (this._dbg.replaying) {
|
||||
this._dbg.replayingOnForcedPause = this.replayingOnForcedPause.bind(this);
|
||||
const sendProgress = throttle((recording, executionPoint) => {
|
||||
|
@ -223,6 +232,16 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
this._xhrBreakpoints = [];
|
||||
this._updateNetworkObserver();
|
||||
|
||||
this._activeEventBreakpoints = new Set();
|
||||
this._debuggerNotificationObserver.removeListener(
|
||||
this._eventBreakpointListener);
|
||||
|
||||
for (const global of this.dbg.getDebuggees()) {
|
||||
try {
|
||||
this._debuggerNotificationObserver.disconnect(global);
|
||||
} catch (e) { }
|
||||
}
|
||||
|
||||
this.sources.off("newSource", this.onNewSourceEvent);
|
||||
this.clearDebuggees();
|
||||
this.conn.removeActorPool(this._threadLifetimePool);
|
||||
|
@ -285,6 +304,9 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
if (options.breakpoints) {
|
||||
this._setBreakpointsOnAttach(options.breakpoints);
|
||||
}
|
||||
if (options.eventBreakpoints) {
|
||||
this.setActiveEventBreakpoints(options.eventBreakpoints);
|
||||
}
|
||||
|
||||
this.dbg.addDebuggees();
|
||||
this.dbg.enabled = true;
|
||||
|
@ -400,10 +422,24 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
return getAvailableEventBreakpoints();
|
||||
},
|
||||
getActiveEventBreakpoints: function() {
|
||||
return this._eventBreakpoints;
|
||||
return Array.from(this._activeEventBreakpoints);
|
||||
},
|
||||
setActiveEventBreakpoints: function(ids) {
|
||||
this._eventBreakpoints = ids;
|
||||
this._activeEventBreakpoints = new Set(ids);
|
||||
|
||||
if (this._activeEventBreakpoints.size === 0) {
|
||||
this._debuggerNotificationObserver.removeListener(
|
||||
this._eventBreakpointListener);
|
||||
} else {
|
||||
this._debuggerNotificationObserver.addListener(
|
||||
this._eventBreakpointListener);
|
||||
}
|
||||
},
|
||||
|
||||
_onNewDebuggee(global) {
|
||||
try {
|
||||
this._debuggerNotificationObserver.connect(global);
|
||||
} catch (e) { }
|
||||
},
|
||||
|
||||
_updateNetworkObserver() {
|
||||
|
@ -513,6 +549,81 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
return {};
|
||||
},
|
||||
|
||||
_eventBreakpointListener(notification) {
|
||||
if (this._state === "paused" || this._state === "detached") {
|
||||
return;
|
||||
}
|
||||
|
||||
const eventBreakpoint =
|
||||
eventBreakpointForNotification(this.dbg, notification);
|
||||
|
||||
if (!this._activeEventBreakpoints.has(eventBreakpoint)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (notification.phase === "pre" && !this._activeEventPause) {
|
||||
this._activeEventPause = this._captureDebuggerHooks();
|
||||
|
||||
this.dbg.onEnterFrame =
|
||||
this._makeEventBreakpointEnterFrame(eventBreakpoint);
|
||||
} else if (notification.phase === "post" && this._activeEventPause) {
|
||||
this._restoreDebuggerHooks(this._activeEventPause);
|
||||
this._activeEventPause = null;
|
||||
} else if (!notification.phase && !this._activeEventPause) {
|
||||
const frame = this.dbg.getNewestFrame();
|
||||
if (frame) {
|
||||
const { sourceActor } = this.sources.getFrameLocation(frame);
|
||||
const url = sourceActor.url;
|
||||
if (this.sources.isBlackBoxed(url)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._pauseAndRespondEventBreakpoint(frame, eventBreakpoint);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
_makeEventBreakpointEnterFrame(eventBreakpoint) {
|
||||
return frame => {
|
||||
const { sourceActor } = this.sources.getFrameLocation(frame);
|
||||
const url = sourceActor.url;
|
||||
if (this.sources.isBlackBoxed(url)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
this._restoreDebuggerHooks(this._activeEventPause);
|
||||
this._activeEventPause = null;
|
||||
|
||||
return this._pauseAndRespondEventBreakpoint(frame, eventBreakpoint);
|
||||
};
|
||||
},
|
||||
|
||||
_pauseAndRespondEventBreakpoint(frame, eventBreakpoint) {
|
||||
if (this.skipBreakpoints) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return this._pauseAndRespond(frame, {
|
||||
type: "eventBreakpoint",
|
||||
breakpoint: eventBreakpoint,
|
||||
message: makeEventBreakpointMessage(eventBreakpoint),
|
||||
});
|
||||
},
|
||||
|
||||
_captureDebuggerHooks() {
|
||||
return {
|
||||
onEnterFrame: this.dbg.onEnterFrame,
|
||||
onStep: this.dbg.onStep,
|
||||
onPop: this.dbg.onPop,
|
||||
};
|
||||
},
|
||||
|
||||
_restoreDebuggerHooks(hooks) {
|
||||
this.dbg.onEnterFrame = hooks.onEnterFrame;
|
||||
this.dbg.onStep = hooks.onStep;
|
||||
this.dbg.onPop = hooks.onPop;
|
||||
},
|
||||
|
||||
/**
|
||||
* Pause the debuggee, by entering a nested event loop, and return a 'paused'
|
||||
* packet to the client.
|
||||
|
@ -575,7 +686,7 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
return this._parentClosed ? null : undefined;
|
||||
},
|
||||
|
||||
_makeOnEnterFrame: function({ thread, pauseAndRespond }) {
|
||||
_makeOnEnterFrame: function({ pauseAndRespond }) {
|
||||
return frame => {
|
||||
const { sourceActor } = this.sources.getFrameLocation(frame);
|
||||
|
||||
|
@ -590,13 +701,13 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
}
|
||||
|
||||
// Continue forward until we get to a valid step target.
|
||||
const { onStep, onPop } = thread._makeSteppingHooks(
|
||||
const { onStep, onPop } = this._makeSteppingHooks(
|
||||
null, "next", false, null
|
||||
);
|
||||
|
||||
if (thread.dbg.replaying) {
|
||||
if (this.dbg.replaying) {
|
||||
const offsets =
|
||||
thread._findReplayingStepOffsets(null, frame,
|
||||
this._findReplayingStepOffsets(null, frame,
|
||||
/* rewinding = */ false);
|
||||
frame.setReplayingOnStep(onStep, offsets);
|
||||
} else {
|
||||
|
@ -608,7 +719,8 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
};
|
||||
},
|
||||
|
||||
_makeOnPop: function({ thread, pauseAndRespond, startLocation, steppingType }) {
|
||||
_makeOnPop: function({ pauseAndRespond, startLocation, steppingType }) {
|
||||
const thread = this;
|
||||
const result = function(completion) {
|
||||
// onPop is called with 'this' set to the current frame.
|
||||
const location = thread.sources.getFrameLocation(this);
|
||||
|
@ -728,8 +840,9 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
return script.getOffsetMetadata(offset).isStepStart;
|
||||
},
|
||||
|
||||
_makeOnStep: function({ thread, pauseAndRespond, startFrame,
|
||||
_makeOnStep: function({ pauseAndRespond, startFrame,
|
||||
startLocation, steppingType, completion, rewinding }) {
|
||||
const thread = this;
|
||||
return function() {
|
||||
// onStep is called with 'this' set to the current frame.
|
||||
|
||||
|
@ -828,7 +941,6 @@ const ThreadActor = ActorClassWithSpec(threadSpec, {
|
|||
{ type: "resumeLimit" },
|
||||
onPacket
|
||||
),
|
||||
thread: this,
|
||||
startFrame: this.youngestFrame,
|
||||
startLocation: startLocation,
|
||||
steppingType: steppingType,
|
||||
|
|
|
@ -6,6 +6,401 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
function generalEvent(groupID, eventType) {
|
||||
return {
|
||||
id: `event.${groupID}.${eventType}`,
|
||||
type: "event",
|
||||
name: eventType,
|
||||
message: `DOM '${eventType}' event`,
|
||||
eventType,
|
||||
filter: "general",
|
||||
};
|
||||
}
|
||||
function nodeEvent(groupID, eventType) {
|
||||
return {
|
||||
...generalEvent(groupID, eventType),
|
||||
filter: "node",
|
||||
};
|
||||
}
|
||||
function mediaNodeEvent(groupID, eventType) {
|
||||
return {
|
||||
...generalEvent(groupID, eventType),
|
||||
filter: "media",
|
||||
};
|
||||
}
|
||||
function globalEvent(groupID, eventType) {
|
||||
return {
|
||||
...generalEvent(groupID, eventType),
|
||||
message: `Global '${eventType}' event`,
|
||||
filter: "global",
|
||||
};
|
||||
}
|
||||
function xhrEvent(groupID, eventType) {
|
||||
return {
|
||||
...generalEvent(groupID, eventType),
|
||||
message: `XHR '${eventType}' event`,
|
||||
filter: "xhr",
|
||||
};
|
||||
}
|
||||
function workerEvent(eventType) {
|
||||
return {
|
||||
...generalEvent("worker", eventType),
|
||||
message: `Worker '${eventType}' event`,
|
||||
filter: "worker",
|
||||
};
|
||||
}
|
||||
|
||||
function timerEvent(type, operation, name, notificationType) {
|
||||
return {
|
||||
id: `timer.${type}.${operation}`,
|
||||
type: "simple",
|
||||
name,
|
||||
message: name,
|
||||
notificationType,
|
||||
};
|
||||
}
|
||||
|
||||
function animationEvent(operation, name, notificationType) {
|
||||
return {
|
||||
id: `animationframe.${operation}`,
|
||||
type: "simple",
|
||||
name,
|
||||
message: name,
|
||||
notificationType,
|
||||
};
|
||||
}
|
||||
|
||||
const AVAILABLE_BREAKPOINTS = [
|
||||
{
|
||||
name: "Animation",
|
||||
items: [
|
||||
animationEvent(
|
||||
"request",
|
||||
"Request Animation Frame",
|
||||
"requestAnimationFrame"
|
||||
),
|
||||
animationEvent(
|
||||
"cancel",
|
||||
"Cancel Animation Frame",
|
||||
"cancelAnimationFrame"
|
||||
),
|
||||
animationEvent(
|
||||
"fire",
|
||||
"Animation Frame fired",
|
||||
"requestAnimationFrameCallback"
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Clipboard",
|
||||
items: [
|
||||
generalEvent("clipboard", "copy"),
|
||||
generalEvent("clipboard", "cut"),
|
||||
generalEvent("clipboard", "paste"),
|
||||
generalEvent("clipboard", "beforecopy"),
|
||||
generalEvent("clipboard", "beforecut"),
|
||||
generalEvent("clipboard", "beforepaste"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Control",
|
||||
items: [
|
||||
generalEvent("control", "resize"),
|
||||
generalEvent("control", "scroll"),
|
||||
generalEvent("control", "zoom"),
|
||||
generalEvent("control", "focus"),
|
||||
generalEvent("control", "blur"),
|
||||
generalEvent("control", "select"),
|
||||
generalEvent("control", "change"),
|
||||
generalEvent("control", "submit"),
|
||||
generalEvent("control", "reset"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "DOM Mutation",
|
||||
items: [
|
||||
// Deprecated DOM events.
|
||||
nodeEvent("dom-mutation", "DOMActivate"),
|
||||
nodeEvent("dom-mutation", "DOMFocusIn"),
|
||||
nodeEvent("dom-mutation", "DOMFocusOut"),
|
||||
|
||||
// Standard DOM mutation events.
|
||||
nodeEvent("dom-mutation", "DOMAttrModified"),
|
||||
nodeEvent("dom-mutation", "DOMCharacterDataModified"),
|
||||
nodeEvent("dom-mutation", "DOMNodeInserted"),
|
||||
nodeEvent("dom-mutation", "DOMNodeInsertedIntoDocument"),
|
||||
nodeEvent("dom-mutation", "DOMNodeRemoved"),
|
||||
nodeEvent("dom-mutation", "DOMNodeRemovedIntoDocument"),
|
||||
nodeEvent("dom-mutation", "DOMSubtreeModified"),
|
||||
|
||||
// DOM load events.
|
||||
nodeEvent("dom-mutation", "DOMContentLoaded"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Device",
|
||||
items: [
|
||||
globalEvent("device", "deviceorientation"),
|
||||
globalEvent("device", "devicemotion"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Drag and Drop",
|
||||
items: [
|
||||
generalEvent("drag-and-drop", "drag"),
|
||||
generalEvent("drag-and-drop", "dragstart"),
|
||||
generalEvent("drag-and-drop", "dragend"),
|
||||
generalEvent("drag-and-drop", "dragenter"),
|
||||
generalEvent("drag-and-drop", "dragover"),
|
||||
generalEvent("drag-and-drop", "dragleave"),
|
||||
generalEvent("drag-and-drop", "drop"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Keyboard",
|
||||
items: [
|
||||
generalEvent("keyboard", "keydown"),
|
||||
generalEvent("keyboard", "keyup"),
|
||||
generalEvent("keyboard", "keypress"),
|
||||
generalEvent("keyboard", "input"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Load",
|
||||
items: [
|
||||
globalEvent("load", "load"),
|
||||
globalEvent("load", "beforeunload"),
|
||||
globalEvent("load", "unload"),
|
||||
globalEvent("load", "abort"),
|
||||
globalEvent("load", "error"),
|
||||
globalEvent("load", "hashchange"),
|
||||
globalEvent("load", "popstate"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Media",
|
||||
items: [
|
||||
mediaNodeEvent("media", "play"),
|
||||
mediaNodeEvent("media", "pause"),
|
||||
mediaNodeEvent("media", "playing"),
|
||||
mediaNodeEvent("media", "canplay"),
|
||||
mediaNodeEvent("media", "canplaythrough"),
|
||||
mediaNodeEvent("media", "seeking"),
|
||||
mediaNodeEvent("media", "seeked"),
|
||||
mediaNodeEvent("media", "timeupdate"),
|
||||
mediaNodeEvent("media", "ended"),
|
||||
mediaNodeEvent("media", "ratechange"),
|
||||
mediaNodeEvent("media", "durationchange"),
|
||||
mediaNodeEvent("media", "volumechange"),
|
||||
mediaNodeEvent("media", "loadstart"),
|
||||
mediaNodeEvent("media", "progress"),
|
||||
mediaNodeEvent("media", "suspend"),
|
||||
mediaNodeEvent("media", "abort"),
|
||||
mediaNodeEvent("media", "error"),
|
||||
mediaNodeEvent("media", "emptied"),
|
||||
mediaNodeEvent("media", "stalled"),
|
||||
mediaNodeEvent("media", "loadedmetadata"),
|
||||
mediaNodeEvent("media", "loadeddata"),
|
||||
mediaNodeEvent("media", "waiting"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Mouse",
|
||||
items: [
|
||||
generalEvent("mouse", "auxclick"),
|
||||
generalEvent("mouse", "click"),
|
||||
generalEvent("mouse", "dblclick"),
|
||||
generalEvent("mouse", "mousedown"),
|
||||
generalEvent("mouse", "mouseup"),
|
||||
generalEvent("mouse", "mouseover"),
|
||||
generalEvent("mouse", "mousemove"),
|
||||
generalEvent("mouse", "mouseout"),
|
||||
generalEvent("mouse", "mouseenter"),
|
||||
generalEvent("mouse", "mouseleave"),
|
||||
generalEvent("mouse", "mousewheel"),
|
||||
generalEvent("mouse", "wheel"),
|
||||
generalEvent("mouse", "contextmenu"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Pointer",
|
||||
items: [
|
||||
generalEvent("pointer", "pointerover"),
|
||||
generalEvent("pointer", "pointerout"),
|
||||
generalEvent("pointer", "pointerenter"),
|
||||
generalEvent("pointer", "pointerleave"),
|
||||
generalEvent("pointer", "pointerdown"),
|
||||
generalEvent("pointer", "pointerup"),
|
||||
generalEvent("pointer", "pointermove"),
|
||||
generalEvent("pointer", "pointercancel"),
|
||||
generalEvent("pointer", "gotpointercapture"),
|
||||
generalEvent("pointer", "lostpointercapture"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Timer",
|
||||
items: [
|
||||
timerEvent("timeout", "set", "setTimeout", "setTimeout"),
|
||||
timerEvent("timeout", "clear", "clearTimeout", "clearTimeout"),
|
||||
timerEvent("timeout", "fire", "setTimeout fired", "setTimeoutCallback"),
|
||||
timerEvent("interval", "set", "setInterval", "setInterval"),
|
||||
timerEvent("interval", "clear", "clearInterval", "clearInterval"),
|
||||
timerEvent(
|
||||
"interval",
|
||||
"fire",
|
||||
"setInterval fired",
|
||||
"setIntervalCallback"
|
||||
),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Touch",
|
||||
items: [
|
||||
generalEvent("touch", "touchstart"),
|
||||
generalEvent("touch", "touchmove"),
|
||||
generalEvent("touch", "touchend"),
|
||||
generalEvent("touch", "touchcancel"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Worker",
|
||||
items: [
|
||||
workerEvent("message"),
|
||||
workerEvent("messageerror"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "XHR",
|
||||
items: [
|
||||
xhrEvent("xhr", "readystatechange"),
|
||||
xhrEvent("xhr", "load"),
|
||||
xhrEvent("xhr", "loadstart"),
|
||||
xhrEvent("xhr", "loadend"),
|
||||
xhrEvent("xhr", "abort"),
|
||||
xhrEvent("xhr", "error"),
|
||||
xhrEvent("xhr", "progress"),
|
||||
xhrEvent("xhr", "timeout"),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
const FLAT_EVENTS = [];
|
||||
for (const category of AVAILABLE_BREAKPOINTS) {
|
||||
for (const event of category.items) {
|
||||
FLAT_EVENTS.push(event);
|
||||
}
|
||||
}
|
||||
const EVENTS_BY_ID = {};
|
||||
for (const event of FLAT_EVENTS) {
|
||||
if (EVENTS_BY_ID[event.id]) {
|
||||
throw new Error("Duplicate event ID detected: " + event.id);
|
||||
}
|
||||
EVENTS_BY_ID[event.id] = event;
|
||||
}
|
||||
|
||||
const SIMPLE_EVENTS = {};
|
||||
const DOM_EVENTS = {};
|
||||
for (const eventBP of FLAT_EVENTS) {
|
||||
if (eventBP.type === "simple") {
|
||||
const { notificationType } = eventBP;
|
||||
if (SIMPLE_EVENTS[notificationType]) {
|
||||
throw new Error("Duplicate simple event");
|
||||
}
|
||||
SIMPLE_EVENTS[notificationType] = eventBP.id;
|
||||
} else if (eventBP.type === "event") {
|
||||
const { eventType, filter } = eventBP;
|
||||
|
||||
let targetTypes;
|
||||
if (filter === "global") {
|
||||
targetTypes = ["global"];
|
||||
} else if (filter === "xhr") {
|
||||
targetTypes = ["xhr"];
|
||||
} else if (filter === "worker") {
|
||||
targetTypes = ["worker"];
|
||||
} else if (filter === "general") {
|
||||
targetTypes = ["global", "node"];
|
||||
} else if (filter === "node" || filter === "media") {
|
||||
targetTypes = ["node"];
|
||||
} else {
|
||||
throw new Error("Unexpected filter type");
|
||||
}
|
||||
|
||||
for (const targetType of targetTypes) {
|
||||
let byEventType = DOM_EVENTS[targetType];
|
||||
if (!byEventType) {
|
||||
byEventType = {};
|
||||
DOM_EVENTS[targetType] = byEventType;
|
||||
}
|
||||
|
||||
if (byEventType[eventType]) {
|
||||
throw new Error("Duplicate dom event: " + eventType);
|
||||
}
|
||||
byEventType[eventType] = eventBP.id;
|
||||
}
|
||||
} else {
|
||||
throw new Error("Unknown type: " + eventBP.type);
|
||||
}
|
||||
}
|
||||
|
||||
exports.eventBreakpointForNotification = eventBreakpointForNotification;
|
||||
function eventBreakpointForNotification(dbg, notification) {
|
||||
const notificationType = notification.type;
|
||||
|
||||
if (notification.type === "domEvent") {
|
||||
const domEventNotification = DOM_EVENTS[notification.targetType];
|
||||
if (!domEventNotification) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// The 'event' value is a cross-compartment wrapper for the DOM Event object.
|
||||
// While we could use that directly in the main thread as an Xray wrapper,
|
||||
// when debugging workers we can't, because it is an opaque wrapper.
|
||||
// To make things work, we have to always interact with the Event object via
|
||||
// the Debugger.Object interface.
|
||||
const evt = dbg
|
||||
.makeGlobalObjectReference(notification.global)
|
||||
.makeDebuggeeValue(notification.event);
|
||||
|
||||
const eventType = evt.getProperty("type").return;
|
||||
const id = domEventNotification[eventType];
|
||||
if (!id) {
|
||||
return null;
|
||||
}
|
||||
const eventBreakpoint = EVENTS_BY_ID[id];
|
||||
|
||||
if (eventBreakpoint.filter === "media") {
|
||||
const currentTarget = evt.getProperty("currentTarget").return;
|
||||
if (!currentTarget) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const nodeType = currentTarget.getProperty("nodeType").return;
|
||||
const namespaceURI = currentTarget.getProperty("namespaceURI").return;
|
||||
if (
|
||||
nodeType !== 1 /* ELEMENT_NODE */ ||
|
||||
namespaceURI !== "http://www.w3.org/1999/xhtml"
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const nodeName =
|
||||
currentTarget.getProperty("nodeName").return.toLowerCase();
|
||||
if (nodeName !== "audio" && nodeName !== "video") {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
return SIMPLE_EVENTS[notificationType] || null;
|
||||
}
|
||||
|
||||
exports.makeEventBreakpointMessage = makeEventBreakpointMessage;
|
||||
function makeEventBreakpointMessage(id) {
|
||||
return EVENTS_BY_ID[id].message;
|
||||
}
|
||||
|
||||
exports.getAvailableEventBreakpoints = getAvailableEventBreakpoints;
|
||||
function getAvailableEventBreakpoints() {
|
||||
const available = [];
|
||||
|
@ -14,196 +409,9 @@ function getAvailableEventBreakpoints() {
|
|||
name,
|
||||
events: items.map(item => ({
|
||||
id: item.id,
|
||||
name: item.eventType,
|
||||
name: item.name,
|
||||
})),
|
||||
});
|
||||
}
|
||||
return available;
|
||||
}
|
||||
|
||||
function event(groupID, name, filter = "content") {
|
||||
return {
|
||||
id: `${groupID}.event.${name}`,
|
||||
type: "event",
|
||||
eventType: name,
|
||||
filter,
|
||||
};
|
||||
}
|
||||
|
||||
const AVAILABLE_BREAKPOINTS = [
|
||||
{
|
||||
name: "Clipboard",
|
||||
items: [
|
||||
event("clipboard", "copy"),
|
||||
event("clipboard", "cut"),
|
||||
event("clipboard", "paste"),
|
||||
event("clipboard", "beforecopy"),
|
||||
event("clipboard", "beforecut"),
|
||||
event("clipboard", "beforepaste"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Control",
|
||||
items: [
|
||||
event("control", "resize"),
|
||||
event("control", "scroll"),
|
||||
event("control", "zoom"),
|
||||
event("control", "focus"),
|
||||
event("control", "blur"),
|
||||
event("control", "select"),
|
||||
event("control", "change"),
|
||||
event("control", "submit"),
|
||||
event("control", "reset"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "DOM Mutation",
|
||||
items: [
|
||||
// Deprecated DOM events.
|
||||
event("dom-mutation", "DOMActivate"),
|
||||
event("dom-mutation", "DOMFocusIn"),
|
||||
event("dom-mutation", "DOMFocusOut"),
|
||||
|
||||
// Standard DOM mutation events.
|
||||
event("dom-mutation", "DOMAttrModified"),
|
||||
event("dom-mutation", "DOMCharacterDataModified"),
|
||||
event("dom-mutation", "DOMNodeInserted"),
|
||||
event("dom-mutation", "DOMNodeInsertedIntoDocument"),
|
||||
event("dom-mutation", "DOMNodeRemoved"),
|
||||
event("dom-mutation", "DOMNodeRemovedIntoDocument"),
|
||||
event("dom-mutation", "DOMSubtreeModified"),
|
||||
|
||||
// DOM load events.
|
||||
event("dom-mutation", "DOMContentLoaded"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Device",
|
||||
items: [
|
||||
event("device", "deviceorientation"),
|
||||
event("device", "devicemotion"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Drag and Drop",
|
||||
items: [
|
||||
event("drag-and-drop", "drag"),
|
||||
event("drag-and-drop", "dragstart"),
|
||||
event("drag-and-drop", "dragend"),
|
||||
event("drag-and-drop", "dragenter"),
|
||||
event("drag-and-drop", "dragover"),
|
||||
event("drag-and-drop", "dragleave"),
|
||||
event("drag-and-drop", "drop"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Keyboard",
|
||||
items: [
|
||||
event("keyboard", "keydown"),
|
||||
event("keyboard", "keyup"),
|
||||
event("keyboard", "keypress"),
|
||||
event("keyboard", "input"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Load",
|
||||
items: [
|
||||
event("load", "load", "global"),
|
||||
event("load", "beforeunload", "global"),
|
||||
event("load", "unload", "global"),
|
||||
event("load", "abort", "global"),
|
||||
event("load", "error", "global"),
|
||||
event("load", "hashchange", "global"),
|
||||
event("load", "popstate", "global"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Media",
|
||||
items: [
|
||||
event("media", "play", "media"),
|
||||
event("media", "pause", "media"),
|
||||
event("media", "playing", "media"),
|
||||
event("media", "canplay", "media"),
|
||||
event("media", "canplaythrough", "media"),
|
||||
event("media", "seeking", "media"),
|
||||
event("media", "seeked", "media"),
|
||||
event("media", "timeupdate", "media"),
|
||||
event("media", "ended", "media"),
|
||||
event("media", "ratechange", "media"),
|
||||
event("media", "durationchange", "media"),
|
||||
event("media", "volumechange", "media"),
|
||||
event("media", "loadstart", "media"),
|
||||
event("media", "progress", "media"),
|
||||
event("media", "suspend", "media"),
|
||||
event("media", "abort", "media"),
|
||||
event("media", "error", "media"),
|
||||
event("media", "emptied", "media"),
|
||||
event("media", "stalled", "media"),
|
||||
event("media", "loadedmetadata", "media"),
|
||||
event("media", "loadeddata", "media"),
|
||||
event("media", "waiting", "media"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Mouse",
|
||||
items: [
|
||||
event("mouse", "auxclick"),
|
||||
event("mouse", "click"),
|
||||
event("mouse", "dblclick"),
|
||||
event("mouse", "mousedown"),
|
||||
event("mouse", "mouseup"),
|
||||
event("mouse", "mouseover"),
|
||||
event("mouse", "mousemove"),
|
||||
event("mouse", "mouseout"),
|
||||
event("mouse", "mouseenter"),
|
||||
event("mouse", "mouseleave"),
|
||||
event("mouse", "mousewheel"),
|
||||
event("mouse", "wheel"),
|
||||
event("mouse", "contextmenu"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Pointer",
|
||||
items: [
|
||||
event("pointer", "pointerover"),
|
||||
event("pointer", "pointerout"),
|
||||
event("pointer", "pointerenter"),
|
||||
event("pointer", "pointerleave"),
|
||||
event("pointer", "pointerdown"),
|
||||
event("pointer", "pointerup"),
|
||||
event("pointer", "pointermove"),
|
||||
event("pointer", "pointercancel"),
|
||||
event("pointer", "gotpointercapture"),
|
||||
event("pointer", "lostpointercapture"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Touch",
|
||||
items: [
|
||||
event("touch", "touchstart"),
|
||||
event("touch", "touchmove"),
|
||||
event("touch", "touchend"),
|
||||
event("touch", "touchcancel"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Worker",
|
||||
items: [
|
||||
event("worker", "message", "global"),
|
||||
event("worker", "messageerror", "global"),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "XHR",
|
||||
items: [
|
||||
event("xhr", "readystatechange", "xhr"),
|
||||
event("xhr", "load", "xhr"),
|
||||
event("xhr", "loadstart", "xhr"),
|
||||
event("xhr", "loadend", "xhr"),
|
||||
event("xhr", "abort", "xhr"),
|
||||
event("xhr", "error", "xhr"),
|
||||
event("xhr", "progress", "xhr"),
|
||||
event("xhr", "timeout", "xhr"),
|
||||
],
|
||||
},
|
||||
];
|
||||
|
|
|
@ -64,15 +64,23 @@ module.exports = function makeDebugger({ findDebuggees, shouldAddNewGlobalAsDebu
|
|||
dbg.allowUnobservedAsmJS = true;
|
||||
dbg.uncaughtExceptionHook = reportDebuggerHookException;
|
||||
|
||||
function onNewDebuggee(global) {
|
||||
if (dbg.onNewDebuggee) {
|
||||
dbg.onNewDebuggee(global);
|
||||
}
|
||||
}
|
||||
|
||||
dbg.onNewGlobalObject = function(global) {
|
||||
if (shouldAddNewGlobalAsDebuggee(global)) {
|
||||
safeAddDebuggee(this, global);
|
||||
onNewDebuggee(global);
|
||||
}
|
||||
};
|
||||
|
||||
dbg.addDebuggees = function() {
|
||||
for (const global of findDebuggees(this)) {
|
||||
safeAddDebuggee(this, global);
|
||||
onNewDebuggee(global);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,7 @@ const systemPrincipal = Services.scriptSecurityManager.getSystemPrincipal();
|
|||
// Steal various globals only available in JSM scope (and not Sandbox one)
|
||||
const {
|
||||
console,
|
||||
DebuggerNotificationObserver,
|
||||
DOMPoint,
|
||||
DOMQuad,
|
||||
DOMRect,
|
||||
|
@ -229,6 +230,7 @@ function lazyRequireGetter(obj, property, module, destructure) {
|
|||
// List of pseudo modules exposed to all devtools modules.
|
||||
exports.modules = {
|
||||
ChromeUtils,
|
||||
DebuggerNotificationObserver,
|
||||
HeapSnapshot,
|
||||
promise,
|
||||
// Expose "chrome" Promise, which aren't related to any document
|
||||
|
|
|
@ -44,6 +44,7 @@ const UnsolicitedPauses = {
|
|||
breakpoint: "breakpoint",
|
||||
DOMEvent: "DOMEvent",
|
||||
watchpoint: "watchpoint",
|
||||
eventBreakpoint: "eventBreakpoint",
|
||||
exception: "exception",
|
||||
replayForcedPause: "replayForcedPause",
|
||||
};
|
||||
|
|
|
@ -97,6 +97,7 @@ class WebConsoleFront extends FrontClassWithSpec(webconsoleSpec) {
|
|||
isThirdPartyTrackingResource: actor.isThirdPartyTrackingResource,
|
||||
referrerPolicy: actor.referrerPolicy,
|
||||
blockedReason: actor.blockedReason,
|
||||
channelId: actor.channelId,
|
||||
};
|
||||
this._networkRequests.set(actor.actor, networkInfo);
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
"use strict";
|
||||
|
||||
/* global worker */
|
||||
/* global worker, DebuggerNotificationObserver */
|
||||
|
||||
// A CommonJS module loader that is designed to run inside a worker debugger.
|
||||
// We can't simply use the SDK module loader, because it relies heavily on
|
||||
|
@ -576,6 +576,7 @@ this.worker = new WorkerDebuggerLoader({
|
|||
"chrome": chrome,
|
||||
"xpcInspector": xpcInspector,
|
||||
"ChromeUtils": ChromeUtils,
|
||||
"DebuggerNotificationObserver": DebuggerNotificationObserver,
|
||||
},
|
||||
paths: {
|
||||
// ⚠ DISCUSSION ON DEV-DEVELOPER-TOOLS REQUIRED BEFORE MODIFYING ⚠
|
||||
|
|
|
@ -42,9 +42,9 @@ already_AddRefed<DOMMatrixReadOnly> DOMMatrixReadOnly::Constructor(
|
|||
const GlobalObject& aGlobal,
|
||||
const Optional<StringOrUnrestrictedDoubleSequence>& aArg,
|
||||
ErrorResult& aRv) {
|
||||
RefPtr<DOMMatrixReadOnly> rval =
|
||||
new DOMMatrixReadOnly(aGlobal.GetAsSupports());
|
||||
if (!aArg.WasPassed()) {
|
||||
RefPtr<DOMMatrixReadOnly> rval =
|
||||
new DOMMatrixReadOnly(aGlobal.GetAsSupports());
|
||||
return rval.forget();
|
||||
}
|
||||
|
||||
|
@ -56,12 +56,18 @@ already_AddRefed<DOMMatrixReadOnly> DOMMatrixReadOnly::Constructor(
|
|||
aRv.ThrowTypeError<MSG_ILLEGAL_CONSTRUCTOR>();
|
||||
return nullptr;
|
||||
}
|
||||
RefPtr<DOMMatrixReadOnly> rval =
|
||||
new DOMMatrixReadOnly(aGlobal.GetAsSupports());
|
||||
rval->SetMatrixValue(arg.GetAsString(), aRv);
|
||||
} else {
|
||||
const auto& sequence = arg.GetAsUnrestrictedDoubleSequence();
|
||||
SetDataInMatrix(rval, sequence.Elements(), sequence.Length(), aRv);
|
||||
return rval.forget();
|
||||
}
|
||||
|
||||
const auto& sequence = arg.GetAsUnrestrictedDoubleSequence();
|
||||
const int length = sequence.Length();
|
||||
const bool is2D = length == 6;
|
||||
RefPtr<DOMMatrixReadOnly> rval =
|
||||
new DOMMatrixReadOnly(aGlobal.GetAsSupports(), is2D);
|
||||
SetDataInMatrix(rval, sequence.Elements(), length, aRv);
|
||||
return rval.forget();
|
||||
}
|
||||
|
||||
|
@ -509,9 +515,12 @@ static void SetDataInMatrix(DOMMatrixReadOnly* aMatrix, const T* aData,
|
|||
already_AddRefed<DOMMatrix> DOMMatrix::Constructor(const GlobalObject& aGlobal,
|
||||
const Float32Array& aArray32,
|
||||
ErrorResult& aRv) {
|
||||
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
||||
aArray32.ComputeLengthAndData();
|
||||
SetDataInMatrix(obj, aArray32.Data(), aArray32.Length(), aRv);
|
||||
|
||||
const int length = aArray32.Length();
|
||||
const bool is2D = length == 6;
|
||||
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports(), is2D);
|
||||
SetDataInMatrix(obj, aArray32.Data(), length, aRv);
|
||||
|
||||
return obj.forget();
|
||||
}
|
||||
|
@ -519,9 +528,12 @@ already_AddRefed<DOMMatrix> DOMMatrix::Constructor(const GlobalObject& aGlobal,
|
|||
already_AddRefed<DOMMatrix> DOMMatrix::Constructor(const GlobalObject& aGlobal,
|
||||
const Float64Array& aArray64,
|
||||
ErrorResult& aRv) {
|
||||
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
||||
aArray64.ComputeLengthAndData();
|
||||
SetDataInMatrix(obj, aArray64.Data(), aArray64.Length(), aRv);
|
||||
|
||||
const int length = aArray64.Length();
|
||||
const bool is2D = length == 6;
|
||||
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports(), is2D);
|
||||
SetDataInMatrix(obj, aArray64.Data(), length, aRv);
|
||||
|
||||
return obj.forget();
|
||||
}
|
||||
|
@ -529,9 +541,10 @@ already_AddRefed<DOMMatrix> DOMMatrix::Constructor(const GlobalObject& aGlobal,
|
|||
already_AddRefed<DOMMatrix> DOMMatrix::Constructor(
|
||||
const GlobalObject& aGlobal, const Sequence<double>& aNumberSequence,
|
||||
ErrorResult& aRv) {
|
||||
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports());
|
||||
SetDataInMatrix(obj, aNumberSequence.Elements(), aNumberSequence.Length(),
|
||||
aRv);
|
||||
const int length = aNumberSequence.Length();
|
||||
const bool is2D = length == 6;
|
||||
RefPtr<DOMMatrix> obj = new DOMMatrix(aGlobal.GetAsSupports(), is2D);
|
||||
SetDataInMatrix(obj, aNumberSequence.Elements(), length, aRv);
|
||||
|
||||
return obj.forget();
|
||||
}
|
||||
|
@ -770,7 +783,9 @@ DOMMatrixReadOnly* DOMMatrixReadOnly::SetMatrixValue(
|
|||
|
||||
if (!contains3dTransform) {
|
||||
mMatrix3D = nullptr;
|
||||
mMatrix2D = new gfx::MatrixDouble();
|
||||
if (!mMatrix2D) {
|
||||
mMatrix2D = new gfx::MatrixDouble();
|
||||
}
|
||||
|
||||
SetA(transform._11);
|
||||
SetB(transform._12);
|
||||
|
|
|
@ -2431,7 +2431,7 @@ class MethodDefiner(PropertyDefiner):
|
|||
self.regular.append({
|
||||
"name": "@@iterator",
|
||||
"methodInfo": False,
|
||||
"selfHostedName": "ArrayValues",
|
||||
"selfHostedName": "$ArrayValues",
|
||||
"length": 0,
|
||||
"flags": "0", # Not enumerable, per spec.
|
||||
"condition": MemberCondition()
|
||||
|
@ -2457,7 +2457,7 @@ class MethodDefiner(PropertyDefiner):
|
|||
self.regular.append({
|
||||
"name": "values",
|
||||
"methodInfo": False,
|
||||
"selfHostedName": "ArrayValues",
|
||||
"selfHostedName": "$ArrayValues",
|
||||
"length": 0,
|
||||
"flags": "JSPROP_ENUMERATE",
|
||||
"condition": PropertyDefiner.getControllingCondition(m,
|
||||
|
|
|
@ -70,6 +70,9 @@ Gamepad::Gamepad(nsISupports* aParent, const nsAString& aID, uint32_t aIndex,
|
|||
mTouchEvents.AppendElement(new GamepadTouch(mParent));
|
||||
}
|
||||
|
||||
// Mapping touchId(0) to touchIdHash(0) by default.
|
||||
mTouchIdHash.Put(0, mTouchIdHashValue);
|
||||
++mTouchIdHashValue;
|
||||
UpdateTimestamp();
|
||||
}
|
||||
|
||||
|
|
|
@ -361,6 +361,11 @@ class StadiaControllerRemapper final : public GamepadRemapper {
|
|||
|
||||
class Dualshock4Remapper final : public GamepadRemapper {
|
||||
public:
|
||||
Dualshock4Remapper() {
|
||||
mLastTouches.SetLength(TOUCH_EVENT_COUNT);
|
||||
mLastTouchId.SetLength(TOUCH_EVENT_COUNT);
|
||||
}
|
||||
|
||||
virtual uint32_t GetAxisCount() const override { return AXIS_INDEX_COUNT; }
|
||||
|
||||
virtual uint32_t GetButtonCount() const override {
|
||||
|
@ -403,45 +408,43 @@ class Dualshock4Remapper final : public GamepadRemapper {
|
|||
touches.SetLength(TOUCH_EVENT_COUNT);
|
||||
uint8_t* rawData = (uint8_t*)aInput;
|
||||
|
||||
const uint32_t kTouchDimensionX = 1920;
|
||||
const uint32_t kTouchDimensionY = 942;
|
||||
bool touch0Pressed = (((rawData[35] & 0xff) >> 7) == 0);
|
||||
bool touch1Pressed = (((rawData[39] & 0xff) >> 7) == 0);
|
||||
|
||||
if (!touch0Pressed && !touch1Pressed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((touch0Pressed && (rawData[35] & 0xff) < mLastTouch0Id) ||
|
||||
(touch1Pressed && (rawData[39] & 0xff) < mLastTouch1Id)) {
|
||||
if ((touch0Pressed && (rawData[35] & 0xff) < mLastTouchId[0]) ||
|
||||
(touch1Pressed && (rawData[39] & 0xff) < mLastTouchId[1])) {
|
||||
mTouchIdBase += 128;
|
||||
}
|
||||
|
||||
const uint32_t kTouchDimensionX = 1920;
|
||||
const uint32_t kTouchDimensionY = 942;
|
||||
|
||||
touches[0].touchId = mTouchIdBase + (rawData[35] & 0x7f);
|
||||
touches[0].surfaceId = 0;
|
||||
touches[0].position[0] = NormalizeTouch(
|
||||
((rawData[37] & 0xf) << 8) | rawData[36], 0, (kTouchDimensionX - 1));
|
||||
touches[0].position[1] =
|
||||
NormalizeTouch(rawData[38] << 4 | ((rawData[37] & 0xf0) >> 4), 0,
|
||||
(kTouchDimensionY - 1));
|
||||
touches[0].surfaceDimensions[0] = kTouchDimensionX;
|
||||
touches[0].surfaceDimensions[1] = kTouchDimensionY;
|
||||
touches[0].isSurfaceDimensionsValid = true;
|
||||
mLastTouch0Id = rawData[35] & 0x7f;
|
||||
|
||||
touches[1].touchId = mTouchIdBase + (rawData[39] & 0x7f);
|
||||
touches[1].surfaceId = 0;
|
||||
touches[1].position[0] =
|
||||
NormalizeTouch((((rawData[41] & 0xf) << 8) | rawData[40]) + 1, 0,
|
||||
(kTouchDimensionX - 1));
|
||||
touches[1].position[1] =
|
||||
NormalizeTouch(rawData[42] << 4 | ((rawData[41] & 0xf0) >> 4), 0,
|
||||
(kTouchDimensionY - 1));
|
||||
touches[1].surfaceDimensions[0] = kTouchDimensionX;
|
||||
touches[1].surfaceDimensions[1] = kTouchDimensionY;
|
||||
touches[1].isSurfaceDimensionsValid = true;
|
||||
mLastTouch1Id = rawData[39] & 0x7f;
|
||||
if (touch0Pressed) {
|
||||
touches[0].touchId = mTouchIdBase + (rawData[35] & 0x7f);
|
||||
touches[0].surfaceId = 0;
|
||||
touches[0].position[0] = NormalizeTouch(
|
||||
((rawData[37] & 0xf) << 8) | rawData[36], 0, (kTouchDimensionX - 1));
|
||||
touches[0].position[1] =
|
||||
NormalizeTouch(rawData[38] << 4 | ((rawData[37] & 0xf0) >> 4), 0,
|
||||
(kTouchDimensionY - 1));
|
||||
touches[0].surfaceDimensions[0] = kTouchDimensionX;
|
||||
touches[0].surfaceDimensions[1] = kTouchDimensionY;
|
||||
touches[0].isSurfaceDimensionsValid = true;
|
||||
mLastTouchId[0] = rawData[35] & 0x7f;
|
||||
}
|
||||
if (touch1Pressed) {
|
||||
touches[1].touchId = mTouchIdBase + (rawData[39] & 0x7f);
|
||||
touches[1].surfaceId = 0;
|
||||
touches[1].position[0] =
|
||||
NormalizeTouch((((rawData[41] & 0xf) << 8) | rawData[40]) + 1, 0,
|
||||
(kTouchDimensionX - 1));
|
||||
touches[1].position[1] =
|
||||
NormalizeTouch(rawData[42] << 4 | ((rawData[41] & 0xf0) >> 4), 0,
|
||||
(kTouchDimensionY - 1));
|
||||
touches[1].surfaceDimensions[0] = kTouchDimensionX;
|
||||
touches[1].surfaceDimensions[1] = kTouchDimensionY;
|
||||
touches[1].isSurfaceDimensionsValid = true;
|
||||
mLastTouchId[1] = rawData[39] & 0x7f;
|
||||
}
|
||||
|
||||
RefPtr<GamepadPlatformService> service =
|
||||
GamepadPlatformService::GetParentService();
|
||||
|
@ -449,8 +452,15 @@ class Dualshock4Remapper final : public GamepadRemapper {
|
|||
return;
|
||||
}
|
||||
|
||||
service->NewMultiTouchEvent(aIndex, 0, touches[0]);
|
||||
service->NewMultiTouchEvent(aIndex, 1, touches[1]);
|
||||
// Avoid to send duplicate untouched events to the gamepad service.
|
||||
if ((mLastTouches[0] != touch0Pressed) || touch0Pressed) {
|
||||
service->NewMultiTouchEvent(aIndex, 0, touches[0]);
|
||||
}
|
||||
if ((mLastTouches[1] != touch1Pressed) || touch1Pressed) {
|
||||
service->NewMultiTouchEvent(aIndex, 1, touches[1]);
|
||||
}
|
||||
mLastTouches[0] = touch0Pressed;
|
||||
mLastTouches[1] = touch1Pressed;
|
||||
}
|
||||
|
||||
virtual void RemapAxisMoveEvent(uint32_t aIndex, uint32_t aAxis,
|
||||
|
@ -537,8 +547,8 @@ class Dualshock4Remapper final : public GamepadRemapper {
|
|||
static const uint32_t LIGHT_INDICATOR_COUNT = 1;
|
||||
static const uint32_t TOUCH_EVENT_COUNT = 2;
|
||||
|
||||
unsigned long mLastTouch0Id = 0;
|
||||
unsigned long mLastTouch1Id = 0;
|
||||
nsTArray<unsigned long> mLastTouchId;
|
||||
nsTArray<bool> mLastTouches;
|
||||
unsigned long mTouchIdBase = 0;
|
||||
};
|
||||
|
||||
|
|
|
@ -4061,10 +4061,6 @@ nsresult HTMLMediaElement::BindToTree(BindContext& aContext, nsINode& aParent) {
|
|||
NotifyUAWidgetSetupOrChange();
|
||||
}
|
||||
|
||||
// FIXME(emilio, bug 1555946): mUnboundFromTree doesn't make any sense, should
|
||||
// just use IsInComposedDoc() in the relevant places or something.
|
||||
mUnboundFromTree = false;
|
||||
|
||||
if (IsInUncomposedDoc()) {
|
||||
// The preload action depends on the value of the autoplay attribute.
|
||||
// It's value may have changed, so update it.
|
||||
|
@ -4278,7 +4274,6 @@ void HTMLMediaElement::ReportTelemetry() {
|
|||
}
|
||||
|
||||
void HTMLMediaElement::UnbindFromTree(bool aNullParent) {
|
||||
mUnboundFromTree = true;
|
||||
mVisibilityState = Visibility::Untracked;
|
||||
|
||||
if (IsInComposedDoc()) {
|
||||
|
@ -4290,14 +4285,21 @@ void HTMLMediaElement::UnbindFromTree(bool aNullParent) {
|
|||
MOZ_ASSERT(IsHidden());
|
||||
NotifyDecoderActivityChanges();
|
||||
|
||||
RefPtr<HTMLMediaElement> self(this);
|
||||
nsCOMPtr<nsIRunnable> task =
|
||||
NS_NewRunnableFunction("dom::HTMLMediaElement::UnbindFromTree", [self]() {
|
||||
if (self->mUnboundFromTree) {
|
||||
self->Pause();
|
||||
}
|
||||
});
|
||||
RunInStableState(task);
|
||||
// Dispatch a task to run once we're in a stable state which ensures we're
|
||||
// paused if we're no longer in a document. Note we set a flag here to
|
||||
// ensure we don't dispatch redundant tasks.
|
||||
if (!mDispatchedTaskToPauseIfNotInDocument) {
|
||||
mDispatchedTaskToPauseIfNotInDocument = true;
|
||||
nsCOMPtr<nsIRunnable> task = NS_NewRunnableFunction(
|
||||
"dom::HTMLMediaElement::UnbindFromTree",
|
||||
[self = RefPtr<HTMLMediaElement>(this)]() {
|
||||
self->mDispatchedTaskToPauseIfNotInDocument = false;
|
||||
if (!self->IsInComposedDoc()) {
|
||||
self->Pause();
|
||||
}
|
||||
});
|
||||
RunInStableState(task);
|
||||
}
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -5696,7 +5698,7 @@ bool HTMLMediaElement::IsActive() const {
|
|||
}
|
||||
|
||||
bool HTMLMediaElement::IsHidden() const {
|
||||
return mUnboundFromTree || OwnerDoc()->Hidden();
|
||||
return !IsInComposedDoc() || OwnerDoc()->Hidden();
|
||||
}
|
||||
|
||||
VideoFrameContainer* HTMLMediaElement::GetVideoFrameContainer() {
|
||||
|
|
|
@ -1671,10 +1671,11 @@ class HTMLMediaElement : public nsGenericHTMLElement,
|
|||
// MediaStream.
|
||||
nsCOMPtr<nsIPrincipal> mSrcStreamVideoPrincipal;
|
||||
|
||||
// True if UnbindFromTree() is called on the element.
|
||||
// Note this flag is false when the element is in a phase after creation and
|
||||
// before attaching to the DOM tree.
|
||||
bool mUnboundFromTree = false;
|
||||
// True if we've dispatched a task in UnbindFromTree() which runs in a
|
||||
// stable state and attempts to pause playback if we're not in a composed
|
||||
// document. The flag stops us dispatching multiple tasks if the element
|
||||
// is involved in a series of append/remove cycles.
|
||||
bool mDispatchedTaskToPauseIfNotInDocument = false;
|
||||
|
||||
// True if the autoplay media was blocked because it hadn't loaded metadata
|
||||
// yet.
|
||||
|
|
|
@ -386,13 +386,13 @@ void HTMLVideoElement::ReleaseVideoWakeLockIfExists() {
|
|||
bool HTMLVideoElement::SetVisualCloneTarget(
|
||||
HTMLVideoElement* aVisualCloneTarget) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
!aVisualCloneTarget || !aVisualCloneTarget->mUnboundFromTree,
|
||||
!aVisualCloneTarget || aVisualCloneTarget->IsInComposedDoc(),
|
||||
"Can't set the clone target to a disconnected video "
|
||||
"element.");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mVisualCloneSource,
|
||||
"Can't clone a video element that is already a clone.");
|
||||
if (!aVisualCloneTarget ||
|
||||
(!aVisualCloneTarget->mUnboundFromTree && !mVisualCloneSource)) {
|
||||
(aVisualCloneTarget->IsInComposedDoc() && !mVisualCloneSource)) {
|
||||
mVisualCloneTarget = aVisualCloneTarget;
|
||||
return true;
|
||||
}
|
||||
|
@ -402,14 +402,14 @@ bool HTMLVideoElement::SetVisualCloneTarget(
|
|||
bool HTMLVideoElement::SetVisualCloneSource(
|
||||
HTMLVideoElement* aVisualCloneSource) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(
|
||||
!aVisualCloneSource || !aVisualCloneSource->mUnboundFromTree,
|
||||
!aVisualCloneSource || aVisualCloneSource->IsInComposedDoc(),
|
||||
"Can't set the clone source to a disconnected video "
|
||||
"element.");
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mVisualCloneTarget,
|
||||
"Can't clone a video element that is already a "
|
||||
"clone.");
|
||||
if (!aVisualCloneSource ||
|
||||
(!aVisualCloneSource->mUnboundFromTree && !mVisualCloneTarget)) {
|
||||
(aVisualCloneSource->IsInComposedDoc() && !mVisualCloneTarget)) {
|
||||
mVisualCloneSource = aVisualCloneSource;
|
||||
return true;
|
||||
}
|
||||
|
@ -452,11 +452,11 @@ double HTMLVideoElement::TotalPlayTime() const {
|
|||
|
||||
void HTMLVideoElement::CloneElementVisually(HTMLVideoElement& aTargetVideo,
|
||||
ErrorResult& rv) {
|
||||
MOZ_ASSERT(!mUnboundFromTree,
|
||||
MOZ_ASSERT(IsInComposedDoc(),
|
||||
"Can't clone a video that's not bound to a DOM tree.");
|
||||
MOZ_ASSERT(!aTargetVideo.mUnboundFromTree,
|
||||
MOZ_ASSERT(aTargetVideo.IsInComposedDoc(),
|
||||
"Can't clone to a video that's not bound to a DOM tree.");
|
||||
if (mUnboundFromTree || aTargetVideo.mUnboundFromTree) {
|
||||
if (!IsInComposedDoc() || !aTargetVideo.IsInComposedDoc()) {
|
||||
rv.Throw(NS_ERROR_UNEXPECTED);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -3332,14 +3332,16 @@ ScreenIntSize BrowserChild::GetInnerSize() {
|
|||
innerSize, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
|
||||
};
|
||||
|
||||
nsRect BrowserChild::GetVisibleRect() {
|
||||
LayoutDeviceIntRect BrowserChild::GetVisibleRect() {
|
||||
CSSRect visibleRect;
|
||||
if (mIsTopLevel) {
|
||||
// We are conservative about visible rects for top-level browsers to avoid
|
||||
// artifacts when resizing
|
||||
return nsRect(nsPoint(), CSSPixel::ToAppUnits(mUnscaledInnerSize));
|
||||
visibleRect = CSSRect(CSSPoint(), mUnscaledInnerSize);
|
||||
} else {
|
||||
return mEffectsInfo.mVisibleRect;
|
||||
visibleRect = CSSPixel::FromAppUnits(mEffectsInfo.mVisibleRect);
|
||||
}
|
||||
return RoundedToInt(visibleRect * mPuppetWidget->GetDefaultScale());
|
||||
}
|
||||
|
||||
ScreenIntRect BrowserChild::GetOuterRect() {
|
||||
|
|
|
@ -549,7 +549,7 @@ class BrowserChild final : public nsMessageManagerScriptExecutor,
|
|||
|
||||
ScreenIntSize GetInnerSize();
|
||||
|
||||
nsRect GetVisibleRect();
|
||||
LayoutDeviceIntRect GetVisibleRect();
|
||||
|
||||
// Call RecvShow(nsIntSize(0, 0)) and block future calls to RecvShow().
|
||||
void DoFakeShow(const ShowInfo& aShowInfo);
|
||||
|
|
|
@ -14,7 +14,8 @@ namespace mozilla {
|
|||
namespace dom {
|
||||
|
||||
MediaElementAudioSourceNode::MediaElementAudioSourceNode(AudioContext* aContext)
|
||||
: MediaStreamAudioSourceNode(aContext) {}
|
||||
: MediaStreamAudioSourceNode(aContext, TrackChangeBehavior::FollowChanges) {
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<MediaElementAudioSourceNode>
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/CORSMode.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsID.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
@ -37,9 +38,11 @@ NS_INTERFACE_MAP_END_INHERITING(AudioNode)
|
|||
NS_IMPL_ADDREF_INHERITED(MediaStreamAudioSourceNode, AudioNode)
|
||||
NS_IMPL_RELEASE_INHERITED(MediaStreamAudioSourceNode, AudioNode)
|
||||
|
||||
MediaStreamAudioSourceNode::MediaStreamAudioSourceNode(AudioContext* aContext)
|
||||
MediaStreamAudioSourceNode::MediaStreamAudioSourceNode(
|
||||
AudioContext* aContext, TrackChangeBehavior aBehavior)
|
||||
: AudioNode(aContext, 2, ChannelCountMode::Max,
|
||||
ChannelInterpretation::Speakers) {}
|
||||
ChannelInterpretation::Speakers),
|
||||
mBehavior(aBehavior) {}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<MediaStreamAudioSourceNode> MediaStreamAudioSourceNode::Create(
|
||||
|
@ -63,7 +66,7 @@ already_AddRefed<MediaStreamAudioSourceNode> MediaStreamAudioSourceNode::Create(
|
|||
}
|
||||
|
||||
RefPtr<MediaStreamAudioSourceNode> node =
|
||||
new MediaStreamAudioSourceNode(&aAudioContext);
|
||||
new MediaStreamAudioSourceNode(&aAudioContext, LockOnTrackPicked);
|
||||
|
||||
node->Init(aOptions.mMediaStream, aRv);
|
||||
if (aRv.Failed()) {
|
||||
|
@ -96,7 +99,7 @@ void MediaStreamAudioSourceNode::Init(DOMMediaStream* aMediaStream,
|
|||
if (mInputStream->Active()) {
|
||||
NotifyActive();
|
||||
}
|
||||
AttachToFirstTrack(mInputStream);
|
||||
AttachToRightTrack(mInputStream, aRv);
|
||||
}
|
||||
|
||||
void MediaStreamAudioSourceNode::Destroy() {
|
||||
|
@ -137,14 +140,35 @@ void MediaStreamAudioSourceNode::DetachFromTrack() {
|
|||
}
|
||||
}
|
||||
|
||||
void MediaStreamAudioSourceNode::AttachToFirstTrack(
|
||||
const RefPtr<DOMMediaStream>& aMediaStream) {
|
||||
static int AudioTrackCompare(const RefPtr<AudioStreamTrack>& aLhs,
|
||||
const RefPtr<AudioStreamTrack>& aRhs) {
|
||||
nsAutoStringN<NSID_LENGTH> IDLhs;
|
||||
nsAutoStringN<NSID_LENGTH> IDRhs;
|
||||
aLhs->GetId(IDLhs);
|
||||
aRhs->GetId(IDRhs);
|
||||
return NS_ConvertUTF16toUTF8(IDLhs).Compare(
|
||||
NS_ConvertUTF16toUTF8(IDRhs).get());
|
||||
}
|
||||
|
||||
void MediaStreamAudioSourceNode::AttachToRightTrack(
|
||||
const RefPtr<DOMMediaStream>& aMediaStream, ErrorResult& aRv) {
|
||||
nsTArray<RefPtr<AudioStreamTrack>> tracks;
|
||||
aMediaStream->GetAudioTracks(tracks);
|
||||
|
||||
if (tracks.IsEmpty() && mBehavior == LockOnTrackPicked) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sort the track to have a stable order, on their ID by lexicographic
|
||||
// ordering on sequences of code unit values.
|
||||
tracks.Sort(AudioTrackCompare);
|
||||
|
||||
for (const RefPtr<AudioStreamTrack>& track : tracks) {
|
||||
if (track->Ended()) {
|
||||
continue;
|
||||
if (mBehavior == FollowChanges) {
|
||||
if (track->Ended()) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
AttachToTrack(track);
|
||||
|
@ -158,6 +182,9 @@ void MediaStreamAudioSourceNode::AttachToFirstTrack(
|
|||
|
||||
void MediaStreamAudioSourceNode::NotifyTrackAdded(
|
||||
const RefPtr<MediaStreamTrack>& aTrack) {
|
||||
if (mBehavior != FollowChanges) {
|
||||
return;
|
||||
}
|
||||
if (mInputTrack) {
|
||||
return;
|
||||
}
|
||||
|
@ -171,12 +198,14 @@ void MediaStreamAudioSourceNode::NotifyTrackAdded(
|
|||
|
||||
void MediaStreamAudioSourceNode::NotifyTrackRemoved(
|
||||
const RefPtr<MediaStreamTrack>& aTrack) {
|
||||
if (aTrack != mInputTrack) {
|
||||
return;
|
||||
}
|
||||
if (mBehavior == FollowChanges) {
|
||||
if (aTrack != mInputTrack) {
|
||||
return;
|
||||
}
|
||||
|
||||
DetachFromTrack();
|
||||
AttachToFirstTrack(mInputStream);
|
||||
DetachFromTrack();
|
||||
AttachToRightTrack(mInputStream, IgnoreErrors());
|
||||
}
|
||||
}
|
||||
|
||||
void MediaStreamAudioSourceNode::NotifyActive() {
|
||||
|
|
|
@ -80,8 +80,10 @@ class MediaStreamAudioSourceNode
|
|||
// Detaches from the currently attached track if there is one.
|
||||
void DetachFromTrack();
|
||||
|
||||
// Attaches to the first available audio track in aMediaStream.
|
||||
void AttachToFirstTrack(const RefPtr<DOMMediaStream>& aMediaStream);
|
||||
// Attaches to the first audio track in the MediaStream, when the tracks are
|
||||
// ordered by id.
|
||||
void AttachToRightTrack(const RefPtr<DOMMediaStream>& aMediaStream,
|
||||
ErrorResult& aRv);
|
||||
|
||||
// From DOMMediaStream::TrackListener.
|
||||
void NotifyTrackAdded(const RefPtr<MediaStreamTrack>& aTrack) override;
|
||||
|
@ -91,13 +93,27 @@ class MediaStreamAudioSourceNode
|
|||
// From PrincipalChangeObserver<MediaStreamTrack>.
|
||||
void PrincipalChanged(MediaStreamTrack* aMediaStreamTrack) override;
|
||||
|
||||
// This allows implementing the correct behaviour for both
|
||||
// MediaElementAudioSourceNode and MediaStreamAudioSourceNode, that have most
|
||||
// of their behaviour shared.
|
||||
enum TrackChangeBehavior {
|
||||
// MediaStreamAudioSourceNode locks on the track it picked, and never
|
||||
// changes.
|
||||
LockOnTrackPicked,
|
||||
// MediaElementAudioSourceNode can change track, depending on what the
|
||||
// HTMLMediaElement does.
|
||||
FollowChanges
|
||||
};
|
||||
|
||||
protected:
|
||||
explicit MediaStreamAudioSourceNode(AudioContext* aContext);
|
||||
MediaStreamAudioSourceNode(AudioContext* aContext,
|
||||
TrackChangeBehavior aBehavior);
|
||||
void Init(DOMMediaStream* aMediaStream, ErrorResult& aRv);
|
||||
virtual void Destroy();
|
||||
virtual ~MediaStreamAudioSourceNode();
|
||||
|
||||
private:
|
||||
const TrackChangeBehavior mBehavior;
|
||||
RefPtr<MediaInputPort> mInputPort;
|
||||
RefPtr<DOMMediaStream> mInputStream;
|
||||
|
||||
|
|
|
@ -104,7 +104,6 @@ tags=capturestream
|
|||
[test_bug1118372.html]
|
||||
[test_bug1027864.html]
|
||||
[test_bug1056032.html]
|
||||
skip-if = toolkit == 'android' # bug 1056706
|
||||
[test_bug1255618.html]
|
||||
skip-if = (os == "win" && processor == "aarch64") # aarch64 due to 1538360
|
||||
[test_bug1267579.html]
|
||||
|
@ -140,7 +139,6 @@ skip-if = !asan && toolkit != android
|
|||
[test_delayNode.html]
|
||||
[test_delayNodeAtMax.html]
|
||||
[test_delayNodeChannelChanges.html]
|
||||
skip-if = toolkit == 'android' # bug 1056706
|
||||
[test_delayNodeCycles.html]
|
||||
[test_delayNodePassThrough.html]
|
||||
[test_delayNodeSmallMaxDelay.html]
|
||||
|
|
|
@ -33,7 +33,7 @@ function tryToCreateNodeOnClosedContext(ctx) {
|
|||
args: [new Audio()],
|
||||
onOfflineAudioContext: false },
|
||||
{ name: "createMediaStreamSource",
|
||||
args: [new Audio().mozCaptureStream()],
|
||||
args: [(new AudioContext()).createMediaStreamDestination().stream],
|
||||
onOfflineAudioContext: false } ].forEach(function(e) {
|
||||
|
||||
if (e.onOfflineAudioContext == false &&
|
||||
|
@ -74,7 +74,6 @@ function tryLegalOpeerationsOnClosedContext(ctx) {
|
|||
loadFile("ting-44.1k-1ch.ogg", function(buf) {
|
||||
ctx.decodeAudioData(buf).then(function(decodedBuf) {
|
||||
ok(true, "decodeAudioData on a closed context should work, it did.")
|
||||
todo(false, "0 " + (ctx instanceof OfflineAudioContext ? "Offline" : "Realtime"));
|
||||
finish();
|
||||
}).catch(function(e){
|
||||
ok(false, "decodeAudioData on a closed context should work, it did not");
|
||||
|
@ -121,8 +120,6 @@ function testMultiContextOutput() {
|
|||
}
|
||||
}
|
||||
|
||||
todo(false, "input buffer is " + (silent ? "silent" : "noisy"));
|
||||
|
||||
if (silent) {
|
||||
silentBuffersInARow++;
|
||||
if (silentBuffersInARow == 10) {
|
||||
|
@ -131,7 +128,6 @@ function testMultiContextOutput() {
|
|||
sp2.onaudioprocess = null;
|
||||
ac1.close();
|
||||
ac2.close();
|
||||
todo(false,"1");
|
||||
finish();
|
||||
}
|
||||
} else {
|
||||
|
@ -182,7 +178,6 @@ function testMultiContextInput() {
|
|||
ac2.close();
|
||||
sp1.onaudioprocess = null;
|
||||
sp2.onaudioprocess = null;
|
||||
todo(false, "2");
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
@ -231,7 +226,6 @@ function testScriptProcessNodeSuspended() {
|
|||
}
|
||||
} else {
|
||||
sp.onaudioprocess = null;
|
||||
todo(false,"3");
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,45 +12,48 @@
|
|||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var audio = new Audio("http://example.org:80/tests/dom/media/webaudio/test/small-shot.ogg");
|
||||
audio.load();
|
||||
var context = new AudioContext();
|
||||
var node = context.createMediaStreamSource(audio.mozCaptureStreamUntilEnded());
|
||||
var sp = context.createScriptProcessor(2048, 1);
|
||||
node.connect(sp);
|
||||
var nonzeroSampleCount = 0;
|
||||
var complete = false;
|
||||
var iterationCount = 0;
|
||||
audio.onloadedmetadata = function() {
|
||||
var node = context.createMediaStreamSource(audio.mozCaptureStreamUntilEnded());
|
||||
var sp = context.createScriptProcessor(2048, 1);
|
||||
node.connect(sp);
|
||||
var nonzeroSampleCount = 0;
|
||||
var complete = false;
|
||||
var iterationCount = 0;
|
||||
|
||||
// This test ensures we receive at least expectedSampleCount nonzero samples
|
||||
function processSamples(e) {
|
||||
if (complete) {
|
||||
return;
|
||||
}
|
||||
// This test ensures we receive at least expectedSampleCount nonzero samples
|
||||
function processSamples(e) {
|
||||
if (complete) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (iterationCount == 0) {
|
||||
// Don't start playing the audio until the AudioContext stuff is connected
|
||||
// and running.
|
||||
audio.play();
|
||||
}
|
||||
++iterationCount;
|
||||
if (iterationCount == 0) {
|
||||
// Don't start playing the audio until the AudioContext stuff is connected
|
||||
// and running.
|
||||
audio.play();
|
||||
}
|
||||
++iterationCount;
|
||||
|
||||
var buf = e.inputBuffer.getChannelData(0);
|
||||
var nonzeroSamplesThisBuffer = 0;
|
||||
for (var i = 0; i < buf.length; ++i) {
|
||||
if (buf[i] != 0) {
|
||||
++nonzeroSamplesThisBuffer;
|
||||
var buf = e.inputBuffer.getChannelData(0);
|
||||
var nonzeroSamplesThisBuffer = 0;
|
||||
for (var i = 0; i < buf.length; ++i) {
|
||||
if (buf[i] != 0) {
|
||||
++nonzeroSamplesThisBuffer;
|
||||
}
|
||||
}
|
||||
is(nonzeroSamplesThisBuffer, 0,
|
||||
"Checking all samples are zero");
|
||||
if (iterationCount >= 20) {
|
||||
SimpleTest.finish();
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
is(nonzeroSamplesThisBuffer, 0,
|
||||
"Checking all samples are zero");
|
||||
if (iterationCount >= 20) {
|
||||
SimpleTest.finish();
|
||||
complete = true;
|
||||
}
|
||||
}
|
||||
|
||||
audio.oncanplaythrough = function() {
|
||||
sp.onaudioprocess = processSamples;
|
||||
};
|
||||
audio.oncanplaythrough = function() {
|
||||
sp.onaudioprocess = processSamples;
|
||||
};
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "SVGEllipseElement.h"
|
||||
#include "SVGGeometryProperty.h"
|
||||
#include "SVGRectElement.h"
|
||||
#include "mozilla/dom/DOMPointBinding.h"
|
||||
#include "mozilla/dom/SVGLengthBinding.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
|
@ -114,6 +115,18 @@ already_AddRefed<Path> SVGGeometryElement::GetOrBuildPathForMeasuring() {
|
|||
return GetOrBuildPath(drawTarget, fillRule);
|
||||
}
|
||||
|
||||
// This helper is currently identical to GetOrBuildPathForMeasuring.
|
||||
// We keep it a separate method because for length measuring purpose,
|
||||
// fillRule isn't really needed. Derived class (e.g. SVGPathElement)
|
||||
// may override GetOrBuildPathForMeasuring() to ignore fillRule. And
|
||||
// GetOrBuildPathForMeasuring() itself may be modified in the future.
|
||||
already_AddRefed<Path> SVGGeometryElement::GetOrBuildPathForHitTest() {
|
||||
RefPtr<DrawTarget> drawTarget =
|
||||
gfxPlatform::GetPlatform()->ScreenReferenceDrawTarget();
|
||||
FillRule fillRule = mCachedPath ? mCachedPath->GetFillRule() : GetFillRule();
|
||||
return GetOrBuildPath(drawTarget, fillRule);
|
||||
}
|
||||
|
||||
bool SVGGeometryElement::IsGeometryChangedViaCSS(
|
||||
ComputedStyle const& aNewStyle, ComputedStyle const& aOldStyle) const {
|
||||
if (IsSVGElement(nsGkAtoms::rect)) {
|
||||
|
@ -153,6 +166,54 @@ FillRule SVGGeometryElement::GetFillRule() {
|
|||
return fillRule;
|
||||
}
|
||||
|
||||
static Point GetPointFrom(const DOMPointInit& aPoint) {
|
||||
return Point(aPoint.mX, aPoint.mY);
|
||||
}
|
||||
|
||||
bool SVGGeometryElement::IsPointInFill(const DOMPointInit& aPoint) {
|
||||
auto point = GetPointFrom(aPoint);
|
||||
|
||||
RefPtr<Path> path = GetOrBuildPathForHitTest();
|
||||
if (!path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return path->ContainsPoint(point, {});
|
||||
}
|
||||
|
||||
bool SVGGeometryElement::IsPointInStroke(const DOMPointInit& aPoint) {
|
||||
auto point = GetPointFrom(aPoint);
|
||||
|
||||
RefPtr<Path> path = GetOrBuildPathForHitTest();
|
||||
if (!path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool res = false;
|
||||
SVGGeometryProperty::DoForComputedStyle(this, [&](const ComputedStyle* s) {
|
||||
// Per spec, we should take vector-effect into account.
|
||||
if (s->StyleSVGReset()->HasNonScalingStroke()) {
|
||||
auto mat = SVGContentUtils::GetCTM(this, true);
|
||||
if (mat.HasNonTranslation()) {
|
||||
// We have non-scaling-stroke as well as a non-translation transform.
|
||||
// We should transform the path first then apply the stroke on the
|
||||
// transformed path to preserve the stroke-width.
|
||||
RefPtr<PathBuilder> builder = path->TransformedCopyToBuilder(mat);
|
||||
|
||||
path = builder->Finish();
|
||||
point = mat.TransformPoint(point);
|
||||
}
|
||||
}
|
||||
|
||||
SVGContentUtils::AutoStrokeOptions strokeOptions;
|
||||
SVGContentUtils::GetStrokeOptions(&strokeOptions, this, s, nullptr);
|
||||
|
||||
res = path->StrokeContainsPoint(strokeOptions, point, {});
|
||||
});
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
float SVGGeometryElement::GetTotalLength() {
|
||||
RefPtr<Path> flat = GetOrBuildPathForMeasuring();
|
||||
return flat ? flat->ComputeLength() : 0.f;
|
||||
|
|
|
@ -216,6 +216,8 @@ class SVGGeometryElement : public SVGGeometryElementBase {
|
|||
|
||||
// WebIDL
|
||||
already_AddRefed<DOMSVGAnimatedNumber> PathLength();
|
||||
bool IsPointInFill(const DOMPointInit& aPoint);
|
||||
bool IsPointInStroke(const DOMPointInit& aPoint);
|
||||
float GetTotalLength();
|
||||
already_AddRefed<nsISVGPoint> GetPointAtLength(float distance,
|
||||
ErrorResult& rv);
|
||||
|
@ -227,6 +229,9 @@ class SVGGeometryElement : public SVGGeometryElementBase {
|
|||
SVGAnimatedNumber mPathLength;
|
||||
static NumberInfo sNumberInfo;
|
||||
mutable RefPtr<Path> mCachedPath;
|
||||
|
||||
private:
|
||||
already_AddRefed<Path> GetOrBuildPathForHitTest();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
|
|
@ -462,7 +462,7 @@ function testCreateMatrix3D()
|
|||
// Should be initialised to identity
|
||||
cmpMatrix(m, [1, 0, 0, 1, 0, 0],
|
||||
"DOMMatrix should produce identity matrix");
|
||||
is(m.is2D, true, "should not produce 3d matrix");
|
||||
is(m.is2D, false, "should produce 3d matrix");
|
||||
|
||||
m = new DOMMatrix([1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0]);
|
||||
|
||||
|
@ -707,16 +707,16 @@ function testParsing()
|
|||
}
|
||||
|
||||
|
||||
function testStringify() {
|
||||
var m = new DOMMatrix();
|
||||
var s = "" + m;
|
||||
ok(s == "matrix" + formatMatrix(m), "stringifier 1 produced wrong result: " + s);
|
||||
m.a = 100;
|
||||
s = "" + m;
|
||||
ok(s == "matrix" + formatMatrix(m), "stringifier 2 produced wrong result: " + s);
|
||||
m.m43 = 200;
|
||||
s = "" + m;
|
||||
ok(s == "matrix3d" + formatMatrix(m), "stringifier 3 produced wrong result:" + s);
|
||||
function testStringify() {
|
||||
var m = new DOMMatrix();
|
||||
var s = "" + m;
|
||||
ok(s == "matrix" + formatMatrix(m), "stringifier 1 produced wrong result: " + s);
|
||||
m.a = 100;
|
||||
s = "" + m;
|
||||
ok(s == "matrix" + formatMatrix(m), "stringifier 2 produced wrong result: " + s);
|
||||
m.m43 = 200;
|
||||
s = "" + m;
|
||||
ok(s == "matrix3d" + formatMatrix(m), "stringifier 3 produced wrong result:" + s);
|
||||
}
|
||||
|
||||
window.addEventListener("load", main);
|
||||
|
|
|
@ -14,6 +14,9 @@ interface SVGGeometryElement : SVGGraphicsElement {
|
|||
[SameObject]
|
||||
readonly attribute SVGAnimatedNumber pathLength;
|
||||
|
||||
boolean isPointInFill(optional DOMPointInit point);
|
||||
boolean isPointInStroke(optional DOMPointInit point);
|
||||
|
||||
float getTotalLength();
|
||||
[NewObject, Throws]
|
||||
SVGPoint getPointAtLength(float distance);
|
||||
|
|
|
@ -11,16 +11,22 @@
|
|||
#include "mozilla/layers/CompositorBridgeChild.h"
|
||||
#include "mozilla/layers/CompositorBridgeParent.h"
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
# include "mozilla/widget/nsWindow.h"
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace gfx;
|
||||
using namespace widget;
|
||||
|
||||
CompositorSession::CompositorSession(CompositorWidgetDelegate* aDelegate,
|
||||
CompositorSession::CompositorSession(nsBaseWidget* aWidget,
|
||||
CompositorWidgetDelegate* aDelegate,
|
||||
CompositorBridgeChild* aChild,
|
||||
const LayersId& aRootLayerTreeId)
|
||||
: mCompositorWidgetDelegate(aDelegate),
|
||||
: mWidget(aWidget),
|
||||
mCompositorWidgetDelegate(aDelegate),
|
||||
mCompositorBridgeChild(aChild),
|
||||
mRootLayerTreeId(aRootLayerTreeId) {}
|
||||
|
||||
|
@ -30,5 +36,15 @@ CompositorBridgeChild* CompositorSession::GetCompositorBridgeChild() {
|
|||
return mCompositorBridgeChild;
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
void CompositorSession::NotifyDisablingWebRender() {
|
||||
if (!mWidget) {
|
||||
return;
|
||||
}
|
||||
nsWindow* window = static_cast<nsWindow*>(mWidget);
|
||||
window->NotifyDisablingWebRender();
|
||||
}
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
# include "mozilla/layers/UiCompositorControllerChild.h"
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
|
||||
class nsIWidget;
|
||||
class nsBaseWidget;
|
||||
|
||||
namespace mozilla {
|
||||
namespace widget {
|
||||
|
@ -80,14 +80,17 @@ class CompositorSession {
|
|||
RefPtr<UiCompositorControllerChild> GetUiCompositorControllerChild() {
|
||||
return mUiCompositorControllerChild;
|
||||
}
|
||||
|
||||
void NotifyDisablingWebRender();
|
||||
#endif // defined(MOZ_WIDGET_ANDROID)
|
||||
protected:
|
||||
CompositorSession(CompositorWidgetDelegate* aDelegate,
|
||||
CompositorSession(nsBaseWidget* aWidget, CompositorWidgetDelegate* aDelegate,
|
||||
CompositorBridgeChild* aChild,
|
||||
const LayersId& aRootLayerTreeId);
|
||||
virtual ~CompositorSession();
|
||||
|
||||
protected:
|
||||
nsBaseWidget* mWidget;
|
||||
CompositorWidgetDelegate* mCompositorWidgetDelegate;
|
||||
RefPtr<CompositorBridgeChild> mCompositorBridgeChild;
|
||||
LayersId mRootLayerTreeId;
|
||||
|
|
|
@ -455,6 +455,15 @@ void GPUProcessManager::DisableWebRender(wr::WebRenderError aError) {
|
|||
}
|
||||
gfx::gfxVars::SetUseWebRender(false);
|
||||
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
// If aError is not wr::WebRenderError::INITIALIZE, nsWindow does not
|
||||
// re-create LayerManager. Needs to trigger re-creating LayerManager on
|
||||
// android
|
||||
if (aError != wr::WebRenderError::INITIALIZE) {
|
||||
NotifyDisablingWebRender();
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mProcess) {
|
||||
OnRemoteProcessDeviceReset(mProcess);
|
||||
} else {
|
||||
|
@ -641,6 +650,18 @@ void GPUProcessManager::RebuildInProcessSessions() {
|
|||
}
|
||||
}
|
||||
|
||||
void GPUProcessManager::NotifyDisablingWebRender() {
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
for (const auto& session : mRemoteSessions) {
|
||||
session->NotifyDisablingWebRender();
|
||||
}
|
||||
|
||||
for (const auto& session : mInProcessSessions) {
|
||||
session->NotifyDisablingWebRender();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void GPUProcessManager::NotifyRemoteActorDestroyed(
|
||||
const uint64_t& aProcessToken) {
|
||||
if (!NS_IsMainThread()) {
|
||||
|
|
|
@ -210,6 +210,8 @@ class GPUProcessManager final : public GPUProcessHost::Listener {
|
|||
void RebuildRemoteSessions();
|
||||
void RebuildInProcessSessions();
|
||||
|
||||
void NotifyDisablingWebRender();
|
||||
|
||||
void FallbackToSoftware(const char* aMessage);
|
||||
|
||||
private:
|
||||
|
|
|
@ -13,13 +13,12 @@ namespace mozilla {
|
|||
namespace layers {
|
||||
|
||||
InProcessCompositorSession::InProcessCompositorSession(
|
||||
widget::CompositorWidget* aWidget, nsBaseWidget* baseWidget,
|
||||
nsBaseWidget* aWidget, widget::CompositorWidget* aCompositorWidget,
|
||||
CompositorBridgeChild* aChild, CompositorBridgeParent* aParent)
|
||||
: CompositorSession(aWidget->AsDelegate(), aChild,
|
||||
: CompositorSession(aWidget, aCompositorWidget->AsDelegate(), aChild,
|
||||
aParent->RootLayerTreeId()),
|
||||
mWidget(baseWidget),
|
||||
mCompositorBridgeParent(aParent),
|
||||
mCompositorWidget(aWidget) {
|
||||
mCompositorWidget(aCompositorWidget) {
|
||||
GPUProcessManager::Get()->RegisterInProcessSession(this);
|
||||
}
|
||||
|
||||
|
@ -45,7 +44,7 @@ RefPtr<InProcessCompositorSession> InProcessCompositorSession::Create(
|
|||
aLayerManager, aNamespace);
|
||||
MOZ_ASSERT(child);
|
||||
|
||||
return new InProcessCompositorSession(widget, aWidget, child, parent);
|
||||
return new InProcessCompositorSession(aWidget, widget, child, parent);
|
||||
}
|
||||
|
||||
void InProcessCompositorSession::NotifySessionLost() {
|
||||
|
|
|
@ -34,13 +34,12 @@ class InProcessCompositorSession final : public CompositorSession {
|
|||
void NotifySessionLost();
|
||||
|
||||
private:
|
||||
InProcessCompositorSession(widget::CompositorWidget* aWidget,
|
||||
nsBaseWidget* baseWidget,
|
||||
InProcessCompositorSession(nsBaseWidget* aWidget,
|
||||
widget::CompositorWidget* aCompositorWidget,
|
||||
CompositorBridgeChild* aChild,
|
||||
CompositorBridgeParent* aParent);
|
||||
|
||||
private:
|
||||
nsBaseWidget* mWidget;
|
||||
RefPtr<CompositorBridgeParent> mCompositorBridgeParent;
|
||||
RefPtr<CompositorWidget> mCompositorWidget;
|
||||
};
|
||||
|
|
|
@ -24,8 +24,7 @@ RemoteCompositorSession::RemoteCompositorSession(
|
|||
nsBaseWidget* aWidget, CompositorBridgeChild* aChild,
|
||||
CompositorWidgetDelegate* aWidgetDelegate, APZCTreeManagerChild* aAPZ,
|
||||
const LayersId& aRootLayerTreeId)
|
||||
: CompositorSession(aWidgetDelegate, aChild, aRootLayerTreeId),
|
||||
mWidget(aWidget),
|
||||
: CompositorSession(aWidget, aWidgetDelegate, aChild, aRootLayerTreeId),
|
||||
mAPZ(aAPZ) {
|
||||
MOZ_ASSERT(!gfxPlatform::IsHeadless());
|
||||
GPUProcessManager::Get()->RegisterRemoteProcessSession(this);
|
||||
|
|
|
@ -31,7 +31,6 @@ class RemoteCompositorSession final : public CompositorSession {
|
|||
void NotifySessionLost();
|
||||
|
||||
private:
|
||||
nsBaseWidget* mWidget;
|
||||
RefPtr<APZCTreeManagerChild> mAPZ;
|
||||
RefPtr<GeckoContentController> mContentController;
|
||||
};
|
||||
|
|
|
@ -103,6 +103,12 @@ void RenderAndroidSurfaceTextureHostOGL::DeleteTextureHandle() {
|
|||
}
|
||||
|
||||
bool RenderAndroidSurfaceTextureHostOGL::EnsureAttachedToGLContext() {
|
||||
// During handling WebRenderError, GeckoSurfaceTexture should not be attached
|
||||
// to GLContext.
|
||||
if (RenderThread::Get()->IsHandlingWebRenderError()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mAttachedToGLContext) {
|
||||
return true;
|
||||
}
|
||||
|
@ -197,7 +203,9 @@ void RenderAndroidSurfaceTextureHostOGL::NofityForUse() {
|
|||
// WebRender, instead rendered to WebGL.
|
||||
// It is not a good way. But it is same to Compositor rendering.
|
||||
MOZ_ASSERT(!mSurfTex || !mSurfTex->IsSingleBuffer());
|
||||
EnsureAttachedToGLContext();
|
||||
if (!EnsureAttachedToGLContext()) {
|
||||
return;
|
||||
}
|
||||
mPrepareStatus = STATUS_PREPARE_NEEDED;
|
||||
}
|
||||
}
|
||||
|
@ -207,7 +215,9 @@ void RenderAndroidSurfaceTextureHostOGL::NotifyNotUsed() {
|
|||
|
||||
if (mSurfTex && mSurfTex->IsSingleBuffer() &&
|
||||
mPrepareStatus == STATUS_PREPARED) {
|
||||
EnsureAttachedToGLContext();
|
||||
if (!EnsureAttachedToGLContext()) {
|
||||
return;
|
||||
}
|
||||
// Release SurfaceTexture's buffer to client side.
|
||||
mGL->MakeCurrent();
|
||||
mSurfTex->ReleaseTexImage();
|
||||
|
@ -215,7 +225,9 @@ void RenderAndroidSurfaceTextureHostOGL::NotifyNotUsed() {
|
|||
// This could happen when video frame was skipped. UpdateTexImage() neeeds
|
||||
// to be called for adjusting SurfaceTexture's buffer status.
|
||||
MOZ_ASSERT(!mSurfTex->IsSingleBuffer());
|
||||
EnsureAttachedToGLContext();
|
||||
if (!EnsureAttachedToGLContext()) {
|
||||
return;
|
||||
}
|
||||
mSurfTex->UpdateTexImage();
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,13 @@ RenderCompositorEGL::RenderCompositorEGL(
|
|||
RefPtr<widget::CompositorWidget> aWidget)
|
||||
: RenderCompositor(std::move(aWidget)), mEGLSurface(EGL_NO_SURFACE) {}
|
||||
|
||||
RenderCompositorEGL::~RenderCompositorEGL() { DestroyEGLSurface(); }
|
||||
RenderCompositorEGL::~RenderCompositorEGL() {
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
java::GeckoSurfaceTexture::DestroyUnused((int64_t)gl());
|
||||
java::GeckoSurfaceTexture::DetachAllFromGLContext((int64_t)gl());
|
||||
#endif
|
||||
DestroyEGLSurface();
|
||||
}
|
||||
|
||||
bool RenderCompositorEGL::BeginFrame() {
|
||||
#ifdef MOZ_WAYLAND
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "mozilla/gfx/GPUParent.h"
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "mozilla/layers/CompositorBridgeParent.h"
|
||||
#include "mozilla/layers/CompositorManagerParent.h"
|
||||
#include "mozilla/layers/WebRenderBridgeParent.h"
|
||||
#include "mozilla/layers/SharedSurfacesParent.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
|
@ -28,6 +29,7 @@
|
|||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
# include "GLLibraryEGL.h"
|
||||
# include "GeneratedJNIWrappers.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -46,7 +48,8 @@ RenderThread::RenderThread(base::Thread* aThread)
|
|||
mWindowInfos("RenderThread.mWindowInfos"),
|
||||
mRenderTextureMapLock("RenderThread.mRenderTextureMapLock"),
|
||||
mHasShutdown(false),
|
||||
mHandlingDeviceReset(false) {}
|
||||
mHandlingDeviceReset(false),
|
||||
mHandlingWebRenderError(false) {}
|
||||
|
||||
RenderThread::~RenderThread() {
|
||||
MOZ_ASSERT(mRenderTexturesDeferred.empty());
|
||||
|
@ -808,6 +811,34 @@ void RenderThread::SimulateDeviceReset() {
|
|||
}
|
||||
}
|
||||
|
||||
static void DoNotifyWebRenderError(WebRenderError aError) {
|
||||
layers::CompositorManagerParent::NotifyWebRenderError(aError);
|
||||
}
|
||||
|
||||
void RenderThread::HandleWebRenderError(WebRenderError aError) {
|
||||
if (mHandlingWebRenderError) {
|
||||
return;
|
||||
}
|
||||
|
||||
layers::CompositorThreadHolder::Loop()->PostTask(NewRunnableFunction(
|
||||
"DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError, aError));
|
||||
{
|
||||
MutexAutoLock lock(mRenderTextureMapLock);
|
||||
mRenderTexturesDeferred.clear();
|
||||
for (const auto& entry : mRenderTextures) {
|
||||
entry.second->ClearCachedResources();
|
||||
}
|
||||
}
|
||||
mHandlingWebRenderError = true;
|
||||
// WebRender is going to be disabled by
|
||||
// GPUProcessManager::NotifyWebRenderError()
|
||||
}
|
||||
|
||||
bool RenderThread::IsHandlingWebRenderError() {
|
||||
MOZ_ASSERT(IsInRenderThread());
|
||||
return mHandlingWebRenderError;
|
||||
}
|
||||
|
||||
gl::GLContext* RenderThread::SharedGL() {
|
||||
MOZ_ASSERT(IsInRenderThread());
|
||||
if (!mSharedGL) {
|
||||
|
|
|
@ -255,6 +255,11 @@ class RenderThread final {
|
|||
/// Can be called from any thread.
|
||||
void SimulateDeviceReset();
|
||||
|
||||
/// Can only be called from the render thread.
|
||||
void HandleWebRenderError(WebRenderError aError);
|
||||
/// Can only be called from the render thread.
|
||||
bool IsHandlingWebRenderError();
|
||||
|
||||
size_t RendererCount();
|
||||
|
||||
void SetCompositionRecorderForWindow(
|
||||
|
@ -314,6 +319,7 @@ class RenderThread final {
|
|||
bool mHasShutdown;
|
||||
|
||||
bool mHandlingDeviceReset;
|
||||
bool mHandlingWebRenderError;
|
||||
};
|
||||
|
||||
} // namespace wr
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#include "mozilla/gfx/gfxVars.h"
|
||||
#include "mozilla/gfx/Types.h"
|
||||
#include "mozilla/layers/CompositorBridgeParent.h"
|
||||
#include "mozilla/layers/CompositorManagerParent.h"
|
||||
#include "mozilla/layers/CompositorThread.h"
|
||||
#include "mozilla/layers/LayersTypes.h"
|
||||
#include "mozilla/webrender/RenderCompositor.h"
|
||||
|
@ -120,7 +119,8 @@ bool RendererOGL::UpdateAndRender(const Maybe<gfx::IntSize>& aReadbackSize,
|
|||
|
||||
if (!wr_renderer_render(mRenderer, size.width, size.height, aHadSlowFrame,
|
||||
aOutStats)) {
|
||||
NotifyWebRenderError(WebRenderError::RENDER);
|
||||
RenderThread::Get()->HandleWebRenderError(WebRenderError::RENDER);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aReadbackBuffer.isSome()) {
|
||||
|
@ -216,14 +216,5 @@ void RendererOGL::AccumulateMemoryReport(MemoryReport* aReport) {
|
|||
aReport->swap_chain += swapChainSize;
|
||||
}
|
||||
|
||||
static void DoNotifyWebRenderError(WebRenderError aError) {
|
||||
layers::CompositorManagerParent::NotifyWebRenderError(aError);
|
||||
}
|
||||
|
||||
void RendererOGL::NotifyWebRenderError(WebRenderError aError) {
|
||||
layers::CompositorThreadHolder::Loop()->PostTask(NewRunnableFunction(
|
||||
"DoNotifyWebRenderErrorRunnable", &DoNotifyWebRenderError, aError));
|
||||
}
|
||||
|
||||
} // namespace wr
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -104,8 +104,6 @@ class RendererOGL {
|
|||
gl::GLContext* gl() const;
|
||||
|
||||
protected:
|
||||
void NotifyWebRenderError(WebRenderError aError);
|
||||
|
||||
RefPtr<RenderThread> mThread;
|
||||
UniquePtr<RenderCompositor> mCompositor;
|
||||
wr::Renderer* mRenderer;
|
||||
|
|
|
@ -247,6 +247,8 @@ struct Symbol {
|
|||
*/
|
||||
class JS_FRIEND_API GCCellPtr {
|
||||
public:
|
||||
GCCellPtr() : GCCellPtr(nullptr) {}
|
||||
|
||||
// Construction from a void* and trace kind.
|
||||
GCCellPtr(void* gcthing, JS::TraceKind traceKind)
|
||||
: ptr(checkedCast(gcthing, traceKind)) {}
|
||||
|
|
|
@ -3765,10 +3765,10 @@ static const JSFunctionSpec array_methods[] = {
|
|||
|
||||
JS_SELF_HOSTED_FN("fill", "ArrayFill", 3, 0),
|
||||
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "ArrayValues", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "$ArrayValues", 0, 0),
|
||||
JS_SELF_HOSTED_FN("entries", "ArrayEntries", 0, 0),
|
||||
JS_SELF_HOSTED_FN("keys", "ArrayKeys", 0, 0),
|
||||
JS_SELF_HOSTED_FN("values", "ArrayValues", 0, 0),
|
||||
JS_SELF_HOSTED_FN("values", "$ArrayValues", 0, 0),
|
||||
|
||||
/* ES7 additions */
|
||||
JS_SELF_HOSTED_FN("includes", "ArrayIncludes", 2, 0),
|
||||
|
@ -3806,7 +3806,7 @@ static const JSFunctionSpec array_static_methods[] = {
|
|||
JS_FS_END};
|
||||
|
||||
const JSPropertySpec array_static_props[] = {
|
||||
JS_SELF_HOSTED_SYM_GET(species, "ArraySpecies", 0), JS_PS_END};
|
||||
JS_SELF_HOSTED_SYM_GET(species, "$ArraySpecies", 0), JS_PS_END};
|
||||
|
||||
static inline bool ArrayConstructorImpl(JSContext* cx, CallArgs& args,
|
||||
bool isConstructor) {
|
||||
|
|
|
@ -789,10 +789,12 @@ function ArrayIteratorNext() {
|
|||
return result;
|
||||
}
|
||||
|
||||
function ArrayValues() {
|
||||
// Uncloned functions with `$` prefix are allocated as extended function
|
||||
// to store the original name in `_SetCanonicalName`.
|
||||
function $ArrayValues() {
|
||||
return CreateArrayIterator(this, ITEM_KIND_VALUE);
|
||||
}
|
||||
_SetCanonicalName(ArrayValues, "values");
|
||||
_SetCanonicalName($ArrayValues, "values");
|
||||
|
||||
function ArrayEntries() {
|
||||
return CreateArrayIterator(this, ITEM_KIND_KEY_AND_VALUE);
|
||||
|
@ -973,11 +975,11 @@ function ArrayToLocaleString(locales, options) {
|
|||
}
|
||||
|
||||
// ES 2016 draft Mar 25, 2016 22.1.2.5.
|
||||
function ArraySpecies() {
|
||||
function $ArraySpecies() {
|
||||
// Step 1.
|
||||
return this;
|
||||
}
|
||||
_SetCanonicalName(ArraySpecies, "get [Symbol.species]");
|
||||
_SetCanonicalName($ArraySpecies, "get [Symbol.species]");
|
||||
|
||||
// ES 2016 draft Mar 25, 2016 9.4.2.3.
|
||||
function ArraySpeciesCreate(originalArray, length) {
|
||||
|
|
|
@ -43,10 +43,23 @@ static void AssertInnerizedEnvironmentChain(JSContext* cx, JSObject& env) {
|
|||
}
|
||||
|
||||
static bool IsEvalCacheCandidate(JSScript* script) {
|
||||
if (!script->isDirectEvalInFunction()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Make sure there are no inner objects which might use the wrong parent
|
||||
// and/or call scope by reusing the previous eval's script.
|
||||
return script->isDirectEvalInFunction() && !script->hasSingletons() &&
|
||||
!script->hasObjects();
|
||||
if (script->hasSingletons()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (JS::GCCellPtr gcThing : script->gcthings()) {
|
||||
if (gcThing.is<JSObject>()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
|
|
@ -63,10 +63,12 @@ function MapForEach(callbackfn, thisArg = undefined) {
|
|||
}
|
||||
}
|
||||
|
||||
function MapEntries() {
|
||||
// Uncloned functions with `$` prefix are allocated as extended function
|
||||
// to store the original name in `_SetCanonicalName`.
|
||||
function $MapEntries() {
|
||||
return callFunction(std_Map_iterator, this);
|
||||
}
|
||||
_SetCanonicalName(MapEntries, "entries");
|
||||
_SetCanonicalName($MapEntries, "entries");
|
||||
|
||||
var iteratorTemp = { mapIterationResultPair: null };
|
||||
|
||||
|
@ -121,8 +123,8 @@ function MapIteratorNext() {
|
|||
}
|
||||
|
||||
// ES6 final draft 23.1.2.2.
|
||||
function MapSpecies() {
|
||||
function $MapSpecies() {
|
||||
// Step 1.
|
||||
return this;
|
||||
}
|
||||
_SetCanonicalName(MapSpecies, "get [Symbol.species]");
|
||||
_SetCanonicalName($MapSpecies, "get [Symbol.species]");
|
||||
|
|
|
@ -411,11 +411,11 @@ const JSFunctionSpec MapObject::methods[] = {
|
|||
JS_SELF_HOSTED_FN("forEach", "MapForEach", 2, 0),
|
||||
// MapEntries only exists to preseve the equal identity of
|
||||
// entries and @@iterator.
|
||||
JS_SELF_HOSTED_FN("entries", "MapEntries", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "MapEntries", 0, 0), JS_FS_END};
|
||||
JS_SELF_HOSTED_FN("entries", "$MapEntries", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "$MapEntries", 0, 0), JS_FS_END};
|
||||
|
||||
const JSPropertySpec MapObject::staticProperties[] = {
|
||||
JS_SELF_HOSTED_SYM_GET(species, "MapSpecies", 0), JS_PS_END};
|
||||
JS_SELF_HOSTED_SYM_GET(species, "$MapSpecies", 0), JS_PS_END};
|
||||
|
||||
template <class Range>
|
||||
static void TraceKey(Range& r, const HashableValue& key, JSTracer* trc) {
|
||||
|
@ -1160,12 +1160,12 @@ const JSFunctionSpec SetObject::methods[] = {
|
|||
JS_SELF_HOSTED_FN("forEach", "SetForEach", 2, 0),
|
||||
// SetValues only exists to preseve the equal identity of
|
||||
// values, keys and @@iterator.
|
||||
JS_SELF_HOSTED_FN("values", "SetValues", 0, 0),
|
||||
JS_SELF_HOSTED_FN("keys", "SetValues", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "SetValues", 0, 0), JS_FS_END};
|
||||
JS_SELF_HOSTED_FN("values", "$SetValues", 0, 0),
|
||||
JS_SELF_HOSTED_FN("keys", "$SetValues", 0, 0),
|
||||
JS_SELF_HOSTED_SYM_FN(iterator, "$SetValues", 0, 0), JS_FS_END};
|
||||
|
||||
const JSPropertySpec SetObject::staticProperties[] = {
|
||||
JS_SELF_HOSTED_SYM_GET(species, "SetSpecies", 0), JS_PS_END};
|
||||
JS_SELF_HOSTED_SYM_GET(species, "$SetSpecies", 0), JS_PS_END};
|
||||
|
||||
bool SetObject::keys(JSContext* cx, HandleObject obj,
|
||||
JS::MutableHandle<GCVector<JS::Value>> keys) {
|
||||
|
|
|
@ -328,7 +328,6 @@ function ModuleInstantiate()
|
|||
// Step 8
|
||||
return undefined;
|
||||
}
|
||||
_SetCanonicalName(ModuleInstantiate, "ModuleInstantiate");
|
||||
|
||||
// 15.2.1.16.4.1 InnerModuleInstantiation(module, stack, index)
|
||||
function InnerModuleInstantiation(module, stack, index)
|
||||
|
@ -552,7 +551,6 @@ function ModuleEvaluate()
|
|||
|
||||
return undefined;
|
||||
}
|
||||
_SetCanonicalName(ModuleEvaluate, "ModuleEvaluate");
|
||||
|
||||
// 15.2.1.16.5.1 InnerModuleEvaluation(module, stack, index)
|
||||
function InnerModuleEvaluation(module, stack, index)
|
||||
|
|
|
@ -771,7 +771,7 @@ bool js::regexp_unicode(JSContext* cx, unsigned argc, JS::Value* vp) {
|
|||
}
|
||||
|
||||
const JSPropertySpec js::regexp_properties[] = {
|
||||
JS_SELF_HOSTED_GET("flags", "RegExpFlagsGetter", 0),
|
||||
JS_SELF_HOSTED_GET("flags", "$RegExpFlagsGetter", 0),
|
||||
JS_PSG("global", regexp_global, 0),
|
||||
JS_PSG("ignoreCase", regexp_ignoreCase, 0),
|
||||
JS_PSG("multiline", regexp_multiline, 0),
|
||||
|
@ -781,8 +781,8 @@ const JSPropertySpec js::regexp_properties[] = {
|
|||
JS_PS_END};
|
||||
|
||||
const JSFunctionSpec js::regexp_methods[] = {
|
||||
JS_SELF_HOSTED_FN(js_toSource_str, "RegExpToString", 0, 0),
|
||||
JS_SELF_HOSTED_FN(js_toString_str, "RegExpToString", 0, 0),
|
||||
JS_SELF_HOSTED_FN(js_toSource_str, "$RegExpToString", 0, 0),
|
||||
JS_SELF_HOSTED_FN(js_toString_str, "$RegExpToString", 0, 0),
|
||||
JS_FN("compile", regexp_compile, 2, 0),
|
||||
JS_SELF_HOSTED_FN("exec", "RegExp_prototype_Exec", 1, 0),
|
||||
JS_SELF_HOSTED_FN("test", "RegExpTest", 1, 0),
|
||||
|
@ -890,7 +890,7 @@ const JSPropertySpec js::regexp_static_props[] = {
|
|||
JS_PSG("$+", static_lastParen_getter, JSPROP_PERMANENT),
|
||||
JS_PSG("$`", static_leftContext_getter, JSPROP_PERMANENT),
|
||||
JS_PSG("$'", static_rightContext_getter, JSPROP_PERMANENT),
|
||||
JS_SELF_HOSTED_SYM_GET(species, "RegExpSpecies", 0),
|
||||
JS_SELF_HOSTED_SYM_GET(species, "$RegExpSpecies", 0),
|
||||
JS_PS_END};
|
||||
|
||||
template <typename CharT>
|
||||
|
|
|
@ -3,7 +3,9 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
// ES6 draft rev34 (2015/02/20) 21.2.5.3 get RegExp.prototype.flags
|
||||
function RegExpFlagsGetter() {
|
||||
// Uncloned functions with `$` prefix are allocated as extended function
|
||||
// to store the original name in `_SetCanonicalName`.
|
||||
function $RegExpFlagsGetter() {
|
||||
// Steps 1-2.
|
||||
var R = this;
|
||||
if (!IsObject(R))
|
||||
|
@ -35,10 +37,10 @@ function RegExpFlagsGetter() {
|
|||
// Step 19.
|
||||
return result;
|
||||
}
|
||||
_SetCanonicalName(RegExpFlagsGetter, "get flags");
|
||||
_SetCanonicalName($RegExpFlagsGetter, "get flags");
|
||||
|
||||
// ES 2017 draft 40edb3a95a475c1b251141ac681b8793129d9a6d 21.2.5.14.
|
||||
function RegExpToString()
|
||||
function $RegExpToString()
|
||||
{
|
||||
// Step 1.
|
||||
var R = this;
|
||||
|
@ -56,7 +58,7 @@ function RegExpToString()
|
|||
// Steps 5-6.
|
||||
return "/" + pattern + "/" + flags;
|
||||
}
|
||||
_SetCanonicalName(RegExpToString, "toString");
|
||||
_SetCanonicalName($RegExpToString, "toString");
|
||||
|
||||
// ES 2016 draft Mar 25, 2016 21.2.5.2.3.
|
||||
function AdvanceStringIndex(S, index) {
|
||||
|
@ -1070,11 +1072,11 @@ function RegExpTest(string) {
|
|||
}
|
||||
|
||||
// ES 2016 draft Mar 25, 2016 21.2.4.2.
|
||||
function RegExpSpecies() {
|
||||
function $RegExpSpecies() {
|
||||
// Step 1.
|
||||
return this;
|
||||
}
|
||||
_SetCanonicalName(RegExpSpecies, "get [Symbol.species]");
|
||||
_SetCanonicalName($RegExpSpecies, "get [Symbol.species]");
|
||||
|
||||
function IsRegExpMatchAllOptimizable(rx, C) {
|
||||
if (!IsRegExpObject(rx))
|
||||
|
|
|
@ -63,8 +63,12 @@
|
|||
#define PROP_DESC_GETTER_INDEX 1
|
||||
#define PROP_DESC_SETTER_INDEX 2
|
||||
|
||||
// The extended slot in which the self-hosted name for self-hosted builtins is
|
||||
// stored.
|
||||
// The extended slot of uncloned self-hosted function, in which the original
|
||||
// name for self-hosted builtins is stored by `_SetCanonicalName`.
|
||||
#define ORIGINAL_FUNCTION_NAME_SLOT 0
|
||||
|
||||
// The extended slot of cloned self-hosted function, in which the self-hosted
|
||||
// name for self-hosted builtins is stored.
|
||||
#define LAZY_FUNCTION_NAME_SLOT 0
|
||||
|
||||
// Stores the length for bound functions, so the .length property doesn't need
|
||||
|
|
|
@ -53,17 +53,19 @@ function SetForEach(callbackfn, thisArg = undefined) {
|
|||
}
|
||||
}
|
||||
|
||||
function SetValues() {
|
||||
// Uncloned functions with `$` prefix are allocated as extended function
|
||||
// to store the original name in `_SetCanonicalName`.
|
||||
function $SetValues() {
|
||||
return callFunction(std_Set_iterator, this);
|
||||
}
|
||||
_SetCanonicalName(SetValues, "values");
|
||||
_SetCanonicalName($SetValues, "values");
|
||||
|
||||
// ES6 final draft 23.2.2.2.
|
||||
function SetSpecies() {
|
||||
function $SetSpecies() {
|
||||
// Step 1.
|
||||
return this;
|
||||
}
|
||||
_SetCanonicalName(SetSpecies, "get [Symbol.species]");
|
||||
_SetCanonicalName($SetSpecies, "get [Symbol.species]");
|
||||
|
||||
|
||||
var setIteratorTemp = { setIterationResult: null };
|
||||
|
|
|
@ -1445,7 +1445,10 @@ function TypedArraySubarray(begin, end) {
|
|||
}
|
||||
|
||||
// ES6 draft rev30 (2014/12/24) 22.2.3.30 %TypedArray%.prototype.values()
|
||||
function TypedArrayValues() {
|
||||
//
|
||||
// Uncloned functions with `$` prefix are allocated as extended function
|
||||
// to store the original name in `_SetCanonicalName`.
|
||||
function $TypedArrayValues() {
|
||||
// Step 1.
|
||||
var O = this;
|
||||
|
||||
|
@ -1455,7 +1458,7 @@ function TypedArrayValues() {
|
|||
// Step 7.
|
||||
return CreateArrayIterator(O, ITEM_KIND_VALUE);
|
||||
}
|
||||
_SetCanonicalName(TypedArrayValues, "values");
|
||||
_SetCanonicalName($TypedArrayValues, "values");
|
||||
|
||||
// Proposed for ES7:
|
||||
// https://github.com/tc39/Array.prototype.includes/blob/7c023c19a0/spec.md
|
||||
|
@ -1551,7 +1554,7 @@ function TypedArrayStaticFrom(source, mapfn = undefined, thisArg = undefined) {
|
|||
// constructor is a built-in TypedArray constructor.
|
||||
if (!mapping && IsTypedArrayConstructor(C) && IsObject(source)) {
|
||||
// The source is a TypedArray using the default iterator.
|
||||
if (usingIterator === TypedArrayValues && IsTypedArray(source) &&
|
||||
if (usingIterator === $TypedArrayValues && IsTypedArray(source) &&
|
||||
ArrayIteratorPrototypeOptimizable())
|
||||
{
|
||||
// Step 7.a.
|
||||
|
@ -1574,7 +1577,7 @@ function TypedArrayStaticFrom(source, mapfn = undefined, thisArg = undefined) {
|
|||
}
|
||||
|
||||
// The source is a packed array using the default iterator.
|
||||
if (usingIterator === ArrayValues && IsPackedArray(source) &&
|
||||
if (usingIterator === $ArrayValues && IsPackedArray(source) &&
|
||||
ArrayIteratorPrototypeOptimizable())
|
||||
{
|
||||
// Steps 7.b-c.
|
||||
|
@ -1674,11 +1677,11 @@ function TypedArrayStaticOf(/*...items*/) {
|
|||
}
|
||||
|
||||
// ES 2016 draft Mar 25, 2016 22.2.2.4.
|
||||
function TypedArraySpecies() {
|
||||
function $TypedArraySpecies() {
|
||||
// Step 1.
|
||||
return this;
|
||||
}
|
||||
_SetCanonicalName(TypedArraySpecies, "get [Symbol.species]");
|
||||
_SetCanonicalName($TypedArraySpecies, "get [Symbol.species]");
|
||||
|
||||
// ES2018 draft rev 0525bb33861c7f4e9850f8a222c89642947c4b9c
|
||||
// 22.2.2.1.1 Runtime Semantics: IterableToList( items, method )
|
||||
|
@ -1806,18 +1809,18 @@ function IsDetachedBufferThis() {
|
|||
}
|
||||
|
||||
// ES 2016 draft Mar 25, 2016 24.1.3.3.
|
||||
function ArrayBufferSpecies() {
|
||||
function $ArrayBufferSpecies() {
|
||||
// Step 1.
|
||||
return this;
|
||||
}
|
||||
_SetCanonicalName(ArrayBufferSpecies, "get [Symbol.species]");
|
||||
_SetCanonicalName($ArrayBufferSpecies, "get [Symbol.species]");
|
||||
|
||||
// Shared memory and atomics proposal (30 Oct 2016)
|
||||
function SharedArrayBufferSpecies() {
|
||||
function $SharedArrayBufferSpecies() {
|
||||
// Step 1.
|
||||
return this;
|
||||
}
|
||||
_SetCanonicalName(SharedArrayBufferSpecies, "get [Symbol.species]");
|
||||
_SetCanonicalName($SharedArrayBufferSpecies, "get [Symbol.species]");
|
||||
|
||||
// Shared memory and atomics proposal 6.2.1.5.3 (30 Oct 2016)
|
||||
// http://tc39.github.io/ecmascript_sharedmem/shmem.html
|
||||
|
|
|
@ -68,7 +68,7 @@ static const JSFunctionSpec collator_methods[] = {
|
|||
JS_FN(js_toSource_str, collator_toSource, 0, 0), JS_FS_END};
|
||||
|
||||
static const JSPropertySpec collator_properties[] = {
|
||||
JS_SELF_HOSTED_GET("compare", "Intl_Collator_compare_get", 0),
|
||||
JS_SELF_HOSTED_GET("compare", "$Intl_Collator_compare_get", 0),
|
||||
JS_STRING_SYM_PS(toStringTag, "Object", JSPROP_READONLY), JS_PS_END};
|
||||
|
||||
/**
|
||||
|
|
|
@ -348,13 +348,15 @@ function collatorCompareToBind(x, y) {
|
|||
*
|
||||
* Spec: ECMAScript Internationalization API Specification, 10.3.3.
|
||||
*/
|
||||
function Intl_Collator_compare_get() {
|
||||
// Uncloned functions with `$` prefix are allocated as extended function
|
||||
// to store the original name in `_SetCanonicalName`.
|
||||
function $Intl_Collator_compare_get() {
|
||||
// Step 1.
|
||||
var collator = this;
|
||||
|
||||
// Steps 2-3.
|
||||
if (!IsObject(collator) || (collator = GuardToCollator(collator)) === null)
|
||||
return callFunction(CallCollatorMethodIfWrapped, this, "Intl_Collator_compare_get");
|
||||
return callFunction(CallCollatorMethodIfWrapped, this, "$Intl_Collator_compare_get");
|
||||
|
||||
var internals = getCollatorInternals(collator);
|
||||
|
||||
|
@ -370,7 +372,7 @@ function Intl_Collator_compare_get() {
|
|||
// Step 5.
|
||||
return internals.boundCompare;
|
||||
}
|
||||
_SetCanonicalName(Intl_Collator_compare_get, "get compare");
|
||||
_SetCanonicalName($Intl_Collator_compare_get, "get compare");
|
||||
|
||||
/**
|
||||
* Returns the resolved options for a Collator object.
|
||||
|
|
|
@ -79,7 +79,7 @@ static const JSFunctionSpec dateTimeFormat_methods[] = {
|
|||
JS_FN(js_toSource_str, dateTimeFormat_toSource, 0, 0), JS_FS_END};
|
||||
|
||||
static const JSPropertySpec dateTimeFormat_properties[] = {
|
||||
JS_SELF_HOSTED_GET("format", "Intl_DateTimeFormat_format_get", 0),
|
||||
JS_SELF_HOSTED_GET("format", "$Intl_DateTimeFormat_format_get", 0),
|
||||
JS_STRING_SYM_PS(toStringTag, "Object", JSPROP_READONLY), JS_PS_END};
|
||||
|
||||
/**
|
||||
|
|
|
@ -791,13 +791,15 @@ function dateTimeFormatFormatToBind(date) {
|
|||
*
|
||||
* Spec: ECMAScript Internationalization API Specification, 12.4.3.
|
||||
*/
|
||||
function Intl_DateTimeFormat_format_get() {
|
||||
// Uncloned functions with `$` prefix are allocated as extended function
|
||||
// to store the original name in `_SetCanonicalName`.
|
||||
function $Intl_DateTimeFormat_format_get() {
|
||||
// Steps 1-3.
|
||||
var thisArg = UnwrapDateTimeFormat(this);
|
||||
var dtf = thisArg;
|
||||
if (!IsObject(dtf) || (dtf = GuardToDateTimeFormat(dtf)) === null) {
|
||||
return callFunction(CallDateTimeFormatMethodIfWrapped, thisArg,
|
||||
"Intl_DateTimeFormat_format_get");
|
||||
"$Intl_DateTimeFormat_format_get");
|
||||
}
|
||||
|
||||
var internals = getDateTimeFormatInternals(dtf);
|
||||
|
@ -814,7 +816,7 @@ function Intl_DateTimeFormat_format_get() {
|
|||
// Step 5.
|
||||
return internals.boundFormat;
|
||||
}
|
||||
_SetCanonicalName(Intl_DateTimeFormat_format_get, "get format");
|
||||
_SetCanonicalName($Intl_DateTimeFormat_format_get, "get format");
|
||||
|
||||
/**
|
||||
* Intl.DateTimeFormat.prototype.formatToParts ( date )
|
||||
|
|
|
@ -78,7 +78,7 @@ static const JSFunctionSpec numberFormat_methods[] = {
|
|||
JS_FN(js_toSource_str, numberFormat_toSource, 0, 0), JS_FS_END};
|
||||
|
||||
static const JSPropertySpec numberFormat_properties[] = {
|
||||
JS_SELF_HOSTED_GET("format", "Intl_NumberFormat_format_get", 0),
|
||||
JS_SELF_HOSTED_GET("format", "$Intl_NumberFormat_format_get", 0),
|
||||
JS_STRING_SYM_PS(toStringTag, "Object", JSPROP_READONLY), JS_PS_END};
|
||||
|
||||
/**
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче