This commit is contained in:
Wes Kocher 2014-07-29 17:19:35 -07:00
Родитель 2e4394c36c 10853dd305
Коммит 9566b1145f
313 изменённых файлов: 6060 добавлений и 2412 удалений

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

@ -10,7 +10,8 @@
#include "HyperTextAccessible.h"
#include "nsAccUtils.h"
using namespace mozilla::a11y;
namespace mozilla {
namespace a11y {
////////////////////////////////////////////////////////////////////////////////
// TextPoint
@ -294,3 +295,6 @@ TextRange::MoveInternal(ETextUnit aUnit, int32_t aCount,
{
}
} // namespace a11y
} // namespace mozilla

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

@ -20,4 +20,4 @@ DIRS += ['base', 'generic', 'html', 'interfaces', 'jsat', 'xpcom']
if CONFIG['MOZ_XUL']:
DIRS += ['xul']
TEST_DIRS += ['tests']
TEST_DIRS += ['tests/mochitest']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,7 +0,0 @@
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -4,36 +4,33 @@
# 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/.
DIRS += [
'actions',
'attributes',
'bounds',
'editabletext',
'elm',
'focus',
'hittest',
'hyperlink',
'hypertext',
'jsat',
'name',
'pivot',
'relations',
'role',
'scroll',
'selectable',
'states',
'table',
'text',
'textattrs',
'textcaret',
'textselection',
'treeupdate',
'value',
]
A11Y_MANIFESTS += [
'a11y.ini',
'actions/a11y.ini',
'attributes/a11y.ini',
'bounds/a11y.ini',
'editabletext/a11y.ini',
'elm/a11y.ini',
'events/a11y.ini',
'focus/a11y.ini',
'hittest/a11y.ini',
'hyperlink/a11y.ini',
'hypertext/a11y.ini',
'jsat/a11y.ini',
'name/a11y.ini',
'pivot/a11y.ini',
'relations/a11y.ini',
'role/a11y.ini',
'scroll/a11y.ini',
'selectable/a11y.ini',
'states/a11y.ini',
'table/a11y.ini',
'text/a11y.ini',
'textattrs/a11y.ini',
'textcaret/a11y.ini',
'textrange/a11y.ini',
'textselection/a11y.ini',
'tree/a11y.ini',
'treeupdate/a11y.ini',
'value/a11y.ini',
]

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
A11Y_MANIFESTS += ['a11y.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DIRS += ['mochitest']

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

@ -346,6 +346,7 @@ var shell = {
window.addEventListener('sizemodechange', this);
window.addEventListener('unload', this);
this.contentBrowser.addEventListener('mozbrowserloadstart', this, true);
this.contentBrowser.addEventListener('mozbrowserselectionchange', this, true);
CustomEventManager.init();
WebappsHelper.init();
@ -372,6 +373,7 @@ var shell = {
window.removeEventListener('mozfullscreenchange', this);
window.removeEventListener('sizemodechange', this);
this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true);
this.contentBrowser.removeEventListener('mozbrowserselectionchange', this, true);
ppmm.removeMessageListener("content-handler", this);
UserAgentOverrides.uninit();
@ -514,6 +516,30 @@ var shell = {
this.notifyContentStart();
break;
case 'mozbrowserselectionchange':
// The mozbrowserselectionchange event, may have crossed the chrome-content boundary.
// This event always dispatch to shell.js. But the offset we got from this event is
// based on tab's coordinate. So get the actual offsets between shell and evt.target.
let elt = evt.target;
let win = elt.ownerDocument.defaultView;
let offsetX = win.mozInnerScreenX;
let offsetY = win.mozInnerScreenY;
let rect = elt.getBoundingClientRect();
offsetX += rect.left;
offsetY += rect.top;
let data = evt.detail;
data.offsetX = offsetX;
data.offsetY = offsetY;
DoCommandHelper.setEvent(evt);
shell.sendChromeEvent({
type: 'selectionchange',
detail: data,
});
break;
case 'MozApplicationManifest':
try {
if (!Services.prefs.getBoolPref('browser.cache.offline.enable'))
@ -713,6 +739,23 @@ var CustomEventManager = {
case 'inputmethod-update-layouts':
KeyboardHelper.handleEvent(detail);
break;
case 'do-command':
DoCommandHelper.handleEvent(detail.cmd);
break;
}
}
}
let DoCommandHelper = {
_event: null,
setEvent: function docommand_setEvent(evt) {
this._event = evt;
},
handleEvent: function docommand_handleEvent(cmd) {
if (this._event) {
shell.sendEvent(this._event.target, 'mozdocommand', { cmd: cmd });
this._event = null;
}
}
}

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

@ -256,6 +256,7 @@ pref("browser.uitour.themeOrigin", "https://addons.mozilla.org/%LOCALE%/firefox/
pref("browser.uitour.pinnedTabUrl", "https://support.mozilla.org/%LOCALE%/kb/pinned-tabs-keep-favorite-websites-open");
pref("browser.uitour.url", "https://www.mozilla.org/%LOCALE%/firefox/%VERSION%/tour/");
pref("browser.uitour.whitelist.add.260", "www.mozilla.org,support.mozilla.org");
pref("browser.uitour.whitelist.add.340", "about:home");
pref("browser.customizemode.tip0.shown", false);
pref("browser.customizemode.tip0.learnMoreUrl", "https://support.mozilla.org/1/firefox/%VERSION%/%OS%/%LOCALE%/customize");

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

@ -1162,10 +1162,25 @@ var gPluginHandler = {
let submitReports = true; // XXX followup for .getPropertyAsBool("submitReports");
let pluginName = propBag.getPropertyAsAString("pluginName");
let pluginDumpID = propBag.getPropertyAsAString("pluginDumpID");
let browserDumpID = propBag.getPropertyAsAString("browserDumpID");
let browserDumpID = null;
let gmpPlugin = false;
// Remap the plugin name to a more user-presentable form.
pluginName = this.makeNicePluginName(pluginName);
try {
browserDumpID = propBag.getPropertyAsAString("browserDumpID");
} catch (e) {
// For GMP crashes we don't get a browser dump.
}
try {
gmpPlugin = propBag.getPropertyAsBool("gmpPlugin");
} catch (e) {
// This property is only set for GMP plugins.
}
// For non-GMP plugins, remap the plugin name to a more user-presentable form.
if (!gmpPlugin) {
pluginName = this.makeNicePluginName(pluginName);
}
let messageString = gNavigatorBundle.getFormattedString("crashedpluginsMessage.title", [pluginName]);

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

@ -241,7 +241,7 @@ let MozLoopServiceInternal = {
* @param {Boolean} noRetry Optional, don't retry if authentication fails.
*/
registerWithLoopServer: function(pushUrl, noRetry) {
this.hawkRequest("/registration", "POST", { simple_push_url: pushUrl})
this.hawkRequest("/registration", "POST", { simplePushURL: pushUrl})
.then((response) => {
// If this failed we got an invalid token. storeSessionToken rejects
// the gRegisteredDeferred promise for us, so here we just need to

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

@ -117,12 +117,6 @@ loop.Client = (function($) {
try {
var urlData = JSON.parse(responseText);
// XXX Support an alternate call_url property for
// backwards compatibility whilst we switch over servers.
// Bug 1033988 will want to remove these two lines.
if (urlData.call_url)
urlData.callUrl = urlData.call_url;
cb(null, this._validate(urlData, expectedCallUrlProperties));
this.mozLoop.noteCallUrlExpiry(urlData.expiresAt);

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

@ -24,7 +24,7 @@ loop.conversation = (function(OT, mozL10n) {
var IncomingCallView = React.createClass({displayName: 'IncomingCallView',
propTypes: {
model: React.PropTypes.func.isRequired
model: React.PropTypes.object.isRequired
},
getInitialState: function() {

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

@ -24,7 +24,7 @@ loop.conversation = (function(OT, mozL10n) {
var IncomingCallView = React.createClass({
propTypes: {
model: React.PropTypes.func.isRequired
model: React.PropTypes.object.isRequired
},
getInitialState: function() {

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

@ -77,22 +77,22 @@ loop.panel = (function(_, mozL10n) {
__("display_name_available_status");
return (
React.DOM.div({className: "footer component-spacer"},
React.DOM.div({className: "do-not-disturb"},
React.DOM.p({className: "dnd-status", onClick: this.showDropdownMenu},
React.DOM.span(null, availabilityText),
React.DOM.i({className: availabilityStatus})
),
React.DOM.ul({className: availabilityDropdown,
onMouseLeave: this.hideDropdownMenu},
React.DOM.li({onClick: this.changeAvailability("available"),
className: "dnd-menu-item dnd-make-available"},
React.DOM.i({className: "status status-available"}),
React.DOM.div( {className:"footer component-spacer"},
React.DOM.div( {className:"do-not-disturb"},
React.DOM.p( {className:"dnd-status", onClick:this.showDropdownMenu},
React.DOM.span(null, availabilityText),
React.DOM.i( {className:availabilityStatus})
),
React.DOM.ul( {className:availabilityDropdown,
onMouseLeave:this.hideDropdownMenu},
React.DOM.li( {onClick:this.changeAvailability("available"),
className:"dnd-menu-item dnd-make-available"},
React.DOM.i( {className:"status status-available"}),
React.DOM.span(null, __("display_name_available_status"))
),
React.DOM.li({onClick: this.changeAvailability("do-not-disturb"),
className: "dnd-menu-item dnd-make-unavailable"},
React.DOM.i({className: "status status-dnd"}),
),
React.DOM.li( {onClick:this.changeAvailability("do-not-disturb"),
className:"dnd-menu-item dnd-make-unavailable"},
React.DOM.i( {className:"status status-dnd"}),
React.DOM.span(null, __("display_name_dnd_status"))
)
)
@ -115,10 +115,10 @@ loop.panel = (function(_, mozL10n) {
if (this.state.seenToS == "unseen") {
navigator.mozLoop.setLoopCharPref('seenToS', 'seen');
return React.DOM.p({className: "terms-service",
dangerouslySetInnerHTML: {__html: tosHTML}});
return React.DOM.p( {className:"terms-service",
dangerouslySetInnerHTML:{__html: tosHTML}});
} else {
return React.DOM.div(null);
return React.DOM.div(null );
}
}
});
@ -130,11 +130,11 @@ loop.panel = (function(_, mozL10n) {
render: function() {
return (
React.DOM.div({className: "component-spacer share generate-url"},
React.DOM.div({className: "description"},
React.DOM.p({className: "description-content"}, this.props.summary)
),
React.DOM.div({className: "action"},
React.DOM.div( {className:"component-spacer share generate-url"},
React.DOM.div( {className:"description"},
React.DOM.p( {className:"description-content"}, this.props.summary)
),
React.DOM.div( {className:"action"},
this.props.children
)
)
@ -178,8 +178,7 @@ loop.panel = (function(_, mozL10n) {
this.setState({pending: false});
} else {
try {
var callUrl = new window.URL(callUrlData.callUrl ||
callUrlData.call_url);
var callUrl = new window.URL(callUrlData.callUrl);
// XXX the current server vers does not implement the callToken field
// but it exists in the API. This workaround should be removed in the future
var token = callUrlData.callToken ||
@ -202,10 +201,10 @@ loop.panel = (function(_, mozL10n) {
// from the react lib.
var cx = React.addons.classSet;
return (
PanelLayout({summary: __("share_link_header_text")},
React.DOM.div({className: "invite"},
React.DOM.input({type: "url", value: this.state.callUrl, readOnly: "true",
className: cx({'pending': this.state.pending})})
PanelLayout( {summary:__("share_link_header_text")},
React.DOM.div( {className:"invite"},
React.DOM.input( {type:"url", value:this.state.callUrl, readOnly:"true",
className:cx({'pending': this.state.pending})} )
)
)
);
@ -224,10 +223,10 @@ loop.panel = (function(_, mozL10n) {
render: function() {
return (
React.DOM.div(null,
CallUrlResult({client: this.props.client,
notifier: this.props.notifier}),
ToSView(null),
AvailabilityDropdown(null)
CallUrlResult( {client:this.props.client,
notifier:this.props.notifier} ),
ToSView(null ),
AvailabilityDropdown(null )
)
);
}
@ -294,8 +293,8 @@ loop.panel = (function(_, mozL10n) {
var client = new loop.Client({
baseServerUrl: navigator.mozLoop.serverUrl
});
this.loadReactComponent(PanelView({client: client,
notifier: this._notifier}));
this.loadReactComponent(PanelView( {client:client,
notifier:this._notifier} ));
}
});

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

@ -178,8 +178,7 @@ loop.panel = (function(_, mozL10n) {
this.setState({pending: false});
} else {
try {
var callUrl = new window.URL(callUrlData.callUrl ||
callUrlData.call_url);
var callUrl = new window.URL(callUrlData.callUrl);
// XXX the current server vers does not implement the callToken field
// but it exists in the API. This workaround should be removed in the future
var token = callUrlData.callToken ||

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

@ -8,7 +8,7 @@
position: relative;
}
.conversation .controls {
.conversation-toolbar {
position: absolute;
z-index: 999; /* required to have it superimposed to the video element */
left: 0;
@ -20,13 +20,13 @@
padding: 0;
}
.conversation .controls li {
.conversation-toolbar li {
float: left;
font-size: 0px; /* prevents vertical bottom padding added to buttons in google
chrome */
}
.conversation .controls .btn {
.conversation-toolbar .btn {
width: 40px;
height: 30px;
background: transparent;
@ -38,66 +38,66 @@
cursor: pointer;
}
.conversation .controls .btn:hover {
.conversation-toolbar .btn:hover {
background-color: rgba(255, 255, 255, .35);
}
/* Hangup button */
.conversation .controls .btn-hangup {
.conversation-toolbar .btn-hangup {
background-color: #D74345;
background-image: url(../img/hangup-inverse-14x14.png);
}
.conversation .controls .btn-hangup:hover {
.conversation-toolbar .btn-hangup:hover {
background-color: #C53436;
}
@media (min-resolution: 2dppx) {
.conversation .controls .btn-hangup {
.conversation-toolbar .btn-hangup {
background-image: url(../img/hangup-inverse-14x14@2x.png);
}
}
/* Common media control buttons behavior */
.conversation .controls .media-control {
.conversation-toolbar .media-control {
background-color: transparent;
opacity: 1;
}
.conversation .controls .media-control:hover {
.conversation-toolbar .media-control:hover {
background-color: rgba(255, 255, 255, .35);
opacity: 1;
}
.conversation .controls .media-control.muted {
.conversation-toolbar .media-control.muted {
background-color: #0096DD;
opacity: 1;
}
/* Audio mute button */
.conversation .controls .local-media.btn-mute-audio {
.conversation-toolbar .local-media.btn-mute-audio {
background-image: url(../img/audio-inverse-14x14.png);
}
.conversation .controls .local-media.btn-mute-audio.muted {
.conversation-toolbar .local-media.btn-mute-audio.muted {
background-image: url(../img/mute-inverse-14x14.png);
}
@media (min-resolution: 2dppx) {
.conversation .controls .local-media.btn-mute-audio {
.conversation-toolbar .local-media.btn-mute-audio {
background-image: url(../img/audio-inverse-14x14@2x.png);
}
.conversation .controls .local-media.btn-mute-audio.muted {
.conversation-toolbar .local-media.btn-mute-audio.muted {
background-image: url(../img/mute-inverse-14x14@2x.png);
}
}
/* Video mute button */
.conversation .controls .local-media.btn-mute-video {
.conversation-toolbar .local-media.btn-mute-video {
background-image: url(../img/video-inverse-14x14.png);
}
.conversation .controls .local-media.btn-mute-video.muted {
.conversation-toolbar .local-media.btn-mute-video.muted {
background-image: url(../img/facemute-14x14.png);
}
@media (min-resolution: 2dppx) {
.conversation .controls .local-media.btn-mute-video {
.conversation-toolbar .local-media.btn-mute-video {
background-image: url(../img/video-inverse-14x14@2x.png);
}
.conversation .controls .local-media.btn-mute-video.muted {
.conversation-toolbar .local-media.btn-mute-video.muted {
background-image: url(../img/facemute-14x14@2x.png);
}
}

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

@ -1,274 +0,0 @@
<!DOCTYPE html>
<!-- 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/. -->
<!-- This file is intended to help frontend developers to easily identify what
are the available styles for the Loop UI components. -->
<html>
<head>
<meta charset="utf-8">
<title>Loop UI shared CSS information/demo</title>
<link type="text/css" rel="stylesheet" href="common.css">
<link type="text/css" rel="stylesheet" href="panel.css">
<link type="text/css" rel="stylesheet" href="conversation.css">
<style>
body {
width: 600px;
margin: 1em auto;
background: #fff;
font-size: 12px;
}
h2 {
margin-top: 3em;
}
</style>
</head>
<body>
<h1>Loop UI toolkit</h1>
<h2>Logo icons</h2>
<p>
<img src="../img/icon_32.png"> 32x32 transparent PNG
<img src="../img/icon_64.png"> 64x64 transparent PNG
</p>
<p><em><strong>Note:</strong> these are temporary.</em></p>
<h2>Share panel</h2>
<h3>Simple</h3>
<div class="share">
<form class="description">
<p>This is a simple message.</p>
</form>
<div class="action">
<p><input type="url" value="http://loop.im/plop75"></p>
<p>Your name will appear as <a href="">Unnamed</a>.</p>
</div>
</div>
<h3>Featuring options</h3>
<div class="share">
<form class="description">
<p class="field">
<label>Share this link with a friend to
<select>
<option>browse together</option>
<option selected="selected">video chat</option>
<option>audio chat</option>
<option>text chat</option>
</select>
</label>
</p>
<p class="field">
<label>
Use webcam <select><option>Foo</option></select>
</label>
</p>
<p class="field">
<label>Use whatever
<select><option>Long foo is long indeed</option></select>
</label>
</p>
<p class="preview cf">
Preview <video></video>
</p>
</form>
<div class="action">
<p><input type="url" value="http://loop.im/plop75"></p>
<p>Your name will appear as <a href="">Unnamed</a>.</p>
</div>
</div>
<h2>Conversation window</h2>
<p><em>The conversation component adapts automatically to its container to
occupy all the available space.</em></p>
<h3>Large</h3>
<div class="conversation">
<div class="media nested">
<div class="remote_wrapper">
<video class="remote"></video>
</div>
<video class="local"></video>
</div>
</div>
<h3>Large with controls</h3>
<div class="conversation">
<ul class="controls">
<li><button class="btn btn-hangup" title="Hangup"></button></li>
<li><button class="btn media-control local-media btn-mute-video" title="Mute video"></button></li>
<li><button class="btn media-control local-media btn-mute-audio" title="Mute audio"></button></li>
</ul>
<div class="media nested">
<div class="remote_wrapper">
<video class="remote"></video>
</div>
<video class="local"></video>
</div>
</div>
<h3>Small (think chat window)</h3>
<div style="width: 204px">
<div class="conversation">
<ul class="controls">
<li><button class="btn btn-hangup" title="Hangup"></button></li>
<li><button class="btn media-control local-media btn-mute-video" title="Mute video"></button></li>
<li><button class="btn media-control local-media btn-mute-audio" title="Mute audio"></button></li>
</ul>
<div class="media nested">
<div class="remote_wrapper">
<video class="remote"></video>
</div>
<video class="local"></video>
</div>
</div>
</div>
<h3>Side by side</h3>
<div class="conversation">
<div class="media side-by-side">
<div class="remote_wrapper">
<video class="remote"></video>
</div>
<video class="local"></video>
</div>
</div>
<h2>Controls button variants</h2>
<h3>Nothing muted</h3>
<div style="width: 204px; min-height: 26px">
<div class="conversation">
<ul class="controls">
<li><button class="btn btn-hangup" title="Hangup"></button></li>
<li><button class="btn media-control local-media btn-mute-video" title="Mute video"></button></li>
<li><button class="btn media-control local-media btn-mute-audio" title="Mute audio"></button></li>
</ul>
</div>
</div>
<h3>Local audio muted</h3>
<div style="width: 204px; min-height: 26px">
<div class="conversation">
<ul class="controls">
<li><button class="btn btn-hangup" title="Hangup"></button></li>
<li><button class="btn media-control local-media btn-mute-video" title="Mute video"></button></li>
<li><button class="btn media-control local-media btn-mute-audio muted" title="Mute audio"></button></li>
</ul>
</div>
</div>
<h3>Local video muted</h3>
<div style="width: 204px; min-height: 26px">
<div class="conversation">
<ul class="controls">
<li><button class="btn btn-hangup" title="Hangup"></button></li>
<li><button class="btn media-control local-media btn-mute-video muted" title="Mute video"></button></li>
<li><button class="btn media-control local-media btn-mute-audio" title="Mute audio"></button></li>
</ul>
</div>
</div>
<h2>Expired call url view</h2>
<div class="expired-url-info">
<div class="info-panel">
<div class="firefox-logo"></div>
<h1 >Oops!</h1>
<h4 >This URL is unavailable.</h4>
</div>
<div class="promote-firefox">
<h3>Download Firefox to make free audio and video calls!</h3>
<p>
<a class="btn btn-large btn-success" href="https://www.mozilla.org/firefox/" data-reactid=".0.1.1.0">Get Firefox</a>
</p>
</div>
</div>
<h2>Buttons</h2>
<h3>Using <code>&lt;a&gt;</code></h3>
<p>
<a href="" class="btn">default</a>
<a href="" class="btn btn-info">info</a>
<a href="" class="btn btn-success">success</a>
<a href="" class="btn btn-warning">warning</a>
<a href="" class="btn btn-error">error</a>
</p>
<h3>Inline</h3>
<p>Click <a href="" class="btn btn-info">here</a>.</p>
<h3>Using <code>&lt;button&gt;</code></h3>
<p>
<button class="btn">default</button>
<button class="btn btn-info">info</button>
<button class="btn btn-success">success</button>
<button class="btn btn-warning">warning</button>
<button class="btn btn-error">error</button>
</p>
<h3>Large buttons</h3>
<p>
<a class="btn btn-large">default</a>
<a class="btn btn-large btn-info">info</a>
<a class="btn btn-large btn-success">success</a>
<a class="btn btn-large btn-warning">warning</a>
<a class="btn btn-large btn-error">error</a>
</p>
<h2>Alerts</h2>
<div class="alert alert-error">
<button class="close"></button>
<p class="message">Oops! Something went really wrong.</p>
</div>
<div class="alert alert-warning">
<button class="close"></button>
<p class="message">Oops! This is a warning.</p>
</div>
<h2>Logos</h2>
<h3>Centered Firefox logo</h3>
<div class="firefox-logo"></div>
<h2>Incoming call</h2>
<div class="incoming-call">
<h2>Incoming call</h2>
<p>
<button class="btn btn-success btn-accept">Accept</button>
<button class="btn btn-error btn-decline">Decline</button>
</p>
</div>
<script>
window.onload = function() {
[].forEach.call(document.querySelectorAll("video"), function(video) {
video.setAttribute("src", "http://v2v.cc/~j/theora_testsuite/320x240.ogg");
});
};
</script>
</body>
</html>

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

@ -180,7 +180,7 @@ loop.shared.views = (function(_, OT, l10n) {
render: function() {
/* jshint ignore:start */
return (
React.DOM.ul({className: "controls"},
React.DOM.ul({className: "conversation-toolbar"},
React.DOM.li(null, React.DOM.button({className: "btn btn-hangup",
onClick: this.handleClickHangup,
title: __("hangup_button_title")})),

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

@ -180,7 +180,7 @@ loop.shared.views = (function(_, OT, l10n) {
render: function() {
/* jshint ignore:start */
return (
<ul className="controls">
<ul className="conversation-toolbar">
<li><button className="btn btn-hangup"
onClick={this.handleClickHangup}
title={__("hangup_button_title")}></button></li>

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

@ -42,14 +42,14 @@ loop.webapp = (function($, _, OT, webL10n) {
render: function() {
if (this.props.helper.isFirefox(navigator.userAgent)) {
return React.DOM.div(null );
return React.DOM.div(null);
}
return (
React.DOM.div( {className:"promote-firefox"},
React.DOM.h3(null, __("promote_firefox_hello_heading")),
React.DOM.div({className: "promote-firefox"},
React.DOM.h3(null, __("promote_firefox_hello_heading")),
React.DOM.p(null,
React.DOM.a( {className:"btn btn-large btn-success",
href:"https://www.mozilla.org/firefox/"},
React.DOM.a({className: "btn btn-large btn-success",
href: "https://www.mozilla.org/firefox/"},
__("get_firefox_button")
)
)
@ -69,13 +69,13 @@ loop.webapp = (function($, _, OT, webL10n) {
render: function() {
/* jshint ignore:start */
return (
React.DOM.div( {className:"expired-url-info"},
React.DOM.div( {className:"info-panel"},
React.DOM.div( {className:"firefox-logo"} ),
React.DOM.h1(null, __("call_url_unavailable_notification_heading")),
React.DOM.div({className: "expired-url-info"},
React.DOM.div({className: "info-panel"},
React.DOM.div({className: "firefox-logo"}),
React.DOM.h1(null, __("call_url_unavailable_notification_heading")),
React.DOM.h4(null, __("call_url_unavailable_notification_message"))
),
PromoteFirefoxView( {helper:this.props.helper} )
),
PromoteFirefoxView({helper: this.props.helper})
)
);
/* jshint ignore:end */

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

@ -200,7 +200,7 @@ describe("loop.panel", function() {
beforeEach(function() {
callUrlData = {
call_url: "http://call.invalid/",
callUrl: "http://call.invalid/",
expiresAt: 1000
};
@ -229,7 +229,7 @@ describe("loop.panel", function() {
beforeEach(function() {
callUrlData = {
call_url: "http://call.invalid/fakeToken",
callUrl: "http://call.invalid/fakeToken",
expiresAt: 1000
};
@ -272,7 +272,7 @@ describe("loop.panel", function() {
it("should update state with the call url received", function() {
expect(view.state.pending).eql(false);
expect(view.state.callUrl).eql(callUrlData.call_url);
expect(view.state.callUrl).eql(callUrlData.callUrl);
});
it("should clear the pending state when a response is received",
@ -283,7 +283,7 @@ describe("loop.panel", function() {
it("should update CallUrlResult with the call url", function() {
var urlField = view.getDOMNode().querySelector("input[type='url']");
expect(urlField.value).eql(callUrlData.call_url);
expect(urlField.value).eql(callUrlData.callUrl);
});
it("should reset all pending notifications", function() {

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

@ -47,12 +47,13 @@ let mockPushHandler = {
// This sets the registration result to be returned when initialize
// is called. By default, it is equivalent to success.
registrationResult: null,
registrationPushURL: undefined,
/**
* MozLoopPushHandler API
*/
initialize: function(registerCallback, notificationCallback) {
registerCallback(this.registrationResult);
registerCallback(this.registrationResult, this.registrationPushURL);
this._notificationCallback = notificationCallback;
},

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

@ -1,6 +1,8 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource://services-common/utils.js");
/**
* This file is to test general registration. Note that once successful
* registration has taken place, we can no longer test the server side
@ -49,7 +51,14 @@ add_test(function test_register_websocket_success_loop_server_fail() {
* registration are complete.
*/
add_test(function test_register_success() {
mockPushHandler.registrationPushURL = kEndPointUrl;
loopServer.registerPathHandler("/registration", (request, response) => {
let body = CommonUtils.readBytesFromInputStream(request.bodyInputStream);
let data = JSON.parse(body);
Assert.equal(data.simplePushURL, kEndPointUrl,
"Should send correct push url");
response.setStatusLine(null, 200, "OK");
response.processAsync();
response.finish();

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

@ -0,0 +1,10 @@
Loop UI Components Showcase
===========================
This app file showcases all Loop's view components.
If you want to modify the app, launch the following command:
browser/components/loop/build-jsx --watch
And start editing the `ui-showcase.jsx` file.

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

@ -0,0 +1,14 @@
/* 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/. */
/**
* /!\ FIXME: THIS IS A HORRID HACK which fakes both the mozL10n and webL10n
* objects and makes them returning "fake string" for any requested string id.
* @type {Object}
*/
document.webL10n = document.mozL10n = {
get: function() {
return "fake text";
}
};

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

@ -0,0 +1,11 @@
/* 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/. */
/**
* Faking the mozLoop object which doesn't exist in regular web pages.
* @type {Object}
*/
navigator.mozLoop = {
getLoopCharPref: function() {}
};

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

@ -0,0 +1,33 @@
<!DOCTYPE html>
<!-- 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/. -->
<html>
<head>
<meta charset="utf-8">
<title>Loop UI Components Showcase</title>
<link rel="stylesheet" type="text/css" href="../content/shared/css/common.css">
<link rel="stylesheet" type="text/css" href="../content/shared/css/conversation.css">
<link rel="stylesheet" type="text/css" href="../content/shared/css/panel.css">
<link rel="stylesheet" type="text/css" href="ui-showcase.css">
</head>
<body>
<div id="main"></div>
<script src="fake-mozLoop.js"></script>
<script src="fake-l10n.js"></script>
<script src="../content/libs/sdk.js"></script>
<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="../content/shared/js/models.js"></script>
<script src="../content/shared/js/router.js"></script>
<script src="../content/shared/js/views.js"></script>
<script src="../content/js/client.js"></script>
<script src="../content/js/desktopRouter.js"></script>
<script src="../standalone/content/js/webapp.js"></script>
<script src="../content/js/panel.js"></script>
<script src="../content/js/conversation.js"></script>
<script src="ui-showcase.js"></script>
</body>
</html>

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

@ -0,0 +1,47 @@
/* 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/. */
.showcase {
width: 730px;
margin: 0 auto;
}
.showcase > header {
position: fixed;
top: 0;
background-color: #fbfbfb;
z-index: 1000;
width: 100%;
padding-bottom: 1em;
}
.showcase .menu > a {
margin-right: .5em;
}
.showcase > section {
position: relative;
padding-top: 10em;
clear: both;
}
.showcase > section > h1 {
border-bottom: 1px solid #aaa;
}
.showcase > section .comp {
margin: 0 auto; /* width is usually set programmatically */
}
.showcase > section .comp.dashed {
border: 1px dashed #ccc;
}
.showcase > section > .example {
margin-bottom: 6em;
}
.showcase > section .example > h3 {
border-bottom: 1px dashed #aaa;
}

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

@ -0,0 +1,133 @@
/** @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 */
(function() {
"use strict";
// 1. Desktop components
// 1.1 Panel
var PanelView = loop.panel.PanelView;
// 1.2. Conversation Window
var IncomingCallView = loop.conversation.IncomingCallView;
// 2. Standalone webapp
var CallUrlExpiredView = loop.webapp.CallUrlExpiredView;
// 3. Shared components
var ConversationToolbar = loop.shared.views.ConversationToolbar;
var ConversationView = loop.shared.views.ConversationView;
// Local helpers
function returnTrue() {
return true;
}
function returnFalse() {
return false;
}
var Example = React.createClass({displayName: 'Example',
render: function() {
var cx = React.addons.classSet;
return (
React.DOM.div({className: "example"},
React.DOM.h3(null, this.props.summary),
React.DOM.div({className: cx({comp: true, dashed: this.props.dashed}),
style: this.props.style || {}},
this.props.children
)
)
);
}
});
var Section = React.createClass({displayName: 'Section',
render: function() {
return (
React.DOM.section({id: this.props.name},
React.DOM.h1(null, this.props.name),
this.props.children
)
);
}
});
var ShowCase = React.createClass({displayName: 'ShowCase',
render: function() {
return (
React.DOM.div({className: "showcase"},
React.DOM.header(null,
React.DOM.h1(null, "Loop UI Components Showcase"),
React.DOM.nav({className: "menu"},
React.Children.map(this.props.children, function(section) {
return (
React.DOM.a({className: "btn btn-info", href: "#" + section.props.name},
section.props.name
)
);
})
)
),
this.props.children
)
);
}
});
var App = React.createClass({displayName: 'App',
render: function() {
return (
ShowCase(null,
Section({name: "PanelView"},
Example({summary: "332px wide", dashed: "true", style: {width: "332px"}},
PanelView(null)
)
),
Section({name: "IncomingCallView"},
Example({summary: "Default", dashed: "true", style: {width: "280px"}},
IncomingCallView(null)
)
),
Section({name: "ConversationToolbar"},
Example({summary: "Default"},
ConversationToolbar({video: {enabled: true}, audio: {enabled: true}})
),
Example({summary: "Video muted"},
ConversationToolbar({video: {enabled: false}, audio: {enabled: true}})
),
Example({summary: "Audio muted"},
ConversationToolbar({video: {enabled: true}, audio: {enabled: false}})
)
),
Section({name: "ConversationView"},
Example({summary: "Default"},
ConversationView({video: {enabled: true}, audio: {enabled: true}})
)
),
Section({name: "CallUrlExpiredView"},
Example({summary: "Firefox User"},
CallUrlExpiredView({helper: {isFirefox: returnTrue}})
),
Example({summary: "Non-Firefox User"},
CallUrlExpiredView({helper: {isFirefox: returnFalse}})
)
)
)
);
}
});
window.addEventListener("DOMContentLoaded", function() {
React.renderComponent(App(null), document.body);
});
})();

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

@ -0,0 +1,133 @@
/** @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 */
(function() {
"use strict";
// 1. Desktop components
// 1.1 Panel
var PanelView = loop.panel.PanelView;
// 1.2. Conversation Window
var IncomingCallView = loop.conversation.IncomingCallView;
// 2. Standalone webapp
var CallUrlExpiredView = loop.webapp.CallUrlExpiredView;
// 3. Shared components
var ConversationToolbar = loop.shared.views.ConversationToolbar;
var ConversationView = loop.shared.views.ConversationView;
// Local helpers
function returnTrue() {
return true;
}
function returnFalse() {
return false;
}
var Example = React.createClass({
render: function() {
var cx = React.addons.classSet;
return (
<div className="example">
<h3>{this.props.summary}</h3>
<div className={cx({comp: true, dashed: this.props.dashed})}
style={this.props.style || {}}>
{this.props.children}
</div>
</div>
);
}
});
var Section = React.createClass({
render: function() {
return (
<section id={this.props.name}>
<h1>{this.props.name}</h1>
{this.props.children}
</section>
);
}
});
var ShowCase = React.createClass({
render: function() {
return (
<div className="showcase">
<header>
<h1>Loop UI Components Showcase</h1>
<nav className="menu">{
React.Children.map(this.props.children, function(section) {
return (
<a className="btn btn-info" href={"#" + section.props.name}>
{section.props.name}
</a>
);
})
}</nav>
</header>
{this.props.children}
</div>
);
}
});
var App = React.createClass({
render: function() {
return (
<ShowCase>
<Section name="PanelView">
<Example summary="332px wide" dashed="true" style={{width: "332px"}}>
<PanelView />
</Example>
</Section>
<Section name="IncomingCallView">
<Example summary="Default" dashed="true" style={{width: "280px"}}>
<IncomingCallView />
</Example>
</Section>
<Section name="ConversationToolbar">
<Example summary="Default">
<ConversationToolbar video={{enabled: true}} audio={{enabled: true}} />
</Example>
<Example summary="Video muted">
<ConversationToolbar video={{enabled: false}} audio={{enabled: true}} />
</Example>
<Example summary="Audio muted">
<ConversationToolbar video={{enabled: true}} audio={{enabled: false}} />
</Example>
</Section>
<Section name="ConversationView">
<Example summary="Default">
<ConversationView video={{enabled: true}} audio={{enabled: true}} />
</Example>
</Section>
<Section name="CallUrlExpiredView">
<Example summary="Firefox User">
<CallUrlExpiredView helper={{isFirefox: returnTrue}} />
</Example>
<Example summary="Non-Firefox User">
<CallUrlExpiredView helper={{isFirefox: returnFalse}} />
</Example>
</Section>
</ShowCase>
);
}
});
window.addEventListener("DOMContentLoaded", function() {
React.renderComponent(<App />, document.body);
});
})();

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

@ -3,4 +3,4 @@
# 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/.
TEST_DIRS += ['test']
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
BROWSER_CHROME_MANIFESTS += ['browser.ini']

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

@ -14,7 +14,8 @@ const TESTCASE_URI_SCSS = TEST_BASE + "sourcemap-sass/sourcemaps.scss";
const TESTCASE_URI_MAP = TEST_BASE + "sourcemap-css/sourcemaps.css.map";
const TESTCASE_SCSS_NAME = "sourcemaps.scss";
const PREF = "devtools.styleeditor.source-maps-enabled";
const SOURCE_MAP_PREF = "devtools.styleeditor.source-maps-enabled";
const TRANSITIONS_PREF = "devtools.styleeditor.transitions";
const CSS_TEXT = "* { color: blue }";
@ -31,7 +32,8 @@ function test()
{
waitForExplicitFinish();
Services.prefs.setBoolPref(PREF, true);
Services.prefs.setBoolPref(SOURCE_MAP_PREF, true);
Services.prefs.setBoolPref(TRANSITIONS_PREF, false);
Task.spawn(function() {
// copy all our files over so we don't screw them up for other tests
@ -126,7 +128,8 @@ function pauseForTimeChange() {
}
function finishUp() {
Services.prefs.clearUserPref(PREF);
Services.prefs.clearUserPref(SOURCE_MAP_PREF);
Services.prefs.clearUserPref(TRANSITIONS_PREF);
finish();
}

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

@ -50,11 +50,17 @@ let test = asyncTest(function*() {
is(specificity, expected,
'Selector "' + selectorText + '" has a specificity of ' + expected);
}
info("Testing specificity of element.style");
let colorProp = cssLogic.getPropertyInfo("background");
is(colorProp.matchedSelectors[0].specificity, 0x01000000,
"Element styles have specificity of 0x01000000 (16777216).");
});
function createDocument() {
let doc = content.document;
doc.body.innerHTML = getStylesheetText();
doc.body.style.background = "blue";
doc.title = "Computed view specificity test";
}

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

@ -18,7 +18,7 @@ window.addEventListener("load", function onLoad() {
// Buttons
document.querySelector("#close").onclick = CloseUI;
document.querySelector("#restoreButton").onclick = RestoreDefaults;
document.querySelector("#restore").onclick = RestoreDefaults;
document.querySelector("#manageSimulators").onclick = ShowAddons;
// Initialize the controls

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

@ -19,6 +19,8 @@
<body>
<div id="controls">
<a id="restore">&prefs_restore;</a>
<a id="manageSimulators">&prefs_simulators;</a>
<a id="close">&deck_close;</a>
</div>
@ -27,6 +29,12 @@
<h2>&prefs_general_title;</h2>
<ul>
<li>
<label title="&prefs_options_templatesurl_tooltip;">
<span>&prefs_options_templatesurl;</span>
<input data-pref="devtools.webide.templatesURL"/>
</label>
</li>
<li>
<label title="&prefs_options_enablelocalruntime_tooltip;">
<input type="checkbox" data-pref="devtools.webide.enableLocalRuntime"/>
@ -40,9 +48,9 @@
</label>
</li>
<li>
<label title="&prefs_options_templatesurl_tooltip;">
<span>&prefs_options_templatesurl;</span>
<input data-pref="devtools.webide.templatesURL"/>
<label title="&prefs_options_showeditor_tooltip;">
<input type="checkbox" data-pref="devtools.webide.showProjectEditor"/>
<span>&prefs_options_showeditor;</span>
</label>
</li>
</ul>
@ -50,36 +58,6 @@
<h2>&prefs_editor_title;</h2>
<ul>
<li>
<label title="&prefs_options_showeditor_tooltip;">
<input type="checkbox" data-pref="devtools.webide.showProjectEditor"/>
<span>&prefs_options_showeditor;</span>
</label>
</li>
<li>
<label title="&prefs_options_autoclosebrackets_tooltip;">
<input type="checkbox" data-pref="devtools.editor.autoclosebrackets"/>
<span>&prefs_options_autoclosebrackets;</span>
</label>
</li>
<li>
<label title="&prefs_options_autocomplete_tooltip;">
<input type="checkbox" data-pref="devtools.editor.autocomplete"/>
<span>&prefs_options_autocomplete;</span>
</label>
</li>
<li>
<label title="&prefs_options_detectindentation_tooltip;">
<input type="checkbox" data-pref="devtools.editor.detectindentation"/>
<span>&prefs_options_detectindentation;</span>
</label>
</li>
<li>
<label title="&prefs_options_expandtab_tooltip;">
<input type="checkbox" data-pref="devtools.editor.expandtab"/>
<span>&prefs_options_expandtab;</span>
</label>
</li>
<li>
<label><span>&prefs_options_tabsize;</span>
<select data-pref="devtools.editor.tabsize">
@ -89,10 +67,31 @@
</select>
</label>
</li>
<li>
<label title="&prefs_options_expandtab_tooltip;">
<input type="checkbox" data-pref="devtools.editor.expandtab"/>
<span>&prefs_options_expandtab;</span>
</label>
</li>
<li>
<label title="&prefs_options_detectindentation_tooltip;">
<input type="checkbox" data-pref="devtools.editor.detectindentation"/>
<span>&prefs_options_detectindentation;</span>
</label>
</li>
<li>
<label title="&prefs_options_autocomplete_tooltip;">
<input type="checkbox" data-pref="devtools.editor.autocomplete"/>
<span>&prefs_options_autocomplete;</span>
</label>
</li>
<li>
<label title="&prefs_options_autoclosebrackets_tooltip;">
<input type="checkbox" data-pref="devtools.editor.autoclosebrackets"/>
<span>&prefs_options_autoclosebrackets;</span>
</label>
</li>
</ul>
<button id="manageSimulators">&prefs_simulators;</button>
<button id="restoreButton">&prefs_restore;</button>
</body>
</html>

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

@ -108,15 +108,15 @@
<!ENTITY prefs_options_templatesurl_tooltip "Index of available templates">
<!ENTITY prefs_options_showeditor "Show editor">
<!ENTITY prefs_options_showeditor_tooltip "Show internal editor">
<!ENTITY prefs_options_detectindentation "Detect indentation">
<!ENTITY prefs_options_tabsize "Tab size">
<!ENTITY prefs_options_expandtab "Soft tabs">
<!ENTITY prefs_options_expandtab_tooltip "Use spaces instead of the tab character">
<!ENTITY prefs_options_detectindentation "Autoindent">
<!ENTITY prefs_options_detectindentation_tooltip "Guess indentation based on source content">
<!ENTITY prefs_options_autocomplete "Autocomplete">
<!ENTITY prefs_options_autocomplete_tooltip "Enable code autocompletion">
<!ENTITY prefs_options_autoclosebrackets "Autoclose brackets">
<!ENTITY prefs_options_autoclosebrackets_tooltip "Automatically insert closing brackets">
<!ENTITY prefs_options_expandtab "Indent using spaces">
<!ENTITY prefs_options_expandtab_tooltip "Use spaces instead of the tab character">
<!ENTITY prefs_options_autocomplete "Autocompletion">
<!ENTITY prefs_options_autocomplete_tooltip "Enable code autocompletion">
<!ENTITY prefs_options_tabsize "Tab size">
<!-- Permissions Table -->
<!ENTITY permissionstable_title "Permissions Table">

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

@ -37,9 +37,6 @@ h1 {
font-size: small;
cursor: pointer;
border-bottom: 1px dotted;
}
#close {
margin-left: 10px;
}

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

@ -4,5 +4,4 @@
# 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/.
TEST_DIRS += ['pdfjs/test']
BROWSER_CHROME_MANIFESTS += ['pdfjs/test/browser.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
BROWSER_CHROME_MANIFESTS += ['browser.ini']

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

@ -5,4 +5,4 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += ['public', 'src']
TEST_DIRS += ['test']
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
BROWSER_CHROME_MANIFESTS += ['browser.ini']

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

@ -619,7 +619,7 @@ this.UITour = {
},
isSafeScheme: function(aURI) {
let allowedSchemes = new Set(["https"]);
let allowedSchemes = new Set(["https", "about"]);
if (!Services.prefs.getBoolPref("browser.uitour.requireSecure"))
allowedSchemes.add("http");

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

@ -4,7 +4,9 @@
# 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/.
TEST_DIRS += ['test']
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
MOCHITEST_CHROME_MANIFESTS += ['test/chrome/chrome.ini']
XPCSHELL_TESTS_MANIFESTS += ['test/unit/social/xpcshell.ini']
EXTRA_JS_MODULES += [
'BrowserNewTabPreloader.jsm',

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

@ -1,8 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
MOCHITEST_CHROME_MANIFESTS += ['chrome.ini']

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

@ -1,10 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
DIRS += ['chrome', 'unit']
BROWSER_CHROME_MANIFESTS += ['browser.ini']

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

@ -1,7 +0,0 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
XPCSHELL_TESTS_MANIFESTS += ['social/xpcshell.ini']

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

@ -18,6 +18,8 @@
#include "nsID.h"
#include "nsNetUtil.h"
#include "nsIClassInfoImpl.h"
#include "nsIObjectInputStream.h"
#include "nsIObjectOutputStream.h"
#include "nsNetCID.h"
#include "nsError.h"
#include "nsIScriptSecurityManager.h"
@ -66,11 +68,24 @@ nsNullPrincipal::~nsNullPrincipal()
{
}
/* static */ already_AddRefed<nsNullPrincipal>
nsNullPrincipal::CreateWithInheritedAttributes(nsIPrincipal* aInheritFrom)
{
nsRefPtr<nsNullPrincipal> nullPrin = new nsNullPrincipal();
nsresult rv = nullPrin->Init(aInheritFrom->GetAppId(),
aInheritFrom->GetIsInBrowserElement());
return NS_SUCCEEDED(rv) ? nullPrin.forget() : nullptr;
}
#define NS_NULLPRINCIPAL_PREFIX NS_NULLPRINCIPAL_SCHEME ":"
nsresult
nsNullPrincipal::Init()
nsNullPrincipal::Init(uint32_t aAppId, bool aInMozBrowser)
{
MOZ_ASSERT(aAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID);
mAppId = aAppId;
mInMozBrowser = aInMozBrowser;
// FIXME: bug 327161 -- make sure the uuid generator is reseeding-resistant.
nsresult rv;
nsCOMPtr<nsIUUIDGenerator> uuidgen =
@ -256,21 +271,21 @@ nsNullPrincipal::GetJarPrefix(nsACString& aJarPrefix)
NS_IMETHODIMP
nsNullPrincipal::GetAppStatus(uint16_t* aAppStatus)
{
*aAppStatus = nsIPrincipal::APP_STATUS_NOT_INSTALLED;
*aAppStatus = nsScriptSecurityManager::AppStatusForPrincipal(this);
return NS_OK;
}
NS_IMETHODIMP
nsNullPrincipal::GetAppId(uint32_t* aAppId)
{
*aAppId = nsIScriptSecurityManager::NO_APP_ID;
*aAppId = mAppId;
return NS_OK;
}
NS_IMETHODIMP
nsNullPrincipal::GetIsInBrowserElement(bool* aIsInBrowserElement)
{
*aIsInBrowserElement = false;
*aIsInBrowserElement = mInMozBrowser;
return NS_OK;
}
@ -301,16 +316,24 @@ nsNullPrincipal::GetBaseDomain(nsACString& aBaseDomain)
NS_IMETHODIMP
nsNullPrincipal::Read(nsIObjectInputStream* aStream)
{
// no-op: CID is sufficient to create a useful nsNullPrincipal, since the URI
// is not really relevant.
// Note - nsNullPrincipal use NS_GENERIC_FACTORY_CONSTRUCTOR_INIT, which means
// that the Init() method has already been invoked by the time we deserialize.
// This is in contrast to nsPrincipal, which uses NS_GENERIC_FACTORY_CONSTRUCTOR,
// in which case ::Read needs to invoke Init().
nsresult rv = aStream->Read32(&mAppId);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->ReadBoolean(&mInMozBrowser);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
nsNullPrincipal::Write(nsIObjectOutputStream* aStream)
{
// no-op: CID is sufficient to create a useful nsNullPrincipal, since the URI
// is not really relevant.
aStream->Write32(mAppId);
aStream->WriteBoolean(mInMozBrowser);
return NS_OK;
}

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

@ -14,14 +14,15 @@
#include "nsIPrincipal.h"
#include "nsJSPrincipals.h"
#include "nsIScriptSecurityManager.h"
#include "nsCOMPtr.h"
#include "nsIContentSecurityPolicy.h"
class nsIURI;
#define NS_NULLPRINCIPAL_CID \
{ 0xdd156d62, 0xd26f, 0x4441, \
{ 0x9c, 0xdb, 0xe8, 0xf0, 0x91, 0x07, 0xc2, 0x73 } }
{ 0xa0bd8b42, 0xf6bf, 0x4fb9, \
{ 0x93, 0x42, 0x90, 0xbf, 0xc9, 0xb7, 0xa1, 0xab } }
#define NS_NULLPRINCIPAL_CONTRACTID "@mozilla.org/nullprincipal;1"
#define NS_NULLPRINCIPAL_SCHEME "moz-nullprincipal"
@ -41,7 +42,10 @@ public:
NS_DECL_NSIPRINCIPAL
NS_DECL_NSISERIALIZABLE
nsresult Init();
static already_AddRefed<nsNullPrincipal> CreateWithInheritedAttributes(nsIPrincipal *aInheritFrom);
nsresult Init(uint32_t aAppId = nsIScriptSecurityManager::NO_APP_ID,
bool aInMozBrowser = false);
virtual void GetScriptLocation(nsACString &aStr) MOZ_OVERRIDE;
@ -54,6 +58,8 @@ public:
nsCOMPtr<nsIURI> mURI;
nsCOMPtr<nsIContentSecurityPolicy> mCSP;
uint32_t mAppId;
bool mInMozBrowser;
};
#endif // nsNullPrincipal_h__

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

@ -577,48 +577,11 @@ nsPrincipal::Write(nsIObjectOutputStream* aStream)
uint16_t
nsPrincipal::GetAppStatus()
{
NS_WARN_IF_FALSE(mAppId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Asking for app status on a principal with an unknown app id");
// Installed apps have a valid app id (not NO_APP_ID or UNKNOWN_APP_ID)
// and they are not inside a mozbrowser.
if (mAppId == nsIScriptSecurityManager::NO_APP_ID ||
mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID || mInMozBrowser) {
if (mAppId == nsIScriptSecurityManager::UNKNOWN_APP_ID) {
NS_WARNING("Asking for app status on a principal with an unknown app id");
return nsIPrincipal::APP_STATUS_NOT_INSTALLED;
}
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(appsService, nsIPrincipal::APP_STATUS_NOT_INSTALLED);
nsCOMPtr<mozIApplication> app;
appsService->GetAppByLocalId(mAppId, getter_AddRefs(app));
NS_ENSURE_TRUE(app, nsIPrincipal::APP_STATUS_NOT_INSTALLED);
uint16_t status = nsIPrincipal::APP_STATUS_INSTALLED;
NS_ENSURE_SUCCESS(app->GetAppStatus(&status),
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
nsAutoCString origin;
NS_ENSURE_SUCCESS(GetOrigin(getter_Copies(origin)),
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
nsString appOrigin;
NS_ENSURE_SUCCESS(app->GetOrigin(appOrigin),
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
// We go from string -> nsIURI -> origin to be sure we
// compare two punny-encoded origins.
nsCOMPtr<nsIURI> appURI;
NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(appURI), appOrigin),
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
nsAutoCString appOriginPunned;
NS_ENSURE_SUCCESS(GetOriginForURI(appURI, getter_Copies(appOriginPunned)),
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
if (!appOriginPunned.Equals(origin)) {
return nsIPrincipal::APP_STATUS_NOT_INSTALLED;
}
return status;
return nsScriptSecurityManager::AppStatusForPrincipal(this);
}
/************************************************************************************************************************/

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

@ -11,6 +11,7 @@
#include "js/OldDebugAPI.h"
#include "xpcprivate.h"
#include "XPCWrapper.h"
#include "nsIAppsService.h"
#include "nsILoadContext.h"
#include "nsIServiceManager.h"
#include "nsIScriptObjectPrincipal.h"
@ -56,6 +57,7 @@
#include "nsIChromeRegistry.h"
#include "nsIContentSecurityPolicy.h"
#include "nsIAsyncVerifyRedirectCallback.h"
#include "mozIApplication.h"
#include "mozilla/Preferences.h"
#include "mozilla/dom/BindingUtils.h"
#include <stdint.h>
@ -252,6 +254,57 @@ nsScriptSecurityManager::SecurityHashURI(nsIURI* aURI)
return NS_SecurityHashURI(aURI);
}
uint16_t
nsScriptSecurityManager::AppStatusForPrincipal(nsIPrincipal *aPrin)
{
uint32_t appId = aPrin->GetAppId();
bool inMozBrowser = aPrin->GetIsInBrowserElement();
NS_WARN_IF_FALSE(appId != nsIScriptSecurityManager::UNKNOWN_APP_ID,
"Asking for app status on a principal with an unknown app id");
// Installed apps have a valid app id (not NO_APP_ID or UNKNOWN_APP_ID)
// and they are not inside a mozbrowser.
if (appId == nsIScriptSecurityManager::NO_APP_ID ||
appId == nsIScriptSecurityManager::UNKNOWN_APP_ID || inMozBrowser)
{
return nsIPrincipal::APP_STATUS_NOT_INSTALLED;
}
nsCOMPtr<nsIAppsService> appsService = do_GetService(APPS_SERVICE_CONTRACTID);
NS_ENSURE_TRUE(appsService, nsIPrincipal::APP_STATUS_NOT_INSTALLED);
nsCOMPtr<mozIApplication> app;
appsService->GetAppByLocalId(appId, getter_AddRefs(app));
NS_ENSURE_TRUE(app, nsIPrincipal::APP_STATUS_NOT_INSTALLED);
uint16_t status = nsIPrincipal::APP_STATUS_INSTALLED;
NS_ENSURE_SUCCESS(app->GetAppStatus(&status),
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
nsAutoCString origin;
NS_ENSURE_SUCCESS(aPrin->GetOrigin(getter_Copies(origin)),
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
nsString appOrigin;
NS_ENSURE_SUCCESS(app->GetOrigin(appOrigin),
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
// We go from string -> nsIURI -> origin to be sure we
// compare two punny-encoded origins.
nsCOMPtr<nsIURI> appURI;
NS_ENSURE_SUCCESS(NS_NewURI(getter_AddRefs(appURI), appOrigin),
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
nsAutoCString appOriginPunned;
NS_ENSURE_SUCCESS(nsPrincipal::GetOriginForURI(appURI, getter_Copies(appOriginPunned)),
nsIPrincipal::APP_STATUS_NOT_INSTALLED);
if (!appOriginPunned.Equals(origin)) {
return nsIPrincipal::APP_STATUS_NOT_INSTALLED;
}
return status;
}
NS_IMETHODIMP
nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel,
nsIPrincipal** aPrincipal)
@ -271,7 +324,11 @@ nsScriptSecurityManager::GetChannelPrincipal(nsIChannel* aChannel,
aChannel->GetLoadInfo(getter_AddRefs(loadInfo));
if (loadInfo) {
if (loadInfo->GetLoadingSandboxed()) {
return CallCreateInstance(NS_NULLPRINCIPAL_CONTRACTID, aPrincipal);
nsRefPtr<nsNullPrincipal> prin =
nsNullPrincipal::CreateWithInheritedAttributes(loadInfo->LoadingPrincipal());
NS_ENSURE_TRUE(prin, NS_ERROR_FAILURE);
prin.forget(aPrincipal);
return NS_OK;
}
if (loadInfo->GetForceInheritPrincipal()) {

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

@ -68,6 +68,8 @@ public:
static bool SecurityCompareURIs(nsIURI* aSourceURI, nsIURI* aTargetURI);
static uint32_t SecurityHashURI(nsIURI* aURI);
static uint16_t AppStatusForPrincipal(nsIPrincipal *aPrin);
static nsresult
ReportError(JSContext* cx, const nsAString& messageTag,
nsIURI* aSource, nsIURI* aTarget);

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

@ -8010,10 +8010,13 @@ if test "$MOZ_TREE_CAIRO"; then
XLIB_SURFACE_FEATURE="#define CAIRO_HAS_XLIB_SURFACE 1"
XLIB_XRENDER_SURFACE_FEATURE="#define CAIRO_HAS_XLIB_XRENDER_SURFACE 1"
PS_SURFACE_FEATURE="#define CAIRO_HAS_PS_SURFACE 1"
fi
if test "$_HAVE_FREETYPE2"; then
FT_FONT_FEATURE="#define CAIRO_HAS_FT_FONT 1"
MOZ_ENABLE_CAIRO_FT=1
CAIRO_FT_CFLAGS="$FT2_CFLAGS"
fi
case "$MOZ_WIDGET_TOOLKIT" in
qt)
QT_SURFACE_FEATURE="#define CAIRO_HAS_QT_SURFACE 1"

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

@ -715,7 +715,7 @@ nsCopySupport::FireClipboardEvent(int32_t aType, int32_t aClipboardType, nsIPres
// Now that we have copied, update the clipboard commands. This should have
// the effect of updating the enabled state of the paste menu item.
if (doDefault || count) {
piWindow->UpdateCommands(NS_LITERAL_STRING("clipboard"));
piWindow->UpdateCommands(NS_LITERAL_STRING("clipboard"), nullptr, 0);
}
return doDefault;

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

@ -2749,13 +2749,17 @@ static void ExtractRectFromOffset(nsIFrame* aFrame,
}
static nsTextFrame*
GetTextFrameForContent(nsIContent* aContent)
GetTextFrameForContent(nsIContent* aContent, bool aFlushLayout)
{
nsIPresShell* presShell = aContent->OwnerDoc()->GetShell();
if (presShell) {
presShell->FrameConstructor()->EnsureFrameForTextNode(
static_cast<nsGenericDOMDataNode*>(aContent));
aContent->OwnerDoc()->FlushPendingNotifications(Flush_Layout);
if (aFlushLayout) {
aContent->OwnerDoc()->FlushPendingNotifications(Flush_Layout);
}
nsIFrame* frame = aContent->GetPrimaryFrame();
if (frame && frame->GetType() == nsGkAtoms::textFrame) {
return static_cast<nsTextFrame*>(frame);
@ -2766,9 +2770,10 @@ GetTextFrameForContent(nsIContent* aContent)
static nsresult GetPartialTextRect(nsLayoutUtils::RectCallback* aCallback,
nsIContent* aContent, int32_t aStartOffset,
int32_t aEndOffset, bool aClampToEdge)
int32_t aEndOffset, bool aClampToEdge,
bool aFlushLayout)
{
nsTextFrame* textFrame = GetTextFrameForContent(aContent);
nsTextFrame* textFrame = GetTextFrameForContent(aContent, aFlushLayout);
if (textFrame) {
nsIFrame* relativeTo = nsLayoutUtils::GetContainingBlockForClientRect(textFrame);
for (nsTextFrame* f = textFrame; f; f = static_cast<nsTextFrame*>(f->GetNextContinuation())) {
@ -2801,7 +2806,7 @@ nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
nsRange* aRange,
nsINode* aStartParent, int32_t aStartOffset,
nsINode* aEndParent, int32_t aEndOffset,
bool aClampToEdge)
bool aClampToEdge, bool aFlushLayout)
{
// Hold strong pointers across the flush
nsCOMPtr<nsINode> startContainer = aStartParent;
@ -2812,11 +2817,12 @@ nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
return;
}
aStartParent->OwnerDoc()->FlushPendingNotifications(Flush_Layout);
// Recheck whether we're still in the document
if (!aStartParent->IsInDoc()) {
return;
if (aFlushLayout) {
aStartParent->OwnerDoc()->FlushPendingNotifications(Flush_Layout);
// Recheck whether we're still in the document
if (!aStartParent->IsInDoc()) {
return;
}
}
RangeSubtreeIterator iter;
@ -2828,7 +2834,7 @@ nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
// the range is collapsed, only continue if the cursor is in a text node
nsCOMPtr<nsIContent> content = do_QueryInterface(aStartParent);
if (content && content->IsNodeOfType(nsINode::eTEXT)) {
nsTextFrame* textFrame = GetTextFrameForContent(content);
nsTextFrame* textFrame = GetTextFrameForContent(content, aFlushLayout);
if (textFrame) {
int32_t outOffset;
nsIFrame* outFrame;
@ -2858,10 +2864,12 @@ nsRange::CollectClientRects(nsLayoutUtils::RectCallback* aCollector,
if (node == startContainer) {
int32_t offset = startContainer == endContainer ?
aEndOffset : content->GetText()->GetLength();
GetPartialTextRect(aCollector, content, aStartOffset, offset, aClampToEdge);
GetPartialTextRect(aCollector, content, aStartOffset, offset,
aClampToEdge, aFlushLayout);
continue;
} else if (node == endContainer) {
GetPartialTextRect(aCollector, content, 0, aEndOffset, aClampToEdge);
GetPartialTextRect(aCollector, content, 0, aEndOffset,
aClampToEdge, aFlushLayout);
continue;
}
}
@ -2883,7 +2891,7 @@ nsRange::GetBoundingClientRect(nsIDOMClientRect** aResult)
}
already_AddRefed<DOMRect>
nsRange::GetBoundingClientRect(bool aClampToEdge)
nsRange::GetBoundingClientRect(bool aClampToEdge, bool aFlushLayout)
{
nsRefPtr<DOMRect> rect = new DOMRect(ToSupports(this));
if (!mStartParent) {
@ -2892,7 +2900,7 @@ nsRange::GetBoundingClientRect(bool aClampToEdge)
nsLayoutUtils::RectAccumulator accumulator;
CollectClientRects(&accumulator, this, mStartParent, mStartOffset,
mEndParent, mEndOffset, aClampToEdge);
mEndParent, mEndOffset, aClampToEdge, aFlushLayout);
nsRect r = accumulator.mResultRect.IsEmpty() ? accumulator.mFirstRect :
accumulator.mResultRect;
@ -2908,7 +2916,7 @@ nsRange::GetClientRects(nsIDOMClientRectList** aResult)
}
already_AddRefed<DOMRectList>
nsRange::GetClientRects(bool aClampToEdge)
nsRange::GetClientRects(bool aClampToEdge, bool aFlushLayout)
{
if (!mStartParent) {
return nullptr;
@ -2920,7 +2928,7 @@ nsRange::GetClientRects(bool aClampToEdge)
nsLayoutUtils::RectListBuilder builder(rectList);
CollectClientRects(&builder, this, mStartParent, mStartOffset,
mEndParent, mEndOffset, aClampToEdge);
mEndParent, mEndOffset, aClampToEdge, aFlushLayout);
return rectList.forget();
}

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

@ -217,8 +217,10 @@ public:
void SetStartAfter(nsINode& aNode, ErrorResult& aErr);
void SetStartBefore(nsINode& aNode, ErrorResult& aErr);
void SurroundContents(nsINode& aNode, ErrorResult& aErr);
already_AddRefed<DOMRect> GetBoundingClientRect(bool aClampToEdge = true);
already_AddRefed<DOMRectList> GetClientRects(bool aClampToEdge = true);
already_AddRefed<DOMRect> GetBoundingClientRect(bool aClampToEdge = true,
bool aFlushLayout = true);
already_AddRefed<DOMRectList> GetClientRects(bool aClampToEdge = true,
bool aFlushLayout = true);
nsINode* GetParentObject() const { return mOwner; }
virtual JSObject* WrapObject(JSContext* cx) MOZ_OVERRIDE MOZ_FINAL;
@ -260,7 +262,7 @@ public:
nsRange* aRange,
nsINode* aStartParent, int32_t aStartOffset,
nsINode* aEndParent, int32_t aEndOffset,
bool aClampToEdge);
bool aClampToEdge, bool aFlushLayout);
typedef nsTHashtable<nsPtrHashKey<nsRange> > RangeHashTable;
protected:

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

@ -676,7 +676,9 @@ protected:
*/
virtual ~nsTextInputListener();
nsresult UpdateTextInputCommands(const nsAString& commandsToUpdate);
nsresult UpdateTextInputCommands(const nsAString& commandsToUpdate,
nsISelection* sel = nullptr,
int16_t reason = 0);
protected:
@ -780,16 +782,18 @@ nsTextInputListener::NotifySelectionChanged(nsIDOMDocument* aDoc, nsISelection*
}
}
UpdateTextInputCommands(NS_LITERAL_STRING("selectionchange"), aSel, aReason);
// if the collapsed state did not change, don't fire notifications
if (collapsed == mSelectionWasCollapsed)
return NS_OK;
mSelectionWasCollapsed = collapsed;
if (!weakFrame.IsAlive() || !nsContentUtils::IsFocusedContent(mFrame->GetContent()))
return NS_OK;
return UpdateTextInputCommands(NS_LITERAL_STRING("select"));
return UpdateTextInputCommands(NS_LITERAL_STRING("select"), aSel, aReason);
}
// END nsIDOMSelectionListener
@ -930,7 +934,9 @@ nsTextInputListener::EditAction()
nsresult
nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate,
nsISelection* sel,
int16_t reason)
{
nsIContent* content = mFrame->GetContent();
NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
@ -941,7 +947,7 @@ nsTextInputListener::UpdateTextInputCommands(const nsAString& commandsToUpdate)
nsPIDOMWindow *domWindow = doc->GetWindow();
NS_ENSURE_TRUE(domWindow, NS_ERROR_FAILURE);
return domWindow->UpdateCommands(commandsToUpdate);
return domWindow->UpdateCommands(commandsToUpdate, sel, reason);
}
// END nsTextInputListener

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

@ -5,6 +5,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include <stdio.h>
#include <math.h>
#include <string.h>
#include "prlog.h"
#include "prdtoa.h"
#include "AudioStream.h"
@ -16,6 +17,9 @@
#include "mozilla/Telemetry.h"
#include "soundtouch/SoundTouch.h"
#include "Latency.h"
#ifdef XP_MACOSX
#include <sys/sysctl.h>
#endif
namespace mozilla {
@ -246,10 +250,10 @@ AudioStream::AudioStream()
, mLatencyRequest(HighLatency)
, mReadPoint(0)
, mDumpFile(nullptr)
, mVolume(1.0)
, mBytesPerFrame(0)
, mState(INITIALIZED)
, mNeedsStart(false)
, mShouldDropFrames(false)
{
// keep a ref in case we shut down later than nsLayoutStatics
mLatencyLog = AsyncLatencyLogger::Get(true);
@ -498,8 +502,10 @@ AudioStream::Init(int32_t aNumChannels, int32_t aRate,
params.channels = mOutChannels;
#if defined(__ANDROID__)
#if defined(MOZ_B2G)
mAudioChannel = aAudioChannel;
params.stream_type = ConvertChannelToCubebType(aAudioChannel);
#else
mAudioChannel = dom::AudioChannel::Content;
params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
@ -544,6 +550,62 @@ AudioStream::Init(int32_t aNumChannels, int32_t aRate,
return rv;
}
// On certain MacBookPro, the microphone is located near the left speaker.
// We need to pan the sound output to the right speaker if we are using the mic
// and the built-in speaker, or we will have terrible echo.
void AudioStream::PanOutputIfNeeded(bool aMicrophoneActive)
{
#ifdef XP_MACOSX
cubeb_device* device;
int rv;
char name[128];
size_t length = sizeof(name);
bool panCenter = false;
rv = sysctlbyname("hw.model", name, &length, NULL, 0);
if (rv) {
return;
}
if (!strncmp(name, "MacBookPro", 10)) {
if (cubeb_stream_get_current_device(mCubebStream, &device) == CUBEB_OK) {
// Check if we are currently outputing sound on external speakers.
if (!strcmp(device->output_name, "ispk")) {
// Pan everything to the right speaker.
if (aMicrophoneActive) {
LOG(("%p Panning audio output to the right.", this));
if (cubeb_stream_set_panning(mCubebStream, 1.0) != CUBEB_OK) {
NS_WARNING("Could not pan audio output to the right.");
}
} else {
panCenter = true;
}
} else {
panCenter = true;
}
if (panCenter) {
LOG(("%p Panning audio output to the center.", this));
if (cubeb_stream_set_panning(mCubebStream, 0.0) != CUBEB_OK) {
NS_WARNING("Could not pan audio output to the center.");
}
// This a microphone that goes through the headphone plug, reset the
// output to prevent echo building up.
if (strcmp(device->input_name, "emic") == 0) {
Reset();
}
}
cubeb_stream_device_destroy(mCubebStream, device);
}
}
#endif
}
void AudioStream::DeviceChangedCallback() {
MonitorAutoLock mon(mMonitor);
PanOutputIfNeeded(mMicrophoneActive);
mShouldDropFrames = true;
}
// This code used to live inside AudioStream::Init(), but on Mac (others?)
// it has been known to take 300-800 (or even 8500) ms to execute(!)
nsresult
@ -600,12 +662,17 @@ AudioStream::OpenCubeb(cubeb_stream_params &aParams,
}
}
cubeb_stream_register_device_changed_callback(mCubebStream,
AudioStream::DeviceChangedCallback_s);
mState = INITIALIZED;
if (!mStartTime.IsNull()) {
TimeDuration timeDelta = TimeStamp::Now() - mStartTime;
TimeDuration timeDelta = TimeStamp::Now() - mStartTime;
LOG(("AudioStream creation time %sfirst: %u ms", mIsFirst ? "" : "not ",
(uint32_t) timeDelta.ToMilliseconds()));
Telemetry::Accumulate(mIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS :
Telemetry::AUDIOSTREAM_LATER_OPEN_MS, timeDelta.ToMilliseconds());
(uint32_t) timeDelta.ToMilliseconds()));
Telemetry::Accumulate(mIsFirst ? Telemetry::AUDIOSTREAM_FIRST_OPEN_MS :
Telemetry::AUDIOSTREAM_LATER_OPEN_MS, timeDelta.ToMilliseconds());
}
return NS_OK;
@ -660,15 +727,20 @@ nsresult
AudioStream::Write(const AudioDataValue* aBuf, uint32_t aFrames, TimeStamp *aTime)
{
MonitorAutoLock mon(mMonitor);
// See if we need to start() the stream, since we must do that from this thread
CheckForStart();
if (mShouldDropFrames) {
mBuffer.ContractTo(0);
return NS_OK;
}
if (mState == ERRORED) {
return NS_ERROR_FAILURE;
}
NS_ASSERTION(mState == INITIALIZED || mState == STARTED || mState == RUNNING,
"Stream write in unexpected state.");
// See if we need to start() the stream, since we must do that from this thread
CheckForStart();
// Downmix to Stereo.
if (mChannels > 2 && mChannels <= 8) {
DownmixAudioToStereo(const_cast<AudioDataValue*> (aBuf), mChannels, aFrames);
@ -751,9 +823,21 @@ AudioStream::Available()
void
AudioStream::SetVolume(double aVolume)
{
MonitorAutoLock mon(mMonitor);
NS_ABORT_IF_FALSE(aVolume >= 0.0 && aVolume <= 1.0, "Invalid volume");
mVolume = aVolume;
if (cubeb_stream_set_volume(mCubebStream, aVolume * GetVolumeScale()) != CUBEB_OK) {
NS_WARNING("Could not change volume on cubeb stream.");
}
}
void
AudioStream::SetMicrophoneActive(bool aActive)
{
MonitorAutoLock mon(mMonitor);
mMicrophoneActive = aActive;
PanOutputIfNeeded(mMicrophoneActive);
}
void
@ -794,11 +878,14 @@ AudioStream::StartUnlocked()
mNeedsStart = true;
return;
}
if (mState == INITIALIZED) {
int r;
{
MonitorAutoUnlock mon(mMonitor);
r = cubeb_stream_start(mCubebStream);
PanOutputIfNeeded(mMicrophoneActive);
}
mState = r == CUBEB_OK ? STARTED : ERRORED;
LOG(("AudioStream: started %p, state %s", this, mState == STARTED ? "STARTED" : "ERRORED"));
@ -1037,6 +1124,59 @@ AudioStream::GetTimeStretched(void* aBuffer, long aFrames, int64_t &aTimeMs)
return processedFrames;
}
void
AudioStream::Reset()
{
mShouldDropFrames = true;
mNeedsStart = true;
cubeb_stream_params params;
params.rate = mInRate;
params.channels = mOutChannels;
#if defined(__ANDROID__)
#if defined(MOZ_B2G)
params.stream_type = ConvertChannelToCubebType(mAudioChannel);
#else
params.stream_type = CUBEB_STREAM_TYPE_MUSIC;
#endif
if (params.stream_type == CUBEB_STREAM_TYPE_MAX) {
return;
}
#endif
if (AUDIO_OUTPUT_FORMAT == AUDIO_FORMAT_S16) {
params.format = CUBEB_SAMPLE_S16NE;
} else {
params.format = CUBEB_SAMPLE_FLOAT32NE;
}
mBytesPerFrame = sizeof(AudioDataValue) * mOutChannels;
// Size mBuffer for one second of audio. This value is arbitrary, and was
// selected based on the observed behaviour of the existing AudioStream
// implementations.
uint32_t bufferLimit = FramesToBytes(mInRate);
NS_ABORT_IF_FALSE(bufferLimit % mBytesPerFrame == 0, "Must buffer complete frames");
mBuffer.Reset();
mBuffer.SetCapacity(bufferLimit);
if (mLatencyRequest == LowLatency) {
// Don't block this thread to initialize a cubeb stream.
// When this is done, it will start callbacks from Cubeb. Those will
// cause us to move from INITIALIZED to RUNNING. Until then, we
// can't access any cubeb functions.
// Use a RefPtr to avoid leaks if Dispatch fails
RefPtr<AudioInitTask> init = new AudioInitTask(this, mLatencyRequest, params);
init->Dispatch();
return;
}
// High latency - open synchronously
OpenCubeb(params, mLatencyRequest);
CheckForStart();
}
long
AudioStream::DataCallback(void* aBuffer, long aFrames)
{
@ -1049,6 +1189,8 @@ AudioStream::DataCallback(void* aBuffer, long aFrames)
uint32_t servicedFrames = 0;
int64_t insertTime;
mShouldDropFrames = false;
// NOTE: wasapi (others?) can call us back *after* stop()/Shutdown() (mState == SHUTDOWN)
// Bug 996162
@ -1099,9 +1241,6 @@ AudioStream::DataCallback(void* aBuffer, long aFrames)
} else {
servicedFrames = GetTimeStretched(output, aFrames, insertTime);
}
float scaled_volume = float(GetVolumeScale() * mVolume);
ScaleAudioSamples(output, aFrames * mOutChannels, scaled_volume);
NS_ABORT_IF_FALSE(mBuffer.Length() % mBytesPerFrame == 0, "Must copy complete frames");

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

@ -158,6 +158,14 @@ public:
return amount;
}
void Reset()
{
mBuffer = nullptr;
mCapacity = 0;
mStart = 0;
mCount = 0;
}
private:
nsAutoArrayPtr<uint8_t> mBuffer;
uint32_t mCapacity;
@ -169,8 +177,8 @@ class AudioInitTask;
// Access to a single instance of this class must be synchronized by
// callers, or made from a single thread. One exception is that access to
// GetPosition, GetPositionInFrames, SetVolume, and Get{Rate,Channels}
// is thread-safe without external synchronization.
// GetPosition, GetPositionInFrames, SetVolume, and Get{Rate,Channels},
// SetMicrophoneActive is thread-safe without external synchronization.
class AudioStream MOZ_FINAL
{
virtual ~AudioStream();
@ -212,6 +220,8 @@ public:
// Closes the stream. All future use of the stream is an error.
void Shutdown();
void Reset();
// Write audio data to the audio hardware. aBuf is an array of AudioDataValues
// AudioDataValue of length aFrames*mChannels. If aFrames is larger
// than the result of Available(), the write will block until sufficient
@ -226,6 +236,11 @@ public:
// 0 (meaning muted) to 1 (meaning full volume). Thread-safe.
void SetVolume(double aVolume);
// Informs the AudioStream that a microphone is being used by someone in the
// application.
void SetMicrophoneActive(bool aActive);
void PanOutputIfNeeded(bool aMicrophoneActive);
// Block until buffered audio data has been consumed.
void Drain();
@ -304,8 +319,14 @@ private:
static_cast<AudioStream*>(aThis)->StateCallback(aState);
}
static void DeviceChangedCallback_s(void * aThis) {
static_cast<AudioStream*>(aThis)->DeviceChangedCallback();
}
long DataCallback(void* aBuffer, long aFrames);
void StateCallback(cubeb_state aState);
void DeviceChangedCallback();
nsresult EnsureTimeStretcherInitializedUnlocked();
@ -331,6 +352,9 @@ private:
int mOutRate;
int mChannels;
int mOutChannels;
#if defined(__ANDROID__)
dom::AudioChannel mAudioChannel;
#endif
// Number of frames written to the buffers.
int64_t mWritten;
AudioClock mAudioClock;
@ -361,9 +385,6 @@ private:
// frames.
CircularByteBuffer mBuffer;
// Software volume level. Applied during the servicing of DataCallback().
double mVolume;
// Owning reference to a cubeb_stream. cubeb_stream_destroy is called by
// nsAutoRef's destructor.
nsAutoRef<cubeb_stream> mCubebStream;
@ -397,6 +418,12 @@ private:
StreamState mState;
bool mNeedsStart; // needed in case Start() is called before cubeb is open
bool mIsFirst;
// True if a microphone is active.
bool mMicrophoneActive;
// When we are in the process of changing the output device, and the callback
// is not going to be called for a little while, simply drop incoming frames.
// This is only on OSX for now, because other systems handle this gracefully.
bool mShouldDropFrames;
// This mutex protects the static members below.
static StaticMutex sMutex;

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

@ -110,6 +110,7 @@ MediaStreamGraphImpl::RemoveStream(MediaStream* aStream)
}
}
// Ensure that mFirstCycleBreaker and mMixer are updated when necessary.
SetStreamOrderDirty();
mStreams.RemoveElement(aStream);
@ -568,8 +569,18 @@ MediaStreamGraphImpl::UpdateStreamOrder()
if (!mMixer && shouldMix) {
mMixer = new AudioMixer(AudioMixerCallback);
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
for (uint32_t i = 0; i < mStreams[i]->mAudioOutputStreams.Length(); ++i) {
mStreams[i]->mAudioOutputStreams[i].mStream->SetMicrophoneActive(true);
}
}
} else if (mMixer && !shouldMix) {
mMixer = nullptr;
for (uint32_t i = 0; i < mStreams.Length(); ++i) {
for (uint32_t i = 0; i < mStreams[i]->mAudioOutputStreams.Length(); ++i) {
mStreams[i]->mAudioOutputStreams[i].mStream->SetMicrophoneActive(false);
}
}
}
// The algorithm for finding cycles is based on Tim Leslie's iterative
@ -692,17 +703,18 @@ MediaStreamGraphImpl::UpdateStreamOrder()
MOZ_ASSERT(cycleStackMarker == ps->mCycleMarker);
// If there are DelayNodes in this SCC, then they may break the cycles.
bool haveDelayNode = false;
auto next = static_cast<ProcessedMediaStream*>(sccStack.getFirst());
auto next = sccStack.getFirst();
// Streams in this SCC are identified by mCycleMarker <= cycleStackMarker.
// (There may be other streams later in sccStack from other incompletely
// searched SCCs, involving streams still on dfsStack.)
//
// DelayNodes in cycles must behave differently from those not in cycles,
// so all DelayNodes in the SCC must be identified.
while (next && next->mCycleMarker <= cycleStackMarker) {
while (next && static_cast<ProcessedMediaStream*>(next)->
mCycleMarker <= cycleStackMarker) {
auto ns = next->AsAudioNodeStream();
// Get next before perhaps removing from list below.
next = static_cast<ProcessedMediaStream*>(next->getNext());
next = next->getNext();
if (ns && ns->Engine()->AsDelayNodeEngine()) {
haveDelayNode = true;
// DelayNodes break cycles by producing their output in a
@ -716,8 +728,9 @@ MediaStreamGraphImpl::UpdateStreamOrder()
}
}
auto after_scc = next;
while ((next = static_cast<ProcessedMediaStream*>(sccStack.popFirst()))
!= after_scc) {
while ((next = sccStack.getFirst()) != after_scc) {
next->remove();
auto removed = static_cast<ProcessedMediaStream*>(next);
if (haveDelayNode) {
// Return streams to the DFS stack again (to order and detect cycles
// without delayNodes). Any of these streams that are still inputs
@ -726,14 +739,14 @@ MediaStreamGraphImpl::UpdateStreamOrder()
// of these streams need input from streams on the visited stack, so
// they can all be searched and ordered before the current stack head
// is popped.
next->mCycleMarker = NOT_VISITED;
dfsStack.insertFront(next);
removed->mCycleMarker = NOT_VISITED;
dfsStack.insertFront(removed);
} else {
// Streams in cycles without any DelayNodes must be muted, and so do
// not need input and can be ordered now. They must be ordered before
// their consumers so that their muted output is available.
next->mCycleMarker = IN_MUTED_CYCLE;
mStreams[orderedStreamCount] = next;
removed->mCycleMarker = IN_MUTED_CYCLE;
mStreams[orderedStreamCount] = removed;
++orderedStreamCount;
}
}
@ -950,6 +963,9 @@ MediaStreamGraphImpl::CreateOrDestroyAudioStreams(GraphTime aAudioOutputStartTim
AudioStream::LowLatency);
audioOutputStream->mTrackID = tracks->GetID();
// If there is a mixer, there is a micrphone active.
audioOutputStream->mStream->SetMicrophoneActive(mMixer);
LogLatency(AsyncLatencyLogger::AudioStreamCreate,
reinterpret_cast<uint64_t>(aStream),
reinterpret_cast<int64_t>(audioOutputStream->mStream.get()));
@ -2034,8 +2050,6 @@ MediaStream::RemoveAllListenersImpl()
void
MediaStream::DestroyImpl()
{
RemoveAllListenersImpl();
for (int32_t i = mConsumers.Length() - 1; i >= 0; --i) {
mConsumers[i]->Disconnect();
}
@ -2043,6 +2057,7 @@ MediaStream::DestroyImpl()
mAudioOutputStreams[i].mStream->Shutdown();
}
mAudioOutputStreams.Clear();
mGraph = nullptr;
}
void
@ -2056,8 +2071,10 @@ MediaStream::Destroy()
Message(MediaStream* aStream) : ControlMessage(aStream) {}
virtual void Run()
{
mStream->RemoveAllListenersImpl();
auto graph = mStream->GraphImpl();
mStream->DestroyImpl();
mStream->GraphImpl()->RemoveStream(mStream);
graph->RemoveStream(mStream);
}
virtual void RunDuringShutdown()
{ Run(); }
@ -2338,10 +2355,9 @@ MediaStream::ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment, Media
void
SourceMediaStream::DestroyImpl()
{
{
MutexAutoLock lock(mMutex);
mDestroyed = true;
}
// Hold mMutex while mGraph is reset so that other threads holding mMutex
// can null-check know that the graph will not destroyed.
MutexAutoLock lock(mMutex);
MediaStream::DestroyImpl();
}
@ -2350,7 +2366,7 @@ SourceMediaStream::SetPullEnabled(bool aEnabled)
{
MutexAutoLock lock(mMutex);
mPullEnabled = aEnabled;
if (mPullEnabled && !mDestroyed) {
if (mPullEnabled && GraphImpl()) {
GraphImpl()->EnsureNextIteration();
}
}
@ -2370,8 +2386,8 @@ SourceMediaStream::AddTrack(TrackID aID, TrackRate aRate, TrackTicks aStart,
data->mCommands = TRACK_CREATE;
data->mData = aSegment;
data->mHaveEnough = false;
if (!mDestroyed) {
GraphImpl()->EnsureNextIteration();
if (auto graph = GraphImpl()) {
graph->EnsureNextIteration();
}
}
@ -2413,7 +2429,8 @@ SourceMediaStream::AppendToTrack(TrackID aID, MediaSegment* aSegment, MediaSegme
MutexAutoLock lock(mMutex);
// ::EndAllTrackAndFinished() can end these before the sources notice
bool appended = false;
if (!mFinished) {
auto graph = GraphImpl();
if (!mFinished && graph) {
TrackData *track = FindDataForTrack(aID);
if (track) {
// Data goes into mData, and on the next iteration of the MSG moves
@ -2432,13 +2449,11 @@ SourceMediaStream::AppendToTrack(TrackID aID, MediaSegment* aSegment, MediaSegme
NotifyDirectConsumers(track, aRawSegment ? aRawSegment : aSegment);
track->mData->AppendFrom(aSegment); // note: aSegment is now dead
appended = true;
graph->EnsureNextIteration();
} else {
aSegment->Clear();
}
}
if (!mDestroyed) {
GraphImpl()->EnsureNextIteration();
}
return appended;
}
@ -2535,8 +2550,8 @@ SourceMediaStream::EndTrack(TrackID aID)
track->mCommands |= TRACK_END;
}
}
if (!mDestroyed) {
GraphImpl()->EnsureNextIteration();
if (auto graph = GraphImpl()) {
graph->EnsureNextIteration();
}
}
@ -2546,8 +2561,8 @@ SourceMediaStream::AdvanceKnownTracksTime(StreamTime aKnownTime)
MutexAutoLock lock(mMutex);
MOZ_ASSERT(aKnownTime >= mUpdateKnownTracksTime);
mUpdateKnownTracksTime = aKnownTime;
if (!mDestroyed) {
GraphImpl()->EnsureNextIteration();
if (auto graph = GraphImpl()) {
graph->EnsureNextIteration();
}
}
@ -2556,8 +2571,8 @@ SourceMediaStream::FinishWithLockHeld()
{
mMutex.AssertCurrentThreadOwns();
mUpdateFinished = true;
if (!mDestroyed) {
GraphImpl()->EnsureNextIteration();
if (auto graph = GraphImpl()) {
graph->EnsureNextIteration();
}
}
@ -2660,6 +2675,7 @@ MediaInputPort::Destroy()
{
mPort->Disconnect();
--mPort->GraphImpl()->mPortCount;
mPort->SetGraphImpl(nullptr);
NS_RELEASE(mPort);
}
virtual void RunDuringShutdown()
@ -2686,7 +2702,7 @@ MediaInputPort::Graph()
void
MediaInputPort::SetGraphImpl(MediaStreamGraphImpl* aGraph)
{
MOZ_ASSERT(!mGraph, "Should only be called once");
MOZ_ASSERT(!mGraph || !aGraph, "Should only be set once");
mGraph = aGraph;
}
@ -2759,7 +2775,10 @@ ProcessedMediaStream::DestroyImpl()
mInputs[i]->Disconnect();
}
MediaStream::DestroyImpl();
GraphImpl()->SetStreamOrderDirty();
// The stream order is only important if there are connections, in which
// case MediaInputPort::Disconnect() called SetStreamOrderDirty().
// MediaStreamGraphImpl::RemoveStream() will also call
// SetStreamOrderDirty(), for other reasons.
}
MediaStreamGraphImpl::MediaStreamGraphImpl(bool aRealtime, TrackRate aSampleRate)

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

@ -677,7 +677,7 @@ protected:
bool mMainThreadFinished;
bool mMainThreadDestroyed;
// Our media stream graph
// Our media stream graph. null if destroyed on the graph thread.
MediaStreamGraphImpl* mGraph;
dom::AudioChannel mAudioChannelType;
@ -697,7 +697,7 @@ public:
mMutex("mozilla::media::SourceMediaStream"),
mUpdateKnownTracksTime(0),
mPullEnabled(false),
mUpdateFinished(false), mDestroyed(false)
mUpdateFinished(false)
{}
virtual SourceMediaStream* AsSourceStream() { return this; }
@ -727,8 +727,6 @@ public:
void AddTrack(TrackID aID, TrackRate aRate, TrackTicks aStart,
MediaSegment* aSegment);
struct TrackData;
void ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSegment* aSegment);
/**
* Append media data to a track. Ownership of aSegment remains with the caller,
* but aSegment is emptied.
@ -795,10 +793,13 @@ public:
*/
TrackTicks GetBufferedTicks(TrackID aID);
void RegisterForAudioMixing();
// XXX need a Reset API
friend class MediaStreamGraphImpl;
protected:
struct ThreadAndRunnable {
void Init(nsIEventTarget* aTarget, nsIRunnable* aRunnable)
{
@ -840,10 +841,10 @@ public:
bool mHaveEnough;
};
void RegisterForAudioMixing();
bool NeedsMixing();
protected:
void ResampleAudioToGraphSampleRate(TrackData* aTrackData, MediaSegment* aSegment);
TrackData* FindDataForTrack(TrackID aID)
{
for (uint32_t i = 0; i < mUpdateTracks.Length(); ++i) {
@ -875,7 +876,6 @@ protected:
nsTArray<nsRefPtr<MediaStreamDirectListener> > mDirectListeners;
bool mPullEnabled;
bool mUpdateFinished;
bool mDestroyed;
bool mNeedsMixing;
};

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

@ -97,6 +97,10 @@ FFmpegDataDecoder<LIBAV_VER>::Init()
}
mCodecContext->extradata = mExtraData.begin();
if (codec->capabilities & CODEC_CAP_DR1) {
mCodecContext->flags |= CODEC_FLAG_EMU_EDGE;
}
if (avcodec_open2(mCodecContext, codec, nullptr) < 0) {
NS_WARNING("Couldn't initialise ffmpeg decoder");
return NS_ERROR_FAILURE;

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

@ -78,20 +78,45 @@ FFmpegH264Decoder<LIBAV_VER>::DecodeFrame(mp4_demuxer::MP4Sample* aSample)
// If we've decoded a frame then we need to output it
if (decoded) {
nsAutoPtr<VideoData> data;
VideoInfo info;
info.mDisplay = nsIntSize(mCodecContext->width, mCodecContext->height);
info.mStereoMode = StereoMode::MONO;
info.mHasVideo = true;
data = VideoData::CreateFromImage(
info, mImageContainer, aSample->byte_offset, mFrame->pkt_pts,
aSample->duration, static_cast<Image*>(mFrame->opaque),
aSample->is_sync_point, -1,
gfx::IntRect(0, 0, mCodecContext->width, mCodecContext->height));
VideoData::YCbCrBuffer b;
b.mPlanes[0].mData = mFrame->data[0];
b.mPlanes[0].mStride = mFrame->linesize[0];
b.mPlanes[0].mHeight = mFrame->height;
b.mPlanes[0].mWidth = mFrame->width;
b.mPlanes[0].mOffset = b.mPlanes[0].mSkip = 0;
mCallback->Output(data.forget());
b.mPlanes[1].mData = mFrame->data[1];
b.mPlanes[1].mStride = mFrame->linesize[1];
b.mPlanes[1].mHeight = (mFrame->height + 1) >> 1;
b.mPlanes[1].mWidth = (mFrame->width + 1) >> 1;
b.mPlanes[1].mOffset = b.mPlanes[1].mSkip = 0;
b.mPlanes[2].mData = mFrame->data[2];
b.mPlanes[2].mStride = mFrame->linesize[2];
b.mPlanes[2].mHeight = (mFrame->height + 1) >> 1;
b.mPlanes[2].mWidth = (mFrame->width + 1) >> 1;
b.mPlanes[2].mOffset = b.mPlanes[2].mSkip = 0;
VideoData *v = VideoData::Create(info,
mImageContainer,
aSample->byte_offset,
mFrame->pkt_pts,
aSample->duration,
b,
aSample->is_sync_point,
-1,
gfx::IntRect(0, 0, mCodecContext->width, mCodecContext->height));
if (!v) {
NS_WARNING("image allocation error.");
mCallback->Error();
return;
}
mCallback->Output(v);
}
if (mTaskQueue->IsEmpty()) {
@ -99,27 +124,6 @@ FFmpegH264Decoder<LIBAV_VER>::DecodeFrame(mp4_demuxer::MP4Sample* aSample)
}
}
static void
PlanarYCbCrDataFromAVFrame(mozilla::layers::PlanarYCbCrData& aData,
AVFrame* aFrame)
{
aData.mPicX = aData.mPicY = 0;
aData.mPicSize = mozilla::gfx::IntSize(aFrame->width, aFrame->height);
aData.mStereoMode = StereoMode::MONO;
aData.mYChannel = aFrame->data[0];
aData.mYStride = aFrame->linesize[0];
aData.mYSize = aData.mPicSize;
aData.mYSkip = 0;
aData.mCbChannel = aFrame->data[1];
aData.mCrChannel = aFrame->data[2];
aData.mCbCrStride = aFrame->linesize[1];
aData.mCbSkip = aData.mCrSkip = 0;
aData.mCbCrSize =
mozilla::gfx::IntSize((aFrame->width + 1) / 2, (aFrame->height + 1) / 2);
}
/* static */ int
FFmpegH264Decoder<LIBAV_VER>::AllocateBufferCb(AVCodecContext* aCodecContext,
AVFrame* aFrame)
@ -159,16 +163,17 @@ int
FFmpegH264Decoder<LIBAV_VER>::AllocateYUV420PVideoBuffer(
AVCodecContext* aCodecContext, AVFrame* aFrame)
{
// Older versions of ffmpeg require that edges be allocated* around* the
// actual image.
int edgeWidth = avcodec_get_edge_width();
bool needAlign = aCodecContext->codec->capabilities & CODEC_CAP_DR1;
int edgeWidth = needAlign ? avcodec_get_edge_width() : 0;
int decodeWidth = aCodecContext->width + edgeWidth * 2;
int decodeHeight = aCodecContext->height + edgeWidth * 2;
// Align width and height to possibly speed up decode.
int stride_align[AV_NUM_DATA_POINTERS];
avcodec_align_dimensions2(aCodecContext, &decodeWidth, &decodeHeight,
stride_align);
if (needAlign) {
// Align width and height to account for CODEC_FLAG_EMU_EDGE.
int stride_align[AV_NUM_DATA_POINTERS];
avcodec_align_dimensions2(aCodecContext, &decodeWidth, &decodeHeight,
stride_align);
}
// Get strides for each plane.
av_image_fill_linesizes(aFrame->linesize, aCodecContext->pix_fmt,
@ -215,10 +220,6 @@ FFmpegH264Decoder<LIBAV_VER>::AllocateYUV420PVideoBuffer(
aFrame->width = aCodecContext->width;
aFrame->height = aCodecContext->height;
mozilla::layers::PlanarYCbCrData data;
PlanarYCbCrDataFromAVFrame(data, aFrame);
ycbcr->SetDataNoCopy(data);
aFrame->opaque = static_cast<void*>(image.forget().take());
return 0;

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

@ -231,6 +231,12 @@ private:
return mDecoders[mActiveVideoDecoder]->GetReader();
}
void SetMediaSourceDuration(double aDuration) {
MOZ_ASSERT(NS_IsMainThread());
ErrorResult dummy;
mMediaSource->SetDuration(aDuration, dummy);
}
nsTArray<nsRefPtr<SubBufferDecoder>> mPendingDecoders;
nsTArray<nsRefPtr<SubBufferDecoder>> mDecoders;
@ -585,8 +591,9 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
if (maxDuration != -1) {
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
mDecoder->SetMediaDuration(maxDuration);
ErrorResult dummy;
mMediaSource->SetDuration(maxDuration, dummy);
nsRefPtr<nsIRunnable> task (
NS_NewRunnableMethodWithArg<double>(this, &MediaSourceReader::SetMediaSourceDuration, maxDuration));
NS_DispatchToMainThread(task);
}
*aInfo = mInfo;

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

@ -9,6 +9,7 @@ DIRS += [
'gmp',
'mediasource',
'ogg',
'systemservices',
'webaudio',
'webvtt'
]

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

@ -0,0 +1,45 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "OSXRunLoopSingleton.h"
#include <mozilla/StaticMutex.h>
#include <mozilla/NullPtr.h>
#include <AudioUnit/AudioUnit.h>
#include <CoreAudio/AudioHardware.h>
#include <CoreAudio/HostTime.h>
#include <CoreFoundation/CoreFoundation.h>
static bool gRunLoopSet = false;
static mozilla::StaticMutex gMutex;
void mozilla_set_coreaudio_notification_runloop_if_needed()
{
mozilla::StaticMutexAutoLock lock(gMutex);
if (gRunLoopSet) {
return;
}
/* This is needed so that AudioUnit listeners get called on this thread, and
* not the main thread. If we don't do that, they are not called, or a crash
* occur, depending on the OSX version. */
AudioObjectPropertyAddress runloop_address = {
kAudioHardwarePropertyRunLoop,
kAudioObjectPropertyScopeGlobal,
kAudioObjectPropertyElementMaster
};
CFRunLoopRef run_loop = nullptr;
OSStatus r;
r = AudioObjectSetPropertyData(kAudioObjectSystemObject,
&runloop_address,
0, NULL, sizeof(CFRunLoopRef), &run_loop);
if (r != noErr) {
NS_WARNING("Could not make global CoreAudio notifications use their own thread.");
}
gRunLoopSet = true;
}

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

@ -0,0 +1,25 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef OSXRUNLOOPSINGLETON_H_
#define OSXRUNLOOPSINGLETON_H_
#include <mozilla/Types.h>
#if defined(__cplusplus)
extern "C" {
#endif
/* This function tells CoreAudio to use its own thread for device change
* notifications, and can be called from any thread without external
* synchronization. */
void MOZ_EXPORT
mozilla_set_coreaudio_notification_runloop_if_needed();
#if defined(__cplusplus)
}
#endif
#endif // OSXRUNLOOPSINGLETON_H_

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

@ -0,0 +1,199 @@
/* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "OpenSLESProvider.h"
#include "prlog.h"
#include "nsDebug.h"
#include "mozilla/NullPtr.h"
#include <dlfcn.h>
#include <SLES/OpenSLES_Android.h>
#include <SLES/OpenSLES_AndroidConfiguration.h>
// NSPR_LOG_MODULES=OpenSLESProvider:5
#undef LOG
#undef LOG_ENABLED
#if defined(PR_LOGGING)
PRLogModuleInfo *gOpenSLESProviderLog;
#define LOG(args) PR_LOG(gOpenSLESProviderLog, PR_LOG_DEBUG, args)
#define LOG_ENABLED() PR_LOG_TEST(gLoadManagerLog, 5)
#else
#define LOG(args)
#define LOG_ENABLED() (false)
#endif
namespace mozilla {
OpenSLESProvider::OpenSLESProvider()
: mLock("OpenSLESProvider.mLock"),
mSLEngine(nullptr),
mSLEngineUsers(0),
mIsRealized(false),
mOpenSLESLib(nullptr)
{
#if defined(PR_LOGGING)
if (!gOpenSLESProviderLog)
gOpenSLESProviderLog = PR_NewLogModule("OpenSLESProvider");
LOG(("OpenSLESProvider being initialized"));
#endif
}
OpenSLESProvider::~OpenSLESProvider()
{
if (mOpenSLESLib) {
LOG(("OpenSLES Engine was not properly Destroyed"));
(void)dlclose(mOpenSLESLib);
}
}
/* static */
OpenSLESProvider& OpenSLESProvider::getInstance()
{
// This doesn't need a Mutex in C++11 or GCC 4.3+, see N2660 and
// https://gcc.gnu.org/projects/cxx0x.html
static OpenSLESProvider instance;
return instance;
}
/* static */
SLresult OpenSLESProvider::Get(SLObjectItf * aObjectm,
SLuint32 aOptionCount,
const SLEngineOption *aOptions)
{
OpenSLESProvider& provider = OpenSLESProvider::getInstance();
return provider.GetEngine(aObjectm, aOptionCount, aOptions);
}
SLresult OpenSLESProvider::GetEngine(SLObjectItf * aObjectm,
SLuint32 aOptionCount,
const SLEngineOption *aOptions)
{
MutexAutoLock lock(mLock);
LOG(("Getting OpenSLES engine"));
// Bug 1042051: Validate options are the same
if (mSLEngine != nullptr) {
*aObjectm = mSLEngine;
mSLEngineUsers++;
LOG(("Returning existing engine, %d users", mSLEngineUsers));
return SL_RESULT_SUCCESS;
} else {
int res = ConstructEngine(aObjectm, aOptionCount, aOptions);
if (res == SL_RESULT_SUCCESS) {
// Bug 1042051: Store engine options
mSLEngine = *aObjectm;
mSLEngineUsers++;
LOG(("Returning new engine"));
} else {
LOG(("Error getting engine: %d", res));
}
return res;
}
}
SLresult OpenSLESProvider::ConstructEngine(SLObjectItf * aObjectm,
SLuint32 aOptionCount,
const SLEngineOption *aOptions)
{
mLock.AssertCurrentThreadOwns();
if (!mOpenSLESLib) {
mOpenSLESLib = dlopen("libOpenSLES.so", RTLD_LAZY);
if (!mOpenSLESLib) {
LOG(("Failed to dlopen OpenSLES library"));
return SL_RESULT_MEMORY_FAILURE;
}
}
typedef SLresult (*slCreateEngine_t)(SLObjectItf *,
SLuint32,
const SLEngineOption *,
SLuint32,
const SLInterfaceID *,
const SLboolean *);
slCreateEngine_t f_slCreateEngine =
(slCreateEngine_t)dlsym(mOpenSLESLib, "slCreateEngine");
int result = f_slCreateEngine(aObjectm, aOptionCount, aOptions, 0, NULL, NULL);
return result;
}
/* static */
void OpenSLESProvider::Destroy(SLObjectItf * aObjectm)
{
OpenSLESProvider& provider = OpenSLESProvider::getInstance();
provider.DestroyEngine(aObjectm);
}
void OpenSLESProvider::DestroyEngine(SLObjectItf * aObjectm)
{
MutexAutoLock lock(mLock);
NS_ASSERTION(mOpenSLESLib, "OpenSLES destroy called but library is not open");
mSLEngineUsers--;
LOG(("Freeing engine, %d users left", mSLEngineUsers));
if (mSLEngineUsers) {
return;
}
(*(*aObjectm))->Destroy(*aObjectm);
// This assumes SLObjectItf is a pointer, but given the previous line,
// that's a given.
*aObjectm = nullptr;
(void)dlclose(mOpenSLESLib);
mOpenSLESLib = nullptr;
mIsRealized = false;
}
/* static */
SLresult OpenSLESProvider::Realize(SLObjectItf aObjectm)
{
OpenSLESProvider& provider = OpenSLESProvider::getInstance();
return provider.RealizeEngine(aObjectm);
}
SLresult OpenSLESProvider::RealizeEngine(SLObjectItf aObjectm)
{
MutexAutoLock lock(mLock);
NS_ASSERTION(mOpenSLESLib, "OpenSLES realize called but library is not open");
NS_ASSERTION(aObjectm != nullptr, "OpenSLES realize engine with empty ObjectItf");
if (mIsRealized) {
LOG(("Not realizing already realized engine"));
return SL_RESULT_SUCCESS;
} else {
SLresult res = (*aObjectm)->Realize(aObjectm, SL_BOOLEAN_FALSE);
if (res != SL_RESULT_SUCCESS) {
LOG(("Error realizing OpenSLES engine: %d", res));
} else {
LOG(("Realized OpenSLES engine"));
mIsRealized = true;
}
return res;
}
}
} // namespace mozilla
extern "C" {
SLresult mozilla_get_sles_engine(SLObjectItf * aObjectm,
SLuint32 aOptionCount,
const SLEngineOption *aOptions)
{
return mozilla::OpenSLESProvider::Get(aObjectm, aOptionCount, aOptions);
}
void mozilla_destroy_sles_engine(SLObjectItf * aObjectm)
{
mozilla::OpenSLESProvider::Destroy(aObjectm);
}
SLresult mozilla_realize_sles_engine(SLObjectItf aObjectm)
{
return mozilla::OpenSLESProvider::Realize(aObjectm);
}
}

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

@ -0,0 +1,68 @@
/* -*- Mode: C++; tab-width: 50; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* 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 _OPENSLESPROVIDER_H_
#define _OPENSLESPROVIDER_H_
#include <SLES/OpenSLES.h>
#include <mozilla/Types.h>
#ifdef __cplusplus
extern "C" {
#endif
extern MOZ_EXPORT
SLresult mozilla_get_sles_engine(SLObjectItf * aObjectm,
SLuint32 aOptionCount,
const SLEngineOption *aOptions);
extern MOZ_EXPORT
void mozilla_destroy_sles_engine(SLObjectItf * aObjectm);
/* Realize is always in synchronous mode. */
extern MOZ_EXPORT
SLresult mozilla_realize_sles_engine(SLObjectItf aObjectm);
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
#include "mozilla/Mutex.h"
extern PRLogModuleInfo *gOpenSLESProviderLog;
namespace mozilla {
class OpenSLESProvider {
public:
static SLresult Get(SLObjectItf * aObjectm,
SLuint32 aOptionCount,
const SLEngineOption *aOptions);
static void Destroy(SLObjectItf * aObjectm);
static SLresult Realize(SLObjectItf aObjectm);
private:
OpenSLESProvider();
~OpenSLESProvider();
OpenSLESProvider(OpenSLESProvider const&); // NO IMPLEMENTATION
void operator=(OpenSLESProvider const&); // NO IMPLEMENTATION
static OpenSLESProvider& getInstance();
SLresult GetEngine(SLObjectItf * aObjectm,
SLuint32 aOptionCount,
const SLEngineOption *aOptions);
SLresult ConstructEngine(SLObjectItf * aObjectm,
SLuint32 aOptionCount,
const SLEngineOption *aOptions);
SLresult RealizeEngine(SLObjectItf aObjectm);
void DestroyEngine(SLObjectItf * aObjectm);
// Protect all our internal variables
mozilla::Mutex mLock;
SLObjectItf mSLEngine;
int mSLEngineUsers;
bool mIsRealized;
void *mOpenSLESLib;
};
} //namespace
#endif // cplusplus
#endif /* _OPENSLESPROVIDER_H_ */

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

@ -0,0 +1,42 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
if CONFIG['MOZ_WEBRTC']:
EXPORTS += ['LoadManager.h',
'LoadManagerFactory.h',
'LoadMonitor.h',
]
UNIFIED_SOURCES += ['LoadManager.cpp',
'LoadManagerFactory.cpp',
'LoadMonitor.cpp',
]
LOCAL_INCLUDES += [
'/media/webrtc/trunk',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gonk'):
EXPORTS += [
'OpenSLESProvider.h'
]
UNIFIED_SOURCES += [
'OpenSLESProvider.cpp',
]
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
UNIFIED_SOURCES += ['OSXRunLoopSingleton.cpp']
EXPORTS += ['OSXRunLoopSingleton.h']
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
CXXFLAGS += [
'-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [
'frameworks/wilhelm/include',
'system/media/wilhelm/include',
]
]
include('/ipc/chromium/chromium-config.mozbuild')
FINAL_LIBRARY = 'xul'

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

@ -8,7 +8,7 @@ var gSmallTests = [
{ name:"small-shot.ogg", type:"audio/ogg", duration:0.276 },
{ name:"small-shot.m4a", type:"audio/mp4", duration:0.29 },
{ name:"small-shot.mp3", type:"audio/mpeg", duration:0.27 },
{ name:"small-shot-mp3.mp4", type:"audio/mp4; codecs=mp3", duration:0.34 },
// { name:"small-shot-mp3.mp4", type:"audio/mp4; codecs=mp3", duration:0.34 },
{ name:"r11025_s16_c1.wav", type:"audio/x-wav", duration:1.0 },
{ name:"320x240.ogv", type:"video/ogg", width:320, height:240, duration:0.266 },
{ name:"seek.webm", type:"video/webm", width:320, height:240, duration:3.966 },

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

@ -96,9 +96,10 @@ AudioContext::AudioContext(nsPIDOMWindow* aWindow,
// bound to the window.
mDestination = new AudioDestinationNode(this, aIsOffline, aChannel,
aNumberOfChannels, aLength, aSampleRate);
// We skip calling SetIsOnlyNodeForContext during mDestination's constructor,
// because we can only call SetIsOnlyNodeForContext after mDestination has
// been set up.
// We skip calling SetIsOnlyNodeForContext and the creation of the
// audioChannelAgent during mDestination's constructor, because we can only
// call them after mDestination has been set up.
mDestination->CreateAudioChannelAgent();
mDestination->SetIsOnlyNodeForContext(true);
}

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