Merge m-c to b2g-inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-04-28 15:40:15 -04:00
Родитель b20c4a477e cb8cb027ac
Коммит 659b2a4f94
115 изменённых файлов: 1936 добавлений и 785 удалений

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

@ -638,6 +638,37 @@ let LoopRoomsInternal = {
}, callback);
},
/**
* Forwards connection status to the server.
*
* @param {String} roomToken The room token.
* @param {String} sessionToken The session token for the
* session that has been
* joined.
* @param {sharedActions.SdkStatus} status The connection status.
* @param {Function} callback Optional. Function that will be invoked once
* the operation finished. The first argument
* passed will be an `Error` object or `null`.
*/
sendConnectionStatus: function(roomToken, sessionToken, status, callback) {
if (!callback) {
callback = function(error) {
if (error) {
MozLoopService.log.error(error);
}
};
}
this._postToRoom(roomToken, {
action: "status",
event: status.event,
state: status.state,
connections: status.connections,
sendStreams: status.sendStreams,
recvStreams: status.recvStreams,
sessionToken: sessionToken
}, callback);
},
/**
* Renames a room.
*
@ -780,6 +811,10 @@ this.LoopRooms = {
return LoopRoomsInternal.leave(roomToken, sessionToken, callback);
},
sendConnectionStatus: function(roomToken, sessionToken, status, callback) {
return LoopRoomsInternal.sendConnectionStatus(roomToken, sessionToken, status, callback);
},
rename: function(roomToken, newRoomName, callback) {
return LoopRoomsInternal.rename(roomToken, newRoomName, callback);
},

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

@ -432,6 +432,8 @@ loop.panel = (function(_, mozL10n) {
});
var RoomEntryContextItem = React.createClass({displayName: "RoomEntryContextItem",
mixins: [loop.shared.mixins.WindowCloseMixin],
propTypes: {
mozLoop: React.PropTypes.object.isRequired,
roomUrls: React.PropTypes.object
@ -441,6 +443,7 @@ loop.panel = (function(_, mozL10n) {
event.stopPropagation();
event.preventDefault();
this.props.mozLoop.openURL(event.currentTarget.href);
this.closeWindow();
},
render: function() {
@ -700,9 +703,17 @@ loop.panel = (function(_, mozL10n) {
},
render: function() {
var hostname;
try {
hostname = new URL(this.state.url).hostname;
} catch (ex) {
// Empty catch - if there's an error, then we won't show the context.
}
var contextClasses = React.addons.classSet({
context: true,
hide: !this.state.url ||
hide: !hostname ||
!this.props.mozLoop.getLoopPref("contextInConverations.enabled")
});
@ -716,7 +727,7 @@ loop.panel = (function(_, mozL10n) {
),
React.createElement("img", {className: "context-preview", src: this.state.previewImage}),
React.createElement("span", {className: "context-description"}, this.state.description),
React.createElement("span", {className: "context-url"}, this.state.url)
React.createElement("span", {className: "context-url"}, hostname)
),
React.createElement("button", {className: "btn btn-info new-room-button",
onClick: this.handleCreateButtonClick,

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

@ -432,6 +432,8 @@ loop.panel = (function(_, mozL10n) {
});
var RoomEntryContextItem = React.createClass({
mixins: [loop.shared.mixins.WindowCloseMixin],
propTypes: {
mozLoop: React.PropTypes.object.isRequired,
roomUrls: React.PropTypes.object
@ -441,6 +443,7 @@ loop.panel = (function(_, mozL10n) {
event.stopPropagation();
event.preventDefault();
this.props.mozLoop.openURL(event.currentTarget.href);
this.closeWindow();
},
render: function() {
@ -700,9 +703,17 @@ loop.panel = (function(_, mozL10n) {
},
render: function() {
var hostname;
try {
hostname = new URL(this.state.url).hostname;
} catch (ex) {
// Empty catch - if there's an error, then we won't show the context.
}
var contextClasses = React.addons.classSet({
context: true,
hide: !this.state.url ||
hide: !hostname ||
!this.props.mozLoop.getLoopPref("contextInConverations.enabled")
});
@ -716,7 +727,7 @@ loop.panel = (function(_, mozL10n) {
</label>
<img className="context-preview" src={this.state.previewImage}/>
<span className="context-description">{this.state.description}</span>
<span className="context-url">{this.state.url}</span>
<span className="context-url">{hostname}</span>
</div>
<button className="btn btn-info new-room-button"
onClick={this.handleCreateButtonClick}

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

@ -499,6 +499,18 @@ loop.shared.actions = (function() {
*/
SendFeedbackError: Action.define("sendFeedbackError", {
error: Error
}),
/**
* Used to inform of the current session, publisher and connection
* status.
*/
ConnectionStatus: Action.define("connectionStatus", {
event: String,
state: String,
connections: Number,
sendStreams: Number,
recvStreams: Number
})
};
})();

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

@ -156,7 +156,8 @@ loop.store.ActiveRoomStore = (function() {
"videoDimensionsChanged",
"startScreenShare",
"endScreenShare",
"updateSocialShareInfo"
"updateSocialShareInfo",
"connectionStatus"
]);
},
@ -639,6 +640,17 @@ loop.store.ActiveRoomStore = (function() {
this.setStoreState({roomState: ROOM_STATES.SESSION_CONNECTED});
},
/**
* Handles an SDK status update, forwarding it to the server.
*
* @param {sharedActions.ConnectionStatus} actionData
*/
connectionStatus: function(actionData) {
this._mozLoop.rooms.sendConnectionStatus(this.getStoreState("roomToken"),
this.getStoreState("sessionToken"),
actionData);
},
/**
* Handles the window being unloaded. Ensures the room is left.
*/

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

@ -38,6 +38,14 @@ loop.OTSdkDriver = (function() {
this.connections = {};
// Metrics object to keep track of the number of connections we have
// and the amount of streams.
this._metrics = {
connections: 0,
sendStreams: 0,
recvStreams: 0
};
this.dispatcher.register(this, [
"setupStreamElements",
"setMute"
@ -104,6 +112,7 @@ loop.OTSdkDriver = (function() {
this.publisher = this.sdk.initPublisher(this.getLocalElement(),
this._getCopyPublisherConfig());
this.publisher.on("streamCreated", this._onLocalStreamCreated.bind(this));
this.publisher.on("streamDestroyed", this._onLocalStreamDestroyed.bind(this));
this.publisher.on("accessAllowed", this._onPublishComplete.bind(this));
this.publisher.on("accessDenied", this._onPublishDenied.bind(this));
this.publisher.on("accessDialogOpened",
@ -164,6 +173,7 @@ loop.OTSdkDriver = (function() {
config);
this.screenshare.on("accessAllowed", this._onScreenShareGranted.bind(this));
this.screenshare.on("accessDenied", this._onScreenShareDenied.bind(this));
this.screenshare.on("streamCreated", this._onScreenShareStreamCreated.bind(this));
this._noteSharingState(options.videoSource, true);
},
@ -193,8 +203,10 @@ loop.OTSdkDriver = (function() {
return false;
}
this._notifyMetricsEvent("Publisher.streamDestroyed");
this.session.unpublish(this.screenshare);
this.screenshare.off("accessAllowed accessDenied");
this.screenshare.off("accessAllowed accessDenied streamCreated");
this.screenshare.destroy();
delete this.screenshare;
this._noteSharingState(this._windowId ? "browser" : "window", false);
@ -223,18 +235,18 @@ loop.OTSdkDriver = (function() {
this._sendTwoWayMediaTelemetry = !!sessionData.sendTwoWayMediaTelemetry;
this._setTwoWayMediaStartTime(this.CONNECTION_START_TIME_UNINITIALIZED);
this.session.on("connectionCreated", this._onConnectionCreated.bind(this));
this.session.on("streamCreated", this._onRemoteStreamCreated.bind(this));
this.session.on("streamDestroyed", this._onRemoteStreamDestroyed.bind(this));
this.session.on("connectionDestroyed",
this._onConnectionDestroyed.bind(this));
this.session.on("sessionDisconnected",
this._onSessionDisconnected.bind(this));
this.session.on("connectionCreated", this._onConnectionCreated.bind(this));
this.session.on("connectionDestroyed",
this._onConnectionDestroyed.bind(this));
this.session.on("streamCreated", this._onRemoteStreamCreated.bind(this));
this.session.on("streamDestroyed", this._onRemoteStreamDestroyed.bind(this));
this.session.on("streamPropertyChanged", this._onStreamPropertyChanged.bind(this));
// This starts the actual session connection.
this.session.connect(sessionData.apiKey, sessionData.sessionToken,
this._onConnectionComplete.bind(this));
this._onSessionConnectionCompleted.bind(this));
},
/**
@ -244,10 +256,11 @@ loop.OTSdkDriver = (function() {
this.endScreenShare();
if (this.session) {
this.session.off("streamCreated streamDestroyed connectionDestroyed " +
"sessionDisconnected streamPropertyChanged");
this.session.off("sessionDisconnected streamCreated streamDestroyed connectionCreated connectionDestroyed streamPropertyChanged");
this.session.disconnect();
delete this.session;
this._notifyMetricsEvent("Session.connectionDestroyed", "local");
}
if (this.publisher) {
this.publisher.off("accessAllowed accessDenied accessDialogOpened streamCreated");
@ -302,7 +315,7 @@ loop.OTSdkDriver = (function() {
*
* @param {Error} error An OT error object, null if there was no error.
*/
_onConnectionComplete: function(error) {
_onSessionConnectionCompleted: function(error) {
if (error) {
console.error("Failed to complete connection", error);
this.dispatcher.dispatch(new sharedActions.ConnectionFailure({
@ -327,7 +340,11 @@ loop.OTSdkDriver = (function() {
if (connection && (connection.id in this.connections)) {
delete this.connections[connection.id];
}
this._notifyMetricsEvent("Session.connectionDestroyed", "peer");
this._noteConnectionLengthIfNeeded(this._getTwoWayMediaStartTime(), performance.now());
this.dispatcher.dispatch(new sharedActions.RemotePeerDisconnected({
peerHungup: event.reason === "clientDisconnected"
}));
@ -370,12 +387,95 @@ loop.OTSdkDriver = (function() {
_onConnectionCreated: function(event) {
var connection = event.connection;
if (this.session.connection.id === connection.id) {
// This is the connection event for our connection.
this._notifyMetricsEvent("Session.connectionCreated", "local");
return;
}
this.connections[connection.id] = connection;
this._notifyMetricsEvent("Session.connectionCreated", "peer");
this.dispatcher.dispatch(new sharedActions.RemotePeerConnected());
},
/**
* Works out the current connection state based on the streams being
* sent or received.
*/
_getConnectionState: function() {
if (this._metrics.sendStreams) {
return this._metrics.recvStreams ? "sendrecv" : "sending";
}
if (this._metrics.recvStreams) {
return "receiving";
}
return "starting";
},
/**
* Notifies of a metrics related event for tracking call setup purposes.
* See https://wiki.mozilla.org/Loop/Architecture/Rooms#Updating_Session_State
*
* @param {String} eventName The name of the event for the update.
* @param {String} clientType Used for connection created/destoryed. Indicates
* if it is for the "peer" or the "local" client.
*/
_notifyMetricsEvent: function(eventName, clientType) {
if (!eventName) {
return;
}
var state;
// We intentionally don't bounds check these, in case there's an error
// somewhere, if there is, we'll see it in the server metrics and are more
// likely to investigate.
switch (eventName) {
case "Session.connectionCreated":
this._metrics.connections++;
if (clientType === "local") {
state = "waiting";
}
break;
case "Session.connectionDestroyed":
this._metrics.connections--;
if (clientType === "local") {
// Don't log this, as the server doesn't accept it after
// the room has been left.
return;
} else if (!this._metrics.connections) {
state = "waiting";
}
break;
case "Publisher.streamCreated":
this._metrics.sendStreams++;
break;
case "Publisher.streamDestroyed":
this._metrics.sendStreams--;
break;
case "Session.streamCreated":
this._metrics.recvStreams++;
break;
case "Session.streamDestroyed":
this._metrics.recvStreams--;
break;
default:
console.error("Unexpected event name", eventName);
return;
}
if (!state) {
state = this._getConnectionState();
}
this.dispatcher.dispatch(new sharedActions.ConnectionStatus({
event: eventName,
state: state,
connections: this._metrics.connections,
sendStreams: this._metrics.sendStreams,
recvStreams: this._metrics.recvStreams
}));
},
/**
* Handles when a remote screen share is created, subscribing to
* the stream, and notifying the stores that a share is being
@ -407,6 +507,8 @@ loop.OTSdkDriver = (function() {
* https://tokbox.com/opentok/libraries/client/js/reference/StreamEvent.html
*/
_onRemoteStreamCreated: function(event) {
this._notifyMetricsEvent("Session.streamCreated");
if (event.stream[STREAM_PROPERTIES.HAS_VIDEO]) {
this.dispatcher.dispatch(new sharedActions.VideoDimensionsChanged({
isLocal: false,
@ -439,6 +541,8 @@ loop.OTSdkDriver = (function() {
* https://tokbox.com/opentok/libraries/client/js/reference/StreamEvent.html
*/
_onLocalStreamCreated: function(event) {
this._notifyMetricsEvent("Publisher.streamCreated");
if (event.stream[STREAM_PROPERTIES.HAS_VIDEO]) {
this.dispatcher.dispatch(new sharedActions.VideoDimensionsChanged({
isLocal: true,
@ -506,6 +610,8 @@ loop.OTSdkDriver = (function() {
* https://tokbox.com/opentok/libraries/client/js/reference/StreamEvent.html
*/
_onRemoteStreamDestroyed: function(event) {
this._notifyMetricsEvent("Session.streamDestroyed");
if (event.stream.videoType !== "screen") {
return;
}
@ -517,6 +623,13 @@ loop.OTSdkDriver = (function() {
}));
},
/**
* Handles the event when the remote stream is destroyed.
*/
_onLocalStreamDestroyed: function() {
this._notifyMetricsEvent("Publisher.streamDestroyed");
},
/**
* Called from the sdk when the media access dialog is opened.
* Prevents the default action, to prevent the SDK's "allow access"
@ -631,6 +744,13 @@ loop.OTSdkDriver = (function() {
}));
},
/**
* Called when a screenshare stream is published.
*/
_onScreenShareStreamCreated: function() {
this._notifyMetricsEvent("Publisher.streamCreated");
},
/*
* XXX all of the bi-directional media connection telemetry stuff in this
* file, (much, but not all, of it is below) should be hoisted into its

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

@ -222,6 +222,29 @@ loop.StandaloneMozLoop = (function(mozL10n) {
}, null, false, callback);
},
/**
* Forwards connection status to the server.
*
* @param {String} roomToken The room token.
* @param {String} sessionToken The session token for the session that has been
* joined.
* @param {sharedActions.SdkStatus} status The connection status.
*/
sendConnectionStatus: function(roomToken, sessionToken, status) {
this._postToRoom(roomToken, sessionToken, {
action: "status",
event: status.event,
state: status.state,
connections: status.connections,
sendStreams: status.sendStreams,
recvStreams: status.recvStreams
}, null, true, function(error) {
if (error) {
console.error(error);
}
});
},
// Dummy functions to reflect those in the desktop mozLoop.rooms that we
// don't currently use.
on: function() {},

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

@ -280,15 +280,28 @@ loop.standaloneRoomViews = (function(mozL10n) {
roomInfoFailure: React.PropTypes.string
},
getInitialState: function() {
return {
failureLogged: false
}
},
_logFailure: function(message) {
if (!this.state.failureLogged) {
console.error(mozL10n.get(message));
this.state.failureLogged = true;
}
},
render: function() {
// For failures, we currently just log the messages - UX doesn't want them
// displayed on primary UI at the moment.
if (this.props.roomInfoFailure === ROOM_INFO_FAILURES.WEB_CRYPTO_UNSUPPORTED) {
return (React.createElement("h2", {className: "room-info-failure"},
mozL10n.get("room_information_failure_unsupported_browser")
));
this._logFailure("room_information_failure_unsupported_browser");
return null;
} else if (this.props.roomInfoFailure) {
return (React.createElement("h2", {className: "room-info-failure"},
mozL10n.get("room_information_failure_not_available")
));
this._logFailure("room_information_failure_not_available");
return null;
}
// We only support one item in the context Urls array for now.

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

@ -280,15 +280,28 @@ loop.standaloneRoomViews = (function(mozL10n) {
roomInfoFailure: React.PropTypes.string
},
getInitialState: function() {
return {
failureLogged: false
}
},
_logFailure: function(message) {
if (!this.state.failureLogged) {
console.error(mozL10n.get(message));
this.state.failureLogged = true;
}
},
render: function() {
// For failures, we currently just log the messages - UX doesn't want them
// displayed on primary UI at the moment.
if (this.props.roomInfoFailure === ROOM_INFO_FAILURES.WEB_CRYPTO_UNSUPPORTED) {
return (<h2 className="room-info-failure">
{mozL10n.get("room_information_failure_unsupported_browser")}
</h2>);
this._logFailure("room_information_failure_unsupported_browser");
return null;
} else if (this.props.roomInfoFailure) {
return (<h2 className="room-info-failure">
{mozL10n.get("room_information_failure_not_available")}
</h2>);
this._logFailure("room_information_failure_not_available");
return null;
}
// We only support one item in the context Urls array for now.

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

@ -614,6 +614,20 @@ describe("loop.panel", function() {
sinon.assert.calledOnce(fakeMozLoop.openURL);
sinon.assert.calledWithExactly(fakeMozLoop.openURL, "http://invalid/");
});
it("should call close the panel after opening a url", function() {
roomData.decryptedContext.urls = [{
description: "invalid entry",
location: "http://invalid/",
thumbnail: "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="
}];
roomEntry = mountEntryForContext();
TestUtils.Simulate.click(roomEntry.getDOMNode().querySelector("a"));
sinon.assert.calledOnce(fakeWindow.close);
});
});
describe("Room Entry click", function() {
@ -833,6 +847,24 @@ describe("loop.panel", function() {
var contextInfo = view.getDOMNode().querySelector(".context");
expect(contextInfo.classList.contains("hide")).to.equal(true);
});
it("should show only the hostname of the url", function() {
fakeMozLoop.getSelectedTabMetadata = function (callback) {
callback({
url: "https://www.example.com:1234",
description: "fake description",
previews: [""]
});
};
var view = createTestComponent();
// Simulate being visible
view.onDocumentVisible();
var contextHostname = view.getDOMNode().querySelector(".context-url");
expect(contextHostname.textContent).eql("www.example.com");
});
});
describe('loop.panel.ToSView', function() {

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

@ -32,7 +32,8 @@ describe("loop.store.ActiveRoomStore", function () {
refreshMembership: sinon.stub(),
leave: sinon.stub(),
on: sinon.stub(),
off: sinon.stub()
off: sinon.stub(),
sendConnectionStatus: sinon.stub()
},
setScreenShareState: sinon.stub(),
getActiveTabWindowId: sandbox.stub().callsArgWith(0, null, 42),
@ -1121,6 +1122,29 @@ describe("loop.store.ActiveRoomStore", function () {
});
});
describe("#connectionStatus", function() {
it("should call rooms.sendConnectionStatus on mozLoop", function() {
store.setStoreState({
roomToken: "fakeToken",
sessionToken: "9876543210"
});
var data = new sharedActions.ConnectionStatus({
event: "Publisher.streamCreated",
state: "sendrecv",
connections: 2,
recvStreams: 1,
sendStreams: 2
});
store.connectionStatus(data);
sinon.assert.calledOnce(fakeMozLoop.rooms.sendConnectionStatus);
sinon.assert.calledWith(fakeMozLoop.rooms.sendConnectionStatus,
"fakeToken", "9876543210", data);
});
});
describe("#windowUnload", function() {
beforeEach(function() {
store.setStoreState({

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

@ -35,6 +35,9 @@ describe("loop.OTSdkDriver", function () {
};
dispatcher = new loop.Dispatcher();
sandbox.stub(dispatcher, "dispatch");
session = _.extend({
connect: sinon.stub(),
disconnect: sinon.stub(),
@ -108,7 +111,7 @@ describe("loop.OTSdkDriver", function () {
describe("#setupStreamElements", function() {
it("should call initPublisher", function() {
dispatcher.dispatch(new sharedActions.SetupStreamElements({
driver.setupStreamElements(new sharedActions.SetupStreamElements({
getLocalElementFunc: function() {return fakeLocalElement;},
getRemoteElementFunc: function() {return fakeRemoteElement;},
publisherConfig: publisherConfig
@ -154,7 +157,7 @@ describe("loop.OTSdkDriver", function () {
beforeEach(function() {
sdk.initPublisher.returns(publisher);
dispatcher.dispatch(new sharedActions.SetupStreamElements({
driver.setupStreamElements(new sharedActions.SetupStreamElements({
getLocalElementFunc: function() {return fakeLocalElement;},
getRemoteElementFunc: function() {return fakeRemoteElement;},
publisherConfig: publisherConfig
@ -162,7 +165,7 @@ describe("loop.OTSdkDriver", function () {
});
it("should publishAudio with the correct enabled value", function() {
dispatcher.dispatch(new sharedActions.SetMute({
driver.setMute(new sharedActions.SetMute({
type: "audio",
enabled: false
}));
@ -172,7 +175,7 @@ describe("loop.OTSdkDriver", function () {
});
it("should publishVideo with the correct enabled value", function() {
dispatcher.dispatch(new sharedActions.SetMute({
driver.setMute(new sharedActions.SetMute({
type: "video",
enabled: true
}));
@ -186,7 +189,6 @@ describe("loop.OTSdkDriver", function () {
var fakeElement;
beforeEach(function() {
sandbox.stub(dispatcher, "dispatch");
sandbox.stub(driver, "_noteSharingState");
fakeElement = {
@ -240,7 +242,6 @@ describe("loop.OTSdkDriver", function () {
driver.getScreenShareElementFunc = function() {
return fakeScreenElement;
};
sandbox.stub(dispatcher, "dispatch");
driver.startScreenShare(options);
});
@ -263,7 +264,6 @@ describe("loop.OTSdkDriver", function () {
beforeEach(function() {
driver.getScreenShareElementFunc = function() {};
sandbox.stub(dispatcher, "dispatch");
sandbox.stub(driver, "_noteSharingState");
});
@ -327,6 +327,32 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledWithExactly(driver._noteSharingState, "browser", false);
});
it("should dispatch a ConnectionStatus action", function() {
driver.startScreenShare({
videoSource: "browser",
constraints: {
browserWindow: 42
}
});
driver.session = session;
driver._metrics.connections = 2;
driver._metrics.recvStreams = 1;
driver._metrics.sendStreams = 2;
driver.endScreenShare(new sharedActions.EndScreenShare());
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ConnectionStatus({
event: "Publisher.streamDestroyed",
state: "sendrecv",
connections: 2,
sendStreams: 1,
recvStreams: 1
}));
});
});
describe("#connectSession", function() {
@ -365,7 +391,6 @@ describe("loop.OTSdkDriver", function () {
it("should dispatch connectionFailure if connecting failed", function() {
session.connect.callsArgWith(2, new Error("Failure"));
sandbox.stub(dispatcher, "dispatch");
driver.connectSession(sessionData);
@ -578,14 +603,12 @@ describe("loop.OTSdkDriver", function () {
beforeEach(function() {
driver.connectSession(sessionData);
dispatcher.dispatch(new sharedActions.SetupStreamElements({
driver.setupStreamElements(new sharedActions.SetupStreamElements({
getLocalElementFunc: function() {return fakeLocalElement;},
getScreenShareElementFunc: function() {return fakeScreenElement;},
getRemoteElementFunc: function() {return fakeRemoteElement;},
publisherConfig: publisherConfig
}));
sandbox.stub(dispatcher, "dispatch");
});
describe("connectionDestroyed", function() {
@ -595,7 +618,7 @@ describe("loop.OTSdkDriver", function () {
reason: "clientDisconnected"
});
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("name", "remotePeerDisconnected"));
sinon.assert.calledWithMatch(dispatcher.dispatch,
@ -608,13 +631,30 @@ describe("loop.OTSdkDriver", function () {
reason: "networkDisconnected"
});
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("name", "remotePeerDisconnected"));
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("peerHungup", false));
});
it("should dispatch a ConnectionStatus action", function() {
driver._metrics.connections = 1;
session.trigger("connectionDestroyed", {
reason: "clientDisconnected"
});
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ConnectionStatus({
event: "Session.connectionDestroyed",
state: "waiting",
connections: 0,
sendStreams: 0,
recvStreams: 0
}));
});
it("should call _noteConnectionLengthIfNeeded with connection duration", function() {
driver.session = session;
@ -681,16 +721,20 @@ describe("loop.OTSdkDriver", function () {
});
describe("streamCreated (publisher/local)", function() {
it("should dispatch a VideoDimensionsChanged action", function() {
var fakeStream = {
var fakeStream;
beforeEach(function() {
fakeStream = {
hasVideo: true,
videoType: "camera",
videoDimensions: {width: 1, height: 2}
};
});
it("should dispatch a VideoDimensionsChanged action", function() {
publisher.trigger("streamCreated", {stream: fakeStream});
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.VideoDimensionsChanged({
isLocal: true,
@ -698,6 +742,23 @@ describe("loop.OTSdkDriver", function () {
dimensions: {width: 1, height: 2}
}));
});
it("should dispatch a ConnectionStatus action", function() {
driver._metrics.recvStreams = 1;
driver._metrics.connections = 2;
publisher.trigger("streamCreated", {stream: fakeStream});
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ConnectionStatus({
event: "Publisher.streamCreated",
state: "sendrecv",
connections: 2,
recvStreams: 1,
sendStreams: 1
}));
});
});
describe("streamCreated (session/remote)", function() {
@ -714,7 +775,7 @@ describe("loop.OTSdkDriver", function () {
it("should dispatch a VideoDimensionsChanged action", function() {
session.trigger("streamCreated", {stream: fakeStream});
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.VideoDimensionsChanged({
isLocal: false,
@ -723,6 +784,22 @@ describe("loop.OTSdkDriver", function () {
}));
});
it("should dispatch a ConnectionStatus action", function() {
driver._metrics.connections = 1;
session.trigger("streamCreated", {stream: fakeStream});
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ConnectionStatus({
event: "Session.streamCreated",
state: "receiving",
connections: 1,
recvStreams: 1,
sendStreams: 0
}));
});
it("should subscribe to a camera stream", function() {
session.trigger("streamCreated", {stream: fakeStream});
@ -747,9 +824,9 @@ describe("loop.OTSdkDriver", function () {
session.trigger("streamCreated", {stream: fakeStream});
// Called twice due to the VideoDimensionsChanged above.
sinon.assert.calledTwice(dispatcher.dispatch);
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("name", "mediaConnected"));
new sharedActions.MediaConnected({}));
});
it("should store the start time when both streams are up and" +
@ -803,13 +880,33 @@ describe("loop.OTSdkDriver", function () {
session.trigger("streamCreated", {stream: fakeStream});
// Called twice due to the VideoDimensionsChanged above.
sinon.assert.calledTwice(dispatcher.dispatch);
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ReceivingScreenShare({receiving: true}));
});
});
describe("streamDestroyed", function() {
describe("streamDestroyed (publisher/local)", function() {
it("should dispatch a ConnectionStatus action", function() {
driver._metrics.sendStreams = 1;
driver._metrics.recvStreams = 1;
driver._metrics.connections = 2;
publisher.trigger("streamDestroyed");
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ConnectionStatus({
event: "Publisher.streamDestroyed",
state: "receiving",
connections: 2,
recvStreams: 1,
sendStreams: 0
}));
});
});
describe("streamDestroyed (session/remote)", function() {
var fakeStream;
beforeEach(function() {
@ -821,19 +918,38 @@ describe("loop.OTSdkDriver", function () {
it("should dispatch a ReceivingScreenShare action", function() {
session.trigger("streamDestroyed", {stream: fakeStream});
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ReceivingScreenShare({
receiving: false
}));
});
it("should dispatch a ConnectionStatus action", function() {
driver._metrics.connections = 2;
driver._metrics.sendStreams = 1;
driver._metrics.recvStreams = 1;
session.trigger("streamDestroyed", {stream: fakeStream});
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ConnectionStatus({
event: "Session.streamDestroyed",
state: "sending",
connections: 2,
recvStreams: 0,
sendStreams: 1
}));
});
it("should not dispatch an action if the videoType is camera", function() {
fakeStream.videoType = "camera";
session.trigger("streamDestroyed", {stream: fakeStream});
sinon.assert.notCalled(dispatcher.dispatch);
sinon.assert.neverCalledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("name", "receivingScreenShare"));
});
});
@ -888,25 +1004,75 @@ describe("loop.OTSdkDriver", function () {
connection: {id: "remoteUser"}
});
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.RemotePeerConnected());
it("should store the connection details for a remote user", function() {
expect(driver.connections).to.include.keys("remoteUser");
});
});
it("should not dispatch an action if this is for a local user",
it("should store the connection details for a remote user", function() {
session.trigger("connectionCreated", {
connection: {id: "remoteUser"}
});
expect(driver.connections).to.include.keys("remoteUser");
});
it("should dispatch a ConnectionStatus action for a remote user", function() {
driver._metrics.connections = 1;
driver._metrics.sendStreams = 1;
session.trigger("connectionCreated", {
connection: {id: "remoteUser"}
});
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ConnectionStatus({
event: "Session.connectionCreated",
state: "sending",
connections: 2,
recvStreams: 0,
sendStreams: 1
}));
});
it("should not dispatch an RemotePeerConnected action if this is for a local user",
function() {
session.trigger("connectionCreated", {
connection: {id: "localUser"}
});
sinon.assert.notCalled(dispatcher.dispatch);
sinon.assert.neverCalledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("name", "remotePeerConnected"));
});
it("should not store the connection details for a local user", function() {
session.trigger("connectionCreated", {
connection: {id: "localUser"}
});
expect(driver.connections).to.not.include.keys("localUser");
});
it("should dispatch a ConnectionStatus action for a remote user", function() {
driver._metrics.connections = 0;
driver._metrics.sendStreams = 0;
session.trigger("connectionCreated", {
connection: {id: "localUser"}
});
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ConnectionStatus({
event: "Session.connectionCreated",
state: "waiting",
connections: 1,
recvStreams: 0,
sendStreams: 0
}));
});
});
describe("accessAllowed", function() {
@ -989,8 +1155,6 @@ describe("loop.OTSdkDriver", function () {
driver.startScreenShare({
videoSource: "window"
});
sandbox.stub(dispatcher, "dispatch");
});
describe("accessAllowed", function() {
@ -1022,5 +1186,25 @@ describe("loop.OTSdkDriver", function () {
}));
});
});
describe("streamCreated", function() {
it("should dispatch a ConnectionStatus action", function() {
driver._metrics.connections = 2;
driver._metrics.recvStreams = 1;
driver._metrics.sendStreams = 1;
publisher.trigger("streamCreated", fakeEvent);
sinon.assert.calledOnce(dispatcher.dispatch);
sinon.assert.calledWithExactly(dispatcher.dispatch,
new sharedActions.ConnectionStatus({
event: "Publisher.streamCreated",
state: "sendrecv",
connections: 2,
recvStreams: 1,
sendStreams: 2
}));
});
});
});
});

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

@ -63,13 +63,14 @@ describe("loop.standaloneRoomViews", function() {
expect(view.getDOMNode().textContent).eql("Mike's room");
});
it("should display an unsupported browser message if crypto is unsupported", function() {
it("should log an unsupported browser message if crypto is unsupported", function() {
var view = mountTestComponent({
roomName: "Mark's room",
roomInfoFailure: ROOM_INFO_FAILURES.WEB_CRYPTO_UNSUPPORTED
});
expect(view.getDOMNode().textContent).match(/unsupported/);
sinon.assert.called(console.error);
sinon.assert.calledWithMatch(console.error, sinon.match("unsupported"));
});
it("should display a general error message for any other failure", function() {
@ -78,7 +79,8 @@ describe("loop.standaloneRoomViews", function() {
roomInfoFailure: ROOM_INFO_FAILURES.NO_DATA
});
expect(view.getDOMNode().textContent).match(/not_available/);
sinon.assert.called(console.error);
sinon.assert.calledWithMatch(console.error, sinon.match("not_available"));
});
it("should display context information if a url is supplied", function() {

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

@ -577,6 +577,26 @@ add_task(function* test_leaveRoom() {
Assert.equal(leaveData.sessionToken, "fakeLeaveSessionToken");
});
// Test if sending connection status works as expected.
add_task(function* test_sendConnectionStatus() {
let roomToken = "_nxD4V4FflQ";
let extraData = {
event: "Session.connectionDestroyed",
state: "test",
connections: 1,
sendStreams: 2,
recvStreams: 3
};
let statusData = yield LoopRooms.promise("sendConnectionStatus", roomToken,
"fakeStatusSessionToken", extraData
);
Assert.equal(statusData.sessionToken, "fakeStatusSessionToken");
extraData.action = "status";
extraData.sessionToken = "fakeStatusSessionToken";
Assert.deepEqual(statusData, extraData);
});
// Test if renaming a room works as expected.
add_task(function* test_renameRoom() {
Services.prefs.setBoolPref(kContextEnabledPref, true);

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

@ -734,7 +734,6 @@ BrowserGlue.prototype = {
LightweightThemeManager.addBuiltInTheme({
id: "firefox-devedition@mozilla.org",
name: themeName,
accentcolor: "transparent",
headerURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.header.png",
iconURL: "resource:///chrome/browser/content/browser/defaultthemes/devedition.icon.png",
author: vendorShortName,

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

@ -234,6 +234,7 @@ var BookmarkPropertiesPanel = {
}
else { // edit
this._node = dialogInfo.node;
this._title = this._node.title;
switch (dialogInfo.type) {
case "bookmark":
this._itemType = BOOKMARK_ITEM;

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

@ -529,7 +529,7 @@ let gEditItemOverlay = {
let itemId = this._paneInfo.itemId;
let description = this._element("descriptionField").value;
if (description != PlacesUIUtils.getItemDescription(this._itemId)) {
if (description != PlacesUIUtils.getItemDescription(this._paneInfo.itemId)) {
let annotation =
{ name: PlacesUIUtils.DESCRIPTION_ANNO, value: description };
if (!PlacesUIUtils.useAsyncTransactions) {
@ -562,7 +562,7 @@ let gEditItemOverlay = {
if (!PlacesUIUtils.useAsyncTransactions) {
let itemId = this._paneInfo.itemId;
let txn = new PlacesEditBookmarkURITransaction(this._itemId, newURI);
let txn = new PlacesEditBookmarkURITransaction(this._paneInfo.itemId, newURI);
PlacesUtils.transactionManager.doTransaction(txn);
return;
}
@ -677,7 +677,7 @@ let gEditItemOverlay = {
if (aEvent.target.id == "editBMPanel_chooseFolderMenuItem") {
// reset the selection back to where it was and expand the tree
// (this menu-item is hidden when the tree is already visible
let containerId = PlacesUtils.bookmarks.getFolderIdForItem(this._itemId);
let containerId = PlacesUtils.bookmarks.getFolderIdForItem(this._paneInfo.itemId);
let item = this._getFolderMenuItem(containerId);
this._folderMenuList.selectedItem = item;
// XXXmano HACK: setTimeout 100, otherwise focus goes back to the
@ -697,7 +697,7 @@ let gEditItemOverlay = {
}.bind(this));
}
else {
let txn = new PlacesMoveItemTransaction(this._itemId,
let txn = new PlacesMoveItemTransaction(this._paneInfo.itemId,
containerId,
PlacesUtils.bookmarks.DEFAULT_INDEX);
PlacesUtils.transactionManager.doTransaction(txn);

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

@ -598,6 +598,30 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
});
},
/**
* Copy the raw request headers from the currently selected item.
*/
copyRequestHeaders: function() {
let selected = this.selectedItem.attachment;
let rawHeaders = selected.requestHeaders.rawHeaders.trim();
if (Services.appinfo.OS !== "WINNT") {
rawHeaders = rawHeaders.replace(/\r/g, "");
}
clipboardHelper.copyString(rawHeaders, document);
},
/**
* Copy the raw response headers from the currently selected item.
*/
copyResponseHeaders: function() {
let selected = this.selectedItem.attachment;
let rawHeaders = selected.responseHeaders.rawHeaders.trim();
if (Services.appinfo.OS !== "WINNT") {
rawHeaders = rawHeaders.replace(/\r/g, "");
}
clipboardHelper.copyString(rawHeaders, document);
},
/**
* Copy image as data uri.
*/
@ -1809,6 +1833,12 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
let copyAsCurlElement = $("#request-menu-context-copy-as-curl");
copyAsCurlElement.hidden = !selectedItem || !selectedItem.attachment.responseContent;
let copyRequestHeadersElement = $("#request-menu-context-copy-request-headers");
copyRequestHeadersElement.hidden = !selectedItem || !selectedItem.attachment.requestHeaders;
let copyResponseHeadersElement = $("#response-menu-context-copy-response-headers");
copyResponseHeadersElement.hidden = !selectedItem || !selectedItem.attachment.responseHeaders;
let copyResponse = $("#request-menu-context-copy-response");
copyResponse.hidden = !selectedItem ||
!selectedItem.attachment.responseContent ||

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

@ -34,6 +34,13 @@
<menuitem id="request-menu-context-copy-as-curl"
label="&netmonitorUI.context.copyAsCurl;"
oncommand="NetMonitorView.RequestsMenu.copyAsCurl();"/>
<menuitem id="request-menu-context-copy-request-headers"
label="&netmonitorUI.context.copyRequestHeaders;"
accesskey="&netmonitorUI.context.copyRequestHeaders.accesskey;"
oncommand="NetMonitorView.RequestsMenu.copyRequestHeaders();"/>
<menuitem id="response-menu-context-copy-response-headers"
label="&netmonitorUI.context.copyResponseHeaders;"
oncommand="NetMonitorView.RequestsMenu.copyResponseHeaders();"/>
<menuitem id="request-menu-context-copy-response"
label="&netmonitorUI.context.copyResponse;"
accesskey="&netmonitorUI.context.copyResponse.accesskey;"/>

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

@ -54,6 +54,7 @@ skip-if= buildapp == 'mulet'
[browser_net_copy_image_as_data_uri.js]
[browser_net_copy_url.js]
[browser_net_copy_response.js]
[browser_net_copy_headers.js]
[browser_net_copy_as_curl.js]
skip-if = e10s # Bug 1091596
[browser_net_cyrillic-01.js]

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

@ -0,0 +1,63 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if copying a request's request/response headers works.
*/
add_task(function*() {
let [ aTab, aDebuggee, aMonitor ] = yield initNetMonitor(SIMPLE_URL);
info("Starting test... ");
let { NetMonitorView } = aMonitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
aDebuggee.location.reload();
yield waitForNetworkEvents(aMonitor, 1);
let requestItem = RequestsMenu.getItemAtIndex(0);
RequestsMenu.selectedItem = requestItem;
let clipboard = null;
const EXPECTED_REQUEST_HEADERS = [
requestItem.attachment.method + " " + SIMPLE_URL + " " + requestItem.attachment.httpVersion,
"Host: example.com",
"User-Agent: " + navigator.userAgent + "",
"Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
"Accept-Language: " + navigator.languages.join(",") + ";q=0.5",
"Accept-Encoding: gzip, deflate",
"Connection: keep-alive",
"Pragma: no-cache",
"Cache-Control: no-cache"
].join("\n");
RequestsMenu.copyRequestHeaders();
clipboard = SpecialPowers.getClipboardData("text/unicode");
// Sometimes, a "Cookie" header is left over from other tests. Remove it:
clipboard = clipboard.replace(/Cookie: [^\n]+\n/, "");
is(clipboard, EXPECTED_REQUEST_HEADERS, "Clipboard contains the currently selected item's request headers.");
const EXPECTED_RESPONSE_HEADERS = [
requestItem.attachment.httpVersion + " " + requestItem.attachment.status + " " + requestItem.attachment.statusText,
"Last-Modified: Sun, 3 May 2015 11:11:11 GMT",
"Content-Type: text/html",
"Content-Length: 465",
"Connection: close",
"Server: httpd.js",
"Date: Sun, 3 May 2015 11:11:11 GMT"
].join("\n");
RequestsMenu.copyResponseHeaders();
clipboard = SpecialPowers.getClipboardData("text/unicode");
// Fake the "Last-Modified" and "Date" headers because they will vary:
clipboard = clipboard
.replace(/Last-Modified: [^\n]+ GMT/, "Last-Modified: Sun, 3 May 2015 11:11:11 GMT")
.replace(/Date: [^\n]+ GMT/, "Date: Sun, 3 May 2015 11:11:11 GMT");
is(clipboard, EXPECTED_RESPONSE_HEADERS, "Clipboard contains the currently selected item's response headers.");
teardown(aMonitor).then(finish);
});

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

@ -33,7 +33,7 @@
background-position: -48px center;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#eyedropper-button {
background-image: url("chrome://browser/skin/devtools/command-eyedropper@2x.png");
}

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

@ -42,7 +42,7 @@
position: relative;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.breakpoint {
background-image: url("chrome://browser/skin/devtools/editor-breakpoint@2x.png");
}
@ -56,7 +56,7 @@
background-image: url("chrome://browser/skin/devtools/editor-debug-location.png");
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.debugLocation {
background-image: url("chrome://browser/skin/devtools/editor-debug-location@2x.png");
}
@ -68,7 +68,7 @@
url("chrome://browser/skin/devtools/editor-breakpoint.png");
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.breakpoint.debugLocation {
background-image:
url("chrome://browser/skin/devtools/editor-debug-location@2x.png"),

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

@ -1415,6 +1415,8 @@ WebConsoleFrame.prototype = {
let severity = 'error';
if (aScriptError.warning || aScriptError.strict) {
severity = 'warning';
} else if (aScriptError.info) {
severity = 'log';
}
let category = 'js';

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

@ -260,16 +260,16 @@
- on the context menu that copies the selected request's url -->
<!ENTITY netmonitorUI.context.copyUrl "Copy URL">
<!-- LOCALIZATION NOTE (netmonitorUI.context.copyUrl.accesskey): This is the access key
- for the Copy URL menu item displayed in the context menu for a request -->
<!ENTITY netmonitorUI.context.copyUrl.accesskey "C">
<!-- LOCALIZATION NOTE (netmonitorUI.context.copyAsCurl): This is the label displayed
- on the context menu that copies the selected request as a cURL command.
- The capitalization is part of the official name and should be used throughout all languages.
- http://en.wikipedia.org/wiki/CURL -->
<!ENTITY netmonitorUI.context.copyAsCurl "Copy as cURL">
<!-- LOCALIZATION NOTE (netmonitorUI.context.copyUrl.accesskey): This is the access key
- for the Copy URL menu item displayed in the context menu for a request -->
<!ENTITY netmonitorUI.context.copyUrl.accesskey "C">
<!-- LOCALIZATION NOTE (netmonitorUI.context.copyImageAsDataUri): This is the label displayed
- on the context menu that copies the selected image as data uri -->
<!ENTITY netmonitorUI.context.copyImageAsDataUri "Copy Image as Data URI">
@ -282,10 +282,22 @@
- on the context menu that copies the selected response as a string -->
<!ENTITY netmonitorUI.context.copyResponse "Copy Response">
<!-- LOCALIZATION NOTE (netmonitorUI.context.copyImageAsDataUri.accesskey): This is the access key
<!-- LOCALIZATION NOTE (netmonitorUI.context.copyRespose.accesskey): This is the access key
- for the Copy Response menu item displayed in the context menu for a request -->
<!ENTITY netmonitorUI.context.copyResponse.accesskey "R">
<!-- LOCALIZATION NOTE (netmonitorUI.context.copyRequestHeaders): This is the label displayed
- on the context menu that copies the selected item's request headers -->
<!ENTITY netmonitorUI.context.copyRequestHeaders "Copy Request Headers">
<!-- LOCALIZATION NOTE (netmonitorUI.context.copyRequestHeaders.accesskey): This is the access key
- for the Copy Request Headers menu item displayed in the context menu for a request -->
<!ENTITY netmonitorUI.context.copyRequestHeaders.accesskey "H">
<!-- LOCALIZATION NOTE (netmonitorUI.context.copyResponseHeaders): This is the label displayed
- on the context menu that copies the selected item's response headers -->
<!ENTITY netmonitorUI.context.copyResponseHeaders "Copy Response Headers">
<!-- LOCALIZATION NOTE (netmonitorUI.summary.editAndResend): This is the label displayed
- on the button in the headers tab that opens a form to edit and resend the currently
displayed request -->

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

@ -84,7 +84,7 @@ body {
background-image: url("debugger-play.png");
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#element-picker::before {
background-image: url("chrome://browser/skin/devtools/command-pick@2x.png");
background-size: 64px;
@ -156,7 +156,7 @@ body {
background-image: url(rewind.png);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.timeline .toggle::before {
background-image: url(debugger-pause@2x.png);
}

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

@ -145,7 +145,7 @@
list-style-image: url(debugger-step-out.png);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#resume {
list-style-image: url(debugger-play@2x.png);
-moz-image-region: rect(0px,64px,32px,32px);
@ -250,7 +250,7 @@
background-size: 12px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.selected .call-item-gutter {
background-image: url("editor-debug-location@2x.png");
}

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

@ -82,7 +82,7 @@
-moz-image-region: rect(0px, 64px, 16px, 48px);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#developer-toolbar-toolbox-button {
list-style-image: url("chrome://browser/skin/devtools/toggle-tools@2x.png");
-moz-image-region: rect(0px, 32px, 32px, 0px);
@ -111,7 +111,7 @@
opacity: 0.6;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#developer-toolbar-closebutton {
list-style-image: url("chrome://browser/skin/devtools/close@2x.png");
}
@ -199,7 +199,7 @@ html|*#gcli-output-frame {
background-position: -16px center;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.gclitoolbar-input-node::before {
background-image: url("chrome://browser/skin/devtools/commandline-icon@2x.png");
}

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

@ -61,7 +61,7 @@ body {
background-size: 5px 8px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.property-value, .other-property-value {
background-image: url(arrow-e@2x.png);
}

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

@ -326,7 +326,7 @@ div.CodeMirror span.eval-text {
background-position: -42px 0;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.theme-twisty, .theme-checkbox {
background-image: url("chrome://browser/skin/devtools/controls@2x.png");
}
@ -364,7 +364,7 @@ div.CodeMirror span.eval-text {
margin-left: -4px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.theme-tooltip-panel .panel-arrow[side="top"],
.theme-tooltip-panel .panel-arrow[side="bottom"] {
list-style-image: url("chrome://browser/skin/devtools/tooltip/arrow-vertical-dark@2x.png");

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

@ -66,7 +66,7 @@
list-style-image: url(debugger-blackbox.png);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#black-box {
list-style-image: url(debugger-blackbox@2x.png);
}
@ -76,7 +76,7 @@
list-style-image: url(debugger-prettyprint.png);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#pretty-print {
list-style-image: url(debugger-prettyprint@2x.png);
}
@ -86,7 +86,7 @@
list-style-image: url(debugger-toggleBreakpoints.png);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#toggle-breakpoints {
list-style-image: url(debugger-toggleBreakpoints@2x.png);
}
@ -100,7 +100,7 @@
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#sources-toolbar .devtools-toolbarbutton:not([label]) {
-moz-image-region: rect(0px,32px,32px,0px);
}
@ -134,7 +134,7 @@
-moz-margin-end: 5px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#black-boxed-message-button > .button-box > .button-icon {
background-image: url(debugger-blackbox@2x.png);
}
@ -222,7 +222,7 @@
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#trace {
list-style-image: url(tracer-icon@2x.png);
-moz-image-region: rect(0px,32px,32px,0px);
@ -324,7 +324,7 @@
margin: 2px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.dbg-expression-arrow {
background-image: url(commandline-icon@2x.png);
}
@ -560,7 +560,7 @@
list-style-image: url(debugger-play.png);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#resume {
list-style-image: url(debugger-pause@2x.png);
-moz-image-region: rect(0px,32px,32px,0px);
@ -592,7 +592,7 @@
list-style-image: url(debugger-step-out.png);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#step-over {
list-style-image: url(debugger-step-over@2x.png);
}
@ -622,7 +622,7 @@
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#instruments-pane-toggle {
list-style-image: url(debugger-collapse@2x.png);
-moz-image-region: rect(0px,32px,32px,0px);

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

@ -60,7 +60,7 @@
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#inspector-pane-toggle {
list-style-image: url(debugger-collapse@2x.png);
-moz-image-region: rect(0px,32px,32px,0px);

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

@ -335,7 +335,7 @@ div.CodeMirror span.eval-text {
background-position: -14px 0;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.theme-twisty, .theme-checkbox {
background-image: url("chrome://browser/skin/devtools/controls@2x.png");
}
@ -373,7 +373,7 @@ div.CodeMirror span.eval-text {
margin-left: -4px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.theme-tooltip-panel .panel-arrow[side="top"],
.theme-tooltip-panel .panel-arrow[side="bottom"] {
list-style-image: url("chrome://browser/skin/devtools/tooltip/arrow-vertical-light@2x.png");

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

@ -470,7 +470,7 @@ label.requests-menu-status-code {
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#details-pane-toggle {
list-style-image: url("chrome://browser/skin/devtools/debugger-collapse@2x.png");
-moz-image-region: rect(0px,32px,32px,0px);
@ -603,7 +603,7 @@ label.requests-menu-status-code {
height: 12px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.security-warning-icon {
background-image: url(alerticon-warning@2x.png);
}

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

@ -281,7 +281,7 @@
background-image: url(magnifying-glass-light.png);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.theme-dark .call-tree-zoom {
background-image: url(magnifying-glass@2x.png);
}
@ -610,7 +610,7 @@
background-position: -16px -16px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#jit-optimizations-view .opt-icon::before {
background-image: url(chrome://browser/skin/devtools/webconsole@2x.png);
}

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

@ -190,7 +190,7 @@
background-image: url(newtab.png);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.theme-dark #profile-newtab-button {
background-image: url(newtab-inverted@2x.png);
}
@ -367,7 +367,7 @@
background-image: url(magnifying-glass-light.png);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.theme-dark .call-tree-zoom {
background-image: url(magnifying-glass@2x.png);
}

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

@ -155,7 +155,7 @@
list-style-image: url("chrome://browser/skin/devtools/responsiveui-rotate.png");
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.devtools-responsiveui-close {
list-style-image: url("chrome://browser/skin/devtools/close@2x.png");
}
@ -174,7 +174,7 @@
-moz-image-region: rect(0px,32px,16px,16px);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.devtools-responsiveui-touch {
list-style-image: url("chrome://browser/skin/devtools/responsiveui-touch@2x.png");
-moz-image-region: rect(0px,32px,32px,0px);
@ -189,7 +189,7 @@
list-style-image: url("chrome://browser/skin/devtools/responsiveui-screenshot.png");
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.devtools-responsiveui-screenshot {
list-style-image: url("chrome://browser/skin/devtools/responsiveui-screenshot@2x.png");
}
@ -321,7 +321,7 @@
border-bottom-left-radius: 12px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.devtools-responsiveui-resizebarV {
background-image: url("chrome://browser/skin/devtools/responsive-vertical-resizer@2x.png");
}

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

@ -107,7 +107,7 @@
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.ruleview-warning {
background-image: url(alerticon-warning@2x.png);
}
@ -194,7 +194,7 @@
background-size: 1em;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.ruleview-bezierswatch {
background: url("chrome://browser/skin/devtools/cubic-bezier-swatch@2x.png");
background-size: 1em;

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

@ -60,7 +60,7 @@
border: 0;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.side-menu-widget-item-checkbox .checkbox-check {
background-image: url(itemToggle@2x.png);
}

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

@ -115,7 +115,7 @@
height: 40px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.stylesheet-enabled {
background-image: url(itemToggle@2x.png);
}

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

@ -316,7 +316,7 @@
background-repeat: no-repeat;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.devtools-button::before {
background-size: 32px;
}
@ -437,7 +437,7 @@
-moz-image-region: rect(0, 32px, 16px, 16px);
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.theme-dark .devtools-searchinput {
background-image: url(magnifying-glass@2x.png);
}
@ -769,7 +769,7 @@
background-image: url("chrome://browser/skin/devtools/command-rulers.png");
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#command-button-paintflashing > image {
background-image: url("chrome://browser/skin/devtools/command-paintflashing@2x.png");
}

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

@ -187,7 +187,7 @@ text {
-moz-box-flex: 1;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
#inspector-pane-toggle {
list-style-image: url(debugger-collapse@2x.png);
-moz-image-region: rect(0px,32px,32px,0px);

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

@ -52,7 +52,7 @@ a {
display: inline-block;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.message > .icon::before {
background-image: url(chrome://browser/skin/devtools/webconsole@2x.png);
}
@ -361,7 +361,7 @@ a {
background-size: 16px 16px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.jsterm-input-node {
background-image: -moz-image-rect(url('chrome://browser/skin/devtools/commandline-icon@2x.png'), 0, 64, 32, 32);
}

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

@ -107,7 +107,7 @@
padding: 0;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.scrollbutton-up > .toolbarbutton-icon,
.scrollbutton-down > .toolbarbutton-icon {
background-image: url("breadcrumbs-scrollbutton@2x.png");
@ -637,7 +637,7 @@
height: 16px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.variable-or-property-non-writable-icon {
background-image: url("chrome://browser/skin/devtools/vview-lock@2x.png");
}
@ -737,7 +737,7 @@
height: 16px;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.variables-view-delete {
background-image: url("chrome://browser/skin/devtools/vview-delete@2x.png");
}
@ -763,7 +763,7 @@
cursor: pointer;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.variables-view-edit {
background-image: url("chrome://browser/skin/devtools/vview-edit@2x.png");
}
@ -789,7 +789,7 @@
cursor: pointer;
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.variables-view-open-inspector {
background-image: url("chrome://browser/skin/devtools/vview-open-inspector@2x.png");
}
@ -1437,7 +1437,7 @@
}
}
@media (min-resolution: 2dppx) {
@media (min-resolution: 1.25dppx) {
.tree-widget-item:before {
background-image: url("chrome://browser/skin/devtools/controls@2x.png");
}

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

@ -8954,11 +8954,8 @@ dnl ========================================================
# builds. Bugs to enable:
#
# Android: bug 864843
# B2G: bug 866301
if test "$MOZ_WIDGET_TOOLKIT" = "android" ||
test "$MOZ_BUILD_APP" = "b2g" ||
test "$MOZ_BUILD_APP" = "b2g/dev"; then
if test "$MOZ_WIDGET_TOOLKIT" = "android"; then
_INTL_API=no
else
_INTL_API=yes

3
dom/cache/TypeUtils.cpp поставляемый
Просмотреть файл

@ -68,7 +68,8 @@ ProcessURL(nsAString& aUrl, bool* aSchemeValidOut,
if (aSchemeValidOut) {
nsAutoCString scheme(Substring(flatURL, schemePos, schemeLen));
*aSchemeValidOut = scheme.LowerCaseEqualsLiteral("http") ||
scheme.LowerCaseEqualsLiteral("https");
scheme.LowerCaseEqualsLiteral("https") ||
scheme.LowerCaseEqualsLiteral("app");
}
uint32_t queryPos;

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

@ -240,13 +240,12 @@ class MemoryReportRequestChild : public PMemoryReportRequestChild,
public:
NS_DECL_ISUPPORTS
MemoryReportRequestChild(uint32_t aGeneration, bool aAnonymize,
MemoryReportRequestChild(bool aAnonymize,
const MaybeFileDesc& aDMDFile);
NS_IMETHOD Run() override;
private:
virtual ~MemoryReportRequestChild();
uint32_t mGeneration;
bool mAnonymize;
FileDescriptor mDMDFile;
};
@ -254,8 +253,8 @@ private:
NS_IMPL_ISUPPORTS(MemoryReportRequestChild, nsIRunnable)
MemoryReportRequestChild::MemoryReportRequestChild(
uint32_t aGeneration, bool aAnonymize, const MaybeFileDesc& aDMDFile)
: mGeneration(aGeneration), mAnonymize(aAnonymize)
bool aAnonymize, const MaybeFileDesc& aDMDFile)
: mAnonymize(aAnonymize)
{
MOZ_COUNT_CTOR(MemoryReportRequestChild);
if (aDMDFile.type() == MaybeFileDesc::TFileDescriptor) {
@ -867,48 +866,37 @@ ContentChild::AllocPMemoryReportRequestChild(const uint32_t& aGeneration,
const MaybeFileDesc& aDMDFile)
{
MemoryReportRequestChild *actor =
new MemoryReportRequestChild(aGeneration, aAnonymize, aDMDFile);
new MemoryReportRequestChild(aAnonymize, aDMDFile);
actor->AddRef();
return actor;
}
// This is just a wrapper for InfallibleTArray<MemoryReport> that implements
// nsISupports, so it can be passed to nsIMemoryReporter::CollectReports.
class MemoryReportsWrapper final : public nsISupports {
~MemoryReportsWrapper() {}
public:
NS_DECL_ISUPPORTS
explicit MemoryReportsWrapper(InfallibleTArray<MemoryReport>* r) : mReports(r) { }
InfallibleTArray<MemoryReport> *mReports;
};
NS_IMPL_ISUPPORTS0(MemoryReportsWrapper)
class MemoryReportCallback final : public nsIMemoryReporterCallback
{
public:
NS_DECL_ISUPPORTS
explicit MemoryReportCallback(const nsACString& aProcess)
: mProcess(aProcess)
explicit MemoryReportCallback(MemoryReportRequestChild* aActor,
const nsACString& aProcess)
: mActor(aActor)
, mProcess(aProcess)
{
}
NS_IMETHOD Callback(const nsACString& aProcess, const nsACString &aPath,
int32_t aKind, int32_t aUnits, int64_t aAmount,
const nsACString& aDescription,
nsISupports* aiWrappedReports) override
nsISupports* aUnused) override
{
MemoryReportsWrapper *wrappedReports =
static_cast<MemoryReportsWrapper *>(aiWrappedReports);
MemoryReport memreport(mProcess, nsCString(aPath), aKind, aUnits,
aAmount, nsCString(aDescription));
wrappedReports->mReports->AppendElement(memreport);
mActor->SendReport(memreport);
return NS_OK;
}
private:
~MemoryReportCallback() {}
nsRefPtr<MemoryReportRequestChild> mActor;
const nsCString mProcess;
};
NS_IMPL_ISUPPORTS(
@ -944,21 +932,18 @@ NS_IMETHODIMP MemoryReportRequestChild::Run()
ContentChild *child = static_cast<ContentChild*>(Manager());
nsCOMPtr<nsIMemoryReporterManager> mgr = do_GetService("@mozilla.org/memory-reporter-manager;1");
InfallibleTArray<MemoryReport> reports;
nsCString process;
child->GetProcessName(process);
child->AppendProcessId(process);
// Run the reporters. The callback will turn each measurement into a
// MemoryReport.
nsRefPtr<MemoryReportsWrapper> wrappedReports =
new MemoryReportsWrapper(&reports);
nsRefPtr<MemoryReportCallback> cb = new MemoryReportCallback(process);
mgr->GetReportsForThisProcessExtended(cb, wrappedReports, mAnonymize,
nsRefPtr<MemoryReportCallback> cb =
new MemoryReportCallback(this, process);
mgr->GetReportsForThisProcessExtended(cb, nullptr, mAnonymize,
FileDescriptorToFILE(mDMDFile, "wb"));
bool sent = Send__delete__(this, mGeneration, reports);
bool sent = Send__delete__(this);
return sent ? NS_OK : NS_ERROR_FAILURE;
}

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

@ -405,45 +405,65 @@ bool ContentParent::sNuwaReady = false;
class MemoryReportRequestParent : public PMemoryReportRequestParent
{
public:
MemoryReportRequestParent();
explicit MemoryReportRequestParent(uint32_t aGeneration);
virtual ~MemoryReportRequestParent();
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
virtual bool Recv__delete__(const uint32_t& aGeneration, InfallibleTArray<MemoryReport>&& aReport) override;
virtual bool RecvReport(const MemoryReport& aReport) override;
virtual bool Recv__delete__() override;
private:
const uint32_t mGeneration;
// Non-null if we haven't yet called EndChildReport() on it.
nsRefPtr<nsMemoryReporterManager> mReporterManager;
ContentParent* Owner()
{
return static_cast<ContentParent*>(Manager());
}
};
MemoryReportRequestParent::MemoryReportRequestParent()
MemoryReportRequestParent::MemoryReportRequestParent(uint32_t aGeneration)
: mGeneration(aGeneration)
{
MOZ_COUNT_CTOR(MemoryReportRequestParent);
mReporterManager = nsMemoryReporterManager::GetOrCreate();
NS_WARN_IF(!mReporterManager);
}
bool
MemoryReportRequestParent::RecvReport(const MemoryReport& aReport)
{
if (mReporterManager) {
mReporterManager->HandleChildReport(mGeneration, aReport);
}
return true;
}
bool
MemoryReportRequestParent::Recv__delete__()
{
// Notifying the reporter manager is done in ActorDestroy, because
// it needs to happen even if the child process exits mid-report.
// (The reporter manager will time out eventually, but let's avoid
// that if possible.)
return true;
}
void
MemoryReportRequestParent::ActorDestroy(ActorDestroyReason aWhy)
{
// Implement me! Bug 1005154
if (mReporterManager) {
mReporterManager->EndChildReport(mGeneration, aWhy == Deletion);
mReporterManager = nullptr;
}
bool
MemoryReportRequestParent::Recv__delete__(const uint32_t& generation,
nsTArray<MemoryReport>&& childReports)
{
nsRefPtr<nsMemoryReporterManager> mgr =
nsMemoryReporterManager::GetOrCreate();
if (mgr) {
mgr->HandleChildReports(generation, childReports);
}
return true;
}
MemoryReportRequestParent::~MemoryReportRequestParent()
{
MOZ_ASSERT(!mReporterManager);
MOZ_COUNT_DTOR(MemoryReportRequestParent);
}
@ -3549,7 +3569,8 @@ ContentParent::AllocPMemoryReportRequestParent(const uint32_t& aGeneration,
const bool &aMinimizeMemoryUsage,
const MaybeFileDesc &aDMDFile)
{
MemoryReportRequestParent* parent = new MemoryReportRequestParent();
MemoryReportRequestParent* parent =
new MemoryReportRequestParent(aGeneration);
return parent;
}

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

@ -1,4 +1,4 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* -*- Mode: C++; tab-width: 8; 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/. */
@ -21,7 +21,8 @@ protocol PMemoryReportRequest {
manager PContent;
parent:
__delete__(uint32_t generation, MemoryReport[] report);
Report(MemoryReport aReport);
__delete__();
};
}

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

@ -51,7 +51,7 @@ PRLogModuleInfo* gAudioOffloadPlayerLog;
#endif
// maximum time in paused state when offloading audio decompression.
// When elapsed, the AudioSink is destroyed to allow the audio DSP to power down.
// When elapsed, the GonkAudioSink is destroyed to allow the audio DSP to power down.
static const uint64_t OFFLOAD_PAUSE_MAX_MSECS = 60000ll;
AudioOffloadPlayer::AudioOffloadPlayer(MediaOmxCommonDecoder* aObserver) :
@ -473,28 +473,28 @@ void AudioOffloadPlayer::NotifyAudioTearDown()
}
// static
size_t AudioOffloadPlayer::AudioSinkCallback(AudioSink* aAudioSink,
size_t AudioOffloadPlayer::AudioSinkCallback(GonkAudioSink* aAudioSink,
void* aBuffer,
size_t aSize,
void* aCookie,
AudioSink::cb_event_t aEvent)
GonkAudioSink::cb_event_t aEvent)
{
AudioOffloadPlayer* me = (AudioOffloadPlayer*) aCookie;
switch (aEvent) {
case AudioSink::CB_EVENT_FILL_BUFFER:
case GonkAudioSink::CB_EVENT_FILL_BUFFER:
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Notify Audio position changed"));
me->NotifyPositionChanged();
return me->FillBuffer(aBuffer, aSize);
case AudioSink::CB_EVENT_STREAM_END:
case GonkAudioSink::CB_EVENT_STREAM_END:
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Notify Audio EOS"));
me->mReachedEOS = true;
me->NotifyAudioEOS();
break;
case AudioSink::CB_EVENT_TEAR_DOWN:
case GonkAudioSink::CB_EVENT_TEAR_DOWN:
AUDIO_OFFLOAD_LOG(PR_LOG_DEBUG, ("Notify Tear down event"));
me->NotifyAudioTearDown();
break;
@ -697,7 +697,7 @@ MediaDecoderOwner::NextFrameStatus AudioOffloadPlayer::GetNextFrameStatus()
}
}
void AudioOffloadPlayer::SendMetaDataToHal(sp<AudioSink>& aSink,
void AudioOffloadPlayer::SendMetaDataToHal(sp<GonkAudioSink>& aSink,
const sp<MetaData>& aMeta)
{
int32_t sampleRate = 0;

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

@ -50,11 +50,11 @@ class WakeLock;
* it to the sink
*
* Also this class passes state changes (play/pause/seek) from
* MediaOmxCommonDecoder to AudioSink as well as provide AudioSink status
* MediaOmxCommonDecoder to GonkAudioSink as well as provide GonkAudioSink status
* (position changed, playback ended, seek complete, audio tear down) back to
* MediaOmxCommonDecoder
*
* It acts as a bridge between MediaOmxCommonDecoder and AudioSink during
* It acts as a bridge between MediaOmxCommonDecoder and GonkAudioSink during
* offload playback
*/
@ -80,7 +80,7 @@ public:
// Caller retains ownership of "aSource".
virtual void SetSource(const android::sp<MediaSource> &aSource) override;
// Start the source if it's not already started and open the AudioSink to
// Start the source if it's not already started and open the GonkAudioSink to
// create an offloaded audio track
virtual status_t Start(bool aSourceAlreadyStarted = false) override;
@ -106,7 +106,7 @@ public:
void Reset();
private:
// Set when audio source is started and audioSink is initialized
// Set when audio source is started and GonkAudioSink is initialized
// Used only in main thread
bool mStarted;
@ -170,7 +170,7 @@ private:
// Audio sink wrapper to access offloaded audio tracks
// Used in main thread and offload callback thread
// Race conditions are protected in underlying Android::AudioTrack class
android::sp<AudioSink> mAudioSink;
android::sp<GonkAudioSink> mAudioSink;
// Buffer used to get date from audio source. Used in offload callback thread
MediaBuffer* mInputBuffer;
@ -183,7 +183,7 @@ private:
// Timer to trigger position changed events
nsCOMPtr<nsITimer> mTimeUpdateTimer;
// Timer to reset AudioSink when audio is paused for OFFLOAD_PAUSE_MAX_USECS.
// Timer to reset GonkAudioSink when audio is paused for OFFLOAD_PAUSE_MAX_USECS.
// It is triggered in Pause() and canceled when there is a Play() within
// OFFLOAD_PAUSE_MAX_USECS. Used only from main thread so no lock is needed.
nsCOMPtr<nsITimer> mResetTimer;
@ -203,12 +203,12 @@ private:
// case of error
size_t FillBuffer(void *aData, size_t aSize);
// Called by AudioSink when it needs data, to notify EOS or tear down event
static size_t AudioSinkCallback(AudioSink *aAudioSink,
// Called by GonkAudioSink when it needs data, to notify EOS or tear down event
static size_t AudioSinkCallback(GonkAudioSink *aAudioSink,
void *aData,
size_t aSize,
void *aMe,
AudioSink::cb_event_t aEvent);
GonkAudioSink::cb_event_t aEvent);
bool IsSeeking();
@ -254,8 +254,8 @@ private:
// MediaDecoder to re-evaluate offloading options
void NotifyAudioTearDown();
// Send information from MetaData to the HAL via AudioSink
void SendMetaDataToHal(android::sp<AudioSink>& aSink,
// Send information from MetaData to the HAL via GonkAudioSink
void SendMetaDataToHal(android::sp<GonkAudioSink>& aSink,
const android::sp<MetaData>& aMeta);
AudioOffloadPlayer(const AudioOffloadPlayer &);

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

@ -24,7 +24,7 @@
#include <utils/Mutex.h>
#include <AudioTrack.h>
#include "AudioSink.h"
#include "GonkAudioSink.h"
namespace mozilla {
@ -34,7 +34,7 @@ namespace mozilla {
* Android::AudioTrack
* Similarly to ease handling offloaded tracks, part of AudioOutput is used here
*/
class AudioOutput : public AudioSink
class AudioOutput : public GonkAudioSink
{
typedef android::Mutex Mutex;
typedef android::String8 String8;

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

@ -17,8 +17,8 @@
* limitations under the License.
*/
#ifndef AUDIO_SINK_H_
#define AUDIO_SINK_H_
#ifndef GONK_AUDIO_SINK_H_
#define GONK_AUDIO_SINK_H_
#include <utils/Errors.h>
#include <utils/String8.h>
@ -39,7 +39,7 @@ namespace mozilla {
* Stripped version of Android KK MediaPlayerBase::AudioSink class
*/
class AudioSink : public android::RefBase
class GonkAudioSink : public android::RefBase
{
typedef android::String8 String8;
typedef android::status_t status_t;
@ -54,12 +54,12 @@ public:
};
// Callback returns the number of bytes actually written to the buffer.
typedef size_t (*AudioCallback)(AudioSink* aAudioSink,
typedef size_t (*AudioCallback)(GonkAudioSink* aAudioSink,
void* aBuffer,
size_t aSize,
void* aCookie,
cb_event_t aEvent);
virtual ~AudioSink() {}
virtual ~GonkAudioSink() {}
virtual ssize_t FrameSize() const = 0;
virtual status_t GetPosition(uint32_t* aPosition) const = 0;
virtual status_t SetVolume(float aVolume) const = 0;
@ -86,4 +86,4 @@ public:
} // namespace mozilla
#endif // AUDIO_SINK_H_
#endif // GONK_AUDIO_SINK_H_

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

@ -26,7 +26,7 @@ if CONFIG['MOZ_AUDIO_OFFLOAD']:
EXPORTS += [
'AudioOffloadPlayer.h',
'AudioOutput.h',
'AudioSink.h',
'GonkAudioSink.h',
]
SOURCES += [
'AudioOffloadPlayer.cpp',

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

@ -371,7 +371,7 @@ DOMSVGLength::SetValueAsString(const nsAString& aValue, ErrorResult& aRv)
}
if (mVal) {
mVal->SetBaseValueString(aValue, mSVGElement, true);
aRv = mVal->SetBaseValueString(aValue, mSVGElement, true);
return;
}

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

@ -3,7 +3,7 @@
https://bugzilla.mozilla.org/show_bug.cgi?id=539697
-->
<head>
<title>Test SVGTransform behavior</title>
<title>Test valueAsString behavior</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
@ -35,6 +35,7 @@ function run()
try {
c.r.baseVal.valueAsString = 'rubbish';
ok(false, 'setting a length to rubbish should fail');
} catch (e) {
is(e.name, 'SyntaxError', 'syntax error expected');
is(e.code, DOMException.SYNTAX_ERR, 'syntax error expected');
@ -46,6 +47,7 @@ function run()
try {
m.orientAngle.baseVal.valueAsString = 'rubbish';
ok(false, 'setting an angle to rubbish should fail');
} catch (e) {
is(e.name, 'SyntaxError', 'syntax error expected');
is(e.code, DOMException.SYNTAX_ERR, 'syntax error expected');

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

@ -61,7 +61,7 @@ var ecmaGlobals =
"Int32Array",
"Int8Array",
"InternalError",
{name: "Intl", desktop: true},
{name: "Intl", android: false},
"Iterator",
"JSON",
"Map",
@ -1391,6 +1391,7 @@ function createInterfaceMap(isXBLScope) {
var isRelease = !version.contains("a");
var isDesktop = !/Mobile|Tablet/.test(navigator.userAgent);
var isB2G = !isDesktop && !navigator.userAgent.contains("Android");
var isAndroid = navigator.userAgent.contains("Android");
var hasPermission = function (aPermissions) {
var result = false;
for (var p of aPermissions) {
@ -1410,6 +1411,7 @@ function createInterfaceMap(isXBLScope) {
(entry.xbl === !isXBLScope) ||
(entry.desktop === !isDesktop) ||
(entry.b2g === !isB2G) ||
(entry.android === !isAndroid) ||
(entry.release === !isRelease) ||
(entry.pref && !prefs.getBoolPref(entry.pref)) ||
(entry.permission && !hasPermission(entry.permission))) {

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

@ -418,11 +418,7 @@ CompareNetwork::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext
}
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(request);
if (!httpChannel) {
mManager->NetworkFinished(NS_ERROR_FAILURE);
return NS_OK;
}
if (httpChannel) {
bool requestSucceeded;
rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
if (NS_WARN_IF(NS_FAILED(rv))) {
@ -434,6 +430,36 @@ CompareNetwork::OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext
mManager->NetworkFinished(NS_ERROR_FAILURE);
return NS_OK;
}
}
else {
// The only supported request schemes are http, https, and app.
// Above, we check to ensure that the request is http or https
// based on the channel qi. Here we test the scheme to ensure
// that it is app. Otherwise, bail.
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
if (NS_WARN_IF(!channel)) {
mManager->NetworkFinished(NS_ERROR_FAILURE);
return NS_OK;
}
nsCOMPtr<nsIURI> uri;
rv = channel->GetURI(getter_AddRefs(uri));
if (NS_WARN_IF(NS_FAILED(rv))) {
mManager->NetworkFinished(rv);
return NS_OK;
}
nsAutoCString scheme;
rv = uri->GetScheme(scheme);
if (NS_WARN_IF(NS_FAILED(rv))) {
mManager->NetworkFinished(rv);
return NS_OK;
}
if (!scheme.LowerCaseEqualsLiteral("app")) {
mManager->NetworkFinished(NS_ERROR_FAILURE);
return NS_OK;
}
}
// FIXME(nsm): "Extract mime type..."

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

@ -35,7 +35,7 @@ var ecmaGlobals =
"Int32Array",
"Int8Array",
"InternalError",
{name: "Intl", b2g: false, android: false},
{name: "Intl", android: false},
"Iterator",
"JSON",
"Map",

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

@ -35,7 +35,7 @@ var ecmaGlobals =
"Int32Array",
"Int8Array",
"InternalError",
{name: "Intl", b2g: false, android: false},
{name: "Intl", android: false},
"Iterator",
"JSON",
"Map",

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

@ -1838,12 +1838,15 @@ class _GenerateProtocolCode(ipdl.ast.Visitor):
if usesend or userecv:
transitionfunc.addstmt(Whitespace.NL)
transitionfunc.addstmt(fromswitch)
# all --> Error transitions break to here. But only insert this
# block if there is any possibility of such transitions.
if self.protocol.transitionStmts:
transitionfunc.addstmts([
fromswitch,
# all --> Error transitions break to here
StmtExpr(ExprAssn(ExprDeref(nextvar), _errorState())),
StmtReturn(ExprLiteral.FALSE)
StmtReturn(ExprLiteral.FALSE),
])
return transitionfunc
##--------------------------------------------------

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

@ -63,15 +63,34 @@ template bool js::IsVectorObject<Int32x4>(HandleValue v);
template bool js::IsVectorObject<Float32x4>(HandleValue v);
template bool js::IsVectorObject<Float64x2>(HandleValue v);
static inline bool
ErrorBadArgs(JSContext* cx)
{
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
static inline bool
ErrorWrongTypeArg(JSContext* cx, size_t argIndex, Handle<TypeDescr*> typeDescr)
{
MOZ_ASSERT(argIndex < 10);
char charArgIndex[2];
JS_snprintf(charArgIndex, sizeof charArgIndex, "%d", argIndex);
HeapSlot& typeNameSlot = typeDescr->getReservedSlotRef(JS_DESCR_SLOT_STRING_REPR);
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_SIMD_NOT_A_VECTOR,
JS_EncodeString(cx, typeNameSlot.toString()), charArgIndex);
return false;
}
template<typename V>
bool
js::ToSimdConstant(JSContext* cx, HandleValue v, jit::SimdConstant* out)
{
typedef typename V::Elem Elem;
if (!IsVectorObject<V>(v)) {
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_SIMD_NOT_A_VECTOR);
return false;
}
Rooted<TypeDescr*> typeDescr(cx, &V::GetTypeDescr(*cx->global()));
if (!IsVectorObject<V>(v))
return ErrorWrongTypeArg(cx, 1, typeDescr);
Elem* mem = reinterpret_cast<Elem*>(v.toObject().as<TypedObject>().typedMem());
*out = jit::SimdConstant::CreateX4(mem);
@ -622,13 +641,6 @@ struct ShiftRightLogical {
};
}
static inline bool
ErrorBadArgs(JSContext* cx)
{
JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_TYPED_ARRAY_BAD_ARGS);
return false;
}
template<typename Out>
static bool
StoreResult(JSContext* cx, CallArgs& args, typename Out::Elem* result)

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

@ -658,14 +658,15 @@ NonLocalExitScope::prepareForNonLocalJump(StmtInfoBCE* toStmt)
if (stmt->isBlockScope) {
MOZ_ASSERT(stmt->isNestedScope);
StaticBlockObject& blockObj = stmt->staticBlock();
if (!bce->emit1(JSOP_DEBUGLEAVEBLOCK))
return false;
if (!popScopeForNonLocalExit(stmt->blockScopeIndex))
return false;
if (blockObj.needsClone()) {
if (!bce->emit1(JSOP_POPBLOCKSCOPE))
return false;
} else {
if (!bce->emit1(JSOP_DEBUGLEAVEBLOCK))
return false;
}
if (!popScopeForNonLocalExit(stmt->blockScopeIndex))
return false;
}
}
@ -877,12 +878,18 @@ BytecodeEmitter::computeLocalOffset(Handle<StaticBlockObject*> blockObj)
// Only functions have fixed var bindings.
//
// To assist the debugger, we emit a DEBUGLEAVEBLOCK opcode before leaving a
// block scope, even if the block has no aliased locals. This allows
// DebugScopes to invalidate any association between a debugger scope object,
// which can proxy access to unaliased stack locals, and the actual live frame.
// In normal, non-debug mode, this opcode does not cause any baseline code to be
// block scope, if the block has no aliased locals. This allows DebugScopes
// to invalidate any association between a debugger scope object, which can
// proxy access to unaliased stack locals, and the actual live frame. In
// normal, non-debug mode, this opcode does not cause any baseline code to be
// emitted.
//
// If the block has aliased locals, no DEBUGLEAVEBLOCK is emitted, and
// POPBLOCKSCOPE itself balances the debug scope mapping. This gets around a
// comedic situation where DEBUGLEAVEBLOCK may remove a block scope from the
// debug scope map, but the immediate following POPBLOCKSCOPE adds it back due
// to an onStep hook.
//
// Enter a nested scope with enterNestedScope. It will emit
// PUSHBLOCKSCOPE/ENTERWITH if needed, and arrange to record the PC bounds of
// the scope. Leave a nested scope with leaveNestedScope, which, for blocks,
@ -974,12 +981,17 @@ BytecodeEmitter::leaveNestedScope(StmtInfoBCE* stmt)
popStatement();
if (!emit1(stmt->isBlockScope ? JSOP_DEBUGLEAVEBLOCK : JSOP_LEAVEWITH))
return false;
if (stmt->isBlockScope && stmt->staticScope->as<StaticBlockObject>().needsClone()) {
if (stmt->isBlockScope) {
if (stmt->staticScope->as<StaticBlockObject>().needsClone()) {
if (!emit1(JSOP_POPBLOCKSCOPE))
return false;
} else {
if (!emit1(JSOP_DEBUGLEAVEBLOCK))
return false;
}
} else {
if (!emit1(JSOP_LEAVEWITH))
return false;
}
blockScopeList.recordEnd(blockScopeIndex, offset());

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

@ -633,6 +633,15 @@ class FullParseHandler
return false;
}
bool isReturnStatement(ParseNode* node) {
return node->isKind(PNK_RETURN);
}
bool isStatementPermittedAfterReturnStatement(ParseNode *node) {
ParseNodeKind kind = node->getKind();
return kind == PNK_FUNCTION || kind == PNK_VAR || kind == PNK_BREAK || kind == PNK_THROW;
}
inline bool finishInitializerAssignment(ParseNode* pn, ParseNode* init, JSOp op);
void setBeginPosition(ParseNode* pn, ParseNode* oth) {
@ -659,11 +668,23 @@ class FullParseHandler
}
ParseNode* newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
return new_<ListNode>(kind, op, pos());
}
ParseNode* newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
kind == PNK_GLOBALCONST);
return new_<ListNode>(kind, op, pos());
}
/* New list with one initial child node. kid must be non-null. */
ParseNode* newList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
return new_<ListNode>(kind, op, kid);
}
ParseNode* newDeclarationList(ParseNodeKind kind, ParseNode* kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
kind == PNK_GLOBALCONST);
return new_<ListNode>(kind, op, kid);
}

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

@ -1670,7 +1670,7 @@ Parser<ParseHandler>::functionArguments(FunctionSyntaxKind kind, FunctionType ty
if (list) {
handler.addList(list, item);
} else {
list = handler.newList(PNK_VAR, item);
list = handler.newDeclarationList(PNK_VAR, item);
if (!list)
return false;
*listp = list;
@ -2820,6 +2820,9 @@ Parser<ParseHandler>::statements()
pc->blockNode = pn;
bool canHaveDirectives = pc->atBodyLevel();
bool afterReturn = false;
bool warnedAboutStatementsAfterReturn = false;
uint32_t statementBegin;
for (;;) {
TokenKind tt;
if (!tokenStream.peekToken(&tt, TokenStream::Operand)) {
@ -2829,12 +2832,32 @@ Parser<ParseHandler>::statements()
}
if (tt == TOK_EOF || tt == TOK_RC)
break;
if (afterReturn) {
TokenPos pos(0, 0);
if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
return null();
statementBegin = pos.begin;
}
Node next = statement(canHaveDirectives);
if (!next) {
if (tokenStream.isEOF())
isUnexpectedEOF_ = true;
return null();
}
if (!warnedAboutStatementsAfterReturn) {
if (afterReturn) {
if (!handler.isStatementPermittedAfterReturnStatement(next)) {
if (!reportWithOffset(ParseWarning, false, statementBegin,
JSMSG_STMT_AFTER_RETURN))
{
return null();
}
warnedAboutStatementsAfterReturn = true;
}
} else if (handler.isReturnStatement(next)) {
afterReturn = true;
}
}
if (canHaveDirectives) {
if (!maybeParseDirective(pn, next, &canHaveDirectives))
@ -3803,7 +3826,7 @@ Parser<ParseHandler>::variables(ParseNodeKind kind, bool* psimple,
else if (kind == PNK_GLOBALCONST)
op = JSOP_DEFCONST;
Node pn = handler.newList(kind, op);
Node pn = handler.newDeclarationList(kind, op);
if (!pn)
return null();
@ -5168,14 +5191,37 @@ Parser<ParseHandler>::switchStatement()
if (!body)
return null();
bool afterReturn = false;
bool warnedAboutStatementsAfterReturn = false;
uint32_t statementBegin;
while (true) {
if (!tokenStream.peekToken(&tt, TokenStream::Operand))
return null();
if (tt == TOK_RC || tt == TOK_CASE || tt == TOK_DEFAULT)
break;
if (afterReturn) {
TokenPos pos(0, 0);
if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
return null();
statementBegin = pos.begin;
}
Node stmt = statement();
if (!stmt)
return null();
if (!warnedAboutStatementsAfterReturn) {
if (afterReturn) {
if (!handler.isStatementPermittedAfterReturnStatement(stmt)) {
if (!reportWithOffset(ParseWarning, false, statementBegin,
JSMSG_STMT_AFTER_RETURN))
{
return null();
}
warnedAboutStatementsAfterReturn = true;
}
} else if (handler.isReturnStatement(stmt)) {
afterReturn = true;
}
}
handler.addList(body, stmt);
}
@ -5319,19 +5365,7 @@ Parser<ParseHandler>::returnStatement()
if (!tokenStream.peekTokenSameLine(&tt, TokenStream::Operand))
return null();
switch (tt) {
case TOK_EOL: {
bool startsExpr;
if (!tokenStream.nextTokenStartsExpr(&startsExpr, TokenStream::Operand))
return null();
if (startsExpr) {
TokenPos pos;
if (!tokenStream.peekTokenPos(&pos, TokenStream::Operand))
return null();
if (!reportWithOffset(ParseWarning, false, pos.begin, JSMSG_STMT_AFTER_SEMI_LESS))
return null();
}
// Fall through.
}
case TOK_EOL:
case TOK_EOF:
case TOK_SEMI:
case TOK_RC:

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

@ -43,6 +43,10 @@ class SyntaxParseHandler
NodeGetProp,
NodeStringExprStatement,
NodeLValue,
NodeReturn,
NodeHoistableDeclaration,
NodeBreak,
NodeThrow,
// In rare cases a parenthesized |node| doesn't have the same semantics
// as |node|. Each such node has a special Node value, and we use a
@ -214,14 +218,14 @@ class SyntaxParseHandler
Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; }
Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; }
Node newContinueStatement(PropertyName* label, const TokenPos& pos) { return NodeGeneric; }
Node newBreakStatement(PropertyName* label, const TokenPos& pos) { return NodeGeneric; }
Node newReturnStatement(Node expr, Node genrval, const TokenPos& pos) { return NodeGeneric; }
Node newBreakStatement(PropertyName* label, const TokenPos& pos) { return NodeBreak; }
Node newReturnStatement(Node expr, Node genrval, const TokenPos& pos) { return NodeReturn; }
Node newLabeledStatement(PropertyName* label, Node stmt, uint32_t begin) {
return NodeGeneric;
}
Node newThrowStatement(Node expr, const TokenPos& pos) { return NodeGeneric; }
Node newThrowStatement(Node expr, const TokenPos& pos) { return NodeThrow; }
Node newTryStatement(uint32_t begin, Node body, Node catchList, Node finallyBlock) {
return NodeGeneric;
}
@ -238,7 +242,7 @@ class SyntaxParseHandler
Node catchName, Node catchGuard, Node catchBody) { return true; }
void setLastFunctionArgumentDefault(Node funcpn, Node pn) {}
Node newFunctionDefinition() { return NodeGeneric; }
Node newFunctionDefinition() { return NodeHoistableDeclaration; }
void setFunctionBody(Node pn, Node kid) {}
void setFunctionBox(Node pn, FunctionBox* funbox) {}
void addFunctionArgument(Node pn, Node argpn) {}
@ -277,11 +281,23 @@ class SyntaxParseHandler
}
Node newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
return NodeGeneric;
}
Node newDeclarationList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
kind == PNK_GLOBALCONST);
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
}
Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind != PNK_VAR);
return NodeGeneric;
}
Node newDeclarationList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
MOZ_ASSERT(kind == PNK_VAR || kind == PNK_CONST || kind == PNK_LET ||
kind == PNK_GLOBALCONST);
return kind == PNK_VAR ? NodeHoistableDeclaration : NodeGeneric;
}
Node newCatchList() {
return newList(PNK_CATCHLIST, JSOP_NOP);
@ -292,7 +308,8 @@ class SyntaxParseHandler
}
void addList(Node list, Node kid) {
MOZ_ASSERT(list == NodeGeneric || list == NodeUnparenthesizedCommaExpr);
MOZ_ASSERT(list == NodeGeneric || list == NodeUnparenthesizedCommaExpr ||
list == NodeHoistableDeclaration);
}
Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs,
@ -315,6 +332,14 @@ class SyntaxParseHandler
return node == NodeUnparenthesizedAssignment;
}
bool isReturnStatement(Node node) {
return node == NodeReturn;
}
bool isStatementPermittedAfterReturnStatement(Node pn) {
return pn == NodeHoistableDeclaration || pn == NodeBreak || pn == NodeThrow;
}
void setOp(Node pn, JSOp op) {}
void setBlockId(Node pn, unsigned blockid) {}
void setFlag(Node pn, unsigned flag) {}

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

@ -322,33 +322,6 @@ TokenStream::TokenStream(ExclusiveContext* cx, const ReadOnlyCompileOptions& opt
isExprEnding[TOK_RP] = 1;
isExprEnding[TOK_RB] = 1;
isExprEnding[TOK_RC] = 1;
memset(isExprStarting, 0, sizeof(isExprStarting));
isExprStarting[TOK_INC] = 1;
isExprStarting[TOK_DEC] = 1;
isExprStarting[TOK_LB] = 1;
isExprStarting[TOK_LC] = 1;
isExprStarting[TOK_LP] = 1;
isExprStarting[TOK_NAME] = 1;
isExprStarting[TOK_NUMBER] = 1;
isExprStarting[TOK_STRING] = 1;
isExprStarting[TOK_TEMPLATE_HEAD] = 1;
isExprStarting[TOK_NO_SUBS_TEMPLATE] = 1;
isExprStarting[TOK_REGEXP] = 1;
isExprStarting[TOK_TRUE] = 1;
isExprStarting[TOK_FALSE] = 1;
isExprStarting[TOK_NULL] = 1;
isExprStarting[TOK_THIS] = 1;
isExprStarting[TOK_NEW] = 1;
isExprStarting[TOK_DELETE] = 1;
isExprStarting[TOK_YIELD] = 1;
isExprStarting[TOK_CLASS] = 1;
isExprStarting[TOK_ADD] = 1;
isExprStarting[TOK_SUB] = 1;
isExprStarting[TOK_TYPEOF] = 1;
isExprStarting[TOK_VOID] = 1;
isExprStarting[TOK_NOT] = 1;
isExprStarting[TOK_BITNOT] = 1;
}
#ifdef _MSC_VER
@ -658,6 +631,7 @@ TokenStream::reportCompileErrorNumberVA(uint32_t offset, unsigned flags, unsigne
if (offset != NoOffset && !err.report.filename && cx->isJSContext()) {
NonBuiltinFrameIter iter(cx->asJSContext(),
FrameIter::ALL_CONTEXTS, FrameIter::GO_THROUGH_SAVED,
FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK,
cx->compartment()->principals());
if (!iter.done() && iter.scriptFilename()) {
callerFilename = true;

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

@ -494,14 +494,6 @@ class MOZ_STACK_CLASS TokenStream
return true;
}
bool nextTokenStartsExpr(bool* startsExpr, Modifier modifier = None) {
TokenKind tt;
if (!peekToken(&tt, modifier))
return false;
*startsExpr = isExprStarting[tt];
return true;
}
bool nextTokenEndsExpr(bool* endsExpr) {
TokenKind tt;
if (!peekToken(&tt))
@ -836,7 +828,6 @@ class MOZ_STACK_CLASS TokenStream
mozilla::UniquePtr<char16_t[], JS::FreePolicy> displayURL_; // the user's requested source URL or null
mozilla::UniquePtr<char16_t[], JS::FreePolicy> sourceMapURL_; // source map's filename or null
CharBuffer tokenbuf; // current token string buffer
uint8_t isExprStarting[TOK_LIMIT];// which tokens can start exprs?
uint8_t isExprEnding[TOK_LIMIT];// which tokens definitely terminate exprs?
ExclusiveContext* const cx;
bool mutedErrors;

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

@ -37,7 +37,7 @@ assertEq(asmLink(asmCompile(USE_ASM + 'function f(){;} return f'))(), undefined)
assertAsmTypeFail(USE_ASM + 'function f(i,j){;} return f');
assertEq(asmLink(asmCompile('"use asm";; function f(){};;; return f;;'))(), undefined);
assertAsmTypeFail(USE_ASM + 'function f(x){} return f');
assertAsmTypeFail(USE_ASM + 'function f(){return; return 1} return f');
assertAsmTypeFail(USE_ASM + 'function f(){if (0) return; return 1} return f');
assertEq(asmLink(asmCompile(USE_ASM + 'function f(x){x=x|0} return f'))(42), undefined);
assertEq(asmLink(asmCompile(USE_ASM + 'function f(x){x=x|0; return x|0} return f'))(42), 42);
assertEq(asmLink(asmCompile(USE_ASM + 'function f(x){x=x|0; return x|0;;;} return f'))(42), 42);

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

@ -12,7 +12,7 @@ assertEq(asmLink(asmCompile(USE_ASM + "function f(i) { i=i|0; if ((i|0) == 0) i
assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; if (i) return 0; } return f");
assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; if (i) return 0; else return 1 } return f");
assertAsmTypeFail(USE_ASM + "function f(i) { i=i|0; if (i) return 0; return 1.0 } return f");
assertAsmTypeFail(USE_ASM + "function f() { return 0; 1 } return f");
assertAsmTypeFail(USE_ASM + "function f() { if (0) return 0; 1 } return f");
assertEq(asmLink(asmCompile(USE_ASM + "function f() { while (0) {} return 0} return f"))(), 0);
assertEq(asmLink(asmCompile(USE_ASM + "function f() { for (;0;) {} return 0} return f"))(), 0);

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

@ -30,7 +30,7 @@ assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { retu
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { return +(inc() + 1.1) } return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { return (+inc() + 1)|0 } return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { var i = 0; inc(i>>>0) } return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { return inc(); return } return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { if (0) return inc(); return } return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { inc(inc()) } return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { g(inc()) } function g() {} return f');
assertAsmTypeFail('glob', 'imp', USE_ASM + 'var inc=imp.inc; function f() { inc()|inc() } return f');

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

@ -137,7 +137,7 @@ assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return 1 } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return false } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true; 1 } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT1 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; if (0) return true; 1 } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); b=b2; return true } function f() { return 42 } return f');
assertAsmTypeFail('glob', 'ffis', 'b', USE_ASM + IMPORT2 + 'function ch(b2) { if(len(b2) & 0xffffff || len(b2) <= 0xffffff || len(b2) > 0x80000000) return false; i32=new I32(b2); i8=new I8(b2); b=b2; return true } function f() { return 42 } return f');

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

@ -1,5 +1,4 @@
// Warning should be shown for expression-like statement after semicolon-less
// return (bug 1005110).
// Warning should be shown for unreachable statement after return (bug 1151931).
load(libdir + "class.js");
@ -12,7 +11,7 @@ function testWarn(code, lineNumber, columnNumber) {
eval(code);
} catch (e) {
caught = true;
assertEq(e.message, "unreachable expression after semicolon-less return statement", code);
assertEq(e.constructor, SyntaxError);
assertEq(e.lineNumber, lineNumber);
assertEq(e.columnNumber, columnNumber);
}
@ -23,7 +22,7 @@ function testWarn(code, lineNumber, columnNumber) {
Reflect.parse(code);
} catch (e) {
caught = true;
assertEq(e.message, "unreachable expression after semicolon-less return statement", code);
assertEq(e.constructor, SyntaxError);
}
assertEq(caught, true, "warning should be caught for " + code);
}
@ -46,8 +45,6 @@ function testPass(code) {
assertEq(caught, false, "warning should not be caught for " + code);
}
// not EOL
testPass(`
function f() {
return (
@ -55,16 +52,8 @@ function f() {
);
}
`);
testPass(`
function f() {
return;
1 + 2;
}
`);
// starts expression
// TOK_INC
// unary expression
testWarn(`
function f() {
var i = 0;
@ -72,8 +61,6 @@ function f() {
++i;
}
`, 5, 4);
// TOK_DEC
testWarn(`
function f() {
var i = 0;
@ -82,7 +69,7 @@ function f() {
}
`, 5, 4);
// TOK_LB
// array
testWarn(`
function f() {
return
@ -90,7 +77,7 @@ function f() {
}
`, 4, 4);
// TOK_LC
// block (object)
testWarn(`
function f() {
return
@ -109,7 +96,7 @@ function f() {
}
`, 4, 2);
// TOK_LP
// expression in paren
testWarn(`
function f() {
return
@ -117,7 +104,7 @@ function f() {
}
`, 4, 4);
// TOK_NAME
// name
testWarn(`
function f() {
return
@ -125,7 +112,7 @@ function f() {
}
`, 4, 4);
// TOK_NUMBER
// binary expression
testWarn(`
function f() {
return
@ -139,7 +126,7 @@ function f() {
}
`, 4, 4);
// TOK_STRING
// string
testWarn(`
function f() {
return
@ -159,15 +146,13 @@ function f() {
}
`, 4, 4);
// TOK_TEMPLATE_HEAD
// template string
testWarn(`
function f() {
return
\`foo\${1 + 2}\`;
}
`, 4, 4);
// TOK_NO_SUBS_TEMPLATE
testWarn(`
function f() {
return
@ -175,7 +160,7 @@ function f() {
}
`, 4, 4);
// TOK_REGEXP
// RegExp
testWarn(`
function f() {
return
@ -183,15 +168,13 @@ function f() {
}
`, 4, 4);
// TOK_TRUE
// boolean
testWarn(`
function f() {
return
true;
}
`, 4, 4);
// TOK_FALSE
testWarn(`
function f() {
return
@ -199,7 +182,7 @@ function f() {
}
`, 4, 4);
// TOK_NULL
// null
testWarn(`
function f() {
return
@ -207,7 +190,7 @@ function f() {
}
`, 4, 4);
// TOK_THIS
// this
testWarn(`
function f() {
return
@ -215,7 +198,7 @@ function f() {
}
`, 4, 4);
// TOK_NEW
// new
testWarn(`
function f() {
return
@ -223,7 +206,7 @@ function f() {
}
`, 4, 4);
// TOK_DELETE
// delete
testWarn(`
function f() {
var a = {x: 10};
@ -232,7 +215,7 @@ function f() {
}
`, 5, 4);
// TOK_YIELD
// yield
testWarn(`
function* f() {
return
@ -240,7 +223,7 @@ function* f() {
}
`, 4, 4);
// TOK_CLASS
// class
if (classesEnabled()) {
testWarn(`
function f() {
@ -250,31 +233,25 @@ function f() {
`, 4, 4);
}
// TOK_ADD
// unary expression
testWarn(`
function f() {
return
+1;
}
`, 4, 4);
// TOK_SUB
testWarn(`
function f() {
return
-1;
}
`, 4, 4);
// TOK_NOT
testWarn(`
function f() {
return
!1;
}
`, 4, 4);
// TOK_BITNOT
testWarn(`
function f() {
return
@ -282,14 +259,12 @@ function f() {
}
`, 4, 4);
// don't start expression
// TOK_EOF
// eof
testPass(`
var f = new Function("return\\n");
`);
// TOK_SEMI
// empty statement
testPass(`
function f() {
return
@ -297,7 +272,7 @@ function f() {
}
`);
// TOK_RC
// end of block
testPass(`
function f() {
{
@ -306,7 +281,7 @@ function f() {
}
`);
// TOK_FUNCTION
// function (hosted)
testPass(`
function f() {
g();
@ -315,16 +290,16 @@ function f() {
}
`);
// TOK_IF
testPass(`
// if
testWarn(`
function f() {
return
if (true)
1 + 2;
}
`);
`, 4, 2);
// TOK_ELSE
// else
testPass(`
function f() {
if (true)
@ -334,8 +309,8 @@ function f() {
}
`);
// TOK_SWITCH
testPass(`
// switch
testWarn(`
function f() {
return
switch (1) {
@ -343,9 +318,32 @@ function f() {
break;
}
}
`, 4, 2);
// return in switch
testWarn(`
function f() {
switch (1) {
case 1:
return;
1 + 2;
break;
}
}
`, 6, 6);
// break in switch
testPass(`
function f() {
switch (1) {
case 1:
return;
break;
}
}
`);
// TOK_CASE
// case
testPass(`
function f() {
switch (1) {
@ -357,7 +355,7 @@ function f() {
}
`);
// TOK_DEFAULT
// default
testPass(`
function f() {
switch (1) {
@ -369,14 +367,14 @@ function f() {
}
`);
// TOK_WHILE
testPass(`
// while
testWarn(`
function f() {
return
while (false)
1 + 2;
}
`);
`, 4, 2);
testPass(`
function f() {
do
@ -385,27 +383,27 @@ function f() {
}
`);
// TOK_DO
testPass(`
// do
testWarn(`
function f() {
return
do {
1 + 2;
} while (false);
}
`);
`, 4, 2);
// TOK_FOR
testPass(`
// for
testWarn(`
function f() {
return
for (;;) {
break;
}
}
`);
`, 4, 2);
// TOK_BREAK
// break in for
testPass(`
function f() {
for (;;) {
@ -413,19 +411,19 @@ function f() {
break;
}
}
`);
`, 5, 4);
// TOK_CONTINUE
testPass(`
// continue
testWarn(`
function f() {
for (;;) {
return
continue;
}
}
`);
`, 5, 4);
// TOK_VAR
// var (hosted)
testPass(`
function f() {
return
@ -433,43 +431,43 @@ function f() {
}
`);
// TOK_CONST
testPass(`
// const
testWarn(`
function f() {
return
const a = 1;
}
`);
`, 4, 2);
// TOK_WITH
testPass(`
// with
testWarn(`
function f() {
return
with ({}) {
1;
}
}
`);
`, 4, 2);
// TOK_RETURN
testPass(`
// return
testWarn(`
function f() {
return
return;
}
`);
`, 4, 2);
// TOK_TRY
testPass(`
// try
testWarn(`
function f() {
return
try {
} catch (e) {
}
}
`);
`, 4, 2);
// TOK_THROW
// throw
testPass(`
function f() {
return
@ -477,29 +475,37 @@ function f() {
}
`);
// TOK_DEBUGGER
testPass(`
// debugger
testWarn(`
function f() {
return
debugger;
}
`);
`, 4, 2);
// TOK_LET
testPass(`
// let
testWarn(`
function f() {
return
let a = 1;
}
`);
`, 4, 2);
// exceptional case
// skip hoisted
// It's not possible to distinguish between a label statement and an expression
// starts with identifier, by checking a token next to return.
testWarn(`
function f() {
return
a: 1;
var a = 0;
(1 + 2);
}
`, 4, 2);
`, 5, 2);
testWarn(`
function f() {
return
function f() {}
var a = 0;
(1 + 2);
}
`, 6, 2);

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

@ -0,0 +1,21 @@
// Test that block scopes cannot be resurrected by onStep.
var g = newGlobal();
var dbg = new Debugger(g);
dbg.onDebuggerStatement = function(frame) {
frame.onStep = (function() {
frame.environment;
});
};
g.eval("debugger; for (let i = 0; i < 1; i++) (function(){});");
// If the last freshened block scope was incorrectly resurrected by onStep
// above, GCing will assert.
gc();
g.eval("debugger; { let i = 0; (function(){ i = 42; }); }");
gc();
g.eval("debugger; try { throw 42; } catch (e) { };");
gc();

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

@ -0,0 +1,14 @@
// |jit-test| error: Error
var g = newGlobal();
g.eval('function f(a) { evaluate("f(" + " - 1);", {newContext: true}); }');
var dbg = new Debugger(g);
var frames = [];
dbg.onEnterFrame = function (frame) {
if (frames.length == 3)
return;
frames.push(frame);
for (var f of frames)
f.eval('a').return
};
g.f();

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

@ -2,7 +2,7 @@ var g = newGlobal();
var dbg = new Debugger(g);
try {
g.eval("function f() { var array = ['a', 'b']; [1].map(function () {}); return {array}; }");
g.eval("function f() { [1].map(function () {}); const x = 42; x = 43; } f();");
} catch (e) {
// Ignore the syntax error.
}

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

@ -0,0 +1,7 @@
// |jit-test| error: ReferenceError
{
for (var i = 0; i < 100; i++)
a += i;
let a = 1;
}

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

@ -3010,14 +3010,24 @@ BaselineCompiler::emit_JSOP_PUSHBLOCKSCOPE()
typedef bool (*PopBlockScopeFn)(JSContext*, BaselineFrame*);
static const VMFunction PopBlockScopeInfo = FunctionInfo<PopBlockScopeFn>(jit::PopBlockScope);
typedef bool (*DebugLeaveThenPopBlockScopeFn)(JSContext*, BaselineFrame*, jsbytecode*);
static const VMFunction DebugLeaveThenPopBlockScopeInfo =
FunctionInfo<DebugLeaveThenPopBlockScopeFn>(jit::DebugLeaveThenPopBlockScope);
bool
BaselineCompiler::emit_JSOP_POPBLOCKSCOPE()
{
prepareVMCall();
masm.loadBaselineFramePtr(BaselineFrameReg, R0.scratchReg());
pushArg(R0.scratchReg());
if (compileDebugInstrumentation_) {
pushArg(ImmPtr(pc));
pushArg(R0.scratchReg());
return callVM(DebugLeaveThenPopBlockScopeInfo);
}
pushArg(R0.scratchReg());
return callVM(PopBlockScopeInfo);
}
@ -3025,7 +3035,7 @@ typedef bool (*FreshenBlockScopeFn)(JSContext*, BaselineFrame*);
static const VMFunction FreshenBlockScopeInfo =
FunctionInfo<FreshenBlockScopeFn>(jit::FreshenBlockScope);
typedef bool (*DebugLeaveThenFreshenBlockScopeFn)(JSContext*, BaselineFrame*, jsbytecode* pc);
typedef bool (*DebugLeaveThenFreshenBlockScopeFn)(JSContext*, BaselineFrame*, jsbytecode*);
static const VMFunction DebugLeaveThenFreshenBlockScopeInfo =
FunctionInfo<DebugLeaveThenFreshenBlockScopeFn>(jit::DebugLeaveThenFreshenBlockScope);

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

@ -4796,39 +4796,24 @@ CodeGenerator::visitCreateThisWithProto(LCreateThisWithProto* lir)
callVM(CreateThisWithProtoInfo, lir);
}
typedef JSObject* (*NewGCObjectFn)(JSContext* cx, gc::AllocKind allocKind,
gc::InitialHeap initialHeap, size_t ndynamic,
const js::Class* clasp);
static const VMFunction NewGCObjectInfo =
FunctionInfo<NewGCObjectFn>(js::jit::NewGCObject);
void
CodeGenerator::visitCreateThisWithTemplate(LCreateThisWithTemplate* lir)
{
JSObject* templateObject = lir->mir()->templateObject();
gc::AllocKind allocKind = templateObject->asTenured().getAllocKind();
gc::InitialHeap initialHeap = lir->mir()->initialHeap();
const js::Class* clasp = templateObject->getClass();
size_t ndynamic = 0;
if (templateObject->isNative())
ndynamic = templateObject->as<NativeObject>().numDynamicSlots();
Register objReg = ToRegister(lir->output());
Register tempReg = ToRegister(lir->temp());
OutOfLineCode* ool = oolCallVM(NewGCObjectInfo, lir,
(ArgList(), Imm32(int32_t(allocKind)), Imm32(initialHeap),
Imm32(ndynamic), ImmPtr(clasp)),
OutOfLineCode* ool = oolCallVM(NewInitObjectWithTemplateInfo, lir,
(ArgList(), ImmGCPtr(templateObject)),
StoreRegisterTo(objReg));
// Allocate. If the FreeList is empty, call to VM, which may GC.
masm.newGCThing(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry());
// Initialize based on the templateObject.
masm.bind(ool->rejoin());
bool initContents = !templateObject->is<PlainObject>() ||
ShouldInitFixedSlots(lir, &templateObject->as<PlainObject>());
masm.initGCThing(objReg, tempReg, templateObject, initContents);
masm.createGCObject(objReg, tempReg, templateObject, lir->mir()->initialHeap(), ool->entry(),
initContents);
masm.bind(ool->rejoin());
}
typedef JSObject* (*NewIonArgumentsObjectFn)(JSContext* cx, JitFrameLayout* frame, HandleObject);

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

@ -12908,6 +12908,9 @@ IonBuilder::addLexicalCheck(MDefinition* input)
// If we're guaranteed to not be JS_UNINITIALIZED_LEXICAL, no need to check.
if (input->type() == MIRType_MagicUninitializedLexical) {
// Mark the input as implicitly used so the JS_UNINITIALIZED_LEXICAL
// magic value will be preserved on bailout.
input->setImplicitlyUsedUnchecked();
lexicalCheck = MThrowUninitializedLexical::New(alloc());
current->add(lexicalCheck);
if (!resumeAfter(lexicalCheck))

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

@ -1183,19 +1183,6 @@ MacroAssembler::allocateObject(Register result, Register temp, gc::AllocKind all
bind(&success);
}
void
MacroAssembler::newGCThing(Register result, Register temp, JSObject* templateObj,
gc::InitialHeap initialHeap, Label* fail)
{
gc::AllocKind allocKind = templateObj->asTenured().getAllocKind();
MOZ_ASSERT(gc::IsObjectAllocKind(allocKind));
size_t ndynamic = 0;
if (templateObj->isNative())
ndynamic = templateObj->as<NativeObject>().numDynamicSlots();
allocateObject(result, temp, allocKind, ndynamic, initialHeap, fail);
}
void
MacroAssembler::createGCObject(Register obj, Register temp, JSObject* templateObj,
gc::InitialHeap initialHeap, Label* fail, bool initContents,

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

@ -802,8 +802,6 @@ class MacroAssembler : public MacroAssemblerSpecific
gc::InitialHeap initialHeap, Label* fail, bool initContents = true,
bool convertDoubleElements = false);
void newGCThing(Register result, Register temp, JSObject* templateObj,
gc::InitialHeap initialHeap, Label* fail);
void initGCThing(Register obj, Register temp, JSObject* templateObj,
bool initContents = true, bool convertDoubleElements = false);

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

@ -86,18 +86,6 @@ InvokeFunction(JSContext* cx, HandleObject obj, uint32_t argc, Value* argv, Valu
return true;
}
JSObject*
NewGCObject(JSContext* cx, gc::AllocKind allocKind, gc::InitialHeap initialHeap,
size_t ndynamic, const js::Class* clasp)
{
JSObject* obj = js::Allocate<JSObject>(cx, allocKind, ndynamic, initialHeap, clasp);
if (!obj)
return nullptr;
SetNewObjectMetadata(cx, obj);
return obj;
}
bool
CheckOverRecursed(JSContext* cx)
{
@ -996,6 +984,14 @@ PopBlockScope(JSContext* cx, BaselineFrame* frame)
return true;
}
bool
DebugLeaveThenPopBlockScope(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
{
MOZ_ALWAYS_TRUE(DebugLeaveBlock(cx, frame, pc));
frame->popBlock(cx);
return true;
}
bool
FreshenBlockScope(JSContext* cx, BaselineFrame* frame)
{
@ -1005,7 +1001,7 @@ FreshenBlockScope(JSContext* cx, BaselineFrame* frame)
bool
DebugLeaveThenFreshenBlockScope(JSContext* cx, BaselineFrame* frame, jsbytecode* pc)
{
DebugLeaveBlock(cx, frame, pc);
MOZ_ALWAYS_TRUE(DebugLeaveBlock(cx, frame, pc));
return frame->freshenBlock(cx);
}

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

@ -632,8 +632,6 @@ class AutoDetectInvalidation
};
bool InvokeFunction(JSContext* cx, HandleObject obj0, uint32_t argc, Value* argv, Value* rval);
JSObject* NewGCObject(JSContext* cx, gc::AllocKind allocKind, gc::InitialHeap initialHeap,
size_t ndynamic, const js::Class* clasp);
bool CheckOverRecursed(JSContext* cx);
bool CheckOverRecursedWithExtra(JSContext* cx, BaselineFrame* frame,
@ -728,6 +726,7 @@ bool LeaveWith(JSContext* cx, BaselineFrame* frame);
bool PushBlockScope(JSContext* cx, BaselineFrame* frame, Handle<StaticBlockObject*> block);
bool PopBlockScope(JSContext* cx, BaselineFrame* frame);
bool DebugLeaveThenPopBlockScope(JSContext* cx, BaselineFrame* frame, jsbytecode* pc);
bool FreshenBlockScope(JSContext* cx, BaselineFrame* frame);
bool DebugLeaveThenFreshenBlockScope(JSContext* cx, BaselineFrame* frame, jsbytecode* pc);
bool DebugLeaveBlock(JSContext* cx, BaselineFrame* frame, jsbytecode* pc);

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

@ -304,12 +304,12 @@ MSG_DEF(JSMSG_SEMI_AFTER_FOR_COND, 0, JSEXN_SYNTAXERR, "missing ; after for-
MSG_DEF(JSMSG_SEMI_AFTER_FOR_INIT, 0, JSEXN_SYNTAXERR, "missing ; after for-loop initializer")
MSG_DEF(JSMSG_SEMI_BEFORE_STMNT, 0, JSEXN_SYNTAXERR, "missing ; before statement")
MSG_DEF(JSMSG_SOURCE_TOO_LONG, 0, JSEXN_RANGEERR, "source is too long")
MSG_DEF(JSMSG_STMT_AFTER_SEMI_LESS, 0, JSEXN_SYNTAXERR, "unreachable expression after semicolon-less return statement")
MSG_DEF(JSMSG_STMT_AFTER_RETURN, 0, JSEXN_SYNTAXERR, "unreachable code after return statement")
MSG_DEF(JSMSG_STRICT_CODE_LET_EXPR_STMT, 0, JSEXN_ERR, "strict mode code may not contain unparenthesized let expression statements")
MSG_DEF(JSMSG_STRICT_CODE_WITH, 0, JSEXN_SYNTAXERR, "strict mode code may not contain 'with' statements")
MSG_DEF(JSMSG_STRICT_FUNCTION_STATEMENT, 0, JSEXN_SYNTAXERR, "in strict mode code, functions may be declared only at top level or immediately within another function")
MSG_DEF(JSMSG_TEMPLSTR_UNTERM_EXPR, 0, JSEXN_SYNTAXERR, "missing } in template string")
MSG_DEF(JSMSG_SIMD_NOT_A_VECTOR, 0, JSEXN_TYPEERR, "value isn't a SIMD value object")
MSG_DEF(JSMSG_SIMD_NOT_A_VECTOR, 2, JSEXN_TYPEERR, "expecting a SIMD {0} object as argument {1}")
MSG_DEF(JSMSG_TOO_MANY_CASES, 0, JSEXN_INTERNALERR, "too many switch cases")
MSG_DEF(JSMSG_TOO_MANY_CATCH_VARS, 0, JSEXN_SYNTAXERR, "too many catch variables")
MSG_DEF(JSMSG_TOO_MANY_CON_ARGS, 0, JSEXN_SYNTAXERR, "too many constructor arguments")

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

@ -758,7 +758,17 @@ CreateLazyScriptsForCompartment(JSContext* cx)
// clones. See bug 1105306.
for (gc::ZoneCellIter i(cx->zone(), JSFunction::FinalizeKind); !i.done(); i.next()) {
JSObject* obj = i.get<JSObject>();
if (obj->compartment() == cx->compartment() && obj->is<JSFunction>()) {
// Sweeping is incremental; take care to not delazify functions that
// are about to be finalized. GC things referenced by objects that are
// about to be finalized (e.g., in slots) may already be freed.
if (gc::IsAboutToBeFinalizedUnbarriered(&obj) ||
obj->compartment() != cx->compartment() ||
!obj->is<JSFunction>())
{
continue;
}
JSFunction* fun = &obj->as<JSFunction>();
if (fun->isInterpretedLazy()) {
LazyScript* lazy = fun->lazyScriptOrNull();
@ -770,7 +780,6 @@ CreateLazyScriptsForCompartment(JSContext* cx)
}
}
}
}
// Create scripts for each lazy function, updating the list of functions to
// process with any newly exposed inner functions in created scripts.

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

@ -342,9 +342,16 @@ class JSFunction : public js::NativeObject
return nonLazyScript();
}
JSScript* nonLazyScript() const {
// The state of a JSFunction whose script errored out during bytecode
// compilation. Such JSFunctions are only reachable via GC iteration and
// not from script.
bool hasUncompiledScript() const {
MOZ_ASSERT(hasScript());
MOZ_ASSERT(u.i.s.script_);
return !u.i.s.script_;
}
JSScript* nonLazyScript() const {
MOZ_ASSERT(!hasUncompiledScript());
return u.i.s.script_;
}

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

@ -3911,7 +3911,7 @@ LazyScript::hasUncompiledEnclosingScript() const
return false;
JSFunction& fun = enclosingScope()->as<JSFunction>();
return fun.isInterpreted() && (!fun.hasScript() || !fun.nonLazyScript()->code());
return !fun.hasScript() || fun.hasUncompiledScript() || !fun.nonLazyScript()->code();
}
uint32_t

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

@ -1,4 +1,4 @@
// |reftest| skip-if(xulRuntime.OS=="Darwin"&&isDebugBuild) -- this takes too long to over-recurse.
// |reftest| skip-if((xulRuntime.OS=="Darwin"||Android)&&isDebugBuild) -- this takes too long to over-recurse.
/*
* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/licenses/publicdomain/

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

@ -5685,7 +5685,8 @@ CheckThisFrame(JSContext* cx, const CallArgs& args, const char* fnname, bool che
maybeIter.emplace(*(ScriptFrameIter::Data*)(f.raw())); \
} else { \
maybeIter.emplace(cx, ScriptFrameIter::ALL_CONTEXTS, \
ScriptFrameIter::GO_THROUGH_SAVED); \
ScriptFrameIter::GO_THROUGH_SAVED, \
ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK); \
ScriptFrameIter& iter = *maybeIter; \
while (!iter.hasUsableAbstractFramePtr() || iter.abstractFramePtr() != f) \
++iter; \

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

@ -3780,13 +3780,15 @@ CASE(JSOP_POPBLOCKSCOPE)
{
#ifdef DEBUG
// Pop block from scope chain.
MOZ_ASSERT(*(REGS.pc - JSOP_DEBUGLEAVEBLOCK_LENGTH) == JSOP_DEBUGLEAVEBLOCK);
NestedScopeObject* scope = script->getStaticBlockScope(REGS.pc - JSOP_DEBUGLEAVEBLOCK_LENGTH);
NestedScopeObject* scope = script->getStaticBlockScope(REGS.pc);
MOZ_ASSERT(scope && scope->is<StaticBlockObject>());
StaticBlockObject& blockObj = scope->as<StaticBlockObject>();
MOZ_ASSERT(blockObj.needsClone());
#endif
if (MOZ_UNLIKELY(cx->compartment()->isDebuggee()))
DebugScopes::onPopBlock(cx, REGS.fp(), REGS.pc);
// Pop block from scope chain.
REGS.fp()->popBlock(cx);
}
@ -3796,6 +3798,7 @@ CASE(JSOP_DEBUGLEAVEBLOCK)
{
MOZ_ASSERT(script->getStaticBlockScope(REGS.pc));
MOZ_ASSERT(script->getStaticBlockScope(REGS.pc)->is<StaticBlockObject>());
MOZ_ASSERT(!script->getStaticBlockScope(REGS.pc)->as<StaticBlockObject>().needsClone());
// FIXME: This opcode should not be necessary. The debugger shouldn't need
// help from bytecode to do its job. See bug 927782.

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

@ -590,10 +590,12 @@ FrameIter::settleOnActivation()
}
FrameIter::Data::Data(JSContext* cx, SavedOption savedOption,
ContextOption contextOption, JSPrincipals* principals)
ContextOption contextOption, DebuggerEvalOption debuggerEvalOption,
JSPrincipals* principals)
: cx_(cx),
savedOption_(savedOption),
contextOption_(contextOption),
debuggerEvalOption_(debuggerEvalOption),
principals_(principals),
pc_(nullptr),
interpFrames_(nullptr),
@ -608,6 +610,7 @@ FrameIter::Data::Data(const FrameIter::Data& other)
: cx_(other.cx_),
savedOption_(other.savedOption_),
contextOption_(other.contextOption_),
debuggerEvalOption_(other.debuggerEvalOption_),
principals_(other.principals_),
state_(other.state_),
pc_(other.pc_),
@ -620,7 +623,7 @@ FrameIter::Data::Data(const FrameIter::Data& other)
}
FrameIter::FrameIter(JSContext* cx, SavedOption savedOption)
: data_(cx, savedOption, CURRENT_CONTEXT, nullptr),
: data_(cx, savedOption, CURRENT_CONTEXT, FOLLOW_DEBUGGER_EVAL_PREV_LINK, nullptr),
ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
{
// settleOnActivation can only GC if principals are given.
@ -629,8 +632,8 @@ FrameIter::FrameIter(JSContext* cx, SavedOption savedOption)
}
FrameIter::FrameIter(JSContext* cx, ContextOption contextOption,
SavedOption savedOption)
: data_(cx, savedOption, contextOption, nullptr),
SavedOption savedOption, DebuggerEvalOption debuggerEvalOption)
: data_(cx, savedOption, contextOption, debuggerEvalOption, nullptr),
ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
{
// settleOnActivation can only GC if principals are given.
@ -639,8 +642,9 @@ FrameIter::FrameIter(JSContext* cx, ContextOption contextOption,
}
FrameIter::FrameIter(JSContext* cx, ContextOption contextOption,
SavedOption savedOption, JSPrincipals* principals)
: data_(cx, savedOption, contextOption, principals),
SavedOption savedOption, DebuggerEvalOption debuggerEvalOption,
JSPrincipals* principals)
: data_(cx, savedOption, contextOption, debuggerEvalOption, principals),
ionInlineFrames_(cx, (js::jit::JitFrameIterator*) nullptr)
{
settleOnActivation();
@ -717,7 +721,10 @@ FrameIter::operator++()
case DONE:
MOZ_CRASH("Unexpected state");
case INTERP:
if (interpFrame()->isDebuggerEvalFrame() && interpFrame()->evalInFramePrev()) {
if (interpFrame()->isDebuggerEvalFrame() &&
interpFrame()->evalInFramePrev() &&
data_.debuggerEvalOption_ == FOLLOW_DEBUGGER_EVAL_PREV_LINK)
{
AbstractFramePtr eifPrev = interpFrame()->evalInFramePrev();
// Eval-in-frame can cross contexts and works across saved frame

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

@ -1586,6 +1586,8 @@ class FrameIter
public:
enum SavedOption { STOP_AT_SAVED, GO_THROUGH_SAVED };
enum ContextOption { CURRENT_CONTEXT, ALL_CONTEXTS };
enum DebuggerEvalOption { FOLLOW_DEBUGGER_EVAL_PREV_LINK,
IGNORE_DEBUGGER_EVAL_PREV_LINK };
enum State { DONE, INTERP, JIT, ASMJS };
// Unlike ScriptFrameIter itself, ScriptFrameIter::Data can be allocated on
@ -1595,6 +1597,7 @@ class FrameIter
JSContext * cx_;
SavedOption savedOption_;
ContextOption contextOption_;
DebuggerEvalOption debuggerEvalOption_;
JSPrincipals * principals_;
State state_;
@ -1609,13 +1612,14 @@ class FrameIter
AsmJSFrameIterator asmJSFrames_;
Data(JSContext* cx, SavedOption savedOption, ContextOption contextOption,
JSPrincipals* principals);
DebuggerEvalOption debuggerEvalOption, JSPrincipals* principals);
Data(const Data& other);
};
MOZ_IMPLICIT FrameIter(JSContext* cx, SavedOption = STOP_AT_SAVED);
FrameIter(JSContext* cx, ContextOption, SavedOption);
FrameIter(JSContext* cx, ContextOption, SavedOption, JSPrincipals*);
FrameIter(JSContext* cx, ContextOption, SavedOption,
DebuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK);
FrameIter(JSContext* cx, ContextOption, SavedOption, DebuggerEvalOption, JSPrincipals*);
FrameIter(const FrameIter& iter);
MOZ_IMPLICIT FrameIter(const Data& data);
MOZ_IMPLICIT FrameIter(AbstractFramePtr frame);
@ -1756,8 +1760,9 @@ class ScriptFrameIter : public FrameIter
ScriptFrameIter(JSContext* cx,
ContextOption cxOption,
SavedOption savedOption)
: FrameIter(cx, cxOption, savedOption)
SavedOption savedOption,
DebuggerEvalOption debuggerEvalOption = FOLLOW_DEBUGGER_EVAL_PREV_LINK)
: FrameIter(cx, cxOption, savedOption, debuggerEvalOption)
{
settle();
}
@ -1765,8 +1770,9 @@ class ScriptFrameIter : public FrameIter
ScriptFrameIter(JSContext* cx,
ContextOption cxOption,
SavedOption savedOption,
DebuggerEvalOption debuggerEvalOption,
JSPrincipals* prin)
: FrameIter(cx, cxOption, savedOption, prin)
: FrameIter(cx, cxOption, savedOption, debuggerEvalOption, prin)
{
settle();
}
@ -1807,8 +1813,10 @@ class NonBuiltinFrameIter : public FrameIter
NonBuiltinFrameIter(JSContext* cx,
FrameIter::ContextOption contextOption,
FrameIter::SavedOption savedOption)
: FrameIter(cx, contextOption, savedOption)
FrameIter::SavedOption savedOption,
FrameIter::DebuggerEvalOption debuggerEvalOption =
FrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK)
: FrameIter(cx, contextOption, savedOption, debuggerEvalOption)
{
settle();
}
@ -1816,8 +1824,9 @@ class NonBuiltinFrameIter : public FrameIter
NonBuiltinFrameIter(JSContext* cx,
FrameIter::ContextOption contextOption,
FrameIter::SavedOption savedOption,
FrameIter::DebuggerEvalOption debuggerEvalOption,
JSPrincipals* principals)
: FrameIter(cx, contextOption, savedOption, principals)
: FrameIter(cx, contextOption, savedOption, debuggerEvalOption, principals)
{
settle();
}
@ -1849,8 +1858,10 @@ class NonBuiltinScriptFrameIter : public ScriptFrameIter
NonBuiltinScriptFrameIter(JSContext* cx,
ScriptFrameIter::ContextOption contextOption,
ScriptFrameIter::SavedOption savedOption)
: ScriptFrameIter(cx, contextOption, savedOption)
ScriptFrameIter::SavedOption savedOption,
ScriptFrameIter::DebuggerEvalOption debuggerEvalOption =
ScriptFrameIter::FOLLOW_DEBUGGER_EVAL_PREV_LINK)
: ScriptFrameIter(cx, contextOption, savedOption, debuggerEvalOption)
{
settle();
}
@ -1858,8 +1869,9 @@ class NonBuiltinScriptFrameIter : public ScriptFrameIter
NonBuiltinScriptFrameIter(JSContext* cx,
ScriptFrameIter::ContextOption contextOption,
ScriptFrameIter::SavedOption savedOption,
ScriptFrameIter::DebuggerEvalOption debuggerEvalOption,
JSPrincipals* principals)
: ScriptFrameIter(cx, contextOption, savedOption, principals)
: ScriptFrameIter(cx, contextOption, savedOption, debuggerEvalOption, principals)
{
settle();
}
@ -1883,7 +1895,8 @@ class AllFramesIter : public ScriptFrameIter
{
public:
explicit AllFramesIter(JSContext* cx)
: ScriptFrameIter(cx, ScriptFrameIter::ALL_CONTEXTS, ScriptFrameIter::GO_THROUGH_SAVED)
: ScriptFrameIter(cx, ScriptFrameIter::ALL_CONTEXTS, ScriptFrameIter::GO_THROUGH_SAVED,
ScriptFrameIter::IGNORE_DEBUGGER_EVAL_PREV_LINK)
{}
};

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

@ -11,7 +11,7 @@
#include "nsISupports.idl"
#include "nsIConsoleMessage.idl"
[scriptable, uuid(d6a8dae2-367f-4939-a843-11e0c48e240c)]
[scriptable, uuid(248b2c94-2736-4d29-bfdf-bc64a2e60d35)]
interface nsIScriptError : nsIConsoleMessage
{
/** pseudo-flag for default case */
@ -27,6 +27,9 @@ interface nsIScriptError : nsIConsoleMessage
/** error or warning is due to strict option */
const unsigned long strictFlag = 0x4;
/** just a log message */
const unsigned long infoFlag = 0x8;
/**
* The error message without any context/line number information.
*

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

@ -89,8 +89,13 @@ nsScriptError::GetMessageMoz(char16_t** result) {
NS_IMETHODIMP
nsScriptError::GetLogLevel(uint32_t* aLogLevel)
{
*aLogLevel = mFlags & (uint32_t)nsIScriptError::errorFlag ?
nsIConsoleMessage::error : nsIConsoleMessage::warn;
if (mFlags & (uint32_t)nsIScriptError::infoFlag) {
*aLogLevel = nsIConsoleMessage::info;
} else if (mFlags & (uint32_t)nsIScriptError::warningFlag) {
*aLogLevel = nsIConsoleMessage::warn;
} else {
*aLogLevel = nsIConsoleMessage::error;
}
return NS_OK;
}

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

@ -6,28 +6,14 @@ add_task(function* () {
SpecialPowers.pushPrefEnv({"set": [["ui.tooltipDelay", 0]]}, resolve);
});
var popup = false;
var doc;
var win;
var p1;
let onPopupShown = function(aEvent) {
popup = true;
}
document.addEventListener("popupshown", onPopupShown, true);
// Send a mousemove at a known position to start the test.
BrowserTestUtils.synthesizeMouseAtCenter("#p1", { type: "mousemove" },
yield BrowserTestUtils.synthesizeMouseAtCenter("#p1", { type: "mousemove" },
gBrowser.selectedBrowser);
BrowserTestUtils.synthesizeMouseAtCenter("#p1", { }, gBrowser.selectedBrowser);
yield BrowserTestUtils.synthesizeMouseAtCenter("#p1", { }, gBrowser.selectedBrowser);
yield new Promise(resolve => {
setTimeout(function() {
is(popup, false, "shouldn't get tooltip after click");
resolve();
}, 200);
});
// Wait until the tooltip timeout triggers that would normally have opened the popup.
yield new Promise(resolve => setTimeout(resolve, 0));
is(document.getElementById("aHTMLTooltip").state, "closed", "local tooltip is closed");
is(document.getElementById("remoteBrowserTooltip").state, "closed", "remote tooltip is closed");
document.removeEventListener("popupshown", onPopupShown, true);
gBrowser.removeCurrentTab();
});

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

@ -918,13 +918,30 @@ public class BrowserApp extends GeckoApp
@Override
public void run() {
if (TabQueueHelper.shouldOpenTabQueueUrls(BrowserApp.this)) {
TabQueueHelper.openQueuedUrls(BrowserApp.this, mProfile, TabQueueHelper.FILE_NAME, false);
openQueuedTabs();
}
}
});
}
}
private void openQueuedTabs() {
ThreadUtils.assertNotOnUiThread();
int queuedTabCount = TabQueueHelper.getTabQueueLength(BrowserApp.this);
TabQueueHelper.openQueuedUrls(BrowserApp.this, mProfile, TabQueueHelper.FILE_NAME, false);
// If there's more than one tab then also show the tabs panel.
if (queuedTabCount > 1) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
showNormalTabs();
}
});
}
}
@Override
public void onResume() {
super.onResume();
@ -3423,18 +3440,7 @@ public class BrowserApp extends GeckoApp
ThreadUtils.postToBackgroundThread(new Runnable() {
@Override
public void run() {
int queuedTabCount = TabQueueHelper.getTabQueueLength(BrowserApp.this);
TabQueueHelper.openQueuedUrls(BrowserApp.this, mProfile, TabQueueHelper.FILE_NAME, false);
// If there's more than one tab then also show the tabs panel.
if (queuedTabCount > 1) {
ThreadUtils.postToUiThread(new Runnable() {
@Override
public void run() {
showNormalTabs();
}
});
}
openQueuedTabs();
}
});
}

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

@ -127,6 +127,34 @@ ALL_TESTS_JSON = b'''
"relpath": "src/TestDistribution.java",
"subsuite": "browser"
}
],
"image/test/browser/browser_bug666317.js": [
{
"dir_relpath": "image/test/browser",
"file_relpath": "image/test/browser/browser_bug666317.js",
"flavor": "browser-chrome",
"here": "/home/chris/m-c/obj-dbg/_tests/testing/mochitest/browser/image/test/browser",
"manifest": "/home/chris/m-c/image/test/browser/browser.ini",
"name": "browser_bug666317.js",
"path": "/home/chris/m-c/obj-dbg/_tests/testing/mochitest/browser/image/test/browser/browser_bug666317.js",
"relpath": "image/test/browser/browser_bug666317.js",
"skip-if": "e10s # Bug 948194 - Decoded Images seem to not be discarded on memory-pressure notification with e10s enabled",
"subsuite": ""
}
],
"browser/devtools/markupview/test/browser_markupview_copy_image_data.js": [
{
"dir_relpath": "browser/devtools/markupview/test",
"file_relpath": "browser/devtools/markupview/test/browser_markupview_copy_image_data.js",
"flavor": "browser-chrome",
"here": "/home/chris/m-c/obj-dbg/_tests/testing/mochitest/browser/browser/devtools/markupview/test",
"manifest": "/home/chris/m-c/browser/devtools/markupview/test/browser.ini",
"name": "browser_markupview_copy_image_data.js",
"path": "/home/chris/m-c/obj-dbg/_tests/testing/mochitest/browser/browser/devtools/markupview/test/browser_markupview_copy_image_data.js",
"relpath": "browser/devtools/markupview/test/browser_markupview_copy_image_data.js",
"subsuite": "devtools",
"tags": "devtools"
}
]
}'''.strip()
@ -153,14 +181,14 @@ class Base(unittest.TestCase):
class TestTestMetadata(Base):
def test_load(self):
t = self._get_test_metadata()
self.assertEqual(len(t._tests_by_path), 6)
self.assertEqual(len(t._tests_by_path), 8)
self.assertEqual(len(list(t.tests_with_flavor('xpcshell'))), 3)
self.assertEqual(len(list(t.tests_with_flavor('mochitest-plain'))), 0)
def test_resolve_all(self):
t = self._get_test_metadata()
self.assertEqual(len(list(t.resolve_tests())), 7)
self.assertEqual(len(list(t.resolve_tests())), 9)
def test_resolve_filter_flavor(self):
t = self._get_test_metadata()
@ -182,6 +210,11 @@ class TestTestMetadata(Base):
result = list(t.resolve_tests(paths=['services', 'toolkit']))
self.assertEqual(len(result), 4)
def test_resolve_path_prefix(self):
t = self._get_test_metadata()
result = list(t.resolve_tests(paths=['image']))
self.assertEqual(len(result), 1)
class TestTestResolver(Base):
FAKE_TOPSRCDIR = '/Users/gps/src/firefox'

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

@ -80,8 +80,9 @@ class TestMetadata(object):
``paths`` can be an iterable of values to use to identify tests to run.
If an entry is a known test file, tests associated with that file are
returned (there may be multiple configurations for a single file). If
an entry is a directory, all tests in that directory are returned. If
the string appears in a known test file, that test file is considered.
an entry is a directory, or a prefix of a directory containing tests,
all tests in that directory are returned. If the string appears in a
known test file, that test file is considered.
If ``under_path`` is a string, it will be used to filter out tests that
aren't in the specified path prefix relative to topsrcdir or the
@ -123,8 +124,10 @@ class TestMetadata(object):
candidate_paths |= set(self._tests_by_path.keys())
continue
# If the path is a directory, pull in all tests in that directory.
if path in self._test_dirs:
# If the path is a directory, or the path is a prefix of a directory
# containing tests, pull in all tests in that directory.
if (path in self._test_dirs or
any(p.startswith(path) for p in self._tests_by_path)):
candidate_paths |= {p for p in self._tests_by_path
if p.startswith(path)}
continue

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

@ -1302,6 +1302,14 @@ function do_send_remote_message(name) {
/**
* Add a test function to the list of tests that are to be run asynchronously.
*
* @param funcOrProperties
* A function to be run or an object represents test properties.
* Supported properties:
* skip_if : An arrow function which has an expression to be
* evaluated whether the test is skipped or not.
* @param func
* A function to be run only if the funcOrProperies is not a function.
*
* Each test function must call run_next_test() when it's done. Test files
* should call run_next_test() in their run_test function to execute all
* async tests.
@ -1309,14 +1317,31 @@ function do_send_remote_message(name) {
* @return the test function that was passed in.
*/
let _gTests = [];
function add_test(func) {
_gTests.push([false, func]);
function add_test(funcOrProperties, func) {
if (typeof funcOrProperties == "function") {
_gTests.push([{ _isTask: false }, funcOrProperties]);
} else if (typeof funcOrProperties == "object") {
funcOrProperties._isTask = false;
_gTests.push([funcOrProperties, func]);
} else {
do_throw("add_test() should take a function or an object and a function");
}
return func;
}
/**
* Add a test function which is a Task function.
*
* @param funcOrProperties
* A generator function to be run or an object represents test
* properties.
* Supported properties:
* skip_if : An arrow function which has an expression to be
* evaluated whether the test is skipped or not.
* @param func
* A generator function to be run only if the funcOrProperies is not a
* function.
*
* Task functions are functions fed into Task.jsm's Task.spawn(). They are
* generators that emit promises.
*
@ -1331,7 +1356,7 @@ function add_test(func) {
*
* Example usage:
*
* add_task(function test() {
* add_task(function* test() {
* let result = yield Promise.resolve(true);
*
* do_check_true(result);
@ -1340,7 +1365,7 @@ function add_test(func) {
* do_check_eq(secondary, "expected value");
* });
*
* add_task(function test_early_return() {
* add_task(function* test_early_return() {
* let result = yield somethingThatReturnsAPromise();
*
* if (!result) {
@ -1350,9 +1375,24 @@ function add_test(func) {
*
* do_check_eq(result, "foo");
* });
*
* add_task({
* skip_if: () => !("@mozilla.org/telephony/volume-service;1" in Components.classes),
* }, function* test_volume_service() {
* let volumeService = Cc["@mozilla.org/telephony/volume-service;1"]
* .getService(Ci.nsIVolumeService);
* ...
* });
*/
function add_task(func) {
_gTests.push([true, func]);
function add_task(funcOrProperties, func) {
if (typeof funcOrProperties == "function") {
_gTests.push([{ _isTask: true }, funcOrProperties]);
} else if (typeof funcOrProperties == "object") {
funcOrProperties._isTask = true;
_gTests.push([funcOrProperties, func]);
} else {
do_throw("add_task() should take a function or an object and a function");
}
}
let _Task = Components.utils.import("resource://gre/modules/Task.jsm", {}).Task;
_Task.Debugging.maintainStack = true;
@ -1377,12 +1417,25 @@ function run_next_test()
if (_gTestIndex < _gTests.length) {
// Flush uncaught errors as early and often as possible.
_Promise.Debugging.flushUncaughtErrors();
let _isTask;
[_isTask, _gRunningTest] = _gTests[_gTestIndex++];
let _properties;
[_properties, _gRunningTest,] = _gTests[_gTestIndex++];
if (typeof(_properties.skip_if) == "function" && _properties.skip_if()) {
let _condition = _properties.skip_if.toSource().replace(/\(\)\s*=>\s*/, "");
let _message = _gRunningTest.name
+ " skipped because the following conditions were"
+ " met: (" + _condition + ")";
_testLogger.testStatus(_TEST_NAME,
_gRunningTest.name,
"SKIP",
"SKIP",
_message);
do_execute_soon(run_next_test);
return;
}
_testLogger.info(_TEST_NAME + " | Starting " + _gRunningTest.name);
do_test_pending(_gRunningTest.name);
if (_isTask) {
if (_properties._isTask) {
_gTaskRunning = true;
_Task.spawn(_gRunningTest).then(
() => { _gTaskRunning = false; run_next_test(); },

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