mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge inbound to m-c. a=merge
This commit is contained in:
commit
fbfa40d6b1
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -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>
|
||||
|
@ -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)
|
||||
|
@ -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) {
|
||||
|
@ -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() {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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; > &newPrivateWindow.label;.">
|
||||
|
@ -12,7 +12,6 @@ MinVersion=@GRE_MILESTONE@
|
||||
MaxVersion=@GRE_MILESTONE@
|
||||
|
||||
[XRE]
|
||||
EnableExtensionManager=0
|
||||
EnableProfileMigrator=0
|
||||
|
||||
[Crash Reporter]
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
*/
|
||||
|
BIN
browser/themes/shared/mask.png
Normal file
BIN
browser/themes/shared/mask.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 KiB |
BIN
browser/themes/shared/mask@2x.png
Normal file
BIN
browser/themes/shared/mask@2x.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 KiB |
@ -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;
|
||||
}
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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')
|
||||
|
@ -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]
|
||||
|
@ -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
|
||||
|
||||
|
2
config/external/ffi/moz.build
vendored
2
config/external/ffi/moz.build
vendored
@ -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 = ''
|
||||
|
@ -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))
|
||||
|
@ -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
|
||||
|
||||
|
@ -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")
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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())
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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];
|
||||
|
@ -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,
|
||||
|
@ -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()) {
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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>
|
||||
|
40
dom/datastore/tests/file_bug1058108.html
Normal file
40
dom/datastore/tests/file_bug1058108.html
Normal 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>
|
||||
|
@ -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
|
||||
|
130
dom/datastore/tests/test_bug1058108.html
Normal file
130
dom/datastore/tests/test_bug1058108.html
Normal 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>
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -100,7 +100,6 @@ public:
|
||||
static void JoinAllSubprocesses();
|
||||
|
||||
static bool PreallocatedProcessReady();
|
||||
static void RunAfterPreallocatedProcessReady(nsIRunnable* aRequest);
|
||||
|
||||
/**
|
||||
* Get or create a content process for:
|
||||
|
@ -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
|
||||
|
@ -86,7 +86,6 @@ public:
|
||||
static bool IsNuwaReady();
|
||||
static void OnNuwaReady();
|
||||
static bool PreallocatedProcessReady();
|
||||
static void RunAfterPreallocatedProcessReady(nsIRunnable* aRunnable);
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
@ -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) {
|
||||
|
@ -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();
|
||||
|
@ -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]
|
||||
|
@ -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>
|
@ -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);
|
||||
};
|
||||
|
@ -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__();
|
||||
};
|
||||
|
||||
|
705
dom/network/src/UDPSocket.cpp
Normal file
705
dom/network/src/UDPSocket.cpp
Normal 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
197
dom/network/src/UDPSocket.h
Normal 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__
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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',
|
||||
]
|
||||
|
23
dom/network/tests/file_udpsocket_iframe.html
Normal file
23
dom/network/tests/file_udpsocket_iframe.html
Normal 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>
|
@ -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]
|
||||
|
409
dom/network/tests/test_udpsocket.html
Normal file
409
dom/network/tests/test_udpsocket.html
Normal 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>
|
@ -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
|
||||
|
47
dom/permission/tests/test_udp-socket.html
Normal file
47
dom/permission/tests/test_udp-socket.html
Normal 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>
|
||||
|
@ -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!
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -11,4 +11,8 @@
|
||||
JSImplementation="@mozilla.org/dom/rtpsender;1"]
|
||||
interface RTCRtpSender {
|
||||
readonly attribute MediaStreamTrack track;
|
||||
|
||||
void replaceTrack(MediaStreamTrack track,
|
||||
VoidFunction successCallback,
|
||||
RTCPeerConnectionErrorCallback failureCallback);
|
||||
};
|
||||
|
16
dom/webidl/SocketCommon.webidl
Normal file
16
dom/webidl/SocketCommon.webidl
Normal 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"
|
||||
};
|
24
dom/webidl/UDPMessageEvent.webidl
Normal file
24
dom/webidl/UDPMessageEvent.webidl
Normal 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
Loading…
Reference in New Issue
Block a user