Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-11-14 13:25:55 +01:00
commit 7a601d0b6d
352 changed files with 4954 additions and 4665 deletions

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
Bug 1095234 - Bug 1091260 stopped packaging a devtools file with EXTRA_JS_MODULES while making it require pre-processing.
Bug 1084498 - Android build tools dependency.

View File

@ -44,3 +44,4 @@ support-files =
[browser_newtab_undo.js]
[browser_newtab_unpin.js]
[browser_newtab_update.js]
skip-if = true # Bug 1008029

View File

@ -697,6 +697,38 @@ html, .fx-embedded, #main,
height: 100%;
}
.standalone .room-conversation-wrapper {
height: calc(100% - 50px - 60px);
background: #000;
}
.room-conversation-wrapper header {
background: #000;
height: 50px;
text-align: left;
}
.room-conversation-wrapper header h1 {
font-size: 1.5em;
color: #fff;
line-height: 50px;
text-indent: 50px;
background-image: url("../img/firefox-logo.png");
background-size: 30px;
background-position: 10px;
background-repeat: no-repeat;
}
.room-conversation-wrapper footer {
background: #000;
height: 60px;
margin-top: -12px;
}
.room-conversation-wrapper footer a {
color: #555;
}
/**
* Hides the hangup button for room conversations.
*/
@ -745,7 +777,7 @@ html, .fx-embedded, #main,
.standalone .room-inner-info-area {
position: absolute;
top: 35%;
top: 50%;
left: 0;
right: 25%;
z-index: 1000;
@ -767,6 +799,7 @@ html, .fx-embedded, #main,
padding: .5em 3em .3em 3em;
border-radius: 3px;
font-weight: normal;
max-width: 400px;
}
.standalone .room-conversation h2.room-name {
@ -796,7 +829,7 @@ html, .fx-embedded, #main,
.standalone .room-conversation .conversation-toolbar {
background: #000;
border-top: none;
border: none;
}
.standalone .room-conversation .conversation-toolbar .btn-hangup-entry {

View File

@ -10,6 +10,15 @@ loop.store.ActiveRoomStore = (function() {
"use strict";
var sharedActions = loop.shared.actions;
var FAILURE_REASONS = loop.shared.utils.FAILURE_REASONS;
// Error numbers taken from
// https://github.com/mozilla-services/loop-server/blob/master/loop/errno.json
var SERVER_CODES = loop.store.SERVER_CODES = {
INVALID_TOKEN: 105,
EXPIRED: 111,
ROOM_FULL: 202
};
var ROOM_STATES = loop.store.ROOM_STATES = {
// The initial state of the room
@ -84,7 +93,8 @@ loop.store.ActiveRoomStore = (function() {
this._storeState = {
roomState: ROOM_STATES.INIT,
audioMuted: false,
videoMuted: false
videoMuted: false,
failureReason: undefined
};
}
@ -112,13 +122,24 @@ loop.store.ActiveRoomStore = (function() {
* @param {sharedActions.RoomFailure} actionData
*/
roomFailure: function(actionData) {
function getReason(serverCode) {
switch (serverCode) {
case SERVER_CODES.INVALID_TOKEN:
case SERVER_CODES.EXPIRED:
return FAILURE_REASONS.EXPIRED_OR_INVALID;
default:
return FAILURE_REASONS.UNKNOWN;
}
}
console.error("Error in state `" + this._storeState.roomState + "`:",
actionData.error);
this.setStoreState({
error: actionData.error,
roomState: actionData.error.errno === 202 ? ROOM_STATES.FULL
: ROOM_STATES.FAILED
failureReason: getReason(actionData.error.errno),
roomState: actionData.error.errno === SERVER_CODES.ROOM_FULL ?
ROOM_STATES.FULL : ROOM_STATES.FAILED
});
},
@ -228,6 +249,11 @@ loop.store.ActiveRoomStore = (function() {
* Handles the action to join to a room.
*/
joinRoom: function() {
// Reset the failure reason if necessary.
if (this.getStoreState().failureReason) {
this.setStoreState({failureReason: undefined});
}
this._mozLoop.rooms.join(this._storeState.roomToken,
function(error, responseData) {
if (error) {
@ -275,11 +301,17 @@ loop.store.ActiveRoomStore = (function() {
/**
* Handles disconnection of this local client from the sdk servers.
*
* @param {sharedActions.ConnectionFailure} actionData
*/
connectionFailure: function() {
connectionFailure: function(actionData) {
// Treat all reasons as something failed. In theory, clientDisconnected
// could be a success case, but there's no way we should be intentionally
// sending that and still have the window open.
this.setStoreState({
failureReason: actionData.reason
});
this._leaveRoom(ROOM_STATES.FAILED);
},

View File

@ -8,6 +8,7 @@ var loop = loop || {};
loop.OTSdkDriver = (function() {
var sharedActions = loop.shared.actions;
var FAILURE_REASONS = loop.shared.utils.FAILURE_REASONS;
/**
* This is a wrapper for the OT sdk. It is used to translate the SDK events into
@ -47,8 +48,11 @@ loop.OTSdkDriver = (function() {
// the initial connect of the session. This saves time when setting up
// the media.
this.publisher = this.sdk.initPublisher(this.getLocalElement(),
this.publisherConfig,
this._onPublishComplete.bind(this));
this.publisherConfig);
this.publisher.on("accessAllowed", this._onPublishComplete.bind(this));
this.publisher.on("accessDenied", this._onPublishDenied.bind(this));
this.publisher.on("accessDialogOpened",
this._onAccessDialogOpened.bind(this));
},
/**
@ -96,16 +100,12 @@ loop.OTSdkDriver = (function() {
*/
disconnectSession: function() {
if (this.session) {
this.session.off("streamCreated", this._onRemoteStreamCreated.bind(this));
this.session.off("connectionDestroyed",
this._onConnectionDestroyed.bind(this));
this.session.off("sessionDisconnected",
this._onSessionDisconnected.bind(this));
this.session.off("streamCreated connectionDestroyed sessionDisconnected");
this.session.disconnect();
delete this.session;
}
if (this.publisher) {
this.publisher.off("accessAllowed accessDenied accessDialogOpened");
this.publisher.destroy();
delete this.publisher;
}
@ -126,7 +126,7 @@ loop.OTSdkDriver = (function() {
if (error) {
console.error("Failed to complete connection", error);
this.dispatcher.dispatch(new sharedActions.ConnectionFailure({
reason: "couldNotConnect"
reason: FAILURE_REASONS.COULD_NOT_CONNECT
}));
return;
}
@ -159,7 +159,7 @@ loop.OTSdkDriver = (function() {
// We only need to worry about the network disconnected reason here.
if (event.reason === "networkDisconnected") {
this.dispatcher.dispatch(new sharedActions.ConnectionFailure({
reason: "networkDisconnected"
reason: FAILURE_REASONS.NETWORK_DISCONNECTED
}));
}
},
@ -188,24 +188,42 @@ loop.OTSdkDriver = (function() {
}
},
/**
* Called from the sdk when the media access dialog is opened.
* Prevents the default action, to prevent the SDK's "allow access"
* dialog from being shown.
*
* @param {OT.Event} event
*/
_onAccessDialogOpened: function(event) {
event.preventDefault();
},
/**
* Handles the publishing being complete.
*
* @param {Error} error An OT error object, null if there was no error.
* @param {OT.Event} event
*/
_onPublishComplete: function(error) {
if (error) {
console.error("Failed to initialize publisher", error);
this.dispatcher.dispatch(new sharedActions.ConnectionFailure({
reason: "noMedia"
}));
return;
}
_onPublishComplete: function(event) {
event.preventDefault();
this._publisherReady = true;
this._maybePublishLocalStream();
},
/**
* Handles publishing of media being denied.
*
* @param {OT.Event} event
*/
_onPublishDenied: function(event) {
// This prevents the SDK's "access denied" dialog showing.
event.preventDefault();
this.dispatcher.dispatch(new sharedActions.ConnectionFailure({
reason: FAILURE_REASONS.MEDIA_DENIED
}));
},
/**
* Publishes the local stream if the session is connected
* and the publisher is ready.

View File

@ -17,6 +17,14 @@ loop.shared.utils = (function(mozL10n) {
AUDIO_ONLY: "audio"
};
var FAILURE_REASONS = {
MEDIA_DENIED: "reason-media-denied",
COULD_NOT_CONNECT: "reason-could-not-connect",
NETWORK_DISCONNECTED: "reason-network-disconnected",
EXPIRED_OR_INVALID: "reason-expired-or-invalid",
UNKNOWN: "reason-unknown"
};
/**
* Format a given date into an l10n-friendly string.
*
@ -110,6 +118,7 @@ loop.shared.utils = (function(mozL10n) {
return {
CALL_TYPES: CALL_TYPES,
FAILURE_REASONS: FAILURE_REASONS,
Helper: Helper,
composeCallUrlEmail: composeCallUrlEmail,
formatDate: formatDate,

View File

@ -18,6 +18,13 @@ body,
font-family: Open Sans,sans-serif;
}
/**
* Note: the is-standalone-room class is dynamically set by the StandaloneRoomView.
*/
.standalone.is-standalone-room {
background-color: #000;
}
.standalone-header {
border-radius: 4px;
background: #fff;

View File

@ -11,8 +11,10 @@ var loop = loop || {};
loop.standaloneRoomViews = (function(mozL10n) {
"use strict";
var FAILURE_REASONS = loop.shared.utils.FAILURE_REASONS;
var ROOM_STATES = loop.store.ROOM_STATES;
var sharedActions = loop.shared.actions;
var sharedMixins = loop.shared.mixins;
var sharedViews = loop.shared.views;
var StandaloneRoomInfoArea = React.createClass({displayName: 'StandaloneRoomInfoArea',
@ -39,6 +41,20 @@ loop.standaloneRoomViews = (function(mozL10n) {
);
},
/**
* @return String An appropriate string according to the failureReason.
*/
_getFailureString: function() {
switch(this.props.failureReason) {
case FAILURE_REASONS.MEDIA_DENIED:
return mozL10n.get("rooms_media_denied_message");
case FAILURE_REASONS.EXPIRED_OR_INVALID:
return mozL10n.get("rooms_unavailable_notification_message");
default:
return mozL10n.get("status_error");
};
},
_renderContent: function() {
switch(this.props.roomState) {
case ROOM_STATES.INIT:
@ -67,6 +83,12 @@ loop.standaloneRoomViews = (function(mozL10n) {
React.DOM.p(null, this._renderCallToActionLink())
)
);
case ROOM_STATES.FAILED:
return (
React.DOM.p({className: "failed-room-message"},
this._getFailureString()
)
);
default:
return null;
}
@ -81,6 +103,43 @@ loop.standaloneRoomViews = (function(mozL10n) {
}
});
var StandaloneRoomHeader = React.createClass({displayName: 'StandaloneRoomHeader',
render: function() {
return (
React.DOM.header(null,
React.DOM.h1(null, mozL10n.get("clientShortname2"))
)
);
}
});
var StandaloneRoomFooter = React.createClass({displayName: 'StandaloneRoomFooter',
_getContent: function() {
return mozL10n.get("legal_text_and_links", {
"clientShortname": mozL10n.get("clientShortname2"),
"terms_of_use_url": React.renderComponentToStaticMarkup(
React.DOM.a({href: loop.config.legalWebsiteUrl, target: "_blank"},
mozL10n.get("terms_of_use_link_text")
)
),
"privacy_notice_url": React.renderComponentToStaticMarkup(
React.DOM.a({href: loop.config.privacyWebsiteUrl, target: "_blank"},
mozL10n.get("privacy_notice_link_text")
)
),
});
},
render: function() {
return (
React.DOM.footer(null,
React.DOM.p({dangerouslySetInnerHTML: {__html: this._getContent()}}),
React.DOM.div({className: "footer-logo"})
)
);
}
});
var StandaloneRoomView = React.createClass({displayName: 'StandaloneRoomView',
mixins: [Backbone.Events],
@ -144,6 +203,11 @@ loop.standaloneRoomViews = (function(mozL10n) {
};
},
componentDidMount: function() {
// Adding a class to the document body element from here to ease styling it.
document.body.classList.add("is-standalone-room");
},
componentWillUnmount: function() {
this.stopListening(this.props.activeRoomStore);
},
@ -207,7 +271,9 @@ loop.standaloneRoomViews = (function(mozL10n) {
return (
React.DOM.div({className: "room-conversation-wrapper"},
StandaloneRoomHeader(null),
StandaloneRoomInfoArea({roomState: this.state.roomState,
failureReason: this.state.failureReason,
joinRoom: this.joinRoom,
helper: this.props.helper}),
React.DOM.div({className: "video-layout-wrapper"},
@ -229,7 +295,8 @@ loop.standaloneRoomViews = (function(mozL10n) {
hangupButtonLabel: mozL10n.get("rooms_leave_button_label"),
enableHangup: this._roomIsActive()})
)
)
),
StandaloneRoomFooter(null)
)
);
}

View File

@ -11,8 +11,10 @@ var loop = loop || {};
loop.standaloneRoomViews = (function(mozL10n) {
"use strict";
var FAILURE_REASONS = loop.shared.utils.FAILURE_REASONS;
var ROOM_STATES = loop.store.ROOM_STATES;
var sharedActions = loop.shared.actions;
var sharedMixins = loop.shared.mixins;
var sharedViews = loop.shared.views;
var StandaloneRoomInfoArea = React.createClass({
@ -39,6 +41,20 @@ loop.standaloneRoomViews = (function(mozL10n) {
);
},
/**
* @return String An appropriate string according to the failureReason.
*/
_getFailureString: function() {
switch(this.props.failureReason) {
case FAILURE_REASONS.MEDIA_DENIED:
return mozL10n.get("rooms_media_denied_message");
case FAILURE_REASONS.EXPIRED_OR_INVALID:
return mozL10n.get("rooms_unavailable_notification_message");
default:
return mozL10n.get("status_error");
};
},
_renderContent: function() {
switch(this.props.roomState) {
case ROOM_STATES.INIT:
@ -67,6 +83,12 @@ loop.standaloneRoomViews = (function(mozL10n) {
<p>{this._renderCallToActionLink()}</p>
</div>
);
case ROOM_STATES.FAILED:
return (
<p className="failed-room-message">
{this._getFailureString()}
</p>
);
default:
return null;
}
@ -81,6 +103,43 @@ loop.standaloneRoomViews = (function(mozL10n) {
}
});
var StandaloneRoomHeader = React.createClass({
render: function() {
return (
<header>
<h1>{mozL10n.get("clientShortname2")}</h1>
</header>
);
}
});
var StandaloneRoomFooter = React.createClass({
_getContent: function() {
return mozL10n.get("legal_text_and_links", {
"clientShortname": mozL10n.get("clientShortname2"),
"terms_of_use_url": React.renderComponentToStaticMarkup(
<a href={loop.config.legalWebsiteUrl} target="_blank">
{mozL10n.get("terms_of_use_link_text")}
</a>
),
"privacy_notice_url": React.renderComponentToStaticMarkup(
<a href={loop.config.privacyWebsiteUrl} target="_blank">
{mozL10n.get("privacy_notice_link_text")}
</a>
),
});
},
render: function() {
return (
<footer>
<p dangerouslySetInnerHTML={{__html: this._getContent()}}></p>
<div className="footer-logo" />
</footer>
);
}
});
var StandaloneRoomView = React.createClass({
mixins: [Backbone.Events],
@ -144,6 +203,11 @@ loop.standaloneRoomViews = (function(mozL10n) {
};
},
componentDidMount: function() {
// Adding a class to the document body element from here to ease styling it.
document.body.classList.add("is-standalone-room");
},
componentWillUnmount: function() {
this.stopListening(this.props.activeRoomStore);
},
@ -207,7 +271,9 @@ loop.standaloneRoomViews = (function(mozL10n) {
return (
<div className="room-conversation-wrapper">
<StandaloneRoomHeader />
<StandaloneRoomInfoArea roomState={this.state.roomState}
failureReason={this.state.failureReason}
joinRoom={this.joinRoom}
helper={this.props.helper} />
<div className="video-layout-wrapper">
@ -230,6 +296,7 @@ loop.standaloneRoomViews = (function(mozL10n) {
enableHangup={this._roomIsActive()} />
</div>
</div>
<StandaloneRoomFooter />
</div>
);
}

View File

@ -116,6 +116,8 @@ rooms_room_full_call_to_action_label=Learn more about {{clientShortname}} »
rooms_room_joined_label=Someone has joined the conversation!
rooms_room_join_label=Join the conversation
rooms_display_name_guest=Guest
rooms_unavailable_notification_message=Sorry, you cannot join this conversation. The link may be expired or invalid.
rooms_media_denied_message=We could not get access to your microphone or camera. Please reload the page to try again.
## LOCALIZATION_NOTE(standalone_title_with_status): {{clientShortname}} will be
## replaced by the brand name and {{currentStatus}} will be replaced

View File

@ -65,6 +65,7 @@ describe("loop.roomViews", function () {
roomState: ROOM_STATES.INIT,
audioMuted: false,
videoMuted: false,
failureReason: undefined,
foo: "bar"
});
});

View File

@ -6,7 +6,9 @@ var sharedActions = loop.shared.actions;
describe("loop.store.ActiveRoomStore", function () {
"use strict";
var SERVER_CODES = loop.store.SERVER_CODES;
var ROOM_STATES = loop.store.ROOM_STATES;
var FAILURE_REASONS = loop.shared.utils.FAILURE_REASONS;
var sandbox, dispatcher, store, fakeMozLoop, fakeSdkDriver;
var fakeMultiplexGum;
@ -91,8 +93,8 @@ describe("loop.store.ActiveRoomStore", function () {
sinon.match(ROOM_STATES.READY), fakeError);
});
it("should set the state to `FULL` on server errno 202", function() {
fakeError.errno = 202;
it("should set the state to `FULL` on server error room full", function() {
fakeError.errno = SERVER_CODES.ROOM_FULL;
store.roomFailure({error: fakeError});
@ -103,6 +105,27 @@ describe("loop.store.ActiveRoomStore", function () {
store.roomFailure({error: fakeError});
expect(store._storeState.roomState).eql(ROOM_STATES.FAILED);
expect(store._storeState.failureReason).eql(FAILURE_REASONS.UNKNOWN);
});
it("should set the failureReason to EXPIRED_OR_INVALID on server error: " +
"invalid token", function() {
fakeError.errno = SERVER_CODES.INVALID_TOKEN;
store.roomFailure({error: fakeError});
expect(store._storeState.roomState).eql(ROOM_STATES.FAILED);
expect(store._storeState.failureReason).eql(FAILURE_REASONS.EXPIRED_OR_INVALID);
});
it("should set the failureReason to EXPIRED_OR_INVALID on server error: " +
"expired", function() {
fakeError.errno = SERVER_CODES.EXPIRED;
store.roomFailure({error: fakeError});
expect(store._storeState.roomState).eql(ROOM_STATES.FAILED);
expect(store._storeState.failureReason).eql(FAILURE_REASONS.EXPIRED_OR_INVALID);
});
});
@ -244,6 +267,14 @@ describe("loop.store.ActiveRoomStore", function () {
store.setStoreState({roomToken: "tokenFake"});
});
it("should reset failureReason", function() {
store.setStoreState({failureReason: "Test"});
store.joinRoom();
expect(store.getStoreState().failureReason).eql(undefined);
});
it("should call rooms.join on mozLoop", function() {
store.joinRoom();
@ -380,22 +411,34 @@ describe("loop.store.ActiveRoomStore", function () {
});
describe("#connectionFailure", function() {
var connectionFailureAction;
beforeEach(function() {
store.setStoreState({
roomState: ROOM_STATES.JOINED,
roomToken: "fakeToken",
sessionToken: "1627384950"
});
connectionFailureAction = new sharedActions.ConnectionFailure({
reason: "FAIL"
});
});
it("should store the failure reason", function() {
store.connectionFailure(connectionFailureAction);
expect(store.getStoreState().failureReason).eql("FAIL");
});
it("should reset the multiplexGum", function() {
store.leaveRoom();
store.connectionFailure(connectionFailureAction);
sinon.assert.calledOnce(fakeMultiplexGum.reset);
});
it("should disconnect from the servers via the sdk", function() {
store.connectionFailure();
store.connectionFailure(connectionFailureAction);
sinon.assert.calledOnce(fakeSdkDriver.disconnectSession);
});
@ -404,13 +447,13 @@ describe("loop.store.ActiveRoomStore", function () {
sandbox.stub(window, "clearTimeout");
store._timeout = {};
store.connectionFailure();
store.connectionFailure(connectionFailureAction);
sinon.assert.calledOnce(clearTimeout);
});
it("should call mozLoop.rooms.leave", function() {
store.connectionFailure();
store.connectionFailure(connectionFailureAction);
sinon.assert.calledOnce(fakeMozLoop.rooms.leave);
sinon.assert.calledWithExactly(fakeMozLoop.rooms.leave,
@ -418,7 +461,7 @@ describe("loop.store.ActiveRoomStore", function () {
});
it("should set the state to `FAILED`", function() {
store.connectionFailure();
store.connectionFailure(connectionFailureAction);
expect(store.getStoreState().roomState).eql(ROOM_STATES.FAILED);
});

View File

@ -7,16 +7,19 @@ describe("loop.OTSdkDriver", function () {
"use strict";
var sharedActions = loop.shared.actions;
var FAILURE_REASONS = loop.shared.utils.FAILURE_REASONS;
var sandbox;
var dispatcher, driver, publisher, sdk, session, sessionData;
var fakeLocalElement, fakeRemoteElement, publisherConfig;
var fakeLocalElement, fakeRemoteElement, publisherConfig, fakeEvent;
beforeEach(function() {
sandbox = sinon.sandbox.create();
fakeLocalElement = {fake: 1};
fakeRemoteElement = {fake: 2};
fakeEvent = {
preventDefault: sinon.stub()
};
publisherConfig = {
fake: "config"
};
@ -34,14 +37,14 @@ describe("loop.OTSdkDriver", function () {
subscribe: sinon.stub()
}, Backbone.Events);
publisher = {
publisher = _.extend({
destroy: sinon.stub(),
publishAudio: sinon.stub(),
publishVideo: sinon.stub()
};
}, Backbone.Events);
sdk = {
initPublisher: sinon.stub(),
initPublisher: sinon.stub().returns(publisher),
initSession: sinon.stub().returns(session)
};
@ -80,51 +83,6 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledOnce(sdk.initPublisher);
sinon.assert.calledWith(sdk.initPublisher, fakeLocalElement, publisherConfig);
});
describe("On Publisher Complete", function() {
it("should publish the stream if the connection is ready", function() {
sdk.initPublisher.callsArgWith(2, null);
driver.session = session;
driver._sessionConnected = true;
dispatcher.dispatch(new sharedActions.SetupStreamElements({
getLocalElementFunc: function() {return fakeLocalElement;},
getRemoteElementFunc: function() {return fakeRemoteElement;},
publisherConfig: publisherConfig
}));
sinon.assert.calledOnce(session.publish);
});
it("should dispatch connectionFailure if connecting failed", function() {
sdk.initPublisher.callsArgWith(2, new Error("Failure"));
// Special stub, as we want to use the dispatcher, but also know that
// we've been called correctly for the second dispatch.
var dispatchStub = (function() {
var originalDispatch = dispatcher.dispatch.bind(dispatcher);
return sandbox.stub(dispatcher, "dispatch", function(action) {
originalDispatch(action);
});
}());
driver.session = session;
driver._sessionConnected = true;
dispatcher.dispatch(new sharedActions.SetupStreamElements({
getLocalElementFunc: function() {return fakeLocalElement;},
getRemoteElementFunc: function() {return fakeRemoteElement;},
publisherConfig: publisherConfig
}));
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("name", "connectionFailure"));
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("reason", "noMedia"));
});
});
});
describe("#setMute", function() {
@ -194,7 +152,7 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("name", "connectionFailure"));
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("reason", "couldNotConnect"));
sinon.match.hasOwn("reason", FAILURE_REASONS.COULD_NOT_CONNECT));
});
});
});
@ -269,7 +227,7 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("name", "connectionFailure"));
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("reason", "networkDisconnected"));
sinon.match.hasOwn("reason", FAILURE_REASONS.NETWORK_DISCONNECTED));
});
});
@ -328,5 +286,41 @@ describe("loop.OTSdkDriver", function () {
sinon.assert.notCalled(dispatcher.dispatch);
});
});
describe("accessAllowed", function() {
it("should publish the stream if the connection is ready", function() {
driver._sessionConnected = true;
publisher.trigger("accessAllowed", fakeEvent);
sinon.assert.calledOnce(session.publish);
});
});
describe("accessDenied", function() {
it("should prevent the default event behavior", function() {
publisher.trigger("accessDenied", fakeEvent);
sinon.assert.calledOnce(fakeEvent.preventDefault);
});
it("should dispatch connectionFailure", function() {
publisher.trigger("accessDenied", fakeEvent);
sinon.assert.called(dispatcher.dispatch);
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("name", "connectionFailure"));
sinon.assert.calledWithMatch(dispatcher.dispatch,
sinon.match.hasOwn("reason", FAILURE_REASONS.MEDIA_DENIED));
});
});
describe("accessDialogOpened", function() {
it("should prevent the default event behavior", function() {
publisher.trigger("accessDialogOpened", fakeEvent);
sinon.assert.calledOnce(fakeEvent.preventDefault);
});
});
});
});

View File

@ -139,6 +139,16 @@ describe("loop.standaloneRoomViews", function() {
});
});
describe("Failed room message", function() {
it("should display a failed room message on FAILED",
function() {
activeRoomStore.setStoreState({roomState: ROOM_STATES.FAILED});
expect(view.getDOMNode().querySelector(".failed-room-message"))
.not.eql(null);
});
});
describe("Join button", function() {
function getJoinButton(view) {
return view.getDOMNode().querySelector(".btn-join");

View File

@ -608,6 +608,16 @@
roomState: ROOM_STATES.FULL,
helper: {isFirefox: returnFalse}})
)
),
Example({summary: "Standalone room conversation (failed)"},
React.DOM.div({className: "standalone"},
StandaloneRoomView({
dispatcher: dispatcher,
activeRoomStore: activeRoomStore,
roomState: ROOM_STATES.FAILED,
helper: {isFirefox: returnFalse}})
)
)
),

View File

@ -609,6 +609,16 @@
helper={{isFirefox: returnFalse}} />
</div>
</Example>
<Example summary="Standalone room conversation (failed)">
<div className="standalone">
<StandaloneRoomView
dispatcher={dispatcher}
activeRoomStore={activeRoomStore}
roomState={ROOM_STATES.FAILED}
helper={{isFirefox: returnFalse}} />
</div>
</Example>
</Section>
<Section name="SVG icons preview">

View File

@ -9,11 +9,6 @@ function test() {
}
function runTests() {
// Request a longer timeout because the test takes quite a while
// to complete on slow Windows debug machines and we would otherwise
// see a lot of (not so) intermittent test failures.
requestLongerTimeout(2);
Services.prefs.setBoolPref(PREF_RESTORE_ON_DEMAND, true);
registerCleanupFunction(function () {
Services.prefs.clearUserPref(PREF_RESTORE_ON_DEMAND);
@ -29,112 +24,31 @@ function runTests() {
{ entries: [{ url: "http://example.org/#7" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.org/#8" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.org/#9" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.org/#10" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.org/#11" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.org/#12" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.org/#13" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.org/#14" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.org/#15" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.org/#16" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.org/#17" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.org/#18" }], extData: { "uniq": r() } }
], selected: 1 }] };
let loadCount = 0;
gProgressListener.setCallback(function (aBrowser, aNeedRestore, aRestoring, aRestored) {
loadCount++;
is(aBrowser.currentURI.spec, state.windows[0].tabs[loadCount - 1].entries[0].url,
"load " + loadCount + " - browser loaded correct url");
gBrowser.tabContainer.addEventListener("SSTabRestored", function onRestored(event) {
let tab = event.target;
let browser = tab.linkedBrowser;
let tabData = state.windows[0].tabs[loadCount++];
if (loadCount <= state.windows[0].tabs.length) {
// double check that this tab was the right one
let expectedData = state.windows[0].tabs[loadCount - 1].extData.uniq;
let tab;
for (let i = 0; i < window.gBrowser.tabs.length; i++) {
if (!tab && window.gBrowser.tabs[i].linkedBrowser == aBrowser)
tab = window.gBrowser.tabs[i];
}
is(ss.getTabValue(tab, "uniq"), expectedData,
is(browser.currentURI.spec, tabData.entries[0].url,
"load " + loadCount + " - browser loaded correct url");
is(ss.getTabValue(tab, "uniq"), tabData.extData.uniq,
"load " + loadCount + " - correct tab was restored");
if (loadCount == state.windows[0].tabs.length) {
gProgressListener.unsetCallback();
gBrowser.tabContainer.removeEventListener("SSTabRestored", onRestored);
executeSoon(function () {
reloadAllTabs(state, function () {
waitForBrowserState(TestRunner.backupState, testCascade);
});
waitForBrowserState(TestRunner.backupState, finish);
});
} else {
// reload the next tab
window.gBrowser.reloadTab(window.gBrowser.tabs[loadCount]);
}
gBrowser.browsers[loadCount].reload();
}
});
yield ss.setBrowserState(JSON.stringify(state));
}
function testCascade() {
Services.prefs.setBoolPref(PREF_RESTORE_ON_DEMAND, false);
let state = { windows: [{ tabs: [
{ entries: [{ url: "http://example.com/#1" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.com/#2" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.com/#3" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.com/#4" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.com/#5" }], extData: { "uniq": r() } },
{ entries: [{ url: "http://example.com/#6" }], extData: { "uniq": r() } }
] }] };
let loadCount = 0;
gProgressListener.setCallback(function (aBrowser, aNeedRestore, aRestoring, aRestored) {
if (++loadCount < state.windows[0].tabs.length) {
return;
}
gProgressListener.unsetCallback();
executeSoon(function () {
reloadAllTabs(state, next);
});
});
ss.setBrowserState(JSON.stringify(state));
}
function reloadAllTabs(aState, aCallback) {
// Simulate a left mouse button click with no modifiers, which is what
// Command-R, or clicking reload does.
let fakeEvent = {
button: 0,
metaKey: false,
altKey: false,
ctrlKey: false,
shiftKey: false
};
let loadCount = 0;
gWebProgressListener.setCallback(function (aBrowser) {
if (++loadCount <= aState.windows[0].tabs.length) {
// double check that this tab was the right one
let expectedData = aState.windows[0].tabs[loadCount - 1].extData.uniq;
let tab;
for (let i = 0; i < window.gBrowser.tabs.length; i++) {
if (!tab && window.gBrowser.tabs[i].linkedBrowser == aBrowser)
tab = window.gBrowser.tabs[i];
}
is(ss.getTabValue(tab, "uniq"), expectedData,
"load " + loadCount + " - correct tab was reloaded");
if (loadCount == aState.windows[0].tabs.length) {
gWebProgressListener.unsetCallback();
executeSoon(aCallback);
} else {
// reload the next tab
window.gBrowser.selectTabAtIndex(loadCount);
BrowserReloadOrDuplicate(fakeEvent);
}
}
});
BrowserReloadOrDuplicate(fakeEvent);
}

View File

@ -152,33 +152,33 @@ skip-if = e10s || os == "mac" || e10s # Bug 895426
[browser_dbg_break-on-dom-event-02.js]
skip-if = e10s
[browser_dbg_breakpoints-actual-location.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_breakpoints-actual-location2.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js]
skip-if = e10s
skip-if = e10s # Bug 1093535
[browser_dbg_breakpoints-button-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_breakpoints-button-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_breakpoints-contextmenu-add.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_breakpoints-contextmenu.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_breakpoints-disabled-reload.js]
skip-if = e10s
skip-if = e10s # Bug 1093535
[browser_dbg_breakpoints-editor.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_breakpoints-highlight.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_breakpoints-new-script.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_breakpoints-other-tabs.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_breakpoints-pane.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_breakpoints-reload.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_chrome-create.js]
skip-if = e10s
[browser_dbg_chrome-debugging.js]
@ -458,21 +458,21 @@ skip-if = e10s && debug
[browser_dbg_variables-view-06.js]
skip-if = e10s && debug
[browser_dbg_variables-view-accessibility.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-data.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-edit-cancel.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-edit-click.js]
skip-if = e10s || (os == 'mac' || os == 'win') && (debug == false) # Bug 986166
[browser_dbg_variables-view-edit-getset-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-edit-getset-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-edit-value.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-edit-watch.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-filter-01.js]
skip-if = e10s && debug
[browser_dbg_variables-view-filter-02.js]
@ -484,27 +484,27 @@ skip-if = e10s && debug
[browser_dbg_variables-view-filter-05.js]
skip-if = e10s && debug
[browser_dbg_variables-view-filter-pref.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-filter-searchbox.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-frame-parameters-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-frame-parameters-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-frame-parameters-03.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-frame-with.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-frozen-sealed-nonext.js]
skip-if = e10s || buildapp == 'mulet'
skip-if = e10s && debug || buildapp == 'mulet'
[browser_dbg_variables-view-hide-non-enums.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-large-array-buffer.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-override-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-override-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-popup-01.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-02.js]
@ -532,20 +532,20 @@ skip-if = e10s && debug
[browser_dbg_variables-view-popup-13.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-14.js]
skip-if = e10s && debug
skip-if = (e10s && debug) || (e10s && os == 'linux') # Linux e10s - bug 1029545
[browser_dbg_variables-view-popup-15.js]
skip-if = e10s && debug
[browser_dbg_variables-view-popup-16.js]
skip-if = e10s && debug
[browser_dbg_variables-view-reexpand-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-reexpand-02.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-reexpand-03.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_variables-view-webidl.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_watch-expressions-01.js]
skip-if = e10s
skip-if = e10s && debug
[browser_dbg_watch-expressions-02.js]
skip-if = e10s
skip-if = e10s && debug

View File

@ -9,12 +9,11 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources, gBreakpoints, gBreakpointsAdded, gBreakpointsRemoving;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -24,7 +23,7 @@ function test() {
gBreakpointsRemoving = gBreakpoints._removing;
waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1).then(performTest);
gDebuggee.firstCall();
callInTab(gTab, "firstCall");
});
function performTest() {

View File

@ -10,12 +10,11 @@
const TAB_URL = EXAMPLE_URL + "doc_breakpoint-move.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources, gBreakpoints, gBreakpointsAdded, gBreakpointsRemoving;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -25,7 +24,7 @@ function test() {
gBreakpointsRemoving = gBreakpoints._removing;
waitForSourceAndCaretAndScopes(gPanel, ".html", 1).then(performTest);
gDebuggee.ermahgerd();
callInTab(gTab, "ermahgerd");
});
function performTest() {
@ -62,7 +61,7 @@ function test() {
yield resumeAndTestBreakpoint(20);
yield doResume(gPanel);
executeSoon(() => gDebuggee.ermahgerd());
callInTab(gTab, "ermahgerd");
yield waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES);
yield resumeAndTestBreakpoint(20);

View File

@ -15,7 +15,7 @@ function test() {
let gPanel, gDebugger, gThreadClient, gEvents;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gThreadClient = gDebugger.gThreadClient;

View File

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gSources, gBreakpoints;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;

View File

@ -9,12 +9,11 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gSources, gBreakpoints;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;

View File

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources, gContextMenu, gBreakpoints, gBreakpointsAdded;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -29,7 +28,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
gDebuggee.firstCall();
callInTab(gTab, "firstCall");
});
function performTest() {

View File

@ -11,12 +11,11 @@ function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gSources, gBreakpoints;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gSources = gDebugger.DebuggerView.Sources;
@ -95,13 +94,7 @@ function test() {
ok(isCaretPos(gPanel, 9),
"The editor location is correct before pausing.");
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
});
sendMouseClickToTab(gTab, content.document.querySelector("button"));
return finished;
}

View File

@ -8,7 +8,8 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
let gTab = aTab;
let gDebugger = aPanel.panelWin;
let gEvents = gDebugger.EVENTS;
let gEditor = gDebugger.DebuggerView.editor;
@ -66,7 +67,7 @@ function test() {
yield ensureSourceIs(aPanel, "-01.js");
yield verifyView({ disabled: false, visible: true });
executeSoon(() => aDebuggee.firstCall());
callInTab(gTab, "firstCall");
yield waitForDebuggerEvents(aPanel, gEvents.FETCHED_SCOPES);
yield ensureSourceIs(aPanel, "-01.js");
yield ensureCaretAt(aPanel, 5);
@ -83,7 +84,7 @@ function test() {
yield ensureSourceIs(aPanel, "-02.js", true);
yield verifyView({ disabled: false, visible: false });
executeSoon(() => aDebuggee.firstCall());
callInTab(gTab, "firstCall");
yield waitForSourceAndCaretAndScopes(aPanel, "-01.js", 1);
yield verifyView({ disabled: false, visible: true });
@ -98,7 +99,7 @@ function test() {
yield ensureSourceIs(aPanel, "-02.js", true);
yield verifyView({ disabled: true, visible: false });
executeSoon(() => aDebuggee.firstCall());
callInTab(gTab, "firstCall");
yield waitForDebuggerEvents(aPanel, gEvents.FETCHED_SCOPES);
yield ensureSourceIs(aPanel, "-02.js");
yield ensureCaretAt(aPanel, 1);

View File

@ -9,12 +9,11 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources, gBreakpoints, gBreakpointsAdded, gBreakpointsRemoving;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -24,7 +23,7 @@ function test() {
gBreakpointsRemoving = gBreakpoints._removing;
waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1).then(performTest);
gDebuggee.firstCall();
callInTab(gTab, "firstCall");
});
function performTest() {

View File

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;

View File

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_inline-script.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -33,7 +32,7 @@ function addBreakpoint() {
});
});
gDebuggee.runDebuggerStatement();
callInTab(gTab, "runDebuggerStatement");
}
function testResume() {
@ -54,9 +53,7 @@ function testResume() {
});
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
});
}
@ -84,7 +81,6 @@ function testBreakpointHit() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
});

View File

@ -9,8 +9,8 @@
const TAB_URL = EXAMPLE_URL + "doc_breakpoints-other-tabs.html";
let test = Task.async(function* () {
const [tab1, debuggee1, panel1] = yield initDebugger(TAB_URL);
const [tab2, debuggee2, panel2] = yield initDebugger(TAB_URL);
const [tab1,, panel1] = yield initDebugger(TAB_URL);
const [tab2,, panel2] = yield initDebugger(TAB_URL);
yield ensureSourceIs(panel1, "code_breakpoints-other-tabs.js", true);
@ -22,7 +22,7 @@ let test = Task.async(function* () {
});
const paused = waitForThreadEvents(panel2, "paused");
executeSoon(() => debuggee2.testCase());
callInTab(tab2, "testCase");
const packet = yield paused;
is(packet.why.type, "debuggerStatement",

View File

@ -9,12 +9,11 @@
const TAB_URL = EXAMPLE_URL + "doc_script-switching-01.html";
function test() {
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gSources, gBreakpoints, gBreakpointsAdded, gBreakpointsRemoving;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
@ -24,7 +23,7 @@ function test() {
gBreakpointsRemoving = gBreakpoints._removing;
waitForSourceAndCaretAndScopes(gPanel, "-02.js", 1).then(performTest);
gDebuggee.firstCall();
callInTab(gTab, "firstCall");
});
let breakpointsAdded = 0;

View File

@ -11,7 +11,7 @@ const TAB_URL = EXAMPLE_URL + "doc_breakpoints-reload.html";
let test = Task.async(function* () {
requestLongerTimeout(4);
const [tab, debuggee, panel] = yield initDebugger(TAB_URL);
const [tab,, panel] = yield initDebugger(TAB_URL);
yield ensureSourceIs(panel, "doc_breakpoints-reload.html", true);

View File

@ -5,13 +5,12 @@
* Make sure that the variables view is keyboard accessible.
*/
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gVariablesView;
function test() {
initDebugger("about:blank").then(([aTab, aDebuggee, aPanel]) => {
initDebugger("about:blank").then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gVariablesView = gDebugger.DebuggerView.Variables;
@ -504,7 +503,6 @@ function performTest() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gVariablesView = null;

View File

@ -6,13 +6,12 @@
* when given some raw data.
*/
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gVariablesView, gScope, gVariable;
function test() {
initDebugger("about:blank").then(([aTab, aDebuggee, aPanel]) => {
initDebugger("about:blank").then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gVariablesView = gDebugger.DebuggerView.Variables;
@ -602,7 +601,6 @@ function testClearHierarchy() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gVariablesView = null;

View File

@ -10,14 +10,13 @@ const TAB_URL = EXAMPLE_URL + "doc_watch-expressions.html";
function test() {
Task.spawn(function*() {
let [tab, debuggee, panel] = yield initDebugger(TAB_URL);
let [tab,, panel] = yield initDebugger(TAB_URL);
let win = panel.panelWin;
let vars = win.DebuggerView.Variables;
win.DebuggerView.WatchExpressions.addExpression("this");
// Allow this generator function to yield first.
executeSoon(() => debuggee.ermahgerd());
callInTab(tab, "ermahgerd");
yield waitForDebuggerEvents(panel, win.EVENTS.FETCHED_WATCH_EXPRESSIONS);
let exprScope = vars.getScopeAtIndex(0);

View File

@ -7,16 +7,15 @@
const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gL10N, gEditor, gVars, gWatch;
function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gL10N = gDebugger.L10N;
@ -115,9 +114,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
});
}
@ -288,7 +285,6 @@ function testWatchExpressionsRemoved() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gL10N = null;

View File

@ -8,16 +8,15 @@
const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gL10N, gEditor, gVars, gWatch;
function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gL10N = gDebugger.L10N;
@ -36,9 +35,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
});
}
@ -94,7 +91,6 @@ function testEdit(aString, aExpected) {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gL10N = null;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gVars;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gVars = gDebugger.DebuggerView.Variables;
@ -38,9 +37,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
});
}
@ -82,7 +79,6 @@ function testModification(aNewValue, aNewResult) {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gVars = null;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_watch-expressions.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gL10N, gEditor, gVars, gWatch;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gL10N = gDebugger.L10N;
@ -44,7 +43,7 @@ function test() {
});
addExpressions();
gDebuggee.ermahgerd();
callInTab(gTab, "ermahgerd");
});
}
@ -494,7 +493,6 @@ function addCmdExpression(aString) {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gL10N = null;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_with-frame.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gPrefs, gOptions, gVariables;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gPrefs = gDebugger.Prefs;
@ -72,7 +71,6 @@ function performTest() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gPrefs = null;

View File

@ -8,13 +8,12 @@
const TAB_URL = EXAMPLE_URL + "doc_with-frame.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gVariables;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gVariables = gDebugger.DebuggerView.Variables;
@ -139,7 +138,6 @@ function performTest() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gVariables = null;

View File

@ -8,16 +8,15 @@
const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gVariables;
function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gVariables = gDebugger.DebuggerView.Variables;
@ -30,9 +29,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
});
}
@ -253,7 +250,6 @@ function testExpandVariables() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gVariables = null;

View File

@ -8,16 +8,15 @@
const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gVariables;
function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gVariables = gDebugger.DebuggerView.Variables;
@ -35,9 +34,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
});
}
@ -543,7 +540,6 @@ function testGetterSetterObject() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gVariables = null;

View File

@ -8,16 +8,15 @@
const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gVariables;
function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gVariables = gDebugger.DebuggerView.Variables;
@ -32,9 +31,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
});
}
@ -148,7 +145,6 @@ function testWindowVariable() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gVariables = null;

View File

@ -7,13 +7,12 @@
const TAB_URL = EXAMPLE_URL + "doc_with-frame.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gVariables;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gVariables = gDebugger.DebuggerView.Variables;
@ -34,9 +33,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
});
}
@ -204,7 +201,6 @@ function testFunctionScope() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gVariables = null;

View File

@ -8,12 +8,11 @@
const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
@ -24,7 +23,7 @@ function test() {
function prepareTest() {
gDebugger.once(gDebugger.EVENTS.FETCHED_SCOPES, runTest);
gDebuggee.eval("(" + function() {
evalInTab(gTab, "(" + function() {
var frozen = Object.freeze({});
var sealed = Object.seal({});
var nonExtensible = Object.preventExtensions({});
@ -83,7 +82,6 @@ function runTest() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
});

View File

@ -8,17 +8,16 @@
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
waitForSourceAndCaretAndScopes(gPanel, ".html", 14).then(performTest);
gDebuggee.simpleCall();
callInTab(gTab, "simpleCall");
});
}
@ -101,7 +100,6 @@ function performTest() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
});

View File

@ -8,13 +8,12 @@
const TAB_URL = EXAMPLE_URL + "doc_large-array-buffer.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gVariables, gEllipsis;
function test() {
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gVariables = gDebugger.DebuggerView.Variables;
@ -29,9 +28,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
});
}
@ -235,7 +232,6 @@ function verifyNextLevels() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gVariables = null;

View File

@ -10,13 +10,12 @@ const TAB_URL = EXAMPLE_URL + "doc_scope-variable-2.html";
function test() {
Task.spawn(function() {
let [tab, debuggee, panel] = yield initDebugger(TAB_URL);
let [tab,, panel] = yield initDebugger(TAB_URL);
let win = panel.panelWin;
let events = win.EVENTS;
let variables = win.DebuggerView.Variables;
// Allow this generator function to yield first.
executeSoon(() => debuggee.test());
callInTab(tab, "test");
yield waitForSourceAndCaretAndScopes(panel, ".html", 23);
let firstScope = variables.getScopeAtIndex(0);

View File

@ -9,7 +9,7 @@ const TAB_URL = EXAMPLE_URL + "doc_scope-variable-2.html";
function test() {
Task.spawn(function() {
let [tab, debuggee, panel] = yield initDebugger(TAB_URL);
let [tab,, panel] = yield initDebugger(TAB_URL);
let win = panel.panelWin;
let events = win.EVENTS;
let variables = win.DebuggerView.Variables;
@ -18,8 +18,7 @@ function test() {
let committedLocalScopeHierarchy = promise.defer();
variables.oncommit = committedLocalScopeHierarchy.resolve;
// Allow this generator function to yield first.
executeSoon(() => debuggee.test());
callInTab(tab, "test");
yield waitForSourceAndCaretAndScopes(panel, ".html", 23);
yield committedLocalScopeHierarchy.promise;

View File

@ -7,16 +7,15 @@
const TAB_URL = EXAMPLE_URL + "doc_with-frame.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gBreakpoints, gSources, gVariables;
function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(4);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gBreakpoints = gDebugger.DebuggerController.Breakpoints;
@ -45,13 +44,7 @@ function addBreakpoint() {
}
function pauseDebuggee() {
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
});
sendMouseClickToTab(gTab, content.document.querySelector("button"));
// The first 'with' scope should be expanded by default, but the
// variables haven't been fetched yet. This is how 'with' scopes work.
@ -200,7 +193,6 @@ function prepareVariablesAndProperties() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gBreakpoints = null;

View File

@ -8,16 +8,15 @@
const TAB_URL = EXAMPLE_URL + "doc_with-frame.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gBreakpoints, gSources, gVariables;
function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(4);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gBreakpoints = gDebugger.DebuggerController.Breakpoints;
@ -46,13 +45,7 @@ function addBreakpoint() {
}
function pauseDebuggee() {
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
});
sendMouseClickToTab(gTab, content.document.querySelector("button"));
// The first 'with' scope should be expanded by default, but the
// variables haven't been fetched yet. This is how 'with' scopes work.
@ -215,7 +208,6 @@ function prepareVariablesAndProperties() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gBreakpoints = null;

View File

@ -7,16 +7,15 @@
const TAB_URL = EXAMPLE_URL + "doc_scope-variable-4.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gBreakpoints, gSources, gVariables;
function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(4);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gBreakpoints = gDebugger.DebuggerController.Breakpoints;
@ -45,11 +44,7 @@ function addBreakpoint() {
}
function pauseDebuggee() {
// Spin the event loop before causing the debuggee to pause, to allow
// this function to return first.
executeSoon(() => {
gDebuggee.test();
});
callInTab(gTab, "test");
return waitForDebuggerEvents(gPanel, gDebugger.EVENTS.FETCHED_SCOPES);
}
@ -120,7 +115,6 @@ function prepareScopes() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gBreakpoints = null;

View File

@ -8,16 +8,15 @@
const TAB_URL = EXAMPLE_URL + "doc_frame-parameters.html";
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gVariables;
function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gVariables = gDebugger.DebuggerView.Variables;
@ -30,9 +29,7 @@ function test() {
ok(false, "Got an error: " + aError.message + "\n" + aError.stack);
});
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
sendMouseClickToTab(gTab, content.document.querySelector("button"));
});
}
@ -253,7 +250,6 @@ function performTest() {
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gVariables = null;

View File

@ -11,12 +11,11 @@ function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gEditor, gWatch, gVariables;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;

View File

@ -11,12 +11,11 @@ function test() {
// Debug test slaves are a bit slow at this test.
requestLongerTimeout(2);
let gTab, gDebuggee, gPanel, gDebugger;
let gTab, gPanel, gDebugger;
let gWatch, gVariables;
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gWatch = gDebugger.DebuggerView.WatchExpressions;
@ -113,7 +112,7 @@ function test() {
aCallback();
});
gDebuggee.test();
callInTab(gTab, "test");
}
function test2(aCallback) {

View File

@ -24,3 +24,10 @@ addMessageListener("test:click", function (message) {
EventUtils.synthesizeMouseAtCenter(target, {},
target.ownerDocument.defaultView);
});
addMessageListener("test:eval", function (message) {
dump("Evalling string " + message.data.string + ".\n");
content.eval(message.data.string);
sendAsyncMessage("test:eval");
});

View File

@ -970,6 +970,15 @@ function callInTab(tab, name) {
waitForMessageFromTab(tab, "test:call");
}
function evalInTab(tab, string) {
info("Evalling string " + string + " in tab.");
sendMessageToTab(tab, "test:eval", {
string: string,
});
waitForMessageFromTab(tab, "test:eval");
}
function sendMouseClickToTab(tab, target) {
info("Sending mouse click to tab.");

View File

@ -13,6 +13,8 @@ var gRGB_TO_HSL = {
"rgb(96, 201, 58)": "hsl(104,57%,51%)",
"rgb(240, 195, 111)": "hsl(39,82%,69%)",
"rgb(227, 155, 22)": "hsl(39,82%,49%)",
"rgb(204, 204, 204)": "hsl(0,0%,80%)",
"rgb(153, 153, 153)": "hsl(0,0%,60%)",
};
let test = Task.async(function*() {

View File

@ -55,7 +55,13 @@ const TIMELINE_BLUEPRINT = {
fill: "hsl(0,0%,80%)",
stroke: "hsl(0,0%,60%)",
label: L10N.getStr("timeline.label.consoleTime")
}
},
"Javascript": {
group: 4,
fill: "hsl(0,0%,80%)",
stroke: "hsl(0,0%,60%)",
label: L10N.getStr("timeline.label.javascript")
},
};
// Exported symbols.

View File

@ -8,9 +8,8 @@ include $(topsrcdir)/config/rules.mk
addondir = $(srcdir)/test/addons
testdir = $(abspath $(DEPTH)/_tests/xpcshell/browser/experiments/test/xpcshell)
libs::
misc:: $(call mkdir_deps,$(testdir))
$(EXIT_ON_ERROR) \
$(NSINSTALL) -D $(testdir); \
for dir in $(addondir)/*; do \
base=`basename $$dir`; \
(cd $$dir && zip -qr $(testdir)/$$base.xpi *); \

View File

@ -2,6 +2,8 @@
# 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/.
HAS_MISC_RULE = True
EXTRA_COMPONENTS += [
'Experiments.manifest',
'ExperimentsService.js',

View File

@ -1,2 +1,6 @@
# 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/.
title=You're browsing privately
title.normal=Open a private window?

View File

@ -38,6 +38,7 @@ timeline.records=RECORDS
timeline.label.styles=Styles
timeline.label.reflow=Reflow
timeline.label.paint=Paint
timeline.label.javascript=Javascript
timeline.label.domevent=DOM Event
timeline.label.consoleTime=Console

View File

@ -12,12 +12,19 @@ public class AnnotationInfo {
public final boolean isMultithreaded;
public final boolean noThrow;
public final boolean narrowChars;
public final boolean catchException;
public AnnotationInfo(String aWrapperName, boolean aIsMultithreaded,
boolean aNoThrow, boolean aNarrowChars) {
boolean aNoThrow, boolean aNarrowChars, boolean aCatchException) {
wrapperName = aWrapperName;
isMultithreaded = aIsMultithreaded;
noThrow = aNoThrow;
narrowChars = aNarrowChars;
catchException = aCatchException;
if (!noThrow && catchException) {
// It doesn't make sense to have these together
throw new IllegalArgumentException("noThrow and catchException are not allowed together");
}
}
}

View File

@ -52,7 +52,7 @@ public class AnnotationProcessor {
"namespace mozilla {\n" +
"namespace widget {\n" +
"namespace android {\n" +
"void InitStubs(JNIEnv *jEnv);\n\n");
"void InitStubs(JNIEnv *env);\n\n");
StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
implementationFile.append("#include \"GeneratedJNIWrappers.h\"\n" +
@ -66,7 +66,7 @@ public class AnnotationProcessor {
// Used to track the calls to the various class-specific initialisation functions.
StringBuilder stubInitialiser = new StringBuilder();
stubInitialiser.append("void InitStubs(JNIEnv *jEnv) {\n");
stubInitialiser.append("void InitStubs(JNIEnv *env) {\n");
while (jarClassIterator.hasNext()) {
ClassWithOptions aClassTuple = jarClassIterator.next();
@ -81,7 +81,7 @@ public class AnnotationProcessor {
}
generatorInstance = new CodeGenerator(aClassTuple.wrappedClass, aClassTuple.generatedName);
stubInitialiser.append(" ").append(aClassTuple.generatedName).append("::InitStubs(jEnv);\n");
stubInitialiser.append(" ").append(aClassTuple.generatedName).append("::InitStubs(env);\n");
// Iterate all annotated members in this class..
while (methodIterator.hasNext()) {

View File

@ -12,6 +12,7 @@ import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.HashSet;
@ -40,21 +41,27 @@ public class CodeGenerator {
private final HashSet<String> mTakenMemberNames = new HashSet<String>();
private int mNameMunger;
private final boolean mLazyInit;
public CodeGenerator(Class<?> aClass, String aGeneratedName) {
this(aClass, aGeneratedName, false);
}
public CodeGenerator(Class<?> aClass, String aGeneratedName, boolean aLazyInit) {
mClassToWrap = aClass;
mCClassName = aGeneratedName;
mLazyInit = aLazyInit;
// Write the file header things. Includes and so forth.
// GeneratedJNIWrappers.cpp is generated as the concatenation of wrapperStartupCode with
// wrapperMethodBodies. Similarly, GeneratedJNIWrappers.h is the concatenation of headerPublic
// with headerProtected.
wrapperStartupCode.append("void ").append(mCClassName).append("::InitStubs(JNIEnv *jEnv) {\n" +
" initInit();\n");
wrapperStartupCode.append("void ").append(mCClassName).append("::InitStubs(JNIEnv *env) {\n");
// Now we write the various GetStaticMethodID calls here...
headerPublic.append("class ").append(mCClassName).append(" : public AutoGlobalWrappedJavaObject {\n" +
"public:\n" +
" static void InitStubs(JNIEnv *jEnv);\n");
" static void InitStubs(JNIEnv *env);\n");
headerProtected.append("protected:");
generateWrapperMethod();
@ -79,7 +86,10 @@ public class CodeGenerator {
private void generateMemberCommon(Member theMethod, String aCMethodName, Class<?> aClass) {
ensureClassHeaderAndStartup(aClass);
writeMemberIdField(theMethod, aCMethodName);
writeStartupCode(theMethod);
if (!mLazyInit) {
writeMemberInit(theMethod, wrapperStartupCode);
}
}
/**
@ -101,8 +111,10 @@ public class CodeGenerator {
Class<?> returnType = theMethod.getReturnType();
// Get the C++ method signature for this method.
String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName, mCClassName, aMethodTuple.mAnnotationInfo.narrowChars);
String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType, CMethodName, mCClassName, isFieldStatic, aMethodTuple.mAnnotationInfo.narrowChars);
String implementationSignature = Utils.getCImplementationMethodSignature(parameterTypes, returnType, CMethodName,
mCClassName, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException);
String headerSignature = Utils.getCHeaderMethodSignature(parameterTypes, theMethod.getParameterAnnotations(), returnType,
CMethodName, mCClassName, isFieldStatic, aMethodTuple.mAnnotationInfo.narrowChars, aMethodTuple.mAnnotationInfo.catchException);
// Add the header signature to the header file.
writeSignatureToHeader(headerSignature);
@ -111,19 +123,25 @@ public class CodeGenerator {
writeMethodBody(implementationSignature, theMethod, mClassToWrap,
aMethodTuple.mAnnotationInfo.isMultithreaded,
aMethodTuple.mAnnotationInfo.noThrow,
aMethodTuple.mAnnotationInfo.narrowChars);
aMethodTuple.mAnnotationInfo.narrowChars,
aMethodTuple.mAnnotationInfo.catchException);
}
private void generateGetterOrSetterBody(Class<?> aFieldType, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) {
private void generateGetterOrSetterBody(Field aField, String aFieldName, boolean aIsFieldStatic, boolean isSetter, boolean aNarrowChars) {
StringBuilder argumentContent = null;
Class<?> fieldType = aField.getType();
if (isSetter) {
Class<?>[] setterArguments = new Class<?>[]{aFieldType};
Class<?>[] setterArguments = new Class<?>[]{fieldType};
// Marshall the argument..
argumentContent = getArgumentMarshalling(setterArguments);
}
boolean isObjectReturningMethod = Utils.isObjectType(aFieldType);
if (mLazyInit) {
writeMemberInit(aField, wrapperMethodBodies);
}
boolean isObjectReturningMethod = Utils.isObjectType(fieldType);
wrapperMethodBodies.append(" ");
if (isSetter) {
wrapperMethodBodies.append("env->Set");
@ -131,7 +149,7 @@ public class CodeGenerator {
wrapperMethodBodies.append("return ");
if (isObjectReturningMethod) {
wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(aFieldType, aNarrowChars)).append(">(");
wrapperMethodBodies.append("static_cast<").append(Utils.getCReturnType(fieldType, aNarrowChars)).append(">(");
}
wrapperMethodBodies.append("env->Get");
@ -140,7 +158,7 @@ public class CodeGenerator {
if (aIsFieldStatic) {
wrapperMethodBodies.append("Static");
}
wrapperMethodBodies.append(Utils.getFieldType(aFieldType))
wrapperMethodBodies.append(Utils.getFieldType(fieldType))
.append("Field(");
// Static will require the class and the field id. Nonstatic, the object and the field id.
@ -181,14 +199,14 @@ public class CodeGenerator {
boolean isFieldFinal = Utils.isMemberFinal(theField);
String getterName = "get" + CFieldName;
String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars);
String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars);
String getterSignature = Utils.getCImplementationMethodSignature(EMPTY_CLASS_ARRAY, fieldType, getterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false);
String getterHeaderSignature = Utils.getCHeaderMethodSignature(EMPTY_CLASS_ARRAY, GETTER_ARGUMENT_ANNOTATIONS, fieldType, getterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false);
writeSignatureToHeader(getterHeaderSignature);
writeFunctionStartupBoilerPlate(getterSignature, true);
generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, false, aFieldTuple.mAnnotationInfo.narrowChars);
generateGetterOrSetterBody(theField, CFieldName, isFieldStatic, false, aFieldTuple.mAnnotationInfo.narrowChars);
// If field not final, also generate a setter function.
if (!isFieldFinal) {
@ -196,14 +214,14 @@ public class CodeGenerator {
Class<?>[] setterArguments = new Class<?>[]{fieldType};
String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars);
String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars);
String setterSignature = Utils.getCImplementationMethodSignature(setterArguments, Void.class, setterName, mCClassName, aFieldTuple.mAnnotationInfo.narrowChars, false);
String setterHeaderSignature = Utils.getCHeaderMethodSignature(setterArguments, SETTER_ARGUMENT_ANNOTATIONS, Void.class, setterName, mCClassName, isFieldStatic, aFieldTuple.mAnnotationInfo.narrowChars, false);
writeSignatureToHeader(setterHeaderSignature);
writeFunctionStartupBoilerPlate(setterSignature, true);
generateGetterOrSetterBody(fieldType, CFieldName, isFieldStatic, true, aFieldTuple.mAnnotationInfo.narrowChars);
generateGetterOrSetterBody(theField, CFieldName, isFieldStatic, true, aFieldTuple.mAnnotationInfo.narrowChars);
}
}
@ -214,8 +232,10 @@ public class CodeGenerator {
generateMemberCommon(theCtor, mCClassName, mClassToWrap);
String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName, mCClassName, aCtorTuple.mAnnotationInfo.narrowChars);
String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName, mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars);
String implementationSignature = Utils.getCImplementationMethodSignature(theCtor.getParameterTypes(), Void.class, CMethodName,
mCClassName, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException);
String headerSignature = Utils.getCHeaderMethodSignature(theCtor.getParameterTypes(), theCtor.getParameterAnnotations(), Void.class, CMethodName,
mCClassName, false, aCtorTuple.mAnnotationInfo.narrowChars, aCtorTuple.mAnnotationInfo.catchException);
// Slice off the "void " from the start of the constructor declaration.
headerSignature = headerSignature.substring(5);
@ -227,13 +247,37 @@ public class CodeGenerator {
// Use the implementation signature to generate the method body...
writeCtorBody(implementationSignature, theCtor,
aCtorTuple.mAnnotationInfo.isMultithreaded,
aCtorTuple.mAnnotationInfo.noThrow);
aCtorTuple.mAnnotationInfo.noThrow,
aCtorTuple.mAnnotationInfo.catchException);
if (theCtor.getParameterTypes().length == 0) {
mHasEncounteredDefaultConstructor = true;
}
}
public void generateMembers(Member[] members) {
for (Member m : members) {
if (!Modifier.isPublic(m.getModifiers())) {
continue;
}
String name = m.getName();
name = name.substring(0, 1).toUpperCase() + name.substring(1);
AnnotationInfo info = new AnnotationInfo(name, true, true, true, true);
AnnotatableEntity entity = new AnnotatableEntity(m, info);
if (m instanceof Constructor) {
generateConstructor(entity);
} else if (m instanceof Method) {
generateMethod(entity);
} else if (m instanceof Field) {
generateField(entity);
} else {
throw new IllegalArgumentException("expected member to be Constructor, Method, or Field");
}
}
}
/**
* Writes the appropriate header and startup code to ensure the existence of a reference to the
* class specified. If this is already done, does nothing.
@ -258,8 +302,7 @@ public class CodeGenerator {
.append(";\n");
// Add startup code to populate it..
wrapperStartupCode.append('\n')
.append(Utils.getStartupLineForClass(aClass));
wrapperStartupCode.append(Utils.getStartupLineForClass(aClass));
seenClasses.add(className);
}
@ -371,14 +414,30 @@ public class CodeGenerator {
return argumentContent;
}
private void writeCatchException() {
wrapperMethodBodies.append(
" if (env->ExceptionCheck()) {\n" +
" env->ExceptionClear();\n" +
" if (aResult) {\n" +
" *aResult = NS_ERROR_FAILURE;\n" +
" }\n" +
" } else if (aResult) {\n" +
" *aResult = NS_OK;\n" +
" }\n\n");
}
private void writeCtorBody(String implementationSignature, Constructor<?> theCtor,
boolean aIsThreaded, boolean aNoThrow) {
boolean aIsThreaded, boolean aNoThrow, boolean aCatchException) {
Class<?>[] argumentTypes = theCtor.getParameterTypes();
writeFunctionStartupBoilerPlate(implementationSignature, aIsThreaded);
writeFramePushBoilerplate(theCtor, false, aNoThrow);
if (mLazyInit) {
writeMemberInit(theCtor, wrapperMethodBodies);
}
// Marshall arguments for this constructor, if any...
boolean hasArguments = argumentTypes.length != 0;
@ -402,9 +461,14 @@ public class CodeGenerator {
wrapperMethodBodies.append(mMembersToIds.get(theCtor))
// Tack on the arguments, if any..
.append(argumentContent)
.append("), env);\n" +
" env->PopLocalFrame(nullptr);\n" +
"}\n");
.append("), env);\n");
// Check for exception and set aResult
if (aCatchException) {
writeCatchException();
}
wrapperMethodBodies.append(" env->PopLocalFrame(nullptr);\n}\n");
}
/**
@ -417,7 +481,8 @@ public class CodeGenerator {
*/
private void writeMethodBody(String methodSignature, Method aMethod,
Class<?> aClass, boolean aIsMultithreaded,
boolean aNoThrow, boolean aNarrowChars) {
boolean aNoThrow, boolean aNarrowChars,
boolean aCatchException) {
Class<?>[] argumentTypes = aMethod.getParameterTypes();
Class<?> returnType = aMethod.getReturnType();
@ -427,6 +492,10 @@ public class CodeGenerator {
writeFramePushBoilerplate(aMethod, isObjectReturningMethod, aNoThrow);
if (mLazyInit) {
writeMemberInit(aMethod, wrapperMethodBodies);
}
// Marshall arguments, if we have any.
boolean hasArguments = argumentTypes.length != 0;
@ -481,6 +550,11 @@ public class CodeGenerator {
wrapperMethodBodies.append(" AndroidBridge::HandleUncaughtException(env);\n");
}
// Check for exception and set aResult
if (aCatchException) {
writeCatchException();
}
// If we're returning an object, pop the callee's stack frame extracting our ref as the return
// value.
if (isObjectReturningMethod) {
@ -501,33 +575,41 @@ public class CodeGenerator {
}
/**
* Generates the code to get the id of the given member on startup.
* Generates the code to get the id of the given member on startup or in the member body if lazy init
* is requested.
*
* @param aMember The Java member being wrapped.
*/
private void writeStartupCode(Member aMember) {
wrapperStartupCode.append(" ")
.append(mMembersToIds.get(aMember))
.append(" = get");
private void writeMemberInit(Member aMember, StringBuilder aOutput) {
if (mLazyInit) {
aOutput.append(" if (!" + mMembersToIds.get(aMember) + ") {\n ");
}
aOutput.append(" " + mMembersToIds.get(aMember)).append(" = AndroidBridge::Get");
if (Utils.isMemberStatic(aMember)) {
wrapperStartupCode.append("Static");
aOutput.append("Static");
}
boolean isField = aMember instanceof Field;
if (isField) {
wrapperStartupCode.append("Field(\"");
aOutput.append("FieldID(env, " + Utils.getClassReferenceName(aMember.getDeclaringClass()) + ", \"");
} else {
wrapperStartupCode.append("Method(\"");
}
if (aMember instanceof Constructor) {
wrapperStartupCode.append("<init>");
} else {
wrapperStartupCode.append(aMember.getName());
aOutput.append("MethodID(env, " + Utils.getClassReferenceName(aMember.getDeclaringClass()) + ", \"");
}
wrapperStartupCode.append("\", \"")
if (aMember instanceof Constructor) {
aOutput.append("<init>");
} else {
aOutput.append(aMember.getName());
}
aOutput.append("\", \"")
.append(Utils.getTypeSignatureStringForMember(aMember))
.append("\");\n");
if (mLazyInit) {
aOutput.append(" }\n\n");
}
}
private void writeZeroingFor(Member aMember, final String aMemberName) {

View File

@ -4,9 +4,9 @@
include $(topsrcdir)/config/rules.mk
JAVA_CLASSPATH := $(ANDROID_SDK)/android.jar
JAVA_CLASSPATH := $(ANDROID_SDK)/android.jar:$(ANDROID_SDK)/../../tools/lib/lint.jar:$(ANDROID_SDK)/../../tools/lib/lint-checks.jar
# Include Android specific java flags, instead of what's in rules.mk.
include $(topsrcdir)/config/android-common.mk
libs:: annotationProcessors.jar
export:: annotationProcessors.jar

View File

@ -0,0 +1,255 @@
/* 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/. */
package org.mozilla.gecko.annotationProcessors;
import com.android.tools.lint.checks.ApiLookup;
import com.android.tools.lint.LintCliClient;
import org.mozilla.gecko.annotationProcessors.classloader.AnnotatableEntity;
import org.mozilla.gecko.annotationProcessors.classloader.ClassWithOptions;
import org.mozilla.gecko.annotationProcessors.classloader.IterableJarLoadingURLClassLoader;
import org.mozilla.gecko.annotationProcessors.utils.GeneratableElementIterator;
import org.mozilla.gecko.annotationProcessors.utils.Utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Properties;
import java.util.Scanner;
import java.util.Vector;
import java.net.URL;
import java.net.URLClassLoader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class SDKProcessor {
public static final String GENERATED_COMMENT =
"// GENERATED CODE\n" +
"// Generated by the Java program at /build/annotationProcessors at compile time from\n" +
"// annotations on Java methods. To update, change the annotations on the corresponding Java\n" +
"// methods and rerun the build. Manually updating this file will cause your build to fail.\n\n";
private static ApiLookup sApiLookup;
private static int sMaxSdkVersion;
public static void main(String[] args) {
// We expect a list of jars on the commandline. If missing, whinge about it.
if (args.length < 5) {
System.err.println("Usage: java SDKProcessor sdkjar classlistfile outdir fileprefix max-sdk-version");
System.exit(1);
}
System.out.println("Processing platform bindings...");
String sdkJar = args[0];
Vector classes = getClassList(args[1]);
String outdir = args[2];
String generatedFilePrefix = args[3];
sMaxSdkVersion = Integer.parseInt(args[4]);
Properties props = System.getProperties();
props.setProperty("com.android.tools.lint.bindir",
new File(new File(sdkJar).getParentFile(), "../../tools").toString());
LintCliClient lintClient = new LintCliClient();
sApiLookup = ApiLookup.get(lintClient);
// Start the clock!
long s = System.currentTimeMillis();
// Get an iterator over the classes in the jar files given...
// Iterator<ClassWithOptions> jarClassIterator = IterableJarLoadingURLClassLoader.getIteratorOverJars(args);
StringBuilder headerFile = new StringBuilder(GENERATED_COMMENT);
headerFile.append("#ifndef " + generatedFilePrefix + "_h__\n" +
"#define " + generatedFilePrefix + "_h__\n" +
"#include \"nsXPCOMStrings.h\"\n" +
"#include \"AndroidJavaWrappers.h\"\n" +
"\n" +
"namespace mozilla {\n" +
"namespace widget {\n" +
"namespace android {\n" +
"namespace sdk {\n" +
"void Init" + generatedFilePrefix + "Stubs(JNIEnv *jEnv);\n\n");
StringBuilder implementationFile = new StringBuilder(GENERATED_COMMENT);
implementationFile.append("#include \"" + generatedFilePrefix + ".h\"\n" +
"#include \"AndroidBridgeUtilities.h\"\n" +
"#include \"nsXPCOMStrings.h\"\n" +
"#include \"AndroidBridge.h\"\n" +
"\n" +
"namespace mozilla {\n" +
"namespace widget {\n" +
"namespace android {\n" +
"namespace sdk {\n");
// Used to track the calls to the various class-specific initialisation functions.
StringBuilder stubInitializer = new StringBuilder();
stubInitializer.append("void Init" + generatedFilePrefix + "Stubs(JNIEnv *jEnv) {\n");
ClassLoader loader = null;
try {
loader = URLClassLoader.newInstance(new URL[] { new URL("file://" + sdkJar) },
SDKProcessor.class.getClassLoader());
} catch (Exception e) {
System.out.println(e);
}
for (Iterator<String> i = classes.iterator(); i.hasNext(); ) {
String className = i.next();
System.out.println("Looking up: " + className);
try {
Class<?> c = Class.forName(className, true, loader);
generateClass(Class.forName(className, true, loader),
stubInitializer,
implementationFile,
headerFile);
} catch (Exception e) {
System.out.println("Failed to generate class " + className + ": " + e);
}
}
implementationFile.append('\n');
stubInitializer.append("}");
implementationFile.append(stubInitializer);
implementationFile.append("\n} /* sdk */\n" +
"} /* android */\n" +
"} /* widget */\n" +
"} /* mozilla */\n");
headerFile.append("\n} /* sdk */\n" +
"} /* android */\n" +
"} /* widget */\n" +
"} /* mozilla */\n" +
"#endif\n");
writeOutputFiles(outdir, generatedFilePrefix, headerFile, implementationFile);
long e = System.currentTimeMillis();
System.out.println("SDK processing complete in " + (e - s) + "ms");
}
private static Member[] sortAndFilterMembers(Member[] members) {
Arrays.sort(members, new Comparator<Member>() {
@Override
public int compare(Member a, Member b) {
return a.getName().compareTo(b.getName());
}
});
ArrayList<Member> list = new ArrayList<>();
for (Member m : members) {
int version = 0;
if (m instanceof Method || m instanceof Constructor) {
version = sApiLookup.getCallVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()),
m.getName(),
Utils.getTypeSignatureStringForMember(m));
} else if (m instanceof Field) {
version = sApiLookup.getFieldVersion(Utils.getTypeSignatureStringForClass(m.getDeclaringClass()),
m.getName());
} else {
throw new IllegalArgumentException("expected member to be Method, Constructor, or Field");
}
if (version > sMaxSdkVersion) {
System.out.println("Skipping " + m.getDeclaringClass().getName() + "." + m.getName() +
", version " + version + " > " + sMaxSdkVersion);
continue;
}
list.add(m);
}
return list.toArray(new Member[list.size()]);
}
private static void generateClass(Class<?> clazz,
StringBuilder stubInitializer,
StringBuilder implementationFile,
StringBuilder headerFile) {
String generatedName = clazz.getSimpleName();
CodeGenerator generator = new CodeGenerator(clazz, generatedName, true);
stubInitializer.append(" ").append(generatedName).append("::InitStubs(jEnv);\n");
generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredConstructors()));
generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredMethods()));
generator.generateMembers(sortAndFilterMembers(clazz.getDeclaredFields()));
headerFile.append(generator.getHeaderFileContents());
implementationFile.append(generator.getWrapperFileContents());
}
private static Vector<String> getClassList(String path) {
Scanner scanner = null;
try {
scanner = new Scanner(new FileInputStream(path));
Vector lines = new Vector();
while (scanner.hasNextLine()) {
lines.add(scanner.nextLine());
}
return lines;
} catch (Exception e) {
System.out.println(e.toString());
return null;
} finally {
if (scanner != null) {
scanner.close();
}
}
}
private static void writeOutputFiles(String aOutputDir, String aPrefix, StringBuilder aHeaderFile,
StringBuilder aImplementationFile) {
FileOutputStream implStream = null;
try {
implStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".cpp"));
implStream.write(aImplementationFile.toString().getBytes());
} catch (IOException e) {
System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?");
e.printStackTrace(System.err);
} finally {
if (implStream != null) {
try {
implStream.close();
} catch (IOException e) {
System.err.println("Unable to close implStream due to "+e);
e.printStackTrace(System.err);
}
}
}
FileOutputStream headerStream = null;
try {
headerStream = new FileOutputStream(new File(aOutputDir, aPrefix + ".h"));
headerStream.write(aHeaderFile.toString().getBytes());
} catch (IOException e) {
System.err.println("Unable to write " + aOutputDir + ". Perhaps a permissions issue?");
e.printStackTrace(System.err);
} finally {
if (headerStream != null) {
try {
headerStream.close();
} catch (IOException e) {
System.err.println("Unable to close headerStream due to "+e);
e.printStackTrace(System.err);
}
}
}
}
}

View File

@ -13,6 +13,7 @@ jar.sources += [
'classloader/IterableJarLoadingURLClassLoader.java',
'classloader/JarClassIterator.java',
'CodeGenerator.java',
'SDKProcessor.java',
'utils/AlphabeticAnnotatableEntityComparator.java',
'utils/GeneratableElementIterator.java',
'utils/Utils.java',

View File

@ -76,6 +76,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
boolean isMultithreadedStub = false;
boolean noThrow = false;
boolean narrowChars = false;
boolean catchException = false;
try {
// Determine the explicitly-given name of the stub to generate, if any.
final Method stubNameMethod = annotationType.getDeclaredMethod("stubName");
@ -97,6 +98,11 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
narrowCharsMethod.setAccessible(true);
narrowChars = (Boolean) narrowCharsMethod.invoke(annotation);
// Determine if we should catch exceptions
final Method catchExceptionMethod = annotationType.getDeclaredMethod("catchException");
catchExceptionMethod.setAccessible(true);
catchException = (Boolean) catchExceptionMethod.invoke(annotation);
} catch (NoSuchMethodException e) {
System.err.println("Unable to find expected field on WrapElementForJNI annotation. Did the signature change?");
e.printStackTrace(System.err);
@ -118,7 +124,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
}
AnnotationInfo annotationInfo = new AnnotationInfo(
stubName, isMultithreadedStub, noThrow, narrowChars);
stubName, isMultithreadedStub, noThrow, narrowChars, catchException);
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
return;
}
@ -128,7 +134,7 @@ public class GeneratableElementIterator implements Iterator<AnnotatableEntity> {
// thanks to the "Generate everything" annotation.
if (mIterateEveryEntry) {
AnnotationInfo annotationInfo = new AnnotationInfo(
candidateElement.getName(), false, false, false);
candidateElement.getName(), false, false, false, false);
mNextReturnValue = new AnnotatableEntity(candidateElement, annotationInfo);
return;
}

View File

@ -318,6 +318,10 @@ public class Utils {
}
}
public static String getTypeSignatureStringForClass(Class<?> clazz) {
return clazz.getCanonicalName().replace('.', '/');
}
public static String getTypeSignatureString(Constructor<?> aConstructor) {
Class<?>[] arguments = aConstructor.getParameterTypes();
StringBuilder sb = new StringBuilder();
@ -341,7 +345,7 @@ public class Utils {
* @param c The type of the element to write the subsignature of.
*/
private static void writeTypeSignature(StringBuilder sb, Class<?> c) {
String name = c.getCanonicalName().replaceAll("\\.", "/");
String name = Utils.getTypeSignatureStringForClass(c);
// Determine if this is an array type and, if so, peel away the array operators..
int len = name.length();
@ -384,7 +388,8 @@ public class Utils {
* @param aCClassName Name of the C++ class into which the method is declared.
* @return The C++ method implementation signature for the method described.
*/
public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aNarrowChars) {
public static String getCImplementationMethodSignature(Class<?>[] aArgumentTypes, Class<?> aReturnType,
String aCMethodName, String aCClassName, boolean aNarrowChars, boolean aCatchException) {
StringBuilder retBuffer = new StringBuilder();
retBuffer.append(getCReturnType(aReturnType, aNarrowChars));
@ -406,6 +411,14 @@ public class Utils {
retBuffer.append(", ");
}
}
if (aCatchException) {
if (aArgumentTypes.length > 0) {
retBuffer.append(", ");
}
retBuffer.append("nsresult* aResult");
}
retBuffer.append(')');
return retBuffer.toString();
}
@ -423,7 +436,8 @@ public class Utils {
* @param aIsStaticStub true if the generated C++ method should be static, false otherwise.
* @return The generated C++ header method signature for the method described.
*/
public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType, String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars) {
public static String getCHeaderMethodSignature(Class<?>[] aArgumentTypes, Annotation[][] aArgumentAnnotations, Class<?> aReturnType,
String aCMethodName, String aCClassName, boolean aIsStaticStub, boolean aNarrowChars, boolean aCatchException) {
StringBuilder retBuffer = new StringBuilder();
// Add the static keyword, if applicable.
@ -453,6 +467,14 @@ public class Utils {
retBuffer.append(", ");
}
}
if (aCatchException) {
if (aArgumentTypes.length > 0) {
retBuffer.append(", ");
}
retBuffer.append("nsresult* aResult = nullptr");
}
retBuffer.append(')');
return retBuffer.toString();
}
@ -587,9 +609,9 @@ public class Utils {
StringBuilder sb = new StringBuilder();
sb.append(" ");
sb.append(getClassReferenceName(aClass));
sb.append(" = getClassGlobalRef(\"");
sb.append(" = AndroidBridge::GetClassGlobalRef(env, \"");
String name = aClass.getCanonicalName().replaceAll("\\.", "/");
String name = Utils.getTypeSignatureStringForClass(aClass);
Class<?> containerClass = aClass.getDeclaringClass();
if (containerClass != null) {
// Is an inner class. Add the $ symbol.

View File

@ -41,7 +41,7 @@ public class FennecNativeActions implements Actions {
}
class GeckoEventExpecter implements RepeatedEventExpecter {
private static final int MAX_WAIT_MS = 90000;
private static final int MAX_WAIT_MS = 180000;
private volatile boolean mIsRegistered;

View File

@ -141,6 +141,10 @@ ifeq (.,$(DEPTH))
# Interdependencies for parallel export.
js/xpconnect/src/export: dom/bindings/export xpcom/xpidl/export
accessible/xpcom/export: xpcom/xpidl/export
# The widget binding generator code is part of the annotationProcessors.
widget/android/bindings/export: build/annotationProcessors/export
ifdef ENABLE_CLANG_PLUGIN
$(filter-out build/clang-plugin/%,$(compile_targets)): build/clang-plugin/target build/clang-plugin/tests/target
build/clang-plugin/tests/target: build/clang-plugin/target

View File

@ -1459,6 +1459,7 @@ if test "$GNU_CC"; then
# -Wignored-qualifiers - catches returns types with qualifiers like const
# -Wint-to-pointer-cast - catches cast to pointer from integer of different size
# -Wmultichar - catches multicharacter integer constants like 'THIS'
# -Wnon-literal-null-conversion - catches expressions used as a null pointer constant
# -Wnonnull - catches NULL used with functions arguments marked as non-null
# -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
# -Wpointer-sign - catches mixing pointers to signed and unsigned types
@ -1493,6 +1494,8 @@ if test "$GNU_CC"; then
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=sequence-point"
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=trigraphs"
_WARNINGS_CFLAGS="${_WARNINGS_CFLAGS} -Werror=unknown-pragmas"
MOZ_C_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_c_has_werror_non_literal_null_conversion)
fi
# Turn off the following warnings that -Wall turns on:
@ -1552,6 +1555,7 @@ if test "$GNU_CXX"; then
# -Wendif-labels - catches `#else FOO` and `#endif FOO` not in comment
# -Wint-to-pointer-cast - catches cast to pointer from integer of different size
# -Wmissing-braces - catches aggregate initializers missing nested braces
# -Wnon-literal-null-conversion - catches expressions used as a null pointer constant
# -Woverloaded-virtual - function declaration hides virtual function from base class
# -Wparentheses - catches `if (a=b)` and operator precedence bugs
# -Wpointer-arith - catches pointer arithmetic using NULL or sizeof(void)
@ -1583,6 +1587,8 @@ if test "$GNU_CXX"; then
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=trigraphs"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=type-limits"
_WARNINGS_CXXFLAGS="${_WARNINGS_CXXFLAGS} -Werror=unused-label"
MOZ_CXX_SUPPORTS_WARNING(-Werror=, non-literal-null-conversion, ac_cxx_has_werror_non_literal_null_conversion)
fi
# Turn off the following warnings that -Wall turns on:

View File

@ -854,7 +854,8 @@ nsDocShell::nsDocShell():
mDefaultLoadFlags(nsIRequest::LOAD_NORMAL),
mFrameType(eFrameTypeRegular),
mOwnOrContainingAppId(nsIScriptSecurityManager::UNKNOWN_APP_ID),
mParentCharsetSource(0)
mParentCharsetSource(0),
mJSRunToCompletionDepth(0)
{
mHistoryID = ++gDocshellIDCounter;
if (gDocShellCount++ == 0) {
@ -890,6 +891,8 @@ nsDocShell::nsDocShell():
nsDocShell::~nsDocShell()
{
MOZ_ASSERT(!mProfileTimelineRecording);
Destroy();
nsCOMPtr<nsISHistoryInternal>
@ -2829,14 +2832,15 @@ NS_IMETHODIMP
nsDocShell::SetRecordProfileTimelineMarkers(bool aValue)
{
#ifdef MOZ_ENABLE_PROFILER_SPS
bool currentValue;
GetRecordProfileTimelineMarkers(&currentValue);
bool currentValue = nsIDocShell::GetRecordProfileTimelineMarkers();
if (currentValue != aValue) {
if (aValue) {
++gProfileTimelineRecordingsCount;
UseEntryScriptProfiling();
mProfileTimelineRecording = true;
} else {
--gProfileTimelineRecordingsCount;
UnuseEntryScriptProfiling();
mProfileTimelineRecording = false;
ClearProfileTimelineMarkers();
}
@ -4243,25 +4247,41 @@ nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
int32_t aChildOffset, uint32_t loadType,
bool aCloneChildren)
{
nsresult rv;
nsresult rv = NS_OK;
if (mLSHE && loadType != LOAD_PUSHSTATE && !aCloneRef) {
if (mLSHE && loadType != LOAD_PUSHSTATE) {
/* You get here if you are currently building a
* hierarchy ie.,you just visited a frameset page
*/
nsCOMPtr<nsISHContainer> container(do_QueryInterface(mLSHE, &rv));
if (container) {
if (NS_FAILED(container->ReplaceChild(aNewEntry))) {
rv = container->AddChild(aNewEntry, aChildOffset);
}
}
}
else if (!aCloneRef) {
/* This is an initial load in some subframe. Just append it if we can */
nsCOMPtr<nsISHContainer> container(do_QueryInterface(mOSHE, &rv));
if (container) {
rv = container->AddChild(aNewEntry, aChildOffset);
}
} else {
rv = AddChildSHEntryInternal(aCloneRef, aNewEntry, aChildOffset,
loadType, aCloneChildren);
}
else if (mSessionHistory) {
return rv;
}
nsresult
nsDocShell::AddChildSHEntryInternal(nsISHEntry* aCloneRef,
nsISHEntry* aNewEntry,
int32_t aChildOffset,
uint32_t aLoadType,
bool aCloneChildren)
{
nsresult rv = NS_OK;
if (mSessionHistory) {
/* You are currently in the rootDocShell.
* You will get here when a subframe has a new url
* to load and you have walked up the tree all the
@ -4300,15 +4320,16 @@ nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
nsCOMPtr<nsIDocShell> parent =
do_QueryInterface(GetAsSupports(mParent), &rv);
if (parent) {
rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset,
loadType, aCloneChildren);
rv = static_cast<nsDocShell*>(parent.get())->
AddChildSHEntryInternal(aCloneRef, aNewEntry, aChildOffset,
aLoadType, aCloneChildren);
}
}
return rv;
}
nsresult
nsDocShell::DoAddChildSHEntry(nsISHEntry* aNewEntry, int32_t aChildOffset,
nsDocShell::AddChildSHEntryToParent(nsISHEntry* aNewEntry, int32_t aChildOffset,
bool aCloneChildren)
{
/* You will get here when you are in a subframe and
@ -11653,7 +11674,7 @@ nsDocShell::AddToSessionHistory(nsIURI * aURI, nsIChannel * aChannel,
// This is a subframe.
if (!mOSHE || !LOAD_TYPE_HAS_FLAGS(mLoadType,
LOAD_FLAGS_REPLACE_HISTORY))
rv = DoAddChildSHEntry(entry, mChildOffset, aCloneChildren);
rv = AddChildSHEntryToParent(entry, mChildOffset, aCloneChildren);
}
// Return the new SH entry...
@ -13591,6 +13612,30 @@ nsDocShell::GetURLSearchParams()
return mURLSearchParams;
}
void
nsDocShell::NotifyJSRunToCompletionStart()
{
bool timelineOn = nsIDocShell::GetRecordProfileTimelineMarkers();
// If first start, mark interval start.
if (timelineOn && mJSRunToCompletionDepth == 0) {
AddProfileTimelineMarker("Javascript", TRACING_INTERVAL_START);
}
mJSRunToCompletionDepth++;
}
void
nsDocShell::NotifyJSRunToCompletionStop()
{
bool timelineOn = nsIDocShell::GetRecordProfileTimelineMarkers();
// If last stop, mark interval end.
mJSRunToCompletionDepth--;
if (timelineOn && mJSRunToCompletionDepth == 0) {
AddProfileTimelineMarker("Javascript", TRACING_INTERVAL_END);
}
}
void
nsDocShell::MaybeNotifyKeywordSearchLoading(const nsString &aProvider,
const nsString &aKeyword) {

View File

@ -371,7 +371,11 @@ protected:
nsISupports* aOwner,
bool aCloneChildren,
nsISHEntry ** aNewEntry);
nsresult DoAddChildSHEntry(nsISHEntry* aNewEntry, int32_t aChildOffset,
nsresult AddChildSHEntryToParent(nsISHEntry* aNewEntry, int32_t aChildOffset,
bool aCloneChildren);
nsresult AddChildSHEntryInternal(nsISHEntry* aCloneRef, nsISHEntry* aNewEntry,
int32_t aChildOffset, uint32_t loadType,
bool aCloneChildren);
NS_IMETHOD LoadHistoryEntry(nsISHEntry * aEntry, uint32_t aLoadType);
@ -946,6 +950,10 @@ private:
nsWeakPtr mOpener;
nsWeakPtr mOpenedRemote;
// A depth count of how many times NotifyRunToCompletionStart
// has been called without a matching NotifyRunToCompletionStop.
uint32_t mJSRunToCompletionDepth;
// True if recording profiles.
bool mProfileTimelineRecording;

View File

@ -54,7 +54,7 @@ interface nsITabParent;
typedef unsigned long nsLoadFlags;
[scriptable, builtinclass, uuid(da8f78f1-8f20-4d6d-be56-fe53e177b630)]
[scriptable, builtinclass, uuid(4e3de242-0b2a-4cf0-81b5-a5fe8628431c)]
interface nsIDocShell : nsIDocShellTreeItem
{
/**
@ -1026,6 +1026,14 @@ interface nsIDocShell : nsIDocShellTreeItem
// URLSearchParams for the window.location is owned by the docShell.
[noscript,notxpcom] URLSearchParams getURLSearchParams();
/**
* Notify DocShell when the browser is about to start executing JS, and after
* that execution has stopped. This only occurs when the Timeline devtool
* is collecting information.
*/
[noscript,notxpcom,nostdcall] void notifyJSRunToCompletionStart();
[noscript,notxpcom,nostdcall] void notifyJSRunToCompletionStop();
/**
* This attribute determines whether a document which is not about:blank has
* already be loaded by this docShell.

View File

@ -14,7 +14,7 @@ interface nsISHEntry;
*
*/
[scriptable, uuid(65281BA2-988A-11d3-BDC7-0050040A9B44)]
[scriptable, uuid(67dd0357-8372-4122-bff6-217435e8b7e4)]
interface nsISHContainer : nsISupports
{
/**
@ -38,5 +38,12 @@ interface nsISHContainer : nsISupports
*/
nsISHEntry GetChildAt(in long index);
/**
* Replaces a child which is for the same docshell as aNewChild
* with aNewChild.
* @throw if nothing was replaced.
*/
void ReplaceChild(in nsISHEntry aNewChild);
};

View File

@ -690,6 +690,27 @@ nsSHEntry::GetChildAt(int32_t aIndex, nsISHEntry ** aResult)
return NS_OK;
}
NS_IMETHODIMP
nsSHEntry::ReplaceChild(nsISHEntry* aNewEntry)
{
NS_ENSURE_STATE(aNewEntry);
uint64_t docshellID;
aNewEntry->GetDocshellID(&docshellID);
uint64_t otherID;
for (int32_t i = 0; i < mChildren.Count(); ++i) {
if (mChildren[i] && NS_SUCCEEDED(mChildren[i]->GetDocshellID(&otherID)) &&
docshellID == otherID) {
mChildren[i]->SetParent(nullptr);
if (mChildren.ReplaceObjectAt(aNewEntry, i)) {
return aNewEntry->SetParent(this);
}
}
}
return NS_ERROR_FAILURE;
}
NS_IMETHODIMP
nsSHEntry::AddChildShell(nsIDocShellTreeItem *aShell)
{

View File

@ -0,0 +1,28 @@
<html>
<head>
<script>
function nestedIframeLoaded() {
var tf = document.getElementById("testframe");
var innerf = tf.contentDocument.getElementsByTagName("iframe")[0];
if (innerf.contentDocument.documentURI.indexOf("frame0") < 0) {
innerf.contentWindow.location.href = "http://mochi.test:8888/tests/docshell/test/navigation/frame0.html";
return;
}
innerf.onload = null;
innerf.src = "about:blank";
var d = innerf.contentDocument;
d.open();
d.write("test");
d.close();
opener.is(window.history.length, 1, "Unexpected history length");
opener.nextTest();
window.close();
}
</script>
</head>
<body>
<iframe id="testframe" src="data:text/html,<iframe onload='parent.nestedIframeLoaded();'></iframe>" onload="frameLoaded()"></iframe>
<script>
</script>
</body>
</html>

View File

@ -9,6 +9,7 @@ support-files =
file_bug534178.html
file_document_write_1.html
file_fragment_handling_during_load.html
file_nested_frames.html
file_static_and_dynamic_1.html
frame0.html
frame1.html

View File

@ -27,7 +27,8 @@ var testFiles =
"file_document_write_1.html", // Session history + document.write
//"file_static_and_dynamic_1.html",// Static and dynamic frames and forward-back
"file_bug534178.html", // Session history transaction clean-up.
"file_fragment_handling_during_load.html"
"file_fragment_handling_during_load.html",
"file_nested_frames.html"
];
var testCount = 0; // Used by the test files.

View File

@ -12,6 +12,7 @@
#include "xpcprivate.h" // For AutoCxPusher guts
#include "xpcpublic.h"
#include "nsIGlobalObject.h"
#include "nsIDocShell.h"
#include "nsIScriptGlobalObject.h"
#include "nsIScriptContext.h"
#include "nsContentUtils.h"
@ -70,8 +71,26 @@ public:
ScriptSettingsStackEntry *entry = EntryPoint();
return entry ? entry->mGlobalObject : nullptr;
}
};
static unsigned long gRunToCompletionListeners = 0;
void
UseEntryScriptProfiling()
{
MOZ_ASSERT(NS_IsMainThread());
++gRunToCompletionListeners;
}
void
UnuseEntryScriptProfiling()
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(gRunToCompletionListeners > 0);
--gRunToCompletionListeners;
}
void
InitScriptSettings()
{
@ -122,10 +141,44 @@ ScriptSettingsStackEntry::~ScriptSettingsStackEntry()
ScriptSettingsStack::Pop(this);
}
// If the entry or incumbent global ends up being something that the subject
// principal doesn't subsume, we don't want to use it. This never happens on
// the web, but can happen with asymmetric privilege relationships (i.e.
// nsExpandedPrincipal and System Principal).
//
// The most correct thing to use instead would be the topmost global on the
// callstack whose principal is subsumed by the subject principal. But that's
// hard to compute, so we just substitute the global of the current
// compartment. In practice, this is fine.
//
// Note that in particular things like:
//
// |SpecialPowers.wrap(crossOriginWindow).eval(open())|
//
// trigger this case. Although both the entry global and the current global
// have normal principals, the use of Gecko-specific System-Principaled JS
// puts the code from two different origins on the callstack at once, which
// doesn't happen normally on the web.
static nsIGlobalObject*
ClampToSubject(nsIGlobalObject* aGlobalOrNull)
{
if (!aGlobalOrNull || !NS_IsMainThread()) {
return aGlobalOrNull;
}
nsIPrincipal* globalPrin = aGlobalOrNull->PrincipalOrNull();
NS_ENSURE_TRUE(globalPrin, GetCurrentGlobal());
if (!nsContentUtils::SubjectPrincipal()->SubsumesConsideringDomain(globalPrin)) {
return GetCurrentGlobal();
}
return aGlobalOrNull;
}
nsIGlobalObject*
GetEntryGlobal()
{
return ScriptSettingsStack::EntryGlobal();
return ClampToSubject(ScriptSettingsStack::EntryGlobal());
}
nsIDocument*
@ -163,12 +216,12 @@ GetIncumbentGlobal()
// there's nothing on the JS stack, which will cause us to check the
// incumbent script stack below.
if (JSObject *global = JS::GetScriptedCallerGlobal(cx)) {
return xpc::NativeGlobal(global);
return ClampToSubject(xpc::NativeGlobal(global));
}
// Ok, nothing from the JS engine. Let's use whatever's on the
// explicit stack.
return ScriptSettingsStack::IncumbentGlobal();
return ClampToSubject(ScriptSettingsStack::IncumbentGlobal());
}
nsIGlobalObject*
@ -463,14 +516,30 @@ AutoEntryScript::AutoEntryScript(nsIGlobalObject* aGlobalObject,
aCx ? aCx : FindJSContext(aGlobalObject))
, ScriptSettingsStackEntry(aGlobalObject, /* aCandidate = */ true)
, mWebIDLCallerPrincipal(nullptr)
, mDocShellForJSRunToCompletion(nullptr)
{
MOZ_ASSERT(aGlobalObject);
MOZ_ASSERT_IF(!aCx, aIsMainThread); // cx is mandatory off-main-thread.
MOZ_ASSERT_IF(aCx && aIsMainThread, aCx == FindJSContext(aGlobalObject));
if (aIsMainThread && gRunToCompletionListeners > 0) {
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aGlobalObject);
if (window) {
mDocShellForJSRunToCompletion = window->GetDocShell();
}
}
if (mDocShellForJSRunToCompletion) {
mDocShellForJSRunToCompletion->NotifyJSRunToCompletionStart();
}
}
AutoEntryScript::~AutoEntryScript()
{
if (mDocShellForJSRunToCompletion) {
mDocShellForJSRunToCompletion->NotifyJSRunToCompletionStop();
}
// GC when we pop a script entry point. This is a useful heuristic that helps
// us out on certain (flawed) benchmarks like sunspider, because it lets us
// avoid GCing during the timing loop.

View File

@ -21,6 +21,7 @@ class nsPIDOMWindow;
class nsGlobalWindow;
class nsIScriptContext;
class nsIDocument;
class nsIDocShell;
namespace mozilla {
namespace dom {
@ -63,6 +64,16 @@ private:
void InitScriptSettings();
void DestroyScriptSettings();
/*
* Static helpers in ScriptSettings which track the number of listeners
* of Javascript RunToCompletion events. These should be used by the code in
* nsDocShell::SetRecordProfileTimelineMarkers to indicate to script
* settings that script run-to-completion needs to be monitored.
* SHOULD BE CALLED ONLY BY MAIN THREAD.
*/
void UseEntryScriptProfiling();
void UnuseEntryScriptProfiling();
// To implement a web-compatible browser, it is often necessary to obtain the
// global object that is "associated" with the currently-running code. This
// process is made more complicated by the fact that, historically, different
@ -331,6 +342,8 @@ private:
// can't go away until then either.
nsIPrincipal* mWebIDLCallerPrincipal;
friend nsIPrincipal* GetWebIDLCallerPrincipal();
nsIDocShell* mDocShellForJSRunToCompletion;
};
/*

View File

@ -415,8 +415,6 @@ nsDOMWindowUtils::SetDisplayPortMarginsForElement(float aLeftMargin,
float aTopMargin,
float aRightMargin,
float aBottomMargin,
uint32_t aAlignmentX,
uint32_t aAlignmentY,
nsIDOMElement* aElement,
uint32_t aPriority)
{
@ -451,7 +449,7 @@ nsDOMWindowUtils::SetDisplayPortMarginsForElement(float aLeftMargin,
aLeftMargin);
nsLayoutUtils::SetDisplayPortMargins(content, presShell, displayportMargins,
aAlignmentX, aAlignmentY, aPriority);
aPriority);
return NS_OK;
}

View File

@ -2412,9 +2412,10 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
bool thisChrome = IsChromeWindow();
// Check if we're near the stack limit before we get anywhere near the
// transplanting code. We use a conservative check since we'll use a little
// more space before we actually hit the critical "can't fail" path.
// Check if we're anywhere near the stack limit before we reach the
// transplanting code, since it has no good way to handle errors. This uses
// the untrusted script limit, which is not strictly necessary since no
// actual script should run.
JS_CHECK_RECURSION_CONSERVATIVE(cx, return NS_ERROR_FAILURE);
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
@ -7783,46 +7784,15 @@ nsGlobalWindow::GetFrames(nsIDOMWindow** aFrames)
return rv.ErrorCode();
}
JSObject* nsGlobalWindow::CallerGlobal()
{
JSContext *cx = nsContentUtils::GetCurrentJSContext();
if (!cx) {
NS_ERROR("Please don't call this method from C++!");
return nullptr;
}
// If somebody does sameOriginIframeWindow.postMessage(...), they probably
// expect the .source attribute of the resulting message event to be |window|
// rather than |sameOriginIframeWindow|, even though the transparent wrapper
// semantics of same-origin access will cause us to be in the iframe's
// compartment at the time of the call. This means that we want the incumbent
// global here, rather than the global of the current compartment.
//
// There are various edge cases in which the incumbent global and the current
// global would not be same-origin. They include:
// * A privileged caller (System Principal or Expanded Principal) manipulating
// less-privileged content via Xray Waivers.
// * An unprivileged caller invoking a cross-origin function that was exposed
// to it by privileged code (i.e. Sandbox.importFunction).
//
// In these cases, we probably don't want the privileged global appearing in the
// .source attribute. So we fall back to the compartment global there.
JS::Rooted<JSObject*> incumbentGlobal(cx, &IncumbentJSGlobal());
JS::Rooted<JSObject*> compartmentGlobal(cx, JS::CurrentGlobalOrNull(cx));
nsIPrincipal* incumbentPrin = nsContentUtils::ObjectPrincipal(incumbentGlobal);
nsIPrincipal* compartmentPrin = nsContentUtils::ObjectPrincipal(compartmentGlobal);
return incumbentPrin->EqualsConsideringDomain(compartmentPrin) ? incumbentGlobal
: compartmentGlobal;
}
nsGlobalWindow*
nsGlobalWindow::CallerInnerWindow()
{
JSContext *cx = nsContentUtils::GetCurrentJSContext();
NS_ENSURE_TRUE(cx, nullptr);
JS::Rooted<JSObject*> scope(cx, CallerGlobal());
nsIGlobalObject* global = GetIncumbentGlobal();
NS_ENSURE_TRUE(global, nullptr);
JS::Rooted<JSObject*> scope(cx, global->GetGlobalJSObject());
NS_ENSURE_TRUE(scope, nullptr);
// When Jetpack runs content scripts inside a sandbox, it uses
// sandboxPrototype to make them appear as though they're running in the
@ -7830,7 +7800,7 @@ nsGlobalWindow::CallerInnerWindow()
// the |source| of the received message to be the window set as the
// sandboxPrototype. This used to work incidentally for unrelated reasons, but
// now we need to do some special handling to support it.
{
if (xpc::IsSandbox(scope)) {
JSAutoCompartment ac(cx, scope);
JS::Rooted<JSObject*> scopeProto(cx);
bool ok = JS_GetPrototype(cx, scope, &scopeProto);
@ -7838,26 +7808,14 @@ nsGlobalWindow::CallerInnerWindow()
if (scopeProto && xpc::IsSandboxPrototypeProxy(scopeProto) &&
(scopeProto = js::CheckedUnwrap(scopeProto, /* stopAtOuter = */ false)))
{
scope = scopeProto;
global = xpc::NativeGlobal(scopeProto);
NS_ENSURE_TRUE(global, nullptr);
}
}
JSAutoCompartment ac(cx, scope);
// We don't use xpc::WindowOrNull here because we want to be able to tell
// apart the cases of "scope is not an nsISupports at all" and "scope is an
// nsISupports that's not a window". It's not clear whether that's desirable,
// see bug 984467.
nsISupports* native =
nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, scope);
if (!native)
return nullptr;
// The calling window must be holding a reference, so we can just return a
// raw pointer here and let the QI's addref be balanced by the nsCOMPtr
// destructor's release.
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(native);
if (!win)
return GetCurrentInnerWindowInternal();
// The calling window must be holding a reference, so we can return a weak
// pointer.
nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(global);
return static_cast<nsGlobalWindow*>(win.get());
}
@ -8258,10 +8216,9 @@ nsGlobalWindow::PostMessageMoz(JSContext* aCx, JS::Handle<JS::Value> aMessage,
else {
// In case the global is not a window, it can be a sandbox, and the sandbox's
// principal can be used for the security check.
JSObject *global = CallerGlobal();
nsIGlobalObject* global = GetIncumbentGlobal();
NS_ASSERTION(global, "Why is there no global object?");
JSCompartment *compartment = js::GetObjectCompartment(global);
callerPrin = xpc::GetCompartmentPrincipal(compartment);
callerPrin = global->PrincipalOrNull();
}
if (!callerPrin) {
return;
@ -12023,6 +11980,9 @@ nsGlobalWindow::InnerForSetTimeoutOrInterval(ErrorResult& aError)
// inner window that's calling window.setTimeout().
forwardTo = CallerInnerWindow();
if (!forwardTo && nsContentUtils::IsCallerChrome()) {
forwardTo = currentInner;
}
if (!forwardTo) {
aError.Throw(NS_ERROR_NOT_AVAILABLE);
return nullptr;
@ -12241,14 +12201,15 @@ nsGlobalWindow::SetTimeoutOrInterval(bool aIsInterval, int32_t *aReturn)
if (IsOuterWindow()) {
nsGlobalWindow* callerInner = CallerInnerWindow();
NS_ENSURE_TRUE(callerInner, NS_ERROR_NOT_AVAILABLE);
NS_ENSURE_TRUE(callerInner || nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
// If the caller and the callee share the same outer window,
// forward to the callee inner. Else, we forward to the current
// inner (e.g. someone is calling setTimeout() on a reference to
// some other window).
if (callerInner->GetOuterWindow() == this &&
if (callerInner &&
callerInner->GetOuterWindow() == this &&
callerInner->IsInnerWindow()) {
return callerInner->SetTimeoutOrInterval(aIsInterval, aReturn);
}

View File

@ -1092,7 +1092,6 @@ protected:
}
void FreeInnerObjects();
JSObject *CallerGlobal();
nsGlobalWindow *CallerInnerWindow();
// Only to be called on an inner window.

View File

@ -1984,6 +1984,11 @@ ToCanonicalSupports(nsINode* aPointer)
aLocalName = nsINode::LocalName(); \
return NS_OK; \
} \
NS_IMETHOD UnusedPlaceholder(bool* aResult) __VA_ARGS__ \
{ \
*aResult = false; \
return NS_OK; \
} \
NS_IMETHOD GetDOMBaseURI(nsAString& aBaseURI) __VA_ARGS__ \
{ \
nsINode::GetBaseURI(aBaseURI); \

View File

@ -1698,9 +1698,10 @@ ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg)
{
js::AssertSameCompartment(aCx, aObjArg);
// Check if we're near the stack limit before we get anywhere near the
// transplanting code. We use a conservative check since we'll use a little
// more space before we actually hit the critical "can't fail" path.
// Check if we're anywhere near the stack limit before we reach the
// transplanting code, since it has no good way to handle errors. This uses
// the untrusted script limit, which is not strictly necessary since no
// actual script should run.
JS_CHECK_RECURSION_CONSERVATIVE(aCx, return NS_ERROR_FAILURE);
JS::Rooted<JSObject*> aObj(aCx, aObjArg);

View File

@ -66,10 +66,10 @@ ToJSValue(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue)
{
MOZ_ASSERT(aArgument.Failed());
ThrowMethodFailedWithDetails(aCx, aArgument, "", "");
if (!JS_GetPendingException(aCx, aValue)) {
return false;
}
DebugOnly<bool> throwResult = ThrowMethodFailedWithDetails(aCx, aArgument, "", "");
MOZ_ASSERT(!throwResult);
DebugOnly<bool> getPendingResult = JS_GetPendingException(aCx, aValue);
MOZ_ASSERT(getPendingResult);
JS_ClearPendingException(aCx);
return true;
}

View File

@ -767,7 +767,7 @@ skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux')
[webgl-conformance/_wrappers/test_conformance__textures__texture-formats-test.html]
[webgl-conformance/_wrappers/test_conformance__textures__texture-mips.html]
[webgl-conformance/_wrappers/test_conformance__textures__texture-npot-video.html]
skip-if = os == 'win'
skip-if = os == 'win' || buildapp == 'mulet' # Mulet - bug 1089453 (crashes in libLLVM-3.0.so)
[webgl-conformance/_wrappers/test_conformance__textures__texture-npot.html]
[webgl-conformance/_wrappers/test_conformance__textures__texture-size.html]
skip-if = os == 'android'

View File

@ -12,7 +12,7 @@ fail-if = (os == 'b2g')
[webgl-mochitest/test_fb_param.html]
[webgl-mochitest/test_fb_param_crash.html]
[webgl-mochitest/test_hidden_alpha.html]
fail-if = (os == 'b2g')
skip-if = (os == 'b2g') || buildapp == 'mulet' # Mulet - bug 1093639 (crashes in libLLVM-3.0.so)
[webgl-mochitest/test_highp_fs.html]
[webgl-mochitest/test_no_arr_points.html]
skip-if = android_version == '10' #Android 2.3 aws only; bug 1030942

View File

@ -1032,11 +1032,12 @@ UploadLastDir::FetchDirectoryAndDisplayPicker(nsIDocument* aDoc,
nsCOMPtr<nsIContentPrefCallback2> prefCallback =
new UploadLastDir::ContentPrefCallback(aFilePicker, aFpCallback);
#ifdef MOZ_B2G
if (XRE_GetProcessType() == GeckoProcessType_Content) {
// FIXME (bug 949666): Run this code in the parent process.
prefCallback->HandleCompletion(nsIContentPrefCallback2::COMPLETE_ERROR);
return NS_OK;
}
#endif
// Attempt to get the CPS, if it's not present we'll fallback to use the Desktop folder
nsCOMPtr<nsIContentPrefService2> contentPrefService =
@ -1062,10 +1063,11 @@ UploadLastDir::StoreLastUsedDirectory(nsIDocument* aDoc, nsIFile* aDir)
return NS_OK;
}
#ifdef MOZ_B2G
if (XRE_GetProcessType() == GeckoProcessType_Content) {
// FIXME (bug 949666): Run this code in the parent process.
return NS_OK;
}
#endif
nsCOMPtr<nsIURI> docURI = aDoc->GetDocumentURI();
NS_PRECONDITION(docURI, "docURI is null");

View File

@ -51,7 +51,7 @@ interface nsITranslationNodeList;
interface nsIJSRAIIHelper;
interface nsIContentPermissionRequest;
[scriptable, uuid(e293355b-ae7f-4ef7-9237-452bcf3e9e6b)]
[scriptable, uuid(9621eb05-b498-4e87-a012-95d817987624)]
interface nsIDOMWindowUtils : nsISupports {
/**
@ -188,8 +188,6 @@ interface nsIDOMWindowUtils : nsISupports {
in float aTopMargin,
in float aRightMargin,
in float aBottomMargin,
in uint32_t aAlignmentX,
in uint32_t aAlignmentY,
in nsIDOMElement aElement,
in uint32_t aPriority);

View File

@ -14,7 +14,7 @@
* http://www.w3.org/TR/DOM-Level-2-Core/
*/
[builtinclass, uuid(7d0582bd-09a7-430e-969b-054abbea19fe)]
[builtinclass, uuid(7db491e8-a3a3-4432-ad67-e6c33e24ac6d)]
interface nsIDOMAttr : nsIDOMNode
{
readonly attribute DOMString name;

View File

@ -15,7 +15,7 @@
* http://www.w3.org/TR/DOM-Level-2-Core/
*/
[uuid(4ac42d40-69b7-4506-b730-c41ec74b74bd)]
[uuid(e14ef131-34cc-40c8-9c99-a403c001184a)]
interface nsIDOMCDATASection : nsIDOMText
{
};

View File

@ -13,7 +13,7 @@
* http://www.w3.org/TR/DOM-Level-2-Core/
*/
[uuid(844b8e7e-6d37-4fa1-8196-86e3afdfa0ca)]
[uuid(4109a2d2-e7af-445d-bb72-c7c9b875f35e)]
interface nsIDOMCharacterData : nsIDOMNode
{
attribute DOMString data;

View File

@ -14,7 +14,7 @@
* http://www.w3.org/TR/DOM-Level-2-Core/
*/
[uuid(c1a1d2ea-e106-4ee8-806d-2633468e8098)]
[uuid(e7866ff8-b7fc-494f-87c0-fb017d8a4d30)]
interface nsIDOMComment : nsIDOMCharacterData
{
};

View File

@ -32,7 +32,7 @@ interface nsIDOMLocation;
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
*/
[uuid(08c6400b-0b6d-4ce6-b88d-e7a15a9c7c03)]
[uuid(35dc5030-dc83-4291-88a2-0906c549788e)]
interface nsIDOMDocument : nsIDOMNode
{
readonly attribute nsIDOMDocumentType doctype;

Some files were not shown because too many files have changed in this diff Show More