зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
4b4bf0951c
|
@ -955,32 +955,30 @@ chatbox:-moz-full-screen-ancestor > .chat-titlebar {
|
|||
opacity: 1.0;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="after_start"] {
|
||||
#BMB_bookmarksPopup[animate="cancel"] {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="after_start"]:-moz-locale-dir(ltr),
|
||||
#BMB_bookmarksPopup[arrowposition="after_end"]:-moz-locale-dir(rtl) {
|
||||
transform-origin: 20px top;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="after_end"] {
|
||||
#BMB_bookmarksPopup[arrowposition="after_end"]:-moz-locale-dir(ltr),
|
||||
#BMB_bookmarksPopup[arrowposition="after_start"]:-moz-locale-dir(rtl) {
|
||||
transform-origin: calc(100% - 20px) top;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="before_start"] {
|
||||
#BMB_bookmarksPopup[arrowposition="before_start"]:-moz-locale-dir(ltr),
|
||||
#BMB_bookmarksPopup[arrowposition="before_end"]:-moz-locale-dir(rtl) {
|
||||
transform-origin: 20px bottom;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="before_end"] {
|
||||
#BMB_bookmarksPopup[arrowposition="before_end"]:-moz-locale-dir(ltr),
|
||||
#BMB_bookmarksPopup[arrowposition="before_start"]:-moz-locale-dir(rtl) {
|
||||
transform-origin: calc(100% - 20px) bottom;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="after_start"][animate="cancel"],
|
||||
#BMB_bookmarksPopup[arrowposition="before_end"][animate="cancel"] {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
#BMB_bookmarksPopup[arrowposition="after_end"][animate="cancel"],
|
||||
#BMB_bookmarksPopup[arrowposition="before_start"][animate="cancel"] {
|
||||
transform: none;
|
||||
}
|
||||
|
||||
%endif
|
||||
|
||||
/* Customize mode */
|
||||
|
|
|
@ -5,8 +5,19 @@
|
|||
<script>
|
||||
|
||||
function init() {
|
||||
window.addEventListener("message", function process(e) {doTest(e)}, false);
|
||||
doTest();
|
||||
window.addEventListener("message", function process(e) {
|
||||
// The init function of abouthealth.js schedules an initial payload event,
|
||||
// which will be sent after the payload data has been collected. This extra
|
||||
// event can cause unexpected successes/failures in this test, so we wait
|
||||
// for the extra event to arrive here before progressing with the actual
|
||||
// test.
|
||||
if (e.data.type == "payload") {
|
||||
window.removeEventListener("message", process, false);
|
||||
|
||||
window.addEventListener("message", doTest, false);
|
||||
doTest();
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
function checkSubmissionValue(payload, expectedValue) {
|
||||
|
|
|
@ -5,8 +5,8 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
PARALLEL_DIRS += [
|
||||
'content',
|
||||
'src',
|
||||
'content',
|
||||
'src',
|
||||
]
|
||||
|
||||
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
window.OTProperties.cssURL = window.OTProperties.assetURL + 'css/ot.css';
|
||||
</script>
|
||||
<script type="text/javascript" src="loop/libs/sdk.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/libs/react-0.10.0.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/libs/jquery-2.1.0.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/libs/lodash-2.4.1.js"></script>
|
||||
<script type="text/javascript" src="loop/shared/libs/backbone-1.1.2.js"></script>
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* 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/. */
|
||||
|
||||
/* jshint esnext:true */
|
||||
/* jshint newcap:false, esnext:true */
|
||||
/* global loop:true */
|
||||
|
||||
var loop = loop || {};
|
||||
|
@ -164,10 +164,10 @@ loop.conversation = (function(OT, mozL10n) {
|
|||
return;
|
||||
}
|
||||
|
||||
this.loadView(
|
||||
new loop.shared.views.ConversationView({
|
||||
sdk: OT,
|
||||
model: this._conversation
|
||||
/*jshint newcap:false*/
|
||||
this.loadReactComponent(sharedViews.ConversationView({
|
||||
sdk: OT,
|
||||
model: this._conversation
|
||||
}));
|
||||
},
|
||||
|
||||
|
|
|
@ -58,7 +58,7 @@
|
|||
/* Common media control buttons behavior */
|
||||
.conversation .controls .media-control {
|
||||
background-color: transparent;
|
||||
opacity: .7; /* reduce the opacity for a non-streaming media */
|
||||
opacity: 1;
|
||||
}
|
||||
.conversation .controls .media-control:hover {
|
||||
background-color: rgba(255, 255, 255, .35);
|
||||
|
@ -68,58 +68,35 @@
|
|||
background-color: #0096DD;
|
||||
opacity: 1;
|
||||
}
|
||||
.conversation .controls .media-control.streaming {
|
||||
opacity: 1;
|
||||
}
|
||||
.conversation .controls .media-control:not(.streaming):hover {
|
||||
background-color: transparent;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Audio mute button */
|
||||
.conversation .controls .btn-mute-audio {
|
||||
.conversation .controls .local-media.btn-mute-audio {
|
||||
background-image: url(../img/audio-inverse-14x14.png);
|
||||
}
|
||||
.conversation .controls .btn-mute-audio.streaming {
|
||||
background-image: url(../img/audio-highlight-14x14.png);
|
||||
}
|
||||
.conversation .controls .btn-mute-audio.muted,
|
||||
.conversation .controls .btn-mute-audio.streaming:hover {
|
||||
.conversation .controls .local-media.btn-mute-audio.muted {
|
||||
background-image: url(../img/mute-inverse-14x14.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.conversation .controls .btn-mute-audio {
|
||||
.conversation .controls .local-media.btn-mute-audio {
|
||||
background-image: url(../img/audio-inverse-14x14@2x.png);
|
||||
}
|
||||
.conversation .controls .btn-mute-audio.streaming {
|
||||
background-image: url(../img/audio-highlight-14x14@2x.png);
|
||||
}
|
||||
.conversation .controls .btn-mute-audio.muted,
|
||||
.conversation .controls .btn-mute-audio.streaming:hover {
|
||||
.conversation .controls .local-media.btn-mute-audio.muted {
|
||||
background-image: url(../img/mute-inverse-14x14@2x.png);
|
||||
}
|
||||
}
|
||||
|
||||
/* Video mute button */
|
||||
.conversation .controls .btn-mute-video {
|
||||
.conversation .controls .local-media.btn-mute-video {
|
||||
background-image: url(../img/video-inverse-14x14.png);
|
||||
}
|
||||
.conversation .controls .btn-mute-video.streaming {
|
||||
background-image: url(../img/video-highlight-14x14.png);
|
||||
}
|
||||
.conversation .controls .btn-mute-video.muted,
|
||||
.conversation .controls .btn-mute-video.streaming:hover {
|
||||
.conversation .controls .local-media.btn-mute-video.muted {
|
||||
background-image: url(../img/facemute-14x14.png);
|
||||
}
|
||||
@media (min-resolution: 2dppx) {
|
||||
.conversation .controls .btn-mute-video {
|
||||
.conversation .controls .local-media.btn-mute-video {
|
||||
background-image: url(../img/video-inverse-14x14@2x.png);
|
||||
}
|
||||
.conversation .controls .btn-mute-video.streaming {
|
||||
background-image: url(../img/video-highlight-14x14@2x.png);
|
||||
}
|
||||
.conversation .controls .btn-mute-video.muted,
|
||||
.conversation .controls .btn-mute-video.streaming:hover {
|
||||
.conversation .controls .local-media.btn-mute-video.muted {
|
||||
background-image: url(../img/facemute-14x14@2x.png);
|
||||
}
|
||||
}
|
||||
|
|
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 226 B |
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 439 B |
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 190 B |
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 301 B |
|
@ -1,15 +1,18 @@
|
|||
/** @jsx React.DOM */
|
||||
|
||||
/* 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/. */
|
||||
|
||||
/* global loop:true */
|
||||
|
||||
/* jshint newcap:false */
|
||||
/* global loop:true, React */
|
||||
var loop = loop || {};
|
||||
loop.shared = loop.shared || {};
|
||||
loop.shared.views = (function(_, OT, l10n) {
|
||||
"use strict";
|
||||
|
||||
var sharedModels = loop.shared.models;
|
||||
var __ = l10n.get;
|
||||
|
||||
/**
|
||||
* L10n view. Translates resulting view DOM fragment once rendered.
|
||||
|
@ -89,35 +92,113 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
});
|
||||
|
||||
/**
|
||||
* Conversation view.
|
||||
* Media control button.
|
||||
*
|
||||
* Required props:
|
||||
* - {String} scope Media scope, can be "local" or "remote".
|
||||
* - {String} type Media type, can be "audio" or "video".
|
||||
* - {Function} action Function to be executed on click.
|
||||
* - {Enabled} enabled Stream activation status (default: true).
|
||||
*/
|
||||
var ConversationView = BaseView.extend({
|
||||
className: "conversation",
|
||||
var MediaControlButton = React.createClass({displayName: 'MediaControlButton',
|
||||
propTypes: {
|
||||
scope: React.PropTypes.string.isRequired,
|
||||
type: React.PropTypes.string.isRequired,
|
||||
action: React.PropTypes.func.isRequired,
|
||||
enabled: React.PropTypes.bool.isRequired
|
||||
},
|
||||
|
||||
/**
|
||||
* Local stream object.
|
||||
* @type {OT.Stream|null}
|
||||
*/
|
||||
localStream: null,
|
||||
getDefaultProps: function() {
|
||||
return {enabled: true};
|
||||
},
|
||||
|
||||
template: _.template([
|
||||
'<ul class="controls cf">',
|
||||
' <li><button class="btn btn-hangup" ',
|
||||
' data-l10n-id="hangup_button"></button></li>',
|
||||
' <li><button class="btn media-control btn-mute-video"',
|
||||
' data-l10n-id="mute_local_video_button"></button></li>',
|
||||
' <li><button class="btn media-control btn-mute-audio"',
|
||||
' data-l10n-id="mute_local_audio_button"></button></li>',
|
||||
'</ul>',
|
||||
'<div class="media nested">',
|
||||
// Both these wrappers are required by the SDK; this is fragile and
|
||||
// will break if a future version of the SDK updates this generated DOM,
|
||||
// especially as the SDK seems to actually move wrapped contents into
|
||||
// their own generated stuff.
|
||||
' <div class="remote"><div class="incoming"></div></div>',
|
||||
' <div class="local"><div class="outgoing"></div></div>',
|
||||
'</div>'
|
||||
].join("")),
|
||||
handleClick: function() {
|
||||
this.props.action();
|
||||
},
|
||||
|
||||
_getClasses: function() {
|
||||
var cx = React.addons.classSet;
|
||||
// classes
|
||||
var classesObj = {
|
||||
"btn": true,
|
||||
"media-control": true,
|
||||
"local-media": this.props.scope === "local",
|
||||
"muted": !this.props.enabled
|
||||
};
|
||||
classesObj["btn-mute-" + this.props.type] = true;
|
||||
return cx(classesObj);
|
||||
},
|
||||
|
||||
_getTitle: function(enabled) {
|
||||
var prefix = this.props.enabled ? "mute" : "unmute";
|
||||
var suffix = "button_title";
|
||||
var msgId = [prefix, this.props.scope, this.props.type, suffix].join("_");
|
||||
return __(msgId);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
React.DOM.button( {className:this._getClasses(),
|
||||
title:this._getTitle(),
|
||||
onClick:this.handleClick})
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Conversation controls.
|
||||
*/
|
||||
var ConversationToolbar = React.createClass({displayName: 'ConversationToolbar',
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
video: {enabled: true},
|
||||
audio: {enabled: true}
|
||||
};
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
video: React.PropTypes.object.isRequired,
|
||||
audio: React.PropTypes.object.isRequired,
|
||||
hangup: React.PropTypes.func.isRequired,
|
||||
publishStream: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
handleClickHangup: function() {
|
||||
this.props.hangup();
|
||||
},
|
||||
|
||||
handleToggleVideo: function() {
|
||||
this.props.publishStream("video", !this.props.video.enabled);
|
||||
},
|
||||
|
||||
handleToggleAudio: function() {
|
||||
this.props.publishStream("audio", !this.props.audio.enabled);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
React.DOM.ul( {className:"controls"},
|
||||
React.DOM.li(null, React.DOM.button( {className:"btn btn-hangup",
|
||||
onClick:this.handleClickHangup,
|
||||
title:__("hangup_button_title")})),
|
||||
React.DOM.li(null, MediaControlButton( {action:this.handleToggleVideo,
|
||||
enabled:this.props.video.enabled,
|
||||
scope:"local", type:"video"} )),
|
||||
React.DOM.li(null, MediaControlButton( {action:this.handleToggleAudio,
|
||||
enabled:this.props.audio.enabled,
|
||||
scope:"local", type:"audio"} ))
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var ConversationView = React.createClass({displayName: 'ConversationView',
|
||||
mixins: [Backbone.Events],
|
||||
|
||||
propTypes: {
|
||||
sdk: React.PropTypes.object.isRequired,
|
||||
model: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
// height set to "auto" to fix video layout on Google Chrome
|
||||
// @see https://bugzilla.mozilla.org/show_bug.cgi?id=991122
|
||||
|
@ -126,32 +207,40 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
height: "auto",
|
||||
style: {
|
||||
bugDisplayMode: "off",
|
||||
buttonDisplayMode: "off"
|
||||
buttonDisplayMode: "off",
|
||||
nameDisplayMode: "off"
|
||||
}
|
||||
},
|
||||
|
||||
events: {
|
||||
'click .btn-hangup': 'hangup',
|
||||
'click .btn-mute-audio': 'toggleMuteAudio',
|
||||
'click .btn-mute-video': 'toggleMuteVideo'
|
||||
getInitialState: function() {
|
||||
return {
|
||||
video: {enabled: false},
|
||||
audio: {enabled: false}
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* Establishes webrtc communication using OT sdk.
|
||||
*/
|
||||
initialize: function(options) {
|
||||
options = options || {};
|
||||
if (!options.sdk) {
|
||||
throw new Error("missing required sdk");
|
||||
}
|
||||
this.sdk = options.sdk;
|
||||
componentDidMount: function() {
|
||||
this.props.model.startSession();
|
||||
},
|
||||
|
||||
this.listenTo(this.model, "session:connected", this.publish);
|
||||
this.listenTo(this.model, "session:stream-created", this._streamCreated);
|
||||
this.listenTo(this.model, ["session:peer-hungup",
|
||||
"session:network-disconnected",
|
||||
"session:ended"].join(" "), this.unpublish);
|
||||
this.model.startSession();
|
||||
componentWillMount: function() {
|
||||
this.listenTo(this.props.model, "session:connected",
|
||||
this.startPublishing);
|
||||
this.listenTo(this.props.model, "session:stream-created",
|
||||
this._streamCreated);
|
||||
this.listenTo(this.props.model, ["session:peer-hungup",
|
||||
"session:network-disconnected",
|
||||
"session:ended"].join(" "),
|
||||
this.stopPublishing);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.hangup();
|
||||
},
|
||||
|
||||
hangup: function() {
|
||||
this.stopPublishing();
|
||||
this.props.model.endSession();
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -165,74 +254,16 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
* @param {StreamEvent} event
|
||||
*/
|
||||
_streamCreated: function(event) {
|
||||
var incoming = this.$(".incoming").get(0);
|
||||
var incoming = this.getDOMNode().querySelector(".incoming");
|
||||
event.streams.forEach(function(stream) {
|
||||
if (stream.connection.connectionId !==
|
||||
this.model.session.connection.connectionId) {
|
||||
this.model.session.subscribe(stream, incoming, this.publisherConfig);
|
||||
this.props.model.session.connection.connectionId) {
|
||||
this.props.model.session.subscribe(stream, incoming,
|
||||
this.publisherConfig);
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Hangs up current conversation.
|
||||
*
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
hangup: function(event) {
|
||||
event.preventDefault();
|
||||
this.unpublish();
|
||||
this.model.endSession();
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles audio mute state.
|
||||
*
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
toggleMuteAudio: function(event) {
|
||||
event.preventDefault();
|
||||
if (!this.localStream) {
|
||||
return;
|
||||
}
|
||||
var msgId;
|
||||
var $button = this.$(".btn-mute-audio");
|
||||
var enabled = !this.localStream.hasAudio;
|
||||
this.publisher.publishAudio(enabled);
|
||||
if (enabled) {
|
||||
msgId = "mute_local_audio_button.title";
|
||||
$button.removeClass("muted");
|
||||
} else {
|
||||
msgId = "unmute_local_audio_button.title";
|
||||
$button.addClass("muted");
|
||||
}
|
||||
$button.attr("title", l10n.get(msgId));
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles video mute state.
|
||||
*
|
||||
* @param {MouseEvent} event
|
||||
*/
|
||||
toggleMuteVideo: function(event) {
|
||||
event.preventDefault();
|
||||
if (!this.localStream) {
|
||||
return;
|
||||
}
|
||||
var msgId;
|
||||
var $button = this.$(".btn-mute-video");
|
||||
var enabled = !this.localStream.hasVideo;
|
||||
this.publisher.publishVideo(enabled);
|
||||
if (enabled) {
|
||||
$button.removeClass("muted");
|
||||
msgId = "mute_local_video_button.title";
|
||||
} else {
|
||||
$button.addClass("muted");
|
||||
msgId = "unmute_local_video_button.title";
|
||||
}
|
||||
$button.attr("title", l10n.get(msgId));
|
||||
},
|
||||
|
||||
/**
|
||||
* Publishes remote streams available once a session is connected.
|
||||
*
|
||||
|
@ -240,10 +271,12 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
*
|
||||
* @param {SessionConnectEvent} event
|
||||
*/
|
||||
publish: function(event) {
|
||||
var outgoing = this.$(".outgoing").get(0);
|
||||
startPublishing: function(event) {
|
||||
var outgoing = this.getDOMNode().querySelector(".outgoing");
|
||||
|
||||
this.publisher = this.sdk.initPublisher(outgoing, this.publisherConfig);
|
||||
// XXX move this into its StreamingVideo component?
|
||||
this.publisher = this.props.sdk.initPublisher(
|
||||
outgoing, this.publisherConfig);
|
||||
|
||||
// Suppress OT GuM custom dialog, see bug 1018875
|
||||
function preventOpeningAccessDialog(event) {
|
||||
|
@ -251,43 +284,64 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
}
|
||||
this.publisher.on("accessDialogOpened", preventOpeningAccessDialog);
|
||||
this.publisher.on("accessDenied", preventOpeningAccessDialog);
|
||||
|
||||
this.publisher.on("streamCreated", function(event) {
|
||||
this.localStream = event.stream;
|
||||
if (this.localStream.hasAudio) {
|
||||
this.$(".btn-mute-audio").addClass("streaming");
|
||||
}
|
||||
if (this.localStream.hasVideo) {
|
||||
this.$(".btn-mute-video").addClass("streaming");
|
||||
}
|
||||
}.bind(this));
|
||||
this.publisher.on("streamDestroyed", function() {
|
||||
this.localStream = null;
|
||||
this.$(".btn-mute-audio").removeClass("streaming muted");
|
||||
this.$(".btn-mute-video").removeClass("streaming muted");
|
||||
this.setState({
|
||||
audio: {enabled: event.stream.hasAudio},
|
||||
video: {enabled: event.stream.hasVideo}
|
||||
});
|
||||
}.bind(this));
|
||||
|
||||
this.model.session.publish(this.publisher);
|
||||
this.publisher.on("streamDestroyed", function() {
|
||||
this.setState({
|
||||
audio: {enabled: false},
|
||||
video: {enabled: false}
|
||||
});
|
||||
}.bind(this));
|
||||
|
||||
this.props.model.session.publish(this.publisher);
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles streaming status for a given stream type.
|
||||
*
|
||||
* @param {String} type Stream type ("audio" or "video").
|
||||
* @param {Boolean} enabled Enabled stream flag.
|
||||
*/
|
||||
publishStream: function(type, enabled) {
|
||||
if (type === "audio") {
|
||||
this.publisher.publishAudio(enabled);
|
||||
this.setState({audio: {enabled: enabled}});
|
||||
} else {
|
||||
this.publisher.publishVideo(enabled);
|
||||
this.setState({video: {enabled: enabled}});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Unpublishes local stream.
|
||||
*/
|
||||
unpublish: function() {
|
||||
stopPublishing: function() {
|
||||
// Unregister access OT GuM custom dialog listeners, see bug 1018875
|
||||
this.publisher.off("accessDialogOpened");
|
||||
this.publisher.off("accessDenied");
|
||||
|
||||
this.model.session.unpublish(this.publisher);
|
||||
this.props.model.session.unpublish(this.publisher);
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders this view.
|
||||
*
|
||||
* @return {ConversationView}
|
||||
*/
|
||||
render: function() {
|
||||
this.$el.html(this.template(this.model.toJSON()));
|
||||
return this;
|
||||
return (
|
||||
React.DOM.div( {className:"conversation"},
|
||||
ConversationToolbar( {video:this.state.video,
|
||||
audio:this.state.audio,
|
||||
publishStream:this.publishStream,
|
||||
hangup:this.hangup} ),
|
||||
React.DOM.div( {className:"media nested"},
|
||||
React.DOM.div( {className:"remote"}, React.DOM.div( {className:"incoming"})),
|
||||
React.DOM.div( {className:"local"}, React.DOM.div( {className:"outgoing"}))
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -456,6 +510,8 @@ loop.shared.views = (function(_, OT, l10n) {
|
|||
L10nView: L10nView,
|
||||
BaseView: BaseView,
|
||||
ConversationView: ConversationView,
|
||||
ConversationToolbar: ConversationToolbar,
|
||||
MediaControlButton: MediaControlButton,
|
||||
NotificationListView: NotificationListView,
|
||||
NotificationView: NotificationView,
|
||||
UnsupportedBrowserView: UnsupportedBrowserView,
|
||||
|
|
|
@ -0,0 +1,520 @@
|
|||
/** @jsx React.DOM */
|
||||
|
||||
/* 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/. */
|
||||
|
||||
/* jshint newcap:false */
|
||||
/* global loop:true, React */
|
||||
var loop = loop || {};
|
||||
loop.shared = loop.shared || {};
|
||||
loop.shared.views = (function(_, OT, l10n) {
|
||||
"use strict";
|
||||
|
||||
var sharedModels = loop.shared.models;
|
||||
var __ = l10n.get;
|
||||
|
||||
/**
|
||||
* L10n view. Translates resulting view DOM fragment once rendered.
|
||||
*/
|
||||
var L10nView = (function() {
|
||||
var L10nViewImpl = Backbone.View.extend(), // Original View constructor
|
||||
originalExtend = L10nViewImpl.extend; // Original static extend fn
|
||||
|
||||
/**
|
||||
* Patches View extend() method so we can hook and patch any declared render
|
||||
* method.
|
||||
*
|
||||
* @return {Backbone.View} Extended view with patched render() method.
|
||||
*/
|
||||
L10nViewImpl.extend = function() {
|
||||
var ExtendedView = originalExtend.apply(this, arguments),
|
||||
originalRender = ExtendedView.prototype.render;
|
||||
|
||||
/**
|
||||
* Wraps original render() method to translate contents once they're
|
||||
* rendered.
|
||||
*
|
||||
* @return {Backbone.View} Extended view instance.
|
||||
*/
|
||||
ExtendedView.prototype.render = function() {
|
||||
if (originalRender) {
|
||||
originalRender.apply(this, arguments);
|
||||
l10n.translate(this.el);
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
return ExtendedView;
|
||||
};
|
||||
|
||||
return L10nViewImpl;
|
||||
})();
|
||||
|
||||
/**
|
||||
* Base view.
|
||||
*/
|
||||
var BaseView = L10nView.extend({
|
||||
/**
|
||||
* Hides view element.
|
||||
*
|
||||
* @return {BaseView}
|
||||
*/
|
||||
hide: function() {
|
||||
this.$el.hide();
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Shows view element.
|
||||
*
|
||||
* @return {BaseView}
|
||||
*/
|
||||
show: function() {
|
||||
this.$el.show();
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Base render implementation: renders an attached template if available.
|
||||
*
|
||||
* Note: You need to override this if you want to do fancier stuff, eg.
|
||||
* rendering the template using model data.
|
||||
*
|
||||
* @return {BaseView}
|
||||
*/
|
||||
render: function() {
|
||||
if (this.template) {
|
||||
this.$el.html(this.template());
|
||||
}
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Media control button.
|
||||
*
|
||||
* Required props:
|
||||
* - {String} scope Media scope, can be "local" or "remote".
|
||||
* - {String} type Media type, can be "audio" or "video".
|
||||
* - {Function} action Function to be executed on click.
|
||||
* - {Enabled} enabled Stream activation status (default: true).
|
||||
*/
|
||||
var MediaControlButton = React.createClass({
|
||||
propTypes: {
|
||||
scope: React.PropTypes.string.isRequired,
|
||||
type: React.PropTypes.string.isRequired,
|
||||
action: React.PropTypes.func.isRequired,
|
||||
enabled: React.PropTypes.bool.isRequired
|
||||
},
|
||||
|
||||
getDefaultProps: function() {
|
||||
return {enabled: true};
|
||||
},
|
||||
|
||||
handleClick: function() {
|
||||
this.props.action();
|
||||
},
|
||||
|
||||
_getClasses: function() {
|
||||
var cx = React.addons.classSet;
|
||||
// classes
|
||||
var classesObj = {
|
||||
"btn": true,
|
||||
"media-control": true,
|
||||
"local-media": this.props.scope === "local",
|
||||
"muted": !this.props.enabled
|
||||
};
|
||||
classesObj["btn-mute-" + this.props.type] = true;
|
||||
return cx(classesObj);
|
||||
},
|
||||
|
||||
_getTitle: function(enabled) {
|
||||
var prefix = this.props.enabled ? "mute" : "unmute";
|
||||
var suffix = "button_title";
|
||||
var msgId = [prefix, this.props.scope, this.props.type, suffix].join("_");
|
||||
return __(msgId);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<button className={this._getClasses()}
|
||||
title={this._getTitle()}
|
||||
onClick={this.handleClick}></button>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Conversation controls.
|
||||
*/
|
||||
var ConversationToolbar = React.createClass({
|
||||
getDefaultProps: function() {
|
||||
return {
|
||||
video: {enabled: true},
|
||||
audio: {enabled: true}
|
||||
};
|
||||
},
|
||||
|
||||
propTypes: {
|
||||
video: React.PropTypes.object.isRequired,
|
||||
audio: React.PropTypes.object.isRequired,
|
||||
hangup: React.PropTypes.func.isRequired,
|
||||
publishStream: React.PropTypes.func.isRequired
|
||||
},
|
||||
|
||||
handleClickHangup: function() {
|
||||
this.props.hangup();
|
||||
},
|
||||
|
||||
handleToggleVideo: function() {
|
||||
this.props.publishStream("video", !this.props.video.enabled);
|
||||
},
|
||||
|
||||
handleToggleAudio: function() {
|
||||
this.props.publishStream("audio", !this.props.audio.enabled);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<ul className="controls">
|
||||
<li><button className="btn btn-hangup"
|
||||
onClick={this.handleClickHangup}
|
||||
title={__("hangup_button_title")}></button></li>
|
||||
<li><MediaControlButton action={this.handleToggleVideo}
|
||||
enabled={this.props.video.enabled}
|
||||
scope="local" type="video" /></li>
|
||||
<li><MediaControlButton action={this.handleToggleAudio}
|
||||
enabled={this.props.audio.enabled}
|
||||
scope="local" type="audio" /></li>
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
var ConversationView = React.createClass({
|
||||
mixins: [Backbone.Events],
|
||||
|
||||
propTypes: {
|
||||
sdk: React.PropTypes.object.isRequired,
|
||||
model: React.PropTypes.object.isRequired
|
||||
},
|
||||
|
||||
// height set to "auto" to fix video layout on Google Chrome
|
||||
// @see https://bugzilla.mozilla.org/show_bug.cgi?id=991122
|
||||
publisherConfig: {
|
||||
width: "100%",
|
||||
height: "auto",
|
||||
style: {
|
||||
bugDisplayMode: "off",
|
||||
buttonDisplayMode: "off",
|
||||
nameDisplayMode: "off"
|
||||
}
|
||||
},
|
||||
|
||||
getInitialState: function() {
|
||||
return {
|
||||
video: {enabled: false},
|
||||
audio: {enabled: false}
|
||||
};
|
||||
},
|
||||
|
||||
componentDidMount: function() {
|
||||
this.props.model.startSession();
|
||||
},
|
||||
|
||||
componentWillMount: function() {
|
||||
this.listenTo(this.props.model, "session:connected",
|
||||
this.startPublishing);
|
||||
this.listenTo(this.props.model, "session:stream-created",
|
||||
this._streamCreated);
|
||||
this.listenTo(this.props.model, ["session:peer-hungup",
|
||||
"session:network-disconnected",
|
||||
"session:ended"].join(" "),
|
||||
this.stopPublishing);
|
||||
},
|
||||
|
||||
componentWillUnmount: function() {
|
||||
this.hangup();
|
||||
},
|
||||
|
||||
hangup: function() {
|
||||
this.stopPublishing();
|
||||
this.props.model.endSession();
|
||||
},
|
||||
|
||||
/**
|
||||
* Subscribes and attaches each created stream to a DOM element.
|
||||
*
|
||||
* XXX: for now we only support a single remote stream, hence a single DOM
|
||||
* element.
|
||||
*
|
||||
* http://tokbox.com/opentok/libraries/client/js/reference/StreamEvent.html
|
||||
*
|
||||
* @param {StreamEvent} event
|
||||
*/
|
||||
_streamCreated: function(event) {
|
||||
var incoming = this.getDOMNode().querySelector(".incoming");
|
||||
event.streams.forEach(function(stream) {
|
||||
if (stream.connection.connectionId !==
|
||||
this.props.model.session.connection.connectionId) {
|
||||
this.props.model.session.subscribe(stream, incoming,
|
||||
this.publisherConfig);
|
||||
}
|
||||
}, this);
|
||||
},
|
||||
|
||||
/**
|
||||
* Publishes remote streams available once a session is connected.
|
||||
*
|
||||
* http://tokbox.com/opentok/libraries/client/js/reference/SessionConnectEvent.html
|
||||
*
|
||||
* @param {SessionConnectEvent} event
|
||||
*/
|
||||
startPublishing: function(event) {
|
||||
var outgoing = this.getDOMNode().querySelector(".outgoing");
|
||||
|
||||
// XXX move this into its StreamingVideo component?
|
||||
this.publisher = this.props.sdk.initPublisher(
|
||||
outgoing, this.publisherConfig);
|
||||
|
||||
// Suppress OT GuM custom dialog, see bug 1018875
|
||||
function preventOpeningAccessDialog(event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
this.publisher.on("accessDialogOpened", preventOpeningAccessDialog);
|
||||
this.publisher.on("accessDenied", preventOpeningAccessDialog);
|
||||
|
||||
this.publisher.on("streamCreated", function(event) {
|
||||
this.setState({
|
||||
audio: {enabled: event.stream.hasAudio},
|
||||
video: {enabled: event.stream.hasVideo}
|
||||
});
|
||||
}.bind(this));
|
||||
|
||||
this.publisher.on("streamDestroyed", function() {
|
||||
this.setState({
|
||||
audio: {enabled: false},
|
||||
video: {enabled: false}
|
||||
});
|
||||
}.bind(this));
|
||||
|
||||
this.props.model.session.publish(this.publisher);
|
||||
},
|
||||
|
||||
/**
|
||||
* Toggles streaming status for a given stream type.
|
||||
*
|
||||
* @param {String} type Stream type ("audio" or "video").
|
||||
* @param {Boolean} enabled Enabled stream flag.
|
||||
*/
|
||||
publishStream: function(type, enabled) {
|
||||
if (type === "audio") {
|
||||
this.publisher.publishAudio(enabled);
|
||||
this.setState({audio: {enabled: enabled}});
|
||||
} else {
|
||||
this.publisher.publishVideo(enabled);
|
||||
this.setState({video: {enabled: enabled}});
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Unpublishes local stream.
|
||||
*/
|
||||
stopPublishing: function() {
|
||||
// Unregister access OT GuM custom dialog listeners, see bug 1018875
|
||||
this.publisher.off("accessDialogOpened");
|
||||
this.publisher.off("accessDenied");
|
||||
|
||||
this.props.model.session.unpublish(this.publisher);
|
||||
},
|
||||
|
||||
render: function() {
|
||||
return (
|
||||
<div className="conversation">
|
||||
<ConversationToolbar video={this.state.video}
|
||||
audio={this.state.audio}
|
||||
publishStream={this.publishStream}
|
||||
hangup={this.hangup} />
|
||||
<div className="media nested">
|
||||
<div className="remote"><div className="incoming"></div></div>
|
||||
<div className="local"><div className="outgoing"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Notification view.
|
||||
*/
|
||||
var NotificationView = BaseView.extend({
|
||||
template: _.template([
|
||||
'<div class="alert alert-<%- level %>">',
|
||||
' <button class="close"></button>',
|
||||
' <p class="message"><%- message %></p>',
|
||||
'</div>'
|
||||
].join("")),
|
||||
|
||||
events: {
|
||||
"click .close": "dismiss"
|
||||
},
|
||||
|
||||
dismiss: function(event) {
|
||||
event.preventDefault();
|
||||
this.$el.addClass("fade-out");
|
||||
setTimeout(function() {
|
||||
this.collection.remove(this.model);
|
||||
this.remove();
|
||||
}.bind(this), 500); // XXX make timeout value configurable
|
||||
},
|
||||
|
||||
render: function() {
|
||||
this.$el.html(this.template(this.model.toJSON()));
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Notification list view.
|
||||
*/
|
||||
var NotificationListView = Backbone.View.extend({
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Available options:
|
||||
* - {loop.shared.models.NotificationCollection} collection Notifications
|
||||
* collection
|
||||
*
|
||||
* @param {Object} options Options object
|
||||
*/
|
||||
initialize: function(options) {
|
||||
options = options || {};
|
||||
if (!options.collection) {
|
||||
this.collection = new sharedModels.NotificationCollection();
|
||||
}
|
||||
this.listenTo(this.collection, "reset add remove", this.render);
|
||||
},
|
||||
|
||||
/**
|
||||
* Clears the notification stack.
|
||||
*/
|
||||
clear: function() {
|
||||
this.collection.reset();
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a new notification to the stack, triggering rendering of it.
|
||||
*
|
||||
* @param {Object|NotificationModel} notification Notification data.
|
||||
*/
|
||||
notify: function(notification) {
|
||||
this.collection.add(notification);
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a new notification to the stack using an l10n message identifier,
|
||||
* triggering rendering of it.
|
||||
*
|
||||
* @param {String} messageId L10n message id
|
||||
* @param {String} level Notification level
|
||||
*/
|
||||
notifyL10n: function(messageId, level) {
|
||||
this.notify({
|
||||
message: l10n.get(messageId),
|
||||
level: level
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a warning notification to the stack and renders it.
|
||||
*
|
||||
* @return {String} message
|
||||
*/
|
||||
warn: function(message) {
|
||||
this.notify({level: "warning", message: message});
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a l10n warning notification to the stack and renders it.
|
||||
*
|
||||
* @param {String} messageId L10n message id
|
||||
*/
|
||||
warnL10n: function(messageId) {
|
||||
this.warn(l10n.get(messageId));
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds an error notification to the stack and renders it.
|
||||
*
|
||||
* @return {String} message
|
||||
*/
|
||||
error: function(message) {
|
||||
this.notify({level: "error", message: message});
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds a l10n rror notification to the stack and renders it.
|
||||
*
|
||||
* @param {String} messageId L10n message id
|
||||
*/
|
||||
errorL10n: function(messageId) {
|
||||
this.error(l10n.get(messageId));
|
||||
},
|
||||
|
||||
/**
|
||||
* Renders this view.
|
||||
*
|
||||
* @return {loop.shared.views.NotificationListView}
|
||||
*/
|
||||
render: function() {
|
||||
this.$el.html(this.collection.map(function(notification) {
|
||||
return new NotificationView({
|
||||
model: notification,
|
||||
collection: this.collection
|
||||
}).render().$el;
|
||||
}.bind(this)));
|
||||
return this;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Unsupported Browsers view.
|
||||
*/
|
||||
var UnsupportedBrowserView = BaseView.extend({
|
||||
template: _.template([
|
||||
'<div>',
|
||||
' <h2 data-l10n-id="incompatible_browser"></h2>',
|
||||
' <p data-l10n-id="powered_by_webrtc"></p>',
|
||||
' <p data-l10n-id="use_latest_firefox" ',
|
||||
' data-l10n-args=\'{"ff_url": "https://www.mozilla.org/firefox/"}\'>',
|
||||
' </p>',
|
||||
'</div>'
|
||||
].join(""))
|
||||
});
|
||||
|
||||
/**
|
||||
* Unsupported Browsers view.
|
||||
*/
|
||||
var UnsupportedDeviceView = BaseView.extend({
|
||||
template: _.template([
|
||||
'<div>',
|
||||
' <h2 data-l10n-id="incompatible_device"></h2>',
|
||||
' <p data-l10n-id="sorry_device_unsupported"></p>',
|
||||
' <p data-l10n-id="use_firefox_windows_mac_linux"></p>',
|
||||
'</div>'
|
||||
].join(""))
|
||||
});
|
||||
|
||||
return {
|
||||
L10nView: L10nView,
|
||||
BaseView: BaseView,
|
||||
ConversationView: ConversationView,
|
||||
ConversationToolbar: ConversationToolbar,
|
||||
MediaControlButton: MediaControlButton,
|
||||
NotificationListView: NotificationListView,
|
||||
NotificationView: NotificationView,
|
||||
UnsupportedBrowserView: UnsupportedBrowserView,
|
||||
UnsupportedDeviceView: UnsupportedDeviceView
|
||||
};
|
||||
})(_, window.OT, document.webL10n || document.mozL10n);
|
|
@ -25,8 +25,6 @@ browser.jar:
|
|||
content/browser/loop/shared/img/icon_32.png (content/shared/img/icon_32.png)
|
||||
content/browser/loop/shared/img/icon_64.png (content/shared/img/icon_64.png)
|
||||
content/browser/loop/shared/img/loading-icon.gif (content/shared/img/loading-icon.gif)
|
||||
content/browser/loop/shared/img/audio-highlight-14x14.png (content/shared/img/audio-highlight-14x14.png)
|
||||
content/browser/loop/shared/img/audio-highlight-14x14@2x.png (content/shared/img/audio-highlight-14x14@2x.png)
|
||||
content/browser/loop/shared/img/audio-inverse-14x14.png (content/shared/img/audio-inverse-14x14.png)
|
||||
content/browser/loop/shared/img/audio-inverse-14x14@2x.png (content/shared/img/audio-inverse-14x14@2x.png)
|
||||
content/browser/loop/shared/img/facemute-14x14.png (content/shared/img/facemute-14x14.png)
|
||||
|
@ -35,8 +33,6 @@ browser.jar:
|
|||
content/browser/loop/shared/img/hangup-inverse-14x14@2x.png (content/shared/img/hangup-inverse-14x14@2x.png)
|
||||
content/browser/loop/shared/img/mute-inverse-14x14.png (content/shared/img/mute-inverse-14x14.png)
|
||||
content/browser/loop/shared/img/mute-inverse-14x14@2x.png (content/shared/img/mute-inverse-14x14@2x.png)
|
||||
content/browser/loop/shared/img/video-highlight-14x14.png (content/shared/img/video-highlight-14x14.png)
|
||||
content/browser/loop/shared/img/video-highlight-14x14@2x.png (content/shared/img/video-highlight-14x14@2x.png)
|
||||
content/browser/loop/shared/img/video-inverse-14x14.png (content/shared/img/video-inverse-14x14.png)
|
||||
content/browser/loop/shared/img/video-inverse-14x14@2x.png (content/shared/img/video-inverse-14x14@2x.png)
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
<!-- libs -->
|
||||
<script src="https://static.opentok.com/webrtc/v2.2/js/opentok.min.js"></script>
|
||||
<script type="text/javascript" src="libs/webl10n-20130617.js"></script>
|
||||
<script type="text/javascript" src="shared/libs/react-0.10.0.js"></script>
|
||||
<script type="text/javascript" src="shared/libs/jquery-2.1.0.js"></script>
|
||||
<script type="text/javascript" src="shared/libs/lodash-2.4.1.js"></script>
|
||||
<script type="text/javascript" src="shared/libs/backbone-1.1.2.js"></script>
|
||||
|
|
|
@ -189,7 +189,7 @@ loop.webapp = (function($, _, OT) {
|
|||
// User has loaded this url directly, actually setup the call.
|
||||
return this.navigate("call/" + loopToken, {trigger: true});
|
||||
}
|
||||
this.loadView(new sharedViews.ConversationView({
|
||||
this.loadReactComponent(sharedViews.ConversationView({
|
||||
sdk: OT,
|
||||
model: this._conversation
|
||||
}));
|
||||
|
|
|
@ -4,11 +4,11 @@ missing_conversation_info=Missing conversation information.
|
|||
network_disconnected=The network connection terminated abruptly.
|
||||
peer_ended_conversation=Your peer ended the conversation.
|
||||
unable_retrieve_call_info=Unable to retrieve conversation information.
|
||||
hangup_button.title=Hangup
|
||||
mute_local_audio_button.title=Mute your audio
|
||||
unmute_local_audio_button.title=Unute your audio
|
||||
mute_local_video_button.title=Mute your video
|
||||
unmute_local_video_button.title=Unmute your video
|
||||
hangup_button_title=Hangup
|
||||
mute_local_audio_button_title=Mute your audio
|
||||
unmute_local_audio_button_title=Unute your audio
|
||||
mute_local_video_button_title=Mute your video
|
||||
unmute_local_video_button_title=Unmute your video
|
||||
start_call=Start the call
|
||||
welcome=Welcome to the Loop web client.
|
||||
incompatible_browser=Incompatible Browser
|
||||
|
@ -25,11 +25,11 @@ missing_conversation_info=Informations de communication manquantes.
|
|||
network_disconnected=La connexion réseau semble avoir été interrompue.
|
||||
peer_ended_conversation=Votre correspondant a mis fin à la communication.
|
||||
unable_retrieve_call_info=Impossible de récupérer les informations liées à cet appel.
|
||||
hangup_button.title=Terminer l'appel
|
||||
mute_local_audio_button.title=Couper la diffusion audio
|
||||
unmute_local_audio_button.title=Reprendre la diffusion audio
|
||||
mute_local_video_button.title=Couper la diffusion vidéo
|
||||
unmute_local_video_button.title=Reprendre la diffusion vidéo
|
||||
hangup_button_title=Terminer l'appel
|
||||
mute_local_audio_button_title=Couper la diffusion audio
|
||||
unmute_local_audio_button_title=Reprendre la diffusion audio
|
||||
mute_local_video_button_title=Couper la diffusion vidéo
|
||||
unmute_local_video_button_title=Reprendre la diffusion vidéo
|
||||
start_call=Démarrer l'appel
|
||||
welcome=Bienvenue sur Loop.
|
||||
incompatible_browser=Navigateur non supporté
|
||||
|
|
|
@ -157,23 +157,28 @@ describe("loop.conversation", function() {
|
|||
});
|
||||
|
||||
describe("#conversation", function() {
|
||||
beforeEach(function() {
|
||||
sandbox.stub(router, "loadReactComponent");
|
||||
});
|
||||
|
||||
it("should load the ConversationView if session is set", function() {
|
||||
sandbox.stub(loop.shared.views.ConversationView.prototype,
|
||||
"initialize");
|
||||
conversation.set("sessionId", "fakeSessionId");
|
||||
|
||||
router.conversation();
|
||||
|
||||
sinon.assert.calledOnce(router.loadView);
|
||||
sinon.assert.calledWith(router.loadView,
|
||||
sinon.match.instanceOf(loop.shared.views.ConversationView));
|
||||
sinon.assert.calledOnce(router.loadReactComponent);
|
||||
sinon.assert.calledWith(router.loadReactComponent,
|
||||
sinon.match(function(value) {
|
||||
return React.addons.TestUtils.isComponentOfType(
|
||||
value, loop.shared.views.ConversationView);
|
||||
}));
|
||||
});
|
||||
|
||||
it("should not load the ConversationView if session is not set",
|
||||
function() {
|
||||
router.conversation();
|
||||
|
||||
sinon.assert.notCalled(router.loadView);
|
||||
sinon.assert.notCalled(router.loadReactComponent);
|
||||
});
|
||||
|
||||
it("should notify the user when session is not set",
|
||||
|
|
|
@ -16,10 +16,11 @@
|
|||
<div id="fixtures"></div>
|
||||
|
||||
<!-- libs -->
|
||||
<script src="../../content/shared/libs/react-0.10.0.js"></script>
|
||||
<script src="../../content/shared/libs/jquery-2.1.0.js"></script>
|
||||
<script src="../../content/shared/libs/lodash-2.4.1.js"></script>
|
||||
<script src="../../content/shared/libs/backbone-1.1.2.js"></script>
|
||||
<script src="../../standalone/content/libs/webl10n-20130617.js"></script>
|
||||
<script src="../../standalone/content/libs/webl10n-20130617.js"></script>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<script src="vendor/mocha-1.17.1.js"></script>
|
||||
|
|
|
@ -2,16 +2,19 @@
|
|||
* 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/. */
|
||||
|
||||
/* global loop, sinon */
|
||||
/*global loop, sinon, React */
|
||||
/* jshint newcap:false */
|
||||
|
||||
var expect = chai.expect;
|
||||
var l10n = document.webL10n || document.mozL10n;
|
||||
var TestUtils = React.addons.TestUtils;
|
||||
|
||||
describe("loop.shared.views", function() {
|
||||
"use strict";
|
||||
|
||||
var sharedModels = loop.shared.models,
|
||||
sharedViews = loop.shared.views,
|
||||
getReactElementByClass = TestUtils.findRenderedDOMComponentWithClass,
|
||||
sandbox;
|
||||
|
||||
beforeEach(function() {
|
||||
|
@ -40,9 +43,143 @@ describe("loop.shared.views", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("MediaControlButton", function() {
|
||||
it("should render an enabled local audio button", function() {
|
||||
var comp = TestUtils.renderIntoDocument(sharedViews.MediaControlButton({
|
||||
scope: "local",
|
||||
type: "audio",
|
||||
action: function(){},
|
||||
enabled: true
|
||||
}));
|
||||
|
||||
expect(comp.getDOMNode().classList.contains("muted")).eql(false);
|
||||
});
|
||||
|
||||
it("should render a muted local audio button", function() {
|
||||
var comp = TestUtils.renderIntoDocument(sharedViews.MediaControlButton({
|
||||
scope: "local",
|
||||
type: "audio",
|
||||
action: function(){},
|
||||
enabled: false
|
||||
}));
|
||||
|
||||
expect(comp.getDOMNode().classList.contains("muted")).eql(true);
|
||||
});
|
||||
|
||||
it("should render an enabled local video button", function() {
|
||||
var comp = TestUtils.renderIntoDocument(sharedViews.MediaControlButton({
|
||||
scope: "local",
|
||||
type: "video",
|
||||
action: function(){},
|
||||
enabled: true
|
||||
}));
|
||||
|
||||
expect(comp.getDOMNode().classList.contains("muted")).eql(false);
|
||||
});
|
||||
|
||||
it("should render a muted local video button", function() {
|
||||
var comp = TestUtils.renderIntoDocument(sharedViews.MediaControlButton({
|
||||
scope: "local",
|
||||
type: "video",
|
||||
action: function(){},
|
||||
enabled: false
|
||||
}));
|
||||
|
||||
expect(comp.getDOMNode().classList.contains("muted")).eql(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ConversationToolbar", function() {
|
||||
var hangup, publishStream;
|
||||
|
||||
function mountTestComponent(props) {
|
||||
return TestUtils.renderIntoDocument(
|
||||
sharedViews.ConversationToolbar(props));
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
hangup = sandbox.stub();
|
||||
publishStream = sandbox.stub();
|
||||
});
|
||||
|
||||
it("should hangup when hangup button is clicked", function() {
|
||||
var comp = mountTestComponent({
|
||||
hangup: hangup,
|
||||
publishStream: publishStream,
|
||||
audio: {enabled: true}
|
||||
});
|
||||
|
||||
TestUtils.Simulate.click(
|
||||
comp.getDOMNode().querySelector(".btn-hangup"));
|
||||
|
||||
sinon.assert.calledOnce(hangup);
|
||||
sinon.assert.calledWithExactly(hangup);
|
||||
});
|
||||
|
||||
it("should unpublish audio when audio mute btn is clicked", function() {
|
||||
var comp = mountTestComponent({
|
||||
hangup: hangup,
|
||||
publishStream: publishStream,
|
||||
audio: {enabled: true}
|
||||
});
|
||||
|
||||
TestUtils.Simulate.click(
|
||||
comp.getDOMNode().querySelector(".btn-mute-audio"));
|
||||
|
||||
sinon.assert.calledOnce(publishStream);
|
||||
sinon.assert.calledWithExactly(publishStream, "audio", false);
|
||||
});
|
||||
|
||||
it("should publish audio when audio mute btn is clicked", function() {
|
||||
var comp = mountTestComponent({
|
||||
hangup: hangup,
|
||||
publishStream: publishStream,
|
||||
audio: {enabled: false}
|
||||
});
|
||||
|
||||
TestUtils.Simulate.click(
|
||||
comp.getDOMNode().querySelector(".btn-mute-audio"));
|
||||
|
||||
sinon.assert.calledOnce(publishStream);
|
||||
sinon.assert.calledWithExactly(publishStream, "audio", true);
|
||||
});
|
||||
|
||||
it("should unpublish video when video mute btn is clicked", function() {
|
||||
var comp = mountTestComponent({
|
||||
hangup: hangup,
|
||||
publishStream: publishStream,
|
||||
video: {enabled: true}
|
||||
});
|
||||
|
||||
TestUtils.Simulate.click(
|
||||
comp.getDOMNode().querySelector(".btn-mute-video"));
|
||||
|
||||
sinon.assert.calledOnce(publishStream);
|
||||
sinon.assert.calledWithExactly(publishStream, "video", false);
|
||||
});
|
||||
|
||||
it("should publish video when video mute btn is clicked", function() {
|
||||
var comp = mountTestComponent({
|
||||
hangup: hangup,
|
||||
publishStream: publishStream,
|
||||
video: {enabled: false}
|
||||
});
|
||||
|
||||
TestUtils.Simulate.click(
|
||||
comp.getDOMNode().querySelector(".btn-mute-video"));
|
||||
|
||||
sinon.assert.calledOnce(publishStream);
|
||||
sinon.assert.calledWithExactly(publishStream, "video", true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ConversationView", function() {
|
||||
var fakeSDK, fakeSessionData, fakeSession, fakePublisher, model;
|
||||
|
||||
function mountTestComponent(props) {
|
||||
return TestUtils.renderIntoDocument(sharedViews.ConversationView(props));
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
fakeSessionData = {
|
||||
sessionId: "sessionId",
|
||||
|
@ -72,50 +209,46 @@ describe("loop.shared.views", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("#initialize", function() {
|
||||
it("should require a sdk object", function() {
|
||||
expect(function() {
|
||||
new sharedViews.ConversationView();
|
||||
}).to.Throw(Error, /sdk/);
|
||||
});
|
||||
|
||||
describe("#componentDidMount", function() {
|
||||
it("should start a session", function() {
|
||||
sandbox.stub(model, "startSession");
|
||||
|
||||
new sharedViews.ConversationView({sdk: fakeSDK, model: model});
|
||||
mountTestComponent({sdk: fakeSDK, model: model});
|
||||
|
||||
sinon.assert.calledOnce(model.startSession);
|
||||
});
|
||||
});
|
||||
|
||||
describe("constructed", function() {
|
||||
describe("#hangup", function() {
|
||||
it("should disconnect the session", function() {
|
||||
var view = new sharedViews.ConversationView({
|
||||
sdk: fakeSDK,
|
||||
model: model
|
||||
});
|
||||
sandbox.stub(model, "endSession");
|
||||
view.publish();
|
||||
var comp;
|
||||
|
||||
view.hangup({preventDefault: function() {}});
|
||||
beforeEach(function() {
|
||||
comp = mountTestComponent({sdk: fakeSDK, model: model});
|
||||
});
|
||||
|
||||
describe("#hangup", function() {
|
||||
beforeEach(function() {
|
||||
comp.startPublishing();
|
||||
});
|
||||
|
||||
it("should disconnect the session", function() {
|
||||
sandbox.stub(model, "endSession");
|
||||
|
||||
comp.hangup();
|
||||
|
||||
sinon.assert.calledOnce(model.endSession);
|
||||
});
|
||||
|
||||
it("should stop publishing local streams", function() {
|
||||
comp.hangup();
|
||||
|
||||
sinon.assert.calledOnce(fakeSession.unpublish);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#publish", function() {
|
||||
var view;
|
||||
|
||||
beforeEach(function() {
|
||||
view = new sharedViews.ConversationView({
|
||||
sdk: fakeSDK,
|
||||
model: model
|
||||
});
|
||||
});
|
||||
|
||||
describe("#startPublishing", function() {
|
||||
it("should publish local stream", function() {
|
||||
view.publish();
|
||||
comp.startPublishing();
|
||||
|
||||
sinon.assert.calledOnce(fakeSDK.initPublisher);
|
||||
sinon.assert.calledOnce(fakeSession.publish);
|
||||
|
@ -124,7 +257,7 @@ describe("loop.shared.views", function() {
|
|||
it("should start listening to OT publisher accessDialogOpened and " +
|
||||
" accessDenied events",
|
||||
function() {
|
||||
view.publish();
|
||||
comp.startPublishing();
|
||||
|
||||
sinon.assert.called(fakePublisher.on);
|
||||
sinon.assert.calledWith(fakePublisher.on, "accessDialogOpened");
|
||||
|
@ -132,26 +265,20 @@ describe("loop.shared.views", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("#unpublish", function() {
|
||||
var view;
|
||||
|
||||
describe("#stopPublishing", function() {
|
||||
beforeEach(function() {
|
||||
view = new sharedViews.ConversationView({
|
||||
sdk: fakeSDK,
|
||||
model: model
|
||||
});
|
||||
view.publish();
|
||||
comp.startPublishing();
|
||||
});
|
||||
|
||||
it("should unpublish local stream", function() {
|
||||
view.unpublish();
|
||||
it("should stop publish local stream", function() {
|
||||
comp.stopPublishing();
|
||||
|
||||
sinon.assert.calledOnce(fakeSession.unpublish);
|
||||
});
|
||||
|
||||
it("should unsubscribe from accessDialogOpened and accessDenied events",
|
||||
function() {
|
||||
view.unpublish();
|
||||
comp.stopPublishing();
|
||||
|
||||
sinon.assert.calledTwice(fakePublisher.off);
|
||||
sinon.assert.calledWith(fakePublisher.off, "accessDialogOpened");
|
||||
|
@ -159,79 +286,48 @@ describe("loop.shared.views", function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe("#toggleMuteAudio", function() {
|
||||
var view;
|
||||
describe("#publishStream", function() {
|
||||
var comp;
|
||||
|
||||
beforeEach(function() {
|
||||
view = new sharedViews.ConversationView({
|
||||
sdk: fakeSDK,
|
||||
model: model
|
||||
});
|
||||
view.publish();
|
||||
comp = mountTestComponent({sdk: fakeSDK, model: model});
|
||||
comp.startPublishing();
|
||||
});
|
||||
|
||||
it("should unpublish local audio when enabled", function() {
|
||||
view.localStream = {hasAudio: true};
|
||||
it("should start streaming local audio", function() {
|
||||
comp.publishStream("audio", true);
|
||||
|
||||
view.toggleMuteAudio({preventDefault: sandbox.spy()});
|
||||
sinon.assert.calledOnce(fakePublisher.publishAudio);
|
||||
sinon.assert.calledWithExactly(fakePublisher.publishAudio, true);
|
||||
});
|
||||
|
||||
it("should stop streaming local audio", function() {
|
||||
comp.publishStream("audio", false);
|
||||
|
||||
sinon.assert.calledOnce(fakePublisher.publishAudio);
|
||||
sinon.assert.calledWithExactly(fakePublisher.publishAudio, false);
|
||||
});
|
||||
|
||||
it("should publish local audio when disabled", function() {
|
||||
view.localStream = {hasAudio: false};
|
||||
|
||||
view.toggleMuteAudio({preventDefault: sandbox.spy()});
|
||||
|
||||
sinon.assert.calledOnce(fakePublisher.publishAudio);
|
||||
sinon.assert.calledWithExactly(fakePublisher.publishAudio, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("#toggleMuteVideo", function() {
|
||||
var view;
|
||||
|
||||
beforeEach(function() {
|
||||
view = new sharedViews.ConversationView({
|
||||
sdk: fakeSDK,
|
||||
model: model
|
||||
});
|
||||
view.publish();
|
||||
});
|
||||
|
||||
it("should unpublish local video when enabled", function() {
|
||||
view.localStream = {hasVideo: true};
|
||||
|
||||
view.toggleMuteVideo({preventDefault: sandbox.spy()});
|
||||
|
||||
sinon.assert.calledOnce(fakePublisher.publishVideo);
|
||||
sinon.assert.calledWithExactly(fakePublisher.publishVideo, false);
|
||||
});
|
||||
|
||||
it("should publish local video when disabled", function() {
|
||||
view.localStream = {hasVideo: false};
|
||||
|
||||
view.toggleMuteVideo({preventDefault: sandbox.spy()});
|
||||
it("should start streaming local video", function() {
|
||||
comp.publishStream("video", true);
|
||||
|
||||
sinon.assert.calledOnce(fakePublisher.publishVideo);
|
||||
sinon.assert.calledWithExactly(fakePublisher.publishVideo, true);
|
||||
});
|
||||
|
||||
it("should stop streaming local video", function() {
|
||||
comp.publishStream("video", false);
|
||||
|
||||
sinon.assert.calledOnce(fakePublisher.publishVideo);
|
||||
sinon.assert.calledWithExactly(fakePublisher.publishVideo, false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("Model events", function() {
|
||||
var view;
|
||||
|
||||
beforeEach(function() {
|
||||
sandbox.stub(sharedViews.ConversationView.prototype, "publish");
|
||||
sandbox.stub(sharedViews.ConversationView.prototype, "unpublish");
|
||||
view = new sharedViews.ConversationView({sdk: fakeSDK, model: model});
|
||||
});
|
||||
|
||||
it("should publish local stream on session:connected", function() {
|
||||
it("should start streaming on session:connected", function() {
|
||||
model.trigger("session:connected");
|
||||
|
||||
sinon.assert.calledOnce(view.publish);
|
||||
sinon.assert.calledOnce(fakeSDK.initPublisher);
|
||||
});
|
||||
|
||||
it("should publish remote streams on session:stream-created",
|
||||
|
@ -246,22 +342,28 @@ describe("loop.shared.views", function() {
|
|||
});
|
||||
|
||||
it("should unpublish local stream on session:ended", function() {
|
||||
comp.startPublishing();
|
||||
|
||||
model.trigger("session:ended");
|
||||
|
||||
sinon.assert.calledOnce(view.unpublish);
|
||||
sinon.assert.calledOnce(fakeSession.unpublish);
|
||||
});
|
||||
|
||||
it("should unpublish local stream on session:peer-hungup", function() {
|
||||
comp.startPublishing();
|
||||
|
||||
model.trigger("session:peer-hungup");
|
||||
|
||||
sinon.assert.calledOnce(view.unpublish);
|
||||
sinon.assert.calledOnce(fakeSession.unpublish);
|
||||
});
|
||||
|
||||
it("should unpublish local stream on session:network-disconnected",
|
||||
function() {
|
||||
comp.startPublishing();
|
||||
|
||||
model.trigger("session:network-disconnected");
|
||||
|
||||
sinon.assert.calledOnce(view.unpublish);
|
||||
sinon.assert.calledOnce(fakeSession.unpublish);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<div id="messages"></div>
|
||||
<div id="fixtures"></div>
|
||||
<!-- libs -->
|
||||
<script src="../../content/shared/libs/react-0.10.0.js"></script>
|
||||
<script src="../../content/shared/libs/jquery-2.1.0.js"></script>
|
||||
<script src="../../content/shared/libs/lodash-2.4.1.js"></script>
|
||||
<script src="../../content/shared/libs/backbone-1.1.2.js"></script>
|
||||
|
|
|
@ -75,6 +75,7 @@ describe("loop.webapp", function() {
|
|||
notifier: notifier
|
||||
});
|
||||
sandbox.stub(router, "loadView");
|
||||
sandbox.stub(router, "loadReactComponent");
|
||||
sandbox.stub(router, "navigate");
|
||||
});
|
||||
|
||||
|
@ -162,14 +163,16 @@ describe("loop.webapp", function() {
|
|||
|
||||
describe("#loadConversation", function() {
|
||||
it("should load the ConversationView if session is set", function() {
|
||||
sandbox.stub(sharedViews.ConversationView.prototype, "initialize");
|
||||
conversation.set("sessionId", "fakeSessionId");
|
||||
|
||||
router.loadConversation();
|
||||
|
||||
sinon.assert.calledOnce(router.loadView);
|
||||
sinon.assert.calledWith(router.loadView,
|
||||
sinon.match.instanceOf(sharedViews.ConversationView));
|
||||
sinon.assert.calledOnce(router.loadReactComponent);
|
||||
sinon.assert.calledWith(router.loadReactComponent,
|
||||
sinon.match(function(value) {
|
||||
return React.addons.TestUtils.isComponentOfType(
|
||||
value, loop.shared.views.ConversationView);
|
||||
}));
|
||||
});
|
||||
|
||||
it("should navigate to #call/{token} if session isn't ready",
|
||||
|
|
|
@ -411,6 +411,8 @@
|
|||
#endif
|
||||
@BINPATH@/components/nsUpdateTimerManager.manifest
|
||||
@BINPATH@/components/nsUpdateTimerManager.js
|
||||
@BINPATH@/components/addoncompat.manifest
|
||||
@BINPATH@/components/multiprocessShims.js
|
||||
@BINPATH@/components/pluginGlue.manifest
|
||||
@BINPATH@/browser/components/nsSessionStore.manifest
|
||||
@BINPATH@/browser/components/nsSessionStartup.js
|
||||
|
|
|
@ -18,11 +18,11 @@ incoming_call_title=Incoming Call…
|
|||
incoming_call=Incoming call
|
||||
accept_button=Accept
|
||||
decline_button=Decline
|
||||
hangup_button.title=Hangup
|
||||
mute_local_audio_button.title=Mute your audio
|
||||
unmute_local_audio_button.title=Unute your audio
|
||||
mute_local_video_button.title=Mute your video
|
||||
unmute_local_video_button.title=Unmute your video
|
||||
hangup_button_title=Hangup
|
||||
mute_local_audio_button_title=Mute your audio
|
||||
unmute_local_audio_button_title=Unmute your audio
|
||||
mute_local_video_button_title=Mute your video
|
||||
unmute_local_video_button_title=Unmute your video
|
||||
|
||||
peer_ended_conversation=Your peer ended the conversation.
|
||||
call_has_ended=Your call has ended.
|
||||
|
|
|
@ -842,7 +842,7 @@ this.UITour = {
|
|||
highlighter.style.width = highlightWidth + "px";
|
||||
|
||||
// Close a previous highlight so we can relocate the panel.
|
||||
if (highlighter.parentElement.state == "open") {
|
||||
if (highlighter.parentElement.state == "showing" || highlighter.parentElement.state == "open") {
|
||||
highlighter.parentElement.hidePopup();
|
||||
}
|
||||
/* The "overlap" position anchors from the top-left but we want to centre highlights at their
|
||||
|
@ -909,7 +909,7 @@ this.UITour = {
|
|||
let tooltipIcon = document.getElementById("UITourTooltipIcon");
|
||||
let tooltipButtons = document.getElementById("UITourTooltipButtons");
|
||||
|
||||
if (tooltip.state == "open") {
|
||||
if (tooltip.state == "showing" || tooltip.state == "open") {
|
||||
tooltip.hidePopup();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,9 +24,9 @@ skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
|
|||
[browser_UITour_detach_tab.js]
|
||||
skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
|
||||
[browser_UITour_annotation_size_attributes.js]
|
||||
skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
|
||||
skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly.
|
||||
[browser_UITour_panel_close_annotation.js]
|
||||
skip-if = e10s || os == "win" # Bug 941428 - UITour.jsm not e10s friendly. Intermittent test failures on Windows (bug 1026310 & bug 1032137)
|
||||
skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
|
||||
[browser_UITour_registerPageID.js]
|
||||
skip-if = e10s # Bug 941428 - UITour.jsm not e10s friendly
|
||||
[browser_UITour_sync.js]
|
||||
|
|
|
@ -11339,7 +11339,7 @@ public:
|
|||
mDocument(do_GetWeakReference(aElement->OwnerDoc())),
|
||||
mUserInputOrChromeCaller(aUserInputOrChromeCaller) {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSICONTENTPERMISSIONREQUEST
|
||||
|
||||
NS_IMETHOD Run()
|
||||
|
|
|
@ -19,7 +19,7 @@ class EncodingCompleteEvent : public nsRunnable
|
|||
virtual ~EncodingCompleteEvent() {}
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
EncodingCompleteEvent(nsIGlobalObject* aGlobal,
|
||||
nsIThread* aEncoderThread,
|
||||
|
@ -85,14 +85,14 @@ private:
|
|||
bool mFailed;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(EncodingCompleteEvent, nsIRunnable);
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(EncodingCompleteEvent, nsRunnable);
|
||||
|
||||
class EncodingRunnable : public nsRunnable
|
||||
{
|
||||
virtual ~EncodingRunnable() {}
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
EncodingRunnable(const nsAString& aType,
|
||||
const nsAString& aOptions,
|
||||
|
@ -180,7 +180,7 @@ private:
|
|||
bool mUsingCustomOptions;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(EncodingRunnable, nsIRunnable)
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(EncodingRunnable, nsRunnable);
|
||||
|
||||
/* static */
|
||||
nsresult
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
namespace {
|
||||
class TimerEvent : public nsITimerCallback, public nsRunnable {
|
||||
typedef mozilla::MediaDecoderStateMachineScheduler Scheduler;
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
public:
|
||||
TimerEvent(Scheduler* aScheduler, int aTimerId)
|
||||
: mScheduler(aScheduler), mTimerId(aTimerId) {}
|
||||
|
@ -32,7 +32,7 @@ private:
|
|||
const int mTimerId;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(TimerEvent, nsITimerCallback, nsIRunnable);
|
||||
NS_IMPL_ISUPPORTS_INHERITED(TimerEvent, nsRunnable, nsITimerCallback);
|
||||
} // anonymous namespace
|
||||
|
||||
static already_AddRefed<nsIEventTarget>
|
||||
|
|
|
@ -129,12 +129,14 @@ SourceBufferResource::ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCo
|
|||
bool
|
||||
SourceBufferResource::EvictData(uint32_t aThreshold)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
return mInputBuffer.Evict(mOffset, aThreshold);
|
||||
}
|
||||
|
||||
void
|
||||
SourceBufferResource::EvictBefore(uint64_t aOffset)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mMonitor);
|
||||
// If aOffset is past the current playback offset we don't evict.
|
||||
if (aOffset < mOffset) {
|
||||
mInputBuffer.Evict(aOffset, 0);
|
||||
|
|
|
@ -72,11 +72,6 @@ private:
|
|||
};
|
||||
|
||||
class ResourceQueue : private nsDeque {
|
||||
private:
|
||||
// Logical offset into the resource of the first element
|
||||
// in the queue.
|
||||
uint64_t mOffset;
|
||||
|
||||
public:
|
||||
ResourceQueue() :
|
||||
nsDeque(new ResourceQueueDeallocator()),
|
||||
|
@ -84,25 +79,11 @@ private:
|
|||
{
|
||||
}
|
||||
|
||||
// Clears all items from the queue
|
||||
inline void Clear() {
|
||||
return nsDeque::Erase();
|
||||
}
|
||||
|
||||
// Returns the number of items in the queue
|
||||
inline uint32_t GetSize() {
|
||||
return nsDeque::GetSize();
|
||||
}
|
||||
|
||||
// Returns the logical byte offset of the start of the data.
|
||||
inline uint64_t GetOffset() {
|
||||
return mOffset;
|
||||
}
|
||||
|
||||
inline ResourceItem* ResourceAt(uint32_t aIndex) {
|
||||
return static_cast<ResourceItem*>(nsDeque::ObjectAt(aIndex));
|
||||
}
|
||||
|
||||
// Returns the length of all items in the queue plus the offset.
|
||||
// This is the logical length of the resource.
|
||||
inline uint64_t GetLength() {
|
||||
|
@ -114,29 +95,6 @@ private:
|
|||
return s;
|
||||
}
|
||||
|
||||
// Returns the index of the resource that contains the given
|
||||
// logical offset. aResourceOffset will contain the offset into
|
||||
// the resource at the given index returned if it is not null. If
|
||||
// no such resource exists, returns GetSize() and aOffset is
|
||||
// untouched.
|
||||
inline uint32_t GetAtOffset(uint64_t aOffset, uint32_t *aResourceOffset) {
|
||||
MOZ_ASSERT(aOffset >= mOffset);
|
||||
uint64_t offset = mOffset;
|
||||
for (uint32_t i = 0; i < GetSize(); ++i) {
|
||||
ResourceItem* item = ResourceAt(i);
|
||||
// If the item contains the start of the offset we want to
|
||||
// break out of the loop.
|
||||
if (item->mData.Length() + offset > aOffset) {
|
||||
if (aResourceOffset) {
|
||||
*aResourceOffset = aOffset - offset;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
offset += item->mData.Length();
|
||||
}
|
||||
return GetSize();
|
||||
}
|
||||
|
||||
// Copies aCount bytes from aOffset in the queue into aDest.
|
||||
inline void CopyData(uint64_t aOffset, uint32_t aCount, char* aDest) {
|
||||
uint32_t offset = 0;
|
||||
|
@ -158,18 +116,6 @@ private:
|
|||
nsDeque::Push(aItem);
|
||||
}
|
||||
|
||||
inline void PushFront(ResourceItem* aItem) {
|
||||
nsDeque::PushFront(aItem);
|
||||
}
|
||||
|
||||
inline ResourceItem* PopBack() {
|
||||
return static_cast<ResourceItem*>(nsDeque::Pop());
|
||||
}
|
||||
|
||||
inline ResourceItem* PopFront() {
|
||||
return static_cast<ResourceItem*>(nsDeque::PopFront());
|
||||
}
|
||||
|
||||
// Evict data in queue if the total queue size is greater than
|
||||
// aThreshold past the offset. Returns true if some data was
|
||||
// actually evicted.
|
||||
|
@ -200,6 +146,47 @@ private:
|
|||
|
||||
return size;
|
||||
}
|
||||
|
||||
private:
|
||||
// Returns the number of items in the queue
|
||||
inline uint32_t GetSize() {
|
||||
return nsDeque::GetSize();
|
||||
}
|
||||
|
||||
inline ResourceItem* ResourceAt(uint32_t aIndex) {
|
||||
return static_cast<ResourceItem*>(nsDeque::ObjectAt(aIndex));
|
||||
}
|
||||
|
||||
// Returns the index of the resource that contains the given
|
||||
// logical offset. aResourceOffset will contain the offset into
|
||||
// the resource at the given index returned if it is not null. If
|
||||
// no such resource exists, returns GetSize() and aOffset is
|
||||
// untouched.
|
||||
inline uint32_t GetAtOffset(uint64_t aOffset, uint32_t *aResourceOffset) {
|
||||
MOZ_ASSERT(aOffset >= mOffset);
|
||||
uint64_t offset = mOffset;
|
||||
for (uint32_t i = 0; i < GetSize(); ++i) {
|
||||
ResourceItem* item = ResourceAt(i);
|
||||
// If the item contains the start of the offset we want to
|
||||
// break out of the loop.
|
||||
if (item->mData.Length() + offset > aOffset) {
|
||||
if (aResourceOffset) {
|
||||
*aResourceOffset = aOffset - offset;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
offset += item->mData.Length();
|
||||
}
|
||||
return GetSize();
|
||||
}
|
||||
|
||||
inline ResourceItem* PopFront() {
|
||||
return static_cast<ResourceItem*>(nsDeque::PopFront());
|
||||
}
|
||||
|
||||
// Logical offset into the resource of the first element
|
||||
// in the queue.
|
||||
uint64_t mOffset;
|
||||
};
|
||||
|
||||
public:
|
||||
|
|
|
@ -346,7 +346,6 @@ public:
|
|||
// on requests.
|
||||
nsRefPtr<MediaResourceServer> mServer;
|
||||
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSISERVERSOCKETLISTENER
|
||||
|
||||
|
@ -355,6 +354,7 @@ public:
|
|||
{
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~ResourceSocketListener() { }
|
||||
};
|
||||
|
||||
|
|
|
@ -117,6 +117,8 @@ NS_IMPL_RELEASE(WMFByteStream)
|
|||
|
||||
// Stores data regarding an async read opreation.
|
||||
class ReadRequest MOZ_FINAL : public IUnknown {
|
||||
~ReadRequest() {}
|
||||
|
||||
public:
|
||||
ReadRequest(int64_t aOffset, BYTE* aBuffer, ULONG aLength)
|
||||
: mOffset(aOffset),
|
||||
|
@ -394,17 +396,17 @@ STDMETHODIMP
|
|||
WMFByteStream::Read(BYTE* aBuffer, ULONG aBufferLength, ULONG* aOutBytesRead)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
ReadRequest request(mOffset, aBuffer, aBufferLength);
|
||||
if (NS_FAILED(Read(&request))) {
|
||||
nsRefPtr<ReadRequest> request = new ReadRequest(mOffset, aBuffer, aBufferLength);
|
||||
if (NS_FAILED(Read(request))) {
|
||||
WMF_BS_LOG("[%p] WMFByteStream::Read() offset=%lld failed!", this, mOffset);
|
||||
return E_FAIL;
|
||||
}
|
||||
if (aOutBytesRead) {
|
||||
*aOutBytesRead = request.mBytesRead;
|
||||
*aOutBytesRead = request->mBytesRead;
|
||||
}
|
||||
WMF_BS_LOG("[%p] WMFByteStream::Read() offset=%lld length=%u bytesRead=%u",
|
||||
this, mOffset, aBufferLength, request.mBytesRead);
|
||||
mOffset += request.mBytesRead;
|
||||
this, mOffset, aBufferLength, request->mBytesRead);
|
||||
mOffset += request->mBytesRead;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -36,9 +36,10 @@ class SharedThreadPool;
|
|||
class WMFByteStream MOZ_FINAL : public IMFByteStream
|
||||
, public IMFAttributes
|
||||
{
|
||||
~WMFByteStream();
|
||||
|
||||
public:
|
||||
WMFByteStream(MediaResource* aResource, WMFSourceReaderCallback* aCallback);
|
||||
~WMFByteStream();
|
||||
|
||||
nsresult Init();
|
||||
nsresult Shutdown();
|
||||
|
|
|
@ -21,6 +21,8 @@ namespace mozilla {
|
|||
// when the MediaResource is unexpectedly shutdown.
|
||||
class WMFSourceReaderCallback MOZ_FINAL : public IMFSourceReaderCallback
|
||||
{
|
||||
~WMFSourceReaderCallback() {}
|
||||
|
||||
public:
|
||||
WMFSourceReaderCallback();
|
||||
|
||||
|
|
|
@ -1213,7 +1213,7 @@ MappedAttrParser::CreateStyleRule()
|
|||
return nullptr; // No mapped attributes were parsed
|
||||
}
|
||||
|
||||
nsRefPtr<css::StyleRule> rule = new css::StyleRule(nullptr, mDecl);
|
||||
nsRefPtr<css::StyleRule> rule = new css::StyleRule(nullptr, mDecl, 0, 0);
|
||||
mDecl = nullptr; // We no longer own the declaration -- drop our pointer to it
|
||||
return rule.forget();
|
||||
}
|
||||
|
|
|
@ -3399,12 +3399,20 @@ this.DOMApplicationRegistry = {
|
|||
debug("Setting origin to " + uri.prePath +
|
||||
" for " + aOldApp.manifestURL);
|
||||
let newId = uri.prePath.substring(6); // "app://".length
|
||||
if (newId in this.webapps) {
|
||||
if (newId in this.webapps && this._isLaunchable(this.webapps[newId])) {
|
||||
throw "DUPLICATE_ORIGIN";
|
||||
}
|
||||
aOldApp.origin = uri.prePath;
|
||||
// Update the registry.
|
||||
let oldId = aOldApp.id;
|
||||
|
||||
if (oldId == newId) {
|
||||
// This could happen when we have an app in the registry
|
||||
// that is not launchable. Since the app already has
|
||||
// the correct id, we don't need to change it.
|
||||
return;
|
||||
}
|
||||
|
||||
aOldApp.id = newId;
|
||||
this.webapps[newId] = aOldApp;
|
||||
delete this.webapps[oldId];
|
||||
|
|
|
@ -2196,33 +2196,6 @@ Navigator::HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */)
|
|||
return !!pmService;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
Navigator::HasMobileMessageSupport(JSContext* /* unused */, JSObject* aGlobal)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
|
||||
|
||||
#ifndef MOZ_WEBSMS_BACKEND
|
||||
return false;
|
||||
#endif
|
||||
|
||||
// First of all, the general pref has to be turned on.
|
||||
bool enabled = false;
|
||||
Preferences::GetBool("dom.sms.enabled", &enabled);
|
||||
if (!enabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(win, false);
|
||||
NS_ENSURE_TRUE(win->GetDocShell(), false);
|
||||
|
||||
if (!CheckPermission(win, "sms")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
Navigator::HasCameraSupport(JSContext* /* unused */, JSObject* aGlobal)
|
||||
|
@ -2268,16 +2241,6 @@ Navigator::HasNFCSupport(JSContext* /* unused */, JSObject* aGlobal)
|
|||
}
|
||||
#endif // MOZ_NFC
|
||||
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
/* static */
|
||||
bool
|
||||
Navigator::HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
|
||||
return win && CheckPermission(win, "time");
|
||||
}
|
||||
#endif // MOZ_TIME_MANAGER
|
||||
|
||||
#ifdef MOZ_MEDIA_NAVIGATOR
|
||||
/* static */
|
||||
bool
|
||||
|
@ -2379,22 +2342,6 @@ Navigator::HasDataStoreSupport(JSContext* aCx, JSObject* aGlobal)
|
|||
return HasDataStoreSupport(doc->NodePrincipal());
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
Navigator::HasNetworkStatsSupport(JSContext* /* unused */, JSObject* aGlobal)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
|
||||
return CheckPermission(win, "networkstats-manage");
|
||||
}
|
||||
|
||||
/* static */
|
||||
bool
|
||||
Navigator::HasFeatureDetectionSupport(JSContext* /* unused */, JSObject* aGlobal)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> win = GetWindowFromGlobal(aGlobal);
|
||||
return CheckPermission(win, "feature-detection");
|
||||
}
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
/* static */
|
||||
bool
|
||||
|
|
|
@ -268,8 +268,6 @@ public:
|
|||
|
||||
// WebIDL helper methods
|
||||
static bool HasWakeLockSupport(JSContext* /* unused*/, JSObject* /*unused */);
|
||||
static bool HasMobileMessageSupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal);
|
||||
static bool HasCameraSupport(JSContext* /* unused */,
|
||||
JSObject* aGlobal);
|
||||
static bool HasWifiManagerSupport(JSContext* /* unused */,
|
||||
|
@ -277,9 +275,6 @@ public:
|
|||
#ifdef MOZ_NFC
|
||||
static bool HasNFCSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
#endif // MOZ_NFC
|
||||
#ifdef MOZ_TIME_MANAGER
|
||||
static bool HasTimeSupport(JSContext* /* unused */, JSObject* aGlobal);
|
||||
#endif // MOZ_TIME_MANAGER
|
||||
#ifdef MOZ_MEDIA_NAVIGATOR
|
||||
static bool HasUserMediaSupport(JSContext* /* unused */,
|
||||
JSObject* /* unused */);
|
||||
|
@ -291,10 +286,6 @@ public:
|
|||
|
||||
static bool HasDataStoreSupport(JSContext* cx, JSObject* aGlobal);
|
||||
|
||||
static bool HasNetworkStatsSupport(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
static bool HasFeatureDetectionSupport(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
#ifdef MOZ_B2G
|
||||
static bool HasMobileIdSupport(JSContext* aCx, JSObject* aGlobal);
|
||||
#endif
|
||||
|
|
|
@ -370,10 +370,9 @@ AsyncErrorReporter::AsyncErrorReporter(JSRuntime* aRuntime,
|
|||
|
||||
const char16_t* m = static_cast<const char16_t*>(aErrorReport->ucmessage);
|
||||
if (m) {
|
||||
const char16_t* n = static_cast<const char16_t*>
|
||||
(js::GetErrorTypeName(aRuntime, aErrorReport->exnType));
|
||||
if (n) {
|
||||
mErrorMsg.Assign(n);
|
||||
JSFlatString* name = js::GetErrorTypeName(aRuntime, aErrorReport->exnType);
|
||||
if (name) {
|
||||
AssignJSFlatString(mErrorMsg, name);
|
||||
mErrorMsg.AppendLiteral(": ");
|
||||
}
|
||||
mErrorMsg.Append(m);
|
||||
|
|
|
@ -365,9 +365,12 @@ InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp)
|
|||
const JSClass* clasp = static_cast<const JSClass*>(v.toPrivate());
|
||||
|
||||
v = js::GetFunctionNativeReserved(callee, TOSTRING_NAME_RESERVED_SLOT);
|
||||
JSString* jsname = static_cast<JSString*>(v.toString());
|
||||
size_t length;
|
||||
const jschar* name = JS_GetInternedStringCharsAndLength(jsname, &length);
|
||||
JSString* jsname = v.toString();
|
||||
|
||||
nsAutoJSString name;
|
||||
if (!name.init(cx, jsname)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (js::GetObjectJSClass(&args.thisv().toObject()) != clasp) {
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
|
||||
|
@ -379,7 +382,7 @@ InterfaceObjectToString(JSContext* cx, unsigned argc, JS::Value *vp)
|
|||
|
||||
nsString str;
|
||||
str.AppendLiteral("function ");
|
||||
str.Append(name, length);
|
||||
str.Append(name);
|
||||
str.AppendLiteral("() {");
|
||||
str.Append('\n');
|
||||
str.AppendLiteral(" [native code]");
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#define WEBCRYPTO_ALG_PBKDF2 "PBKDF2"
|
||||
#define WEBCRYPTO_ALG_RSAES_PKCS1 "RSAES-PKCS1-v1_5"
|
||||
#define WEBCRYPTO_ALG_RSASSA_PKCS1 "RSASSA-PKCS1-v1_5"
|
||||
#define WEBCRYPTO_ALG_RSA_OAEP "RSA-OAEP"
|
||||
|
||||
// WebCrypto key formats
|
||||
#define WEBCRYPTO_KEY_FORMAT_RAW "raw"
|
||||
|
@ -146,6 +147,8 @@ MapAlgorithmNameToMechanism(const nsString& aName)
|
|||
mechanism = CKM_RSA_PKCS;
|
||||
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
|
||||
mechanism = CKM_RSA_PKCS;
|
||||
} else if (aName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
mechanism = CKM_RSA_PKCS_OAEP;
|
||||
}
|
||||
|
||||
return mechanism;
|
||||
|
|
|
@ -303,7 +303,7 @@ class AesTask : public ReturnArrayBufferViewTask
|
|||
{
|
||||
public:
|
||||
AesTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
|
||||
mozilla::dom::CryptoKey& aKey, const CryptoOperationData& aData,
|
||||
CryptoKey& aKey, const CryptoOperationData& aData,
|
||||
bool aEncrypt)
|
||||
: mSymKey(aKey.GetSymKey())
|
||||
, mEncrypt(aEncrypt)
|
||||
|
@ -480,7 +480,7 @@ class RsaesPkcs1Task : public ReturnArrayBufferViewTask
|
|||
{
|
||||
public:
|
||||
RsaesPkcs1Task(JSContext* aCx, const ObjectOrString& aAlgorithm,
|
||||
mozilla::dom::CryptoKey& aKey, const CryptoOperationData& aData,
|
||||
CryptoKey& aKey, const CryptoOperationData& aData,
|
||||
bool aEncrypt)
|
||||
: mPrivKey(aKey.GetPrivateKey())
|
||||
, mPubKey(aKey.GetPublicKey())
|
||||
|
@ -549,11 +549,134 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
class RsaOaepTask : public ReturnArrayBufferViewTask
|
||||
{
|
||||
public:
|
||||
RsaOaepTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
|
||||
CryptoKey& aKey, const CryptoOperationData& aData,
|
||||
bool aEncrypt)
|
||||
: mPrivKey(aKey.GetPrivateKey())
|
||||
, mPubKey(aKey.GetPublicKey())
|
||||
, mEncrypt(aEncrypt)
|
||||
{
|
||||
Telemetry::Accumulate(Telemetry::WEBCRYPTO_ALG, TA_RSA_OAEP);
|
||||
|
||||
ATTEMPT_BUFFER_INIT(mData, aData);
|
||||
|
||||
if (mEncrypt) {
|
||||
if (!mPubKey) {
|
||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
return;
|
||||
}
|
||||
mStrength = SECKEY_PublicKeyStrength(mPubKey);
|
||||
} else {
|
||||
if (!mPrivKey) {
|
||||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
return;
|
||||
}
|
||||
mStrength = PK11_GetPrivateModulusLen(mPrivKey);
|
||||
}
|
||||
|
||||
RootedDictionary<RsaOaepParams> params(aCx);
|
||||
mEarlyRv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(mEarlyRv)) {
|
||||
mEarlyRv = NS_ERROR_DOM_SYNTAX_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (params.mLabel.WasPassed() && !params.mLabel.Value().IsNull()) {
|
||||
ATTEMPT_BUFFER_INIT(mLabel, params.mLabel.Value().Value());
|
||||
}
|
||||
// Otherwise mLabel remains the empty octet string, as intended
|
||||
|
||||
// Look up the MGF based on the KeyAlgorithm.
|
||||
// static_cast is safe because we only get here if the algorithm name
|
||||
// is RSA-OAEP, and that only happens if we've constructed
|
||||
// an RsaHashedKeyAlgorithm.
|
||||
// TODO: Add As* methods to KeyAlgorithm (Bug 1036734)
|
||||
nsRefPtr<RsaHashedKeyAlgorithm> rsaAlg =
|
||||
static_cast<RsaHashedKeyAlgorithm*>(aKey.Algorithm());
|
||||
mHashMechanism = rsaAlg->Hash()->Mechanism();
|
||||
|
||||
switch (mHashMechanism) {
|
||||
case CKM_SHA_1:
|
||||
mMgfMechanism = CKG_MGF1_SHA1; break;
|
||||
case CKM_SHA256:
|
||||
mMgfMechanism = CKG_MGF1_SHA256; break;
|
||||
case CKM_SHA384:
|
||||
mMgfMechanism = CKG_MGF1_SHA384; break;
|
||||
case CKM_SHA512:
|
||||
mMgfMechanism = CKG_MGF1_SHA512; break;
|
||||
default: {
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
CK_MECHANISM_TYPE mHashMechanism;
|
||||
CK_MECHANISM_TYPE mMgfMechanism;
|
||||
ScopedSECKEYPrivateKey mPrivKey;
|
||||
ScopedSECKEYPublicKey mPubKey;
|
||||
CryptoBuffer mLabel;
|
||||
CryptoBuffer mData;
|
||||
uint32_t mStrength;
|
||||
bool mEncrypt;
|
||||
|
||||
virtual nsresult DoCrypto() MOZ_OVERRIDE
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
// Ciphertext is an integer mod the modulus, so it will be
|
||||
// no longer than mStrength octets
|
||||
if (!mResult.SetLength(mStrength)) {
|
||||
return NS_ERROR_DOM_UNKNOWN_ERR;
|
||||
}
|
||||
|
||||
CK_RSA_PKCS_OAEP_PARAMS oaepParams;
|
||||
oaepParams.source = CKZ_DATA_SPECIFIED;
|
||||
|
||||
oaepParams.pSourceData = mLabel.Length() ? mLabel.Elements() : nullptr;
|
||||
oaepParams.ulSourceDataLen = mLabel.Length();
|
||||
|
||||
oaepParams.mgf = mMgfMechanism;
|
||||
oaepParams.hashAlg = mHashMechanism;
|
||||
|
||||
SECItem param;
|
||||
param.type = siBuffer;
|
||||
param.data = (unsigned char*) &oaepParams;
|
||||
param.len = sizeof(oaepParams);
|
||||
|
||||
uint32_t outLen;
|
||||
if (mEncrypt) {
|
||||
// PK11_PubEncrypt() checks the plaintext's length and fails if it is too
|
||||
// long to encrypt, i.e. if it is longer than (k - 2hLen - 2) with 'k'
|
||||
// being the length in octets of the RSA modulus n and 'hLen' being the
|
||||
// output length in octets of the chosen hash function.
|
||||
// <https://tools.ietf.org/html/rfc3447#section-7.1>
|
||||
rv = MapSECStatus(PK11_PubEncrypt(
|
||||
mPubKey.get(), CKM_RSA_PKCS_OAEP, ¶m,
|
||||
mResult.Elements(), &outLen, mResult.Length(),
|
||||
mData.Elements(), mData.Length(), nullptr));
|
||||
} else {
|
||||
rv = MapSECStatus(PK11_PrivDecrypt(
|
||||
mPrivKey.get(), CKM_RSA_PKCS_OAEP, ¶m,
|
||||
mResult.Elements(), &outLen, mResult.Length(),
|
||||
mData.Elements(), mData.Length()));
|
||||
}
|
||||
mResult.SetLength(outLen);
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_OPERATION_ERR);
|
||||
return NS_OK;
|
||||
}
|
||||
};
|
||||
|
||||
class HmacTask : public WebCryptoTask
|
||||
{
|
||||
public:
|
||||
HmacTask(JSContext* aCx, const ObjectOrString& aAlgorithm,
|
||||
mozilla::dom::CryptoKey& aKey,
|
||||
CryptoKey& aKey,
|
||||
const CryptoOperationData& aSignature,
|
||||
const CryptoOperationData& aData,
|
||||
bool aSign)
|
||||
|
@ -656,7 +779,7 @@ class RsassaPkcs1Task : public WebCryptoTask
|
|||
{
|
||||
public:
|
||||
RsassaPkcs1Task(JSContext* aCx, const ObjectOrString& aAlgorithm,
|
||||
mozilla::dom::CryptoKey& aKey,
|
||||
CryptoKey& aKey,
|
||||
const CryptoOperationData& aSignature,
|
||||
const CryptoOperationData& aData,
|
||||
bool aSign)
|
||||
|
@ -1017,7 +1140,8 @@ public:
|
|||
}
|
||||
|
||||
// If this is RSA with a hash, cache the hash name
|
||||
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
|
||||
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
RootedDictionary<RsaHashedImportParams> params(aCx);
|
||||
mEarlyRv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(mEarlyRv) || !params.mHash.WasPassed()) {
|
||||
|
@ -1088,15 +1212,14 @@ private:
|
|||
{
|
||||
// Construct an appropriate KeyAlgorithm
|
||||
nsIGlobalObject* global = mKey->GetParentObject();
|
||||
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) {
|
||||
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1) ||
|
||||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
if ((mKey->GetKeyType() == CryptoKey::PUBLIC &&
|
||||
mKey->HasUsageOtherThan(CryptoKey::ENCRYPT)) ||
|
||||
(mKey->GetKeyType() == CryptoKey::PRIVATE &&
|
||||
mKey->HasUsageOtherThan(CryptoKey::DECRYPT))) {
|
||||
return NS_ERROR_DOM_DATA_ERR;
|
||||
}
|
||||
|
||||
mKey->SetAlgorithm(new RsaKeyAlgorithm(global, mAlgName, mModulusLength, mPublicExponent));
|
||||
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
|
||||
if ((mKey->GetKeyType() == CryptoKey::PUBLIC &&
|
||||
mKey->HasUsageOtherThan(CryptoKey::VERIFY)) ||
|
||||
|
@ -1104,16 +1227,23 @@ private:
|
|||
mKey->HasUsageOtherThan(CryptoKey::SIGN))) {
|
||||
return NS_ERROR_DOM_DATA_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
nsRefPtr<RsaHashedKeyAlgorithm> algorithm = new RsaHashedKeyAlgorithm(
|
||||
global,
|
||||
mAlgName,
|
||||
mModulusLength,
|
||||
mPublicExponent,
|
||||
mHashName);
|
||||
// Construct an appropriate KeyAlgorithm
|
||||
if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) {
|
||||
mKey->SetAlgorithm(new RsaKeyAlgorithm(global, mAlgName, mModulusLength, mPublicExponent));
|
||||
} else if (mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
mAlgName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
nsRefPtr<RsaHashedKeyAlgorithm> algorithm =
|
||||
new RsaHashedKeyAlgorithm(global, mAlgName,
|
||||
mModulusLength, mPublicExponent, mHashName);
|
||||
if (algorithm->Mechanism() == UNKNOWN_CK_MECHANISM) {
|
||||
return NS_ERROR_DOM_SYNTAX_ERR;
|
||||
}
|
||||
|
||||
if (algorithm->Hash()->Mechanism() == UNKNOWN_CK_MECHANISM) {
|
||||
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
}
|
||||
mKey->SetAlgorithm(algorithm);
|
||||
}
|
||||
|
||||
|
@ -1345,7 +1475,8 @@ public:
|
|||
// Construct an appropriate KeyAlorithm
|
||||
KeyAlgorithm* algorithm;
|
||||
uint32_t privateAllowedUsages = 0, publicAllowedUsages = 0;
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
RootedDictionary<RsaHashedKeyGenParams> params(aCx);
|
||||
mEarlyRv = Coerce(aCx, params, aAlgorithm);
|
||||
if (NS_FAILED(mEarlyRv) || !params.mModulusLength.WasPassed() ||
|
||||
|
@ -1380,9 +1511,6 @@ public:
|
|||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
privateAllowedUsages = CryptoKey::SIGN;
|
||||
publicAllowedUsages = CryptoKey::VERIFY;
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) {
|
||||
RootedDictionary<RsaKeyGenParams> params(aCx);
|
||||
mEarlyRv = Coerce(aCx, params, aAlgorithm);
|
||||
|
@ -1411,14 +1539,21 @@ public:
|
|||
mEarlyRv = NS_ERROR_DOM_INVALID_ACCESS_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
privateAllowedUsages = CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY;
|
||||
publicAllowedUsages = CryptoKey::ENCRYPT | CryptoKey::WRAPKEY;
|
||||
} else {
|
||||
mEarlyRv = NS_ERROR_DOM_NOT_SUPPORTED_ERR;
|
||||
return;
|
||||
}
|
||||
|
||||
// Set key usages.
|
||||
if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
|
||||
privateAllowedUsages = CryptoKey::SIGN;
|
||||
publicAllowedUsages = CryptoKey::VERIFY;
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
privateAllowedUsages = CryptoKey::DECRYPT | CryptoKey::UNWRAPKEY;
|
||||
publicAllowedUsages = CryptoKey::ENCRYPT | CryptoKey::WRAPKEY;
|
||||
}
|
||||
|
||||
mKeyPair->PrivateKey()->SetExtractable(aExtractable);
|
||||
mKeyPair->PrivateKey()->SetType(CryptoKey::PRIVATE);
|
||||
|
||||
|
@ -1676,6 +1811,8 @@ WebCryptoTask::EncryptDecryptTask(JSContext* aCx,
|
|||
return new AesTask(aCx, aAlgorithm, aKey, aData, aEncrypt);
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1)) {
|
||||
return new RsaesPkcs1Task(aCx, aAlgorithm, aKey, aData, aEncrypt);
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
return new RsaOaepTask(aCx, aAlgorithm, aKey, aData, aEncrypt);
|
||||
}
|
||||
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
|
@ -1748,7 +1885,8 @@ WebCryptoTask::ImportKeyTask(JSContext* aCx,
|
|||
return new ImportSymmetricKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
|
||||
aExtractable, aKeyUsages);
|
||||
} else if (algName.EqualsLiteral(WEBCRYPTO_ALG_RSAES_PKCS1) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
algName.EqualsLiteral(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
return new ImportRsaKeyTask(aCx, aFormat, aKeyData, aAlgorithm,
|
||||
aExtractable, aKeyUsages);
|
||||
} else {
|
||||
|
@ -1790,7 +1928,8 @@ WebCryptoTask::GenerateKeyTask(JSContext* aCx,
|
|||
algName.EqualsASCII(WEBCRYPTO_ALG_HMAC)) {
|
||||
return new GenerateSymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
|
||||
} else if (algName.EqualsASCII(WEBCRYPTO_ALG_RSAES_PKCS1) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1)) {
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_RSASSA_PKCS1) ||
|
||||
algName.EqualsASCII(WEBCRYPTO_ALG_RSA_OAEP)) {
|
||||
return new GenerateAsymmetricKeyTask(aCx, aAlgorithm, aExtractable, aKeyUsages);
|
||||
} else {
|
||||
return new FailureTask(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[DEFAULT]
|
||||
# Bug 1010743 - Re-enable WebCrypto tests on b2g-desktop
|
||||
skip-if = (buildapp == 'b2g' && toolkit != 'gonk')
|
||||
# Bug 1010743 - Re-enable WebCrypto tests on b2g
|
||||
skip-if = (buildapp == 'b2g')
|
||||
support-files =
|
||||
test-array.js
|
||||
test-vectors.js
|
||||
|
|
|
@ -311,6 +311,50 @@ tv = {
|
|||
),
|
||||
},
|
||||
|
||||
// RSA test vectors, oaep-vect.txt, Example 1.1: A 1024-bit RSA Key Pair
|
||||
// <ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip>
|
||||
rsaoaep: {
|
||||
pkcs8: util.hex2abv(
|
||||
"30820276020100300d06092a864886f70d0101010500048202603082025c0201" +
|
||||
"0002818100a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae" +
|
||||
"4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630" +
|
||||
"f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fa" +
|
||||
"b9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de" +
|
||||
"88d39f16fb020301000102818053339cfdb79fc8466a655c7316aca85c55fd8f" +
|
||||
"6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a55" +
|
||||
"3d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c4831" +
|
||||
"16ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0c" +
|
||||
"f539e9cfcdd3de653729ead5d1024100d32737e7267ffe1341b2d5c0d150a81b" +
|
||||
"586fb3132bed2f8d5262864a9cb9f30af38be448598d413a172efb802c21acf1" +
|
||||
"c11c520c2f26a471dcad212eac7ca39d024100cc8853d1d54da630fac004f471" +
|
||||
"f281c7b8982d8224a490edbeb33d3e3d5cc93c4765703d1dd791642f1f116a0d" +
|
||||
"d852be2419b2af72bfe9a030e860b0288b5d7702400e12bf1718e9cef5599ba1" +
|
||||
"c3882fe8046a90874eefce8f2ccc20e4f2741fb0a33a3848aec9c9305fbecbd2" +
|
||||
"d76819967d4671acc6431e4037968db37878e695c102410095297b0f95a2fa67" +
|
||||
"d00707d609dfd4fc05c89dafc2ef6d6ea55bec771ea333734d9251e79082ecda" +
|
||||
"866efef13c459e1a631386b7e354c899f5f112ca85d7158302404f456c502493" +
|
||||
"bdc0ed2ab756a3a6ed4d67352a697d4216e93212b127a63d5411ce6fa98d5dbe" +
|
||||
"fd73263e3728142743818166ed7dd63687dd2a8ca1d2f4fbd8e1"
|
||||
),
|
||||
spki: util.hex2abv(
|
||||
"30819f300d06092a864886f70d010101050003818d0030818902818100a8b3b2" +
|
||||
"84af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0" +
|
||||
"b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae8" +
|
||||
"33c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef739" +
|
||||
"2dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb020301" +
|
||||
"0001"
|
||||
),
|
||||
data: util.hex2abv(
|
||||
"6628194e12073db03ba94cda9ef9532397d50dba79b987004afefe34"
|
||||
),
|
||||
result: util.hex2abv(
|
||||
"354fe67b4a126d5d35fe36c777791a3f7ba13def484e2d3908aff722fad468fb" +
|
||||
"21696de95d0be911c2d3174f8afcc201035f7b6d8e69402de5451618c21a535f" +
|
||||
"a9d7bfc5b8dd9fc243f8cf927db31322d6e881eaa91a996170e657a05a266426" +
|
||||
"d98c88003f8477c1227094a0d9fa1e8c4024309ce1ecccb5210035d47ac72e8a"
|
||||
),
|
||||
},
|
||||
|
||||
// RFC 6070 <http://tools.ietf.org/html/rfc6070>
|
||||
pbkdf2_sha1: {
|
||||
password: new TextEncoder("utf-8").encode("passwordPASSWORDpassword"),
|
||||
|
|
|
@ -154,7 +154,7 @@ TestArray.addTest(
|
|||
"Import / export round-trip with 'pkcs8'",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA1" };
|
||||
var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" };
|
||||
|
||||
function doExport(x) {
|
||||
if (!hasKeyFields(x)) {
|
||||
|
@ -186,7 +186,7 @@ TestArray.addTest(
|
|||
"Import failure with format 'pkcs8'",
|
||||
function() {
|
||||
var that = this;
|
||||
var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA1" };
|
||||
var alg = { name: "RSASSA-PKCS1-v1_5", hash: "SHA-1" };
|
||||
|
||||
crypto.subtle.importKey("pkcs8", tv.negative_pkcs8, alg, true, ["encrypt"])
|
||||
.then(error(that), complete(that));
|
||||
|
@ -1150,3 +1150,127 @@ TestArray.addTest(
|
|||
.then( memcmp_complete(that, tv.pbkdf2_sha256.derived), fail );
|
||||
}
|
||||
);*/
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"RSA-OAEP encrypt/decrypt round-trip",
|
||||
function () {
|
||||
var that = this;
|
||||
var privKey, pubKey;
|
||||
var alg = {name: "RSA-OAEP", hash: "SHA-1"};
|
||||
|
||||
var privKey, pubKey;
|
||||
function setPriv(x) { privKey = x; }
|
||||
function setPub(x) { pubKey = x; }
|
||||
function doEncrypt() {
|
||||
return crypto.subtle.encrypt(alg, pubKey, tv.rsaoaep.data);
|
||||
}
|
||||
function doDecrypt(x) {
|
||||
return crypto.subtle.decrypt(alg, privKey, x);
|
||||
}
|
||||
|
||||
Promise.all([
|
||||
crypto.subtle.importKey("pkcs8", tv.rsaoaep.pkcs8, alg, false, ['decrypt'])
|
||||
.then(setPriv, error(that)),
|
||||
crypto.subtle.importKey("spki", tv.rsaoaep.spki, alg, false, ['encrypt'])
|
||||
.then(setPub, error(that))
|
||||
]).then(doEncrypt, error(that))
|
||||
.then(doDecrypt, error(that))
|
||||
.then(
|
||||
memcmp_complete(that, tv.rsaoaep.data),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"RSA-OAEP key generation and encrypt/decrypt round-trip (SHA-256)",
|
||||
function () {
|
||||
var that = this;
|
||||
var alg = {
|
||||
name: "RSA-OAEP",
|
||||
hash: "SHA-256",
|
||||
modulusLength: 2048,
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01])
|
||||
};
|
||||
|
||||
var privKey, pubKey, data = crypto.getRandomValues(new Uint8Array(128));
|
||||
function setKey(x) { pubKey = x.publicKey; privKey = x.privateKey; }
|
||||
function doEncrypt() {
|
||||
return crypto.subtle.encrypt(alg, pubKey, data);
|
||||
}
|
||||
function doDecrypt(x) {
|
||||
return crypto.subtle.decrypt(alg, privKey, x);
|
||||
}
|
||||
|
||||
crypto.subtle.generateKey(alg, false, ['encrypt', 'decrypt'])
|
||||
.then(setKey, error(that))
|
||||
.then(doEncrypt, error(that))
|
||||
.then(doDecrypt, error(that))
|
||||
.then(
|
||||
memcmp_complete(that, data),
|
||||
error(that)
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"RSA-OAEP decryption known answer",
|
||||
function () {
|
||||
var that = this;
|
||||
var alg = {name: "RSA-OAEP", hash: "SHA-1"};
|
||||
|
||||
function doDecrypt(x) {
|
||||
return crypto.subtle.decrypt(alg, x, tv.rsaoaep.result);
|
||||
}
|
||||
function fail() { error(that); }
|
||||
|
||||
crypto.subtle.importKey("pkcs8", tv.rsaoaep.pkcs8, alg, false, ['decrypt'])
|
||||
.then( doDecrypt, fail )
|
||||
.then( memcmp_complete(that, tv.rsaoaep.data), fail );
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"RSA-OAEP input data length checks (2048-bit key)",
|
||||
function () {
|
||||
var that = this;
|
||||
var privKey, pubKey;
|
||||
var alg = {
|
||||
name: "RSA-OAEP",
|
||||
hash: "SHA-1",
|
||||
modulusLength: 2048,
|
||||
publicExponent: new Uint8Array([0x01, 0x00, 0x01])
|
||||
};
|
||||
|
||||
var privKey, pubKey;
|
||||
function setKey(x) { pubKey = x.publicKey; privKey = x.privateKey; }
|
||||
function doEncrypt(n) {
|
||||
return function () {
|
||||
return crypto.subtle.encrypt(alg, pubKey, new Uint8Array(n));
|
||||
}
|
||||
}
|
||||
|
||||
crypto.subtle.generateKey(alg, false, ['encrypt'])
|
||||
.then(setKey, error(that))
|
||||
.then(doEncrypt(214), error(that))
|
||||
.then(doEncrypt(215), error(that))
|
||||
.then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
TestArray.addTest(
|
||||
"RSA-OAEP key import with invalid hash",
|
||||
function () {
|
||||
var that = this;
|
||||
var alg = {name: "RSA-OAEP", hash: "SHA-123"};
|
||||
|
||||
crypto.subtle.importKey("pkcs8", tv.rsaoaep.pkcs8, alg, false, ['decrypt'])
|
||||
.then(error(that), complete(that));
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if CONFIG["MOZ_B2G"]:
|
||||
TEST_DIRS += ['tests']
|
||||
TEST_DIRS += ['tests']
|
||||
|
||||
PARALLEL_DIRS += ['src']
|
||||
|
|
|
@ -17,7 +17,7 @@ class FocusEvent : public UIEvent,
|
|||
public nsIDOMFocusEvent
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMFOCUSEVENT
|
||||
|
||||
// Forward to base class
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "nsIDOMCSSRule.idl"
|
||||
|
||||
[scriptable, uuid(19fe78cc-65ff-4b1d-a5d7-9ea89692cec6)]
|
||||
[scriptable, uuid(756c326c-eb38-4342-95e5-5eabea809174)]
|
||||
interface nsIDOMCSSCharsetRule : nsIDOMCSSRule
|
||||
{
|
||||
attribute DOMString encoding;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* Interface in the CSS OM for at-rules that conditionally apply their
|
||||
* child rules.
|
||||
*/
|
||||
[scriptable, uuid(942754f2-2c0e-461b-9c10-c0e929504fe1)]
|
||||
[scriptable, uuid(44da41b2-5660-415d-8692-eae805776103)]
|
||||
interface nsIDOMCSSConditionRule : nsIDOMCSSGroupingRule
|
||||
{
|
||||
attribute DOMString conditionText;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
#include "nsIDOMCSSRule.idl"
|
||||
|
||||
[scriptable, uuid(5f9f2068-743b-42e3-becb-10ffa994d1e3)]
|
||||
[scriptable, uuid(9b5e48ce-d84c-4e31-aff5-34e9f4141313)]
|
||||
interface nsIDOMCSSCounterStyleRule : nsIDOMCSSRule
|
||||
{
|
||||
attribute DOMString name;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "nsIDOMCSSRule.idl"
|
||||
|
||||
[scriptable, uuid(a6cf90bb-15b3-11d2-932e-00805f8add32)]
|
||||
[scriptable, uuid(db971017-fe0c-4529-972c-8217f2fee217)]
|
||||
interface nsIDOMCSSFontFaceRule : nsIDOMCSSRule
|
||||
{
|
||||
readonly attribute nsIDOMCSSStyleDeclaration style;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "nsIDOMCSSRule.idl"
|
||||
|
||||
[scriptable, uuid(f4cb1776-389d-4f52-a4d8-68bea5bd00c1)]
|
||||
[scriptable, uuid(a343d27f-1da6-4fc3-9355-d4ca434f958e)]
|
||||
interface nsIDOMCSSFontFeatureValuesRule : nsIDOMCSSRule
|
||||
{
|
||||
attribute DOMString fontFamily;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
/**
|
||||
* Interface for at-rules that have child rules in the CSS OM.
|
||||
*/
|
||||
[scriptable, uuid(ab013eed-fa21-4c6a-bba3-79e8780f583e)]
|
||||
[scriptable, uuid(a0e3324a-f911-4baf-9591-5322c76cbb0d)]
|
||||
interface nsIDOMCSSGroupingRule : nsIDOMCSSRule
|
||||
{
|
||||
readonly attribute nsIDOMCSSRuleList cssRules;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "nsIDOMCSSRule.idl"
|
||||
|
||||
[scriptable, uuid(a6cf90cf-15b3-11d2-932e-00805f8add32)]
|
||||
[scriptable, uuid(d3b2b914-01ef-4663-beda-a6475a26f491)]
|
||||
interface nsIDOMCSSImportRule : nsIDOMCSSRule
|
||||
{
|
||||
readonly attribute DOMString href;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
/**
|
||||
* Interface for @media rules in the CSS OM.
|
||||
*/
|
||||
[scriptable, uuid(1f491b05-932b-4aa1-a1f1-466505d70898)]
|
||||
[scriptable, uuid(6cf9c5b2-fa0f-43c0-aa50-ef85b4756e3a)]
|
||||
interface nsIDOMCSSMediaRule : nsIDOMCSSConditionRule
|
||||
{
|
||||
readonly attribute nsIDOMMediaList media;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
/**
|
||||
* Interface for @-moz-document rules in the CSS OM.
|
||||
*/
|
||||
[scriptable, uuid(f118a5a8-ac36-464f-b993-18cf6fe76fda)]
|
||||
[scriptable, uuid(2d0cef9d-c1b2-4c6c-9003-fa83040626d1)]
|
||||
interface nsIDOMCSSMozDocumentRule : nsIDOMCSSConditionRule
|
||||
{
|
||||
// XXX Add access to the URL list.
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "nsIDOMCSSRule.idl"
|
||||
|
||||
[scriptable, uuid(6126024d-d716-4ad8-bc53-24dd6d5846b1)]
|
||||
[scriptable, uuid(c119072b-7d2f-4aeb-a90d-e2d6b606c32a)]
|
||||
interface nsIDOMCSSPageRule : nsIDOMCSSRule
|
||||
{
|
||||
//attribute DOMString selectorText;
|
||||
|
|
|
@ -5,6 +5,16 @@
|
|||
|
||||
#include "domstubs.idl"
|
||||
|
||||
%{C++
|
||||
namespace mozilla {
|
||||
namespace css {
|
||||
class Rule;
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
||||
[ptr] native Rule(mozilla::css::Rule);
|
||||
|
||||
/**
|
||||
* The nsIDOMCSSRule interface is a datatype for a CSS style rule in
|
||||
* the Document Object Model.
|
||||
|
@ -13,7 +23,7 @@
|
|||
* http://www.w3.org/TR/DOM-Level-2-Style
|
||||
*/
|
||||
|
||||
[scriptable, uuid(2938307a-9d70-4b63-8afc-0197e82318ad)]
|
||||
[scriptable, uuid(4d6b3bad-f53c-4585-82f6-62982e27ede8)]
|
||||
interface nsIDOMCSSRule : nsISupports
|
||||
{
|
||||
// RuleType
|
||||
|
@ -41,4 +51,6 @@ interface nsIDOMCSSRule : nsISupports
|
|||
|
||||
readonly attribute nsIDOMCSSStyleSheet parentStyleSheet;
|
||||
readonly attribute nsIDOMCSSRule parentRule;
|
||||
|
||||
[noscript, nostdcall, notxpcom] Rule getCSSRule();
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "nsIDOMCSSRule.idl"
|
||||
|
||||
[scriptable, uuid(a6cf90bf-15b3-11d2-932e-00805f8add32)]
|
||||
[scriptable, uuid(b5e9af48-a7c2-4f88-aae3-58307af4b5a5)]
|
||||
interface nsIDOMCSSStyleRule : nsIDOMCSSRule
|
||||
{
|
||||
attribute DOMString selectorText;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
/**
|
||||
* Interface for @supports rules in the CSS OM.
|
||||
*/
|
||||
[scriptable, uuid(5f409a4d-92f9-4a62-8e8a-cc1c02c32918)]
|
||||
[scriptable, uuid(0b9e63a1-1bd7-4caf-850e-148b762b14d2)]
|
||||
interface nsIDOMCSSSupportsRule : nsIDOMCSSConditionRule
|
||||
{
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "nsIDOMCSSRule.idl"
|
||||
|
||||
[scriptable, uuid(a6cf90d0-15b3-11d2-932e-00805f8add32)]
|
||||
[scriptable, uuid(98f4c27b-fb35-4355-8fd9-546c4697d71a)]
|
||||
interface nsIDOMCSSUnknownRule : nsIDOMCSSRule
|
||||
{
|
||||
};
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "nsIDOMCSSRule.idl"
|
||||
|
||||
[scriptable, uuid(38a19612-dc58-414a-954c-233183808484)]
|
||||
[scriptable, uuid(a281a8b4-eaa2-49a8-8b97-acc2814a57c9)]
|
||||
interface nsIDOMMozCSSKeyframeRule : nsIDOMCSSRule
|
||||
{
|
||||
attribute DOMString keyText;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "nsIDOMCSSRule.idl"
|
||||
|
||||
[scriptable, uuid(aa4ea11f-791b-4671-b192-b931e6539669)]
|
||||
[scriptable, uuid(400f4b70-ad0a-4047-aba4-ee8019f6b907)]
|
||||
interface nsIDOMMozCSSKeyframesRule : nsIDOMCSSRule
|
||||
{
|
||||
attribute DOMString name;
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
#include "nsIMutable.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsScreenManagerProxy.h"
|
||||
#include "nsMemoryInfoDumper.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "nsStyleSheetService.h"
|
||||
|
@ -169,6 +170,7 @@ using namespace mozilla::jsipc;
|
|||
#if defined(MOZ_WIDGET_GONK)
|
||||
using namespace mozilla::system;
|
||||
#endif
|
||||
using namespace mozilla::widget;
|
||||
|
||||
#ifdef MOZ_NUWA_PROCESS
|
||||
static bool sNuwaForking = false;
|
||||
|
@ -1200,6 +1202,28 @@ ContentChild::DeallocPNeckoChild(PNeckoChild* necko)
|
|||
return true;
|
||||
}
|
||||
|
||||
PScreenManagerChild*
|
||||
ContentChild::AllocPScreenManagerChild(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess)
|
||||
{
|
||||
// The ContentParent should never attempt to allocate the
|
||||
// nsScreenManagerProxy. Instead, the nsScreenManagerProxy
|
||||
// service is requested and instantiated via XPCOM, and the
|
||||
// constructor of nsScreenManagerProxy sets up the IPC connection.
|
||||
NS_NOTREACHED("Should never get here!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::DeallocPScreenManagerChild(PScreenManagerChild* aService)
|
||||
{
|
||||
// nsScreenManagerProxy is AddRef'd in its constructor.
|
||||
nsScreenManagerProxy *child = static_cast<nsScreenManagerProxy*>(aService);
|
||||
child->Release();
|
||||
return true;
|
||||
}
|
||||
|
||||
PExternalHelperAppChild*
|
||||
ContentChild::AllocPExternalHelperAppChild(const OptionalURIParams& uri,
|
||||
const nsCString& aMimeContentType,
|
||||
|
|
|
@ -193,6 +193,12 @@ public:
|
|||
virtual PNeckoChild* AllocPNeckoChild() MOZ_OVERRIDE;
|
||||
virtual bool DeallocPNeckoChild(PNeckoChild*) MOZ_OVERRIDE;
|
||||
|
||||
virtual PScreenManagerChild*
|
||||
AllocPScreenManagerChild(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess) MOZ_OVERRIDE;
|
||||
virtual bool DeallocPScreenManagerChild(PScreenManagerChild*) MOZ_OVERRIDE;
|
||||
|
||||
virtual PExternalHelperAppChild *AllocPExternalHelperAppChild(
|
||||
const OptionalURIParams& uri,
|
||||
const nsCString& aMimeContentType,
|
||||
|
|
|
@ -113,6 +113,7 @@
|
|||
#include "PreallocatedProcessManager.h"
|
||||
#include "ProcessPriorityManager.h"
|
||||
#include "SandboxHal.h"
|
||||
#include "ScreenManagerParent.h"
|
||||
#include "StructuredCloneUtils.h"
|
||||
#include "TabParent.h"
|
||||
#include "URIUtils.h"
|
||||
|
@ -189,6 +190,7 @@ using namespace mozilla::ipc;
|
|||
using namespace mozilla::layers;
|
||||
using namespace mozilla::net;
|
||||
using namespace mozilla::jsipc;
|
||||
using namespace mozilla::widget;
|
||||
|
||||
#ifdef ENABLE_TESTS
|
||||
|
||||
|
@ -2903,6 +2905,21 @@ ContentParent::DeallocPNeckoParent(PNeckoParent* necko)
|
|||
return true;
|
||||
}
|
||||
|
||||
PScreenManagerParent*
|
||||
ContentParent::AllocPScreenManagerParent(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess)
|
||||
{
|
||||
return new ScreenManagerParent(aNumberOfScreens, aSystemDefaultScale, aSuccess);
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::DeallocPScreenManagerParent(PScreenManagerParent* aActor)
|
||||
{
|
||||
delete aActor;
|
||||
return true;
|
||||
}
|
||||
|
||||
PExternalHelperAppParent*
|
||||
ContentParent::AllocPExternalHelperAppParent(const OptionalURIParams& uri,
|
||||
const nsCString& aMimeContentType,
|
||||
|
|
|
@ -230,6 +230,12 @@ public:
|
|||
return PContentParent::RecvPNeckoConstructor(aActor);
|
||||
}
|
||||
|
||||
virtual PScreenManagerParent*
|
||||
AllocPScreenManagerParent(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess) MOZ_OVERRIDE;
|
||||
virtual bool DeallocPScreenManagerParent(PScreenManagerParent* aActor) MOZ_OVERRIDE;
|
||||
|
||||
virtual PHalParent* AllocPHalParent() MOZ_OVERRIDE;
|
||||
virtual bool RecvPHalConstructor(PHalParent* aActor) MOZ_OVERRIDE {
|
||||
return PContentParent::RecvPHalConstructor(aActor);
|
||||
|
|
|
@ -23,6 +23,7 @@ include protocol PImageBridge;
|
|||
include protocol PIndexedDB;
|
||||
include protocol PMemoryReportRequest;
|
||||
include protocol PNecko;
|
||||
include protocol PScreenManager;
|
||||
include protocol PSharedBufferManager;
|
||||
include protocol PSms;
|
||||
include protocol PSpeechSynthesis;
|
||||
|
@ -303,6 +304,7 @@ intr protocol PContent
|
|||
manages PIndexedDB;
|
||||
manages PMemoryReportRequest;
|
||||
manages PNecko;
|
||||
manages PScreenManager;
|
||||
manages PSms;
|
||||
manages PSpeechSynthesis;
|
||||
manages PStorage;
|
||||
|
@ -479,6 +481,11 @@ parent:
|
|||
|
||||
PNecko();
|
||||
|
||||
sync PScreenManager()
|
||||
returns (uint32_t numberOfScreens,
|
||||
float systemDefaultScale,
|
||||
bool success);
|
||||
|
||||
PSms();
|
||||
|
||||
PSpeechSynthesis();
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 8 -*- */
|
||||
/* 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/. */
|
||||
|
||||
include protocol PBrowser;
|
||||
include protocol PContent;
|
||||
|
||||
using struct nsIntRect from "nsRect.h";
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
struct ScreenDetails {
|
||||
uint32_t id;
|
||||
nsIntRect rect;
|
||||
nsIntRect availRect;
|
||||
int32_t pixelDepth;
|
||||
int32_t colorDepth;
|
||||
double contentsScaleFactor;
|
||||
};
|
||||
|
||||
sync protocol PScreenManager
|
||||
{
|
||||
manager PContent;
|
||||
|
||||
parent:
|
||||
sync Refresh()
|
||||
returns (uint32_t numberOfScreens,
|
||||
float systemDefaultScale,
|
||||
bool success);
|
||||
|
||||
sync ScreenRefresh(uint32_t aId)
|
||||
returns (ScreenDetails screen,
|
||||
bool success);
|
||||
|
||||
sync GetPrimaryScreen()
|
||||
returns (ScreenDetails screen,
|
||||
bool success);
|
||||
|
||||
sync ScreenForRect(int32_t aLeft,
|
||||
int32_t aTop,
|
||||
int32_t aWidth,
|
||||
int32_t aHeight)
|
||||
returns (ScreenDetails screen,
|
||||
bool success);
|
||||
|
||||
sync ScreenForBrowser(PBrowser aBrowser)
|
||||
returns (ScreenDetails screen,
|
||||
bool success);
|
||||
|
||||
child:
|
||||
__delete__();
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -0,0 +1,195 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
||||
/* 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/. */
|
||||
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "nsIWidget.h"
|
||||
#include "nsServiceManagerUtils.h"
|
||||
#include "ScreenManagerParent.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
static const char *sScreenManagerContractID = "@mozilla.org/gfx/screenmanager;1";
|
||||
|
||||
ScreenManagerParent::ScreenManagerParent(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess)
|
||||
{
|
||||
mScreenMgr = do_GetService(sScreenManagerContractID);
|
||||
if (!mScreenMgr) {
|
||||
MOZ_CRASH("Couldn't get nsIScreenManager from ScreenManagerParent.");
|
||||
}
|
||||
|
||||
unused << RecvRefresh(aNumberOfScreens, aSystemDefaultScale, aSuccess);
|
||||
}
|
||||
|
||||
bool
|
||||
ScreenManagerParent::RecvRefresh(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
|
||||
nsresult rv = mScreenMgr->GetNumberOfScreens(aNumberOfScreens);
|
||||
if (NS_FAILED(rv)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
rv = mScreenMgr->GetSystemDefaultScale(aSystemDefaultScale);
|
||||
if (NS_FAILED(rv)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*aSuccess = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ScreenManagerParent::RecvScreenRefresh(const uint32_t& aId,
|
||||
ScreenDetails* aRetVal,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
nsresult rv = mScreenMgr->ScreenForId(aId, getter_AddRefs(screen));
|
||||
if (NS_FAILED(rv)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ScreenDetails details;
|
||||
unused << ExtractScreenDetails(screen, details);
|
||||
|
||||
*aRetVal = details;
|
||||
*aSuccess = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ScreenManagerParent::RecvGetPrimaryScreen(ScreenDetails* aRetVal,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
nsresult rv = mScreenMgr->GetPrimaryScreen(getter_AddRefs(screen));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
ScreenDetails details;
|
||||
if (!ExtractScreenDetails(screen, details)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*aRetVal = details;
|
||||
*aSuccess = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ScreenManagerParent::RecvScreenForRect(const int32_t& aLeft,
|
||||
const int32_t& aTop,
|
||||
const int32_t& aWidth,
|
||||
const int32_t& aHeight,
|
||||
ScreenDetails* aRetVal,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
nsresult rv = mScreenMgr->ScreenForRect(aLeft, aTop, aWidth, aHeight, getter_AddRefs(screen));
|
||||
|
||||
NS_ENSURE_SUCCESS(rv, true);
|
||||
|
||||
ScreenDetails details;
|
||||
if (!ExtractScreenDetails(screen, details)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*aRetVal = details;
|
||||
*aSuccess = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ScreenManagerParent::RecvScreenForBrowser(PBrowserParent* aBrowser,
|
||||
ScreenDetails* aRetVal,
|
||||
bool* aSuccess)
|
||||
{
|
||||
*aSuccess = false;
|
||||
|
||||
// Find the mWidget associated with the tabparent, and then return
|
||||
// the nsIScreen it's on.
|
||||
TabParent* tabParent = static_cast<TabParent*>(aBrowser);
|
||||
nsCOMPtr<nsIWidget> widget = tabParent->GetWidget();
|
||||
if (!widget) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIScreen> screen;
|
||||
if (widget->GetNativeData(NS_NATIVE_WINDOW)) {
|
||||
mScreenMgr->ScreenForNativeWidget(widget->GetNativeData(NS_NATIVE_WINDOW),
|
||||
getter_AddRefs(screen));
|
||||
}
|
||||
|
||||
NS_ENSURE_TRUE(screen, true);
|
||||
|
||||
ScreenDetails details;
|
||||
if (!ExtractScreenDetails(screen, details)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
*aRetVal = details;
|
||||
*aSuccess = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ScreenManagerParent::ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails)
|
||||
{
|
||||
uint32_t id;
|
||||
nsresult rv = aScreen->GetId(&id);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.id() = id;
|
||||
|
||||
nsIntRect rect;
|
||||
rv = aScreen->GetRect(&rect.x, &rect.y, &rect.width, &rect.height);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.rect() = rect;
|
||||
|
||||
nsIntRect availRect;
|
||||
rv = aScreen->GetAvailRect(&availRect.x, &availRect.y, &availRect.width,
|
||||
&availRect.height);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.availRect() = availRect;
|
||||
|
||||
int32_t pixelDepth = 0;
|
||||
rv = aScreen->GetPixelDepth(&pixelDepth);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.pixelDepth() = pixelDepth;
|
||||
|
||||
int32_t colorDepth = 0;
|
||||
rv = aScreen->GetColorDepth(&colorDepth);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.colorDepth() = colorDepth;
|
||||
|
||||
double contentsScaleFactor = 1.0;
|
||||
rv = aScreen->GetContentsScaleFactor(&contentsScaleFactor);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
aDetails.contentsScaleFactor() = contentsScaleFactor;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
ScreenManagerParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
|
@ -0,0 +1,56 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* vim: set sw=4 ts=8 et tw=80 : */
|
||||
/* 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/. */
|
||||
|
||||
#ifndef mozilla_dom_ScreenManagerParent_h
|
||||
#define mozilla_dom_ScreenManagerParent_h
|
||||
|
||||
#include "mozilla/dom/PScreenManagerParent.h"
|
||||
#include "nsIScreenManager.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class ScreenManagerParent : public PScreenManagerParent
|
||||
{
|
||||
public:
|
||||
ScreenManagerParent(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess);
|
||||
~ScreenManagerParent() {};
|
||||
|
||||
virtual bool RecvRefresh(uint32_t* aNumberOfScreens,
|
||||
float* aSystemDefaultScale,
|
||||
bool* aSuccess) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvScreenRefresh(const uint32_t& aId,
|
||||
ScreenDetails* aRetVal,
|
||||
bool* aSuccess) MOZ_OVERRIDE;
|
||||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvGetPrimaryScreen(ScreenDetails* aRetVal,
|
||||
bool* aSuccess) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvScreenForRect(const int32_t& aLeft,
|
||||
const int32_t& aTop,
|
||||
const int32_t& aWidth,
|
||||
const int32_t& aHeight,
|
||||
ScreenDetails* aRetVal,
|
||||
bool* aSuccess) MOZ_OVERRIDE;
|
||||
|
||||
virtual bool RecvScreenForBrowser(PBrowserParent* aBrowser,
|
||||
ScreenDetails* aRetVal,
|
||||
bool* aSuccess);
|
||||
|
||||
private:
|
||||
bool ExtractScreenDetails(nsIScreen* aScreen, ScreenDetails &aDetails);
|
||||
nsCOMPtr<nsIScreenManager> mScreenMgr;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // mozilla_dom_ScreenManagerParent_h
|
|
@ -309,6 +309,8 @@ public:
|
|||
*/
|
||||
bool IsDestroyed() const { return mIsDestroyed; }
|
||||
|
||||
already_AddRefed<nsIWidget> GetWidget() const;
|
||||
|
||||
protected:
|
||||
bool ReceiveMessage(const nsString& aMessage,
|
||||
bool aSync,
|
||||
|
@ -380,7 +382,6 @@ protected:
|
|||
|
||||
private:
|
||||
already_AddRefed<nsFrameLoader> GetFrameLoader() const;
|
||||
already_AddRefed<nsIWidget> GetWidget() const;
|
||||
layout::RenderFrameParent* GetRenderFrame();
|
||||
nsRefPtr<nsIContentParent> mManager;
|
||||
void TryCacheDPIAndScale();
|
||||
|
|
|
@ -59,6 +59,7 @@ UNIFIED_SOURCES += [
|
|||
'PermissionMessageUtils.cpp',
|
||||
'PreallocatedProcessManager.cpp',
|
||||
'ProcessPriorityManager.cpp',
|
||||
'ScreenManagerParent.cpp',
|
||||
'StructuredCloneUtils.cpp',
|
||||
'TabChild.cpp',
|
||||
'TabContext.cpp',
|
||||
|
@ -92,6 +93,7 @@ IPDL_SOURCES += [
|
|||
'PFileDescriptorSet.ipdl',
|
||||
'PFilePicker.ipdl',
|
||||
'PMemoryReportRequest.ipdl',
|
||||
'PScreenManager.ipdl',
|
||||
'PTabContext.ipdlh',
|
||||
]
|
||||
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if CONFIG ['MOZ_WEBRTC']:
|
||||
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
||||
WEBRTC_SIGNALLING_TEST_MANIFESTS += ['steeplechase.ini']
|
||||
MOCHITEST_MANIFESTS += ['mochitest.ini']
|
||||
WEBRTC_SIGNALLING_TEST_MANIFESTS += ['steeplechase.ini']
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ class DesktopNotificationRequest : public nsIContentPermissionRequest,
|
|||
}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSICONTENTPERMISSIONREQUEST
|
||||
|
||||
DesktopNotificationRequest(DesktopNotification* notification)
|
||||
|
@ -309,9 +309,8 @@ DesktopNotificationCenter::WrapObject(JSContext* aCx)
|
|||
/* DesktopNotificationRequest */
|
||||
/* ------------------------------------------------------------------------ */
|
||||
|
||||
NS_IMPL_ISUPPORTS(DesktopNotificationRequest,
|
||||
nsIContentPermissionRequest,
|
||||
nsIRunnable)
|
||||
NS_IMPL_ISUPPORTS_INHERITED(DesktopNotificationRequest, nsRunnable,
|
||||
nsIContentPermissionRequest)
|
||||
|
||||
NS_IMETHODIMP
|
||||
DesktopNotificationRequest::GetPrincipal(nsIPrincipal * *aRequestingPrincipal)
|
||||
|
|
|
@ -26,8 +26,8 @@ dictionary NetworkStatsAlarmOptions
|
|||
|
||||
[JSImplementation="@mozilla.org/networkstats;1",
|
||||
ChromeOnly,
|
||||
Pref="dom.mozNetworkStats.enabled",
|
||||
Func="Navigator::HasNetworkStatsSupport"]
|
||||
CheckPermissions="networkstats-manage",
|
||||
Pref="dom.mozNetworkStats.enabled"]
|
||||
interface MozNetworkStats {
|
||||
/**
|
||||
* App manifest URL of an application for specifying the per-app stats of the
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
[JSImplementation="@mozilla.org/networkstatsalarm;1",
|
||||
ChromeOnly,
|
||||
Pref="dom.mozNetworkStats.enabled",
|
||||
Func="Navigator::HasNetworkStatsSupport"]
|
||||
CheckPermissions="networkstats-manage",
|
||||
Pref="dom.mozNetworkStats.enabled"]
|
||||
interface MozNetworkStatsAlarm {
|
||||
readonly attribute unsigned long alarmId;
|
||||
readonly attribute MozNetworkStatsInterface network;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
|
||||
[JSImplementation="@mozilla.org/networkStatsdata;1",
|
||||
ChromeOnly,
|
||||
Pref="dom.mozNetworkStats.enabled",
|
||||
Func="Navigator::HasNetworkStatsSupport"]
|
||||
CheckPermissions="networkstats-manage",
|
||||
Pref="dom.mozNetworkStats.enabled"]
|
||||
interface MozNetworkStatsData {
|
||||
readonly attribute unsigned long rxBytes; // Received bytes.
|
||||
readonly attribute unsigned long txBytes; // Sent bytes.
|
||||
|
|
|
@ -12,8 +12,8 @@ dictionary NetworkInterface {
|
|||
*/
|
||||
[Constructor(optional NetworkInterface networkinterface),
|
||||
JSImplementation="@mozilla.org/networkstatsinterface;1",
|
||||
Pref="dom.mozNetworkStats.enabled",
|
||||
Func="Navigator::HasNetworkStatsSupport"]
|
||||
CheckPermissions="networkstats-manage",
|
||||
Pref="dom.mozNetworkStats.enabled"]
|
||||
interface MozNetworkStatsInterface {
|
||||
readonly attribute long type;
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ interface NavigatorStorageUtils {
|
|||
|
||||
[NoInterfaceObject]
|
||||
interface NavigatorFeatures {
|
||||
[Func="Navigator::HasFeatureDetectionSupport"]
|
||||
[CheckPermissions="feature-detection"]
|
||||
Promise getFeature(DOMString name);
|
||||
};
|
||||
|
||||
|
@ -252,10 +252,12 @@ partial interface Navigator {
|
|||
boolean mozIsLocallyAvailable(DOMString uri, boolean whenOffline);
|
||||
};
|
||||
|
||||
#ifdef MOZ_WEBSMS_BACKEND
|
||||
partial interface Navigator {
|
||||
[Func="Navigator::HasMobileMessageSupport"]
|
||||
[CheckPermissions="sms", Pref="dom.sms.enabled"]
|
||||
readonly attribute MozMobileMessageManager? mozMobileMessage;
|
||||
};
|
||||
#endif
|
||||
|
||||
// NetworkInformation
|
||||
partial interface Navigator {
|
||||
|
@ -331,7 +333,7 @@ partial interface Navigator {
|
|||
#ifdef MOZ_TIME_MANAGER
|
||||
// nsIDOMMozNavigatorTime
|
||||
partial interface Navigator {
|
||||
[Throws, Func="Navigator::HasTimeSupport"]
|
||||
[Throws, CheckPermissions="time"]
|
||||
readonly attribute MozTimeManager mozTime;
|
||||
};
|
||||
#endif // MOZ_TIME_MANAGER
|
||||
|
|
|
@ -95,6 +95,10 @@ dictionary RsaHashedKeyGenParams : RsaKeyGenParams {
|
|||
AlgorithmIdentifier hash;
|
||||
};
|
||||
|
||||
dictionary RsaOaepParams : Algorithm {
|
||||
CryptoOperationData? label;
|
||||
};
|
||||
|
||||
dictionary DhKeyGenParams : Algorithm {
|
||||
BigInteger prime;
|
||||
BigInteger generator;
|
||||
|
|
|
@ -204,7 +204,7 @@ struct TextureFactoryIdentifier
|
|||
|
||||
TextureFactoryIdentifier(LayersBackend aLayersBackend = LayersBackend::LAYERS_NONE,
|
||||
GeckoProcessType aParentProcessId = GeckoProcessType_Default,
|
||||
int32_t aMaxTextureSize = 0,
|
||||
int32_t aMaxTextureSize = 4096,
|
||||
bool aSupportsTextureBlitting = false,
|
||||
bool aSupportsPartialUploads = false)
|
||||
: mParentBackend(aLayersBackend)
|
||||
|
|
|
@ -1410,6 +1410,8 @@ public:
|
|||
mManager->Mutated(this);
|
||||
}
|
||||
|
||||
virtual int32_t GetMaxLayerSize() { return Manager()->GetMaxTextureSize(); }
|
||||
|
||||
protected:
|
||||
Layer(LayerManager* aManager, void* aImplData);
|
||||
|
||||
|
|
|
@ -412,34 +412,13 @@ GetFrameTime() {
|
|||
return sFrameTime;
|
||||
}
|
||||
|
||||
// This is a base class for animations that can deal with
|
||||
// overscroll states. In particular, it ensures that overscroll
|
||||
// states are cleared when the animation is cancelled.
|
||||
class OverscrollableAnimation: public AsyncPanZoomAnimation {
|
||||
public:
|
||||
OverscrollableAnimation(AsyncPanZoomController& aApzc,
|
||||
const TimeDuration& aRepaintInterval = TimeDuration::Forever())
|
||||
: AsyncPanZoomAnimation(aRepaintInterval)
|
||||
, mApzc(aApzc)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void Cancel() MOZ_OVERRIDE
|
||||
{
|
||||
mApzc.mX.ClearOverscroll();
|
||||
mApzc.mY.ClearOverscroll();
|
||||
}
|
||||
|
||||
protected:
|
||||
AsyncPanZoomController& mApzc;
|
||||
};
|
||||
|
||||
class FlingAnimation: public OverscrollableAnimation {
|
||||
class FlingAnimation: public AsyncPanZoomAnimation {
|
||||
public:
|
||||
FlingAnimation(AsyncPanZoomController& aApzc,
|
||||
bool aApplyAcceleration,
|
||||
bool aAllowOverscroll)
|
||||
: OverscrollableAnimation(aApzc, TimeDuration::FromMilliseconds(gfxPrefs::APZFlingRepaintInterval()))
|
||||
: AsyncPanZoomAnimation(TimeDuration::FromMilliseconds(gfxPrefs::APZFlingRepaintInterval()))
|
||||
, mApzc(aApzc)
|
||||
, mAllowOverscroll(aAllowOverscroll)
|
||||
{
|
||||
TimeStamp now = GetFrameTime();
|
||||
|
@ -594,6 +573,7 @@ private:
|
|||
+ (aSupplemental * gfxPrefs::APZFlingAccelSupplementalMultiplier());
|
||||
}
|
||||
|
||||
AsyncPanZoomController& mApzc;
|
||||
bool mAllowOverscroll;
|
||||
};
|
||||
|
||||
|
@ -656,10 +636,10 @@ private:
|
|||
CSSToScreenScale mEndZoom;
|
||||
};
|
||||
|
||||
class OverscrollSnapBackAnimation: public OverscrollableAnimation {
|
||||
class OverscrollSnapBackAnimation: public AsyncPanZoomAnimation {
|
||||
public:
|
||||
OverscrollSnapBackAnimation(AsyncPanZoomController& aApzc)
|
||||
: OverscrollableAnimation(aApzc)
|
||||
: mApzc(aApzc)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -671,6 +651,8 @@ public:
|
|||
bool continueY = mApzc.mY.SampleSnapBack(aDelta);
|
||||
return continueX || continueY;
|
||||
}
|
||||
private:
|
||||
AsyncPanZoomController& mApzc;
|
||||
};
|
||||
|
||||
void
|
||||
|
@ -1771,10 +1753,13 @@ void AsyncPanZoomController::CancelAnimation() {
|
|||
ReentrantMonitorAutoEnter lock(mMonitor);
|
||||
APZC_LOG("%p running CancelAnimation in state %d\n", this, mState);
|
||||
SetState(NOTHING);
|
||||
if (mAnimation) {
|
||||
mAnimation->Cancel();
|
||||
mAnimation = nullptr;
|
||||
// mAnimation->Cancel() may have done something that requires a repaint.
|
||||
mAnimation = nullptr;
|
||||
// Setting the state to nothing and cancelling the animation can
|
||||
// preempt normal mechanisms for relieving overscroll, so we need to clear
|
||||
// overscroll here.
|
||||
if (mX.IsOverscrolled() || mY.IsOverscrolled()) {
|
||||
mX.ClearOverscroll();
|
||||
mY.ClearOverscroll();
|
||||
RequestContentRepaint();
|
||||
ScheduleComposite();
|
||||
UpdateSharedCompositorFrameMetrics();
|
||||
|
|
|
@ -800,7 +800,6 @@ public:
|
|||
bool TakeOverFling(ScreenPoint aVelocity);
|
||||
|
||||
private:
|
||||
friend class OverscrollableAnimation;
|
||||
friend class FlingAnimation;
|
||||
friend class OverscrollSnapBackAnimation;
|
||||
// The initial velocity of the most recent fling.
|
||||
|
@ -1039,9 +1038,6 @@ public:
|
|||
virtual bool Sample(FrameMetrics& aFrameMetrics,
|
||||
const TimeDuration& aDelta) = 0;
|
||||
|
||||
// Called if the animation is cancelled before it ends.
|
||||
virtual void Cancel() {}
|
||||
|
||||
/**
|
||||
* Get the deferred tasks in |mDeferredTasks|. See |mDeferredTasks|
|
||||
* for more information.
|
||||
|
|
|
@ -86,6 +86,12 @@ public:
|
|||
void* aCallbackData,
|
||||
ReadbackProcessor* aReadback) MOZ_OVERRIDE;
|
||||
|
||||
/**
|
||||
* We don't really have a hard restriction for max layer size, but we pick
|
||||
* 4096 to avoid excessive memory usage.
|
||||
*/
|
||||
virtual int32_t GetMaxLayerSize() MOZ_OVERRIDE { return 4096; }
|
||||
|
||||
protected:
|
||||
BasicLayerManager* BasicManager()
|
||||
{
|
||||
|
|
|
@ -631,11 +631,17 @@ nsDeviceContext::ComputeFullAreaUsingScreen(nsRect* outRect)
|
|||
void
|
||||
nsDeviceContext::FindScreen(nsIScreen** outScreen)
|
||||
{
|
||||
if (mWidget && mWidget->GetNativeData(NS_NATIVE_WINDOW))
|
||||
if (mWidget && mWidget->GetOwningTabChild()) {
|
||||
mScreenManager->ScreenForNativeWidget((void *)mWidget->GetOwningTabChild(),
|
||||
outScreen);
|
||||
}
|
||||
else if (mWidget && mWidget->GetNativeData(NS_NATIVE_WINDOW)) {
|
||||
mScreenManager->ScreenForNativeWidget(mWidget->GetNativeData(NS_NATIVE_WINDOW),
|
||||
outScreen);
|
||||
else
|
||||
}
|
||||
else {
|
||||
mScreenManager->GetPrimaryScreen(outScreen);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -29,7 +29,7 @@ FontInfoData::Load()
|
|||
class FontInfoLoadCompleteEvent : public nsRunnable {
|
||||
virtual ~FontInfoLoadCompleteEvent() {}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
FontInfoLoadCompleteEvent(FontInfoData *aFontInfo) :
|
||||
mFontInfo(aFontInfo)
|
||||
|
@ -43,7 +43,7 @@ class FontInfoLoadCompleteEvent : public nsRunnable {
|
|||
class AsyncFontInfoLoader : public nsRunnable {
|
||||
virtual ~AsyncFontInfoLoader() {}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
AsyncFontInfoLoader(FontInfoData *aFontInfo) :
|
||||
mFontInfo(aFontInfo)
|
||||
|
@ -70,7 +70,7 @@ FontInfoLoadCompleteEvent::Run()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(FontInfoLoadCompleteEvent, nsIRunnable);
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(FontInfoLoadCompleteEvent, nsRunnable);
|
||||
|
||||
// runs on separate thread
|
||||
nsresult
|
||||
|
@ -86,7 +86,7 @@ AsyncFontInfoLoader::Run()
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(AsyncFontInfoLoader, nsIRunnable);
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(AsyncFontInfoLoader, nsRunnable);
|
||||
|
||||
NS_IMPL_ISUPPORTS(gfxFontInfoLoader::ShutdownObserver, nsIObserver)
|
||||
|
||||
|
|
|
@ -115,6 +115,8 @@ NS_IMPL_ISUPPORTS(GfxD2DSurfaceReporter, nsIMemoryReporter)
|
|||
|
||||
class GfxD2DVramReporter MOZ_FINAL : public nsIMemoryReporter
|
||||
{
|
||||
~GfxD2DVramReporter() {}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
|
|
|
@ -281,11 +281,6 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
virtual ~Observer()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
void SetDeviceChangeTimer()
|
||||
{
|
||||
// Set stable timer, since we will get multiple devices-changed
|
||||
|
@ -297,6 +292,11 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
virtual ~Observer()
|
||||
{
|
||||
Stop();
|
||||
}
|
||||
|
||||
// Gamepad service owns us, we just hold a reference back to it.
|
||||
WindowsGamepadService& mSvc;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
|
|
|
@ -156,7 +156,7 @@ ClippedImage::ShouldClip()
|
|||
return mShouldClip.ref();
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(ClippedImage, imgIContainer)
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(ClippedImage, ImageWrapper)
|
||||
|
||||
nsIntRect
|
||||
ClippedImage::FrameRect(uint32_t aWhichFrame)
|
||||
|
|
|
@ -29,7 +29,7 @@ class ClippedImage : public ImageWrapper
|
|||
typedef mozilla::gfx::SourceSurface SourceSurface;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ using namespace mozilla::gfx;
|
|||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
NS_IMPL_ISUPPORTS(FrozenImage, imgIContainer)
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(FrozenImage, ImageWrapper)
|
||||
|
||||
nsIntRect
|
||||
FrozenImage::FrameRect(uint32_t /* aWhichFrame - ignored */)
|
||||
|
|
|
@ -29,7 +29,7 @@ class FrozenImage : public ImageWrapper
|
|||
typedef mozilla::gfx::SourceSurface SourceSurface;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
|
||||
virtual void IncrementAnimationConsumers() MOZ_OVERRIDE;
|
||||
|
|
|
@ -20,7 +20,7 @@ using mozilla::layers::ImageContainer;
|
|||
namespace mozilla {
|
||||
namespace image {
|
||||
|
||||
NS_IMPL_ISUPPORTS(OrientedImage, imgIContainer)
|
||||
NS_IMPL_ISUPPORTS_INHERITED0(OrientedImage, ImageWrapper)
|
||||
|
||||
nsIntRect
|
||||
OrientedImage::FrameRect(uint32_t aWhichFrame)
|
||||
|
|
|
@ -26,7 +26,7 @@ class OrientedImage : public ImageWrapper
|
|||
typedef mozilla::gfx::SourceSurface SourceSurface;
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
||||
virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE;
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
#include "nsSemanticUnitScanner.h"
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSemanticUnitScanner, nsISemanticUnitScanner)
|
||||
NS_IMPL_ISUPPORTS_INHERITED(nsSemanticUnitScanner, nsSampleWordBreaker, nsISemanticUnitScanner)
|
||||
|
||||
nsSemanticUnitScanner::nsSemanticUnitScanner() : nsSampleWordBreaker()
|
||||
{
|
||||
|
|
|
@ -14,7 +14,7 @@ class nsSemanticUnitScanner : public nsISemanticUnitScanner
|
|||
, public nsSampleWordBreaker
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSISEMANTICUNITSCANNER
|
||||
|
||||
nsSemanticUnitScanner();
|
||||
|
|
|
@ -1018,12 +1018,12 @@ template <typename T> class MaybeRooted<T, NoGC>
|
|||
typedef FakeRooted<T> RootType;
|
||||
typedef FakeMutableHandle<T> MutableHandleType;
|
||||
|
||||
static inline JS::Handle<T> toHandle(HandleType v) {
|
||||
MOZ_ASSUME_UNREACHABLE("Bad conversion");
|
||||
static JS::Handle<T> toHandle(HandleType v) {
|
||||
MOZ_CRASH("Bad conversion");
|
||||
}
|
||||
|
||||
static inline JS::MutableHandle<T> toMutableHandle(MutableHandleType v) {
|
||||
MOZ_ASSUME_UNREACHABLE("Bad conversion");
|
||||
static JS::MutableHandle<T> toMutableHandle(MutableHandleType v) {
|
||||
MOZ_CRASH("Bad conversion");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче