зеркало из https://github.com/mozilla/gecko-dev.git
Merge m-c to b2g-inbound. a=merge
This commit is contained in:
Коммит
659b2a4f94
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -17,39 +17,47 @@ loop.OTSdkDriver = (function() {
|
|||
* actions, and instruct the SDK what to do as a result of actions.
|
||||
*/
|
||||
var OTSdkDriver = function(options) {
|
||||
if (!options.dispatcher) {
|
||||
throw new Error("Missing option dispatcher");
|
||||
}
|
||||
if (!options.sdk) {
|
||||
throw new Error("Missing option sdk");
|
||||
if (!options.dispatcher) {
|
||||
throw new Error("Missing option dispatcher");
|
||||
}
|
||||
if (!options.sdk) {
|
||||
throw new Error("Missing option sdk");
|
||||
}
|
||||
|
||||
this.dispatcher = options.dispatcher;
|
||||
this.sdk = options.sdk;
|
||||
|
||||
this._isDesktop = !!options.isDesktop;
|
||||
|
||||
if (this._isDesktop) {
|
||||
if (!options.mozLoop) {
|
||||
throw new Error("Missing option mozLoop");
|
||||
}
|
||||
this.mozLoop = options.mozLoop;
|
||||
}
|
||||
|
||||
this.dispatcher = options.dispatcher;
|
||||
this.sdk = options.sdk;
|
||||
this.connections = {};
|
||||
|
||||
this._isDesktop = !!options.isDesktop;
|
||||
// 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
|
||||
};
|
||||
|
||||
if (this._isDesktop) {
|
||||
if (!options.mozLoop) {
|
||||
throw new Error("Missing option mozLoop");
|
||||
}
|
||||
this.mozLoop = options.mozLoop;
|
||||
}
|
||||
this.dispatcher.register(this, [
|
||||
"setupStreamElements",
|
||||
"setMute"
|
||||
]);
|
||||
|
||||
this.connections = {};
|
||||
|
||||
this.dispatcher.register(this, [
|
||||
"setupStreamElements",
|
||||
"setMute"
|
||||
]);
|
||||
|
||||
// Set loop.debug.twoWayMediaTelemetry to true in the browser
|
||||
// by changing the hidden pref loop.debug.twoWayMediaTelemetry using
|
||||
// about:config, or use
|
||||
//
|
||||
// localStorage.setItem("debug.twoWayMediaTelemetry", true);
|
||||
this._debugTwoWayMediaTelemetry =
|
||||
loop.shared.utils.getBoolPreference("debug.twoWayMediaTelemetry");
|
||||
// Set loop.debug.twoWayMediaTelemetry to true in the browser
|
||||
// by changing the hidden pref loop.debug.twoWayMediaTelemetry using
|
||||
// about:config, or use
|
||||
//
|
||||
// localStorage.setItem("debug.twoWayMediaTelemetry", true);
|
||||
this._debugTwoWayMediaTelemetry =
|
||||
loop.shared.utils.getBoolPreference("debug.twoWayMediaTelemetry");
|
||||
|
||||
/**
|
||||
* XXX This is a workaround for desktop machines that do not have a
|
||||
|
@ -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);
|
||||
it("should not store the connection details for a local user", function() {
|
||||
expect(driver.connections).to.not.include.keys("localUser");
|
||||
});
|
||||
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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
bool
|
||||
MemoryReportRequestParent::Recv__delete__(const uint32_t& generation,
|
||||
nsTArray<MemoryReport>&& childReports)
|
||||
{
|
||||
nsRefPtr<nsMemoryReporterManager> mgr =
|
||||
nsMemoryReporterManager::GetOrCreate();
|
||||
if (mgr) {
|
||||
mgr->HandleChildReports(generation, childReports);
|
||||
if (mReporterManager) {
|
||||
mReporterManager->EndChildReport(mGeneration, aWhy == Deletion);
|
||||
mReporterManager = nullptr;
|
||||
}
|
||||
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/. */
|
||||
|
@ -20,8 +20,9 @@ struct MemoryReport {
|
|||
protocol PMemoryReportRequest {
|
||||
manager PContent;
|
||||
|
||||
parent:
|
||||
__delete__(uint32_t generation, MemoryReport[] report);
|
||||
parent:
|
||||
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,21 +418,47 @@ 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))) {
|
||||
mManager->NetworkFinished(rv);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool requestSucceeded;
|
||||
rv = httpChannel->GetRequestSucceeded(&requestSucceeded);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
mManager->NetworkFinished(rv);
|
||||
return NS_OK;
|
||||
if (!requestSucceeded) {
|
||||
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;
|
||||
}
|
||||
|
||||
if (!requestSucceeded) {
|
||||
mManager->NetworkFinished(NS_ERROR_FAILURE);
|
||||
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.addstmts([
|
||||
fromswitch,
|
||||
# all --> Error transitions break to here
|
||||
StmtExpr(ExprAssn(ExprDeref(nextvar), _errorState())),
|
||||
StmtReturn(ExprLiteral.FALSE)
|
||||
])
|
||||
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([
|
||||
StmtExpr(ExprAssn(ExprDeref(nextvar), _errorState())),
|
||||
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,11 +981,16 @@ BytecodeEmitter::leaveNestedScope(StmtInfoBCE* stmt)
|
|||
|
||||
popStatement();
|
||||
|
||||
if (!emit1(stmt->isBlockScope ? JSOP_DEBUGLEAVEBLOCK : JSOP_LEAVEWITH))
|
||||
return false;
|
||||
|
||||
if (stmt->isBlockScope && stmt->staticScope->as<StaticBlockObject>().needsClone()) {
|
||||
if (!emit1(JSOP_POPBLOCKSCOPE))
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
ShouldInitFixedSlots(lir, &templateObject->as<PlainObject>());
|
||||
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,16 +758,25 @@ 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>()) {
|
||||
JSFunction* fun = &obj->as<JSFunction>();
|
||||
if (fun->isInterpretedLazy()) {
|
||||
LazyScript* lazy = fun->lazyScriptOrNull();
|
||||
if (lazy && lazy->sourceObject() && !lazy->maybeScript() &&
|
||||
!lazy->hasUncompiledEnclosingScript())
|
||||
{
|
||||
if (!lazyFunctions.append(fun))
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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();
|
||||
if (lazy && lazy->sourceObject() && !lazy->maybeScript() &&
|
||||
!lazy->hasUncompiledEnclosingScript())
|
||||
{
|
||||
if (!lazyFunctions.append(fun))
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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/
|
||||
|
|
|
@ -5672,7 +5672,7 @@ CheckThisFrame(JSContext* cx, const CallArgs& args, const char* fnname, bool che
|
|||
THIS_FRAME_THISOBJ(cx, argc, vp, fnname, args, thisobj); \
|
||||
AbstractFramePtr frame = AbstractFramePtr::FromRaw(thisobj->getPrivate()); \
|
||||
if (frame.isScriptFrameIterData()) { \
|
||||
ScriptFrameIter iter(*(ScriptFrameIter::Data*)(frame.raw())); \
|
||||
ScriptFrameIter iter(*(ScriptFrameIter::Data*)(frame.raw())); \
|
||||
frame = iter.abstractFramePtr(); \
|
||||
}
|
||||
|
||||
|
@ -5682,10 +5682,11 @@ CheckThisFrame(JSContext* cx, const CallArgs& args, const char* fnname, bool che
|
|||
{ \
|
||||
AbstractFramePtr f = AbstractFramePtr::FromRaw(thisobj->getPrivate()); \
|
||||
if (f.isScriptFrameIterData()) { \
|
||||
maybeIter.emplace(*(ScriptFrameIter::Data*)(f.raw())); \
|
||||
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; \
|
||||
|
@ -6407,7 +6408,7 @@ DebuggerObject_checkThis(JSContext* cx, const CallArgs& args, const char* fnname
|
|||
RootedObject obj(cx, DebuggerObject_checkThis(cx, args, fnname)); \
|
||||
if (!obj) \
|
||||
return false; \
|
||||
obj = (JSObject*) obj->as<NativeObject>().getPrivate(); \
|
||||
obj = (JSObject*) obj->as<NativeObject>().getPrivate(); \
|
||||
MOZ_ASSERT(obj)
|
||||
|
||||
#define THIS_DEBUGOBJECT_OWNER_REFERENT(cx, argc, vp, fnname, args, dbg, obj) \
|
||||
|
@ -6416,7 +6417,7 @@ DebuggerObject_checkThis(JSContext* cx, const CallArgs& args, const char* fnname
|
|||
if (!obj) \
|
||||
return false; \
|
||||
Debugger* dbg = Debugger::fromChildJSObject(obj); \
|
||||
obj = (JSObject*) obj->as<NativeObject>().getPrivate(); \
|
||||
obj = (JSObject*) obj->as<NativeObject>().getPrivate(); \
|
||||
MOZ_ASSERT(obj)
|
||||
|
||||
static bool
|
||||
|
@ -7332,10 +7333,10 @@ DebuggerEnv_checkThis(JSContext* cx, const CallArgs& args, const char* fnname,
|
|||
NativeObject* envobj = DebuggerEnv_checkThis(cx, args, fnname); \
|
||||
if (!envobj) \
|
||||
return false; \
|
||||
Rooted<Env*> env(cx, static_cast<Env*>(envobj->getPrivate())); \
|
||||
Rooted<Env*> env(cx, static_cast<Env*>(envobj->getPrivate())); \
|
||||
MOZ_ASSERT(env); \
|
||||
MOZ_ASSERT(!IsSyntacticScope(env));
|
||||
|
||||
|
||||
#define THIS_DEBUGENV_OWNER(cx, argc, vp, fnname, args, envobj, env, dbg) \
|
||||
THIS_DEBUGENV(cx, argc, vp, fnname, args, envobj, env); \
|
||||
Debugger* dbg = Debugger::fromChildJSObject(envobj)
|
||||
|
|
|
@ -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;
|
||||
yield BrowserTestUtils.synthesizeMouseAtCenter("#p1", { type: "mousemove" },
|
||||
gBrowser.selectedBrowser);
|
||||
yield BrowserTestUtils.synthesizeMouseAtCenter("#p1", { }, gBrowser.selectedBrowser);
|
||||
|
||||
let onPopupShown = function(aEvent) {
|
||||
popup = true;
|
||||
}
|
||||
document.addEventListener("popupshown", onPopupShown, true);
|
||||
// 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");
|
||||
|
||||
// Send a mousemove at a known position to start the test.
|
||||
BrowserTestUtils.synthesizeMouseAtCenter("#p1", { type: "mousemove" },
|
||||
gBrowser.selectedBrowser);
|
||||
BrowserTestUtils.synthesizeMouseAtCenter("#p1", { }, gBrowser.selectedBrowser);
|
||||
|
||||
yield new Promise(resolve => {
|
||||
setTimeout(function() {
|
||||
is(popup, false, "shouldn't get tooltip after click");
|
||||
resolve();
|
||||
}, 200);
|
||||
});
|
||||
|
||||
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,7 +127,35 @@ 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(); },
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче