mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-12 18:50:08 +00:00
Merge mozilla-central to b2g-inbound
This commit is contained in:
commit
abefd9f650
@ -196,6 +196,7 @@ let RemoteDebugger = {
|
||||
globalActorFactories: restrictPrivileges ? {
|
||||
webappsActor: DebuggerServer.globalActorFactories.webappsActor,
|
||||
deviceActor: DebuggerServer.globalActorFactories.deviceActor,
|
||||
settingsActor: DebuggerServer.globalActorFactories.settingsActor
|
||||
} : DebuggerServer.globalActorFactories
|
||||
};
|
||||
let { RootActor } = devtools.require("devtools/server/actors/root");
|
||||
|
@ -329,11 +329,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
render: function() {
|
||||
var cx = React.addons.classSet;
|
||||
|
||||
// For now all of the menu entries require FxA so hide the whole gear if FxA is disabled.
|
||||
if (!navigator.mozLoop.fxAEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
React.createElement("div", {className: "settings-menu dropdown"},
|
||||
React.createElement("a", {className: "button-settings", onClick: this.showDropdownMenu,
|
||||
@ -347,7 +342,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
React.createElement(SettingsDropdownEntry, {label: mozL10n.get("settings_menu_item_account"),
|
||||
onClick: this.handleClickAccountEntry,
|
||||
icon: "account",
|
||||
displayed: this._isSignedIn()}),
|
||||
displayed: this._isSignedIn() && navigator.mozLoop.fxAEnabled}),
|
||||
React.createElement(SettingsDropdownEntry, {icon: "tour",
|
||||
label: mozL10n.get("tour_label"),
|
||||
onClick: this.openGettingStartedTour}),
|
||||
|
@ -329,11 +329,6 @@ loop.panel = (function(_, mozL10n) {
|
||||
render: function() {
|
||||
var cx = React.addons.classSet;
|
||||
|
||||
// For now all of the menu entries require FxA so hide the whole gear if FxA is disabled.
|
||||
if (!navigator.mozLoop.fxAEnabled) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="settings-menu dropdown">
|
||||
<a className="button-settings" onClick={this.showDropdownMenu}
|
||||
@ -347,7 +342,7 @@ loop.panel = (function(_, mozL10n) {
|
||||
<SettingsDropdownEntry label={mozL10n.get("settings_menu_item_account")}
|
||||
onClick={this.handleClickAccountEntry}
|
||||
icon="account"
|
||||
displayed={this._isSignedIn()} />
|
||||
displayed={this._isSignedIn() && navigator.mozLoop.fxAEnabled} />
|
||||
<SettingsDropdownEntry icon="tour"
|
||||
label={mozL10n.get("tour_label")}
|
||||
onClick={this.openGettingStartedTour} />
|
||||
|
@ -260,6 +260,17 @@ describe("loop.panel", function() {
|
||||
});
|
||||
});
|
||||
|
||||
it("should hide the account entry when FxA is not enabled", function() {
|
||||
navigator.mozLoop.userProfile = {email: "test@example.com"};
|
||||
navigator.mozLoop.fxAEnabled = false;
|
||||
|
||||
var view = TestUtils.renderIntoDocument(
|
||||
React.createElement(loop.panel.SettingsDropdown));
|
||||
|
||||
expect(view.getDOMNode().querySelectorAll(".icon-account"))
|
||||
.to.have.length.of(0);
|
||||
});
|
||||
|
||||
describe("SettingsDropdown", function() {
|
||||
beforeEach(function() {
|
||||
navigator.mozLoop.logInToFxA = sandbox.stub();
|
||||
@ -271,14 +282,6 @@ describe("loop.panel", function() {
|
||||
navigator.mozLoop.fxAEnabled = true;
|
||||
});
|
||||
|
||||
it("should be hidden if FxA is not enabled",
|
||||
function() {
|
||||
navigator.mozLoop.fxAEnabled = false;
|
||||
var view = TestUtils.renderIntoDocument(
|
||||
React.createElement(loop.panel.SettingsDropdown));
|
||||
expect(view.getDOMNode()).to.be.null;
|
||||
});
|
||||
|
||||
it("should show a signin entry when user is not authenticated",
|
||||
function() {
|
||||
navigator.mozLoop.loggedInToFxA = false;
|
||||
|
@ -86,6 +86,7 @@ support-files =
|
||||
doc_scope-variable-3.html
|
||||
doc_scope-variable-4.html
|
||||
doc_script-eval.html
|
||||
doc_script-bookmarklet.html
|
||||
doc_script-switching-01.html
|
||||
doc_script-switching-02.html
|
||||
doc_split-console-paused-reload.html
|
||||
@ -413,6 +414,8 @@ skip-if = e10s && debug
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_sources-sorting.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_sources-bookmarklet.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_split-console-paused-reload.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_stack-01.js]
|
||||
|
@ -0,0 +1,50 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Make sure javascript bookmarklet scripts appear and load correctly in the source list
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_script-bookmarklet.html";
|
||||
|
||||
const BOOKMARKLET_SCRIPT_CODE = "console.log('bookmarklet executed');";
|
||||
|
||||
function test() {
|
||||
let gTab, gPanel, gDebugger;
|
||||
let gSources, gBreakpoints;
|
||||
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
gTab = aTab;
|
||||
gPanel = aPanel;
|
||||
gDebugger = gPanel.panelWin;
|
||||
gSources = gDebugger.DebuggerView.Sources;
|
||||
gBreakpoints = gDebugger.DebuggerController.Breakpoints;
|
||||
|
||||
return Task.spawn(function*() {
|
||||
let waitForSource = waitForDebuggerEvents(gPanel, gPanel.panelWin.EVENTS.NEW_SOURCE, 1);
|
||||
|
||||
// NOTE: devtools debugger panel needs to be already open,
|
||||
// or the bookmarklet script will not be shown in the sources panel
|
||||
callInTab(gTab, "injectBookmarklet", BOOKMARKLET_SCRIPT_CODE);
|
||||
|
||||
yield waitForSource;
|
||||
|
||||
is(gSources.values.length, 2, "Should have 2 source");
|
||||
|
||||
let item = gSources.getItemForAttachment(e => {
|
||||
return e.label.indexOf("javascript:") === 0;
|
||||
});
|
||||
ok(item, "Source label is incorrect.");
|
||||
|
||||
let res = yield promiseInvoke(gDebugger.DebuggerController.client,
|
||||
gDebugger.DebuggerController.client.request,
|
||||
{ to: item.value, type: "source"});
|
||||
|
||||
ok(res && res.source == BOOKMARKLET_SCRIPT_CODE, "SourceActor reply received");
|
||||
is(res.source, BOOKMARKLET_SCRIPT_CODE, "source is correct");
|
||||
is(res.contentType, "text/javascript", "contentType is correct");
|
||||
|
||||
yield closeDebuggerAndFinish(gPanel);
|
||||
});
|
||||
});
|
||||
}
|
14
browser/devtools/debugger/test/doc_script-bookmarklet.html
Normal file
14
browser/devtools/debugger/test/doc_script-bookmarklet.html
Normal file
@ -0,0 +1,14 @@
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
<!doctype html>
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<title>Debugger test page</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<script>function injectBookmarklet(bookmarklet) { setTimeout(function() { window.location = "javascript:" + bookmarklet; }, 0); }</script>
|
||||
</body>
|
||||
</html>
|
603
browser/devtools/shared/devices.js
Normal file
603
browser/devtools/shared/devices.js
Normal file
@ -0,0 +1,603 @@
|
||||
/* 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 { Ci, Cc } = require("chrome");
|
||||
const { Services } = require("resource://gre/modules/Services.jsm");
|
||||
const Strings = Services.strings.createBundle("chrome://browser/locale/devtools/device.properties");
|
||||
|
||||
/* `Devices` is a catalog of existing devices and their properties, intended
|
||||
* for (mobile) device emulation tools and features.
|
||||
*
|
||||
* The properties of a device are:
|
||||
* - name: Device brand and model(s).
|
||||
* - width: Viewport width.
|
||||
* - height: Viewport height.
|
||||
* - pixelRatio: Screen pixel ratio to viewport.
|
||||
* - userAgent: Device UserAgent string.
|
||||
* - touch: Whether the screen is touch-enabled.
|
||||
*
|
||||
* To add more devices to this catalog, either patch this file, or push new
|
||||
* device descriptions from your own code (e.g. an addon) like so:
|
||||
*
|
||||
* var myPhone = { name: "My Phone", ... };
|
||||
* require("devtools/shared/devices").Devices.Others.phones.push(myPhone);
|
||||
*/
|
||||
|
||||
let Devices = {
|
||||
Types: ["phones", "tablets", "notebooks", "televisions", "watches"],
|
||||
|
||||
// Get the localized string of a device type.
|
||||
GetString(deviceType) {
|
||||
return Strings.GetStringFromName("device." + deviceType);
|
||||
},
|
||||
};
|
||||
exports.Devices = Devices;
|
||||
|
||||
|
||||
// The `Devices.FirefoxOS` list was put together from various sources online.
|
||||
Devices.FirefoxOS = {
|
||||
phones: [
|
||||
{
|
||||
name: "Firefox OS Flame",
|
||||
width: 320,
|
||||
height: 570,
|
||||
pixelRatio: 1.5,
|
||||
userAgent: "Mozilla/5.0 (Mobile; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Alcatel One Touch Fire, Fire C",
|
||||
width: 320,
|
||||
height: 480,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Mobile; ALCATELOneTouch4012X; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Alcatel Fire E",
|
||||
width: 320,
|
||||
height: 480,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (Mobile; ALCATELOneTouch4012X; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Geeksphone Keon",
|
||||
width: 320,
|
||||
height: 480,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Mobile; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Geeksphone Peak, Revolution",
|
||||
width: 360,
|
||||
height: 640,
|
||||
pixelRatio: 1.5,
|
||||
userAgent: "Mozilla/5.0 (Mobile; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Intex Cloud Fx",
|
||||
width: 320,
|
||||
height: 480,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Mobile; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "LG Fireweb",
|
||||
width: 320,
|
||||
height: 480,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Mobile; LG-D300; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Spice Fire One Mi-FX1",
|
||||
width: 320,
|
||||
height: 480,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Mobile; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Symphony GoFox F15",
|
||||
width: 320,
|
||||
height: 480,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Mobile; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Zen Fire 105",
|
||||
width: 320,
|
||||
height: 480,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Mobile; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "ZTE Open",
|
||||
width: 320,
|
||||
height: 480,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Mobile; ZTEOPEN; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "ZTE Open C",
|
||||
width: 320,
|
||||
height: 450,
|
||||
pixelRatio: 1.5,
|
||||
userAgent: "Mozilla/5.0 (Mobile; OPENC; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
],
|
||||
tablets: [
|
||||
{
|
||||
name: "Foxconn InFocus",
|
||||
width: 1280,
|
||||
height: 800,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Mobile; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "VIA Vixen",
|
||||
width: 1024,
|
||||
height: 600,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Mobile; rv:28.0) Gecko/28.0 Firefox/28.0",
|
||||
touch: true,
|
||||
},
|
||||
],
|
||||
notebooks: [
|
||||
],
|
||||
televisions: [
|
||||
{
|
||||
name: "720p HD Television",
|
||||
width: 1280,
|
||||
height: 720,
|
||||
pixelRatio: 1,
|
||||
userAgent: "",
|
||||
touch: false,
|
||||
},
|
||||
{
|
||||
name: "1080p Full HD Television",
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
pixelRatio: 1,
|
||||
userAgent: "",
|
||||
touch: false,
|
||||
},
|
||||
{
|
||||
name: "4K Ultra HD Television",
|
||||
width: 3840,
|
||||
height: 2160,
|
||||
pixelRatio: 1,
|
||||
userAgent: "",
|
||||
touch: false,
|
||||
},
|
||||
],
|
||||
watches: [
|
||||
{
|
||||
name: "LG G Watch",
|
||||
width: 280,
|
||||
height: 280,
|
||||
pixelRatio: 1,
|
||||
userAgent: "",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "LG G Watch R",
|
||||
width: 320,
|
||||
height: 320,
|
||||
pixelRatio: 1,
|
||||
userAgent: "",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Moto 360",
|
||||
width: 320,
|
||||
height: 290,
|
||||
pixelRatio: 1,
|
||||
userAgent: "",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Samsung Gear Live",
|
||||
width: 320,
|
||||
height: 320,
|
||||
pixelRatio: 1,
|
||||
userAgent: "",
|
||||
touch: true,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
// `Devices.Others` was derived from the Chromium source code:
|
||||
// - chromium/src/third_party/WebKit/Source/devtools/front_end/toolbox/OverridesUI.js
|
||||
Devices.Others = {
|
||||
phones: [
|
||||
{
|
||||
name: "Apple iPhone 3GS",
|
||||
width: 320,
|
||||
height: 480,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Apple iPhone 4",
|
||||
width: 320,
|
||||
height: 480,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_2_1 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8C148 Safari/6533.18.5",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Apple iPhone 5",
|
||||
width: 320,
|
||||
height: 568,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X; en-us) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Apple iPhone 6",
|
||||
width: 375,
|
||||
height: 667,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Apple iPhone 6 Plus",
|
||||
width: 414,
|
||||
height: 736,
|
||||
pixelRatio: 3,
|
||||
userAgent: "Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/600.1.3 (KHTML, like Gecko) Version/8.0 Mobile/12A4345d Safari/600.1.4",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "BlackBerry Z10",
|
||||
width: 384,
|
||||
height: 640,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "BlackBerry Z30",
|
||||
width: 360,
|
||||
height: 640,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.0.9.2372 Mobile Safari/537.10+",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Google Nexus 4",
|
||||
width: 384,
|
||||
height: 640,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 4 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Google Nexus 5",
|
||||
width: 360,
|
||||
height: 640,
|
||||
pixelRatio: 3,
|
||||
userAgent: "Mozilla/5.0 (Linux; Android 4.2.1; en-us; Nexus 5 Build/JOP40D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Google Nexus S",
|
||||
width: 320,
|
||||
height: 533,
|
||||
pixelRatio: 1.5,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.3.4; en-us; Nexus S Build/GRJ22) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "HTC Evo, Touch HD, Desire HD, Desire",
|
||||
width: 320,
|
||||
height: 533,
|
||||
pixelRatio: 1.5,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Sprint APA9292KT Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "HTC One X, EVO LTE",
|
||||
width: 360,
|
||||
height: 640,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (Linux; Android 4.0.3; HTC One X Build/IML74K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "HTC Sensation, Evo 3D",
|
||||
width: 360,
|
||||
height: 640,
|
||||
pixelRatio: 1.5,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 4.0.3; en-us; HTC Sensation Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "LG Optimus 2X, Optimus 3D, Optimus Black",
|
||||
width: 320,
|
||||
height: 533,
|
||||
pixelRatio: 1.5,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.2; en-us; LG-P990/V08c Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1 MMS/LG-Android-MMS-V1.0/1.2",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "LG Optimus G",
|
||||
width: 384,
|
||||
height: 640,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (Linux; Android 4.0; LG-E975 Build/IMM76L) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Mobile Safari/535.19",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "LG Optimus LTE, Optimus 4X HD",
|
||||
width: 424,
|
||||
height: 753,
|
||||
pixelRatio: 1.7,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.3; en-us; LG-P930 Build/GRJ90) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "LG Optimus One",
|
||||
width: 213,
|
||||
height: 320,
|
||||
pixelRatio: 1.5,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.2.1; en-us; LG-MS690 Build/FRG83) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Motorola Defy, Droid, Droid X, Milestone",
|
||||
width: 320,
|
||||
height: 569,
|
||||
pixelRatio: 1.5,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.0; en-us; Milestone Build/ SHOLS_U2_01.03.1) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Motorola Droid 3, Droid 4, Droid Razr, Atrix 4G, Atrix 2",
|
||||
width: 540,
|
||||
height: 960,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.2; en-us; Droid Build/FRG22D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Motorola Droid Razr HD",
|
||||
width: 720,
|
||||
height: 1280,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.3; en-us; DROID RAZR 4G Build/6.5.1-73_DHD-11_M1-29) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Nokia C5, C6, C7, N97, N8, X7",
|
||||
width: 360,
|
||||
height: 640,
|
||||
pixelRatio: 1,
|
||||
userAgent: "NokiaN97/21.1.107 (SymbianOS/9.4; Series60/5.0 Mozilla/5.0; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebkit/525 (KHTML, like Gecko) BrowserNG/7.1.4",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Nokia Lumia 7X0, Lumia 8XX, Lumia 900, N800, N810, N900",
|
||||
width: 320,
|
||||
height: 533,
|
||||
pixelRatio: 1.5,
|
||||
userAgent: "Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 820)",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Samsung Galaxy Note 3",
|
||||
width: 360,
|
||||
height: 640,
|
||||
pixelRatio: 3,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 4.3; en-us; SM-N900T Build/JSS15J) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Samsung Galaxy Note II",
|
||||
width: 360,
|
||||
height: 640,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 4.1; en-us; GT-N7100 Build/JRO03C) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Samsung Galaxy Note",
|
||||
width: 400,
|
||||
height: 640,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.3; en-us; SAMSUNG-SGH-I717 Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Samsung Galaxy S III, Galaxy Nexus",
|
||||
width: 360,
|
||||
height: 640,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 4.0; en-us; GT-I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Samsung Galaxy S, S II, W",
|
||||
width: 320,
|
||||
height: 533,
|
||||
pixelRatio: 1.5,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.1; en-us; GT-I9000 Build/ECLAIR) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Samsung Galaxy S4",
|
||||
width: 360,
|
||||
height: 640,
|
||||
pixelRatio: 3,
|
||||
userAgent: "Mozilla/5.0 (Linux; Android 4.2.2; GT-I9505 Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.59 Mobile Safari/537.36",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Sony Xperia S, Ion",
|
||||
width: 360,
|
||||
height: 640,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 4.0; en-us; LT28at Build/6.1.C.1.111) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Sony Xperia Sola, U",
|
||||
width: 480,
|
||||
height: 854,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.3; en-us; SonyEricssonST25i Build/6.0.B.1.564) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Sony Xperia Z, Z1",
|
||||
width: 360,
|
||||
height: 640,
|
||||
pixelRatio: 3,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 4.2; en-us; SonyC6903 Build/14.1.G.1.518) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30",
|
||||
touch: true,
|
||||
},
|
||||
],
|
||||
tablets: [
|
||||
{
|
||||
name: "Amazon Kindle Fire HDX 7″",
|
||||
width: 1920,
|
||||
height: 1200,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; en-us; KFTHWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Amazon Kindle Fire HDX 8.9″",
|
||||
width: 2560,
|
||||
height: 1600,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; en-us; KFAPWI Build/JDQ39) AppleWebKit/535.19 (KHTML, like Gecko) Silk/3.13 Safari/535.19 Silk-Accelerated=true",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Amazon Kindle Fire (First Generation)",
|
||||
width: 1024,
|
||||
height: 600,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_3; en-us; Silk/1.0.141.16-Gen4_11004310) AppleWebkit/533.16 (KHTML, like Gecko) Version/5.0 Safari/533.16 Silk-Accelerated=true",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Apple iPad 1 / 2 / iPad Mini",
|
||||
width: 1024,
|
||||
height: 768,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (iPad; CPU OS 4_3_5 like Mac OS X; en-us) AppleWebKit/533.17.9 (KHTML, like Gecko) Version/5.0.2 Mobile/8L1 Safari/6533.18.5",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Apple iPad 3 / 4",
|
||||
width: 1024,
|
||||
height: 768,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "BlackBerry PlayBook",
|
||||
width: 1024,
|
||||
height: 600,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML like Gecko) Version/7.2.1.0 Safari/536.2+",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Google Nexus 10",
|
||||
width: 1280,
|
||||
height: 800,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (Linux; Android 4.3; Nexus 10 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Google Nexus 7 2",
|
||||
width: 960,
|
||||
height: 600,
|
||||
pixelRatio: 2,
|
||||
userAgent: "Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Google Nexus 7",
|
||||
width: 966,
|
||||
height: 604,
|
||||
pixelRatio: 1.325,
|
||||
userAgent: "Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JSS15Q) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.72 Safari/537.36",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Motorola Xoom, Xyboard",
|
||||
width: 1280,
|
||||
height: 800,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Samsung Galaxy Tab 7.7, 8.9, 10.1",
|
||||
width: 1280,
|
||||
height: 800,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.2; en-us; SCH-I800 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Samsung Galaxy Tab",
|
||||
width: 1024,
|
||||
height: 600,
|
||||
pixelRatio: 1,
|
||||
userAgent: "Mozilla/5.0 (Linux; U; Android 2.2; en-us; SCH-I800 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1",
|
||||
touch: true,
|
||||
},
|
||||
],
|
||||
notebooks: [
|
||||
{
|
||||
name: "Notebook with touch",
|
||||
width: 1280,
|
||||
height: 950,
|
||||
pixelRatio: 1,
|
||||
userAgent: "",
|
||||
touch: true,
|
||||
},
|
||||
{
|
||||
name: "Notebook with HiDPI screen",
|
||||
width: 1440,
|
||||
height: 900,
|
||||
pixelRatio: 2,
|
||||
userAgent: "",
|
||||
touch: false,
|
||||
},
|
||||
{
|
||||
name: "Generic notebook",
|
||||
width: 1280,
|
||||
height: 800,
|
||||
pixelRatio: 1,
|
||||
userAgent: "",
|
||||
touch: false,
|
||||
},
|
||||
],
|
||||
televisions: [
|
||||
],
|
||||
watches: [
|
||||
],
|
||||
};
|
@ -48,6 +48,7 @@ EXTRA_JS_MODULES.devtools.shared.timeline += [
|
||||
EXTRA_JS_MODULES.devtools.shared += [
|
||||
'autocomplete-popup.js',
|
||||
'd3.js',
|
||||
'devices.js',
|
||||
'doorhanger.js',
|
||||
'frame-script-utils.js',
|
||||
'inplace-editor.js',
|
||||
|
@ -37,7 +37,6 @@ add_task(function*() {
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
function* testLivePreviewData(data, ruleView, selector) {
|
||||
let testElement = getNode(selector);
|
||||
let idRuleEditor = getRuleViewRuleEditor(ruleView, 1);
|
||||
@ -57,10 +56,13 @@ function* testLivePreviewData(data, ruleView, selector) {
|
||||
EventUtils.synthesizeKey("VK_RETURN", {});
|
||||
}
|
||||
|
||||
// This wait is an orange waiting to happen, but it might take a few event
|
||||
// loop spins in either the client or parent process before we see the
|
||||
// updated value.
|
||||
yield wait(1);
|
||||
// Wait for the modifyproperties request to complete before
|
||||
// checking the computed style.
|
||||
for (let rule of ruleView._elementStyle.rules) {
|
||||
if (rule._applyingModifications) {
|
||||
yield rule._applyingModifications;
|
||||
}
|
||||
}
|
||||
|
||||
// While the editor is still focused in, the display should have changed already
|
||||
is((yield getComputedStyleProperty(selector, null, "display")),
|
||||
|
@ -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/.
|
||||
|
||||
# LOCALIZATION NOTE These strings are used inside Device Emulation developer
|
||||
# tools. The correct localization of this file might be to keep it in English,
|
||||
# or another language commonly spoken among web developers. You want to make
|
||||
# that choice consistent across the developer tools. A good criteria is the
|
||||
# language in which you'd find the best documentation on web development on the
|
||||
# web.
|
||||
|
||||
# LOCALIZATION NOTE:
|
||||
# These strings are category names in a list of devices that a user can choose
|
||||
# to simulate (e.g. "ZTE Open C", "VIA Vixen", "720p HD Television", etc).
|
||||
device.phones=Phones
|
||||
device.tablets=Tablets
|
||||
device.notebooks=Notebooks
|
||||
device.televisions=TVs
|
||||
device.watches=Watches
|
@ -33,6 +33,7 @@
|
||||
locale/browser/devtools/appcacheutils.properties (%chrome/browser/devtools/appcacheutils.properties)
|
||||
locale/browser/devtools/debugger.dtd (%chrome/browser/devtools/debugger.dtd)
|
||||
locale/browser/devtools/debugger.properties (%chrome/browser/devtools/debugger.properties)
|
||||
locale/browser/devtools/device.properties (%chrome/browser/devtools/device.properties)
|
||||
locale/browser/devtools/netmonitor.dtd (%chrome/browser/devtools/netmonitor.dtd)
|
||||
locale/browser/devtools/netmonitor.properties (%chrome/browser/devtools/netmonitor.properties)
|
||||
locale/browser/devtools/shadereditor.dtd (%chrome/browser/devtools/shadereditor.dtd)
|
||||
|
@ -52,6 +52,7 @@
|
||||
#include "nsIAuthPrompt2.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
#include "nsIServiceWorkerManager.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsIScriptObjectPrincipal.h"
|
||||
#include "nsIScrollableFrame.h"
|
||||
@ -1041,6 +1042,7 @@ NS_INTERFACE_MAP_BEGIN(nsDocShell)
|
||||
NS_INTERFACE_MAP_ENTRY(nsILinkHandler)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIClipboardCommands)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMStorageManager)
|
||||
NS_INTERFACE_MAP_ENTRY(nsINetworkInterceptController)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDocLoader)
|
||||
|
||||
///*****************************************************************************
|
||||
@ -13921,6 +13923,52 @@ nsDocShell::MaybeNotifyKeywordSearchLoading(const nsString& aProvider,
|
||||
#endif
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::ShouldPrepareForIntercept(nsIURI* aURI, bool aIsNavigate, bool* aShouldIntercept)
|
||||
{
|
||||
*aShouldIntercept = false;
|
||||
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
|
||||
if (!swm) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (aIsNavigate) {
|
||||
return swm->IsAvailableForURI(aURI, aShouldIntercept);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = GetDocument();
|
||||
if (!doc) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return swm->IsControlled(doc, aShouldIntercept);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::ChannelIntercepted(nsIInterceptedChannel* aChannel)
|
||||
{
|
||||
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
|
||||
if (!swm) {
|
||||
aChannel->Cancel();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool isNavigation = false;
|
||||
nsresult rv = aChannel->GetIsNavigation(&isNavigation);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
|
||||
if (!isNavigation) {
|
||||
doc = GetDocument();
|
||||
if (!doc) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
}
|
||||
|
||||
return swm->DispatchFetchEvent(doc, aChannel);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::SetPaymentRequestId(const nsAString& aPaymentRequestId)
|
||||
{
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsIScrollable.h"
|
||||
#include "nsITextScroll.h"
|
||||
#include "nsIContentViewerContainer.h"
|
||||
@ -152,6 +153,7 @@ class nsDocShell MOZ_FINAL
|
||||
, public nsILinkHandler
|
||||
, public nsIClipboardCommands
|
||||
, public nsIDOMStorageManager
|
||||
, public nsINetworkInterceptController
|
||||
, public mozilla::SupportsWeakPtr<nsDocShell>
|
||||
{
|
||||
friend class nsDSURIContentListener;
|
||||
@ -182,6 +184,7 @@ public:
|
||||
NS_DECL_NSIAUTHPROMPTPROVIDER
|
||||
NS_DECL_NSICLIPBOARDCOMMANDS
|
||||
NS_DECL_NSIWEBSHELLSERVICES
|
||||
NS_DECL_NSINETWORKINTERCEPTCONTROLLER
|
||||
NS_FORWARD_SAFE_NSIDOMSTORAGEMANAGER(TopSessionStorageManager())
|
||||
|
||||
NS_IMETHOD Stop() MOZ_OVERRIDE {
|
||||
|
@ -622,7 +622,7 @@ protected:
|
||||
DECL_SHIM(nsIApplicationCacheContainer, NSIAPPLICATIONCACHECONTAINER)
|
||||
#undef DECL_SHIM
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Add an ExternalResource for aURI. aViewer and aLoadGroup might be null
|
||||
* when this is called if the URI didn't result in an XML document. This
|
||||
|
@ -106,7 +106,10 @@ using namespace mozilla::dom;
|
||||
#define XML_HTTP_REQUEST_HEADERS_RECEIVED (1 << 2) // 2 HEADERS_RECEIVED
|
||||
#define XML_HTTP_REQUEST_LOADING (1 << 3) // 3 LOADING
|
||||
#define XML_HTTP_REQUEST_DONE (1 << 4) // 4 DONE
|
||||
#define XML_HTTP_REQUEST_SENT (1 << 5) // Internal, OPENED in IE and external view
|
||||
#define XML_HTTP_REQUEST_SENT (1 << 5) // Internal, corresponds to
|
||||
// "OPENED and the send()
|
||||
// flag is set" in spec
|
||||
// terms.
|
||||
// The above states are mutually exclusive, change with ChangeState() only.
|
||||
// The states below can be combined.
|
||||
#define XML_HTTP_REQUEST_ABORTED (1 << 7) // Internal
|
||||
@ -1078,8 +1081,7 @@ nsXMLHttpRequest::GetResponseURL(nsAString& aUrl)
|
||||
{
|
||||
aUrl.Truncate();
|
||||
|
||||
uint16_t readyState;
|
||||
GetReadyState(&readyState);
|
||||
uint16_t readyState = ReadyState();
|
||||
if ((readyState == UNSENT || readyState == OPENED) || !mChannel) {
|
||||
return;
|
||||
}
|
||||
@ -3367,9 +3369,12 @@ nsXMLHttpRequest::SetWithCredentials(bool aWithCredentials)
|
||||
void
|
||||
nsXMLHttpRequest::SetWithCredentials(bool aWithCredentials, ErrorResult& aRv)
|
||||
{
|
||||
// Return error if we're already processing a request
|
||||
if (XML_HTTP_REQUEST_SENT & mState) {
|
||||
aRv = NS_ERROR_FAILURE;
|
||||
// Return error if we're already processing a request. Note that we can't use
|
||||
// ReadyState() here, because it can't differentiate between "opened" and
|
||||
// "sent", so we use mState directly.
|
||||
if (!(mState & XML_HTTP_REQUEST_UNSENT) &&
|
||||
!(mState & XML_HTTP_REQUEST_OPENED)) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -418,6 +418,14 @@ DOMInterfaces = {
|
||||
'nativeType': 'mozilla::dom::workers::ExtendableEvent',
|
||||
},
|
||||
|
||||
'FetchEvent': {
|
||||
'headerFile': 'ServiceWorkerEvents.h',
|
||||
'nativeType': 'mozilla::dom::workers::FetchEvent',
|
||||
'binaryNames': {
|
||||
'request': 'request_'
|
||||
},
|
||||
},
|
||||
|
||||
'FileList': {
|
||||
'headerFile': 'mozilla/dom/File.h',
|
||||
},
|
||||
|
@ -459,12 +459,45 @@ WebGL2Context::InvalidateSubFramebuffer(GLenum target, const dom::Sequence<GLenu
|
||||
void
|
||||
WebGL2Context::ReadBuffer(GLenum mode)
|
||||
{
|
||||
MOZ_CRASH("Not Implemented.");
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
if (mBoundReadFramebuffer) {
|
||||
bool isColorAttachment = (mode >= LOCAL_GL_COLOR_ATTACHMENT0 &&
|
||||
mode <= LastColorAttachment());
|
||||
if (mode != LOCAL_GL_NONE &&
|
||||
!isColorAttachment)
|
||||
{
|
||||
ErrorInvalidEnumInfo("readBuffer: If READ_FRAMEBUFFER is non-null,"
|
||||
" `mode` must be COLOR_ATTACHMENTN or NONE."
|
||||
" Was:", mode);
|
||||
return;
|
||||
}
|
||||
|
||||
gl->fReadBuffer(mode);
|
||||
return;
|
||||
}
|
||||
|
||||
// Operating on the default framebuffer.
|
||||
|
||||
if (mode != LOCAL_GL_NONE &&
|
||||
mode != LOCAL_GL_BACK)
|
||||
{
|
||||
ErrorInvalidEnumInfo("readBuffer: If READ_FRAMEBUFFER is null, `mode`"
|
||||
" must be BACK or NONE. Was:", mode);
|
||||
return;
|
||||
}
|
||||
|
||||
gl->Screen()->SetReadBuffer(mode);
|
||||
}
|
||||
|
||||
void
|
||||
WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples, GLenum internalformat,
|
||||
WebGL2Context::RenderbufferStorageMultisample(GLenum target, GLsizei samples,
|
||||
GLenum internalFormat,
|
||||
GLsizei width, GLsizei height)
|
||||
{
|
||||
MOZ_CRASH("Not Implemented.");
|
||||
RenderbufferStorage_base("renderbufferStorageMultisample", target, samples,
|
||||
internalFormat, width, height);
|
||||
}
|
||||
|
@ -203,6 +203,7 @@ WebGLContextOptions::WebGLContextOptions()
|
||||
WebGLContext::WebGLContext()
|
||||
: WebGLContextUnchecked(nullptr)
|
||||
, mBypassShaderValidation(false)
|
||||
, mGLMaxSamples(1)
|
||||
, mNeedsFakeNoAlpha(false)
|
||||
{
|
||||
mGeneration = 0;
|
||||
@ -1721,6 +1722,7 @@ WebGLContext::GetSurfaceSnapshot(bool* out_premultAlpha)
|
||||
{
|
||||
ScopedBindFramebuffer autoFB(gl, 0);
|
||||
ClearBackbufferIfNeeded();
|
||||
// TODO: Save, override, then restore glReadBuffer if present.
|
||||
ReadPixelsIntoDataSurface(gl, surf);
|
||||
}
|
||||
|
||||
|
@ -254,7 +254,9 @@ public:
|
||||
void ErrorInvalidOperation(const char* fmt = 0, ...);
|
||||
void ErrorInvalidValue(const char* fmt = 0, ...);
|
||||
void ErrorInvalidFramebufferOperation(const char* fmt = 0, ...);
|
||||
void ErrorInvalidEnumInfo(const char* info, GLenum enumvalue);
|
||||
void ErrorInvalidEnumInfo(const char* info, GLenum enumValue);
|
||||
void ErrorInvalidEnumInfo(const char* info, const char* funcName,
|
||||
GLenum enumValue);
|
||||
void ErrorOutOfMemory(const char* fmt = 0, ...);
|
||||
|
||||
const char* ErrorName(GLenum error);
|
||||
@ -531,6 +533,11 @@ public:
|
||||
ErrorResult& rv);
|
||||
void RenderbufferStorage(GLenum target, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height);
|
||||
protected:
|
||||
void RenderbufferStorage_base(const char* funcName, GLenum target,
|
||||
GLsizei samples, GLenum internalformat,
|
||||
GLsizei width, GLsizei height);
|
||||
public:
|
||||
void SampleCoverage(GLclampf value, WebGLboolean invert);
|
||||
void Scissor(GLint x, GLint y, GLsizei width, GLsizei height);
|
||||
void ShaderSource(WebGLShader* shader, const nsAString& source);
|
||||
@ -1146,8 +1153,9 @@ protected:
|
||||
int32_t mGLMaxVertexUniformVectors;
|
||||
int32_t mGLMaxColorAttachments;
|
||||
int32_t mGLMaxDrawBuffers;
|
||||
GLuint mGLMaxTransformFeedbackSeparateAttribs;
|
||||
uint32_t mGLMaxTransformFeedbackSeparateAttribs;
|
||||
GLuint mGLMaxUniformBufferBindings;
|
||||
GLsizei mGLMaxSamples;
|
||||
|
||||
public:
|
||||
GLuint MaxVertexAttribs() const {
|
||||
@ -1422,6 +1430,10 @@ protected:
|
||||
|
||||
uint32_t mMaxFramebufferColorAttachments;
|
||||
|
||||
GLenum LastColorAttachment() const {
|
||||
return LOCAL_GL_COLOR_ATTACHMENT0 + mMaxFramebufferColorAttachments - 1;
|
||||
}
|
||||
|
||||
bool ValidateFramebufferTarget(GLenum target, const char* const info);
|
||||
|
||||
WebGLRefPtr<WebGLFramebuffer> mBoundDrawFramebuffer;
|
||||
|
@ -1970,33 +1970,28 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
return rv.Throw(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
bool isSourceTypeFloat = false;
|
||||
if (mBoundReadFramebuffer &&
|
||||
mBoundReadFramebuffer->ColorAttachmentCount() &&
|
||||
mBoundReadFramebuffer->ColorAttachment(0).IsDefined())
|
||||
{
|
||||
isSourceTypeFloat = mBoundReadFramebuffer->ColorAttachment(0).IsReadableFloat();
|
||||
MakeContextCurrent();
|
||||
|
||||
bool isSourceTypeFloat;
|
||||
if (mBoundReadFramebuffer) {
|
||||
TexInternalFormat srcFormat;
|
||||
if (!mBoundReadFramebuffer->ValidateForRead("readPixels", &srcFormat))
|
||||
return;
|
||||
|
||||
MOZ_ASSERT(srcFormat != LOCAL_GL_NONE);
|
||||
TexType type = TypeFromInternalFormat(srcFormat);
|
||||
isSourceTypeFloat = (type == LOCAL_GL_FLOAT ||
|
||||
type == LOCAL_GL_HALF_FLOAT);
|
||||
} else {
|
||||
ClearBackbufferIfNeeded();
|
||||
|
||||
isSourceTypeFloat = false;
|
||||
}
|
||||
|
||||
if (isReadTypeFloat != isSourceTypeFloat)
|
||||
return ErrorInvalidOperation("readPixels: Invalid type floatness");
|
||||
|
||||
// Check the format and type params to assure they are an acceptable pair (as per spec)
|
||||
MakeContextCurrent();
|
||||
|
||||
if (mBoundReadFramebuffer) {
|
||||
// prevent readback of arbitrary video memory through uninitialized renderbuffers!
|
||||
if (!mBoundReadFramebuffer->CheckAndInitializeAttachments())
|
||||
return ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
|
||||
|
||||
GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
|
||||
if (!mBoundReadFramebuffer->HasCompletePlanes(readPlaneBits)) {
|
||||
return ErrorInvalidOperation("readPixels: Read source attachment doesn't have the"
|
||||
" correct color/depth/stencil type.");
|
||||
}
|
||||
} else {
|
||||
ClearBackbufferIfNeeded();
|
||||
}
|
||||
|
||||
bool isFormatAndTypeValid = false;
|
||||
|
||||
@ -2128,95 +2123,156 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::RenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height)
|
||||
WebGLContext::RenderbufferStorage_base(const char* funcName, GLenum target,
|
||||
GLsizei samples,
|
||||
GLenum internalFormat, GLsizei width,
|
||||
GLsizei height)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
if (!mBoundRenderbuffer)
|
||||
return ErrorInvalidOperation("renderbufferStorage called on renderbuffer 0");
|
||||
if (!mBoundRenderbuffer) {
|
||||
ErrorInvalidOperation("%s: Called on renderbuffer 0.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (target != LOCAL_GL_RENDERBUFFER)
|
||||
return ErrorInvalidEnumInfo("renderbufferStorage: target", target);
|
||||
if (target != LOCAL_GL_RENDERBUFFER) {
|
||||
ErrorInvalidEnumInfo("`target`", funcName, target);
|
||||
return;
|
||||
}
|
||||
|
||||
if (width < 0 || height < 0)
|
||||
return ErrorInvalidValue("renderbufferStorage: width and height must be >= 0");
|
||||
if (samples < 0 || samples > mGLMaxSamples) {
|
||||
ErrorInvalidValue("%s: `samples` is out of the valid range.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (width > mGLMaxRenderbufferSize || height > mGLMaxRenderbufferSize)
|
||||
return ErrorInvalidValue("renderbufferStorage: width or height exceeds maximum renderbuffer size");
|
||||
if (width < 0 || height < 0) {
|
||||
ErrorInvalidValue("%s: Width and height must be >= 0.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (width > mGLMaxRenderbufferSize || height > mGLMaxRenderbufferSize) {
|
||||
ErrorInvalidValue("%s: Width or height exceeds maximum renderbuffer"
|
||||
" size.", funcName);
|
||||
return;
|
||||
}
|
||||
|
||||
bool isFormatValid = false;
|
||||
switch (internalFormat) {
|
||||
case LOCAL_GL_RGBA4:
|
||||
case LOCAL_GL_RGB5_A1:
|
||||
case LOCAL_GL_RGB565:
|
||||
case LOCAL_GL_DEPTH_COMPONENT16:
|
||||
case LOCAL_GL_STENCIL_INDEX8:
|
||||
case LOCAL_GL_DEPTH_STENCIL:
|
||||
isFormatValid = true;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_SRGB8_ALPHA8_EXT:
|
||||
if (IsExtensionEnabled(WebGLExtensionID::EXT_sRGB))
|
||||
isFormatValid = true;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_RGB16F:
|
||||
case LOCAL_GL_RGBA16F:
|
||||
if (IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float) &&
|
||||
IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float))
|
||||
{
|
||||
isFormatValid = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case LOCAL_GL_RGB32F:
|
||||
case LOCAL_GL_RGBA32F:
|
||||
if (IsExtensionEnabled(WebGLExtensionID::OES_texture_float) &&
|
||||
IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float))
|
||||
{
|
||||
isFormatValid = true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (!isFormatValid) {
|
||||
ErrorInvalidEnumInfo("`internalFormat`", funcName, internalFormat);
|
||||
return;
|
||||
}
|
||||
|
||||
// certain OpenGL ES renderbuffer formats may not exist on desktop OpenGL
|
||||
GLenum internalformatForGL = internalformat;
|
||||
GLenum internalFormatForGL = internalFormat;
|
||||
|
||||
switch (internalformat) {
|
||||
switch (internalFormat) {
|
||||
case LOCAL_GL_RGBA4:
|
||||
case LOCAL_GL_RGB5_A1:
|
||||
// 16-bit RGBA formats are not supported on desktop GL
|
||||
if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGBA8;
|
||||
if (!gl->IsGLES())
|
||||
internalFormatForGL = LOCAL_GL_RGBA8;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_RGB565:
|
||||
// the RGB565 format is not supported on desktop GL
|
||||
if (!gl->IsGLES()) internalformatForGL = LOCAL_GL_RGB8;
|
||||
if (!gl->IsGLES())
|
||||
internalFormatForGL = LOCAL_GL_RGB8;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_DEPTH_COMPONENT16:
|
||||
if (!gl->IsGLES() || gl->IsExtensionSupported(gl::GLContext::OES_depth24))
|
||||
internalformatForGL = LOCAL_GL_DEPTH_COMPONENT24;
|
||||
internalFormatForGL = LOCAL_GL_DEPTH_COMPONENT24;
|
||||
else if (gl->IsExtensionSupported(gl::GLContext::OES_packed_depth_stencil))
|
||||
internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
case LOCAL_GL_STENCIL_INDEX8:
|
||||
internalFormatForGL = LOCAL_GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_DEPTH_STENCIL:
|
||||
// We emulate this in WebGLRenderbuffer if we don't have the requisite extension.
|
||||
internalformatForGL = LOCAL_GL_DEPTH24_STENCIL8;
|
||||
internalFormatForGL = LOCAL_GL_DEPTH24_STENCIL8;
|
||||
break;
|
||||
case LOCAL_GL_SRGB8_ALPHA8_EXT:
|
||||
break;
|
||||
case LOCAL_GL_RGB16F:
|
||||
case LOCAL_GL_RGBA16F: {
|
||||
bool hasExtensions = IsExtensionEnabled(WebGLExtensionID::OES_texture_half_float) &&
|
||||
IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float);
|
||||
if (!hasExtensions)
|
||||
return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
|
||||
break;
|
||||
}
|
||||
case LOCAL_GL_RGB32F:
|
||||
case LOCAL_GL_RGBA32F: {
|
||||
bool hasExtensions = IsExtensionEnabled(WebGLExtensionID::OES_texture_float) &&
|
||||
IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float);
|
||||
if (!hasExtensions)
|
||||
return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return ErrorInvalidEnumInfo("renderbufferStorage: internalformat", internalformat);
|
||||
break;
|
||||
}
|
||||
|
||||
// Validation complete.
|
||||
|
||||
MakeContextCurrent();
|
||||
|
||||
bool sizeChanges = width != mBoundRenderbuffer->Width() ||
|
||||
height != mBoundRenderbuffer->Height() ||
|
||||
internalformat != mBoundRenderbuffer->InternalFormat();
|
||||
if (sizeChanges) {
|
||||
bool willRealloc = samples != mBoundRenderbuffer->Samples() ||
|
||||
internalFormat != mBoundRenderbuffer->InternalFormat() ||
|
||||
width != mBoundRenderbuffer->Width() ||
|
||||
height != mBoundRenderbuffer->Height();
|
||||
|
||||
if (willRealloc) {
|
||||
// Invalidate framebuffer status cache
|
||||
mBoundRenderbuffer->NotifyFBsStatusChanged();
|
||||
GetAndFlushUnderlyingGLErrors();
|
||||
mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height);
|
||||
mBoundRenderbuffer->RenderbufferStorage(samples, internalFormatForGL,
|
||||
width, height);
|
||||
GLenum error = GetAndFlushUnderlyingGLErrors();
|
||||
if (error) {
|
||||
GenerateWarning("renderbufferStorage generated error %s", ErrorName(error));
|
||||
GenerateWarning("%s generated error %s", funcName,
|
||||
ErrorName(error));
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
mBoundRenderbuffer->RenderbufferStorage(internalformatForGL, width, height);
|
||||
mBoundRenderbuffer->RenderbufferStorage(samples, internalFormatForGL,
|
||||
width, height);
|
||||
}
|
||||
|
||||
mBoundRenderbuffer->SetInternalFormat(internalformat);
|
||||
mBoundRenderbuffer->SetInternalFormatForGL(internalformatForGL);
|
||||
mBoundRenderbuffer->SetSamples(samples);
|
||||
mBoundRenderbuffer->SetInternalFormat(internalFormat);
|
||||
mBoundRenderbuffer->SetInternalFormatForGL(internalFormatForGL);
|
||||
mBoundRenderbuffer->setDimensions(width, height);
|
||||
mBoundRenderbuffer->SetImageDataStatus(WebGLImageDataStatus::UninitializedImageData);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::RenderbufferStorage(GLenum target, GLenum internalFormat, GLsizei width, GLsizei height)
|
||||
{
|
||||
RenderbufferStorage_base("renderbufferStorage", target, 0,
|
||||
internalFormat, width, height);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::Scissor(GLint x, GLint y, GLsizei width, GLsizei height)
|
||||
{
|
||||
|
@ -501,12 +501,23 @@ WebGLContext::ErrorInvalidEnum(const char* fmt, ...)
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::ErrorInvalidEnumInfo(const char* info, GLenum enumvalue)
|
||||
WebGLContext::ErrorInvalidEnumInfo(const char* info, GLenum enumValue)
|
||||
{
|
||||
nsCString name;
|
||||
EnumName(enumvalue, &name);
|
||||
EnumName(enumValue, &name);
|
||||
|
||||
return ErrorInvalidEnum("%s: invalid enum value %s", info, name.get());
|
||||
return ErrorInvalidEnum("%s: invalid enum value %s", info, name.BeginReading());
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::ErrorInvalidEnumInfo(const char* info, const char* funcName,
|
||||
GLenum enumValue)
|
||||
{
|
||||
nsCString name;
|
||||
EnumName(enumValue, &name);
|
||||
|
||||
ErrorInvalidEnum("%s: %s: Invalid enum: 0x%04x (%s).", funcName, info,
|
||||
enumValue, name.BeginReading());
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1286,25 +1286,11 @@ WebGLContext::ValidateCopyTexImage(GLenum format, WebGLTexImageFunc func,
|
||||
GLenum fboFormat = mOptions.alpha ? LOCAL_GL_RGBA : LOCAL_GL_RGB;
|
||||
|
||||
if (mBoundReadFramebuffer) {
|
||||
if (!mBoundReadFramebuffer->CheckAndInitializeAttachments()) {
|
||||
ErrorInvalidFramebufferOperation("%s: Incomplete framebuffer.",
|
||||
InfoFrom(func, dims));
|
||||
TexInternalFormat srcFormat;
|
||||
if (!mBoundReadFramebuffer->ValidateForRead(InfoFrom(func, dims), &srcFormat))
|
||||
return false;
|
||||
}
|
||||
|
||||
GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
|
||||
if (!mBoundReadFramebuffer->HasCompletePlanes(readPlaneBits)) {
|
||||
ErrorInvalidOperation("%s: Read source attachment doesn't have the"
|
||||
" correct color/depth/stencil type.",
|
||||
InfoFrom(func, dims));
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the correct format for the framebuffer, as it's not the default one.
|
||||
const WebGLFramebuffer::Attachment& color0 =
|
||||
mBoundReadFramebuffer->GetAttachment(LOCAL_GL_COLOR_ATTACHMENT0);
|
||||
|
||||
fboFormat = mBoundReadFramebuffer->GetFormatForAttachment(color0);
|
||||
fboFormat = srcFormat.get();
|
||||
}
|
||||
|
||||
// Make sure the format of the framebuffer is a superset of the format
|
||||
@ -1818,12 +1804,16 @@ WebGLContext::InitAndValidateGL()
|
||||
mGLMaxRenderbufferSize = MINVALUE_GL_MAX_RENDERBUFFER_SIZE;
|
||||
mGLMaxTextureImageUnits = MINVALUE_GL_MAX_TEXTURE_IMAGE_UNITS;
|
||||
mGLMaxVertexTextureImageUnits = MINVALUE_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS;
|
||||
mGLMaxSamples = 1;
|
||||
} else {
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mGLMaxTextureSize);
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mGLMaxCubeMapTextureSize);
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mGLMaxRenderbufferSize);
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_TEXTURE_IMAGE_UNITS, &mGLMaxTextureImageUnits);
|
||||
gl->fGetIntegerv(LOCAL_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &mGLMaxVertexTextureImageUnits);
|
||||
|
||||
if (!gl->GetPotentialInteger(LOCAL_GL_MAX_SAMPLES, (GLint*)&mGLMaxSamples))
|
||||
mGLMaxSamples = 1;
|
||||
}
|
||||
|
||||
// Calculate log2 of mGLMaxTextureSize and mGLMaxCubeMapTextureSize
|
||||
|
@ -28,6 +28,7 @@ WebGLFramebuffer::WebGLFramebuffer(WebGLContext* webgl, GLuint fbo)
|
||||
, mDepthAttachment(LOCAL_GL_DEPTH_ATTACHMENT)
|
||||
, mStencilAttachment(LOCAL_GL_STENCIL_ATTACHMENT)
|
||||
, mDepthStencilAttachment(LOCAL_GL_DEPTH_STENCIL_ATTACHMENT)
|
||||
, mReadBufferMode(LOCAL_GL_COLOR_ATTACHMENT0)
|
||||
{
|
||||
mContext->mFramebuffers.insertBack(this);
|
||||
|
||||
@ -977,6 +978,38 @@ WebGLFramebuffer::FinalizeAttachments() const
|
||||
FinalizeDrawAndReadBuffers(gl, ColorAttachment(0).IsDefined());
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLFramebuffer::ValidateForRead(const char* info, TexInternalFormat* const out_format)
|
||||
{
|
||||
if (mReadBufferMode == LOCAL_GL_NONE) {
|
||||
mContext->ErrorInvalidOperation("%s: Read buffer mode must not be"
|
||||
" NONE.", info);
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto& attachment = GetAttachment(mReadBufferMode);
|
||||
|
||||
if (!CheckAndInitializeAttachments()) {
|
||||
mContext->ErrorInvalidFramebufferOperation("readPixels: incomplete framebuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
GLenum readPlaneBits = LOCAL_GL_COLOR_BUFFER_BIT;
|
||||
if (!HasCompletePlanes(readPlaneBits)) {
|
||||
mContext->ErrorInvalidOperation("readPixels: Read source attachment doesn't have the"
|
||||
" correct color/depth/stencil type.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!attachment.IsDefined()) {
|
||||
mContext->ErrorInvalidOperation("readPixels: ");
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_format = attachment.EffectiveInternalFormat();
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void
|
||||
ImplCycleCollectionUnlink(mozilla::WebGLFramebuffer::Attachment& field)
|
||||
{
|
||||
|
@ -174,6 +174,8 @@ public:
|
||||
|
||||
void NotifyAttachableChanged() const;
|
||||
|
||||
bool ValidateForRead(const char* info, TexInternalFormat* const out_format);
|
||||
|
||||
private:
|
||||
~WebGLFramebuffer() {
|
||||
DeleteOnce();
|
||||
@ -187,6 +189,7 @@ private:
|
||||
Attachment mDepthAttachment;
|
||||
Attachment mStencilAttachment;
|
||||
Attachment mDepthStencilAttachment;
|
||||
GLenum mReadBufferMode;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -54,6 +54,7 @@ WebGLRenderbuffer::WebGLRenderbuffer(WebGLContext* webgl)
|
||||
, mInternalFormat(0)
|
||||
, mInternalFormatForGL(0)
|
||||
, mImageDataStatus(WebGLImageDataStatus::NoImageData)
|
||||
, mSamples(1)
|
||||
{
|
||||
mContext->MakeContextCurrent();
|
||||
|
||||
@ -156,11 +157,30 @@ WebGLRenderbuffer::BindRenderbuffer() const
|
||||
mContext->gl->fBindRenderbuffer(LOCAL_GL_RENDERBUFFER, mPrimaryRB);
|
||||
}
|
||||
|
||||
static void
|
||||
RenderbufferStorageMaybeMultisample(gl::GLContext* gl, GLsizei samples,
|
||||
GLenum internalFormat, GLsizei width,
|
||||
GLsizei height)
|
||||
{
|
||||
MOZ_ASSERT_IF(samples >= 1, gl->IsSupported(gl::GLFeature::framebuffer_multisample));
|
||||
MOZ_ASSERT(samples >= 0);
|
||||
MOZ_ASSERT(samples <= gl->MaxSamples());
|
||||
|
||||
if (samples > 0) {
|
||||
gl->fRenderbufferStorageMultisample(LOCAL_GL_RENDERBUFFER, samples,
|
||||
internalFormat, width, height);
|
||||
} else {
|
||||
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, internalFormat, width,
|
||||
height);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLRenderbuffer::RenderbufferStorage(GLenum internalFormat, GLsizei width,
|
||||
GLsizei height) const
|
||||
WebGLRenderbuffer::RenderbufferStorage(GLsizei samples, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height) const
|
||||
{
|
||||
gl::GLContext* gl = mContext->gl;
|
||||
MOZ_ASSERT(samples >= 0 && samples <= 256); // Sanity check.
|
||||
|
||||
GLenum primaryFormat = internalFormat;
|
||||
GLenum secondaryFormat = 0;
|
||||
@ -170,7 +190,8 @@ WebGLRenderbuffer::RenderbufferStorage(GLenum internalFormat, GLsizei width,
|
||||
secondaryFormat = LOCAL_GL_STENCIL_INDEX8;
|
||||
}
|
||||
|
||||
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, primaryFormat, width, height);
|
||||
RenderbufferStorageMaybeMultisample(gl, samples, primaryFormat, width,
|
||||
height);
|
||||
|
||||
if (!mSecondaryRB) {
|
||||
MOZ_ASSERT(!secondaryFormat);
|
||||
@ -182,9 +203,10 @@ WebGLRenderbuffer::RenderbufferStorage(GLenum internalFormat, GLsizei width,
|
||||
// non-depth-stencil attachment point.
|
||||
gl::ScopedBindRenderbuffer autoRB(gl, mSecondaryRB);
|
||||
if (secondaryFormat) {
|
||||
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, secondaryFormat, width, height);
|
||||
RenderbufferStorageMaybeMultisample(gl, samples, secondaryFormat, width,
|
||||
height);
|
||||
} else {
|
||||
gl->fRenderbufferStorage(LOCAL_GL_RENDERBUFFER, LOCAL_GL_RGBA4, 1, 1);
|
||||
RenderbufferStorageMaybeMultisample(gl, samples, LOCAL_GL_RGBA4, 1, 1);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,9 @@ public:
|
||||
mImageDataStatus = x;
|
||||
}
|
||||
|
||||
GLsizei Samples() const { return mSamples; }
|
||||
void SetSamples(GLsizei samples) { mSamples = samples; }
|
||||
|
||||
GLenum InternalFormat() const { return mInternalFormat; }
|
||||
void SetInternalFormat(GLenum internalFormat) {
|
||||
mInternalFormat = internalFormat;
|
||||
@ -55,8 +58,8 @@ public:
|
||||
}
|
||||
|
||||
void BindRenderbuffer() const;
|
||||
void RenderbufferStorage(GLenum internalFormat, GLsizei width,
|
||||
GLsizei height) const;
|
||||
void RenderbufferStorage(GLsizei samples, GLenum internalFormat,
|
||||
GLsizei width, GLsizei height) const;
|
||||
void FramebufferRenderbuffer(FBAttachment attachment) const;
|
||||
// Only handles a subset of `pname`s.
|
||||
GLint GetRenderbufferParameter(RBTarget target, RBParam pname) const;
|
||||
@ -76,6 +79,7 @@ protected:
|
||||
GLenum mInternalFormat;
|
||||
GLenum mInternalFormatForGL;
|
||||
WebGLImageDataStatus mImageDataStatus;
|
||||
GLsizei mSamples;
|
||||
|
||||
friend class WebGLFramebuffer;
|
||||
};
|
||||
|
@ -866,6 +866,11 @@ FetchBody<Request>::FetchBody();
|
||||
template
|
||||
FetchBody<Response>::FetchBody();
|
||||
|
||||
template <class Derived>
|
||||
FetchBody<Derived>::~FetchBody()
|
||||
{
|
||||
}
|
||||
|
||||
// Returns true if addref succeeded.
|
||||
// Always succeeds on main thread.
|
||||
// May fail on worker if RegisterFeature() fails. In that case, it will release
|
||||
|
@ -135,6 +135,12 @@ public:
|
||||
void
|
||||
CancelPump();
|
||||
|
||||
void
|
||||
SetBodyUsed()
|
||||
{
|
||||
mBodyUsed = true;
|
||||
}
|
||||
|
||||
// Always set whenever the FetchBody is created on the worker thread.
|
||||
workers::WorkerPrivate* mWorkerPrivate;
|
||||
|
||||
@ -145,15 +151,7 @@ public:
|
||||
protected:
|
||||
FetchBody();
|
||||
|
||||
virtual ~FetchBody()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
SetBodyUsed()
|
||||
{
|
||||
mBodyUsed = true;
|
||||
}
|
||||
virtual ~FetchBody();
|
||||
|
||||
void
|
||||
SetMimeType(ErrorResult& aRv);
|
||||
|
@ -2,7 +2,6 @@
|
||||
"WeakMap.prototype.clear.length": true,
|
||||
"WeakMap.prototype.delete.length": true,
|
||||
"WeakMap.prototype.get.length": true,
|
||||
"WeakMap.prototype.get: return undefined": true,
|
||||
"WeakMap.prototype.has.length": true,
|
||||
"WeakMap.prototype.set.length": true
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "domstubs.idl"
|
||||
|
||||
interface nsIDocument;
|
||||
interface nsIInterceptedChannel;
|
||||
interface nsIPrincipal;
|
||||
interface nsIURI;
|
||||
|
||||
@ -18,7 +19,7 @@ interface nsIServiceWorkerUnregisterCallback : nsISupports
|
||||
[noscript] void UnregisterFailed();
|
||||
};
|
||||
|
||||
[builtinclass, uuid(861b55e9-d6ac-47cf-a528-8590e9b44de6)]
|
||||
[builtinclass, uuid(464882c8-81c0-4620-b9c4-44c12085b65b)]
|
||||
interface nsIServiceWorkerManager : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -51,6 +52,15 @@ interface nsIServiceWorkerManager : nsISupports
|
||||
// Remove ready pending Promise
|
||||
void removeReadyPromise(in nsIDOMWindow aWindow);
|
||||
|
||||
// Returns true if a ServiceWorker is available for the scope of aURI.
|
||||
bool isAvailableForURI(in nsIURI aURI);
|
||||
|
||||
// Returns true if a given document is currently controlled by a ServiceWorker
|
||||
bool isControlled(in nsIDocument aDocument);
|
||||
|
||||
// Cause a fetch event to be dispatched to the worker global associated with the given document.
|
||||
void dispatchFetchEvent(in nsIDocument aDoc, in nsIInterceptedChannel aChannel);
|
||||
|
||||
// aTarget MUST be a ServiceWorkerRegistration.
|
||||
[noscript] void AddRegistrationEventListener(in DOMString aScope, in nsIDOMEventTarget aTarget);
|
||||
[noscript] void RemoveRegistrationEventListener(in DOMString aScope, in nsIDOMEventTarget aTarget);
|
||||
|
@ -13,7 +13,6 @@
|
||||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "mozilla/ipc/InputStreamUtils.h"
|
||||
|
||||
using namespace base;
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::jsipc;
|
||||
|
||||
|
@ -9,7 +9,6 @@
|
||||
#include "mozilla/jsipc/CrossProcessObjectWrappers.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
using namespace base;
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::jsipc;
|
||||
|
||||
|
@ -172,7 +172,6 @@
|
||||
#include "mozilla/net/NeckoMessageUtils.h"
|
||||
#include "mozilla/RemoteSpellCheckEngineChild.h"
|
||||
|
||||
using namespace base;
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::docshell;
|
||||
using namespace mozilla::dom::bluetooth;
|
||||
|
@ -17,8 +17,6 @@
|
||||
#include "nsThreadUtils.h"
|
||||
#endif
|
||||
|
||||
using namespace base;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -64,7 +64,7 @@ AppleDecoderModule::Init()
|
||||
bool haveVideoToolbox = AppleVTLinker::Link();
|
||||
sIsVTAvailable = haveCoreMedia && haveVideoToolbox;
|
||||
|
||||
sIsVTHWAvailable = AppleVTLinker::skPropHWAccel != nullptr;
|
||||
sIsVTHWAvailable = AppleVTLinker::skPropEnableHWAccel != nullptr;
|
||||
|
||||
if (sIsVDAAvailable) {
|
||||
AppleVDALinker::Unlink();
|
||||
|
@ -305,6 +305,20 @@ AppleVTDecoder::InitializeSession()
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (AppleVTLinker::skPropUsingHWAccel) {
|
||||
CFBooleanRef isUsingHW = nullptr;
|
||||
rv = VTSessionCopyProperty(mSession,
|
||||
AppleVTLinker::skPropUsingHWAccel,
|
||||
kCFAllocatorDefault,
|
||||
&isUsingHW);
|
||||
if (rv != noErr) {
|
||||
LOG("AppleVTDecoder: system doesn't support hardware acceleration");
|
||||
}
|
||||
LOG("AppleVTDecoder: %s hardware accelerated decoding",
|
||||
(rv == noErr && isUsingHW == kCFBooleanTrue) ? "using" : "not using");
|
||||
} else {
|
||||
LOG("AppleVTDecoder: couldn't determine hardware acceleration status.");
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -356,11 +370,11 @@ AppleVTDecoder::CreateDecoderExtensions()
|
||||
CFDictionaryRef
|
||||
AppleVTDecoder::CreateDecoderSpecification()
|
||||
{
|
||||
if (!AppleVTLinker::skPropHWAccel) {
|
||||
if (!AppleVTLinker::skPropEnableHWAccel) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const void* specKeys[] = { AppleVTLinker::skPropHWAccel };
|
||||
const void* specKeys[] = { AppleVTLinker::skPropEnableHWAccel };
|
||||
const void* specValues[] = { kCFBooleanTrue };
|
||||
static_assert(ArrayLength(specKeys) == ArrayLength(specValues),
|
||||
"Non matching keys/values array size");
|
||||
|
@ -10,3 +10,5 @@ LINK_FUNC(VTDecompressionSessionCreate)
|
||||
LINK_FUNC(VTDecompressionSessionDecodeFrame)
|
||||
LINK_FUNC(VTDecompressionSessionInvalidate)
|
||||
LINK_FUNC(VTDecompressionSessionWaitForAsynchronousFrames)
|
||||
LINK_FUNC(VTSessionCopyProperty)
|
||||
LINK_FUNC(VTSessionCopySupportedPropertyDictionary)
|
||||
|
@ -25,7 +25,8 @@ AppleVTLinker::sLinkStatus = LinkStatus_INIT;
|
||||
|
||||
void* AppleVTLinker::sLink = nullptr;
|
||||
nsrefcnt AppleVTLinker::sRefCount = 0;
|
||||
CFStringRef AppleVTLinker::skPropHWAccel = nullptr;
|
||||
CFStringRef AppleVTLinker::skPropEnableHWAccel = nullptr;
|
||||
CFStringRef AppleVTLinker::skPropUsingHWAccel = nullptr;
|
||||
|
||||
#define LINK_FUNC(func) typeof(func) func;
|
||||
#include "AppleVTFunctions.h"
|
||||
@ -69,8 +70,10 @@ AppleVTLinker::Link()
|
||||
#undef LINK_FUNC
|
||||
|
||||
// Will only resolve in 10.9 and later.
|
||||
skPropHWAccel =
|
||||
skPropEnableHWAccel =
|
||||
GetIOConst("kVTVideoDecoderSpecification_EnableHardwareAcceleratedVideoDecoder");
|
||||
skPropUsingHWAccel =
|
||||
GetIOConst("kVTDecompressionPropertyKey_UsingHardwareAcceleratedVideoDecoder");
|
||||
|
||||
LOG("Loaded VideoToolbox framework.");
|
||||
sLinkStatus = LinkStatus_SUCCEEDED;
|
||||
@ -97,7 +100,8 @@ AppleVTLinker::Unlink()
|
||||
LOG("Unlinking VideoToolbox framework.");
|
||||
dlclose(sLink);
|
||||
sLink = nullptr;
|
||||
skPropHWAccel = nullptr;
|
||||
skPropEnableHWAccel = nullptr;
|
||||
skPropUsingHWAccel = nullptr;
|
||||
sLinkStatus = LinkStatus_INIT;
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,8 @@ class AppleVTLinker
|
||||
public:
|
||||
static bool Link();
|
||||
static void Unlink();
|
||||
static CFStringRef skPropHWAccel;
|
||||
static CFStringRef skPropEnableHWAccel;
|
||||
static CFStringRef skPropUsingHWAccel;
|
||||
|
||||
private:
|
||||
static void* sLink;
|
||||
|
@ -26,6 +26,7 @@ enum {
|
||||
kVTDecodeInfo_FrameDropped = 1UL << 1,
|
||||
};
|
||||
|
||||
typedef CFTypeRef VTSessionRef;
|
||||
typedef struct OpaqueVTDecompressionSession* VTDecompressionSessionRef;
|
||||
typedef void (*VTDecompressionOutputCallback)(
|
||||
void*,
|
||||
@ -70,4 +71,18 @@ VTDecompressionSessionInvalidate(
|
||||
VTDecompressionSessionRef
|
||||
);
|
||||
|
||||
OSStatus
|
||||
VTSessionCopyProperty(
|
||||
VTSessionRef,
|
||||
CFStringRef,
|
||||
CFAllocatorRef,
|
||||
void*
|
||||
);
|
||||
|
||||
OSStatus
|
||||
VTSessionCopySupportedPropertyDictionary(
|
||||
VTSessionRef,
|
||||
CFDictionaryRef*
|
||||
);
|
||||
|
||||
#endif // mozilla_VideoToolbox_VideoToolbox_h
|
||||
|
27
dom/webidl/FetchEvent.webidl
Normal file
27
dom/webidl/FetchEvent.webidl
Normal file
@ -0,0 +1,27 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* 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/.
|
||||
*
|
||||
* For more information on this interface, please see
|
||||
* http://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html
|
||||
*/
|
||||
|
||||
[Constructor(DOMString type, optional FetchEventInit eventInitDict),
|
||||
Func="mozilla::dom::workers::ServiceWorkerVisible",
|
||||
Exposed=(ServiceWorker)]
|
||||
interface FetchEvent : Event {
|
||||
readonly attribute Request request;
|
||||
readonly attribute ServiceWorkerClient client; // The window issuing the request.
|
||||
readonly attribute boolean isReload;
|
||||
|
||||
[Throws] void respondWith(Promise<Response> r);
|
||||
Promise<Response> forwardTo(USVString url);
|
||||
Promise<Response> default();
|
||||
};
|
||||
|
||||
dictionary FetchEventInit : EventInit {
|
||||
Request request;
|
||||
ServiceWorkerClient client;
|
||||
boolean isReload;
|
||||
};
|
@ -132,6 +132,7 @@ WEBIDL_FILES = [
|
||||
'EventTarget.webidl',
|
||||
'ExtendableEvent.webidl',
|
||||
'Fetch.webidl',
|
||||
'FetchEvent.webidl',
|
||||
'File.webidl',
|
||||
'FileList.webidl',
|
||||
'FileMode.webidl',
|
||||
|
@ -5,9 +5,20 @@
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "ServiceWorkerEvents.h"
|
||||
#include "ServiceWorkerClient.h"
|
||||
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsIOutputStream.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsNetCID.h"
|
||||
|
||||
#include "mozilla/dom/FetchEventBinding.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/Request.h"
|
||||
#include "mozilla/dom/Response.h"
|
||||
#include "mozilla/dom/WorkerScope.h"
|
||||
#include "mozilla/dom/workers/bindings/ServiceWorker.h"
|
||||
|
||||
@ -15,6 +26,271 @@ using namespace mozilla::dom;
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
FetchEvent::FetchEvent(EventTarget* aOwner)
|
||||
: Event(aOwner, nullptr, nullptr)
|
||||
, mWindowId(0)
|
||||
, mIsReload(false)
|
||||
, mWaitToRespond(false)
|
||||
{
|
||||
}
|
||||
|
||||
FetchEvent::~FetchEvent()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
FetchEvent::PostInit(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
|
||||
uint64_t aWindowId)
|
||||
{
|
||||
mChannel = aChannel;
|
||||
mServiceWorker = aServiceWorker;
|
||||
mWindowId = aWindowId;
|
||||
}
|
||||
|
||||
/*static*/ already_AddRefed<FetchEvent>
|
||||
FetchEvent::Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const FetchEventInit& aOptions,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsRefPtr<EventTarget> owner = do_QueryObject(aGlobal.GetAsSupports());
|
||||
MOZ_ASSERT(owner);
|
||||
nsRefPtr<FetchEvent> e = new FetchEvent(owner);
|
||||
bool trusted = e->Init(owner);
|
||||
e->InitEvent(aType, aOptions.mBubbles, aOptions.mCancelable);
|
||||
e->SetTrusted(trusted);
|
||||
e->mRequest = aOptions.mRequest.WasPassed() ?
|
||||
&aOptions.mRequest.Value() : nullptr;
|
||||
e->mIsReload = aOptions.mIsReload.WasPassed() ?
|
||||
aOptions.mIsReload.Value() : false;
|
||||
e->mClient = aOptions.mClient.WasPassed() ?
|
||||
&aOptions.mClient.Value() : nullptr;
|
||||
return e.forget();
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
class CancelChannelRunnable MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
|
||||
public:
|
||||
explicit CancelChannelRunnable(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel)
|
||||
: mChannel(aChannel)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsresult rv = mChannel->Cancel();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class FinishResponse MOZ_FINAL : public nsRunnable
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
|
||||
public:
|
||||
explicit FinishResponse(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel)
|
||||
: mChannel(aChannel)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
nsresult rv = mChannel->FinishSynthesizedResponse();
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to finish synthesized response");
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
class RespondWithHandler MOZ_FINAL : public PromiseNativeHandler
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
|
||||
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||
public:
|
||||
RespondWithHandler(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker)
|
||||
: mInterceptedChannel(aChannel)
|
||||
, mServiceWorker(aServiceWorker)
|
||||
{
|
||||
}
|
||||
|
||||
void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
|
||||
|
||||
void RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE;
|
||||
|
||||
void CancelRequest();
|
||||
};
|
||||
|
||||
struct RespondWithClosure
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
|
||||
|
||||
explicit RespondWithClosure(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel)
|
||||
: mInterceptedChannel(aChannel)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
void RespondWithCopyComplete(void* aClosure, nsresult aStatus)
|
||||
{
|
||||
nsAutoPtr<RespondWithClosure> data(static_cast<RespondWithClosure*>(aClosure));
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
if (NS_SUCCEEDED(aStatus)) {
|
||||
event = new FinishResponse(data->mInterceptedChannel);
|
||||
} else {
|
||||
event = new CancelChannelRunnable(data->mInterceptedChannel);
|
||||
}
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(event)));
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS AutoCancel
|
||||
{
|
||||
nsRefPtr<RespondWithHandler> mOwner;
|
||||
|
||||
public:
|
||||
explicit AutoCancel(RespondWithHandler* aOwner)
|
||||
: mOwner(aOwner)
|
||||
{
|
||||
}
|
||||
|
||||
~AutoCancel()
|
||||
{
|
||||
if (mOwner) {
|
||||
mOwner->CancelRequest();
|
||||
}
|
||||
}
|
||||
|
||||
void Reset()
|
||||
{
|
||||
mOwner = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
RespondWithHandler::ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
AutoCancel autoCancel(this);
|
||||
|
||||
if (!aValue.isObject()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<Response> response;
|
||||
nsresult rv = UNWRAP_OBJECT(Response, &aValue.toObject(), response);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInputStream> body;
|
||||
response->GetBody(getter_AddRefs(body));
|
||||
if (NS_WARN_IF(!body) || NS_WARN_IF(response->BodyUsed())) {
|
||||
return;
|
||||
}
|
||||
response->SetBodyUsed();
|
||||
|
||||
nsCOMPtr<nsIOutputStream> responseBody;
|
||||
rv = mInterceptedChannel->GetResponseBody(getter_AddRefs(responseBody));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsAutoPtr<RespondWithClosure> closure(new RespondWithClosure(mInterceptedChannel));
|
||||
|
||||
nsCOMPtr<nsIEventTarget> stsThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
|
||||
if (NS_WARN_IF(!stsThread)) {
|
||||
return;
|
||||
}
|
||||
rv = NS_AsyncCopy(body, responseBody, stsThread, NS_ASYNCCOPY_VIA_READSEGMENTS, 4096,
|
||||
RespondWithCopyComplete, closure.forget());
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
autoCancel.Reset();
|
||||
}
|
||||
|
||||
void
|
||||
RespondWithHandler::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
|
||||
{
|
||||
CancelRequest();
|
||||
}
|
||||
|
||||
void
|
||||
RespondWithHandler::CancelRequest()
|
||||
{
|
||||
nsCOMPtr<nsIRunnable> runnable = new CancelChannelRunnable(mInterceptedChannel);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
void
|
||||
FetchEvent::RespondWith(Promise& aPromise, ErrorResult& aRv)
|
||||
{
|
||||
if (mWaitToRespond) {
|
||||
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
mWaitToRespond = true;
|
||||
nsRefPtr<RespondWithHandler> handler = new RespondWithHandler(mChannel, mServiceWorker);
|
||||
aPromise.AppendNativeHandler(handler);
|
||||
}
|
||||
|
||||
already_AddRefed<ServiceWorkerClient>
|
||||
FetchEvent::Client()
|
||||
{
|
||||
if (!mClient) {
|
||||
mClient = new ServiceWorkerClient(GetParentObject(), mWindowId);
|
||||
}
|
||||
nsRefPtr<ServiceWorkerClient> client = mClient;
|
||||
return client.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
FetchEvent::ForwardTo(const nsAString& aUrl)
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
|
||||
MOZ_ASSERT(global);
|
||||
ErrorResult result;
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, result);
|
||||
if (NS_WARN_IF(result.Failed())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
already_AddRefed<Promise>
|
||||
FetchEvent::Default()
|
||||
{
|
||||
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetParentObject());
|
||||
MOZ_ASSERT(global);
|
||||
ErrorResult result;
|
||||
nsRefPtr<Promise> promise = Promise::Create(global, result);
|
||||
if (result.Failed()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
promise->MaybeReject(NS_ERROR_NOT_AVAILABLE);
|
||||
return promise.forget();
|
||||
}
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(FetchEvent, Event)
|
||||
NS_IMPL_RELEASE_INHERITED(FetchEvent, Event)
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(FetchEvent)
|
||||
NS_INTERFACE_MAP_END_INHERITING(Event)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_INHERITED(FetchEvent, Event, mRequest, mClient)
|
||||
|
||||
ExtendableEvent::ExtendableEvent(EventTarget* aOwner)
|
||||
: Event(aOwner, nullptr, nullptr)
|
||||
{
|
||||
|
@ -8,12 +8,87 @@
|
||||
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/ExtendableEventBinding.h"
|
||||
#include "mozilla/dom/FetchEventBinding.h"
|
||||
#include "mozilla/dom/InstallEventBinding.h"
|
||||
#include "mozilla/dom/Promise.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
class nsIInterceptedChannel;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class Request;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
BEGIN_WORKERS_NAMESPACE
|
||||
|
||||
class ServiceWorker;
|
||||
class ServiceWorkerClient;
|
||||
|
||||
class FetchEvent MOZ_FINAL : public Event
|
||||
{
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
|
||||
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||
nsRefPtr<ServiceWorkerClient> mClient;
|
||||
nsRefPtr<Request> mRequest;
|
||||
uint64_t mWindowId;
|
||||
bool mIsReload;
|
||||
bool mWaitToRespond;
|
||||
protected:
|
||||
explicit FetchEvent(EventTarget* aOwner);
|
||||
~FetchEvent();
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FetchEvent, Event)
|
||||
NS_FORWARD_TO_EVENT
|
||||
|
||||
virtual JSObject* WrapObjectInternal(JSContext* aCx) MOZ_OVERRIDE
|
||||
{
|
||||
return FetchEventBinding::Wrap(aCx, this);
|
||||
}
|
||||
|
||||
void PostInit(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
|
||||
uint64_t aWindowId);
|
||||
|
||||
static already_AddRefed<FetchEvent>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const FetchEventInit& aOptions,
|
||||
ErrorResult& aRv);
|
||||
|
||||
bool
|
||||
WaitToRespond() const
|
||||
{
|
||||
return mWaitToRespond;
|
||||
}
|
||||
|
||||
Request*
|
||||
Request_() const
|
||||
{
|
||||
return mRequest;
|
||||
}
|
||||
|
||||
already_AddRefed<ServiceWorkerClient>
|
||||
Client();
|
||||
|
||||
bool
|
||||
IsReload() const
|
||||
{
|
||||
return mIsReload;
|
||||
}
|
||||
|
||||
void
|
||||
RespondWith(Promise& aPromise, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
ForwardTo(const nsAString& aUrl);
|
||||
|
||||
already_AddRefed<Promise>
|
||||
Default();
|
||||
};
|
||||
|
||||
class ExtendableEvent : public Event
|
||||
{
|
||||
|
@ -11,7 +11,10 @@
|
||||
#include "nsIStreamLoader.h"
|
||||
#include "nsIHttpChannel.h"
|
||||
#include "nsIHttpChannelInternal.h"
|
||||
#include "nsIHttpHeaderVisitor.h"
|
||||
#include "nsINetworkInterceptController.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
#include "nsDebug.h"
|
||||
|
||||
#include "jsapi.h"
|
||||
|
||||
@ -19,9 +22,13 @@
|
||||
#include "mozilla/dom/BindingUtils.h"
|
||||
#include "mozilla/dom/DOMError.h"
|
||||
#include "mozilla/dom/ErrorEvent.h"
|
||||
#include "mozilla/dom/Headers.h"
|
||||
#include "mozilla/dom/InstallEventBinding.h"
|
||||
#include "mozilla/dom/InternalHeaders.h"
|
||||
#include "mozilla/dom/Navigator.h"
|
||||
#include "mozilla/dom/PromiseNativeHandler.h"
|
||||
#include "mozilla/dom/Request.h"
|
||||
#include "mozilla/dom/RootedDictionary.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundChild.h"
|
||||
#include "mozilla/ipc/PBackgroundSharedTypes.h"
|
||||
@ -2121,6 +2128,267 @@ ServiceWorkerManager::GetServiceWorkerForScope(nsIDOMWindow* aWindow,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class FetchEventRunnable : public WorkerRunnable
|
||||
, public nsIHttpHeaderVisitor {
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mInterceptedChannel;
|
||||
nsMainThreadPtrHandle<ServiceWorker> mServiceWorker;
|
||||
nsTArray<nsCString> mHeaderNames;
|
||||
nsTArray<nsCString> mHeaderValues;
|
||||
uint64_t mWindowId;
|
||||
nsCString mSpec;
|
||||
nsCString mMethod;
|
||||
bool mIsReload;
|
||||
public:
|
||||
FetchEventRunnable(WorkerPrivate* aWorkerPrivate,
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel,
|
||||
nsMainThreadPtrHandle<ServiceWorker>& aServiceWorker,
|
||||
uint64_t aWindowId)
|
||||
: WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
|
||||
, mInterceptedChannel(aChannel)
|
||||
, mServiceWorker(aServiceWorker)
|
||||
, mWindowId(aWindowId)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
NS_IMETHOD
|
||||
VisitHeader(const nsACString& aHeader, const nsACString& aValue)
|
||||
{
|
||||
mHeaderNames.AppendElement(aHeader);
|
||||
mHeaderValues.AppendElement(aValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
Init()
|
||||
{
|
||||
nsCOMPtr<nsIChannel> channel;
|
||||
nsresult rv = mInterceptedChannel->GetChannel(getter_AddRefs(channel));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = channel->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = uri->GetSpec(mSpec);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(channel);
|
||||
NS_ENSURE_TRUE(httpChannel, NS_ERROR_NOT_AVAILABLE);
|
||||
|
||||
rv = httpChannel->GetRequestMethod(mMethod);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
uint32_t loadFlags;
|
||||
rv = channel->GetLoadFlags(&loadFlags);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
//TODO(jdm): we should probably include reload-ness in the loadinfo or as a separate load flag
|
||||
mIsReload = false;
|
||||
|
||||
rv = httpChannel->VisitRequestHeaders(this);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
return DispatchFetchEvent(aCx, aWorkerPrivate);
|
||||
}
|
||||
|
||||
private:
|
||||
~FetchEventRunnable() {}
|
||||
|
||||
class ResumeRequest MOZ_FINAL : public nsRunnable {
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> mChannel;
|
||||
public:
|
||||
explicit ResumeRequest(nsMainThreadPtrHandle<nsIInterceptedChannel>& aChannel)
|
||||
: mChannel(aChannel)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run()
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
nsresult rv = mChannel->ResetInterception();
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to resume intercepted network request");
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
||||
bool
|
||||
DispatchFetchEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
|
||||
{
|
||||
MOZ_ASSERT(aCx);
|
||||
MOZ_ASSERT(aWorkerPrivate);
|
||||
MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
|
||||
GlobalObject globalObj(aCx, aWorkerPrivate->GlobalScope()->GetWrapper());
|
||||
|
||||
RequestOrUSVString requestInfo;
|
||||
*requestInfo.SetAsUSVString().ToAStringPtr() = NS_ConvertUTF8toUTF16(mSpec);
|
||||
|
||||
RootedDictionary<RequestInit> reqInit(aCx);
|
||||
reqInit.mMethod.Construct(mMethod);
|
||||
|
||||
nsRefPtr<InternalHeaders> internalHeaders = new InternalHeaders(HeadersGuardEnum::Request);
|
||||
MOZ_ASSERT(mHeaderNames.Length() == mHeaderValues.Length());
|
||||
for (uint32_t i = 0; i < mHeaderNames.Length(); i++) {
|
||||
ErrorResult rv;
|
||||
internalHeaders->Set(mHeaderNames[i], mHeaderValues[i], rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<Headers> headers = new Headers(globalObj.GetAsSupports(), internalHeaders);
|
||||
reqInit.mHeaders.Construct();
|
||||
reqInit.mHeaders.Value().SetAsHeaders() = headers;
|
||||
|
||||
//TODO(jdm): set request body
|
||||
//TODO(jdm): set request same-origin mode and credentials
|
||||
|
||||
ErrorResult rv;
|
||||
nsRefPtr<Request> request = Request::Constructor(globalObj, requestInfo, reqInit, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RootedDictionary<FetchEventInit> init(aCx);
|
||||
init.mRequest.Construct();
|
||||
init.mRequest.Value() = request;
|
||||
init.mBubbles = false;
|
||||
init.mCancelable = true;
|
||||
init.mIsReload.Construct(mIsReload);
|
||||
nsRefPtr<FetchEvent> event =
|
||||
FetchEvent::Constructor(globalObj, NS_LITERAL_STRING("fetch"), init, rv);
|
||||
if (NS_WARN_IF(rv.Failed())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
event->PostInit(mInterceptedChannel, mServiceWorker, mWindowId);
|
||||
event->SetTrusted(true);
|
||||
|
||||
nsRefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
|
||||
nsresult rv2 = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv2)) || !event->WaitToRespond()) {
|
||||
nsCOMPtr<nsIRunnable> runnable = new ResumeRequest(mInterceptedChannel);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(runnable)));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(FetchEventRunnable, WorkerRunnable, nsIHttpHeaderVisitor)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::DispatchFetchEvent(nsIDocument* aDoc, nsIInterceptedChannel* aChannel)
|
||||
{
|
||||
MOZ_ASSERT(aChannel);
|
||||
nsCOMPtr<nsISupports> serviceWorker;
|
||||
|
||||
bool isNavigation = false;
|
||||
nsresult rv = aChannel->GetIsNavigation(&isNavigation);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!isNavigation) {
|
||||
MOZ_ASSERT(aDoc);
|
||||
rv = GetDocumentController(aDoc->GetWindow(), getter_AddRefs(serviceWorker));
|
||||
} else {
|
||||
nsCOMPtr<nsIChannel> internalChannel;
|
||||
rv = aChannel->GetChannel(getter_AddRefs(internalChannel));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
rv = internalChannel->GetURI(getter_AddRefs(uri));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
|
||||
GetServiceWorkerRegistrationInfo(uri);
|
||||
// This should only happen if IsAvailableForURI() returned true.
|
||||
MOZ_ASSERT(registration);
|
||||
MOZ_ASSERT(registration->mActiveWorker);
|
||||
|
||||
nsRefPtr<ServiceWorker> sw;
|
||||
rv = CreateServiceWorker(registration->mPrincipal,
|
||||
registration->mActiveWorker->ScriptSpec(),
|
||||
registration->mScope,
|
||||
getter_AddRefs(sw));
|
||||
serviceWorker = sw.forget();
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsMainThreadPtrHandle<nsIInterceptedChannel> handle(
|
||||
new nsMainThreadPtrHolder<nsIInterceptedChannel>(aChannel, false));
|
||||
|
||||
uint64_t windowId = aDoc ? aDoc->GetInnerWindow()->WindowID() : 0;
|
||||
|
||||
nsRefPtr<ServiceWorker> sw = static_cast<ServiceWorker*>(serviceWorker.get());
|
||||
nsMainThreadPtrHandle<ServiceWorker> serviceWorkerHandle(
|
||||
new nsMainThreadPtrHolder<ServiceWorker>(sw));
|
||||
|
||||
nsRefPtr<FetchEventRunnable> event =
|
||||
new FetchEventRunnable(sw->GetWorkerPrivate(), handle, serviceWorkerHandle, windowId);
|
||||
rv = event->Init();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
AutoJSAPI api;
|
||||
api.Init();
|
||||
if (NS_WARN_IF(!event->Dispatch(api.cx()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::IsAvailableForURI(nsIURI* aURI, bool* aIsAvailable)
|
||||
{
|
||||
MOZ_ASSERT(aURI);
|
||||
MOZ_ASSERT(aIsAvailable);
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration =
|
||||
GetServiceWorkerRegistrationInfo(aURI);
|
||||
*aIsAvailable = registration && registration->mActiveWorker;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ServiceWorkerManager::IsControlled(nsIDocument* aDoc, bool* aIsControlled)
|
||||
{
|
||||
MOZ_ASSERT(aDoc);
|
||||
MOZ_ASSERT(aIsControlled);
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
|
||||
nsresult rv = GetDocumentRegistration(aDoc, getter_AddRefs(registration));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
*aIsControlled = !!registration;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
ServiceWorkerManager::GetDocumentRegistration(nsIDocument* aDoc,
|
||||
ServiceWorkerRegistrationInfo** aRegistrationInfo)
|
||||
{
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
|
||||
if (!mControlledDocuments.Get(aDoc, getter_AddRefs(registration))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If the document is controlled, the current worker MUST be non-null.
|
||||
if (!registration->mActiveWorker) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
registration.forget(aRegistrationInfo);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* The .controller is for the registration associated with the document when
|
||||
* the document was loaded.
|
||||
@ -2137,21 +2405,16 @@ ServiceWorkerManager::GetDocumentController(nsIDOMWindow* aWindow, nsISupports**
|
||||
nsCOMPtr<nsIDocument> doc = window->GetExtantDoc();
|
||||
|
||||
nsRefPtr<ServiceWorkerRegistrationInfo> registration;
|
||||
if (!mControlledDocuments.Get(doc, getter_AddRefs(registration))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv = GetDocumentRegistration(doc, getter_AddRefs(registration));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// If the document is controlled, the current worker MUST be non-null.
|
||||
if (!registration->mActiveWorker) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
nsresult rv = CreateServiceWorkerForWindow(window,
|
||||
registration->mActiveWorker->ScriptSpec(),
|
||||
registration->mScope,
|
||||
getter_AddRefs(serviceWorker));
|
||||
rv = CreateServiceWorkerForWindow(window,
|
||||
registration->mActiveWorker->ScriptSpec(),
|
||||
registration->mScope,
|
||||
getter_AddRefs(serviceWorker));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -399,6 +399,9 @@ private:
|
||||
nsresult
|
||||
Update(ServiceWorkerRegistrationInfo* aRegistration);
|
||||
|
||||
nsresult
|
||||
GetDocumentRegistration(nsIDocument* aDoc, ServiceWorkerRegistrationInfo** aRegistrationInfo);
|
||||
|
||||
NS_IMETHOD
|
||||
CreateServiceWorkerForWindow(nsPIDOMWindow* aWindow,
|
||||
const nsACString& aScriptSpec,
|
||||
|
54
dom/workers/test/serviceworkers/fetch/fetch_tests.js
Normal file
54
dom/workers/test/serviceworkers/fetch/fetch_tests.js
Normal file
@ -0,0 +1,54 @@
|
||||
function fetch(name, onload, onerror, headers) {
|
||||
expectAsyncResult();
|
||||
|
||||
onload = onload || function() {
|
||||
my_ok(false, "XHR load should not complete successfully");
|
||||
finish();
|
||||
};
|
||||
onerror = onerror || function() {
|
||||
my_ok(false, "XHR load should be intercepted successfully");
|
||||
finish();
|
||||
};
|
||||
|
||||
var x = new XMLHttpRequest();
|
||||
x.open('GET', name, true);
|
||||
x.onload = function() { onload(x) };
|
||||
x.onerror = function() { onerror(x) };
|
||||
headers = headers || [];
|
||||
headers.forEach(function(header) {
|
||||
x.setRequestHeader(header[0], header[1]);
|
||||
});
|
||||
x.send();
|
||||
}
|
||||
|
||||
fetch('synthesized.txt', function(xhr) {
|
||||
my_ok(xhr.status == 200, "load should be successful");
|
||||
my_ok(xhr.responseText == "synthesized response body", "load should have synthesized response");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('ignored.txt', function(xhr) {
|
||||
my_ok(xhr.status == 404, "load should be uninterrupted");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('rejected.txt', null, function(xhr) {
|
||||
my_ok(xhr.status == 0, "load should not complete");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('nonresponse.txt', null, function(xhr) {
|
||||
my_ok(xhr.status == 0, "load should not complete");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('nonresponse2.txt', null, function(xhr) {
|
||||
my_ok(xhr.status == 0, "load should not complete");
|
||||
finish();
|
||||
});
|
||||
|
||||
fetch('headers.txt', function(xhr) {
|
||||
my_ok(xhr.status == 200, "load should be successful");
|
||||
my_ok(xhr.responseText == "1", "request header checks should have passed");
|
||||
finish();
|
||||
}, null, [["X-Test1", "header1"], ["X-Test2", "header2"]]);
|
29
dom/workers/test/serviceworkers/fetch/fetch_worker_script.js
Normal file
29
dom/workers/test/serviceworkers/fetch/fetch_worker_script.js
Normal file
@ -0,0 +1,29 @@
|
||||
function my_ok(v, msg) {
|
||||
postMessage({type: "ok", value: v, msg: msg});
|
||||
}
|
||||
|
||||
function finish() {
|
||||
postMessage('finish');
|
||||
}
|
||||
|
||||
function expectAsyncResult() {
|
||||
postMessage('expect');
|
||||
}
|
||||
|
||||
expectAsyncResult();
|
||||
try {
|
||||
var success = false;
|
||||
importScripts("nonexistent_imported_script.js");
|
||||
} catch(x) {
|
||||
}
|
||||
|
||||
my_ok(success, "worker imported script should be intercepted");
|
||||
finish();
|
||||
|
||||
function check_intercepted_script() {
|
||||
success = true;
|
||||
}
|
||||
|
||||
importScripts('fetch_tests.js')
|
||||
|
||||
finish(); //corresponds to the gExpected increment before creating this worker
|
147
dom/workers/test/serviceworkers/fetch/index.html
Normal file
147
dom/workers/test/serviceworkers/fetch/index.html
Normal file
@ -0,0 +1,147 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 94048 - test install event.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<div id="style-test" style="background-color: white"></div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
function my_ok(result, msg) {
|
||||
window.opener.postMessage({status: "ok", result: result, message: msg}, "*");
|
||||
}
|
||||
|
||||
function check_intercepted_script() {
|
||||
document.getElementById('intercepted-script').test_result =
|
||||
document.currentScript == document.getElementById('intercepted-script');
|
||||
}
|
||||
|
||||
function fetch(name, onload, onerror, headers) {
|
||||
gExpected++;
|
||||
|
||||
onload = onload || function() {
|
||||
my_ok(false, "load should not complete successfully");
|
||||
finish();
|
||||
};
|
||||
onerror = onerror || function() {
|
||||
my_ok(false, "load should be intercepted successfully");
|
||||
finish();
|
||||
};
|
||||
|
||||
var x = new XMLHttpRequest();
|
||||
x.open('GET', name, true);
|
||||
x.onload = function() { onload(x) };
|
||||
x.onerror = function() { onerror(x) };
|
||||
headers = headers || [];
|
||||
headers.forEach(function(header) {
|
||||
x.setRequestHeader(header[0], header[1]);
|
||||
});
|
||||
x.send();
|
||||
}
|
||||
|
||||
var gExpected = 0;
|
||||
var gEncountered = 0;
|
||||
function finish() {
|
||||
gEncountered++;
|
||||
if (gEncountered == gExpected) {
|
||||
window.opener.postMessage({status: "done"}, "*");
|
||||
}
|
||||
}
|
||||
|
||||
function test_onload(creator, complete) {
|
||||
gExpected++;
|
||||
var elem = creator();
|
||||
elem.onload = function() {
|
||||
complete.call(elem);
|
||||
finish();
|
||||
};
|
||||
elem.onerror = function() {
|
||||
my_ok(false, elem.tagName + " load should complete successfully");
|
||||
finish();
|
||||
};
|
||||
document.body.appendChild(elem);
|
||||
}
|
||||
|
||||
function expectAsyncResult() {
|
||||
gExpected++;
|
||||
}
|
||||
|
||||
my_ok(navigator.serviceWorker.controller != null, "should be controlled");
|
||||
</script>
|
||||
<script src="fetch_tests.js"></script>
|
||||
<script>
|
||||
test_onload(function() {
|
||||
var elem = document.createElement('img');
|
||||
elem.src = "nonexistent_image.gifs";
|
||||
elem.id = 'intercepted-img';
|
||||
return elem;
|
||||
}, function() {
|
||||
my_ok(this.complete, "image should be complete");
|
||||
my_ok(this.naturalWidth == 1 && this.naturalHeight == 1, "image should be 1x1 gif");
|
||||
});
|
||||
|
||||
test_onload(function() {
|
||||
var elem = document.createElement('script');
|
||||
elem.id = 'intercepted-script';
|
||||
elem.src = "nonexistent_script.js";
|
||||
return elem;
|
||||
}, function() {
|
||||
my_ok(this.test_result, "script load should be intercepted");
|
||||
});
|
||||
|
||||
test_onload(function() {
|
||||
var elem = document.createElement('link');
|
||||
elem.href = "nonexistent_stylesheet.css";
|
||||
elem.rel = "stylesheet";
|
||||
return elem;
|
||||
}, function() {
|
||||
var styled = document.getElementById('style-test');
|
||||
my_ok(window.getComputedStyle(styled).backgroundColor == 'rgb(0, 0, 0)',
|
||||
"stylesheet load should be intercepted");
|
||||
});
|
||||
|
||||
test_onload(function() {
|
||||
var elem = document.createElement('iframe');
|
||||
elem.id = 'intercepted-iframe';
|
||||
elem.src = "nonexistent_page.html";
|
||||
return elem;
|
||||
}, function() {
|
||||
my_ok(this.test_result, "iframe load should be intercepted");
|
||||
});
|
||||
|
||||
gExpected++;
|
||||
var worker = new Worker('nonexistent_worker_script.js');
|
||||
worker.onmessage = function(e) {
|
||||
my_ok(e.data == "worker-intercept-success", "worker load intercepted");
|
||||
finish();
|
||||
};
|
||||
worker.onerror = function() {
|
||||
my_ok(false, "worker load should be intercepted");
|
||||
};
|
||||
|
||||
gExpected++;
|
||||
var worker = new Worker('fetch_worker_script.js');
|
||||
worker.onmessage = function(e) {
|
||||
if (e.data == "finish") {
|
||||
finish();
|
||||
} else if (e.data == "expect") {
|
||||
gExpected++;
|
||||
} else if (e.data.type == "ok") {
|
||||
my_ok(e.data.value, e.data.msg);
|
||||
}
|
||||
};
|
||||
worker.onerror = function() {
|
||||
my_ok(false, "worker should not cause any errors");
|
||||
};
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
86
dom/workers/test/serviceworkers/fetch_event_worker.js
Normal file
86
dom/workers/test/serviceworkers/fetch_event_worker.js
Normal file
@ -0,0 +1,86 @@
|
||||
onfetch = function(ev) {
|
||||
if (ev.request.url.contains("synthesized.txt")) {
|
||||
var p = new Promise(function(resolve) {
|
||||
var r = new Response("synthesized response body", {});
|
||||
resolve(r);
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("ignored.txt")) {
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("rejected.txt")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
reject();
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonresponse.txt")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(5);
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonresponse2.txt")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve({});
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("headers.txt")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
var ok = true;
|
||||
ok &= ev.request.headers.get("X-Test1") == "header1";
|
||||
ok &= ev.request.headers.get("X-Test2") == "header2";
|
||||
var r = new Response(ok.toString(), {});
|
||||
resolve(r);
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonexistent_image.gif")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(new Response(atob("R0lGODlhAQABAIAAAAUEBAAAACwAAAAAAQABAAACAkQBADs"), {}));
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonexistent_script.js")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(new Response("check_intercepted_script();", {}));
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonexistent_stylesheet.css")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(new Response("#style-test { background-color: black !important; }", {}));
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonexistent_page.html")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(new Response("<script>window.frameElement.test_result = true;</script>", {}));
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonexistent_worker_script.js")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(new Response("postMessage('worker-intercept-success')", {}));
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
|
||||
else if (ev.request.url.contains("nonexistent_imported_script.js")) {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
resolve(new Response("check_intercepted_script();", {}));
|
||||
});
|
||||
ev.respondWith(p);
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@ support-files =
|
||||
worker.js
|
||||
worker2.js
|
||||
worker3.js
|
||||
fetch_event_worker.js
|
||||
parse_error_worker.js
|
||||
activate_event_error_worker.js
|
||||
install_event_worker.js
|
||||
@ -20,10 +21,14 @@ support-files =
|
||||
worker_unregister.js
|
||||
worker_update.js
|
||||
message_posting_worker.js
|
||||
fetch/index.html
|
||||
fetch/fetch_worker_script.js
|
||||
fetch/fetch_tests.js
|
||||
|
||||
[test_unregister.html]
|
||||
skip-if = true # Bug 1133805
|
||||
[test_installation_simple.html]
|
||||
[test_fetch_event.html]
|
||||
[test_get_serviced.html]
|
||||
[test_install_event.html]
|
||||
[test_navigator.html]
|
||||
|
62
dom/workers/test/serviceworkers/test_fetch_event.html
Normal file
62
dom/workers/test/serviceworkers/test_fetch_event.html
Normal file
@ -0,0 +1,62 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Bug 94048 - test install event.</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<pre id="test"></pre>
|
||||
<script class="testbody" type="text/javascript">
|
||||
SimpleTest.requestCompleteLog();
|
||||
|
||||
function simpleRegister() {
|
||||
var p = navigator.serviceWorker.register("fetch_event_worker.js", { scope: "./fetch" });
|
||||
return p;
|
||||
}
|
||||
|
||||
function testController() {
|
||||
var p = new Promise(function(resolve, reject) {
|
||||
window.onmessage = function(e) {
|
||||
if (e.data.status == "ok") {
|
||||
ok(e.data.result, e.data.message);
|
||||
} else if (e.data.status == "done") {
|
||||
window.onmessage = null;
|
||||
w.close();
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
var w = window.open("fetch/index.html");
|
||||
return p;
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
simpleRegister()
|
||||
.then(testController)
|
||||
.then(function() {
|
||||
SimpleTest.finish();
|
||||
}).catch(function(e) {
|
||||
ok(false, "Some test failed with error " + e);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
SpecialPowers.pushPrefEnv({"set": [
|
||||
["dom.serviceWorkers.enabled", true],
|
||||
["dom.serviceWorkers.testing.enabled", true],
|
||||
["dom.fetch.enabled", true]
|
||||
]}, runTest);
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
||||
|
24
gfx/2d/2D.h
24
gfx/2d/2D.h
@ -194,7 +194,10 @@ public:
|
||||
: mColor(aColor)
|
||||
{}
|
||||
|
||||
virtual PatternType GetType() const { return PatternType::COLOR; }
|
||||
virtual PatternType GetType() const MOZ_OVERRIDE
|
||||
{
|
||||
return PatternType::COLOR;
|
||||
}
|
||||
|
||||
Color mColor;
|
||||
};
|
||||
@ -219,7 +222,10 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual PatternType GetType() const { return PatternType::LINEAR_GRADIENT; }
|
||||
virtual PatternType GetType() const MOZ_OVERRIDE
|
||||
{
|
||||
return PatternType::LINEAR_GRADIENT;
|
||||
}
|
||||
|
||||
Point mBegin; //!< Start of the linear gradient
|
||||
Point mEnd; /**< End of the linear gradient - NOTE: In the case
|
||||
@ -256,7 +262,10 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual PatternType GetType() const { return PatternType::RADIAL_GRADIENT; }
|
||||
virtual PatternType GetType() const MOZ_OVERRIDE
|
||||
{
|
||||
return PatternType::RADIAL_GRADIENT;
|
||||
}
|
||||
|
||||
Point mCenter1; //!< Center of the inner (focal) circle.
|
||||
Point mCenter2; //!< Center of the outer circle.
|
||||
@ -286,7 +295,10 @@ public:
|
||||
, mSamplingRect(aSamplingRect)
|
||||
{}
|
||||
|
||||
virtual PatternType GetType() const { return PatternType::SURFACE; }
|
||||
virtual PatternType GetType() const MOZ_OVERRIDE
|
||||
{
|
||||
return PatternType::SURFACE;
|
||||
}
|
||||
|
||||
RefPtr<SourceSurface> mSurface; //!< Surface to use for drawing
|
||||
ExtendMode mExtendMode; /**< This determines how the image is extended
|
||||
@ -383,7 +395,7 @@ public:
|
||||
READ_WRITE
|
||||
};
|
||||
|
||||
virtual SurfaceType GetType() const { return SurfaceType::DATA; }
|
||||
virtual SurfaceType GetType() const MOZ_OVERRIDE { return SurfaceType::DATA; }
|
||||
/** @deprecated
|
||||
* Get the raw bitmap data of the surface.
|
||||
* Can return null if there was OOM allocating surface data.
|
||||
@ -415,7 +427,7 @@ public:
|
||||
* Returns a DataSourceSurface with the same data as this one, but
|
||||
* guaranteed to have surface->GetType() == SurfaceType::DATA.
|
||||
*/
|
||||
virtual TemporaryRef<DataSourceSurface> GetDataSurface();
|
||||
virtual TemporaryRef<DataSourceSurface> GetDataSurface() MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
bool mIsMapped;
|
||||
|
@ -57,7 +57,7 @@ class GenericRefCounted : public GenericRefCountedBase
|
||||
}
|
||||
|
||||
public:
|
||||
virtual void AddRef() {
|
||||
virtual void AddRef() MOZ_OVERRIDE {
|
||||
// Note: this method must be thread safe for GenericAtomicRefCounted.
|
||||
MOZ_ASSERT(int32_t(refCnt) >= 0);
|
||||
#ifndef MOZ_REFCOUNTED_LEAK_CHECKING
|
||||
@ -71,7 +71,7 @@ class GenericRefCounted : public GenericRefCountedBase
|
||||
#endif
|
||||
}
|
||||
|
||||
virtual void Release() {
|
||||
virtual void Release() MOZ_OVERRIDE {
|
||||
// Note: this method must be thread safe for GenericAtomicRefCounted.
|
||||
MOZ_ASSERT(int32_t(refCnt) > 0);
|
||||
#ifndef MOZ_REFCOUNTED_LEAK_CHECKING
|
||||
|
@ -1412,6 +1412,20 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
|
||||
}
|
||||
}
|
||||
|
||||
if (IsSupported(GLFeature::read_buffer)) {
|
||||
SymLoadStruct extSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fReadBuffer, { "ReadBuffer", nullptr } },
|
||||
END_SYMBOLS
|
||||
};
|
||||
|
||||
if (!LoadSymbols(&extSymbols[0], trygl, prefix)) {
|
||||
NS_ERROR("GL supports read_buffer without supplying its functions.");
|
||||
|
||||
MarkUnsupported(GLFeature::read_buffer);
|
||||
ClearSymbols(extSymbols);
|
||||
}
|
||||
}
|
||||
|
||||
// Load developer symbols, don't fail if we can't find them.
|
||||
SymLoadStruct auxSymbols[] = {
|
||||
{ (PRFuncPtr*) &mSymbols.fGetTexImage, { "GetTexImage", nullptr } },
|
||||
|
@ -115,6 +115,7 @@ enum class GLFeature {
|
||||
occlusion_query2,
|
||||
packed_depth_stencil,
|
||||
query_objects,
|
||||
read_buffer,
|
||||
renderbuffer_color_float,
|
||||
renderbuffer_color_half_float,
|
||||
robustness,
|
||||
|
@ -408,6 +408,15 @@ static const FeatureInfo sFeatureInfoArr[] = {
|
||||
* (added in OpenGL ES 3.0)
|
||||
*/
|
||||
},
|
||||
{
|
||||
"read_buffer",
|
||||
GLVersion::GL2,
|
||||
GLESVersion::ES3,
|
||||
GLContext::Extension_None,
|
||||
{
|
||||
GLContext::Extensions_End
|
||||
}
|
||||
},
|
||||
{
|
||||
"renderbuffer_color_float",
|
||||
GLVersion::GL3,
|
||||
|
@ -421,6 +421,12 @@ GLScreenBuffer::Attach(SharedSurface* surf, const gfx::IntSize& size)
|
||||
// Check that we're all set up.
|
||||
MOZ_ASSERT(SharedSurf() == surf);
|
||||
|
||||
// Update the ReadBuffer mode.
|
||||
if (mGL->IsSupported(gl::GLFeature::read_buffer)) {
|
||||
BindFB(0);
|
||||
mRead->SetReadBuffer(mUserReadBufferMode);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -517,6 +523,16 @@ GLScreenBuffer::CreateRead(SharedSurface* surf)
|
||||
return ReadBuffer::Create(gl, caps, formats, surf);
|
||||
}
|
||||
|
||||
void
|
||||
GLScreenBuffer::SetReadBuffer(GLenum mode)
|
||||
{
|
||||
MOZ_ASSERT(mGL->IsSupported(gl::GLFeature::read_buffer));
|
||||
MOZ_ASSERT(GetReadFB() == 0);
|
||||
|
||||
mUserReadBufferMode = mode;
|
||||
mRead->SetReadBuffer(mUserReadBufferMode);
|
||||
}
|
||||
|
||||
bool
|
||||
GLScreenBuffer::IsDrawFramebufferDefault() const
|
||||
{
|
||||
@ -636,7 +652,6 @@ ReadBuffer::Create(GLContext* gl,
|
||||
|
||||
if (surf->mAttachType == AttachmentType::Screen) {
|
||||
// Don't need anything. Our read buffer will be the 'screen'.
|
||||
|
||||
return UniquePtr<ReadBuffer>( new ReadBuffer(gl, 0, 0, 0,
|
||||
surf) );
|
||||
}
|
||||
@ -740,5 +755,31 @@ ReadBuffer::Size() const
|
||||
return mSurf->mSize;
|
||||
}
|
||||
|
||||
void
|
||||
ReadBuffer::SetReadBuffer(GLenum userMode) const
|
||||
{
|
||||
if (!mGL->IsSupported(GLFeature::read_buffer))
|
||||
return;
|
||||
|
||||
GLenum internalMode;
|
||||
|
||||
switch (userMode) {
|
||||
case LOCAL_GL_BACK:
|
||||
internalMode = (mFB == 0) ? LOCAL_GL_BACK
|
||||
: LOCAL_GL_COLOR_ATTACHMENT0;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_NONE:
|
||||
internalMode = LOCAL_GL_NONE;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Bad value.");
|
||||
}
|
||||
|
||||
mGL->MakeCurrent();
|
||||
mGL->fReadBuffer(internalMode);
|
||||
}
|
||||
|
||||
} /* namespace gl */
|
||||
} /* namespace mozilla */
|
||||
|
@ -116,6 +116,8 @@ public:
|
||||
SharedSurface* SharedSurf() const {
|
||||
return mSurf;
|
||||
}
|
||||
|
||||
void SetReadBuffer(GLenum mode) const;
|
||||
};
|
||||
|
||||
|
||||
@ -142,6 +144,8 @@ protected:
|
||||
|
||||
bool mNeedsBlit;
|
||||
|
||||
GLenum mUserReadBufferMode;
|
||||
|
||||
// Below are the parts that help us pretend to be framebuffer 0:
|
||||
GLuint mUserDrawFB;
|
||||
GLuint mUserReadFB;
|
||||
@ -160,6 +164,7 @@ protected:
|
||||
, mCaps(caps)
|
||||
, mFactory(Move(factory))
|
||||
, mNeedsBlit(true)
|
||||
, mUserReadBufferMode(LOCAL_GL_BACK)
|
||||
, mUserDrawFB(0)
|
||||
, mUserReadFB(0)
|
||||
, mInternalDrawFB(0)
|
||||
@ -223,6 +228,8 @@ public:
|
||||
void AfterDrawCall();
|
||||
void BeforeReadCall();
|
||||
|
||||
void SetReadBuffer(GLenum userMode);
|
||||
|
||||
/**
|
||||
* Attempts to read pixels from the current bound framebuffer, if
|
||||
* it is backed by a SharedSurface.
|
||||
|
@ -236,6 +236,8 @@ public:
|
||||
*/
|
||||
virtual const nsIntRegion& GetValidLowPrecisionRegion() const = 0;
|
||||
|
||||
virtual const nsIntRegion& GetValidRegion() const = 0;
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
|
||||
/**
|
||||
* Store a fence that will signal when the current buffer is no longer being read.
|
||||
|
@ -233,7 +233,7 @@ LayerManagerComposite::ApplyOcclusionCulling(Layer* aLayer, nsIntRegion& aOpaque
|
||||
!aLayer->GetMaskLayer() &&
|
||||
aLayer->GetLocalOpacity() == 1.0f) {
|
||||
if (aLayer->GetContentFlags() & Layer::CONTENT_OPAQUE) {
|
||||
localOpaque.Or(localOpaque, composite->GetShadowVisibleRegion());
|
||||
localOpaque.Or(localOpaque, composite->GetFullyRenderedRegion());
|
||||
}
|
||||
localOpaque.MoveBy(transform2d._31, transform2d._32);
|
||||
const nsIntRect* clip = aLayer->GetEffectiveClipRect();
|
||||
@ -304,11 +304,8 @@ LayerManagerComposite::EndTransaction(DrawPaintedLayerCallback aCallback,
|
||||
// so we don't need to pass any global transform here.
|
||||
mRoot->ComputeEffectiveTransforms(gfx::Matrix4x4());
|
||||
|
||||
// Disable culling for now. We need to fix /the regressions from
|
||||
// bug 1085223 before we can re-enable this:
|
||||
// 1) Don't cull during progressive draw, 2) OS X tp5 regressions.
|
||||
//nsIntRegion opaque;
|
||||
//ApplyOcclusionCulling(mRoot, opaque);
|
||||
nsIntRegion opaque;
|
||||
ApplyOcclusionCulling(mRoot, opaque);
|
||||
|
||||
Render();
|
||||
mGeometryChanged = false;
|
||||
@ -1154,6 +1151,20 @@ LayerComposite::SetLayerManager(LayerManagerComposite* aManager)
|
||||
mCompositor = aManager->GetCompositor();
|
||||
}
|
||||
|
||||
nsIntRegion
|
||||
LayerComposite::GetFullyRenderedRegion() {
|
||||
if (TiledLayerComposer* tiled = GetTiledLayerComposer()) {
|
||||
nsIntRegion shadowVisibleRegion = GetShadowVisibleRegion();
|
||||
// Discard the region which hasn't been drawn yet when doing
|
||||
// progressive drawing. Note that if the shadow visible region
|
||||
// shrunk the tiled valig region may not have discarded this yet.
|
||||
shadowVisibleRegion.And(shadowVisibleRegion, tiled->GetValidRegion());
|
||||
return shadowVisibleRegion;
|
||||
} else {
|
||||
return GetShadowVisibleRegion();
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef MOZ_HAVE_PLATFORM_SPECIFIC_LAYER_BUFFERS
|
||||
|
||||
/*static*/ bool
|
||||
|
@ -441,6 +441,13 @@ public:
|
||||
bool HasLayerBeenComposited() { return mLayerComposited; }
|
||||
nsIntRect GetClearRect() { return mClearRect; }
|
||||
|
||||
/**
|
||||
* Return the part of the visible region that has been fully rendered.
|
||||
* While progressive drawing is in progress this region will be
|
||||
* a subset of the shadow visible region.
|
||||
*/
|
||||
nsIntRegion GetFullyRenderedRegion();
|
||||
|
||||
protected:
|
||||
gfx::Matrix4x4 mShadowTransform;
|
||||
nsIntRegion mShadowVisibleRegion;
|
||||
|
@ -231,6 +231,11 @@ public:
|
||||
return mLowPrecisionTiledBuffer.GetValidRegion();
|
||||
}
|
||||
|
||||
const nsIntRegion& GetValidRegion() const MOZ_OVERRIDE
|
||||
{
|
||||
return mTiledBuffer.GetValidRegion();
|
||||
}
|
||||
|
||||
virtual void SetCompositor(Compositor* aCompositor) MOZ_OVERRIDE
|
||||
{
|
||||
CompositableHost::SetCompositor(aCompositor);
|
||||
|
@ -74,11 +74,13 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
using namespace base;
|
||||
using namespace mozilla::ipc;
|
||||
using namespace mozilla::gfx;
|
||||
using namespace std;
|
||||
|
||||
using base::ProcessHandle;
|
||||
using base::Thread;
|
||||
|
||||
CompositorParent::LayerTreeState::LayerTreeState()
|
||||
: mParent(nullptr)
|
||||
, mLayerManager(nullptr)
|
||||
|
@ -12,9 +12,10 @@
|
||||
#include "FenceUtilsGonk.h"
|
||||
|
||||
using namespace android;
|
||||
using namespace base;
|
||||
using namespace mozilla::layers;
|
||||
|
||||
using base::FileDescriptor;
|
||||
|
||||
namespace IPC {
|
||||
|
||||
void
|
||||
|
@ -33,10 +33,11 @@
|
||||
#include "MainThreadUtils.h"
|
||||
|
||||
using namespace android;
|
||||
using namespace base;
|
||||
using namespace mozilla::layers;
|
||||
using namespace mozilla::gl;
|
||||
|
||||
using base::FileDescriptor;
|
||||
|
||||
namespace IPC {
|
||||
|
||||
void
|
||||
|
@ -5,6 +5,8 @@
|
||||
#ifndef BASE_FILE_DESCRIPTOR_SHUFFLE_H_
|
||||
#define BASE_FILE_DESCRIPTOR_SHUFFLE_H_
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
// This code exists to perform the shuffling of file descriptors which is
|
||||
// commonly needed when forking subprocesses. The naive approve is very simple,
|
||||
// just call dup2 to setup the desired descriptors, but wrong. It's tough to
|
||||
@ -42,9 +44,9 @@ class InjectionDelegate {
|
||||
// An implementation of the InjectionDelegate interface using the file
|
||||
// descriptor table of the current process as the domain.
|
||||
class FileDescriptorTableInjection : public InjectionDelegate {
|
||||
bool Duplicate(int* result, int fd);
|
||||
bool Move(int src, int dest);
|
||||
void Close(int fd);
|
||||
virtual bool Duplicate(int* result, int fd) MOZ_OVERRIDE;
|
||||
virtual bool Move(int src, int dest) MOZ_OVERRIDE;
|
||||
virtual void Close(int fd) MOZ_OVERRIDE;
|
||||
};
|
||||
|
||||
// A single arc of the directed graph which describes an injective multimapping.
|
||||
|
@ -176,7 +176,7 @@ public:
|
||||
// arbitrary MessageLoop to Quit.
|
||||
class QuitTask : public Task {
|
||||
public:
|
||||
virtual void Run() {
|
||||
virtual void Run() MOZ_OVERRIDE {
|
||||
MessageLoop::current()->Quit();
|
||||
}
|
||||
};
|
||||
@ -396,9 +396,9 @@ public:
|
||||
int delay_ms, bool nestable);
|
||||
|
||||
// base::MessagePump::Delegate methods:
|
||||
virtual bool DoWork();
|
||||
virtual bool DoDelayedWork(base::TimeTicks* next_delayed_work_time);
|
||||
virtual bool DoIdleWork();
|
||||
virtual bool DoWork() MOZ_OVERRIDE;
|
||||
virtual bool DoDelayedWork(base::TimeTicks* next_delayed_work_time) MOZ_OVERRIDE;
|
||||
virtual bool DoIdleWork() MOZ_OVERRIDE;
|
||||
|
||||
Type type_;
|
||||
int32_t id_;
|
||||
|
@ -133,10 +133,10 @@ class MessagePumpLibevent : public MessagePump {
|
||||
|
||||
|
||||
// MessagePump methods:
|
||||
virtual void Run(Delegate* delegate);
|
||||
virtual void Quit();
|
||||
virtual void ScheduleWork();
|
||||
virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time);
|
||||
virtual void Run(Delegate* delegate) MOZ_OVERRIDE;
|
||||
virtual void Quit() MOZ_OVERRIDE;
|
||||
virtual void ScheduleWork() MOZ_OVERRIDE;
|
||||
virtual void ScheduleDelayedWork(const TimeTicks& delayed_work_time) MOZ_OVERRIDE;
|
||||
|
||||
protected:
|
||||
|
||||
@ -204,9 +204,9 @@ protected:
|
||||
*/
|
||||
virtual void OnError() {}
|
||||
virtual void OnLineRead(int aFd, nsDependentCSubstring& aMessage) = 0;
|
||||
virtual void OnFileCanWriteWithoutBlocking(int /* aFd */) {}
|
||||
virtual void OnFileCanWriteWithoutBlocking(int /* aFd */) MOZ_OVERRIDE {}
|
||||
private:
|
||||
virtual void OnFileCanReadWithoutBlocking(int aFd) MOZ_FINAL;
|
||||
virtual void OnFileCanReadWithoutBlocking(int aFd) MOZ_FINAL MOZ_OVERRIDE;
|
||||
|
||||
nsAutoPtr<char> mReceiveBuffer;
|
||||
int mReceivedIndex;
|
||||
|
@ -98,7 +98,7 @@ class Channel : public Message::Sender {
|
||||
//
|
||||
// If you Send() a message on a Close()'d channel, we delete the message
|
||||
// immediately.
|
||||
virtual bool Send(Message* message);
|
||||
virtual bool Send(Message* message) MOZ_OVERRIDE;
|
||||
|
||||
// Unsound_IsClosed() and Unsound_NumQueuedMessages() are safe to call from
|
||||
// any thread, but the value returned may be out of date, because we don't
|
||||
|
@ -10,7 +10,8 @@
|
||||
#include "nsDebug.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
|
||||
using namespace base;
|
||||
using base::GetCurrentProcessHandle;
|
||||
using base::ProcessHandle;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -451,7 +451,7 @@ class MessageChannel : HasResultCodes
|
||||
explicit DequeueTask(RefCountedTask* aTask)
|
||||
: mTask(aTask)
|
||||
{ }
|
||||
void Run() { mTask->Run(); }
|
||||
void Run() MOZ_OVERRIDE { mTask->Run(); }
|
||||
|
||||
private:
|
||||
nsRefPtr<RefCountedTask> mTask;
|
||||
|
@ -92,9 +92,17 @@ void SetThisProcessName(const char *aName)
|
||||
* NOTE: The server process serves at most one load() request.
|
||||
*/
|
||||
|
||||
using namespace base;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
using base::ChildPrivileges;
|
||||
using base::InjectionArc;
|
||||
using base::InjectiveMultimap;
|
||||
using base::ProcessHandle;
|
||||
using base::ProcessId;
|
||||
using base::SetCurrentProcessPrivileges;
|
||||
using base::ShuffleFileDescriptors;
|
||||
using base::file_handle_mapping_vector;
|
||||
|
||||
static bool sProcLoaderClientOnDeinit = false;
|
||||
static DebugOnly<bool> sProcLoaderClientInitialized = false;
|
||||
static DebugOnly<bool> sProcLoaderClientGeckoInitialized = false;
|
||||
|
@ -11,9 +11,13 @@
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/ipc/Transport.h"
|
||||
|
||||
using namespace base;
|
||||
using namespace IPC;
|
||||
|
||||
using base::GetCurrentProcessHandle;
|
||||
using base::GetProcId;
|
||||
using base::ProcessHandle;
|
||||
using base::ProcessId;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
|
@ -14,9 +14,10 @@
|
||||
#include "mozilla/ipc/Transport.h"
|
||||
#include "mozilla/ipc/FileDescriptor.h"
|
||||
|
||||
using namespace base;
|
||||
using namespace std;
|
||||
|
||||
using base::ProcessHandle;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
|
@ -10,9 +10,10 @@
|
||||
|
||||
#include "mozilla/ipc/Transport.h"
|
||||
|
||||
using namespace base;
|
||||
using namespace std;
|
||||
|
||||
using base::ProcessHandle;
|
||||
|
||||
namespace mozilla {
|
||||
namespace ipc {
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
${INCLUDES}
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
using namespace base;
|
||||
using namespace std;
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -18,7 +18,6 @@ struct RunnableMethodTraits<mozilla::_ipdltest2::TestOpensOpenedChild>
|
||||
static void ReleaseCallee(mozilla::_ipdltest2::TestOpensOpenedChild* obj) { }
|
||||
};
|
||||
|
||||
using namespace base;
|
||||
using namespace mozilla::ipc;
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -398,15 +398,15 @@ IsNormalObjectField(ExclusiveContext *cx, ParseNode *pn)
|
||||
{
|
||||
return pn->isKind(PNK_COLON) &&
|
||||
pn->getOp() == JSOP_INITPROP &&
|
||||
BinaryLeft(pn)->isKind(PNK_NAME) &&
|
||||
BinaryLeft(pn)->name() != cx->names().proto;
|
||||
BinaryLeft(pn)->isKind(PNK_OBJECT_PROPERTY_NAME);
|
||||
}
|
||||
|
||||
static inline PropertyName *
|
||||
ObjectNormalFieldName(ExclusiveContext *cx, ParseNode *pn)
|
||||
{
|
||||
MOZ_ASSERT(IsNormalObjectField(cx, pn));
|
||||
return BinaryLeft(pn)->name();
|
||||
MOZ_ASSERT(BinaryLeft(pn)->isKind(PNK_OBJECT_PROPERTY_NAME));
|
||||
return BinaryLeft(pn)->pn_atom->asPropertyName();
|
||||
}
|
||||
|
||||
static inline ParseNode *
|
||||
|
@ -1701,8 +1701,6 @@ BindNameToSlotHelper(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
{
|
||||
MOZ_ASSERT(pn->isKind(PNK_NAME));
|
||||
|
||||
MOZ_ASSERT_IF(pn->isKind(PNK_FUNCTION), pn->isBound());
|
||||
|
||||
/* Don't attempt if 'pn' is already bound or deoptimized or a function. */
|
||||
if (pn->isBound() || pn->isDeoptimized())
|
||||
return true;
|
||||
@ -3692,7 +3690,7 @@ EmitDestructuringOpsObjectHelper(ExclusiveContext *cx, BytecodeEmitter *bce, Par
|
||||
if (key->isKind(PNK_NUMBER)) {
|
||||
if (!EmitNumberOp(cx, key->pn_dval, bce)) // ... OBJ OBJ KEY
|
||||
return false;
|
||||
} else if (key->isKind(PNK_NAME) || key->isKind(PNK_STRING)) {
|
||||
} else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) {
|
||||
PropertyName *name = key->pn_atom->asPropertyName();
|
||||
|
||||
// The parser already checked for atoms representing indexes and
|
||||
@ -4325,7 +4323,7 @@ ParseNode::getConstantValue(ExclusiveContext *cx, AllowConstantObjects allowObje
|
||||
if (pnid->isKind(PNK_NUMBER)) {
|
||||
idvalue = NumberValue(pnid->pn_dval);
|
||||
} else {
|
||||
MOZ_ASSERT(pnid->isKind(PNK_NAME) || pnid->isKind(PNK_STRING));
|
||||
MOZ_ASSERT(pnid->isKind(PNK_OBJECT_PROPERTY_NAME) || pnid->isKind(PNK_STRING));
|
||||
MOZ_ASSERT(pnid->pn_atom != cx->names().proto);
|
||||
idvalue = StringValue(pnid->pn_atom);
|
||||
}
|
||||
@ -6598,7 +6596,7 @@ EmitObject(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
if (!EmitNumberOp(cx, key->pn_dval, bce))
|
||||
return false;
|
||||
isIndex = true;
|
||||
} else if (key->isKind(PNK_NAME) || key->isKind(PNK_STRING)) {
|
||||
} else if (key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING)) {
|
||||
// The parser already checked for atoms representing indexes and
|
||||
// used PNK_NUMBER instead, but also watch for ids which TI treats
|
||||
// as indexes for simpliciation of downstream analysis.
|
||||
@ -6638,7 +6636,7 @@ EmitObject(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
|
||||
if (Emit1(cx, bce, op) < 0)
|
||||
return false;
|
||||
} else {
|
||||
MOZ_ASSERT(key->isKind(PNK_NAME) || key->isKind(PNK_STRING));
|
||||
MOZ_ASSERT(key->isKind(PNK_OBJECT_PROPERTY_NAME) || key->isKind(PNK_STRING));
|
||||
|
||||
jsatomid index;
|
||||
if (!bce->makeAtomIndex(key->pn_atom, &index))
|
||||
|
@ -322,6 +322,7 @@ ContainsHoistedDeclaration(ExclusiveContext *cx, ParseNode *node, bool *result)
|
||||
|
||||
// Grammar sub-components that should never be reached directly by this
|
||||
// method, because some parent component should have asserted itself.
|
||||
case PNK_OBJECT_PROPERTY_NAME:
|
||||
case PNK_COMPUTED_NAME:
|
||||
case PNK_SPREAD:
|
||||
case PNK_MUTATEPROTO:
|
||||
@ -814,6 +815,7 @@ Fold(ExclusiveContext *cx, ParseNode **pnp,
|
||||
* NB: pn must be a PNK_IF as PNK_CONDITIONAL can never have a null
|
||||
* kid or an empty statement for a child.
|
||||
*/
|
||||
handler.prepareNodeForMutation(pn);
|
||||
pn->setKind(PNK_STATEMENTLIST);
|
||||
pn->setArity(PN_LIST);
|
||||
pn->makeEmpty();
|
||||
|
@ -104,8 +104,8 @@ class FullParseHandler
|
||||
return dn;
|
||||
}
|
||||
|
||||
ParseNode *newIdentifier(JSAtom *atom, const TokenPos &pos) {
|
||||
return new_<NullaryNode>(PNK_NAME, JSOP_NOP, pos, atom);
|
||||
ParseNode *newObjectLiteralPropertyName(JSAtom *atom, const TokenPos &pos) {
|
||||
return new_<NullaryNode>(PNK_OBJECT_PROPERTY_NAME, JSOP_NOP, pos, atom);
|
||||
}
|
||||
|
||||
ParseNode *newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) {
|
||||
@ -137,8 +137,7 @@ class FullParseHandler
|
||||
if (!propExpr)
|
||||
return null();
|
||||
|
||||
if (!addArrayElement(callSite, propExpr))
|
||||
return null();
|
||||
addArrayElement(callSite, propExpr);
|
||||
|
||||
return callSite;
|
||||
}
|
||||
@ -146,10 +145,8 @@ class FullParseHandler
|
||||
bool addToCallSiteObject(ParseNode *callSiteObj, ParseNode *rawNode, ParseNode *cookedNode) {
|
||||
MOZ_ASSERT(callSiteObj->isKind(PNK_CALLSITEOBJ));
|
||||
|
||||
if (!addArrayElement(callSiteObj, cookedNode))
|
||||
return false;
|
||||
if (!addArrayElement(callSiteObj->pn_head, rawNode))
|
||||
return false;
|
||||
addArrayElement(callSiteObj, cookedNode);
|
||||
addArrayElement(callSiteObj->pn_head, rawNode);
|
||||
|
||||
/*
|
||||
* We don't know when the last noSubstTemplate will come in, and we
|
||||
@ -270,11 +267,10 @@ class FullParseHandler
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addArrayElement(ParseNode *literal, ParseNode *element) {
|
||||
void addArrayElement(ParseNode *literal, ParseNode *element) {
|
||||
if (!element->isConstant())
|
||||
literal->pn_xflags |= PNX_NONCONST;
|
||||
literal->append(element);
|
||||
return true;
|
||||
}
|
||||
|
||||
ParseNode *newObjectLiteral(uint32_t begin) {
|
||||
@ -297,25 +293,46 @@ class FullParseHandler
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *expr,
|
||||
bool isShorthand = false) {
|
||||
bool addPropertyDefinition(ParseNode *literal, ParseNode *key, ParseNode *val) {
|
||||
MOZ_ASSERT(literal->isKind(PNK_OBJECT));
|
||||
MOZ_ASSERT(literal->isArity(PN_LIST));
|
||||
ParseNode *propdef = newBinary(isShorthand ? PNK_SHORTHAND : PNK_COLON, name, expr,
|
||||
JSOP_INITPROP);
|
||||
if (isShorthand)
|
||||
literal->pn_xflags |= PNX_NONCONST;
|
||||
MOZ_ASSERT(key->isKind(PNK_NUMBER) ||
|
||||
key->isKind(PNK_OBJECT_PROPERTY_NAME) ||
|
||||
key->isKind(PNK_STRING) ||
|
||||
key->isKind(PNK_COMPUTED_NAME));
|
||||
|
||||
ParseNode *propdef = newBinary(PNK_COLON, key, val, JSOP_INITPROP);
|
||||
if (!propdef)
|
||||
return false;
|
||||
literal->append(propdef);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addMethodDefinition(ParseNode *literal, ParseNode *name, ParseNode *fn, JSOp op)
|
||||
bool addShorthand(ParseNode *literal, ParseNode *name, ParseNode *expr) {
|
||||
MOZ_ASSERT(literal->isKind(PNK_OBJECT));
|
||||
MOZ_ASSERT(literal->isArity(PN_LIST));
|
||||
MOZ_ASSERT(name->isKind(PNK_OBJECT_PROPERTY_NAME));
|
||||
MOZ_ASSERT(expr->isKind(PNK_NAME));
|
||||
MOZ_ASSERT(name->pn_atom == expr->pn_atom);
|
||||
|
||||
setListFlag(literal, PNX_NONCONST);
|
||||
ParseNode *propdef = newBinary(PNK_SHORTHAND, name, expr, JSOP_INITPROP);
|
||||
if (!propdef)
|
||||
return false;
|
||||
literal->append(propdef);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool addMethodDefinition(ParseNode *literal, ParseNode *key, ParseNode *fn, JSOp op)
|
||||
{
|
||||
MOZ_ASSERT(literal->isArity(PN_LIST));
|
||||
MOZ_ASSERT(key->isKind(PNK_NUMBER) ||
|
||||
key->isKind(PNK_OBJECT_PROPERTY_NAME) ||
|
||||
key->isKind(PNK_STRING) ||
|
||||
key->isKind(PNK_COMPUTED_NAME));
|
||||
literal->pn_xflags |= PNX_NONCONST;
|
||||
|
||||
ParseNode *propdef = newBinary(PNK_COLON, name, fn, op);
|
||||
ParseNode *propdef = newBinary(PNK_COLON, key, fn, op);
|
||||
if (!propdef)
|
||||
return false;
|
||||
literal->append(propdef);
|
||||
|
@ -224,12 +224,14 @@ class NameResolver
|
||||
|
||||
if (node->isKind(PNK_COLON) || node->isKind(PNK_SHORTHAND)) {
|
||||
ParseNode *left = node->pn_left;
|
||||
if (left->isKind(PNK_NAME) || left->isKind(PNK_STRING)) {
|
||||
if (left->isKind(PNK_OBJECT_PROPERTY_NAME) || left->isKind(PNK_STRING)) {
|
||||
if (!appendPropertyReference(left->pn_atom))
|
||||
return false;
|
||||
} else if (left->isKind(PNK_NUMBER)) {
|
||||
if (!appendNumericPropertyReference(left->pn_dval))
|
||||
return false;
|
||||
} else {
|
||||
MOZ_ASSERT(left->isKind(PNK_COMPUTED_NAME));
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
|
@ -79,7 +79,6 @@ class NodeStack {
|
||||
pn->pn_next = top;
|
||||
top = pn;
|
||||
}
|
||||
void pushUnlessNull(ParseNode *pn) { if (pn) push(pn); }
|
||||
/* Push the children of the PN_LIST node |pn| on the stack. */
|
||||
void pushList(ParseNode *pn) {
|
||||
/* This clobbers pn->pn_head if the list is empty; should be okay. */
|
||||
@ -123,7 +122,8 @@ PushCodeNodeChildren(ParseNode *node, NodeStack *stack)
|
||||
* them.
|
||||
*/
|
||||
node->pn_funbox = nullptr;
|
||||
stack->pushUnlessNull(node->pn_body);
|
||||
if (node->pn_body)
|
||||
stack->push(node->pn_body);
|
||||
node->pn_body = nullptr;
|
||||
|
||||
return PushResult::CleanUpLater;
|
||||
@ -146,7 +146,8 @@ PushNameNodeChildren(ParseNode *node, NodeStack *stack)
|
||||
* reference.
|
||||
*/
|
||||
if (!node->isUsed()) {
|
||||
stack->pushUnlessNull(node->pn_expr);
|
||||
if (node->pn_expr)
|
||||
stack->push(node->pn_expr);
|
||||
node->pn_expr = nullptr;
|
||||
}
|
||||
|
||||
@ -167,18 +168,6 @@ PushListNodeChildren(ParseNode *node, NodeStack *stack)
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
static PushResult
|
||||
PushTernaryNodeNullableChildren(ParseNode *node, NodeStack *stack)
|
||||
{
|
||||
MOZ_ASSERT(node->isArity(PN_TERNARY));
|
||||
|
||||
stack->pushUnlessNull(node->pn_kid1);
|
||||
stack->pushUnlessNull(node->pn_kid2);
|
||||
stack->pushUnlessNull(node->pn_kid3);
|
||||
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
static PushResult
|
||||
PushUnaryNodeChild(ParseNode *node, NodeStack *stack)
|
||||
{
|
||||
@ -189,57 +178,6 @@ PushUnaryNodeChild(ParseNode *node, NodeStack *stack)
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
static PushResult
|
||||
PushUnaryNodeNullableChild(ParseNode *node, NodeStack *stack)
|
||||
{
|
||||
MOZ_ASSERT(node->isArity(PN_UNARY));
|
||||
|
||||
if (node->pn_kid)
|
||||
stack->push(node->pn_kid);
|
||||
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
static PushResult
|
||||
PushBinaryNodeChildren(ParseNode *node, NodeStack *stack)
|
||||
{
|
||||
MOZ_ASSERT(node->isArity(PN_BINARY));
|
||||
|
||||
stack->push(node->pn_left);
|
||||
stack->push(node->pn_right);
|
||||
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
static PushResult
|
||||
PushBinaryNodeNullableChildren(ParseNode *node, NodeStack *stack)
|
||||
{
|
||||
MOZ_ASSERT(node->isArity(PN_BINARY) || node->isArity(PN_BINARY_OBJ));
|
||||
|
||||
if (node->pn_left != node->pn_right) {
|
||||
// XXX Is it ever the case that left == right any more? I think this
|
||||
// used to be PNK_SHORTHAND, but its two children are now different
|
||||
// nodes that are structurally equivalent, so PNK_SHORTHAND doesn't
|
||||
// require this.
|
||||
stack->pushUnlessNull(node->pn_left);
|
||||
}
|
||||
|
||||
stack->pushUnlessNull(node->pn_right);
|
||||
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
static PushResult
|
||||
CanRecycleNullaryNode(ParseNode *node, NodeStack *stack)
|
||||
{
|
||||
MOZ_ASSERT(node->isArity(PN_NULLARY));
|
||||
|
||||
if (node->isUsed() || node->isDefn())
|
||||
return PushResult::CleanUpLater;
|
||||
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
/*
|
||||
* Push the children of |pn| on |stack|. Return true if |pn| itself could be
|
||||
* safely recycled, or false if it must be cleaned later (pn_used and pn_defn
|
||||
@ -269,6 +207,7 @@ PushNodeChildren(ParseNode *pn, NodeStack *stack)
|
||||
case PNK_CONTINUE:
|
||||
case PNK_DEBUGGER:
|
||||
case PNK_EXPORT_BATCH_SPEC:
|
||||
case PNK_OBJECT_PROPERTY_NAME:
|
||||
MOZ_ASSERT(pn->isArity(PN_NULLARY));
|
||||
MOZ_ASSERT(!pn->isUsed(), "handle non-trivial cases separately");
|
||||
MOZ_ASSERT(!pn->isDefn(), "handle non-trivial cases separately");
|
||||
@ -295,8 +234,12 @@ PushNodeChildren(ParseNode *pn, NodeStack *stack)
|
||||
return PushUnaryNodeChild(pn, stack);
|
||||
|
||||
// Nodes with a single nullable child.
|
||||
case PNK_SEMI:
|
||||
return PushUnaryNodeNullableChild(pn, stack);
|
||||
case PNK_SEMI: {
|
||||
MOZ_ASSERT(pn->isArity(PN_UNARY));
|
||||
if (pn->pn_kid)
|
||||
stack->push(pn->pn_kid);
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
// Binary nodes with two non-null children.
|
||||
|
||||
@ -314,6 +257,10 @@ PushNodeChildren(ParseNode *pn, NodeStack *stack)
|
||||
case PNK_DIVASSIGN:
|
||||
case PNK_MODASSIGN:
|
||||
// ...and a few others.
|
||||
case PNK_ELEM:
|
||||
case PNK_LETEXPR:
|
||||
case PNK_IMPORT_SPEC:
|
||||
case PNK_EXPORT_SPEC:
|
||||
case PNK_COLON:
|
||||
case PNK_CASE:
|
||||
case PNK_SHORTHAND:
|
||||
@ -321,8 +268,23 @@ PushNodeChildren(ParseNode *pn, NodeStack *stack)
|
||||
case PNK_WHILE:
|
||||
case PNK_SWITCH:
|
||||
case PNK_LETBLOCK:
|
||||
case PNK_FOR:
|
||||
return PushBinaryNodeChildren(pn, stack);
|
||||
case PNK_FOR: {
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
stack->push(pn->pn_left);
|
||||
stack->push(pn->pn_right);
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
// PNK_WITH is PN_BINARY_OBJ -- that is, PN_BINARY with (irrelevant for
|
||||
// this method's purposes) the addition of the StaticWithObject as
|
||||
// pn_binary_obj. Both left (expression) and right (statement) are
|
||||
// non-null.
|
||||
case PNK_WITH: {
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY_OBJ));
|
||||
stack->push(pn->pn_left);
|
||||
stack->push(pn->pn_right);
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
// Default nodes, for dumb reasons that we're not changing now (mostly
|
||||
// structural semi-consistency with PNK_CASE nodes), have a null left
|
||||
@ -352,6 +314,36 @@ PushNodeChildren(ParseNode *pn, NodeStack *stack)
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
// A return node's left half is what you'd expect: the return expression,
|
||||
// if any. The right half is non-null only for returns inside generator
|
||||
// functions, with the structure described in the assertions.
|
||||
case PNK_RETURN: {
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
if (pn->pn_left)
|
||||
stack->push(pn->pn_left);
|
||||
if (pn->pn_right) {
|
||||
MOZ_ASSERT(pn->pn_right->isKind(PNK_NAME));
|
||||
MOZ_ASSERT(pn->pn_right->pn_atom->equals(".genrval"));
|
||||
MOZ_ASSERT(pn->pn_right->isAssigned());
|
||||
stack->push(pn->pn_right);
|
||||
}
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
// Import and export-from nodes have a list of specifiers on the left
|
||||
// and a module string on the right.
|
||||
case PNK_IMPORT:
|
||||
case PNK_EXPORT_FROM: {
|
||||
MOZ_ASSERT(pn->isArity(PN_BINARY));
|
||||
MOZ_ASSERT_IF(pn->isKind(PNK_IMPORT), pn->pn_left->isKind(PNK_IMPORT_SPEC_LIST));
|
||||
MOZ_ASSERT_IF(pn->isKind(PNK_EXPORT_FROM), pn->pn_left->isKind(PNK_EXPORT_SPEC_LIST));
|
||||
MOZ_ASSERT(pn->pn_left->isArity(PN_LIST));
|
||||
MOZ_ASSERT(pn->pn_right->isKind(PNK_STRING));
|
||||
stack->pushList(pn->pn_left);
|
||||
stack->push(pn->pn_right);
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
// Ternary nodes with all children non-null.
|
||||
case PNK_CONDITIONAL: {
|
||||
MOZ_ASSERT(pn->isArity(PN_TERNARY));
|
||||
@ -378,8 +370,16 @@ PushNodeChildren(ParseNode *pn, NodeStack *stack)
|
||||
}
|
||||
|
||||
// for (;;) nodes have one child per optional component of the loop head.
|
||||
case PNK_FORHEAD:
|
||||
return PushTernaryNodeNullableChildren(pn, stack);
|
||||
case PNK_FORHEAD: {
|
||||
MOZ_ASSERT(pn->isArity(PN_TERNARY));
|
||||
if (pn->pn_kid1)
|
||||
stack->push(pn->pn_kid1);
|
||||
if (pn->pn_kid2)
|
||||
stack->push(pn->pn_kid2);
|
||||
if (pn->pn_kid3)
|
||||
stack->push(pn->pn_kid3);
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
// if-statement nodes have condition and consequent children and a
|
||||
// possibly-null alternative.
|
||||
@ -405,6 +405,19 @@ PushNodeChildren(ParseNode *pn, NodeStack *stack)
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
// A catch node has first kid as catch-variable pattern, the second kid
|
||||
// as catch condition (which, if non-null, records the |<cond>| in
|
||||
// SpiderMonkey's |catch (e if <cond>)| extension), and third kid as the
|
||||
// statements in the catch block.
|
||||
case PNK_CATCH: {
|
||||
MOZ_ASSERT(pn->isArity(PN_TERNARY));
|
||||
stack->push(pn->pn_kid1);
|
||||
if (pn->pn_kid2)
|
||||
stack->push(pn->pn_kid2);
|
||||
stack->push(pn->pn_kid3);
|
||||
return PushResult::Recyclable;
|
||||
}
|
||||
|
||||
// List nodes with all non-null children.
|
||||
case PNK_OR:
|
||||
case PNK_AND:
|
||||
@ -430,77 +443,54 @@ PushNodeChildren(ParseNode *pn, NodeStack *stack)
|
||||
case PNK_DIV:
|
||||
case PNK_MOD:
|
||||
case PNK_COMMA:
|
||||
case PNK_NEW:
|
||||
case PNK_CALL:
|
||||
case PNK_GENEXP:
|
||||
case PNK_ARRAY:
|
||||
case PNK_OBJECT:
|
||||
case PNK_TEMPLATE_STRING_LIST:
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
case PNK_CALLSITEOBJ:
|
||||
case PNK_VAR:
|
||||
case PNK_CONST:
|
||||
case PNK_GLOBALCONST:
|
||||
case PNK_LET:
|
||||
case PNK_CATCHLIST:
|
||||
case PNK_STATEMENTLIST:
|
||||
case PNK_IMPORT_SPEC_LIST:
|
||||
case PNK_EXPORT_SPEC_LIST:
|
||||
case PNK_SEQ:
|
||||
case PNK_ARGSBODY:
|
||||
return PushListNodeChildren(pn, stack);
|
||||
|
||||
// Array comprehension nodes are lists with a single child -- PNK_FOR for
|
||||
// comprehensions, PNK_LEXICALSCOPE for legacy comprehensions. Probably
|
||||
// this should be a non-list eventually.
|
||||
case PNK_ARRAYCOMP: {
|
||||
#ifdef DEBUG
|
||||
MOZ_ASSERT(pn->isKind(PNK_ARRAYCOMP));
|
||||
MOZ_ASSERT(pn->isArity(PN_LIST));
|
||||
MOZ_ASSERT(pn->pn_count == 1);
|
||||
MOZ_ASSERT(pn->pn_head->isKind(PNK_LEXICALSCOPE) || pn->pn_head->isKind(PNK_FOR));
|
||||
#endif
|
||||
return PushListNodeChildren(pn, stack);
|
||||
}
|
||||
|
||||
case PNK_LABEL:
|
||||
case PNK_DOT:
|
||||
case PNK_LEXICALSCOPE:
|
||||
case PNK_NAME:
|
||||
return PushNameNodeChildren(pn, stack);
|
||||
|
||||
case PNK_DOT:
|
||||
case PNK_ELEM:
|
||||
case PNK_STATEMENTLIST:
|
||||
case PNK_CALL:
|
||||
case PNK_NAME:
|
||||
case PNK_TEMPLATE_STRING_LIST:
|
||||
case PNK_TAGGED_TEMPLATE:
|
||||
case PNK_CALLSITEOBJ:
|
||||
case PNK_FUNCTION:
|
||||
case PNK_WITH:
|
||||
case PNK_RETURN:
|
||||
case PNK_NEW:
|
||||
case PNK_CATCH:
|
||||
case PNK_GENEXP:
|
||||
case PNK_ARRAYCOMP:
|
||||
case PNK_LEXICALSCOPE:
|
||||
case PNK_LET:
|
||||
case PNK_LETEXPR:
|
||||
case PNK_IMPORT:
|
||||
case PNK_IMPORT_SPEC_LIST:
|
||||
case PNK_IMPORT_SPEC:
|
||||
case PNK_EXPORT_FROM:
|
||||
case PNK_EXPORT_SPEC_LIST:
|
||||
case PNK_EXPORT_SPEC:
|
||||
break; // for now
|
||||
return PushCodeNodeChildren(pn, stack);
|
||||
|
||||
case PNK_LIMIT: // invalid sentinel value
|
||||
MOZ_CRASH("invalid node kind");
|
||||
}
|
||||
|
||||
// Fallthrough for not-yet-handled kinds.
|
||||
switch (pn->getArity()) {
|
||||
case PN_CODE:
|
||||
return PushCodeNodeChildren(pn, stack);
|
||||
|
||||
case PN_NAME:
|
||||
return PushNameNodeChildren(pn, stack);
|
||||
|
||||
case PN_LIST:
|
||||
return PushListNodeChildren(pn, stack);
|
||||
|
||||
case PN_TERNARY:
|
||||
return PushTernaryNodeNullableChildren(pn, stack);
|
||||
|
||||
case PN_BINARY:
|
||||
case PN_BINARY_OBJ:
|
||||
return PushBinaryNodeNullableChildren(pn, stack);
|
||||
|
||||
case PN_UNARY:
|
||||
return PushUnaryNodeNullableChild(pn, stack);
|
||||
|
||||
case PN_NULLARY:
|
||||
return CanRecycleNullaryNode(pn, stack);
|
||||
|
||||
default:
|
||||
MOZ_CRASH("huh?");
|
||||
return PushResult::CleanUpLater;
|
||||
}
|
||||
MOZ_CRASH("bad ParseNodeKind");
|
||||
return PushResult::CleanUpLater;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -89,6 +89,7 @@ class UpvarCookie
|
||||
F(OBJECT) \
|
||||
F(CALL) \
|
||||
F(NAME) \
|
||||
F(OBJECT_PROPERTY_NAME) \
|
||||
F(COMPUTED_NAME) \
|
||||
F(NUMBER) \
|
||||
F(STRING) \
|
||||
|
@ -7008,26 +7008,30 @@ template <>
|
||||
ParseNode*
|
||||
Parser<FullParseHandler>::legacyArrayComprehension(ParseNode *array)
|
||||
{
|
||||
array->setKind(PNK_ARRAYCOMP);
|
||||
|
||||
// Remove the single element from array's linked list, leaving us with an
|
||||
// empty array literal and a comprehension expression.
|
||||
// Discard our presumed array literal containing only a single element, and
|
||||
// instead return an array comprehension node. Extract the few bits of
|
||||
// information needed from the array literal, then free it.
|
||||
MOZ_ASSERT(array->isKind(PNK_ARRAY));
|
||||
MOZ_ASSERT(array->pn_count == 1);
|
||||
ParseNode *bodyExpr = array->last();
|
||||
|
||||
uint32_t arrayBegin = handler.getPosition(array).begin;
|
||||
uint32_t blockid = array->pn_blockid;
|
||||
|
||||
ParseNode *bodyExpr = array->pn_head;
|
||||
array->pn_count = 0;
|
||||
array->pn_tail = &array->pn_head;
|
||||
*array->pn_tail = nullptr;
|
||||
|
||||
ParseNode *comp = legacyComprehensionTail(bodyExpr, array->pn_blockid, NotGenerator,
|
||||
nullptr, LegacyComprehensionHeadBlockScopeDepth(pc));
|
||||
handler.freeTree(array);
|
||||
|
||||
ParseNode *comp = legacyComprehensionTail(bodyExpr, blockid, NotGenerator, nullptr,
|
||||
LegacyComprehensionHeadBlockScopeDepth(pc));
|
||||
if (!comp)
|
||||
return null();
|
||||
|
||||
MUST_MATCH_TOKEN(TOK_RB, JSMSG_BRACKET_AFTER_ARRAY_COMPREHENSION);
|
||||
|
||||
TokenPos p = handler.getPosition(array);
|
||||
p.end = pos().end;
|
||||
return handler.newArrayComprehension(comp, array->pn_blockid, p);
|
||||
return handler.newArrayComprehension(comp, blockid, TokenPos(arrayBegin, pos().end));
|
||||
}
|
||||
|
||||
template <>
|
||||
@ -7770,8 +7774,7 @@ Parser<ParseHandler>::arrayInitializer()
|
||||
return null();
|
||||
if (foldConstants && !FoldConstants(context, &element, this))
|
||||
return null();
|
||||
if (!handler.addArrayElement(literal, element))
|
||||
return null();
|
||||
handler.addArrayElement(literal, element);
|
||||
}
|
||||
|
||||
if (tt != TOK_COMMA) {
|
||||
@ -7936,7 +7939,7 @@ Parser<ParseHandler>::objectLiteral()
|
||||
op = atom == context->names().get ? JSOP_INITPROP_GETTER
|
||||
: JSOP_INITPROP_SETTER;
|
||||
} else {
|
||||
propname = handler.newIdentifier(atom, pos());
|
||||
propname = handler.newObjectLiteralPropertyName(atom, pos());
|
||||
if (!propname)
|
||||
return null();
|
||||
break;
|
||||
@ -7949,7 +7952,7 @@ Parser<ParseHandler>::objectLiteral()
|
||||
return null();
|
||||
if (tt == TOK_NAME) {
|
||||
atom = tokenStream.currentName();
|
||||
propname = newName(atom->asPropertyName());
|
||||
propname = handler.newObjectLiteralPropertyName(atom, pos());
|
||||
if (!propname)
|
||||
return null();
|
||||
} else if (tt == TOK_STRING) {
|
||||
@ -7982,7 +7985,7 @@ Parser<ParseHandler>::objectLiteral()
|
||||
} else {
|
||||
// Not an accessor property after all.
|
||||
tokenStream.ungetToken();
|
||||
propname = handler.newIdentifier(atom, pos());
|
||||
propname = handler.newObjectLiteralPropertyName(atom, pos());
|
||||
if (!propname)
|
||||
return null();
|
||||
op = JSOP_INITPROP;
|
||||
@ -8061,20 +8064,16 @@ Parser<ParseHandler>::objectLiteral()
|
||||
report(ParseError, false, null(), JSMSG_BAD_PROP_ID);
|
||||
return null();
|
||||
}
|
||||
if (!abortIfSyntaxParser())
|
||||
return null();
|
||||
|
||||
tokenStream.ungetToken();
|
||||
if (!tokenStream.checkForKeyword(atom, nullptr))
|
||||
return null();
|
||||
PropertyName *name = handler.isName(propname);
|
||||
MOZ_ASSERT(atom);
|
||||
propname = newName(name);
|
||||
if (!propname)
|
||||
|
||||
Node nameExpr = identifierName();
|
||||
if (!nameExpr)
|
||||
return null();
|
||||
Node ident = identifierName();
|
||||
if (!ident)
|
||||
return null();
|
||||
if (!handler.addPropertyDefinition(literal, propname, ident, true))
|
||||
|
||||
if (!handler.addShorthand(literal, propname, nameExpr))
|
||||
return null();
|
||||
} else if (tt == TOK_LP) {
|
||||
tokenStream.ungetToken();
|
||||
|
@ -120,7 +120,10 @@ class SyntaxParseHandler
|
||||
return Definition::PLACEHOLDER;
|
||||
}
|
||||
|
||||
Node newIdentifier(JSAtom *atom, const TokenPos &pos) { return NodeName; }
|
||||
Node newObjectLiteralPropertyName(JSAtom *atom, const TokenPos &pos) {
|
||||
return NodeName;
|
||||
}
|
||||
|
||||
Node newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) { return NodeGeneric; }
|
||||
Node newBooleanLiteral(bool cond, const TokenPos &pos) { return NodeGeneric; }
|
||||
|
||||
@ -180,11 +183,12 @@ class SyntaxParseHandler
|
||||
Node newArrayLiteral(uint32_t begin, unsigned blockid) { return NodeGeneric; }
|
||||
bool addElision(Node literal, const TokenPos &pos) { return true; }
|
||||
bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; }
|
||||
bool addArrayElement(Node literal, Node element) { return true; }
|
||||
void addArrayElement(Node literal, Node element) { }
|
||||
|
||||
Node newObjectLiteral(uint32_t begin) { return NodeGeneric; }
|
||||
bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; }
|
||||
bool addPropertyDefinition(Node literal, Node name, Node expr, bool isShorthand = false) { return true; }
|
||||
bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; }
|
||||
bool addShorthand(Node literal, Node name, Node expr) { return true; }
|
||||
bool addMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
|
||||
Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; }
|
||||
Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
|
||||
|
@ -471,7 +471,7 @@ static const size_t MAX_ATTEMPTS = 2;
|
||||
|
||||
bool
|
||||
BacktrackingAllocator::tryAllocateFixed(LiveInterval *interval, bool *success,
|
||||
bool *pfixed, LiveInterval **pconflicting)
|
||||
bool *pfixed, LiveIntervalVector &conflicting)
|
||||
{
|
||||
// Spill intervals which are required to be in a certain stack slot.
|
||||
if (!interval->requirement()->allocation().isRegister()) {
|
||||
@ -482,12 +482,12 @@ BacktrackingAllocator::tryAllocateFixed(LiveInterval *interval, bool *success,
|
||||
}
|
||||
|
||||
AnyRegister reg = interval->requirement()->allocation().toRegister();
|
||||
return tryAllocateRegister(registers[reg.code()], interval, success, pfixed, pconflicting);
|
||||
return tryAllocateRegister(registers[reg.code()], interval, success, pfixed, conflicting);
|
||||
}
|
||||
|
||||
bool
|
||||
BacktrackingAllocator::tryAllocateNonFixed(LiveInterval *interval, bool *success,
|
||||
bool *pfixed, LiveInterval **pconflicting)
|
||||
bool *pfixed, LiveIntervalVector &conflicting)
|
||||
{
|
||||
// If we want, but do not require an interval to be in a specific
|
||||
// register, only look at that register for allocating and evict
|
||||
@ -496,7 +496,7 @@ BacktrackingAllocator::tryAllocateNonFixed(LiveInterval *interval, bool *success
|
||||
// and will tie up more registers than if we spilled.
|
||||
if (interval->hint()->kind() == Requirement::FIXED) {
|
||||
AnyRegister reg = interval->hint()->allocation().toRegister();
|
||||
if (!tryAllocateRegister(registers[reg.code()], interval, success, pfixed, pconflicting))
|
||||
if (!tryAllocateRegister(registers[reg.code()], interval, success, pfixed, conflicting))
|
||||
return false;
|
||||
if (*success)
|
||||
return true;
|
||||
@ -511,11 +511,11 @@ BacktrackingAllocator::tryAllocateNonFixed(LiveInterval *interval, bool *success
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!*pconflicting || minimalInterval(interval)) {
|
||||
if (conflicting.empty() || minimalInterval(interval)) {
|
||||
// Search for any available register which the interval can be
|
||||
// allocated to.
|
||||
for (size_t i = 0; i < AnyRegister::Total; i++) {
|
||||
if (!tryAllocateRegister(registers[i], interval, success, pfixed, pconflicting))
|
||||
if (!tryAllocateRegister(registers[i], interval, success, pfixed, conflicting))
|
||||
return false;
|
||||
if (*success)
|
||||
return true;
|
||||
@ -568,19 +568,19 @@ BacktrackingAllocator::processInterval(LiveInterval *interval)
|
||||
bool canAllocate = setIntervalRequirement(interval);
|
||||
|
||||
bool fixed;
|
||||
LiveInterval *conflict = nullptr;
|
||||
LiveIntervalVector conflicting;
|
||||
for (size_t attempt = 0;; attempt++) {
|
||||
if (canAllocate) {
|
||||
bool success = false;
|
||||
fixed = false;
|
||||
conflict = nullptr;
|
||||
conflicting.clear();
|
||||
|
||||
// Ok, let's try allocating for this interval.
|
||||
if (interval->requirement()->kind() == Requirement::FIXED) {
|
||||
if (!tryAllocateFixed(interval, &success, &fixed, &conflict))
|
||||
if (!tryAllocateFixed(interval, &success, &fixed, conflicting))
|
||||
return false;
|
||||
} else {
|
||||
if (!tryAllocateNonFixed(interval, &success, &fixed, &conflict))
|
||||
if (!tryAllocateNonFixed(interval, &success, &fixed, conflicting))
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -588,15 +588,17 @@ BacktrackingAllocator::processInterval(LiveInterval *interval)
|
||||
if (success)
|
||||
return true;
|
||||
|
||||
// If that didn't work, but we have a non-fixed LiveInterval known
|
||||
// to be conflicting, maybe we can evict it and try again.
|
||||
// If that didn't work, but we have one or more non-fixed intervals
|
||||
// known to be conflicting, maybe we can evict them and try again.
|
||||
if (attempt < MAX_ATTEMPTS &&
|
||||
!fixed &&
|
||||
conflict &&
|
||||
computeSpillWeight(conflict) < computeSpillWeight(interval))
|
||||
!conflicting.empty() &&
|
||||
maximumSpillWeight(conflicting) < computeSpillWeight(interval))
|
||||
{
|
||||
if (!evictInterval(conflict))
|
||||
return false;
|
||||
for (size_t i = 0; i < conflicting.length(); i++) {
|
||||
if (!evictInterval(conflicting[i]))
|
||||
return false;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -607,6 +609,7 @@ BacktrackingAllocator::processInterval(LiveInterval *interval)
|
||||
// be constructed so that any minimal interval is allocatable.
|
||||
MOZ_ASSERT(!minimalInterval(interval));
|
||||
|
||||
LiveInterval *conflict = conflicting.empty() ? nullptr : conflicting[0];
|
||||
return chooseIntervalSplit(interval, canAllocate && fixed, conflict);
|
||||
}
|
||||
}
|
||||
@ -782,7 +785,7 @@ BacktrackingAllocator::tryAllocateGroupRegister(PhysicalRegister &r, VirtualRegi
|
||||
|
||||
bool
|
||||
BacktrackingAllocator::tryAllocateRegister(PhysicalRegister &r, LiveInterval *interval,
|
||||
bool *success, bool *pfixed, LiveInterval **pconflicting)
|
||||
bool *success, bool *pfixed, LiveIntervalVector &conflicting)
|
||||
{
|
||||
*success = false;
|
||||
|
||||
@ -796,6 +799,8 @@ BacktrackingAllocator::tryAllocateRegister(PhysicalRegister &r, LiveInterval *in
|
||||
MOZ_ASSERT_IF(interval->requirement()->kind() == Requirement::FIXED,
|
||||
interval->requirement()->allocation() == LAllocation(r.reg));
|
||||
|
||||
LiveIntervalVector aliasedConflicting;
|
||||
|
||||
for (size_t i = 0; i < interval->numRanges(); i++) {
|
||||
AllocatedRange range(interval, interval->getRange(i)), existing;
|
||||
for (size_t a = 0; a < r.reg.numAliased(); a++) {
|
||||
@ -803,26 +808,63 @@ BacktrackingAllocator::tryAllocateRegister(PhysicalRegister &r, LiveInterval *in
|
||||
if (!rAlias.allocations.contains(range, &existing))
|
||||
continue;
|
||||
if (existing.interval->hasVreg()) {
|
||||
if (JitSpewEnabled(JitSpew_RegAlloc)) {
|
||||
JitSpew(JitSpew_RegAlloc, " %s collides with v%u[%u] %s [weight %lu]",
|
||||
rAlias.reg.name(), existing.interval->vreg(),
|
||||
existing.interval->index(),
|
||||
existing.range->toString(),
|
||||
computeSpillWeight(existing.interval));
|
||||
MOZ_ASSERT(existing.interval->getAllocation()->toRegister() == rAlias.reg);
|
||||
bool duplicate = false;
|
||||
for (size_t i = 0; i < aliasedConflicting.length(); i++) {
|
||||
if (aliasedConflicting[i] == existing.interval) {
|
||||
duplicate = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!*pconflicting || computeSpillWeight(existing.interval) < computeSpillWeight(*pconflicting))
|
||||
*pconflicting = existing.interval;
|
||||
if (!duplicate && !aliasedConflicting.append(existing.interval))
|
||||
return false;
|
||||
} else {
|
||||
if (JitSpewEnabled(JitSpew_RegAlloc)) {
|
||||
JitSpew(JitSpew_RegAlloc, " %s collides with fixed use %s",
|
||||
rAlias.reg.name(), existing.range->toString());
|
||||
}
|
||||
*pfixed = true;
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!aliasedConflicting.empty()) {
|
||||
// One or more aliased registers is allocated to another live interval
|
||||
// overlapping this one. Keep track of the conflicting set, and in the
|
||||
// case of multiple conflicting sets keep track of the set with the
|
||||
// lowest maximum spill weight.
|
||||
|
||||
if (JitSpewEnabled(JitSpew_RegAlloc)) {
|
||||
if (aliasedConflicting.length() == 1) {
|
||||
LiveInterval *existing = aliasedConflicting[0];
|
||||
JitSpew(JitSpew_RegAlloc, " %s collides with v%u[%u] %s [weight %lu]",
|
||||
r.reg.name(), existing->vreg(), existing->index(),
|
||||
existing->rangesToString(), computeSpillWeight(existing));
|
||||
} else {
|
||||
JitSpew(JitSpew_RegAlloc, " %s collides with the following", r.reg.name());
|
||||
for (size_t i = 0; i < aliasedConflicting.length(); i++) {
|
||||
LiveInterval *existing = aliasedConflicting[i];
|
||||
JitSpew(JitSpew_RegAlloc, " v%u[%u] %s [weight %lu]",
|
||||
existing->vreg(), existing->index(),
|
||||
existing->rangesToString(), computeSpillWeight(existing));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (conflicting.empty()) {
|
||||
if (!conflicting.appendAll(aliasedConflicting))
|
||||
return false;
|
||||
} else {
|
||||
if (maximumSpillWeight(aliasedConflicting) < maximumSpillWeight(conflicting)) {
|
||||
conflicting.clear();
|
||||
if (!conflicting.appendAll(aliasedConflicting))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
JitSpew(JitSpew_RegAlloc, " allocated to %s", r.reg.name());
|
||||
|
||||
for (size_t i = 0; i < interval->numRanges(); i++) {
|
||||
@ -1792,6 +1834,15 @@ BacktrackingAllocator::computeSpillWeight(const VirtualRegisterGroup *group)
|
||||
return maxWeight;
|
||||
}
|
||||
|
||||
size_t
|
||||
BacktrackingAllocator::maximumSpillWeight(const LiveIntervalVector &intervals)
|
||||
{
|
||||
size_t maxWeight = 0;
|
||||
for (size_t i = 0; i < intervals.length(); i++)
|
||||
maxWeight = Max(maxWeight, computeSpillWeight(intervals[i]));
|
||||
return maxWeight;
|
||||
}
|
||||
|
||||
bool
|
||||
BacktrackingAllocator::trySplitAcrossHotcode(LiveInterval *interval, bool *success)
|
||||
{
|
||||
|
@ -211,13 +211,15 @@ class BacktrackingAllocator
|
||||
bool tryGroupRegisters(uint32_t vreg0, uint32_t vreg1);
|
||||
bool tryGroupReusedRegister(uint32_t def, uint32_t use);
|
||||
bool groupAndQueueRegisters();
|
||||
bool tryAllocateFixed(LiveInterval *interval, bool *success, bool *pfixed, LiveInterval **pconflicting);
|
||||
bool tryAllocateNonFixed(LiveInterval *interval, bool *success, bool *pfixed, LiveInterval **pconflicting);
|
||||
bool tryAllocateFixed(LiveInterval *interval, bool *success, bool *pfixed,
|
||||
LiveIntervalVector &conflicting);
|
||||
bool tryAllocateNonFixed(LiveInterval *interval, bool *success, bool *pfixed,
|
||||
LiveIntervalVector &conflicting);
|
||||
bool processInterval(LiveInterval *interval);
|
||||
bool processGroup(VirtualRegisterGroup *group);
|
||||
bool setIntervalRequirement(LiveInterval *interval);
|
||||
bool tryAllocateRegister(PhysicalRegister &r, LiveInterval *interval,
|
||||
bool *success, bool *pfixed, LiveInterval **pconflicting);
|
||||
bool *success, bool *pfixed, LiveIntervalVector &conflicting);
|
||||
bool tryAllocateGroupRegister(PhysicalRegister &r, VirtualRegisterGroup *group,
|
||||
bool *psuccess, bool *pfixed, LiveInterval **pconflicting);
|
||||
bool evictInterval(LiveInterval *interval);
|
||||
@ -261,6 +263,8 @@ class BacktrackingAllocator
|
||||
size_t computePriority(const VirtualRegisterGroup *group);
|
||||
size_t computeSpillWeight(const VirtualRegisterGroup *group);
|
||||
|
||||
size_t maximumSpillWeight(const LiveIntervalVector &intervals);
|
||||
|
||||
bool chooseIntervalSplit(LiveInterval *interval, bool fixed, LiveInterval *conflict);
|
||||
|
||||
bool splitAt(LiveInterval *interval,
|
||||
|
@ -2384,6 +2384,14 @@ MacroAssemblerMIPSCompat::branchTestObject(Condition cond, const BaseIndex &src,
|
||||
ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_OBJECT), label, cond);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::branchTestObject(Condition cond, const Address &address, Label *label)
|
||||
{
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
extractTag(address, SecondScratchReg);
|
||||
ma_b(SecondScratchReg, ImmTag(JSVAL_TAG_OBJECT), label, cond);
|
||||
}
|
||||
|
||||
void
|
||||
MacroAssemblerMIPSCompat::testObjectSet(Condition cond, const ValueOperand &value, Register dest)
|
||||
{
|
||||
|
@ -687,6 +687,7 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS
|
||||
void branchTestObject(Condition cond, const ValueOperand &value, Label *label);
|
||||
void branchTestObject(Condition cond, Register tag, Label *label);
|
||||
void branchTestObject(Condition cond, const BaseIndex &src, Label *label);
|
||||
void branchTestObject(Condition cond, const Address &src, Label *label);
|
||||
void testObjectSet(Condition cond, const ValueOperand &value, Register dest);
|
||||
|
||||
void branchTestString(Condition cond, const ValueOperand &value, Label *label);
|
||||
|
@ -977,6 +977,12 @@ class MacroAssemblerX64 : public MacroAssemblerX86Shared
|
||||
branchTestNull(cond, Operand(address), label);
|
||||
}
|
||||
|
||||
// This one, though, clobbers the ScratchReg.
|
||||
void branchTestObject(Condition cond, const Address &src, Label *label) {
|
||||
cond = testObject(cond, src);
|
||||
j(cond, label);
|
||||
}
|
||||
|
||||
// Perform a type-test on a full Value loaded into a register.
|
||||
// Clobbers the ScratchReg.
|
||||
void branchTestUndefined(Condition cond, const ValueOperand &src, Label *label) {
|
||||
|
@ -360,6 +360,15 @@ class MacroAssemblerX86 : public MacroAssemblerX86Shared
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
return testInt32(cond, Operand(address));
|
||||
}
|
||||
Condition testObject(Condition cond, const Operand &operand) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
cmp32(ToType(operand), ImmTag(JSVAL_TAG_OBJECT));
|
||||
return cond;
|
||||
}
|
||||
Condition testObject(Condition cond, const Address &address) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
return testObject(cond, Operand(address));
|
||||
}
|
||||
Condition testDouble(Condition cond, const Operand &operand) {
|
||||
MOZ_ASSERT(cond == Equal || cond == NotEqual);
|
||||
Condition actual = (cond == Equal) ? Below : AboveOrEqual;
|
||||
|
@ -3329,6 +3329,14 @@ EnsureNewArrayElements(ExclusiveContext *cx, ArrayObject *obj, uint32_t length)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
NewArrayIsCachable(ExclusiveContext *cxArg, NewObjectKind newKind)
|
||||
{
|
||||
return cxArg->isJSContext() &&
|
||||
newKind == GenericObject &&
|
||||
!cxArg->asJSContext()->compartment()->hasObjectMetadataCallback();
|
||||
}
|
||||
|
||||
template <uint32_t maxLength>
|
||||
static MOZ_ALWAYS_INLINE ArrayObject *
|
||||
NewArray(ExclusiveContext *cxArg, uint32_t length,
|
||||
@ -3338,15 +3346,13 @@ NewArray(ExclusiveContext *cxArg, uint32_t length,
|
||||
MOZ_ASSERT(CanBeFinalizedInBackground(allocKind, &ArrayObject::class_));
|
||||
allocKind = GetBackgroundAllocKind(allocKind);
|
||||
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
uint64_t gcNumber = 0;
|
||||
if (JSContext *cx = cxArg->maybeJSContext()) {
|
||||
bool isCachable = NewArrayIsCachable(cxArg, newKind);
|
||||
if (isCachable) {
|
||||
JSContext *cx = cxArg->asJSContext();
|
||||
JSRuntime *rt = cx->runtime();
|
||||
NewObjectCache &cache = rt->newObjectCache;
|
||||
if (newKind == GenericObject &&
|
||||
!cx->compartment()->hasObjectMetadataCallback() &&
|
||||
cache.lookupGlobal(&ArrayObject::class_, cx->global(), allocKind, &entry))
|
||||
{
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
if (cache.lookupGlobal(&ArrayObject::class_, cx->global(), allocKind, &entry)) {
|
||||
gc::InitialHeap heap = GetInitialHeap(newKind, &ArrayObject::class_);
|
||||
JSObject *obj = cache.newObjectFromHit(cx, entry, heap);
|
||||
if (obj) {
|
||||
@ -3361,8 +3367,6 @@ NewArray(ExclusiveContext *cxArg, uint32_t length,
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
} else {
|
||||
gcNumber = rt->gc.gcNumber();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3405,11 +3409,11 @@ NewArray(ExclusiveContext *cxArg, uint32_t length,
|
||||
if (newKind == SingletonObject && !JSObject::setSingleton(cxArg, arr))
|
||||
return nullptr;
|
||||
|
||||
if (entry != -1 &&
|
||||
cxArg->asJSContext()->runtime()->gc.gcNumber() == gcNumber)
|
||||
{
|
||||
cxArg->asJSContext()->runtime()->newObjectCache.fillGlobal(entry, &ArrayObject::class_,
|
||||
cxArg->global(), allocKind, arr);
|
||||
if (isCachable) {
|
||||
NewObjectCache &cache = cxArg->asJSContext()->runtime()->newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
cache.lookupGlobal(&ArrayObject::class_, cxArg->global(), allocKind, &entry);
|
||||
cache.fillGlobal(entry, &ArrayObject::class_, cxArg->global(), allocKind, arr);
|
||||
}
|
||||
|
||||
if (maxLength > 0 && !EnsureNewArrayElements(cxArg, arr, std::min(maxLength, length)))
|
||||
|
@ -1110,17 +1110,17 @@ struct CompartmentFilter {
|
||||
};
|
||||
|
||||
struct AllCompartments : public CompartmentFilter {
|
||||
virtual bool match(JSCompartment *c) const { return true; }
|
||||
virtual bool match(JSCompartment *c) const MOZ_OVERRIDE { return true; }
|
||||
};
|
||||
|
||||
struct ContentCompartmentsOnly : public CompartmentFilter {
|
||||
virtual bool match(JSCompartment *c) const {
|
||||
virtual bool match(JSCompartment *c) const MOZ_OVERRIDE {
|
||||
return !IsSystemCompartment(c);
|
||||
}
|
||||
};
|
||||
|
||||
struct ChromeCompartmentsOnly : public CompartmentFilter {
|
||||
virtual bool match(JSCompartment *c) const {
|
||||
virtual bool match(JSCompartment *c) const MOZ_OVERRIDE {
|
||||
return IsSystemCompartment(c);
|
||||
}
|
||||
};
|
||||
@ -1128,13 +1128,13 @@ struct ChromeCompartmentsOnly : public CompartmentFilter {
|
||||
struct SingleCompartment : public CompartmentFilter {
|
||||
JSCompartment *ours;
|
||||
explicit SingleCompartment(JSCompartment *c) : ours(c) {}
|
||||
virtual bool match(JSCompartment *c) const { return c == ours; }
|
||||
virtual bool match(JSCompartment *c) const MOZ_OVERRIDE { return c == ours; }
|
||||
};
|
||||
|
||||
struct CompartmentsWithPrincipals : public CompartmentFilter {
|
||||
JSPrincipals *principals;
|
||||
explicit CompartmentsWithPrincipals(JSPrincipals *p) : principals(p) {}
|
||||
virtual bool match(JSCompartment *c) const {
|
||||
virtual bool match(JSCompartment *c) const MOZ_OVERRIDE {
|
||||
return JS_GetCompartmentPrincipals(c) == principals;
|
||||
}
|
||||
};
|
||||
|
133
js/src/jsobj.cpp
133
js/src/jsobj.cpp
@ -1218,6 +1218,20 @@ NewObjectCache::fillProto(EntryIndex entry, const Class *clasp, js::TaggedProto
|
||||
return fill(entry, clasp, proto.raw(), kind, obj);
|
||||
}
|
||||
|
||||
static bool
|
||||
NewObjectWithTaggedProtoIsCachable(ExclusiveContext *cxArg, Handle<TaggedProto> proto,
|
||||
NewObjectKind newKind, const Class *clasp,
|
||||
HandleObject parentArg)
|
||||
{
|
||||
return cxArg->isJSContext() &&
|
||||
proto.isObject() &&
|
||||
newKind == GenericObject &&
|
||||
clasp->isNative() &&
|
||||
!cxArg->asJSContext()->compartment()->hasObjectMetadataCallback() &&
|
||||
(!parentArg || parentArg == proto.toObject()->getParent()) &&
|
||||
!proto.toObject()->is<GlobalObject>();
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js::NewObjectWithGivenTaggedProto(ExclusiveContext *cxArg, const Class *clasp,
|
||||
Handle<TaggedProto> proto, HandleObject parentArg,
|
||||
@ -1226,25 +1240,16 @@ js::NewObjectWithGivenTaggedProto(ExclusiveContext *cxArg, const Class *clasp,
|
||||
if (CanBeFinalizedInBackground(allocKind, clasp))
|
||||
allocKind = GetBackgroundAllocKind(allocKind);
|
||||
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
uint64_t gcNumber = 0;
|
||||
if (JSContext *cx = cxArg->maybeJSContext()) {
|
||||
bool isCachable = NewObjectWithTaggedProtoIsCachable(cxArg, proto, newKind, clasp, parentArg);
|
||||
if (isCachable) {
|
||||
JSContext *cx = cxArg->asJSContext();
|
||||
JSRuntime *rt = cx->runtime();
|
||||
NewObjectCache &cache = rt->newObjectCache;
|
||||
if (proto.isObject() &&
|
||||
newKind == GenericObject &&
|
||||
clasp->isNative() &&
|
||||
!cx->compartment()->hasObjectMetadataCallback() &&
|
||||
(!parentArg || parentArg == proto.toObject()->getParent()) &&
|
||||
!proto.toObject()->is<GlobalObject>())
|
||||
{
|
||||
if (cache.lookupProto(clasp, proto.toObject(), allocKind, &entry)) {
|
||||
JSObject *obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
|
||||
if (obj)
|
||||
return obj;
|
||||
} else {
|
||||
gcNumber = rt->gc.gcNumber();
|
||||
}
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
if (cache.lookupProto(clasp, proto.toObject(), allocKind, &entry)) {
|
||||
JSObject *obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
|
||||
if (obj)
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1264,12 +1269,11 @@ js::NewObjectWithGivenTaggedProto(ExclusiveContext *cxArg, const Class *clasp,
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
if (entry != -1 && !obj->as<NativeObject>().hasDynamicSlots() &&
|
||||
cxArg->asJSContext()->runtime()->gc.gcNumber() == gcNumber)
|
||||
{
|
||||
cxArg->asJSContext()->runtime()->newObjectCache.fillProto(entry, clasp,
|
||||
proto, allocKind,
|
||||
&obj->as<NativeObject>());
|
||||
if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
|
||||
NewObjectCache &cache = cxArg->asJSContext()->runtime()->newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
cache.lookupProto(clasp, proto.toObject(), allocKind, &entry);
|
||||
cache.fillProto(entry, clasp, proto, allocKind, &obj->as<NativeObject>());
|
||||
}
|
||||
|
||||
return obj;
|
||||
@ -1369,6 +1373,17 @@ FindProto(ExclusiveContext *cx, const js::Class *clasp, MutableHandleObject prot
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
NewObjectWithClassProtoIsCachable(ExclusiveContext *cxArg, HandleObject parent,
|
||||
JSProtoKey protoKey, NewObjectKind newKind, const Class *clasp)
|
||||
{
|
||||
return cxArg->isJSContext() &&
|
||||
parent->is<GlobalObject>() &&
|
||||
protoKey != JSProto_Null &&
|
||||
newKind == GenericObject &&
|
||||
clasp->isNative() &&
|
||||
!cxArg->asJSContext()->compartment()->hasObjectMetadataCallback();
|
||||
}
|
||||
|
||||
JSObject *
|
||||
js::NewObjectWithClassProtoCommon(ExclusiveContext *cxArg, const Class *clasp,
|
||||
@ -1396,24 +1411,16 @@ js::NewObjectWithClassProtoCommon(ExclusiveContext *cxArg, const Class *clasp,
|
||||
*/
|
||||
JSProtoKey protoKey = ClassProtoKeyOrAnonymousOrNull(clasp);
|
||||
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
uint64_t gcNumber = 0;
|
||||
if (JSContext *cx = cxArg->maybeJSContext()) {
|
||||
bool isCachable = NewObjectWithClassProtoIsCachable(cxArg, parent, protoKey, newKind, clasp);
|
||||
if (isCachable) {
|
||||
JSContext *cx = cxArg->asJSContext();
|
||||
JSRuntime *rt = cx->runtime();
|
||||
NewObjectCache &cache = rt->newObjectCache;
|
||||
if (parent->is<GlobalObject>() &&
|
||||
protoKey != JSProto_Null &&
|
||||
newKind == GenericObject &&
|
||||
clasp->isNative() &&
|
||||
!cx->compartment()->hasObjectMetadataCallback())
|
||||
{
|
||||
if (cache.lookupGlobal(clasp, &parent->as<GlobalObject>(), allocKind, &entry)) {
|
||||
JSObject *obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
|
||||
if (obj)
|
||||
return obj;
|
||||
} else {
|
||||
gcNumber = rt->gc.gcNumber();
|
||||
}
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
if (cache.lookupGlobal(clasp, &parent->as<GlobalObject>(), allocKind, &entry)) {
|
||||
JSObject *obj = cache.newObjectFromHit(cx, entry, GetInitialHeap(newKind, clasp));
|
||||
if (obj)
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1430,17 +1437,29 @@ js::NewObjectWithClassProtoCommon(ExclusiveContext *cxArg, const Class *clasp,
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
if (entry != -1 && !obj->as<NativeObject>().hasDynamicSlots() &&
|
||||
cxArg->asJSContext()->runtime()->gc.gcNumber() == gcNumber)
|
||||
{
|
||||
cxArg->asJSContext()->runtime()->newObjectCache.fillGlobal(entry, clasp,
|
||||
&parent->as<GlobalObject>(),
|
||||
allocKind, &obj->as<NativeObject>());
|
||||
if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
|
||||
NewObjectCache &cache = cxArg->asJSContext()->runtime()->newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
cache.lookupGlobal(clasp, &parent->as<GlobalObject>(), allocKind, &entry);
|
||||
cache.fillGlobal(entry, clasp, &parent->as<GlobalObject>(), allocKind,
|
||||
&obj->as<NativeObject>());
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
static bool
|
||||
NewObjectWithGroupIsCachable(JSContext *cx, HandleObjectGroup group, HandleObject parent,
|
||||
NewObjectKind newKind)
|
||||
{
|
||||
return group->proto().isObject() &&
|
||||
parent == group->proto().toObject()->getParent() &&
|
||||
newKind == GenericObject &&
|
||||
group->clasp()->isNative() &&
|
||||
(!group->newScript() || group->newScript()->analyzed()) &&
|
||||
!cx->compartment()->hasObjectMetadataCallback();
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a plain object with the specified group. This bypasses getNewGroup to
|
||||
* avoid losing creation site information for objects made by scripted 'new'.
|
||||
@ -1455,24 +1474,15 @@ js::NewObjectWithGroupCommon(JSContext *cx, HandleObjectGroup group, HandleObjec
|
||||
if (CanBeFinalizedInBackground(allocKind, group->clasp()))
|
||||
allocKind = GetBackgroundAllocKind(allocKind);
|
||||
|
||||
NewObjectCache &cache = cx->runtime()->newObjectCache;
|
||||
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
uint64_t gcNumber = 0;
|
||||
if (group->proto().isObject() &&
|
||||
parent == group->proto().toObject()->getParent() &&
|
||||
newKind == GenericObject &&
|
||||
group->clasp()->isNative() &&
|
||||
(!group->newScript() || group->newScript()->analyzed()) &&
|
||||
!cx->compartment()->hasObjectMetadataCallback())
|
||||
{
|
||||
bool isCachable = NewObjectWithGroupIsCachable(cx, group, parent, newKind);
|
||||
if (isCachable) {
|
||||
NewObjectCache &cache = cx->runtime()->newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
if (cache.lookupGroup(group, allocKind, &entry)) {
|
||||
JSObject *obj = cache.newObjectFromHit(cx, entry,
|
||||
GetInitialHeap(newKind, group->clasp()));
|
||||
if (obj)
|
||||
return obj;
|
||||
} else {
|
||||
gcNumber = cx->runtime()->gc.gcNumber();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1480,9 +1490,10 @@ js::NewObjectWithGroupCommon(JSContext *cx, HandleObjectGroup group, HandleObjec
|
||||
if (!obj)
|
||||
return nullptr;
|
||||
|
||||
if (entry != -1 && !obj->as<NativeObject>().hasDynamicSlots() &&
|
||||
cx->runtime()->gc.gcNumber() == gcNumber)
|
||||
{
|
||||
if (isCachable && !obj->as<NativeObject>().hasDynamicSlots()) {
|
||||
NewObjectCache &cache = cx->runtime()->newObjectCache;
|
||||
NewObjectCache::EntryIndex entry = -1;
|
||||
cache.lookupGroup(group, allocKind, &entry);
|
||||
cache.fillGroup(entry, group, allocKind, &obj->as<NativeObject>());
|
||||
}
|
||||
|
||||
|
@ -1796,6 +1796,7 @@ class ASTSerializer
|
||||
|
||||
bool identifier(HandleAtom atom, TokenPos *pos, MutableHandleValue dst);
|
||||
bool identifier(ParseNode *pn, MutableHandleValue dst);
|
||||
bool objectPropertyName(ParseNode *pn, MutableHandleValue dst);
|
||||
bool literal(ParseNode *pn, MutableHandleValue dst);
|
||||
|
||||
bool pattern(ParseNode *pn, MutableHandleValue dst);
|
||||
@ -3058,7 +3059,7 @@ ASTSerializer::propertyName(ParseNode *pn, MutableHandleValue dst)
|
||||
{
|
||||
if (pn->isKind(PNK_COMPUTED_NAME))
|
||||
return expression(pn, dst);
|
||||
if (pn->isKind(PNK_NAME))
|
||||
if (pn->isKind(PNK_OBJECT_PROPERTY_NAME))
|
||||
return identifier(pn, dst);
|
||||
|
||||
LOCAL_ASSERT(pn->isKind(PNK_STRING) || pn->isKind(PNK_NUMBER));
|
||||
@ -3250,6 +3251,17 @@ ASTSerializer::identifier(ParseNode *pn, MutableHandleValue dst)
|
||||
return identifier(pnAtom, &pn->pn_pos, dst);
|
||||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::objectPropertyName(ParseNode *pn, MutableHandleValue dst)
|
||||
{
|
||||
LOCAL_ASSERT(pn->isKind(PNK_OBJECT_PROPERTY_NAME));
|
||||
LOCAL_ASSERT(pn->isArity(PN_NULLARY));
|
||||
LOCAL_ASSERT(pn->pn_atom);
|
||||
|
||||
RootedAtom pnAtom(cx, pn->pn_atom);
|
||||
return identifier(pnAtom, &pn->pn_pos, dst);
|
||||
}
|
||||
|
||||
bool
|
||||
ASTSerializer::function(ParseNode *pn, ASTType type, MutableHandleValue dst)
|
||||
{
|
||||
|
@ -200,16 +200,6 @@ ObjectValueMap::findZoneEdges()
|
||||
return true;
|
||||
}
|
||||
|
||||
static JSObject *
|
||||
GetKeyArg(JSContext *cx, CallArgs &args)
|
||||
{
|
||||
if (args[0].isPrimitive()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
|
||||
return nullptr;
|
||||
}
|
||||
return &args[0].toObject();
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_INLINE bool
|
||||
IsWeakMap(HandleValue v)
|
||||
{
|
||||
@ -221,16 +211,13 @@ WeakMap_has_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
MOZ_ASSERT(IsWeakMap(args.thisv()));
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
|
||||
"WeakMap.has", "0", "s");
|
||||
return false;
|
||||
if (!args.get(0).isObject()) {
|
||||
args.rval().setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
JSObject *key = GetKeyArg(cx, args);
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
if (ObjectValueMap *map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
|
||||
JSObject *key = &args[0].toObject();
|
||||
if (map->has(key)) {
|
||||
args.rval().setBoolean(true);
|
||||
return true;
|
||||
@ -274,23 +261,20 @@ WeakMap_get_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
MOZ_ASSERT(IsWeakMap(args.thisv()));
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
|
||||
"WeakMap.get", "0", "s");
|
||||
return false;
|
||||
if (!args.get(0).isObject()) {
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
JSObject *key = GetKeyArg(cx, args);
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
if (ObjectValueMap *map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
|
||||
JSObject *key = &args[0].toObject();
|
||||
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
|
||||
args.rval().set(ptr->value());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
args.rval().set((args.length() > 1) ? args[1] : UndefinedValue());
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -306,16 +290,13 @@ WeakMap_delete_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
MOZ_ASSERT(IsWeakMap(args.thisv()));
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
|
||||
"WeakMap.delete", "0", "s");
|
||||
return false;
|
||||
if (!args.get(0).isObject()) {
|
||||
args.rval().setBoolean(false);
|
||||
return true;
|
||||
}
|
||||
JSObject *key = GetKeyArg(cx, args);
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
if (ObjectValueMap *map = args.thisv().toObject().as<WeakMapObject>().getMap()) {
|
||||
JSObject *key = &args[0].toObject();
|
||||
if (ObjectValueMap::Ptr ptr = map->lookup(key)) {
|
||||
map->remove(ptr);
|
||||
args.rval().setBoolean(true);
|
||||
@ -402,20 +383,16 @@ WeakMap_set_impl(JSContext *cx, CallArgs args)
|
||||
{
|
||||
MOZ_ASSERT(IsWeakMap(args.thisv()));
|
||||
|
||||
if (args.length() < 1) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
|
||||
"WeakMap.set", "0", "s");
|
||||
if (!args.get(0).isObject()) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NOT_NONNULL_OBJECT);
|
||||
return false;
|
||||
}
|
||||
RootedObject key(cx, GetKeyArg(cx, args));
|
||||
if (!key)
|
||||
return false;
|
||||
|
||||
RootedValue value(cx, (args.length() > 1) ? args[1] : UndefinedValue());
|
||||
RootedObject key(cx, &args[0].toObject());
|
||||
Rooted<JSObject*> thisObj(cx, &args.thisv().toObject());
|
||||
Rooted<WeakMapObject*> map(cx, &thisObj->as<WeakMapObject>());
|
||||
|
||||
if (!SetWeakMapEntryInternal(cx, map, key, value))
|
||||
if (!SetWeakMapEntryInternal(cx, map, key, args.get(1)))
|
||||
return false;
|
||||
args.rval().set(args.thisv());
|
||||
return true;
|
||||
|
@ -83,22 +83,39 @@ function test()
|
||||
var map = new WeakMap();
|
||||
|
||||
check(function() !map.has(key));
|
||||
map.set(key, 42);
|
||||
check(function() map.delete(key) == false);
|
||||
check(function() map.set(key, 42) === map);
|
||||
check(function() map.get(key) == 42);
|
||||
check(function() typeof map.get({}) == "undefined");
|
||||
check(function() map.get({}, "foo") == "foo");
|
||||
check(function() map.get({}, "foo") == undefined);
|
||||
|
||||
gc(); gc(); gc();
|
||||
|
||||
check(function() map.get(key) == 42);
|
||||
map.delete(key);
|
||||
check(function() map.delete(key) == true);
|
||||
check(function() map.delete(key) == false);
|
||||
check(function() map.delete({}) == false);
|
||||
|
||||
check(function() typeof map.get(key) == "undefined");
|
||||
check(function() !map.has(key));
|
||||
check(function() map.delete(key) == false);
|
||||
|
||||
var value = { };
|
||||
map.set(new Object(), value);
|
||||
check(function() map.set(new Object(), value) === map);
|
||||
gc(); gc(); gc();
|
||||
|
||||
check(function() map.has("non-object key") == false);
|
||||
check(function() map.has() == false);
|
||||
check(function() map.get("non-object key") == undefined);
|
||||
check(function() map.get() == undefined);
|
||||
check(function() map.delete("non-object key") == false);
|
||||
check(function() map.delete() == false);
|
||||
|
||||
check(function() map.set(key) === map);
|
||||
check(function() map.get(key) == undefined);
|
||||
|
||||
checkThrows(function() map.set("non-object key", value));
|
||||
|
||||
print ("done");
|
||||
|
||||
reportCompare(0, TestFailCount, "weak map tests");
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user