Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-08-26 15:55:57 -04:00
commit 63ce3d4152
357 changed files with 7089 additions and 3034 deletions

View File

@ -1013,3 +1013,6 @@ pref("services.mobileid.server.uri", "https://msisdn.services.mozilla.com");
#ifndef XP_WIN
pref("dom.mapped_arraybuffer.enabled", true);
#endif
// UDPSocket API
pref("dom.udpsocket.enabled", true);

View File

@ -48,7 +48,6 @@ fi
MOZ_MEDIA_NAVIGATOR=1
MOZ_APP_ID={3c2e2abc-06d4-11e1-ac3b-374f68613e61}
MOZ_EXTENSION_MANAGER=1
MOZ_TIME_MANAGER=1

View File

@ -0,0 +1,61 @@
%if 0
/* 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/. */
%endif
@import url("chrome://global/skin/in-content/common.css");
body {
display: flex;
box-sizing: padding-box;
min-height: 100vh;
padding: 0 48px;
align-items: center;
justify-content: center;
}
body.normal .showPrivate,
body.private .showNormal {
display: none;
}
#pageContainer {
min-width: 320px;
max-width: 512px;
}
.titleText {
background: url("chrome://browser/skin/mask.png") left 0 no-repeat;
background-size: 45px;
-moz-margin-start: -2em;
-moz-padding-start: 2em;
}
.titleText:-moz-dir(rtl) {
background-position: right 0;
}
@media (min-resolution: 2dppx) {
.titleText {
background-image: url("chrome://browser/skin/mask@2x.png");
}
}
@media (max-width: 675px) {
.titleText {
padding-top: 0;
background-image: none;
-moz-margin-start: 0;
-moz-padding-start: 0;
}
}
a {
font-size: 1rem;
}
button {
margin-top: 1.2em;
-moz-margin-start: 0;
}

View File

@ -13,32 +13,24 @@
%brandDTD;
<!ENTITY % browserDTD SYSTEM "chrome://browser/locale/browser.dtd">
%browserDTD;
<!ENTITY % privatebrowsingpageDTD SYSTEM "chrome://browser/locale/aboutPrivateBrowsing.dtd">
%privatebrowsingpageDTD;
<!ENTITY % aboutPrivateBrowsingDTD SYSTEM "chrome://browser/locale/aboutPrivateBrowsing.dtd">
%aboutPrivateBrowsingDTD;
]>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<link rel="stylesheet" href="chrome://global/skin/netError.css" type="text/css" media="all"/>
<link rel="stylesheet" href="chrome://browser/skin/aboutPrivateBrowsing.css" type="text/css" media="all"/>
<style type="text/css"><![CDATA[
body.normal .showPrivate,
body.private .showNormal {
display: none;
}
]]></style>
<link rel="stylesheet" href="chrome://browser/content/aboutPrivateBrowsing.css" type="text/css" media="all"/>
<script type="application/javascript;version=1.7"><![CDATA[
const Cc = Components.classes;
const Ci = Components.interfaces;
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
Cu.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
if (!PrivateBrowsingUtils.isWindowPrivate(window)) {
document.title = "]]>&privatebrowsingpage.title.normal;<![CDATA[";
document.title = "]]>&aboutPrivateBrowsing.title.normal;<![CDATA[";
setFavIcon("chrome://global/skin/icons/question-16.png");
} else {
#ifndef XP_MACOSX
document.title = "]]>&privatebrowsingpage.title;<![CDATA[";
document.title = "]]>&aboutPrivateBrowsing.title;<![CDATA[";
#endif
setFavIcon("chrome://browser/skin/Privacy-16.png");
}
@ -65,12 +57,13 @@
}
// Set up the help link
let moreInfoURL = Cc["@mozilla.org/toolkit/URLFormatterService;1"].
getService(Ci.nsIURLFormatter).
formatURLPref("app.support.baseURL");
let moreInfoLink = document.getElementById("moreInfoLink");
if (moreInfoLink)
moreInfoLink.setAttribute("href", moreInfoURL + "private-browsing");
let learnMoreURL = Cc["@mozilla.org/toolkit/URLFormatterService;1"]
.getService(Ci.nsIURLFormatter)
.formatURLPref("app.support.baseURL");
let learnMore = document.getElementById("learnMore");
if (learnMore) {
learnMore.setAttribute("href", learnMoreURL + "private-browsing");
}
}, false);
function openPrivateWindow() {
@ -79,57 +72,27 @@
]]></script>
</head>
<body dir="&locale.dir;"
class="private">
<body dir="&locale.dir;" class="private">
<div id="pageContainer">
<h1 class="titleText showPrivate">&aboutPrivateBrowsing.title;</h1>
<h1 class="titleText showNormal">&aboutPrivateBrowsing.title.normal;</h1>
<!-- PAGE CONTAINER (for styling purposes only) -->
<div id="errorPageContainer">
<p class="showPrivate">&aboutPrivateBrowsing.subtitle;</p>
<p class="showNormal">&aboutPrivateBrowsing.subtitle.normal;</p>
<!-- Error Title -->
<div id="errorTitle">
<h1 id="errorTitleText" class="showPrivate">&privatebrowsingpage.title;</h1>
<h1 id="errorTitleTextNormal" class="showNormal">&privatebrowsingpage.title.normal;</h1>
</div>
<p>&aboutPrivateBrowsing.description;</p>
<!-- LONG CONTENT (the section most likely to require scrolling) -->
<div id="errorLongContent">
<p class="showNormal">&aboutPrivateBrowsing.notPrivate;</p>
<!-- Short Description -->
<div id="errorShortDesc">
<p id="errorShortDescText" class="showPrivate">&privatebrowsingpage.perwindow.issueDesc;</p>
<p id="errorShortDescTextNormal" class="showNormal">&privatebrowsingpage.perwindow.issueDesc.normal;</p>
</div>
<!-- Long Description -->
<div id="errorLongDesc">
<p id="errorLongDescText">&privatebrowsingpage.perwindow.description;</p>
</div>
<!-- Start Private Browsing -->
<div id="startPrivateBrowsingDesc" class="showNormal">
<button xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
id="startPrivateBrowsing" label="&privatebrowsingpage.openPrivateWindow.label;"
accesskey="&privatebrowsingpage.openPrivateWindow.accesskey;"
oncommand="openPrivateWindow();"/>
</div>
<!-- Footer -->
<div id="footerDesc">
<p id="footerText" class="showPrivate">&privatebrowsingpage.howToStop3;</p>
<p id="footerTextNormal" class="showNormal">&privatebrowsingpage.howToStart4;</p>
</div>
<!-- More Info -->
<div id="moreInfo" class="showPrivate">
<p id="moreInfoText">
&privatebrowsingpage.moreInfo;
</p>
<p id="moreInfoLinkContainer">
<a id="moreInfoLink" target="_blank">&privatebrowsingpage.learnMore;</a>
</p>
</div>
<button xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
class="showNormal"
label="&privatebrowsingpage.openPrivateWindow.label;"
accesskey="&privatebrowsingpage.openPrivateWindow.accesskey;"
oncommand="openPrivateWindow();"/>
<div class="showPrivate">
<p>&aboutPrivateBrowsing.moreInfo;</p>
<p><a id="learnMore" target="_blank">&aboutPrivateBrowsing.learnMore;</a></p>
</div>
</div>
</body>
</html>

View File

@ -3,4 +3,5 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
browser.jar:
* content/browser/aboutPrivateBrowsing.css (content/aboutPrivateBrowsing.css)
* content/browser/aboutPrivateBrowsing.xhtml (content/aboutPrivateBrowsing.xhtml)

View File

@ -24,7 +24,7 @@ function test() {
if (isOSX) {
page_with_title = test_title;
page_without_title = app_name;
about_pb_title = "Would you like to start Private Browsing?";
about_pb_title = "Open a private window?";
pb_page_with_title = test_title + " - (Private Browsing)";
pb_page_without_title = app_name + " - (Private Browsing)";
pb_about_pb_title = pb_page_without_title;
@ -32,10 +32,10 @@ function test() {
else {
page_with_title = test_title + " - " + app_name;
page_without_title = app_name;
about_pb_title = "Would you like to start Private Browsing?" + " - " + app_name;
about_pb_title = "Open a private window?" + " - " + app_name;
pb_page_with_title = test_title + " - " + app_name + " (Private Browsing)";
pb_page_without_title = app_name + " (Private Browsing)";
pb_about_pb_title = "Private Browsing - " + app_name + " (Private Browsing)";
pb_about_pb_title = "You're browsing privately - " + app_name + " (Private Browsing)";
}
function testTabTitle(aWindow, url, insidePB, expected_title, funcNext) {

View File

@ -27,18 +27,12 @@ MozSelfSupportInterface.prototype = {
classDescription: "MozSelfSupport",
classID: Components.ID("{d30aae8b-f352-4de3-b936-bb9d875df0bb}"),
contractID: "@mozilla.org/mozselfsupport;1",
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer,
Ci.nsIObserver]),
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGlobalPropertyInitializer]),
_window: null,
init: function (window) {
this._window = window;
// FIXME: Remove this hack after static attributes work for JS-implemented
// WebIDL (see bug 863952). For a detailed description of how this works,
// see the comment accompanying the init function of amInstallTrigger.js.
return window.MozSelfSupportImpl._create(this._window, this);
},
get healthReportDataSubmissionEnabled() {

View File

@ -1,4 +1,2 @@
component {d30aae8b-f352-4de3-b936-bb9d875df0bb} SelfSupportService.js
contract @mozilla.org/mozselfsupport;1 {d30aae8b-f352-4de3-b936-bb9d875df0bb}
category JavaScript-global-privileged-property MozSelfSupport @mozilla.org/mozselfsupport;1

View File

@ -51,7 +51,6 @@ ACCEPTED_MAR_CHANNEL_IDS=firefox-mozilla-central
# The MAR_CHANNEL_ID must not contain the following 3 characters: ",\t "
MAR_CHANNEL_ID=firefox-mozilla-central
MOZ_PROFILE_MIGRATOR=1
MOZ_EXTENSION_MANAGER=1
MOZ_APP_STATIC_INI=1
MOZ_WEBAPP_RUNTIME=1
MOZ_MEDIA_NAVIGATOR=1

View File

@ -2,25 +2,22 @@
- 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/. -->
<!ENTITY privatebrowsingpage.title "Private Browsing">
<!ENTITY privatebrowsingpage.title.normal "Would you like to start Private Browsing?">
<!ENTITY aboutPrivateBrowsing.title "You're browsing privately">
<!ENTITY aboutPrivateBrowsing.title.normal "Open a private window?">
<!ENTITY privatebrowsingpage.perwindow.issueDesc "&brandShortName; won't remember any history for this window.">
<!ENTITY privatebrowsingpage.perwindow.issueDesc.normal "You are not currently in a private window.">
<!ENTITY aboutPrivateBrowsing.subtitle "&brandShortName; won't remember any history for this window.">
<!ENTITY aboutPrivateBrowsing.subtitle.normal "&brandShortName; won't remember any history for private windows.">
<!ENTITY privatebrowsingpage.perwindow.description "In a Private Browsing window, &brandShortName; won't keep any browser history, search history, download history, web form history, cookies, or temporary internet files. However, files you download and bookmarks you make will be kept.">
<!ENTITY aboutPrivateBrowsing.description "That includes browsing history, search history, download history, web form history, cookies, and temporary internet files. However, files you download and bookmarks you make will be kept.">
<!ENTITY aboutPrivateBrowsing.notPrivate "You are currently not in a private window.">
<!ENTITY aboutPrivateBrowsing.moreInfo "While this computer won't have a record of your browsing history, your employer or internet service provider can still track the pages you visit.">
<!ENTITY aboutPrivateBrowsing.learnMore "Learn More.">
<!ENTITY privatebrowsingpage.openPrivateWindow.label "Open a Private Window">
<!ENTITY privatebrowsingpage.openPrivateWindow.accesskey "P">
<!-- LOCALIZATION NOTE (privatebrowsingpage.howToStart4): please leave &newPrivateWindow.label; intact in the translation -->
<!ENTITY privatebrowsingpage.howToStart4 "To start Private Browsing, you can also select &newPrivateWindow.label; from the menu.">
<!ENTITY privatebrowsingpage.howToStop3 "To stop Private Browsing, you can close this window.">
<!ENTITY privatebrowsingpage.moreInfo "While this computer won't have a record of your browsing history, your internet service provider or employer can still track the pages you visit.">
<!ENTITY privatebrowsingpage.learnMore "Learn More">
<!-- TO BE REMOVED POST-AUSTRALIS -->
<!-- LOCALIZATION NOTE (privatebrowsingpage.howToStart3): please leave &basePBMenu.label; intact in the translation -->
<!ENTITY privatebrowsingpage.howToStart3 "To start Private Browsing, you can also select &basePBMenu.label; &gt; &newPrivateWindow.label;.">

View File

@ -12,7 +12,6 @@ MinVersion=@GRE_MILESTONE@
MaxVersion=@GRE_MILESTONE@
[XRE]
EnableExtensionManager=0
EnableProfileMigrator=0
[Crash Reporter]

View File

@ -1,47 +0,0 @@
%if 0
/* 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/. */
%endif
body.private > #errorPageContainer {
background-image: url("chrome://browser/skin/Privacy-48.png");
}
body.normal > #errorPageContainer {
background-image: url("moz-icon://stock/gtk-dialog-question?size=dialog");
}
#clearRecentHistoryDesc {
margin-top: 2em;
}
#clearRecentHistoryDesc > p {
font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
}
#startPrivateBrowsingDesc > button {
-moz-margin-start: 0;
}
#footerDesc > p {
font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
}
#moreInfo {
font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
-moz-padding-start: 25px;
background: url("moz-icon://stock/gtk-dialog-info?size=menu") no-repeat top left;
}
#moreInfo:-moz-dir(rtl) {
background-position: top right;
}
#moreInfoText {
margin-bottom: 0;
}
#moreInfoLinkContainer {
margin-top: 0.5em;
}

View File

@ -6,7 +6,6 @@ browser.jar:
% skin browser classic/1.0 %skin/classic/browser/
% override chrome://global/skin/icons/warning-16.png moz-icon://stock/gtk-dialog-warning?size=menu
skin/classic/browser/sanitizeDialog.css
* skin/classic/browser/aboutPrivateBrowsing.css
* skin/classic/browser/aboutSessionRestore.css
skin/classic/browser/aboutSessionRestore-window-icon.png
skin/classic/browser/aboutWelcomeBack.css (../shared/aboutWelcomeBack.css)
@ -35,6 +34,8 @@ browser.jar:
skin/classic/browser/identity-icons-https-mixed-active.png
skin/classic/browser/identity-icons-https-mixed-display.png
skin/classic/browser/Info.png
skin/classic/browser/mask.png (../shared/mask.png)
skin/classic/browser/mask@2x.png (../shared/mask@2x.png)
skin/classic/browser/menuPanel.png
skin/classic/browser/menuPanel-customize.png
skin/classic/browser/menuPanel-exit.png
@ -55,7 +56,6 @@ browser.jar:
skin/classic/browser/pointerLock-16.png
skin/classic/browser/pointerLock-64.png
skin/classic/browser/Privacy-16.png
skin/classic/browser/Privacy-48.png
skin/classic/browser/privatebrowsing-mask.png
skin/classic/browser/reload-stop-go.png
skin/classic/browser/searchbar.css

View File

@ -74,18 +74,6 @@ label.small {
-moz-box-flex: 1;
}
/* Privacy Pane */
/* styles for the link elements copied from .text-link in global.css */
.inline-link {
color: -moz-nativehyperlinktext;
text-decoration: none;
}
.inline-link:hover {
text-decoration: underline;
}
/* Modeless Window Dialogs */
.windowDialog,
.windowDialog prefpane {

View File

@ -1,47 +0,0 @@
%if 0
/* 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/. */
%endif
body.private > #errorPageContainer {
background-image: url("chrome://browser/skin/Privacy-48.png");
}
body.normal > #errorPageContainer {
background-image: url("chrome://global/skin/icons/question-64.png");
}
#clearRecentHistoryDesc {
margin-top: 2em;
}
#clearRecentHistoryDesc > p {
font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
}
#startPrivateBrowsingDesc > button {
-moz-margin-start: 0;
}
#footerDesc > p {
font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
}
#moreInfo {
font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
-moz-padding-start: 25px;
background: url("chrome://global/skin/icons/information-16.png") no-repeat top left;
}
#moreInfo:-moz-dir(rtl) {
background-position: top right;
}
#moreInfoText {
margin-bottom: 0;
}
#moreInfoLinkContainer {
margin-top: 0.5em;
}

View File

@ -5,7 +5,6 @@
browser.jar:
% skin browser classic/1.0 %skin/classic/browser/
skin/classic/browser/sanitizeDialog.css (sanitizeDialog.css)
* skin/classic/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css)
* skin/classic/browser/aboutSessionRestore.css (aboutSessionRestore.css)
skin/classic/browser/aboutSessionRestore-window-icon.png
skin/classic/browser/aboutWelcomeBack.css (../shared/aboutWelcomeBack.css)
@ -53,6 +52,8 @@ browser.jar:
skin/classic/browser/notification-16@2x.png
skin/classic/browser/notification-64.png
skin/classic/browser/notification-64@2x.png
skin/classic/browser/mask.png (../shared/mask.png)
skin/classic/browser/mask@2x.png (../shared/mask@2x.png)
skin/classic/browser/menuPanel.png
skin/classic/browser/menuPanel@2x.png
skin/classic/browser/menuPanel-customize.png
@ -86,7 +87,6 @@ browser.jar:
skin/classic/browser/pointerLock-64.png
skin/classic/browser/pointerLock-64@2x.png
skin/classic/browser/Privacy-16.png
skin/classic/browser/Privacy-48.png
skin/classic/browser/privatebrowsing-mask.png
skin/classic/browser/privatebrowsing-mask@2x.png
skin/classic/browser/privatebrowsing-mask-short.png

View File

@ -173,24 +173,6 @@ caption {
font-weight: bold;
}
/**
* Privacy Pane
*/
html|a.inline-link {
color: -moz-nativehyperlinktext;
text-decoration: none;
}
html|a.inline-link:hover {
text-decoration: underline;
}
html|a.inline-link:-moz-focusring {
outline-width: 0;
box-shadow: @focusRingShadow@;
}
/**
* Update Preferences
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

View File

@ -1,47 +0,0 @@
%if 0
/* 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/. */
%endif
body.private > #errorPageContainer {
background-image: url("chrome://browser/skin/Privacy-48.png");
}
body.normal > #errorPageContainer {
background-image: url("chrome://global/skin/icons/question-48.png");
}
#clearRecentHistoryDesc {
margin-top: 2em;
}
#clearRecentHistoryDesc > p {
font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
}
#startPrivateBrowsingDesc > button {
-moz-margin-start: 0;
}
#footerDesc > p {
font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
}
#moreInfo {
font-size: 110%; /* to match the value set in chrome://global/skin/netError.css */
-moz-padding-start: 25px;
background: url("chrome://global/skin/icons/information-16.png") no-repeat top left;
}
#moreInfo:-moz-dir(rtl) {
background-position: top right;
}
#moreInfoText {
margin-bottom: 0;
}
#moreInfoLinkContainer {
margin-top: 0.5em;
}

View File

@ -8,7 +8,6 @@ browser.jar:
# NOTE: If you add a new file here, you'll need to add it to the aero
# section at the bottom of this file
skin/classic/browser/sanitizeDialog.css
* skin/classic/browser/aboutPrivateBrowsing.css
* skin/classic/browser/aboutSessionRestore.css
skin/classic/browser/aboutSessionRestore-window-icon.png (preferences/application.png)
skin/classic/browser/aboutWelcomeBack.css (../shared/aboutWelcomeBack.css)
@ -40,6 +39,8 @@ browser.jar:
skin/classic/browser/keyhole-forward-mask.svg
skin/classic/browser/KUI-background.png
skin/classic/browser/livemark-folder.png
skin/classic/browser/mask.png (../shared/mask.png)
skin/classic/browser/mask@2x.png (../shared/mask@2x.png)
skin/classic/browser/menu-back.png
skin/classic/browser/menu-forward.png
skin/classic/browser/menuPanel.png
@ -416,7 +417,6 @@ browser.jar:
browser.jar:
% skin browser classic/1.0 %skin/classic/aero/browser/ os=WINNT osversion>=6
skin/classic/aero/browser/sanitizeDialog.css (sanitizeDialog.css)
* skin/classic/aero/browser/aboutPrivateBrowsing.css (aboutPrivateBrowsing.css)
* skin/classic/aero/browser/aboutSessionRestore.css (aboutSessionRestore.css)
skin/classic/aero/browser/aboutSessionRestore-window-icon.png (aboutSessionRestore-window-icon-aero.png)
skin/classic/aero/browser/aboutCertError.css
@ -448,6 +448,8 @@ browser.jar:
skin/classic/aero/browser/keyhole-forward-mask.svg
skin/classic/aero/browser/KUI-background.png
skin/classic/aero/browser/livemark-folder.png (livemark-folder-aero.png)
skin/classic/aero/browser/mask.png (../shared/mask.png)
skin/classic/aero/browser/mask@2x.png (../shared/mask@2x.png)
skin/classic/aero/browser/menu-back.png (menu-back-aero.png)
skin/classic/aero/browser/menu-forward.png (menu-forward-aero.png)
skin/classic/aero/browser/menuPanel.png
@ -476,7 +478,6 @@ browser.jar:
skin/classic/aero/browser/pointerLock-64.png
skin/classic/aero/browser/Privacy-16.png (Privacy-16-aero.png)
skin/classic/aero/browser/Privacy-32.png (Privacy-32-aero.png)
skin/classic/aero/browser/Privacy-48.png (Privacy-48-aero.png)
skin/classic/aero/browser/privatebrowsing-mask-tabstrip.png
skin/classic/aero/browser/privatebrowsing-mask-tabstrip-XPVista7.png
skin/classic/aero/browser/privatebrowsing-mask-titlebar.png

View File

@ -74,18 +74,6 @@ label.small {
-moz-box-flex: 1;
}
/* Privacy Pane */
/* styles for the link elements copied from .text-link in global.css */
.inline-link {
color: -moz-nativehyperlinktext;
text-decoration: none;
}
.inline-link:hover {
text-decoration: underline;
}
/* Modeless Window Dialogs */
.windowDialog,
.windowDialog prefpane {

View File

@ -12,10 +12,6 @@ def main(file):
config = ConfigParser.RawConfigParser()
config.read(file)
flags = set()
try:
if config.getint('XRE', 'EnableExtensionManager') == 1:
flags.add('NS_XRE_ENABLE_EXTENSION_MANAGER')
except: pass
try:
if config.getint('XRE', 'EnableProfileMigrator') == 1:
flags.add('NS_XRE_ENABLE_PROFILE_MIGRATOR')

View File

@ -42,9 +42,6 @@ MaxVersion=@GRE_MILESTONE@
#ifdef MOZ_PROFILE_MIGRATOR
EnableProfileMigrator=1
#endif
#ifdef MOZ_EXTENSION_MANAGER
EnableExtensionManager=1
#endif
#if MOZ_CRASHREPORTER
[Crash Reporter]

View File

@ -40,7 +40,7 @@ if CONFIG['MOZ_APP_PROFILE']:
DEFINES['MOZ_APP_PROFILE'] = CONFIG['MOZ_APP_PROFILE']
for var in ('MOZ_CRASHREPORTER', 'MOZ_PROFILE_MIGRATOR',
'MOZ_EXTENSION_MANAGER', 'MOZ_APP_STATIC_INI'):
'MOZ_APP_STATIC_INI'):
if CONFIG[var]:
DEFINES[var] = True

View File

@ -9,7 +9,7 @@ LIBRARY_NAME = 'ffi'
if CONFIG['MOZ_NATIVE_FFI']:
OS_LIBS += CONFIG['MOZ_FFI_LIBS']
else:
if CONFIG['OS_ARCH'] == 'WINNT':
if CONFIG['_MSC_VER']:
prefix = 'lib'
else:
prefix = ''

View File

@ -150,6 +150,10 @@ endef
$(foreach subtier,export libs tools,$(eval $(call CREATE_SUBTIER_TRAVERSAL_RULE,$(subtier))))
ifndef TOPLEVEL_BUILD
libs:: target host
endif
endif # ifdef TIERS
endif # ifeq ($(NO_RECURSE_MAKELEVEL),$(MAKELEVEL))

View File

@ -697,7 +697,7 @@ ifdef MOZ_PROFILE_GENERATE
touch -t `date +%Y%m%d%H%M.%S -d 'now+5seconds'` pgo.relink
endif
else # !WINNT || GNU_CC
$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
$(EXPAND_CCC) -o $@ $(CXXFLAGS) $(PROGOBJS) $(RESFILE) $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(EXE_DEF_FILE) $(STLPORT_LIBS)
$(call CHECK_BINARY,$@)
endif # WINNT && !GNU_CC
@ -753,7 +753,7 @@ ifdef MSMANIFEST_TOOL
fi
endif # MSVC with manifest tool
else
$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(STATIC_LIBS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
$(EXPAND_CCC) $(CXXFLAGS) -o $@ $< $(WIN32_EXE_LDFLAGS) $(LDFLAGS) $(WRAP_LDFLAGS) $(STATIC_LIBS) $(MOZ_GLUE_PROGRAM_LDFLAGS) $(SHARED_LIBS) $(EXTRA_LIBS) $(OS_LIBS) $(BIN_FLAGS) $(STLPORT_LIBS)
$(call CHECK_BINARY,$@)
endif # WINNT && !GNU_CC

View File

@ -8485,7 +8485,6 @@ AC_SUBST(MOZ_CHILD_PROCESS_BUNDLE)
# - MOZ_APP_ID: When set, used for application.ini's "ID" field, and
# crash reporter server url.
# - MOZ_PROFILE_MIGRATOR: When set, enables profile migrator.
# - MOZ_EXTENSION_MANAGER: When set, enabled extension manager.
if test -z "$MOZ_APP_NAME"; then
MOZ_APP_NAME=`echo $MOZ_APP_BASENAME | tr A-Z a-z`
@ -8518,7 +8517,6 @@ AC_SUBST(MOZ_APP_ID)
AC_SUBST(MAR_CHANNEL_ID)
AC_SUBST(ACCEPTED_MAR_CHANNEL_IDS)
AC_SUBST(MOZ_PROFILE_MIGRATOR)
AC_SUBST(MOZ_EXTENSION_MANAGER)
AC_DEFINE_UNQUOTED(MOZ_APP_UA_NAME, "$MOZ_APP_UA_NAME")
AC_SUBST(MOZ_APP_UA_NAME)
AC_DEFINE_UNQUOTED(MOZ_APP_UA_VERSION, "$MOZ_APP_VERSION")

View File

@ -35,6 +35,7 @@
#include "nsAttrValue.h"
#include "mozilla/EventForwards.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/WindowBinding.h"
#include "Units.h"
class nsIDOMEventListener;
@ -720,11 +721,8 @@ public:
already_AddRefed<ShadowRoot> CreateShadowRoot(ErrorResult& aError);
already_AddRefed<DestinationInsertionPointList> GetDestinationInsertionPoints();
void ScrollIntoView()
{
ScrollIntoView(true);
}
void ScrollIntoView(bool aTop);
void ScrollIntoView();
void ScrollIntoView(bool aTop, const ScrollOptions &aOptions);
int32_t ScrollTop()
{
nsIScrollableFrame* sf = GetScrollFrame();

View File

@ -103,7 +103,7 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
// QueryInterface implementation for Attr
NS_INTERFACE_TABLE_HEAD(Attr)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE(Attr, nsINode, nsIDOMAttr, nsIAttribute, nsIDOMNode,
nsIDOMEventTarget, EventTarget)
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(Attr)

View File

@ -75,7 +75,7 @@ DOMRect::Constructor(const GlobalObject& aGlobal, double aX, double aY,
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(DOMRectList, mParent, mArray)
NS_INTERFACE_TABLE_HEAD(DOMRectList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE(DOMRectList, nsIDOMClientRectList)
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(DOMRectList)
NS_INTERFACE_MAP_END

View File

@ -586,7 +586,13 @@ Element::GetScrollFrame(nsIFrame **aStyledFrame, bool aFlushLayout)
}
void
Element::ScrollIntoView(bool aTop)
Element::ScrollIntoView()
{
ScrollIntoView(true, ScrollOptions());
}
void
Element::ScrollIntoView(bool aTop, const ScrollOptions &aOptions)
{
nsIDocument *document = GetCurrentDoc();
if (!document) {
@ -602,12 +608,17 @@ Element::ScrollIntoView(bool aTop)
int16_t vpercent = aTop ? nsIPresShell::SCROLL_TOP :
nsIPresShell::SCROLL_BOTTOM;
uint32_t flags = nsIPresShell::SCROLL_OVERFLOW_HIDDEN;
if (aOptions.mBehavior == ScrollBehavior::Smooth) {
flags |= nsIPresShell::SCROLL_SMOOTH;
}
presShell->ScrollContentIntoView(this,
nsIPresShell::ScrollAxis(
vpercent,
nsIPresShell::SCROLL_ALWAYS),
nsIPresShell::ScrollAxis(),
nsIPresShell::SCROLL_OVERFLOW_HIDDEN);
flags);
}
bool

View File

@ -394,7 +394,7 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_BEGIN(nsChildContentList)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
NS_INTERFACE_TABLE_HEAD(nsChildContentList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE(nsChildContentList, nsINodeList, nsIDOMNodeList)
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsChildContentList)
NS_INTERFACE_MAP_END

View File

@ -85,7 +85,7 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
// QueryInterface implementation for nsBaseContentList
NS_INTERFACE_TABLE_HEAD(nsBaseContentList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE(nsBaseContentList, nsINodeList, nsIDOMNodeList)
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(nsBaseContentList)
NS_INTERFACE_MAP_END

View File

@ -116,7 +116,7 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_THIS_END
NS_INTERFACE_TABLE_HEAD(nsDOMAttributeMap)
NS_INTERFACE_TABLE(nsDOMAttributeMap, nsIDOMMozNamedAttrMap)
NS_INTERFACE_TABLE_TO_MAP_SEGUE
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(nsDOMAttributeMap)
NS_INTERFACE_MAP_END

View File

@ -1737,7 +1737,7 @@ nsDocument::~nsDocument()
}
NS_INTERFACE_TABLE_HEAD(nsDocument)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE_BEGIN
NS_INTERFACE_TABLE_ENTRY_AMBIGUOUS(nsDocument, nsISupports, nsINode)
NS_INTERFACE_TABLE_ENTRY(nsDocument, nsINode)

View File

@ -467,13 +467,6 @@ nsFrameLoader::ReallyStartLoadingInternal()
mPendingFrameSent = true;
}
}
if (Preferences::GetBool("dom.ipc.processPrelaunch.enabled", false) &&
!ContentParent::PreallocatedProcessReady()) {
ContentParent::RunAfterPreallocatedProcessReady(
new DelayedStartLoadingRunnable(this));
return NS_ERROR_FAILURE;
}
TryRemoteBrowser();

View File

@ -136,7 +136,7 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_END
// XPConnect interface list for HTMLFormControlsCollection
NS_INTERFACE_TABLE_HEAD(HTMLFormControlsCollection)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE(HTMLFormControlsCollection,
nsIHTMLCollection,
nsIDOMHTMLCollection)

View File

@ -95,7 +95,7 @@ NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(HTMLOptionsCollection, mElements)
// QueryInterface implementation for HTMLOptionsCollection
NS_INTERFACE_TABLE_HEAD(HTMLOptionsCollection)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE(HTMLOptionsCollection,
nsIHTMLCollection,
nsIDOMHTMLOptionsCollection,

View File

@ -61,7 +61,7 @@ HTMLPropertiesCollection::~HTMLPropertiesCollection()
}
NS_INTERFACE_TABLE_HEAD(HTMLPropertiesCollection)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE(HTMLPropertiesCollection,
nsIDOMHTMLCollection,
nsIHTMLCollection,
@ -408,7 +408,7 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(PropertyNodeList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(PropertyNodeList)
NS_INTERFACE_TABLE_HEAD(PropertyNodeList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE(PropertyNodeList,
nsIDOMNodeList,
nsINodeList,

View File

@ -95,7 +95,7 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(TableRowsCollection)
NS_IMPL_CYCLE_COLLECTING_RELEASE(TableRowsCollection)
NS_INTERFACE_TABLE_HEAD(TableRowsCollection)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE(TableRowsCollection, nsIHTMLCollection,
nsIDOMHTMLCollection)
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(TableRowsCollection)

View File

@ -469,7 +469,7 @@ public:
if (!_argc) {
top = true;
}
mozilla::dom::Element::ScrollIntoView(top);
mozilla::dom::Element::ScrollIntoView(top, mozilla::dom::ScrollOptions());
return NS_OK;
}
NS_IMETHOD GetOffsetParent(nsIDOMElement** aOffsetParent) MOZ_FINAL {

View File

@ -36,6 +36,7 @@ const gPropertyTestDecls = {
"opacity": "opacity: 0.8",
"mask": "mask: url(#mymask)",
"clip": "clip: rect(0 0 0 0)",
"clipPath": "clip-path: url(#mypath)",
"filter": "filter: url(#myfilter)",
"transform": "transform: translate(0)",
// XXXdholbert The "will-change" line in full-screen-override.css is only

View File

@ -180,7 +180,7 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
aDecoder->GetReentrantMonitor(),
&MediaDecoderStateMachine::TimeoutExpired,
MOZ_THIS_IN_INITIALIZER_LIST(), aRealTime)),
mState(DECODER_STATE_DECODING_METADATA),
mState(DECODER_STATE_DECODING_NONE),
mSyncPointInMediaStream(-1),
mSyncPointInDecodedStream(-1),
mPlayDuration(0),
@ -209,7 +209,6 @@ MediaDecoderStateMachine::MediaDecoderStateMachine(MediaDecoder* aDecoder,
mQuickBuffering(false),
mMinimizePreroll(false),
mDecodeThreadWaiting(false),
mDispatchedDecodeMetadataTask(false),
mDropAudioUntilNextDiscontinuity(false),
mDropVideoUntilNextDiscontinuity(false),
mDecodeToSeekTarget(false),
@ -358,22 +357,26 @@ static const TrackRate RATE_VIDEO = USECS_PER_S;
void MediaDecoderStateMachine::SendStreamData()
{
NS_ASSERTION(OnDecodeThread() ||
OnStateMachineThread(), "Should be on decode thread or state machine thread");
NS_ASSERTION(OnDecodeThread() || OnStateMachineThread(),
"Should be on decode thread or state machine thread");
AssertCurrentThreadInMonitor();
MOZ_ASSERT(mState != DECODER_STATE_DECODING_NONE);
DecodedStreamData* stream = mDecoder->GetDecodedStream();
if (!stream)
if (!stream) {
return;
}
if (mState == DECODER_STATE_DECODING_METADATA)
if (mState == DECODER_STATE_DECODING_METADATA) {
return;
}
// If there's still an audio sink alive, then we can't send any stream
// data yet since both SendStreamData and the audio sink want to be in
// charge of popping the audio queue. We're waiting for the audio sink
if (mAudioSink)
if (mAudioSink) {
return;
}
int64_t minLastAudioPacketTime = INT64_MAX;
bool finished =
@ -1330,7 +1333,7 @@ void MediaDecoderStateMachine::SetDormant(bool aDormant)
ScheduleStateMachine();
mStartTime = 0;
mCurrentFrameTime = 0;
mState = DECODER_STATE_DECODING_METADATA;
mState = DECODER_STATE_DECODING_NONE;
mDecoder->GetReentrantMonitor().NotifyAll();
}
}
@ -1399,8 +1402,8 @@ void MediaDecoderStateMachine::NotifyWaitingForResourcesStatusChanged()
DECODER_LOG("NotifyWaitingForResourcesStatusChanged");
// The reader is no longer waiting for resources (say a hardware decoder),
// we can now proceed to decode metadata.
mState = DECODER_STATE_DECODING_METADATA;
EnqueueDecodeMetadataTask();
mState = DECODER_STATE_DECODING_NONE;
ScheduleStateMachine();
}
void MediaDecoderStateMachine::Play()
@ -1531,21 +1534,13 @@ nsresult
MediaDecoderStateMachine::EnqueueDecodeMetadataTask()
{
AssertCurrentThreadInMonitor();
MOZ_ASSERT(mState == DECODER_STATE_DECODING_METADATA);
if (mState != DECODER_STATE_DECODING_METADATA ||
mDispatchedDecodeMetadataTask) {
return NS_OK;
}
mDispatchedDecodeMetadataTask = true;
RefPtr<nsIRunnable> task(
NS_NewRunnableMethod(this, &MediaDecoderStateMachine::CallDecodeMetadata));
nsresult rv = mDecodeTaskQueue->Dispatch(task);
if (NS_FAILED(rv)) {
DECODER_WARN("Dispatch ReadMetadata task failed.");
mDispatchedDecodeMetadataTask = false;
}
return rv;
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
void
@ -1872,10 +1867,8 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
{
AssertCurrentThreadInMonitor();
NS_ASSERTION(OnDecodeThread(), "Should be on decode thread.");
MOZ_ASSERT(mState == DECODER_STATE_DECODING_METADATA);
DECODER_LOG("Decoding Media Headers");
if (mState != DECODER_STATE_DECODING_METADATA) {
return NS_ERROR_FAILURE;
}
nsresult res;
MediaInfo info;
@ -1890,7 +1883,6 @@ nsresult MediaDecoderStateMachine::DecodeMetadata()
// change state to DECODER_STATE_WAIT_FOR_RESOURCES
StartWaitForResources();
// affect values only if ReadMetadata succeeds
mDispatchedDecodeMetadataTask = false;
return NS_OK;
}
}
@ -2012,7 +2004,6 @@ MediaDecoderStateMachine::FinishDecodeMetadata()
StartPlayback();
}
mDispatchedDecodeMetadataTask = false;
return NS_OK;
}
@ -2143,6 +2134,8 @@ MediaDecoderStateMachine::SeekCompleted()
}
}
MOZ_ASSERT(mState != DECODER_STATE_DECODING_NONE);
mDecoder->StartProgressUpdates();
if (mState == DECODER_STATE_DECODING_METADATA ||
mState == DECODER_STATE_DORMANT ||
@ -2329,11 +2322,16 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
return NS_OK;
}
case DECODER_STATE_DECODING_METADATA: {
case DECODER_STATE_DECODING_NONE: {
mState = DECODER_STATE_DECODING_METADATA;
// Ensure we have a decode thread to decode metadata.
return EnqueueDecodeMetadataTask();
}
case DECODER_STATE_DECODING_METADATA: {
return NS_OK;
}
case DECODER_STATE_DECODING: {
if (mDecoder->GetState() != MediaDecoder::PLAY_STATE_PLAYING &&
IsPlaying())

View File

@ -135,6 +135,7 @@ public:
// Enumeration for the valid decoding states
enum State {
DECODER_STATE_DECODING_NONE,
DECODER_STATE_DECODING_METADATA,
DECODER_STATE_WAIT_FOR_RESOURCES,
DECODER_STATE_DORMANT,
@ -893,11 +894,6 @@ protected:
// by the decoder monitor.
bool mDecodeThreadWaiting;
// True if we've dispatched a task to the decode task queue to call
// ReadMetadata on the reader. We maintain a flag to ensure that we don't
// dispatch multiple tasks to re-do the metadata loading.
bool mDispatchedDecodeMetadataTask;
// These two flags are true when we need to drop decoded samples that
// we receive up to the next discontinuity. We do this when we seek;
// the first sample in each stream after the seek is marked as being

View File

@ -154,6 +154,9 @@ public:
MediaByteRange Extents(const MediaByteRange& aByteRange) const
{
if (IsNull()) {
return aByteRange;
}
return MediaByteRange(std::min(mStart, aByteRange.mStart),
std::max(mEnd, aByteRange.mEnd));
}

View File

@ -855,6 +855,7 @@ protected:
TrackData* FindDataForTrack(TrackID aID)
{
mMutex.AssertCurrentThreadOwns();
for (uint32_t i = 0; i < mUpdateTracks.Length(); ++i) {
if (mUpdateTracks[i].mID == aID) {
return &mUpdateTracks[i];

View File

@ -24,6 +24,7 @@ const StreamTime STREAM_TIME_MAX = MEDIA_TIME_MAX;
*/
typedef int32_t TrackID;
const TrackID TRACK_NONE = 0;
const TrackID TRACK_INVALID = -1;
inline TrackTicks RateConvertTicksRoundDown(TrackRate aOutRate,
TrackRate aInRate,

View File

@ -266,6 +266,7 @@ MediaSource::EndOfStream(const Optional<MediaSourceEndOfStreamError>& aError, Er
SetReadyState(MediaSourceReadyState::Ended);
mSourceBuffers->Ended();
mDecoder->Ended();
if (!aError.WasPassed()) {
DurationChange(mSourceBuffers->GetHighestBufferedEndTime(), aRv);
if (aRv.Failed()) {

View File

@ -128,6 +128,14 @@ MediaSourceDecoder::CreateSubDecoder(const nsACString& aType)
return mReader->CreateSubDecoder(aType);
}
void
MediaSourceDecoder::Ended()
{
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
mReader->Ended();
mon.NotifyAll();
}
void
MediaSourceDecoder::SetMediaSourceDuration(double aDuration)
{

View File

@ -47,6 +47,8 @@ public:
already_AddRefed<SourceBufferDecoder> CreateSubDecoder(const nsACString& aType);
void Ended();
void SetMediaSourceDuration(double aDuration);
// Provide a mechanism for MediaSourceReader to block waiting on data from a SourceBuffer.

View File

@ -40,6 +40,7 @@ MediaSourceReader::MediaSourceReader(MediaSourceDecoder* aDecoder)
, mTimeThreshold(-1)
, mDropAudioBeforeThreshold(false)
, mDropVideoBeforeThreshold(false)
, mEnded(false)
{
}
@ -133,11 +134,16 @@ MediaSourceReader::OnVideoEOS()
if (SwitchReaders(SWITCH_FORCED)) {
// Success! Resume decoding with next video decoder.
RequestVideoData(false, mTimeThreshold);
} else {
} else if (IsEnded()) {
// End of stream.
MSE_DEBUG("MediaSourceReader(%p)::OnVideoEOS reader=%p EOS (readers=%u)",
this, mVideoReader.get(), mDecoders.Length());
GetCallback()->OnVideoEOS();
} else {
// If a new decoder isn't ready to respond with frames yet, we're going to
// keep hitting this path at 1/frame_duration Hz. Bug 1058422 is raised to
// address this issue.
RequestVideoData(false, mTimeThreshold);
}
}
@ -209,10 +215,14 @@ MediaSourceReader::SwitchVideoReader(MediaDecoderReader* aTargetReader)
bool
MediaSourceReader::SwitchReaders(SwitchType aType)
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
InitializePendingDecoders();
// This monitor must be held after the call to InitializePendingDecoders
// as that method also obtains the lock, and then attempts to exit it
// to call ReadMetadata on the readers. If we hold it before the call then
// it remains held during the ReadMetadata call causing a deadlock.
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
bool didSwitch = false;
double decodeTarget = double(mTimeThreshold) / USECS_PER_S;
@ -412,14 +422,14 @@ MediaSourceReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime,
// This is a workaround for our lack of async functionality in the
// MediaDecoderStateMachine. Bug 979104 implements what we need and
// we'll remove this for an async approach based on that in bug XXXXXXX.
while (!DecodersContainTime(target) && !IsShutdown()) {
while (!DecodersContainTime(target) && !IsShutdown() && !IsEnded()) {
MSE_DEBUG("MediaSourceReader(%p)::Seek waiting for target=%f", this, target);
static_cast<MediaSourceDecoder*>(mDecoder)->WaitForData();
SwitchReaders(SWITCH_FORCED);
}
if (IsShutdown()) {
return NS_OK;
return NS_ERROR_FAILURE;
}
ResetDecode();
@ -494,4 +504,18 @@ MediaSourceReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags)
return NS_OK;
}
void
MediaSourceReader::Ended()
{
mDecoder->GetReentrantMonitor().AssertCurrentThreadIn();
mEnded = true;
}
bool
MediaSourceReader::IsEnded()
{
ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor());
return mEnded;
}
} // namespace mozilla

View File

@ -87,6 +87,12 @@ public:
// Return true if any of the active decoders contain data for the given time
bool DecodersContainTime(double aTime);
// Mark the reader to indicate that EndOfStream has been called on our MediaSource
void Ended();
// Return true if the Ended method has been called
bool IsEnded();
private:
enum SwitchType {
SWITCH_OPTIONAL,
@ -108,6 +114,8 @@ private:
nsRefPtr<MediaDecoderReader> mAudioReader;
nsRefPtr<MediaDecoderReader> mVideoReader;
bool mEnded;
};
} // namespace mozilla

View File

@ -16,6 +16,8 @@
#include "mozilla/FloatingPoint.h"
#include "mozilla/dom/MediaSourceBinding.h"
#include "mozilla/dom/TimeRanges.h"
#include "mp4_demuxer/BufferStream.h"
#include "mp4_demuxer/MoofParser.h"
#include "nsError.h"
#include "nsIEventTarget.h"
#include "nsIRunnable.h"
@ -85,6 +87,8 @@ public:
class MP4ContainerParser : public ContainerParser {
public:
MP4ContainerParser() : mTimescale(0) {}
bool IsInitSegmentPresent(const uint8_t* aData, uint32_t aLength)
{
ContainerParser::IsInitSegmentPresent(aData, aLength);
@ -111,6 +115,33 @@ public:
return aData[4] == 'f' && aData[5] == 't' && aData[6] == 'y' &&
aData[7] == 'p';
}
virtual bool ParseStartAndEndTimestamps(const uint8_t* aData, uint32_t aLength,
double& aStart, double& aEnd)
{
mp4_demuxer::MoofParser parser(new mp4_demuxer::BufferStream(aData, aLength), 0);
parser.mMdhd.mTimescale = mTimescale;
nsTArray<MediaByteRange> byteRanges;
byteRanges.AppendElement(MediaByteRange(0, aLength));
parser.RebuildFragmentedIndex(byteRanges);
// Persist the timescale for when it is absent in later chunks
mTimescale = parser.mMdhd.mTimescale;
mp4_demuxer::Interval<mp4_demuxer::Microseconds> compositionRange =
parser.GetCompositionRange();
if (compositionRange.IsNull()) {
return false;
}
aStart = static_cast<double>(compositionRange.start) / USECS_PER_S;
aEnd = static_cast<double>(compositionRange.end) / USECS_PER_S;
return true;
}
private:
uint32_t mTimescale;
};

View File

@ -130,7 +130,8 @@ MediaCodecReader::TrackInputCopier::Copy(MediaBuffer* aSourceBuffer,
}
MediaCodecReader::Track::Track()
: mDurationUs(INT64_C(0))
: mSourceIsStopped(true)
, mDurationUs(INT64_C(0))
, mInputIndex(sInvalidInputIndex)
, mInputEndOfStream(false)
, mOutputEndOfStream(false)
@ -220,12 +221,22 @@ MediaCodecReader::IsWaitingMediaResources()
bool
MediaCodecReader::IsDormantNeeded()
{
return mVideoTrack.mCodec != nullptr;
return mVideoTrack.mSource != nullptr;
}
void
MediaCodecReader::ReleaseMediaResources()
{
// Stop the mSource because we are in the dormant state and the stop function
// will rewind the mSource to the beginning of the stream.
if (mVideoTrack.mSource != nullptr) {
mVideoTrack.mSource->stop();
mVideoTrack.mSourceIsStopped = true;
}
if (mAudioTrack.mSource != nullptr) {
mAudioTrack.mSource->stop();
mAudioTrack.mSourceIsStopped = true;
}
ReleaseCriticalResources();
}
@ -836,6 +847,7 @@ MediaCodecReader::CreateMediaSources()
sp<MediaSource> audioSource = mExtractor->getTrack(audioTrackIndex);
if (audioSource != nullptr && audioSource->start() == OK) {
mAudioTrack.mSource = audioSource;
mAudioTrack.mSourceIsStopped = false;
}
// Get one another track instance for audio offload playback.
mAudioOffloadTrack.mSource = mExtractor->getTrack(audioTrackIndex);
@ -845,6 +857,7 @@ MediaCodecReader::CreateMediaSources()
sp<MediaSource> videoSource = mExtractor->getTrack(videoTrackIndex);
if (videoSource != nullptr && videoSource->start() == OK) {
mVideoTrack.mSource = videoSource;
mVideoTrack.mSourceIsStopped = false;
}
}
@ -1229,6 +1242,14 @@ MediaCodecReader::FillCodecInputData(Track& aTrack)
}
MOZ_ASSERT(aTrack.mInputIndex.isValid(), "aElement.mInputIndex should be valid");
// Start the mSource before we read it.
if (aTrack.mSourceIsStopped) {
if (aTrack.mSource->start() == OK) {
aTrack.mSourceIsStopped = false;
} else {
return UNKNOWN_ERROR;
}
}
MediaBuffer* source_buffer = nullptr;
status_t status = OK;
if (IsValidTimestampUs(aTrack.mSeekTimeUs)) {
@ -1311,7 +1332,7 @@ MediaCodecReader::GetCodecOutputData(Track& aTrack,
&info.mSize, &info.mTimeUs, &info.mFlags, duration);
// Check EOS first.
if (status == ERROR_END_OF_STREAM ||
info.mFlags & MediaCodec::BUFFER_FLAG_EOS) {
(info.mFlags & MediaCodec::BUFFER_FLAG_EOS)) {
aBuffer = info;
aBuffer.mBuffer = aTrack.mOutputBuffers[info.mIndex];
aTrack.mOutputEndOfStream = true;

View File

@ -100,6 +100,7 @@ protected:
// pipeline parameters
android::sp<android::MediaSource> mSource;
bool mSourceIsStopped;
android::sp<android::MediaCodecProxy> mCodec;
android::Vector<android::sp<android::ABuffer> > mInputBuffers;
android::Vector<android::sp<android::ABuffer> > mOutputBuffers;

View File

@ -21,15 +21,20 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=799315
<script>
function IsWindowsVistaOrLater() {
var re = /Windows NT (\d.\d)/;
var re = /Windows NT (\d+\.\d)/;
var winver = navigator.userAgent.match(re);
return winver && winver.length == 2 && parseFloat(winver[1]) >= 6.0;
}
function IsWindowsXPOrEarlier() {
var re = /Windows NT (\d.\d)/;
var winver = navigator.userAgent.match(re);
return winver && winver.length == 2 && parseFloat(winver[1]) < 6.0;
function IsMacOSLionOrLater() {
var re = /Mac OS X (\d+)\.(\d+)/;
var ver = navigator.userAgent.match(re);
if (!ver || ver.length != 3) {
return false;
}
var major = ver[1] | 0;
var minor = ver[2] | 0;
return major == 10 && minor >= 7;
}
function getPref(name) {
@ -40,10 +45,17 @@ function getPref(name) {
return pref;
}
// Check whether we should expect the new MP4Reader-based support to work.
function IsMP4ReaderAvailable() {
var prefs = getPref("media.fragmented-mp4.enabled") &&
getPref("media.fragmented-mp4.exposed");
return prefs && (IsWindowsVistaOrLater() || IsMacOSLionOrLater());
}
var haveMp4 = (getPref("media.windows-media-foundation.enabled") && IsWindowsVistaOrLater()) ||
getPref("media.omx.enabled") ||
getPref("media.gstreamer.enabled") ||
(getPref("media.fragmented-mp4.exposed") && !IsWindowsXPOrEarlier());
IsMP4ReaderAvailable();
// TODO: Add "getPref("media.plugins.enabled")" once MP4 works on Gingerbread.
check_mp4(document.getElementById('v'), haveMp4);

View File

@ -20,7 +20,6 @@ NS_IMPL_CYCLE_COLLECTION_INHERITED(SpeechSynthesisUtterance,
DOMEventTargetHelper, mVoice);
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(SpeechSynthesisUtterance)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
NS_IMPL_ADDREF_INHERITED(SpeechSynthesisUtterance, DOMEventTargetHelper)

View File

@ -52,6 +52,11 @@ this.PermissionsTable = { geolocation: {
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"udp-socket": {
app: DENY_ACTION,
privileged: ALLOW_ACTION,
certified: ALLOW_ACTION
},
"network-events": {
app: DENY_ACTION,
privileged: DENY_ACTION,

View File

@ -213,6 +213,7 @@
#include "mozilla/dom/Console.h"
#include "mozilla/dom/FunctionBinding.h"
#include "mozilla/dom/HashChangeEvent.h"
#include "mozilla/dom/MozSelfSupportBinding.h"
#include "mozilla/dom/PopStateEvent.h"
#include "mozilla/dom/PopupBlockedEvent.h"
#include "mozilla/dom/WindowBinding.h"
@ -1467,6 +1468,8 @@ nsGlobalWindow::CleanUp()
mExternal = nullptr;
mMozSelfSupport = nullptr;
mPerformance = nullptr;
#ifdef MOZ_WEBSPEECH
@ -1786,6 +1789,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCrypto)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mConsole)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mExternal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMozSelfSupport)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -1846,6 +1850,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mCrypto)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mConsole)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mExternal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mMozSelfSupport)
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
@ -4065,6 +4070,19 @@ nsGlobalWindow::GetContent(nsIDOMWindow** aContent)
return rv.ErrorCode();
}
MozSelfSupport*
nsGlobalWindow::GetMozSelfSupport(ErrorResult& aError)
{
if (mMozSelfSupport) {
return mMozSelfSupport;
}
AutoSafeJSContext cx;
GlobalObject global(cx, FastGetGlobalJSObject());
mMozSelfSupport = MozSelfSupport::Constructor(global, cx, aError);
return mMozSelfSupport;
}
NS_IMETHODIMP
nsGlobalWindow::GetScriptableContent(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
{
@ -7189,22 +7207,37 @@ nsGlobalWindow::GetTopWindowRoot()
return window.forget();
}
void
nsGlobalWindow::Scroll(int32_t aXScroll, int32_t aYScroll,
const ScrollOptions& aOptions)
{
ScrollTo(CSSIntPoint(aXScroll, aYScroll), aOptions);
}
void
nsGlobalWindow::ScrollTo(int32_t aXScroll, int32_t aYScroll,
const ScrollOptions& aOptions)
{
ScrollTo(CSSIntPoint(aXScroll, aYScroll), aOptions);
}
NS_IMETHODIMP
nsGlobalWindow::Scroll(int32_t aXScroll, int32_t aYScroll)
{
ScrollTo(CSSIntPoint(aXScroll, aYScroll));
ScrollTo(CSSIntPoint(aXScroll, aYScroll), ScrollOptions());
return NS_OK;
}
NS_IMETHODIMP
nsGlobalWindow::ScrollTo(int32_t aXScroll, int32_t aYScroll)
{
ScrollTo(CSSIntPoint(aXScroll, aYScroll));
ScrollTo(CSSIntPoint(aXScroll, aYScroll), ScrollOptions());
return NS_OK;
}
void
nsGlobalWindow::ScrollTo(const CSSIntPoint& aScroll)
nsGlobalWindow::ScrollTo(const CSSIntPoint& aScroll,
const ScrollOptions& aOptions)
{
FlushPendingNotifications(Flush_Layout);
nsIScrollableFrame *sf = GetScrollFrame();
@ -7225,7 +7258,86 @@ nsGlobalWindow::ScrollTo(const CSSIntPoint& aScroll)
if (scroll.y > maxpx) {
scroll.y = maxpx;
}
sf->ScrollToCSSPixels(scroll);
sf->ScrollToCSSPixels(scroll,
aOptions.mBehavior == ScrollBehavior::Smooth
? nsIScrollableFrame::SMOOTH_MSD
: nsIScrollableFrame::INSTANT);
}
}
NS_IMETHODIMP
nsGlobalWindow::ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif)
{
ScrollBy(aXScrollDif, aYScrollDif, ScrollOptions());
return NS_OK;
}
void
nsGlobalWindow::ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif,
const ScrollOptions& aOptions)
{
FlushPendingNotifications(Flush_Layout);
nsIScrollableFrame *sf = GetScrollFrame();
if (sf) {
CSSIntPoint scrollPos =
sf->GetScrollPositionCSSPixels() + CSSIntPoint(aXScrollDif, aYScrollDif);
// It seems like it would make more sense for ScrollBy to use
// SMOOTH mode, but tests seem to depend on the synchronous behaviour.
// Perhaps Web content does too.
ScrollTo(scrollPos, aOptions);
}
}
NS_IMETHODIMP
nsGlobalWindow::ScrollByLines(int32_t numLines)
{
ScrollByLines(numLines, ScrollOptions());
return NS_OK;
}
void
nsGlobalWindow::ScrollByLines(int32_t numLines,
const ScrollOptions& aOptions)
{
FlushPendingNotifications(Flush_Layout);
nsIScrollableFrame *sf = GetScrollFrame();
if (sf) {
// It seems like it would make more sense for ScrollByLines to use
// SMOOTH mode, but tests seem to depend on the synchronous behaviour.
// Perhaps Web content does too.
sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
aOptions.mBehavior == ScrollBehavior::Smooth
? nsIScrollableFrame::SMOOTH_MSD
: nsIScrollableFrame::INSTANT);
}
}
NS_IMETHODIMP
nsGlobalWindow::ScrollByPages(int32_t numPages)
{
ScrollByPages(numPages, ScrollOptions());
return NS_OK;
}
void
nsGlobalWindow::ScrollByPages(int32_t numPages,
const ScrollOptions& aOptions)
{
FlushPendingNotifications(Flush_Layout);
nsIScrollableFrame *sf = GetScrollFrame();
if (sf) {
// It seems like it would make more sense for ScrollByPages to use
// SMOOTH mode, but tests seem to depend on the synchronous behaviour.
// Perhaps Web content does too.
sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
aOptions.mBehavior == ScrollBehavior::Smooth
? nsIScrollableFrame::SMOOTH_MSD
: nsIScrollableFrame::INSTANT);
}
}
@ -7245,56 +7357,6 @@ nsGlobalWindow::MozRequestOverfill(OverfillCallback& aCallback,
aError.Throw(NS_ERROR_NOT_AVAILABLE);
}
NS_IMETHODIMP
nsGlobalWindow::ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif)
{
FlushPendingNotifications(Flush_Layout);
nsIScrollableFrame *sf = GetScrollFrame();
if (sf) {
CSSIntPoint scrollPos =
sf->GetScrollPositionCSSPixels() + CSSIntPoint(aXScrollDif, aYScrollDif);
// It seems like it would make more sense for ScrollBy to use
// SMOOTH mode, but tests seem to depend on the synchronous behaviour.
// Perhaps Web content does too.
ScrollTo(scrollPos);
}
return NS_OK;
}
NS_IMETHODIMP
nsGlobalWindow::ScrollByLines(int32_t numLines)
{
FlushPendingNotifications(Flush_Layout);
nsIScrollableFrame *sf = GetScrollFrame();
if (sf) {
// It seems like it would make more sense for ScrollByLines to use
// SMOOTH mode, but tests seem to depend on the synchronous behaviour.
// Perhaps Web content does too.
sf->ScrollBy(nsIntPoint(0, numLines), nsIScrollableFrame::LINES,
nsIScrollableFrame::INSTANT);
}
return NS_OK;
}
NS_IMETHODIMP
nsGlobalWindow::ScrollByPages(int32_t numPages)
{
FlushPendingNotifications(Flush_Layout);
nsIScrollableFrame *sf = GetScrollFrame();
if (sf) {
// It seems like it would make more sense for ScrollByPages to use
// SMOOTH mode, but tests seem to depend on the synchronous behaviour.
// Perhaps Web content does too.
sf->ScrollBy(nsIntPoint(0, numPages), nsIScrollableFrame::PAGES,
nsIScrollableFrame::INSTANT);
}
return NS_OK;
}
void
nsGlobalWindow::ClearTimeout(int32_t aHandle, ErrorResult& aError)
{

View File

@ -49,6 +49,7 @@
#include "nsIDocument.h"
#include "nsIDOMTouchEvent.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/dom/WindowBinding.h"
#include "Units.h"
#include "nsComponentManagerUtils.h"
@ -113,6 +114,7 @@ class External;
class Function;
class Gamepad;
class MediaQueryList;
class MozSelfSupport;
class Navigator;
class OwningExternalOrWindowProxy;
class Selection;
@ -935,6 +937,16 @@ public:
mozilla::ErrorResult& aError);
void ResizeBy(int32_t aWidthDif, int32_t aHeightDif,
mozilla::ErrorResult& aError);
void Scroll(int32_t aXScroll, int32_t aYScroll,
const mozilla::dom::ScrollOptions& aOptions);
void ScrollTo(int32_t aXScroll, int32_t aYScroll,
const mozilla::dom::ScrollOptions& aOptions);
void ScrollBy(int32_t aXScrollDif, int32_t aYScrollDif,
const mozilla::dom::ScrollOptions& aOptions);
void ScrollByLines(int32_t numLines,
const mozilla::dom::ScrollOptions& aOptions);
void ScrollByPages(int32_t numPages,
const mozilla::dom::ScrollOptions& aOptions);
int32_t GetInnerWidth(mozilla::ErrorResult& aError);
void SetInnerWidth(int32_t aInnerWidth, mozilla::ErrorResult& aError);
int32_t GetInnerHeight(mozilla::ErrorResult& aError);
@ -1005,6 +1017,9 @@ public:
bool aWrapAround, bool aWholeWord, bool aSearchInFrames,
bool aShowDialog, mozilla::ErrorResult& aError);
uint64_t GetMozPaintCount(mozilla::ErrorResult& aError);
mozilla::dom::MozSelfSupport* GetMozSelfSupport(mozilla::ErrorResult& aError);
already_AddRefed<nsIDOMWindow> OpenDialog(JSContext* aCx,
const nsAString& aUrl,
const nsAString& aName,
@ -1312,7 +1327,8 @@ public:
mozilla::ErrorResult& aError);
nsRect GetInnerScreenRect();
void ScrollTo(const mozilla::CSSIntPoint& aScroll);
void ScrollTo(const mozilla::CSSIntPoint& aScroll,
const mozilla::dom::ScrollOptions& aOptions);
bool IsFrame()
{
@ -1550,6 +1566,8 @@ protected:
// it wouldn't see the ~External function's declaration.
nsCOMPtr<nsISupports> mExternal;
nsRefPtr<mozilla::dom::MozSelfSupport> mMozSelfSupport;
nsRefPtr<mozilla::dom::DOMStorage> mLocalStorage;
nsRefPtr<mozilla::dom::DOMStorage> mSessionStorage;

View File

@ -313,12 +313,16 @@ enum { WRAPPER_CACHE_FLAGS_BITS_USED = 2 };
NS_DEFINE_STATIC_IID_ACCESSOR(nsWrapperCache, NS_WRAPPERCACHE_IID)
#define NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY \
#define NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY \
if ( aIID.Equals(NS_GET_IID(nsWrapperCache)) ) { \
*aInstancePtr = static_cast<nsWrapperCache*>(this); \
return NS_OK; \
}
#define NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY \
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY \
else
// Cycle collector macros for wrapper caches.

View File

@ -168,11 +168,14 @@ function BrowserElementParent(frameLoader, hasRemoteFrame, isPendingFrame) {
/* wantsUntrusted = */ false);
}
this._doCommandHandlerBinder = this._doCommandHandler.bind(this);
this._frameElement.addEventListener('mozdocommand',
this._doCommandHandler.bind(this),
this._doCommandHandlerBinder,
/* useCapture = */ false,
/* wantsUntrusted = */ false);
Services.obs.addObserver(this, 'ipc:browser-destroyed', /* ownsWeak = */ true);
this._window._browserElementParents.set(this, null);
// Insert ourself into the prompt service.
@ -919,6 +922,13 @@ BrowserElementParent.prototype = {
}
Services.obs.removeObserver(this, 'remote-browser-frame-shown');
}
case 'ipc:browser-destroyed':
if (this._isAlive() && subject == this._frameLoader) {
Services.obs.removeObserver(this, 'ipc:browser-destroyed');
this._frameElement.removeEventListener('mozdocommand',
this._doCommandHandlerBinder)
}
break;
default:
debug('Unknown topic: ' + topic);
break;

View File

@ -172,7 +172,7 @@ DataStore.prototype = {
debug("GetInternal: " + aIds.toSource());
// Creation of the results array.
let results = new Array(aIds.length);
let results = new this._window.Array(aIds.length);
// We're going to create this amount of requests.
let pendingIds = aIds.length;
@ -419,6 +419,10 @@ DataStore.prototype = {
}
}
if (ids.length == 0) {
return this._window.Promise.resolve(new this._window.Array());
}
let self = this;
// Promise<Object>

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for DataStore - basic operation on a readonly db</title>
<script type="text/javascript" src="file_basic_common.js"></script>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7">
function is(a, b, msg) {
ok(a === b, msg);
}
function ok(a, msg) {
alert((a ? 'OK' : 'KO') + ' ' + msg)
}
function finish() {
alert('DONE');
}
navigator.getDataStores('foo').then(function(stores) {
is(stores.length, 1, "getDataStores('foo') returns 1 element");
is(stores[0].name, 'foo', 'The dataStore.name is foo');
is(stores[0].readOnly, false, 'The dataStore foo is not in readonly');
var store = stores[0];
store.get.apply(store, []).then(function(a) {
ok(Array.isArray(a), "bug 1058108");
is(a.length, 0, "bug 1058108");
finish();
});
});
</script>
</body>
</html>

View File

@ -23,6 +23,7 @@ support-files =
file_bug976311.template.webapp
file_bug986056.html
file_bug986056.template.webapp
file_bug1058108.html
file_event_maker.html
file_event_receiver.html
file_transactions.html
@ -51,5 +52,6 @@ support-files =
[test_transactions.html]
[test_bug1008044.html]
[test_bug957086.html]
[test_bug1058108.html]
[test_notify_system_message.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || toolkit == 'win' #bug 1053662 - Timeout prone

View File

@ -0,0 +1,130 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for DataStore - bug 1058108</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<div id="container"></div>
<script type="application/javascript;version=1.7">
var gHostedManifestURL = 'http://test/tests/dom/datastore/tests/file_app.sjs?testToken=file_bug1058108.html';
var gApp;
function cbError() {
ok(false, "Error callback invoked");
finish();
}
function installApp() {
var request = navigator.mozApps.install(gHostedManifestURL);
request.onerror = cbError;
request.onsuccess = function() {
gApp = request.result;
runTest();
}
}
function uninstallApp() {
// Uninstall the app.
var request = navigator.mozApps.mgmt.uninstall(gApp);
request.onerror = cbError;
request.onsuccess = function() {
// All done.
info("All done");
runTest();
}
}
function testApp() {
var ifr = document.createElement('iframe');
ifr.setAttribute('mozbrowser', 'true');
ifr.setAttribute('mozapp', gApp.manifestURL);
ifr.setAttribute('src', gApp.manifest.launch_path);
var domParent = document.getElementById('container');
// Set us up to listen for messages from the app.
var listener = function(e) {
var message = e.detail.message;
if (/^OK/.exec(message)) {
ok(true, "Message from app: " + message);
} else if (/KO/.exec(message)) {
ok(false, "Message from app: " + message);
} else if (/DONE/.exec(message)) {
ok(true, "Messaging from app complete");
ifr.removeEventListener('mozbrowsershowmodalprompt', listener);
domParent.removeChild(ifr);
runTest();
}
}
// This event is triggered when the app calls "alert".
ifr.addEventListener('mozbrowsershowmodalprompt', listener, false);
domParent.appendChild(ifr);
}
var tests = [
// Permissions
function() {
SpecialPowers.pushPermissions(
[{ "type": "browser", "allow": 1, "context": document },
{ "type": "embed-apps", "allow": 1, "context": document },
{ "type": "webapps-manage", "allow": 1, "context": document }], runTest);
},
// Preferences
function() {
SpecialPowers.pushPrefEnv({"set": [["dom.datastore.enabled", true],
["dom.datastore.sysMsgOnChangeShortTimeoutSec", 1],
["dom.datastore.sysMsgOnChangeLongTimeoutSec", 3],
["dom.testing.ignore_ipc_principal", true],
["dom.testing.datastore_enabled_for_hosted_apps", true]]}, runTest);
},
function() {
if (SpecialPowers.isMainProcess()) {
SpecialPowers.Cu.import("resource://gre/modules/DataStoreChangeNotifier.jsm");
}
SpecialPowers.setAllAppsLaunchable(true);
SpecialPowers.setBoolPref("dom.mozBrowserFramesEnabled", true);
runTest();
},
// No confirmation needed when an app is installed
function() {
SpecialPowers.autoConfirmAppInstall(() =>
SpecialPowers.autoConfirmAppUninstall(runTest));
},
// Installing the app
installApp,
// Run tests in app
testApp,
// Uninstall the app
uninstallApp
];
function runTest() {
if (!tests.length) {
finish();
return;
}
var test = tests.shift();
test();
}
function finish() {
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
runTest();
</script>
</body>
</html>

View File

@ -19,7 +19,7 @@ namespace dom {
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PaintRequest, mParent)
NS_INTERFACE_TABLE_HEAD(PaintRequest)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_WRAPPERCACHE_INTERFACE_TABLE_ENTRY
NS_INTERFACE_TABLE(PaintRequest, nsIDOMPaintRequest)
NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(PaintRequest)
NS_INTERFACE_MAP_END

View File

@ -8,7 +8,7 @@
interface nsIDocument;
interface nsIURI;
[uuid(c7132f91-c46c-4e01-b75a-43babb254d93)]
[uuid(91b9d3fc-1654-44da-b438-15123cdbe7aa)]
interface nsIServiceWorkerManager : nsISupports
{
/**
@ -36,6 +36,12 @@ interface nsIServiceWorkerManager : nsISupports
// Returns a Promise
nsISupports getRegistration(in nsIDOMWindow aWindow, in DOMString aScope);
// Returns a Promise
nsISupports getReadyPromise(in nsIDOMWindow aWindow);
// Remove ready pending Promise
void removeReadyPromise(in nsIDOMWindow aWindow);
// aTarget MUST be a ServiceWorkerRegistration.
[noscript] void AddRegistrationEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);
[noscript] void RemoveRegistrationEventListener(in nsIURI aPageURI, in nsIDOMEventTarget aTarget);

View File

@ -853,14 +853,6 @@ ContentParent::PreallocatedProcessReady()
#endif
}
void
ContentParent::RunAfterPreallocatedProcessReady(nsIRunnable* aRequest)
{
#ifdef MOZ_NUWA_PROCESS
PreallocatedProcessManager::RunAfterPreallocatedProcessReady(aRequest);
#endif
}
typedef std::map<ContentParent*, std::set<ContentParent*> > GrandchildMap;
static GrandchildMap sGrandchildProcessMap;

View File

@ -100,7 +100,6 @@ public:
static void JoinAllSubprocesses();
static bool PreallocatedProcessReady();
static void RunAfterPreallocatedProcessReady(nsIRunnable* aRequest);
/**
* Get or create a content process for:

View File

@ -58,7 +58,6 @@ public:
void OnNuwaReady();
bool PreallocatedProcessReady();
already_AddRefed<ContentParent> GetSpareProcess();
void RunAfterPreallocatedProcessReady(nsIRunnable* aRunnable);
private:
void NuwaFork();
@ -70,8 +69,6 @@ private:
// should be enough so we don't need to grow the nsAutoTArray.
nsAutoTArray<nsRefPtr<ContentParent>, 4> mSpareProcesses;
nsTArray<nsCOMPtr<nsIRunnable> > mDelayedContentParentRequests;
// Nuwa process is ready for creating new process.
bool mIsNuwaReady;
#endif
@ -224,16 +221,6 @@ PreallocatedProcessManagerImpl::AllocateNow()
#ifdef MOZ_NUWA_PROCESS
void
PreallocatedProcessManagerImpl::RunAfterPreallocatedProcessReady(nsIRunnable* aRequest)
{
MOZ_ASSERT(NS_IsMainThread());
mDelayedContentParentRequests.AppendElement(aRequest);
// This is an urgent NuwaFork() request. Request to fork at once.
DelayedNuwaFork();
}
void
PreallocatedProcessManagerImpl::ScheduleDelayedNuwaFork()
{
@ -311,12 +298,6 @@ PreallocatedProcessManagerImpl::PublishSpareProcess(ContentParent* aContent)
}
mSpareProcesses.AppendElement(aContent);
if (!mDelayedContentParentRequests.IsEmpty()) {
nsCOMPtr<nsIRunnable> runnable = mDelayedContentParentRequests[0];
mDelayedContentParentRequests.RemoveElementAt(0);
NS_DispatchToMainThread(runnable);
}
}
void
@ -324,13 +305,6 @@ PreallocatedProcessManagerImpl::MaybeForgetSpare(ContentParent* aContent)
{
MOZ_ASSERT(NS_IsMainThread());
if (!mDelayedContentParentRequests.IsEmpty()) {
if (!mPreallocateAppProcessTask) {
// This NuwaFork request is urgent. Don't delay it.
DelayedNuwaFork();
}
}
if (mSpareProcesses.RemoveElement(aContent)) {
return;
}
@ -507,12 +481,6 @@ PreallocatedProcessManager::PreallocatedProcessReady()
return GetPPMImpl()->PreallocatedProcessReady();
}
/* static */ void
PreallocatedProcessManager::RunAfterPreallocatedProcessReady(nsIRunnable* aRequest)
{
GetPPMImpl()->RunAfterPreallocatedProcessReady(aRequest);
}
#endif
} // namespace mozilla

View File

@ -86,7 +86,6 @@ public:
static bool IsNuwaReady();
static void OnNuwaReady();
static bool PreallocatedProcessReady();
static void RunAfterPreallocatedProcessReady(nsIRunnable* aRunnable);
#endif
private:

View File

@ -303,6 +303,9 @@ function RTCPeerConnection() {
this._onCreateAnswerFailure = null;
this._onGetStatsSuccess = null;
this._onGetStatsFailure = null;
this._onReplaceTrackSender = null;
this._onReplaceTrackSuccess = null;
this._onReplaceTrackFailure = null;
this._pendingType = null;
this._localType = null;
@ -812,7 +815,8 @@ RTCPeerConnection.prototype = {
this._checkClosed();
this._impl.addTrack(track, stream);
let sender = this._win.RTCRtpSender._create(this._win,
new RTCRtpSender(this, track));
new RTCRtpSender(this, track,
stream));
this._senders.push({ sender: sender, stream: stream });
return sender;
},
@ -822,6 +826,24 @@ RTCPeerConnection.prototype = {
throw new this._win.DOMError("", "removeTrack not yet implemented");
},
_replaceTrack: function(sender, withTrack, onSuccess, onError) {
// TODO: Do a (sender._stream.getTracks().indexOf(track) == -1) check
// on both track args someday.
//
// The proposed API will be that both tracks must already be in the same
// stream. However, since our MediaStreams currently are limited to one
// track per type, we allow replacement with an outside track not already
// in the same stream.
//
// Since a track may be replaced more than once, the track being replaced
// may not be in the stream either, so we check neither arg right now.
this._onReplaceTrackSender = sender;
this._onReplaceTrackSuccess = onSuccess;
this._onReplaceTrackFailure = onError;
this._impl.replaceTrack(sender.track, withTrack, sender._stream);
},
close: function() {
if (this._closed) {
return;
@ -1306,6 +1328,15 @@ PeerConnectionObserver.prototype = {
{ track: track }));
},
onReplaceTrackSuccess: function() {
this._dompc.callCB(this._dompc._onReplaceTrackSuccess);
},
onReplaceTrackError: function(code, message) {
this._dompc.callCB(this._dompc._onReplaceTrackError,
new RTCError(code, message));
},
foundIceCandidate: function(cand) {
this.dispatchEvent(new this._dompc._win.RTCPeerConnectionIceEvent("icecandidate",
{ candidate: cand } ));
@ -1337,15 +1368,25 @@ RTCPeerConnectionStatic.prototype = {
},
};
function RTCRtpSender(pc, track) {
this.pc = pc;
function RTCRtpSender(pc, track, stream) {
this._pc = pc;
this.track = track;
this._stream = stream;
}
RTCRtpSender.prototype = {
classDescription: "RTCRtpSender",
classID: PC_SENDER_CID,
contractID: PC_SENDER_CONTRACT,
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupports]),
replaceTrack: function(withTrack, onSuccess, onError) {
this._pc._checkClosed();
this._pc._queueOrRun({
func: this._pc._replaceTrack,
args: [this, withTrack, onSuccess, onError],
wait: false
});
}
};
function RTCRtpReceiver(pc, track) {

View File

@ -170,10 +170,12 @@ class FakeVideoEncoder : public GMPVideoEncoder {
GMPVideoEncodedFrame* f = static_cast<GMPVideoEncodedFrame*> (ftmp);
// Encode this in a frame that looks a little bit like H.264.
// Note that we don't do PPS or SPS.
// Copy the data. This really should convert this to network byte order.
EncodedFrame eframe;
eframe.length_ = sizeof(eframe) - sizeof(uint32_t);
eframe.h264_compat_ = 'g';
eframe.h264_compat_ = 5; // Emulate a H.264 IDR NAL.
eframe.magic_ = ENCODED_FRAME_MAGIC;
eframe.width_ = inputImage->Width();
eframe.height_ = inputImage->Height();

View File

@ -87,6 +87,8 @@ skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabl
skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_offerRequiresReceiveVideoAudio.html]
skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_replaceTrack.html]
skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g)
[test_peerConnection_setLocalAnswerInHaveLocalOffer.html]
[test_peerConnection_setLocalAnswerInStable.html]
[test_peerConnection_setLocalOfferInHaveRemoteOffer.html]

View File

@ -0,0 +1,64 @@
<!DOCTYPE HTML>
<html>
<head>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="head.js"></script>
<script type="application/javascript" src="mediaStreamPlayback.js"></script>
<script type="application/javascript" src="pc.js"></script>
<script type="application/javascript" src="templates.js"></script>
<script type="application/javascript" src="turnConfig.js"></script>
</head>
<body>
<pre id="test">
<script type="application/javascript;version=1.8">
createHTML({
bug: "1032839",
title: "Replace video track",
visible: true
});
function isSenderOfTrack(sender) {
return sender.track == this;
}
// Test basically just verifies that success callback is called at this point
var test;
runNetworkTest(function () {
test = new PeerConnectionTest();
test.setMediaConstraints([{video: true}], [{video: true}]);
test.chain.removeAfter("PC_REMOTE_CHECK_MEDIA_FLOW_PRESENT");
var flowtest = test.chain.remove("PC_REMOTE_CHECK_MEDIA_FLOW_PRESENT");
test.chain.append(flowtest);
test.chain.append([["PC_LOCAL_REPLACE_VIDEOTRACK",
function (test) {
var stream = test.pcLocal._pc.getLocalStreams()[0];
var track = stream.getVideoTracks()[0];
var sender = test.pcLocal._pc.getSenders().find(isSenderOfTrack, track);
ok(sender, "track has a sender");
navigator.mozGetUserMedia({video:true, fake: true}, function(newStream) {
sender.replaceTrack(newStream.getVideoTracks()[0],
function() {
ok(true, "replaceTrack success callback is called");
test.next();
},
function(err) {
ok(false, "replaceTrack failed with error = " + err);
test.next();
});
},
function(err) {
ok(false, "mozGetUserMedia failed. error = " + err);
test.next();
});
}
]]);
test.chain.append(flowtest);
test.run();
});
</script>
</pre>
</body>
</html>

View File

@ -6,6 +6,7 @@
#include "nsINetAddr.idl"
interface nsIUDPSocketInternal;
interface nsIInputStream;
%{ C++
namespace mozilla {
@ -17,7 +18,7 @@ union NetAddr;
native NetAddr(mozilla::net::NetAddr);
[ptr] native NetAddrPtr(mozilla::net::NetAddr);
[scriptable, uuid(B47E5A0F-D384-48EF-8885-4259793D9CF0)]
[scriptable, uuid(5bb7de5a-8766-4c13-b9ed-14e63168dabf)]
interface nsIUDPSocketChild : nsISupports
{
readonly attribute unsigned short localPort;
@ -25,7 +26,8 @@ interface nsIUDPSocketChild : nsISupports
attribute AUTF8String filterName;
// Tell the chrome process to bind the UDP socket to a given local host and port
void bind(in nsIUDPSocketInternal socket, in AUTF8String host, in unsigned short port);
void bind(in nsIUDPSocketInternal socket, in AUTF8String host, in unsigned short port,
in bool addressReuse, in bool loopback);
// Tell the chrome process to perform equivalent operations to all following methods
void send(in AUTF8String host, in unsigned short port,
@ -38,21 +40,28 @@ interface nsIUDPSocketChild : nsISupports
[noscript] void sendWithAddress([const] in NetAddrPtr addr,
[const, array, size_is(byteLength)] in uint8_t bytes,
in unsigned long byteLength);
// Send input stream. This must be a buffered stream implementation.
void sendBinaryStream(in AUTF8String host, in unsigned short port, in nsIInputStream stream);
void close();
void joinMulticast(in AUTF8String multicastAddress, in AUTF8String iface);
void leaveMulticast(in AUTF8String multicastAddress, in AUTF8String iface);
};
/*
* Internal interface for callback from chrome process
*/
[scriptable, uuid(1E27E9B3-C1C8-4B05-A415-1A2C1A641C60)]
[scriptable, uuid(44cd9ad5-d574-4169-baf9-e1af0648a143)]
interface nsIUDPSocketInternal : nsISupports
{
void callListenerError(in AUTF8String type, in AUTF8String message, in AUTF8String filename,
in uint32_t lineNumber, in uint32_t columnNumber);
void callListenerReceivedData(in AUTF8String type, in AUTF8String host, in unsigned short port,
[array, size_is(dataLength)] in uint8_t data,
// callback while socket is opened. localPort and localAddress is ready until this time.
void callListenerOpened();
// callback while socket is closed.
void callListenerClosed();
// callback while incoming packet is received.
void callListenerReceivedData(in AUTF8String host, in unsigned short port,
[const, array, size_is(dataLength)] in uint8_t data,
in unsigned long dataLength);
void callListenerVoid(in AUTF8String type);
void callListenerSent(in AUTF8String type, in nsresult status);
void updateReadyState(in AUTF8String readyState);
// callback while any error happened.
void callListenerError(in AUTF8String message, in AUTF8String filename, in uint32_t lineNumber);
};

View File

@ -6,6 +6,8 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
include protocol PNecko;
include protocol PBlob;
include InputStreamParams;
include "mozilla/net/NeckoMessageUtils.h";
include "mozilla/net/DNS.h";
@ -14,34 +16,19 @@ include "prio.h";
using mozilla::net::NetAddr from "mozilla/net/DNS.h";
using struct mozilla::void_t from "ipc/IPCMessageUtils.h";
struct UDPError {
nsCString message;
nsCString filename;
uint32_t lineNumber;
uint32_t columnNumber;
};
struct UDPMessage {
nsCString fromAddr;
uint16_t port;
uint8_t[] data;
};
struct UDPAddressInfo {
nsCString local;
nsCString addr;
uint16_t port;
};
struct UDPSendResult {
nsresult value;
union UDPSocketAddr {
UDPAddressInfo;
NetAddr;
};
union UDPCallbackData {
void_t;
UDPMessage;
UDPAddressInfo;
UDPSendResult;
UDPError;
union UDPData {
uint8_t[];
InputStreamParams;
};
namespace mozilla {
@ -53,13 +40,22 @@ protocol PUDPSocket
manager PNecko;
parent:
Data(uint8_t[] data, nsCString remoteAddress, uint16_t port);
DataWithAddress(uint8_t[] data, NetAddr addr);
Bind(UDPAddressInfo addressInfo, bool addressReuse, bool loopback);
OutgoingData(UDPData data, UDPSocketAddr addr);
JoinMulticast(nsCString multicastAddress, nsCString iface);
LeaveMulticast(nsCString multicastAddress, nsCString iface);
Close();
RequestDelete();
child:
Callback(nsCString type, UDPCallbackData data, nsCString aState);
CallbackOpened(UDPAddressInfo addressInfo);
CallbackClosed();
CallbackReceivedData(UDPAddressInfo addressInfo, uint8_t[] data);
CallbackError(nsCString message, nsCString filename, uint32_t lineNumber);
__delete__();
};

View File

@ -0,0 +1,705 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* 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 "UDPSocket.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/dom/ErrorEvent.h"
#include "mozilla/dom/UDPMessageEvent.h"
#include "mozilla/dom/UDPSocketBinding.h"
#include "mozilla/dom/UnionTypes.h"
#include "mozilla/net/DNS.h"
#include "nsComponentManagerUtils.h"
#include "nsContentUtils.h"
#include "nsIDOMFile.h"
#include "nsINetAddr.h"
#include "nsStringStream.h"
namespace mozilla {
namespace dom {
NS_IMPL_CYCLE_COLLECTION_CLASS(UDPSocket)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(UDPSocket, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOpened)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mClosed)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(UDPSocket, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mOpened)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mClosed)
tmp->CloseWithReason(NS_OK);
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_ADDREF_INHERITED(UDPSocket, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(UDPSocket, DOMEventTargetHelper)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(UDPSocket)
NS_INTERFACE_MAP_ENTRY(nsIUDPSocketListener)
NS_INTERFACE_MAP_ENTRY(nsIUDPSocketInternal)
NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
/* static */ already_AddRefed<UDPSocket>
UDPSocket::Constructor(const GlobalObject& aGlobal,
const UDPOptions& aOptions,
ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> ownerWindow = do_QueryInterface(aGlobal.GetAsSupports());
if (!ownerWindow) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
bool addressReuse = aOptions.mAddressReuse;
bool loopback = aOptions.mLoopback;
nsCString remoteAddress;
if (aOptions.mRemoteAddress.WasPassed()) {
remoteAddress = NS_ConvertUTF16toUTF8(aOptions.mRemoteAddress.Value());
} else {
remoteAddress.SetIsVoid(true);
}
Nullable<uint16_t> remotePort;
if (aOptions.mRemotePort.WasPassed()) {
remotePort.SetValue(aOptions.mRemotePort.Value());
if (remotePort.Value() == 0) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return nullptr;
}
}
nsString localAddress;
if (aOptions.mLocalAddress.WasPassed()) {
localAddress = aOptions.mLocalAddress.Value();
// check if localAddress is a valid IPv4/6 address
NS_ConvertUTF16toUTF8 address(localAddress);
PRNetAddr prAddr;
PRStatus status = PR_StringToNetAddr(address.BeginReading(), &prAddr);
if (status != PR_SUCCESS) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return nullptr;
}
} else {
SetDOMStringToNull(localAddress);
}
Nullable<uint16_t> localPort;
if (aOptions.mLocalPort.WasPassed()) {
localPort.SetValue(aOptions.mLocalPort.Value());
if (localPort.Value() == 0) {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return nullptr;
}
}
nsRefPtr<UDPSocket> socket = new UDPSocket(ownerWindow, remoteAddress, remotePort);
aRv = socket->Init(localAddress, localPort, addressReuse, loopback);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
return socket.forget();
}
UDPSocket::UDPSocket(nsPIDOMWindow* aOwner,
const nsCString& aRemoteAddress,
const Nullable<uint16_t>& aRemotePort)
: DOMEventTargetHelper(aOwner)
, mRemoteAddress(aRemoteAddress)
, mRemotePort(aRemotePort)
, mReadyState(SocketReadyState::Opening)
{
MOZ_ASSERT(aOwner);
MOZ_ASSERT(aOwner->IsInnerWindow());
nsIDocument* aDoc = aOwner->GetExtantDoc();
if (aDoc) {
aDoc->DisallowBFCaching();
}
}
UDPSocket::~UDPSocket()
{
CloseWithReason(NS_OK);
}
JSObject*
UDPSocket::WrapObject(JSContext* aCx)
{
return UDPSocketBinding::Wrap(aCx, this);
}
void
UDPSocket::DisconnectFromOwner()
{
DOMEventTargetHelper::DisconnectFromOwner();
CloseWithReason(NS_OK);
}
already_AddRefed<Promise>
UDPSocket::Close()
{
MOZ_ASSERT(mClosed);
nsRefPtr<Promise> promise = mClosed;
if (mReadyState == SocketReadyState::Closed) {
return promise.forget();
}
CloseWithReason(NS_OK);
return promise.forget();
}
void
UDPSocket::CloseWithReason(nsresult aReason)
{
if (mReadyState == SocketReadyState::Closed) {
return;
}
if (mOpened) {
if (mReadyState == SocketReadyState::Opening) {
// reject openedPromise with AbortError if socket is closed without error
nsresult openFailedReason = NS_FAILED(aReason) ? aReason : NS_ERROR_DOM_ABORT_ERR;
mOpened->MaybeReject(openFailedReason);
}
}
mReadyState = SocketReadyState::Closed;
if (mSocket) {
mSocket->Close();
mSocket = nullptr;
}
if (mSocketChild) {
mSocketChild->Close();
mSocketChild = nullptr;
}
if (mClosed) {
if (NS_SUCCEEDED(aReason)) {
mClosed->MaybeResolve(JS::UndefinedHandleValue);
} else {
mClosed->MaybeReject(aReason);
}
}
mPendingMcastCommands.Clear();
}
void
UDPSocket::JoinMulticastGroup(const nsAString& aMulticastGroupAddress,
ErrorResult& aRv)
{
if (mReadyState == SocketReadyState::Closed) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (mReadyState == SocketReadyState::Opening) {
MulticastCommand joinCommand(MulticastCommand::Join, aMulticastGroupAddress);
mPendingMcastCommands.AppendElement(joinCommand);
return;
}
MOZ_ASSERT(mSocket || mSocketChild);
NS_ConvertUTF16toUTF8 address(aMulticastGroupAddress);
if (mSocket) {
MOZ_ASSERT(!mSocketChild);
aRv = mSocket->JoinMulticast(address, EmptyCString());
NS_WARN_IF(aRv.Failed());
return;
}
MOZ_ASSERT(mSocketChild);
aRv = mSocketChild->JoinMulticast(address, EmptyCString());
NS_WARN_IF(aRv.Failed());
}
void
UDPSocket::LeaveMulticastGroup(const nsAString& aMulticastGroupAddress,
ErrorResult& aRv)
{
if (mReadyState == SocketReadyState::Closed) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return;
}
if (mReadyState == SocketReadyState::Opening) {
MulticastCommand leaveCommand(MulticastCommand::Leave, aMulticastGroupAddress);
mPendingMcastCommands.AppendElement(leaveCommand);
return;
}
MOZ_ASSERT(mSocket || mSocketChild);
nsCString address = NS_ConvertUTF16toUTF8(aMulticastGroupAddress);
if (mSocket) {
MOZ_ASSERT(!mSocketChild);
aRv = mSocket->LeaveMulticast(address, EmptyCString());
NS_WARN_IF(aRv.Failed());
return;
}
MOZ_ASSERT(mSocketChild);
aRv = mSocketChild->LeaveMulticast(address, EmptyCString());
NS_WARN_IF(aRv.Failed());
}
nsresult
UDPSocket::DoPendingMcastCommand()
{
MOZ_ASSERT(mReadyState == SocketReadyState::Open, "Multicast command can only be executed after socket opened");
for (uint32_t i = 0; i < mPendingMcastCommands.Length(); ++i) {
MulticastCommand& command = mPendingMcastCommands[i];
ErrorResult rv;
switch (command.mCommand) {
case MulticastCommand::Join: {
JoinMulticastGroup(command.mAddress, rv);
break;
}
case MulticastCommand::Leave: {
LeaveMulticastGroup(command.mAddress, rv);
break;
}
}
if (NS_WARN_IF(rv.Failed())) {
return rv.ErrorCode();
}
}
mPendingMcastCommands.Clear();
return NS_OK;
}
bool
UDPSocket::Send(const StringOrBlobOrArrayBufferOrArrayBufferView& aData,
const Optional<nsAString>& aRemoteAddress,
const Optional<Nullable<uint16_t>>& aRemotePort,
ErrorResult& aRv)
{
if (mReadyState != SocketReadyState::Open) {
aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
return false;
}
MOZ_ASSERT(mSocket || mSocketChild);
// If the remote address and port were not specified in the constructor or as arguments,
// throw InvalidAccessError.
nsCString remoteAddress;
if (aRemoteAddress.WasPassed()) {
remoteAddress = NS_ConvertUTF16toUTF8(aRemoteAddress.Value());
} else if (!mRemoteAddress.IsVoid()) {
remoteAddress = mRemoteAddress;
} else {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return false;
}
uint16_t remotePort;
if (aRemotePort.WasPassed() && !aRemotePort.Value().IsNull()) {
remotePort = aRemotePort.Value().Value();
} else if (!mRemotePort.IsNull()) {
remotePort = mRemotePort.Value();
} else {
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
return false;
}
nsCOMPtr<nsIInputStream> stream;
if (aData.IsBlob()) {
nsCOMPtr<nsIDOMBlob> blob = aData.GetAsBlob();
aRv = blob->GetInternalStream(getter_AddRefs(stream));
if (NS_WARN_IF(aRv.Failed())) {
return false;
}
} else {
nsresult rv;
nsCOMPtr<nsIStringInputStream> strStream = do_CreateInstance(NS_STRINGINPUTSTREAM_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
return false;
}
if (aData.IsString()) {
NS_ConvertUTF16toUTF8 data(aData.GetAsString());
aRv = strStream->SetData(data.BeginReading(), data.Length());
} else if (aData.IsArrayBuffer()) {
const ArrayBuffer& data = aData.GetAsArrayBuffer();
data.ComputeLengthAndData();
aRv = strStream->SetData(reinterpret_cast<const char*>(data.Data()), data.Length());
} else {
const ArrayBufferView& data = aData.GetAsArrayBufferView();
data.ComputeLengthAndData();
aRv = strStream->SetData(reinterpret_cast<const char*>(data.Data()), data.Length());
}
if (NS_WARN_IF(aRv.Failed())) {
return false;
}
stream = strStream;
}
if (mSocket) {
aRv = mSocket->SendBinaryStream(remoteAddress, remotePort, stream);
} else if (mSocketChild) {
aRv = mSocketChild->SendBinaryStream(remoteAddress, remotePort, stream);
}
if (NS_WARN_IF(aRv.Failed())) {
return false;
}
return true;
}
nsresult
UDPSocket::InitLocal(const nsAString& aLocalAddress,
const uint16_t& aLocalPort)
{
nsresult rv;
nsCOMPtr<nsIUDPSocket> sock =
do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
if (NS_FAILED(rv)) {
return rv;
}
if (aLocalAddress.IsEmpty()) {
rv = sock->Init(aLocalPort, /* loopback = */ false, mAddressReuse, /* optionalArgc = */ 1);
} else {
PRNetAddr prAddr;
PR_InitializeNetAddr(PR_IpAddrAny, aLocalPort, &prAddr);
PR_StringToNetAddr(NS_ConvertUTF16toUTF8(aLocalAddress).BeginReading(), &prAddr);
mozilla::net::NetAddr addr;
PRNetAddrToNetAddr(&prAddr, &addr);
rv = sock->InitWithAddress(&addr, mAddressReuse, /* optionalArgc = */ 1);
}
if (NS_FAILED(rv)) {
return rv;
}
rv = sock->SetMulticastLoopback(mLoopback);
if (NS_FAILED(rv)) {
return rv;
}
mSocket = sock;
// Get real local address and local port
nsCOMPtr<nsINetAddr> localAddr;
rv = mSocket->GetLocalAddr(getter_AddRefs(localAddr));
if (NS_FAILED(rv)) {
return rv;
}
nsCString localAddress;
rv = localAddr->GetAddress(localAddress);
if (NS_FAILED(rv)) {
return rv;
}
mLocalAddress = NS_ConvertUTF8toUTF16(localAddress);
uint16_t localPort;
rv = localAddr->GetPort(&localPort);
if (NS_FAILED(rv)) {
return rv;
}
mLocalPort.SetValue(localPort);
rv = mSocket->AsyncListen(this);
if (NS_FAILED(rv)) {
return rv;
}
mReadyState = SocketReadyState::Open;
rv = DoPendingMcastCommand();
if (NS_FAILED(rv)) {
return rv;
}
mOpened->MaybeResolve(JS::UndefinedHandleValue);
return NS_OK;
}
nsresult
UDPSocket::InitRemote(const nsAString& aLocalAddress,
const uint16_t& aLocalPort)
{
nsresult rv;
nsCOMPtr<nsIUDPSocketChild> sock =
do_CreateInstance("@mozilla.org/udp-socket-child;1", &rv);
if (NS_FAILED(rv)) {
return rv;
}
rv = sock->Bind(this, NS_ConvertUTF16toUTF8(aLocalAddress), aLocalPort, mAddressReuse, mLoopback);
if (NS_FAILED(rv)) {
return rv;
}
mSocketChild = sock;
return NS_OK;
}
nsresult
UDPSocket::Init(const nsString& aLocalAddress,
const Nullable<uint16_t>& aLocalPort,
const bool& aAddressReuse,
const bool& aLoopback)
{
MOZ_ASSERT(!mSocket && !mSocketChild);
mLocalAddress = aLocalAddress;
mLocalPort = aLocalPort;
mAddressReuse = aAddressReuse;
mLoopback = aLoopback;
ErrorResult rv;
nsCOMPtr<nsIGlobalObject> global = do_QueryInterface(GetOwner());
mOpened = Promise::Create(global, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.ErrorCode();
}
mClosed = Promise::Create(global, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.ErrorCode();
}
class OpenSocketRunnable MOZ_FINAL : public nsRunnable
{
public:
OpenSocketRunnable(UDPSocket* aSocket) : mSocket(aSocket)
{ }
NS_IMETHOD Run() MOZ_OVERRIDE
{
MOZ_ASSERT(mSocket);
if (mSocket->mReadyState != SocketReadyState::Opening) {
return NS_OK;
}
uint16_t localPort = 0;
if (!mSocket->mLocalPort.IsNull()) {
localPort = mSocket->mLocalPort.Value();
}
nsresult rv;
if (XRE_GetProcessType() != GeckoProcessType_Default) {
rv = mSocket->InitRemote(mSocket->mLocalAddress, localPort);
} else {
rv = mSocket->InitLocal(mSocket->mLocalAddress, localPort);
}
if (NS_WARN_IF(NS_FAILED(rv))) {
mSocket->CloseWithReason(NS_ERROR_DOM_NETWORK_ERR);
}
return NS_OK;
}
private:
nsRefPtr<UDPSocket> mSocket;
};
nsCOMPtr<nsIRunnable> runnable = new OpenSocketRunnable(this);
return NS_DispatchToMainThread(runnable);
}
void
UDPSocket::HandleReceivedData(const nsACString& aRemoteAddress,
const uint16_t& aRemotePort,
const uint8_t* aData,
const uint32_t& aDataLength)
{
if (mReadyState != SocketReadyState::Open) {
return;
}
if (NS_FAILED(CheckInnerWindowCorrectness())) {
return;
}
if (NS_FAILED(DispatchReceivedData(aRemoteAddress, aRemotePort, aData, aDataLength))) {
CloseWithReason(NS_ERROR_TYPE_ERR);
}
}
nsresult
UDPSocket::DispatchReceivedData(const nsACString& aRemoteAddress,
const uint16_t& aRemotePort,
const uint8_t* aData,
const uint32_t& aDataLength)
{
AutoJSAPI jsapi;
if (NS_WARN_IF(!jsapi.Init(GetOwner()))) {
return NS_ERROR_FAILURE;
}
JSContext* cx = jsapi.cx();
// Copy packet data to ArrayBuffer
JS::Rooted<JSObject*> arrayBuf(cx, ArrayBuffer::Create(cx, aDataLength, aData));
if (NS_WARN_IF(!arrayBuf)) {
return NS_ERROR_FAILURE;
}
JS::Rooted<JS::Value> jsData(cx, JS::ObjectValue(*arrayBuf));
// Create DOM event
RootedDictionary<UDPMessageEventInit> init(cx);
init.mRemoteAddress = NS_ConvertUTF8toUTF16(aRemoteAddress);
init.mRemotePort = aRemotePort;
init.mData = jsData;
nsRefPtr<UDPMessageEvent> udpEvent =
UDPMessageEvent::Constructor(this, NS_LITERAL_STRING("message"), init);
if (NS_WARN_IF(!udpEvent)) {
return NS_ERROR_FAILURE;
}
udpEvent->SetTrusted(true);
nsRefPtr<AsyncEventDispatcher> asyncDispatcher = new AsyncEventDispatcher(this, udpEvent);
return asyncDispatcher->PostDOMEvent();
}
// nsIUDPSocketListener
NS_IMETHODIMP
UDPSocket::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage)
{
// nsIUDPSocketListener callbacks should be invoked on main thread.
MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
// Create appropriate JS object for message
FallibleTArray<uint8_t>& buffer = aMessage->GetDataAsTArray();
nsCOMPtr<nsINetAddr> addr;
if (NS_WARN_IF(NS_FAILED(aMessage->GetFromAddr(getter_AddRefs(addr))))) {
return NS_OK;
}
nsCString remoteAddress;
if (NS_WARN_IF(NS_FAILED(addr->GetAddress(remoteAddress)))) {
return NS_OK;
}
uint16_t remotePort;
if (NS_WARN_IF(NS_FAILED(addr->GetPort(&remotePort)))) {
return NS_OK;
}
HandleReceivedData(remoteAddress, remotePort, buffer.Elements(), buffer.Length());
return NS_OK;
}
NS_IMETHODIMP
UDPSocket::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus)
{
// nsIUDPSocketListener callbacks should be invoked on main thread.
MOZ_ASSERT(NS_IsMainThread(), "Not running on main thread");
CloseWithReason(aStatus);
return NS_OK;
}
// nsIUDPSocketInternal
NS_IMETHODIMP
UDPSocket::CallListenerError(const nsACString& aMessage,
const nsACString& aFilename,
uint32_t aLineNumber)
{
CloseWithReason(NS_ERROR_DOM_NETWORK_ERR);
return NS_OK;
}
NS_IMETHODIMP
UDPSocket::CallListenerReceivedData(const nsACString& aRemoteAddress,
uint16_t aRemotePort,
const uint8_t* aData,
uint32_t aDataLength)
{
HandleReceivedData(aRemoteAddress, aRemotePort, aData, aDataLength);
return NS_OK;
}
NS_IMETHODIMP
UDPSocket::CallListenerOpened()
{
if (mReadyState != SocketReadyState::Opening) {
return NS_OK;
}
MOZ_ASSERT(mSocketChild);
// Get real local address and local port
nsCString localAddress;
mSocketChild->GetLocalAddress(localAddress);
mLocalAddress = NS_ConvertUTF8toUTF16(localAddress);
uint16_t localPort;
mSocketChild->GetLocalPort(&localPort);
mLocalPort.SetValue(localPort);
mReadyState = SocketReadyState::Open;
nsresult rv = DoPendingMcastCommand();
if (NS_WARN_IF(NS_FAILED(rv))) {
CloseWithReason(rv);
return NS_OK;
}
mOpened->MaybeResolve(JS::UndefinedHandleValue);
return NS_OK;
}
NS_IMETHODIMP
UDPSocket::CallListenerClosed()
{
CloseWithReason(NS_OK);
return NS_OK;
}
} // namespace dom
} // namespace mozilla

197
dom/network/src/UDPSocket.h Normal file
View File

@ -0,0 +1,197 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_UDPSocket_h__
#define mozilla_dom_UDPSocket_h__
#include "mozilla/Attributes.h"
#include "mozilla/DOMEventTargetHelper.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/Promise.h"
#include "mozilla/dom/SocketCommonBinding.h"
#include "nsIUDPSocket.h"
#include "nsIUDPSocketChild.h"
#include "nsTArray.h"
struct JSContext;
namespace mozilla {
namespace dom {
struct UDPOptions;
class StringOrBlobOrArrayBufferOrArrayBufferView;
class UDPSocket MOZ_FINAL : public DOMEventTargetHelper
, public nsIUDPSocketListener
, public nsIUDPSocketInternal
{
public:
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(UDPSocket, DOMEventTargetHelper)
NS_DECL_NSIUDPSOCKETLISTENER
NS_DECL_NSIUDPSOCKETINTERNAL
NS_REALLY_FORWARD_NSIDOMEVENTTARGET(DOMEventTargetHelper)
public:
nsPIDOMWindow*
GetParentObject() const
{
return GetOwner();
}
virtual JSObject*
WrapObject(JSContext* aCx) MOZ_OVERRIDE;
virtual void
DisconnectFromOwner() MOZ_OVERRIDE;
static already_AddRefed<UDPSocket>
Constructor(const GlobalObject& aGlobal, const UDPOptions& aOptions, ErrorResult& aRv);
void
GetLocalAddress(nsString& aRetVal) const
{
aRetVal = mLocalAddress;
}
Nullable<uint16_t>
GetLocalPort() const
{
return mLocalPort;
}
void
GetRemoteAddress(nsString& aRetVal) const
{
if (mRemoteAddress.IsVoid()) {
SetDOMStringToNull(aRetVal);
return;
}
aRetVal = NS_ConvertUTF8toUTF16(mRemoteAddress);
}
Nullable<uint16_t>
GetRemotePort() const
{
return mRemotePort;
}
bool
AddressReuse() const
{
return mAddressReuse;
}
bool
Loopback() const
{
return mLoopback;
}
SocketReadyState
ReadyState() const
{
return mReadyState;
}
Promise*
Opened() const
{
return mOpened;
}
Promise*
Closed() const
{
return mClosed;
}
IMPL_EVENT_HANDLER(message)
already_AddRefed<Promise>
Close();
void
JoinMulticastGroup(const nsAString& aMulticastGroupAddress, ErrorResult& aRv);
void
LeaveMulticastGroup(const nsAString& aMulticastGroupAddress, ErrorResult& aRv);
bool
Send(const StringOrBlobOrArrayBufferOrArrayBufferView& aData,
const Optional<nsAString>& aRemoteAddress,
const Optional<Nullable<uint16_t>>& aRemotePort,
ErrorResult& aRv);
private:
UDPSocket(nsPIDOMWindow* aOwner,
const nsCString& aRemoteAddress,
const Nullable<uint16_t>& aRemotePort);
virtual ~UDPSocket();
nsresult
Init(const nsString& aLocalAddress,
const Nullable<uint16_t>& aLocalPort,
const bool& aAddressReuse,
const bool& aLoopback);
nsresult
InitLocal(const nsAString& aLocalAddress, const uint16_t& aLocalPort);
nsresult
InitRemote(const nsAString& aLocalAddress, const uint16_t& aLocalPort);
void
HandleReceivedData(const nsACString& aRemoteAddress,
const uint16_t& aRemotePort,
const uint8_t* aData,
const uint32_t& aDataLength);
nsresult
DispatchReceivedData(const nsACString& aRemoteAddress,
const uint16_t& aRemotePort,
const uint8_t* aData,
const uint32_t& aDataLength);
void
CloseWithReason(nsresult aReason);
nsresult
DoPendingMcastCommand();
nsString mLocalAddress;
Nullable<uint16_t> mLocalPort;
nsCString mRemoteAddress;
Nullable<uint16_t> mRemotePort;
bool mAddressReuse;
bool mLoopback;
SocketReadyState mReadyState;
nsRefPtr<Promise> mOpened;
nsRefPtr<Promise> mClosed;
nsCOMPtr<nsIUDPSocket> mSocket;
nsCOMPtr<nsIUDPSocketChild> mSocketChild;
struct MulticastCommand {
enum CommandType { Join, Leave };
MulticastCommand(CommandType aCommand, const nsAString& aAddress)
: mCommand(aCommand), mAddress(aAddress)
{ }
CommandType mCommand;
nsString mAddress;
};
nsTArray<MulticastCommand> mPendingMcastCommands;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_UDPSocket_h__

View File

@ -3,6 +3,8 @@
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "UDPSocketChild.h"
#include "mozilla/unused.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/net/NeckoChild.h"
using mozilla::net::gNeckoChild;
@ -59,17 +61,20 @@ UDPSocketChild::~UDPSocketChild()
// nsIUDPSocketChild Methods
NS_IMETHODIMP
UDPSocketChild::Bind(nsIUDPSocketInternal *aSocket,
UDPSocketChild::Bind(nsIUDPSocketInternal* aSocket,
const nsACString& aHost,
uint16_t aPort)
uint16_t aPort,
bool aAddressReuse,
bool aLoopback)
{
NS_ENSURE_ARG(aSocket);
mSocket = aSocket;
AddIPDLReference();
gNeckoChild->SendPUDPSocketConstructor(this, nsCString(aHost), aPort, mFilterName);
gNeckoChild->SendPUDPSocketConstructor(this, mFilterName);
SendBind(UDPAddressInfo(nsCString(aHost), aPort), aAddressReuse, aLoopback);
return NS_OK;
}
@ -83,26 +88,18 @@ UDPSocketChild::Close()
NS_IMETHODIMP
UDPSocketChild::Send(const nsACString& aHost,
uint16_t aPort,
const uint8_t *aData,
const uint8_t* aData,
uint32_t aByteLength)
{
NS_ENSURE_ARG(aData);
FallibleTArray<uint8_t> fallibleArray;
if (!fallibleArray.InsertElementsAt(0, aData, aByteLength)) {
return NS_ERROR_OUT_OF_MEMORY;
}
InfallibleTArray<uint8_t> array;
array.SwapElements(fallibleArray);
SendData(array, nsCString(aHost), aPort);
return NS_OK;
return SendDataInternal(UDPSocketAddr(UDPAddressInfo(nsCString(aHost), aPort)),
aData, aByteLength);
}
NS_IMETHODIMP
UDPSocketChild::SendWithAddr(nsINetAddr *aAddr,
const uint8_t *aData,
UDPSocketChild::SendWithAddr(nsINetAddr* aAddr,
const uint8_t* aData,
uint32_t aByteLength)
{
NS_ENSURE_ARG(aAddr);
@ -111,17 +108,27 @@ UDPSocketChild::SendWithAddr(nsINetAddr *aAddr,
NetAddr addr;
aAddr->GetNetAddr(&addr);
return SendWithAddress(&addr, aData, aByteLength);
return SendDataInternal(UDPSocketAddr(addr), aData, aByteLength);
}
NS_IMETHODIMP
UDPSocketChild::SendWithAddress(const NetAddr *aAddr,
const uint8_t *aData,
UDPSocketChild::SendWithAddress(const NetAddr* aAddr,
const uint8_t* aData,
uint32_t aByteLength)
{
NS_ENSURE_ARG(aAddr);
NS_ENSURE_ARG(aData);
return SendDataInternal(UDPSocketAddr(*aAddr), aData, aByteLength);
}
nsresult
UDPSocketChild::SendDataInternal(const UDPSocketAddr& aAddr,
const uint8_t* aData,
const uint32_t aByteLength)
{
NS_ENSURE_ARG(aData);
FallibleTArray<uint8_t> fallibleArray;
if (!fallibleArray.InsertElementsAt(0, aData, aByteLength)) {
return NS_ERROR_OUT_OF_MEMORY;
@ -129,13 +136,48 @@ UDPSocketChild::SendWithAddress(const NetAddr *aAddr,
InfallibleTArray<uint8_t> array;
array.SwapElements(fallibleArray);
SendDataWithAddress(array, *aAddr);
SendOutgoingData(array, aAddr);
return NS_OK;
}
NS_IMETHODIMP
UDPSocketChild::GetLocalPort(uint16_t *aLocalPort)
UDPSocketChild::SendBinaryStream(const nsACString& aHost,
uint16_t aPort,
nsIInputStream* aStream)
{
NS_ENSURE_ARG(aStream);
OptionalInputStreamParams stream;
nsTArray<mozilla::ipc::FileDescriptor> fds;
SerializeInputStream(aStream, stream, fds);
MOZ_ASSERT(fds.IsEmpty());
SendOutgoingData(UDPData(stream), UDPSocketAddr(UDPAddressInfo(nsCString(aHost), aPort)));
return NS_OK;
}
NS_IMETHODIMP
UDPSocketChild::JoinMulticast(const nsACString& aMulticastAddress,
const nsACString& aInterface)
{
SendJoinMulticast(nsCString(aMulticastAddress), nsCString(aInterface));
return NS_OK;
}
NS_IMETHODIMP
UDPSocketChild::LeaveMulticast(const nsACString& aMulticastAddress,
const nsACString& aInterface)
{
SendLeaveMulticast(nsCString(aMulticastAddress), nsCString(aInterface));
return NS_OK;
}
NS_IMETHODIMP
UDPSocketChild::GetLocalPort(uint16_t* aLocalPort)
{
NS_ENSURE_ARG_POINTER(aLocalPort);
@ -144,14 +186,14 @@ UDPSocketChild::GetLocalPort(uint16_t *aLocalPort)
}
NS_IMETHODIMP
UDPSocketChild::GetLocalAddress(nsACString &aLocalAddress)
UDPSocketChild::GetLocalAddress(nsACString& aLocalAddress)
{
aLocalAddress = mLocalAddress;
return NS_OK;
}
NS_IMETHODIMP
UDPSocketChild::SetFilterName(const nsACString &aFilterName)
UDPSocketChild::SetFilterName(const nsACString& aFilterName)
{
if (!mFilterName.IsEmpty()) {
// filter name can only be set once.
@ -162,7 +204,7 @@ UDPSocketChild::SetFilterName(const nsACString &aFilterName)
}
NS_IMETHODIMP
UDPSocketChild::GetFilterName(nsACString &aFilterName)
UDPSocketChild::GetFilterName(nsACString& aFilterName)
{
aFilterName = mFilterName;
return NS_OK;
@ -170,39 +212,44 @@ UDPSocketChild::GetFilterName(nsACString &aFilterName)
// PUDPSocketChild Methods
bool
UDPSocketChild::RecvCallback(const nsCString &aType,
const UDPCallbackData &aData,
const nsCString &aState)
UDPSocketChild::RecvCallbackOpened(const UDPAddressInfo& aAddressInfo)
{
if (NS_FAILED(mSocket->UpdateReadyState(aState)))
NS_ERROR("Shouldn't fail!");
mLocalAddress = aAddressInfo.addr();
mLocalPort = aAddressInfo.port();
nsresult rv = NS_ERROR_FAILURE;
if (aData.type() == UDPCallbackData::Tvoid_t) {
rv = mSocket->CallListenerVoid(aType);
} else if (aData.type() == UDPCallbackData::TUDPError) {
const UDPError& err(aData.get_UDPError());
rv = mSocket->CallListenerError(aType, err.message(), err.filename(),
err.lineNumber(), err.columnNumber());
} else if (aData.type() == UDPCallbackData::TUDPMessage) {
const UDPMessage& message(aData.get_UDPMessage());
InfallibleTArray<uint8_t> data(message.data());
rv = mSocket->CallListenerReceivedData(aType, message.fromAddr(), message.port(),
data.Elements(), data.Length());
} else if (aData.type() == UDPCallbackData::TUDPAddressInfo) {
//update local address and port.
const UDPAddressInfo& addressInfo(aData.get_UDPAddressInfo());
mLocalAddress = addressInfo.local();
mLocalPort = addressInfo.port();
rv = mSocket->CallListenerVoid(aType);
} else if (aData.type() == UDPCallbackData::TUDPSendResult) {
const UDPSendResult& returnValue(aData.get_UDPSendResult());
rv = mSocket->CallListenerSent(aType, returnValue.value());
} else {
MOZ_ASSERT(false, "Invalid callback type!");
}
nsresult rv = mSocket->CallListenerOpened();
mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
NS_ENSURE_SUCCESS(rv, true);
return true;
}
bool
UDPSocketChild::RecvCallbackClosed()
{
nsresult rv = mSocket->CallListenerClosed();
mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
return true;
}
bool
UDPSocketChild::RecvCallbackReceivedData(const UDPAddressInfo& aAddressInfo,
const InfallibleTArray<uint8_t>& aData)
{
nsresult rv = mSocket->CallListenerReceivedData(aAddressInfo.addr(), aAddressInfo.port(),
aData.Elements(), aData.Length());
mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
return true;
}
bool
UDPSocketChild::RecvCallbackError(const nsCString& aMessage,
const nsCString& aFilename,
const uint32_t& aLineNumber)
{
nsresult rv = mSocket->CallListenerError(aMessage, aFilename, aLineNumber);
mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
return true;
}

View File

@ -40,10 +40,19 @@ public:
UDPSocketChild();
virtual ~UDPSocketChild();
virtual bool RecvCallback(const nsCString& aType,
const UDPCallbackData& aData,
const nsCString& aState) MOZ_OVERRIDE;
virtual bool RecvCallbackOpened(const UDPAddressInfo& aAddressInfo) MOZ_OVERRIDE;
virtual bool RecvCallbackClosed() MOZ_OVERRIDE;
virtual bool RecvCallbackReceivedData(const UDPAddressInfo& aAddressInfo,
const InfallibleTArray<uint8_t>& aData) MOZ_OVERRIDE;
virtual bool RecvCallbackError(const nsCString& aMessage,
const nsCString& aFilename,
const uint32_t& aLineNumber) MOZ_OVERRIDE;
private:
nsresult SendDataInternal(const UDPSocketAddr& aAddr,
const uint8_t* aData,
const uint32_t aByteLength);
uint16_t mLocalPort;
nsCString mLocalAddress;
nsCString mFilterName;

View File

@ -9,8 +9,11 @@
#include "nsComponentManagerUtils.h"
#include "nsIUDPSocket.h"
#include "nsINetAddr.h"
#include "mozilla/AppProcessChecker.h"
#include "mozilla/unused.h"
#include "mozilla/ipc/InputStreamUtils.h"
#include "mozilla/net/DNS.h"
#include "mozilla/net/NeckoCommon.h"
#include "nsNetUtil.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/TabParent.h"
@ -19,52 +22,10 @@
namespace mozilla {
namespace dom {
static void
FireInternalError(mozilla::net::PUDPSocketParent *aActor, uint32_t aLineNo)
{
mozilla::unused <<
aActor->SendCallback(NS_LITERAL_CSTRING("onerror"),
UDPError(NS_LITERAL_CSTRING("Internal error"),
NS_LITERAL_CSTRING(__FILE__), aLineNo, 0),
NS_LITERAL_CSTRING("connecting"));
}
static nsresult
ConvertNetAddrToString(mozilla::net::NetAddr &netAddr, nsACString *address, uint16_t *port)
{
NS_ENSURE_ARG_POINTER(address);
NS_ENSURE_ARG_POINTER(port);
*port = 0;
uint32_t bufSize = 0;
switch(netAddr.raw.family) {
case AF_INET:
*port = PR_ntohs(netAddr.inet.port);
bufSize = mozilla::net::kIPv4CStrBufSize;
break;
case AF_INET6:
*port = PR_ntohs(netAddr.inet6.port);
bufSize = mozilla::net::kIPv6CStrBufSize;
break;
default:
//impossible
MOZ_ASSERT(false, "Unexpected address family");
return NS_ERROR_INVALID_ARG;
}
address->SetCapacity(bufSize);
NetAddrToString(&netAddr, address->BeginWriting(), bufSize);
address->SetLength(strlen(address->BeginReading()));
return NS_OK;
}
NS_IMPL_ISUPPORTS(UDPSocketParent, nsIUDPSocketListener)
UDPSocketParent::UDPSocketParent(nsIUDPSocketFilter *filter)
UDPSocketParent::UDPSocketParent()
: mIPCOpen(true)
, mFilter(filter)
{
mObserver = new mozilla::net::OfflineObserver(this);
}
@ -76,6 +37,30 @@ UDPSocketParent::~UDPSocketParent()
}
}
bool
UDPSocketParent::Init(const nsACString& aFilter)
{
if (!aFilter.IsEmpty()) {
nsAutoCString contractId(NS_NETWORK_UDP_SOCKET_FILTER_HANDLER_PREFIX);
contractId.Append(aFilter);
nsCOMPtr<nsIUDPSocketFilterHandler> filterHandler =
do_GetService(contractId.get());
if (filterHandler) {
nsresult rv = filterHandler->NewFilter(getter_AddRefs(mFilter));
if (NS_FAILED(rv)) {
printf_stderr("Cannot create filter that content specified. "
"filter name: %s, error code: %d.", aFilter.BeginReading(), rv);
return false;
}
} else {
printf_stderr("Content doesn't have a valid filter. "
"filter name: %s.", aFilter.BeginReading());
return false;
}
}
return true;
}
uint32_t
UDPSocketParent::GetAppId()
{
@ -119,125 +104,236 @@ UDPSocketParent::OfflineNotification(nsISupports *aSubject)
// PUDPSocketParent methods
bool
UDPSocketParent::Init(const nsCString &aHost, const uint16_t aPort)
UDPSocketParent::RecvBind(const UDPAddressInfo& aAddressInfo,
const bool& aAddressReuse, const bool& aLoopback)
{
nsresult rv;
NS_ASSERTION(mFilter, "No packet filter");
// We don't have browser actors in xpcshell, and hence can't run automated
// tests without this loophole.
if (net::UsingNeckoIPCSecurity() && !mFilter &&
!AssertAppProcessPermission(Manager()->Manager(), "udp-socket")) {
FireInternalError(__LINE__);
return false;
}
nsCOMPtr<nsIUDPSocket> sock =
do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
if (NS_FAILED(rv)) {
FireInternalError(this, __LINE__);
if (NS_FAILED(BindInternal(aAddressInfo.addr(), aAddressInfo.port(), aAddressReuse, aLoopback))) {
FireInternalError(__LINE__);
return true;
}
nsCOMPtr<nsINetAddr> localAddr;
mSocket->GetLocalAddr(getter_AddRefs(localAddr));
nsCString addr;
if (NS_FAILED(localAddr->GetAddress(addr))) {
FireInternalError(__LINE__);
return true;
}
uint16_t port;
if (NS_FAILED(localAddr->GetPort(&port))) {
FireInternalError(__LINE__);
return true;
}
mozilla::unused << SendCallbackOpened(UDPAddressInfo(addr, port));
return true;
}
nsresult
UDPSocketParent::BindInternal(const nsCString& aHost, const uint16_t& aPort,
const bool& aAddressReuse, const bool& aLoopback)
{
nsresult rv;
nsCOMPtr<nsIUDPSocket> sock =
do_CreateInstance("@mozilla.org/network/udp-socket;1", &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (aHost.IsEmpty()) {
rv = sock->Init(aPort, false);
rv = sock->Init(aPort, false, aAddressReuse, /* optional_argc = */ 1);
} else {
PRNetAddr prAddr;
PR_InitializeNetAddr(PR_IpAddrAny, aPort, &prAddr);
PRStatus status = PR_StringToNetAddr(aHost.BeginReading(), &prAddr);
if (status != PR_SUCCESS) {
FireInternalError(this, __LINE__);
return true;
return NS_ERROR_FAILURE;
}
mozilla::net::NetAddr addr;
PRNetAddrToNetAddr(&prAddr, &addr);
rv = sock->InitWithAddress(&addr);
rv = sock->InitWithAddress(&addr, aAddressReuse, /* optional_argc = */ 1);
}
if (NS_FAILED(rv)) {
FireInternalError(this, __LINE__);
return true;
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
rv = sock->SetMulticastLoopback(aLoopback);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// register listener
rv = sock->AsyncListen(this);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
mSocket = sock;
net::NetAddr localAddr;
mSocket->GetAddress(&localAddr);
return NS_OK;
}
uint16_t port;
nsCString addr;
rv = ConvertNetAddrToString(localAddr, &addr, &port);
bool
UDPSocketParent::RecvOutgoingData(const UDPData& aData,
const UDPSocketAddr& aAddr)
{
MOZ_ASSERT(mSocket);
if (NS_FAILED(rv)) {
FireInternalError(this, __LINE__);
return true;
nsresult rv;
if (mFilter) {
// TODO, Bug 933102, filter packets that are sent with hostname.
// Until then we simply throw away packets that are sent to a hostname.
if (aAddr.type() != UDPSocketAddr::TNetAddr) {
return true;
}
// TODO, Packet filter doesn't support input stream yet.
if (aData.type() != UDPData::TArrayOfuint8_t) {
return true;
}
bool allowed;
const InfallibleTArray<uint8_t>& data(aData.get_ArrayOfuint8_t());
rv = mFilter->FilterPacket(&aAddr.get_NetAddr(), data.Elements(),
data.Length(), nsIUDPSocketFilter::SF_OUTGOING,
&allowed);
// Sending unallowed data, kill content.
if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
return false;
}
}
// register listener
mSocket->AsyncListen(this);
mozilla::unused <<
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onopen"),
UDPAddressInfo(addr, port),
NS_LITERAL_CSTRING("connected"));
switch(aData.type()) {
case UDPData::TArrayOfuint8_t:
Send(aData.get_ArrayOfuint8_t(), aAddr);
break;
case UDPData::TInputStreamParams:
Send(aData.get_InputStreamParams(), aAddr);
break;
default:
MOZ_ASSERT(false, "Invalid data type!");
return true;
}
return true;
}
bool
UDPSocketParent::RecvData(const InfallibleTArray<uint8_t> &aData,
const nsCString& aRemoteAddress,
const uint16_t& aPort)
void
UDPSocketParent::Send(const InfallibleTArray<uint8_t>& aData,
const UDPSocketAddr& aAddr)
{
NS_ENSURE_TRUE(mSocket, true);
NS_ASSERTION(mFilter, "No packet filter");
// TODO, Bug 933102, filter packets that are sent with hostname.
// Until then we simply throw away packets that are sent to a hostname.
return true;
#if 0
// Enable this once we have filtering working with hostname delivery.
uint32_t count;
nsresult rv = mSocket->Send(aRemoteAddress,
aPort, aData.Elements(),
aData.Length(), &count);
mozilla::unused <<
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"),
UDPSendResult(rv),
NS_LITERAL_CSTRING("connected"));
NS_ENSURE_SUCCESS(rv, true);
NS_ENSURE_TRUE(count > 0, true);
return true;
#endif
}
bool
UDPSocketParent::RecvDataWithAddress(const InfallibleTArray<uint8_t>& aData,
const mozilla::net::NetAddr& aAddr)
{
NS_ENSURE_TRUE(mSocket, true);
NS_ASSERTION(mFilter, "No packet filter");
uint32_t count;
nsresult rv;
bool allowed;
rv = mFilter->FilterPacket(&aAddr, aData.Elements(),
aData.Length(), nsIUDPSocketFilter::SF_OUTGOING,
&allowed);
// Sending unallowed data, kill content.
NS_ENSURE_SUCCESS(rv, false);
NS_ENSURE_TRUE(allowed, false);
uint32_t count;
switch(aAddr.type()) {
case UDPSocketAddr::TUDPAddressInfo: {
const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
rv = mSocket->Send(addrInfo.addr(), addrInfo.port(),
aData.Elements(), aData.Length(), &count);
break;
}
case UDPSocketAddr::TNetAddr: {
const NetAddr& addr(aAddr.get_NetAddr());
rv = mSocket->SendWithAddress(&addr, aData.Elements(),
aData.Length(), &count);
break;
}
default:
MOZ_ASSERT(false, "Invalid address type!");
return;
}
if (NS_WARN_IF(NS_FAILED(rv)) || count == 0) {
FireInternalError(__LINE__);
}
}
void
UDPSocketParent::Send(const InputStreamParams& aStream,
const UDPSocketAddr& aAddr)
{
nsTArray<mozilla::ipc::FileDescriptor> fds;
nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aStream, fds);
if (NS_WARN_IF(!stream)) {
return;
}
nsresult rv;
switch(aAddr.type()) {
case UDPSocketAddr::TUDPAddressInfo: {
const UDPAddressInfo& addrInfo(aAddr.get_UDPAddressInfo());
rv = mSocket->SendBinaryStream(addrInfo.addr(), addrInfo.port(), stream);
break;
}
case UDPSocketAddr::TNetAddr: {
const NetAddr& addr(aAddr.get_NetAddr());
rv = mSocket->SendBinaryStreamWithAddress(&addr, stream);
break;
}
default:
MOZ_ASSERT(false, "Invalid address type!");
return;
}
if (NS_FAILED(rv)) {
FireInternalError(__LINE__);
}
}
bool
UDPSocketParent::RecvJoinMulticast(const nsCString& aMulticastAddress,
const nsCString& aInterface)
{
nsresult rv = mSocket->JoinMulticast(aMulticastAddress, aInterface);
if (NS_WARN_IF(NS_FAILED(rv))) {
FireInternalError(__LINE__);
}
return true;
}
bool
UDPSocketParent::RecvLeaveMulticast(const nsCString& aMulticastAddress,
const nsCString& aInterface)
{
nsresult rv = mSocket->LeaveMulticast(aMulticastAddress, aInterface);
if (NS_WARN_IF(NS_FAILED(rv))) {
FireInternalError(__LINE__);
}
rv = mSocket->SendWithAddress(&aAddr, aData.Elements(),
aData.Length(), &count);
mozilla::unused <<
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onsent"),
UDPSendResult(rv),
NS_LITERAL_CSTRING("connected"));
NS_ENSURE_SUCCESS(rv, true);
NS_ENSURE_TRUE(count > 0, true);
return true;
}
bool
UDPSocketParent::RecvClose()
{
NS_ENSURE_TRUE(mSocket, true);
if (!mSocket) {
return true;
}
nsresult rv = mSocket->Close();
mSocket = nullptr;
NS_ENSURE_SUCCESS(rv, true);
mozilla::unused << NS_WARN_IF(NS_FAILED(rv));
return true;
}
@ -268,7 +364,6 @@ UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage
if (!mIPCOpen) {
return NS_OK;
}
NS_ASSERTION(mFilter, "No packet filter");
uint16_t port;
nsCString ip;
@ -283,30 +378,30 @@ UDPSocketParent::OnPacketReceived(nsIUDPSocket* aSocket, nsIUDPMessage* aMessage
const char* buffer = data.get();
uint32_t len = data.Length();
bool allowed;
mozilla::net::NetAddr addr;
fromAddr->GetNetAddr(&addr);
nsresult rv = mFilter->FilterPacket(&addr,
(const uint8_t*)buffer, len,
nsIUDPSocketFilter::SF_INCOMING,
&allowed);
// Receiving unallowed data, drop.
NS_ENSURE_SUCCESS(rv, NS_OK);
NS_ENSURE_TRUE(allowed, NS_OK);
if (mFilter) {
bool allowed;
mozilla::net::NetAddr addr;
fromAddr->GetNetAddr(&addr);
nsresult rv = mFilter->FilterPacket(&addr,
(const uint8_t*)buffer, len,
nsIUDPSocketFilter::SF_INCOMING,
&allowed);
// Receiving unallowed data, drop.
if (NS_WARN_IF(NS_FAILED(rv)) || !allowed) {
return NS_OK;
}
}
FallibleTArray<uint8_t> fallibleArray;
if (!fallibleArray.InsertElementsAt(0, buffer, len)) {
FireInternalError(this, __LINE__);
FireInternalError(__LINE__);
return NS_ERROR_OUT_OF_MEMORY;
}
InfallibleTArray<uint8_t> infallibleArray;
infallibleArray.SwapElements(fallibleArray);
// compose callback
mozilla::unused <<
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("ondata"),
UDPMessage(ip, port, infallibleArray),
NS_LITERAL_CSTRING("connected"));
mozilla::unused << SendCallbackReceivedData(UDPAddressInfo(ip, port), infallibleArray);
return NS_OK;
}
@ -316,13 +411,21 @@ UDPSocketParent::OnStopListening(nsIUDPSocket* aSocket, nsresult aStatus)
{
// underlying socket is dead, send state update to child process
if (mIPCOpen) {
mozilla::unused <<
PUDPSocketParent::SendCallback(NS_LITERAL_CSTRING("onclose"),
mozilla::void_t(),
NS_LITERAL_CSTRING("closed"));
mozilla::unused << SendCallbackClosed();
}
return NS_OK;
}
void
UDPSocketParent::FireInternalError(uint32_t aLineNo)
{
if (!mIPCOpen) {
return;
}
mozilla::unused << SendCallbackError(NS_LITERAL_CSTRING("Internal error"),
NS_LITERAL_CSTRING(__FILE__), aLineNo);
}
} // namespace dom
} // namespace mozilla

View File

@ -24,17 +24,22 @@ public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIUDPSOCKETLISTENER
explicit UDPSocketParent(nsIUDPSocketFilter* filter);
explicit UDPSocketParent();
bool Init(const nsCString& aHost, const uint16_t aPort);
bool Init(const nsACString& aFilter);
virtual bool RecvBind(const UDPAddressInfo& aAddressInfo,
const bool& aAddressReuse, const bool& aLoopback) MOZ_OVERRIDE;
virtual bool RecvOutgoingData(const UDPData& aData, const UDPSocketAddr& aAddr) MOZ_OVERRIDE;
virtual bool RecvClose() MOZ_OVERRIDE;
virtual bool RecvData(const InfallibleTArray<uint8_t>& aData,
const nsCString& aRemoteAddress,
const uint16_t& aPort) MOZ_OVERRIDE;
virtual bool RecvDataWithAddress( const InfallibleTArray<uint8_t>& data,
const mozilla::net::NetAddr& addr);
virtual bool RecvRequestDelete() MOZ_OVERRIDE;
virtual bool RecvJoinMulticast(const nsCString& aMulticastAddress,
const nsCString& aInterface) MOZ_OVERRIDE;
virtual bool RecvLeaveMulticast(const nsCString& aMulticastAddress,
const nsCString& aInterface) MOZ_OVERRIDE;
virtual nsresult OfflineNotification(nsISupports *) MOZ_OVERRIDE;
virtual uint32_t GetAppId() MOZ_OVERRIDE;
@ -42,6 +47,12 @@ private:
virtual ~UDPSocketParent();
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;
void Send(const InfallibleTArray<uint8_t>& aData, const UDPSocketAddr& aAddr);
void Send(const InputStreamParams& aStream, const UDPSocketAddr& aAddr);
nsresult BindInternal(const nsCString& aHost, const uint16_t& aPort,
const bool& aAddressReuse, const bool& aLoopback);
void FireInternalError(uint32_t aLineNo);
bool mIPCOpen;
nsCOMPtr<nsIUDPSocket> mSocket;

View File

@ -4,6 +4,10 @@
# 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/.
EXPORTS.mozilla.dom += [
'UDPSocket.h',
]
EXPORTS.mozilla.dom.network += [
'Connection.h',
'Constants.h',
@ -22,6 +26,7 @@ UNIFIED_SOURCES += [
'TCPServerSocketParent.cpp',
'TCPSocketChild.cpp',
'TCPSocketParent.cpp',
'UDPSocket.cpp',
'UDPSocketChild.cpp',
'UDPSocketParent.cpp',
]

View File

@ -0,0 +1,23 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test UDPSocket BFCache</title>
</head>
<body>
<script type="application/javascript;version=1.8">
'use strict';
window.addEventListener('load', function onload() {
window.removeEventListener('load', onload);
let remotePort = parseInt(window.location.search.substring(1), 10);
let socket = new UDPSocket();
socket.addEventListener('message', function () {
socket.send('fail', '127.0.0.1', remotePort);
});
socket.opened.then(function() {
socket.send('ready', '127.0.0.1', remotePort);
});
});
</script>
</body>
</html>

View File

@ -1,3 +1,7 @@
[DEFAULT]
support-files =
file_udpsocket_iframe.html
[test_network_basics.html]
skip-if = toolkit == "gonk" || toolkit == 'android'
[test_tcpsocket_default_permissions.html]
@ -16,3 +20,4 @@ skip-if = toolkit != "gonk"
skip-if = toolkit != "gonk"
[test_networkstats_enabled_perm.html]
skip-if = toolkit != "gonk"
[test_udpsocket.html]

View File

@ -0,0 +1,409 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test UDPSocket API</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<iframe id="iframe"></iframe>
<pre id="test">
<script type="application/javascript;version=1.8">
'use strict';
SimpleTest.waitForExplicitFinish();
const HELLO_WORLD = 'hlo wrld. ';
const DATA_ARRAY = [0, 255, 254, 0, 1, 2, 3, 0, 255, 255, 254, 0];
const DATA_ARRAY_BUFFER = new ArrayBuffer(DATA_ARRAY.length);
const TYPED_DATA_ARRAY = new Uint8Array(DATA_ARRAY_BUFFER);
const BIG_ARRAY = new Array(4096);
const BIG_ARRAY_BUFFER = new ArrayBuffer(BIG_ARRAY.length);
const BIG_TYPED_ARRAY = new Uint8Array(BIG_ARRAY_BUFFER);
for (let i = 0; i < BIG_ARRAY.length; i++) {
BIG_ARRAY[i] = Math.floor(Math.random() * 256);
}
TYPED_DATA_ARRAY.set(DATA_ARRAY);
BIG_TYPED_ARRAY.set(BIG_ARRAY);
function is_same_buffer(recv_data, expect_data) {
let recv_dataview = new Uint8Array(recv_data);
let expected_dataview = new Uint8Array(expect_data);
if (recv_dataview.length !== expected_dataview.length) {
return false;
}
for (let i = 0; i < recv_dataview.length; i++) {
if (recv_dataview[i] != expected_dataview[i]) {
info('discover byte differenct at ' + i);
return false;
}
}
return true;
}
function testOpen() {
info('test for creating an UDP Socket');
let socket = new UDPSocket();
is(socket.localPort, null, 'expect no local port before socket opened');
is(socket.localAddress, null, 'expect no local address before socket opened');
is(socket.remotePort, null, 'expected no default remote port');
is(socket.remoteAddress, null, 'expected no default remote address');
is(socket.readyState, 'opening', 'expected ready state = opening');
is(socket.loopback, false, 'expected no loopback');
is(socket.addressReuse, true, 'expect to reuse address');
return socket.opened.then(function() {
ok(true, 'expect openedPromise to be resolved after successful socket binding');
ok(!(socket.localPort === 0), 'expect allocated a local port');
is(socket.localAddress, '0.0.0.0', 'expect assigned to default address');
is(socket.readyState, 'open', 'expected ready state = open');
return socket;
});
}
function testSendString(socket) {
info('test for sending string data');
socket.send(HELLO_WORLD, '127.0.0.1', socket.localPort);
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
is(recvData, HELLO_WORLD, 'expected same string data');
resolve(socket);
});
});
}
function testSendArrayBuffer(socket) {
info('test for sending ArrayBuffer');
socket.send(DATA_ARRAY_BUFFER, '127.0.0.1', socket.localPort);
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
ok(is_same_buffer(msg.data, DATA_ARRAY_BUFFER), 'expected same buffer data');
resolve(socket);
});
});
}
function testSendArrayBufferView(socket) {
info('test for sending ArrayBufferView');
socket.send(TYPED_DATA_ARRAY, '127.0.0.1', socket.localPort);
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
ok(is_same_buffer(msg.data, TYPED_DATA_ARRAY), 'expected same buffer data');
resolve(socket);
});
});
}
function testSendBlob(socket) {
info('test for sending Blob');
let blob = new Blob([HELLO_WORLD], {type : 'text/plain'});
socket.send(blob, '127.0.0.1', socket.localPort);
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
is(recvData, HELLO_WORLD, 'expected same string data');
resolve(socket);
});
});
}
function testSendBigArray(socket) {
info('test for sending Big ArrayBuffer');
socket.send(BIG_TYPED_ARRAY, '127.0.0.1', socket.localPort);
return new Promise(function(resolve, reject) {
let byteReceived = 0;
socket.addEventListener('message', function recv_callback(msg) {
let byteBegin = byteReceived;
byteReceived += msg.data.byteLength;
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
ok(is_same_buffer(msg.data, BIG_TYPED_ARRAY.subarray(byteBegin, byteReceived)), 'expected same buffer data [' + byteBegin+ '-' + byteReceived + ']');
if (byteReceived >= BIG_TYPED_ARRAY.length) {
socket.removeEventListener('message', recv_callback);
clearTimeout(timeout);
resolve(socket);
}
});
let timeout = setTimeout(function() {
ok(false, 'timeout for sending big array');
resolve(socket);
}, 5000);
});
}
function testSendBigBlob(socket) {
info('test for sending Big Blob');
let blob = new Blob([BIG_TYPED_ARRAY]);
socket.send(blob, '127.0.0.1', socket.localPort);
return new Promise(function(resolve, reject) {
let byteReceived = 0;
socket.addEventListener('message', function recv_callback(msg) {
let byteBegin = byteReceived;
byteReceived += msg.data.byteLength;
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
ok(is_same_buffer(msg.data, BIG_TYPED_ARRAY.subarray(byteBegin, byteReceived)), 'expected same buffer data [' + byteBegin+ '-' + byteReceived + ']');
if (byteReceived >= BIG_TYPED_ARRAY.length) {
socket.removeEventListener('message', recv_callback);
clearTimeout(timeout);
resolve(socket);
}
});
let timeout = setTimeout(function() {
ok(false, 'timeout for sending big blob');
resolve(socket);
}, 5000);
});
}
function testUDPOptions(socket) {
info('test for UDP init options');
let remoteSocket = new UDPSocket({addressReuse: false,
loopback: true,
localAddress: '127.0.0.1',
remoteAddress: '127.0.0.1',
remotePort: socket.localPort});
is(remoteSocket.localAddress, '127.0.0.1', 'expected local address');
is(remoteSocket.remoteAddress, '127.0.0.1', 'expected remote address');
is(remoteSocket.remotePort, socket.localPort, 'expected remote port');
is(remoteSocket.addressReuse, false, 'expected address not reusable');
is(remoteSocket.loopback, true, 'expected loopback mode is on');
return remoteSocket.opened.then(function() {
remoteSocket.send(HELLO_WORLD);
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
is(msg.remotePort, remoteSocket.localPort, 'expected packet from ' + remoteSocket.localPort);
is(recvData, HELLO_WORLD, 'expected same string data');
resolve(socket);
});
});
});
}
function testClose(socket) {
info('test for close');
socket.close();
is(socket.readyState, 'closed', 'expect ready state to be "closed"');
try {
socket.send(HELLO_WORLD, '127.0.0.1', socket.localPort);
ok(false, 'unexpect to send successfully');
} catch (e) {
ok(true, 'expected send fail after socket closed');
}
return socket.closed.then(function() {
ok(true, 'expected closedPromise is resolved after socket.close()');
});
}
function testMulticast() {
info('test for multicast');
let socket = new UDPSocket({loopback: true});
const MCAST_ADDRESS = '224.0.0.255';
socket.joinMulticastGroup(MCAST_ADDRESS);
return socket.opened.then(function() {
socket.send(HELLO_WORLD, MCAST_ADDRESS, socket.localPort);
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
let recvData= String.fromCharCode.apply(null, new Uint8Array(msg.data));
is(msg.remotePort, socket.localPort, 'expected packet from ' + socket.localPort);
is(recvData, HELLO_WORLD, 'expected same string data');
socket.leaveMulticastGroup(MCAST_ADDRESS);
resolve();
});
});
});
}
function testInvalidUDPOptions() {
info('test for invalid UDPOptions');
try {
let socket = new UDPSocket({localAddress: 'not-a-valid-address'});
ok(false, 'should not create an UDPSocket with an invalid localAddress');
} catch (e) {
is(e.name, 'InvalidAccessError', 'expected InvalidAccessError will be thrown if localAddress is not a valid IPv4/6 address');
}
try {
let socket = new UDPSocket({localPort: 0});
ok(false, 'should not create an UDPSocket with an invalid localPort');
} catch (e) {
is(e.name, 'InvalidAccessError', 'expected InvalidAccessError will be thrown if localPort is not a valid port number');
}
try {
let socket = new UDPSocket({remotePort: 0});
ok(false, 'should not create an UDPSocket with an invalid remotePort');
} catch (e) {
is(e.name, 'InvalidAccessError', 'expected InvalidAccessError will be thrown if localPort is not a valid port number');
}
}
function testOpenFailed() {
info('test for falied on open');
//according to RFC5737, address block 192.0.2.0/24 should not be used in both local and public contexts
let socket = new UDPSocket({localAddress: '192.0.2.0'});
return socket.opened.then(function() {
ok(false, 'should not resolve openedPromise while fail to bind socket');
}).catch(function(reason) {
is(reason.name, 'NetworkError', 'expected openedPromise to be rejected while fail to bind socket');
});
}
function testSendBeforeOpen() {
info('test for send before open');
let socket = new UDPSocket();
try {
socket.send(HELLO_WORLD, '127.0.0.1', 9);
ok(false, 'unexpect to send successfully');
} catch (e) {
ok(true, 'expected send fail before openedPromise is resolved');
}
return socket.opened;
}
function testCloseBeforeOpened() {
info('test for close socket before opened');
let socket = new UDPSocket();
socket.opened.then(function() {
ok(false, 'should not resolve openedPromise if it has already been closed');
}).catch(function(reason) {
is(reason.name, 'AbortError', 'expected openedPromise to be rejected while socket is closed during opening');
});
return socket.close().then(function() {
ok(true, 'expected closedPromise to be resolved');
}).then(socket.opened);
}
function testOpenWithoutClose() {
info('test for open without close');
let opened = [];
for (let i = 0; i < 50; i++) {
let socket = new UDPSocket();
opened.push(socket.opened);
}
return Promise.all(opened);
}
function testBFCache() {
info('test for bfcache behavior');
let socket = new UDPSocket();
return socket.opened.then(function() {
let iframe = document.getElementById('iframe');
SpecialPowers.wrap(iframe).mozbrowser = true;
iframe.src = 'file_udpsocket_iframe.html?' + socket.localPort;
return new Promise(function(resolve, reject) {
socket.addEventListener('message', function recv_callback(msg) {
socket.removeEventListener('message', recv_callback);
iframe.src = 'about:blank';
iframe.addEventListener('load', function onload() {
iframe.removeEventListener('load', onload);
socket.send(HELLO_WORLD, '127.0.0.1', msg.remotePort);
function recv_again_callback(msg) {
socket.removeEventListener('message', recv_again_callback);
ok(false, 'should not receive packet after page unload');
}
socket.addEventListener('message', recv_again_callback);
let timeout = setTimeout(function() {
socket.removeEventListener('message', recv_again_callback);
socket.close();
resolve();
}, 5000);
});
});
});
});
}
function runTest() {
testOpen()
.then(testSendString)
.then(testSendArrayBuffer)
.then(testSendArrayBufferView)
.then(testSendBlob)
.then(testSendBigArray)
.then(testSendBigBlob)
.then(testUDPOptions)
.then(testClose)
.then(testMulticast)
.then(testInvalidUDPOptions)
.then(testOpenFailed)
.then(testSendBeforeOpen)
.then(testCloseBeforeOpened)
.then(testOpenWithoutClose)
.then(testBFCache)
.then(function() {
info('test finished');
SimpleTest.finish();
});
}
window.addEventListener('load', function () {
SpecialPowers.pushPermissions([
{type: 'udp-socket', allow: true, context: document}], function() {
SpecialPowers.pushPrefEnv({
'set': [
['dom.udpsocket.enabled', true],
['browser.sessionhistory.max_total_viewers', 10]
]
}, runTest);
});
});
</script>
</pre>
</body>
</html>

View File

@ -16,6 +16,7 @@ skip-if = buildapp == 'b2g' || toolkit == 'android' # b2g(https not working, bug
[test_power.html]
[test_systemXHR.html]
[test_tcp-socket.html]
[test_udp-socket.html]
[test_webapps-manage.html]
[test_camera.html]
disabled = disabled until bug 859593 is fixed

View File

@ -0,0 +1,47 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=745283
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 745283 </title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=745283">Mozilla Bug 745283 </a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
<script type="application/javascript;version=1.8" src="file_framework.js"></script>
<script type="application/javascript;version=1.8">
function verifier(success, failure) {
try {
var socket = new UDPSocket();
if (socket) {
success("Opened socket");
} else {
failure("failed to open socket");
}
} catch (e) {
failure("Got an exception " + e);
}
}
var gData = [
{
perm: ["udp-socket"],
needParentPerm: true,
obj: "UDPSocket",
webidl: "UDPSocket",
settings: [["dom.udpsocket.enabled", true]],
verifier: verifier.toSource(),
}
]
</script>
</pre>
</body>
</html>

View File

@ -1168,6 +1168,10 @@ var interfaceNamesInGlobalScope =
{name: "TreeSelection", xbl: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
"TreeWalker",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "UDPMessageEvent", pref: "dom.udpsocket.enabled", permission: "udp-socket"},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "UDPSocket", pref: "dom.udpsocket.enabled", permission: "udp-socket"},
// IMPORTANT: Do not change this list without review from a DOM peer!
"UIEvent",
// IMPORTANT: Do not change this list without review from a DOM peer!

View File

@ -156,7 +156,7 @@ partial interface Element {
// scrolling
void scrollIntoView();
void scrollIntoView(boolean top);
void scrollIntoView(boolean top, optional ScrollOptions options);
// None of the CSSOM attributes are [Pure], because they flush
attribute long scrollTop; // scroll on setting
attribute long scrollLeft; // scroll on setting

View File

@ -11,8 +11,9 @@
* specific Mozilla domains to access it directly.
*/
[ChromeOnly,
JSImplementation="@mozilla.org/mozselfsupport;1"]
interface MozSelfSupportImpl
JSImplementation="@mozilla.org/mozselfsupport;1",
Constructor()]
interface MozSelfSupport
{
/**
* Controls whether uploading FHR data is allowed.

View File

@ -44,6 +44,9 @@ interface PeerConnectionImpl {
[Throws]
void removeTrack(MediaStreamTrack track);
[Throws]
void replaceTrack(MediaStreamTrack thisTrack, MediaStreamTrack withTrack,
MediaStream stream);
[Throws]
void closeStreams();
sequence<MediaStream> getLocalStreams();

View File

@ -28,6 +28,10 @@ interface PeerConnectionObserver
void onGetStatsSuccess(optional RTCStatsReportInternal report);
void onGetStatsError(unsigned long name, DOMString message);
/* replaceTrack callbacks */
void onReplaceTrackSuccess();
void onReplaceTrackError(unsigned long name, DOMString message);
/* Data channel callbacks */
void notifyDataChannel(DataChannel channel);

View File

@ -11,4 +11,8 @@
JSImplementation="@mozilla.org/dom/rtpsender;1"]
interface RTCRtpSender {
readonly attribute MediaStreamTrack track;
void replaceTrack(MediaStreamTrack track,
VoidFunction successCallback,
RTCPeerConnectionErrorCallback failureCallback);
};

View File

@ -0,0 +1,16 @@
/* -*- Mode: IDL; 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/.
*
* The origin of this IDL file is
* http://www.w3.org/2012/sysapps/tcp-udp-sockets/#readystate
*/
enum SocketReadyState {
"opening",
"open",
"closing",
"closed",
"halfclosed"
};

View File

@ -0,0 +1,24 @@
/* -*- Mode: IDL; 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/.
*
* The origin of this IDL file is
* http://www.w3.org/TR/raw-sockets/#interface-udpmessageevent
*/
//Bug 1056444: This interface should be removed after UDPSocket.input/UDPSocket.output are ready.
[Constructor(DOMString type, optional UDPMessageEventInit eventInitDict),
Pref="dom.udpsocket.enabled",
CheckPermissions="udp-socket"]
interface UDPMessageEvent : Event {
readonly attribute DOMString remoteAddress;
readonly attribute unsigned short remotePort;
readonly attribute any data;
};
dictionary UDPMessageEventInit : EventInit {
DOMString remoteAddress = "";
unsigned short remotePort = 0;
any data = null;
};

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