--- a/browser/base/content/browser-data-submission-info-bar.js
+++ b/browser/base/content/browser-data-submission-info-bar.js
@@ -21,18 +21,16 @@ let gDataNotificationInfoBar = {
get _log() {
let Log = Cu.import("resource://gre/modules/Log.jsm", {}).Log;
delete this._log;
return this._log = Log.repository.getLogger("Services.DataReporting.InfoBar");
},
init: function() {
window.addEventListener("unload", function onUnload() {
- window.removeEventListener("unload", onUnload, false);
-
for (let o of this._OBSERVERS) {
Services.obs.removeObserver(this, o);
}
}.bind(this), false);
for (let o of this._OBSERVERS) {
Services.obs.addObserver(this, o, true);
}
--- a/browser/base/content/browser.css
+++ b/browser/base/content/browser.css
@@ -1007,18 +1007,18 @@ chatbox:-moz-full-screen-ancestor > .cha
}
/* hide sidebar when fullscreen */
*:-moz-full-screen-ancestor #social-sidebar-box:not(:-moz-full-screen-ancestor) {
display: none;
}
/* Combobox dropdown renderer */
-#ContentSelectDropdown {
- -moz-binding: url("chrome://global/content/bindings/popup.xml#popup-scrollbars");
+#ContentSelectDropdown > menupopup {
+ max-height: 350px;
}
.contentSelectDropdown-optgroup {
font-weight: bold;
/* color: menutext used to overwrite the disabled color */
color: menutext;
}
--- a/browser/base/content/browser.xul
+++ b/browser/base/content/browser.xul
@@ -141,18 +141,23 @@
<panel type="autocomplete" id="PopupAutoComplete" noautofocus="true" hidden="true"/>
<!-- for search with one-off buttons -->
<panel type="autocomplete" id="PopupSearchAutoComplete" noautofocus="true" hidden="true"/>
<!-- for url bar autocomplete -->
<panel type="autocomplete-richlistbox" id="PopupAutoCompleteRichResult" noautofocus="true" hidden="true"/>
- <!-- for select dropdowns -->
- <menupopup id="ContentSelectDropdown" rolluponmousewheel="true" hidden="true"/>
+ <!-- for select dropdowns. The menupopup is what shows the list of options,
+ and the popuponly menulist makes things like the menuactive attributes
+ work correctly on the menupopup. ContentSelectDropdown expects the
+ popuponly menulist to be its immediate parent. -->
+ <menulist popuponly="true" id="ContentSelectDropdown" hidden="true">
+ <menupopup rolluponmousewheel="true"/>
+ </menulist>
<!-- for invalid form error message -->
<panel id="invalid-form-popup" type="arrow" orient="vertical" noautofocus="true" hidden="true" level="parent">
<description/>
</panel>
<panel id="editBookmarkPanel"
type="arrow"
@@ -1164,17 +1169,17 @@
<splitter id="sidebar-splitter" class="chromeclass-extrachrome sidebar-splitter" hidden="true"/>
<vbox id="appcontent" flex="1">
<notificationbox id="high-priority-global-notificationbox"/>
<tabbrowser id="content"
flex="1" contenttooltip="aHTMLTooltip"
tabcontainer="tabbrowser-tabs"
contentcontextmenu="contentAreaContextMenu"
autocompletepopup="PopupAutoComplete"
- selectpopup="ContentSelectDropdown"/>
+ selectmenulist="ContentSelectDropdown"/>
<chatbar id="pinnedchats" layer="true" mousethrough="always" hidden="true"/>
</vbox>
<splitter id="social-sidebar-splitter"
class="chromeclass-extrachrome sidebar-splitter"
observes="socialSidebarBroadcaster"/>
<vbox id="social-sidebar-box"
class="chromeclass-extrachrome"
observes="socialSidebarBroadcaster"
--- a/browser/base/content/tabbrowser.xml
+++ b/browser/base/content/tabbrowser.xml
@@ -25,17 +25,17 @@
flex="1" eventnode="document" xbl:inherits="handleCtrlPageUpDown"
onselect="if (event.target.localName == 'tabpanels') this.parentNode.updateCurrentBrowser();">
<xul:tabpanels flex="1" class="plain" selectedIndex="0" anonid="panelcontainer">
<xul:notificationbox flex="1">
<xul:hbox flex="1" class="browserSidebarContainer">
<xul:vbox flex="1" class="browserContainer">
<xul:stack flex="1" class="browserStack" anonid="browserStack">
<xul:browser anonid="initialBrowser" type="content-primary" message="true" messagemanagergroup="browsers"
- xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup,selectpopup"/>
+ xbl:inherits="tooltip=contenttooltip,contextmenu=contentcontextmenu,autocompletepopup,selectmenulist"/>
</xul:stack>
</xul:vbox>
</xul:hbox>
</xul:notificationbox>
</xul:tabpanels>
</xul:tabbox>
<children/>
</content>
@@ -1595,18 +1595,18 @@
if (window.gShowPageResizers && window.windowState == window.STATE_NORMAL) {
b.setAttribute("showresizer", "true");
}
if (!isPreloadBrowser && this.hasAttribute("autocompletepopup"))
b.setAttribute("autocompletepopup", this.getAttribute("autocompletepopup"));
- if (this.hasAttribute("selectpopup"))
- b.setAttribute("selectpopup", this.getAttribute("selectpopup"));
+ if (this.hasAttribute("selectmenulist"))
+ b.setAttribute("selectmenulist", this.getAttribute("selectmenulist"));
b.setAttribute("autoscrollpopup", this._autoScrollPopup.id);
// Create the browserStack container
var stack = document.createElementNS(NS_XUL, "stack");
stack.className = "browserStack";
stack.appendChild(b);
stack.setAttribute("flex", "1");
--- a/browser/components/loop/content/shared/js/mixins.js
+++ b/browser/components/loop/content/shared/js/mixins.js
@@ -198,17 +198,16 @@ loop.shared.mixins = (function() {
// @see https://bugzilla.mozilla.org/show_bug.cgi?id=1020445
return {
insertMode: "append",
width: "100%",
height: "100%",
publishVideo: options.publishVideo,
style: {
audioLevelDisplayMode: "off",
- bugDisplayMode: "off",
buttonDisplayMode: "off",
nameDisplayMode: "off",
videoDisabledDisplayMode: "off"
}
};
},
/**
--- a/browser/components/loop/content/shared/libs/sdk-content/css/ot.css
+++ b/browser/components/loop/content/shared/libs/sdk-content/css/ot.css
@@ -113,226 +113,98 @@
border: 0 none;
}
/* Modal dialog styles */
/* Modal dialog styles */
+.OT_dialog-centering {
+ display: table;
+ width: 100%;
+ height: 100%;
+}
+
+.OT_dialog-centering-child {
+ display: table-cell;
+ vertical-align: middle;
+}
+
.OT_dialog {
- border: none;
- border-radius: 0;
- top: 50%;
- left: 50%;
- position: absolute;
- position: fixed;
- padding: 0;
+ position: relative;
+
+ box-sizing: border-box;
+ max-width: 576px;
+ margin-right: auto;
+ margin-left: auto;
+ padding: 36px;
+ text-align: center; /* centers all the inline content */
+
background-color: #363636;
color: #fff;
- z-index: 9999;
box-shadow: 2px 4px 6px #999;
font-family: 'Didact Gothic', sans-serif;
-}
-
-.OT_dialog-blackout {
- position: absolute;
- position: fixed;
- top: 0;
- right: 0;
- bottom: 0;
- left: 0;
- background-color: #363636;
-}
-
-.OT_dialog-blackout .OT_dialog {
- box-shadow: 0 0 0 transparent;
+ font-size: 13px;
+ line-height: 1.4;
}
.OT_dialog * {
- font-family: 'Didact Gothic', sans-serif;
-}
-
-.OT_dialog-plugin-prompt {
- margin-left: -350px;
- margin-top: -127px;
- width: 650px;
- height: 254px;
-}
-
-.OT_dialog-plugin-reinstall {
- margin-left: -271px;
- margin-top: -107px;
- width: 542px;
- height: 214px;
-}
-
-.OT_dialog-plugin-upgrading {
- margin-left: -267px;
- margin-top: -94px;
- width: 514px;
- height: 188px;
-}
-
-.OT_dialog-plugin-upgraded {
- margin-left: -300px;
- margin-top: -100px;
- width: 600px;
- height: 200px;
-}
-
-.OT_dialog-allow-deny-chrome-first {
- margin-left: -227px;
- margin-top: -122px;
- width: 453px;
- height: 244px;
-}
-
-.OT_dialog-allow-deny-chrome-pre-denied {
- margin-left: -263px;
- margin-top: -135px;
- width: 526px;
- height: 270px;
-}
-
-.OT_dialog-allow-deny-chrome-now-denied {
- margin-left: -120px;
- margin-top: -85px;
- width: 256px;
- height: 170px;
-}
-
-.OT_dialog-allow-deny-firefox-denied {
- margin-left: -160px;
- margin-top: -105px;
- width: 320px;
- height: 190px;
-}
-
-.OT_dialog-allow-deny-firefox-maybe-denied {
- margin-left: -281px;
- margin-top: -126px;
- width: 562px;
- height: 252px;
-}
-
-.OT_dialog-allow-highlight-chrome {
- display: inline-block;
- margin-top: 20px;
- width: 227px;
- height: 94px;
- background-image: url(../images/rtc/access-prompt-chrome.png);
+ font-family: inherit;
+ box-sizing: inherit;
}
.OT_closeButton {
color: #999999;
cursor: pointer;
font-size: 32px;
- line-height: 30px;
+ line-height: 36px;
position: absolute;
- right: 15px;
+ right: 18px;
top: 0;
}
.OT_dialog-messages {
- position: absolute;
- top: 32px;
- left: 32px;
- right: 32px;
text-align: center;
}
-.OT_dialog-allow-deny-firefox-maybe-denied .OT_dialog-messages {
- top: 45px;
-}
-
.OT_dialog-messages-main {
+ margin-bottom: 36px;
+ line-height: 36px;
+
font-weight: 300;
- font-size: 18pt;
- line-height: 24px;
+ font-size: 24px;
}
.OT_dialog-messages-minor {
- font-weight: 300;
- margin-top: 12px;
+ margin-bottom: 18px;
+
font-size: 13px;
line-height: 18px;
color: #A4A4A4;
}
-.OT_dialog-allow-deny-firefox-maybe-denied .OT_dialog-messages-minor {
- margin-top: 4px;
-}
-
.OT_dialog-messages-minor strong {
- font-weight: 300;
color: #ffffff;
}
-.OT_dialog-hidden {
- display: none;
-}
-
-.OT_dialog-single-button {
- position: absolute;
- bottom: 41px;
- left: 50%;
- margin-left: -97px;
- height: 47px;
- width: 193px;
-}
-
-
-.OT_dialog-single-button-wide {
- bottom: 35px;
- height: 140px;
- left: 5px;
- position: absolute;
- right: 0;
-}
- .OT_dialog-single-button-with-title {
- margin: 0 auto;
- padding-left: 30px;
- padding-right: 30px;
- width: 270px;
- }
-
-
-.OT_dialog-button-pair {
- position: absolute;
- bottom: 45px;
- left: 5px;
- right: 0;
- height: 94px;
-}
-
-.OT_dialog-button-with-title {
- padding-left: 30px;
- padding-right: 30px;
- width: 260px;
- float: left;
-}
-
-.OT_dialog-button-pair-seperator {
- border-right: 1px solid #555555;
- height: 112px;
- width: 1px;
- float: left;
+.OT_dialog-actions-card {
+ display: inline-block;
}
.OT_dialog-button-title {
+ margin-bottom: 18px;
+ line-height: 18px;
+
font-weight: 300;
text-align: center;
- margin-bottom: 15px;
font-size: 14px;
- line-height: 150%;
color: #999999;
}
-
.OT_dialog-button-title label {
color: #999999;
}
.OT_dialog-button-title a,
.OT_dialog-button-title a:link,
.OT_dialog-button-title a:active {
color: #02A1DE;
@@ -340,167 +212,96 @@
.OT_dialog-button-title strong {
color: #ffffff;
font-weight: 100;
display: block;
}
.OT_dialog-button {
- font-weight: 100;
- display: block;
- line-height: 50px;
- height: 47px;
+ display: inline-block;
+
+ margin-bottom: 18px;
+ padding: 0 1em;
+
background-color: #1CA3DC;
text-align: center;
- font-size: 16pt;
cursor: pointer;
}
.OT_dialog-button.OT_dialog-button-disabled {
cursor: not-allowed;
/* IE 8 */
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";
opacity: 0.5;
}
-.OT_dialog-button.OT_dialog-button-large {
- line-height: 60px;
- height: 58px;
+.OT_dialog-button-large {
+ line-height: 36px;
+ padding-top: 9px;
+ padding-bottom: 9px;
+
+ font-weight: 100;
+ font-size: 24px;
}
-.OT_dialog-button.OT_dialog-button-small {
+.OT_dialog-button-small {
+ line-height: 18px;
+ padding-top: 9px;
+ padding-bottom: 9px;
+
background-color: #444444;
color: #999999;
- font-size: 12pt;
- height: 40px;
- line-height: 40px;
- margin: 20px auto 0 auto;
- width: 86px;
+ font-size: 16px;
}
.OT_dialog-progress-bar {
+ display: inline-block; /* prevents margin collapse */
+ width: 100%;
+ margin-top: 5px;
+ margin-bottom: 41px;
+
border: 1px solid #4E4E4E;
height: 8px;
}
.OT_dialog-progress-bar-fill {
+ height: 100%;
+
background-color: #29A4DA;
- height: 10px;
- margin-top: -1px;
- margin-left: -1px;
- margin-right: -1px;
}
.OT_dialog-plugin-upgrading .OT_dialog-plugin-upgrade-percentage {
- font-size: 36pt;
+ line-height: 54px;
+
+ font-size: 48px;
font-weight: 100;
}
-.OT_dialog-plugin-upgrading .OT_dialog-progress-bar {
- margin-top: 25px;
- margin-bottom: 25px;
-}
-
-.OT_dialog-3steps {
- margin-top: 24px;
-}
-
-.OT_dialog-allow-deny-firefox-maybe-denied .OT_dialog-3steps {
- margin-top: 21px;
-}
-
-.OT_dialog-3steps-step {
- float: left;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- width: 33%;
- height: 140px;
- padding: 0 10px;
- color: #A4A4A4;
-}
+/* Helpers */
-.OT_dialog-3steps-seperator {
- float: left;
- -moz-box-sizing: border-box;
- box-sizing: border-box;
- margin-top: 10px;
- width: 1px;
- height: 68px;
- background-color: #555555;
-}
-
-.OT_dialog-allow-deny-chrome-pre-denied .OT_dialog-3steps-seperator {
- margin-top: 16px;
-}
-
-.OT_dialog-3steps-step-num {
- font-size: 20px;
- background-color: #2AA3D8;
- border-radius: 20px;
- line-height: 33px;
- height: 33px;
- width: 33px;
- margin: 0 auto 17px;
+.OT_centered {
+ position: fixed;
+ left: 50%;
+ top: 50%;
+ margin: 0;
}
-.OT_dialog-allow-deny-chrome-pre-denied .OT_dialog-3steps-step-num {
- margin-bottom: 10px;
-}
-
-.OT_dialog-allow-camera-icon {
- background-color: #000;
- width: 113px;
- height: 48px;
- margin: 10px auto 0;
- background-image: url(../images/rtc/access-predenied-chrome.png);
-}
-
-/* Publisher Deny Helpers */
-
-.OT_publisher-denied-firefox {
- background-color: #fff;
+.OT_dialog-hidden {
+ display: none;
}
-.OT_publisher-denied-firefox p {
- width: 232px;
- height: 103px;
- top: 50%;
- left: 50%;
+.OT_dialog-button-block {
display: block;
- position: absolute;
- margin-top: -52px;
- margin-left: -116px;
- background-image: url(../images/rtc/access-denied-firefox.png);
- background-position: 50% 0;
- background-repeat: no-repeat;
}
-.OT_publisher-denied-firefox span {
- display: block;
- position: absolute;
- bottom: 0;
- right: 0;
- left: 0;
- margin: 0 auto;
- width: 232px;
- height: 31px;
- background-image: url(../images/rtc/access-denied-copy-firefox.png);
- text-indent: 100%;
- white-space: nowrap;
- overflow: hidden;
-}
-
-.OT_centered {
- position: fixed;
- left: 50%;
- top: 50%;
- margin: 0;
+.OT_dialog-no-natural-margin {
+ margin-bottom: 0;
}
/* Publisher and Subscriber styles */
.OT_publisher, .OT_subscriber {
position: relative;
min-width: 48px;
min-height: 48px;
@@ -798,56 +599,34 @@
.OT_mini .OT_name.OT_mode-on,
.OT_mini .OT_name.OT_mode-auto,
.OT_mini:hover .OT_name.OT_mode-auto {
display: none;
}
.OT_publisher .OT_name,
.OT_subscriber .OT_name {
- left: 24px;
+ left: 10px;
right: 37px;
height: 34px;
-}
-
-.OT_publisher .OT_name-no-bug,
-.OT_subscriber .OT_name-no-bug {
- left: 10px;
padding-left: 0;
}
.OT_publisher .OT_mute,
-.OT_subscriber .OT_mute,
-.OT_publisher .OT_opentok,
-.OT_subscriber .OT_opentok {
+.OT_subscriber .OT_mute {
border: none;
cursor: pointer;
display: block;
position: absolute;
text-align: center;
text-indent: -9999em;
background-color: transparent;
background-repeat: no-repeat;
}
-.OT_publisher .OT_opentok,
-.OT_subscriber .OT_opentok {
- background: url(../images/rtc/buttons.png) 0 -32px no-repeat;
- cursor: default;
- height: 18px;
- left: 8px;
- line-height: 18px;
- top: 8px;
- width: 16px;
-}
-
-.OT_micro .OT_opentok {
- display: none !important;
-}
-
.OT_publisher .OT_mute,
.OT_subscriber .OT_mute {
right: 0;
top: 0;
border-left: 1px solid rgba(255, 255, 255, 0.2);
height: 36px;
width: 37px;
}
@@ -878,31 +657,16 @@
background-position: 8px 7px;
}
.OT_subscriber .OT_mute.OT_active {
background-image: url(../images/rtc/speaker-off.png);
background-position: 7px 7px;
}
-/* Disabling this for now - see https://jira.tokbox.com/browse/OPENTOK-8870
-.OT_publisher .OT_opentok:hover:after,
-.OT_subscriber .OT_opentok:hover:after {
- content: 'tokbox';
- color: #fff;
- font-weight: bold;
- font-size: 14px;
- letter-spacing: -1px;
- top: 20px;
- opacity: 0.5;
- position: absolute;
- text-indent: 0;
- top: 0;
-}*/
-
/**
* Styles for display modes
*
* Note: It's important that these completely control the display and opacity
* attributes, no other selectors should atempt to change them.
*/
/* Default display mode transitions for various chrome elements */
@@ -970,33 +734,16 @@
.OT_subscriber .OT_edge-bar-item.OT_edge-bottom.OT_mode-on,
.OT_publisher:hover .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto,
.OT_subscriber:hover .OT_edge-bar-item.OT_edge-bottom.OT_mode-auto {
top: auto;
bottom: 0;
opacity: 1;
}
-.OT_publisher .OT_opentok.OT_mode-off,
-.OT_publisher .OT_opentok.OT_mode-auto,
-.OT_subscriber .OT_opentok.OT_mode-off,
-.OT_subscriber .OT_opentok.OT_mode-auto {
- top: -17px;
-}
-
-.OT_publisher .OT_opentok.OT_mode-on,
-.OT_publisher .OT_opentok.OT_mode-auto.OT_mode-on-hold,
-.OT_publisher:hover .OT_opentok.OT_mode-auto,
-.OT_subscriber .OT_opentok.OT_mode-on,
-.OT_subscriber .OT_opentok.OT_mode-auto.OT_mode-on-hold,
-.OT_subscriber:hover .OT_opentok.OT_mode-auto {
- top: 8px;
-}
-
-
/* Contains the video element, used to fix video letter-boxing */
.OT_video-container {
position: absolute;
background-color: #000000;
overflow: hidden;
}
.OT_hidden-audio {
@@ -1090,17 +837,17 @@
}
.OT_audio-level-meter__value {
position: absolute;
border-radius: 50%;
background-image: radial-gradient(circle, rgba(151,206,0,1) 0%, rgba(151,206,0,0) 100%);
}
-.OT_audio-level-meter {
+.OT_audio-level-meter.OT_mode-off {
display: none;
}
.OT_audio-level-meter.OT_mode-on,
.OT_audio-only .OT_audio-level-meter.OT_mode-auto {
display: block;
}
--- a/browser/components/loop/content/shared/libs/sdk.js
+++ b/browser/components/loop/content/shared/libs/sdk.js
@@ -1,25 +1,25 @@
/**
- * @license OpenTok JavaScript Library v2.2.9.1
+ * @license OpenTok JavaScript Library v2.2.9.7
* http://www.tokbox.com/
*
* Copyright (c) 2014 TokBox, Inc.
* Released under the MIT license
* http://opensource.org/licenses/MIT
*
- * Date: September 08 10:17:05 2014
+ * Date: January 26 03:18:02 2015
*/
(function(window) {
if (!window.OT) window.OT = {};
OT.properties = {
- version: 'v2.2.9.1', // The current version (eg. v2.0.4) (This is replaced by gradle)
- build: '72b534e', // The current build hash (This is replaced by gradle)
+ version: 'v2.2.9.7', // The current version (eg. v2.0.4) (This is replaced by gradle)
+ build: '59e99bc', // The current build hash (This is replaced by gradle)
// Whether or not to turn on debug logging by default
debug: 'false',
// The URL of the tokbox website
websiteURL: 'http://www.tokbox.com',
// The URL of the CDN
cdnURL: 'http://static.opentok.com',
@@ -3098,16 +3098,24 @@
* @memberof OT
* @function
* @see <a href="#setLogLevel">OT.setLogLevel()</a>
*/
})(window);
!(function() {
+ var adjustModal = function(callback) {
+ return function setFullHeightDocument(window, document) {
+ // required in IE8
+ document.querySelector('html').style.height = document.body.style.height = '100%';
+ callback(window, document);
+ };
+ };
+
var addCss = function(document, url, callback) {
var head = document.head || document.getElementsByTagName('head')[0];
var cssTag = OT.$.createElement('link', {
type: 'text/css',
media: 'screen',
rel: 'stylesheet',
href: url
});
@@ -3162,213 +3170,20 @@
var linkElement = function(children, href, classes) {
var link = templateElement.call(this, classes || '', children, 'a');
link.setAttribute('href', href);
return link;
};
OT.Dialogs = {};
- OT.Dialogs.AllowDeny = {
- Chrome: {},
- Firefox: {}
- };
-
- OT.Dialogs.AllowDeny.Chrome.initialPrompt = function() {
- var modal = new OT.$.Modal(function(window, document) {
-
- var el = OT.$.bind(templateElement, document),
- close, root;
-
- close = el('OT_closeButton', '×')
- .on('click', function() {
- modal.trigger('closeButtonClicked');
- modal.close();
- });
-
- root = el('OT_root OT_dialog OT_dialog-allow-deny-chrome-first', [
- close,
- el('OT_dialog-messages', [
- el('OT_dialog-messages-main', 'Allow camera and mic access'),
- el('OT_dialog-messages-minor', 'Click the Allow button in the upper-right corner ' +
- 'of your browser to enable real-time communication.'),
- el('OT_dialog-allow-highlight-chrome')
- ])
- ]);
-
- addDialogCSS(document, [], function() {
- document.body.appendChild(root);
- });
-
- });
- return modal;
- };
-
- OT.Dialogs.AllowDeny.Chrome.previouslyDenied = function(website) {
- var modal = new OT.$.Modal(function(window, document) {
-
- var el = OT.$.bind(templateElement, document),
- close,
- root;
-
- close = el('OT_closeButton', '×')
- .on('click', function() {
- modal.trigger('closeButtonClicked');
- modal.close();
- });
-
- root = el('OT_root OT_dialog OT_dialog-allow-deny-chrome-pre-denied', [
- close,
- el('OT_dialog-messages', [
- el('OT_dialog-messages-main', 'Allow camera and mic access'),
- el('OT_dialog-messages-minor', [
- 'To interact with this app, follow these 3 steps:',
- el('OT_dialog-3steps', [
- el('OT_dialog-3steps-step', [
- el('OT_dialog-3steps-step-num', '1'),
- 'Find this icon in the URL bar and click it',
- el('OT_dialog-allow-camera-icon')
- ]),
- el('OT_dialog-3steps-seperator'),
- el('OT_dialog-3steps-step', [
- el('OT_dialog-3steps-step-num', '2'),
- 'Select "Ask if ' + website + ' wants to access your camera and mic" ' +
- 'and then click Done.'
- ]),
- el('OT_dialog-3steps-seperator'),
- el('OT_dialog-3steps-step', [
- el('OT_dialog-3steps-step-num', '3'),
- 'Refresh your browser.'
- ])
- ])
- ])
- ])
- ]);
-
- addDialogCSS(document, [], function() {
- document.body.appendChild(root);
- });
-
- });
- return modal;
- };
-
- OT.Dialogs.AllowDeny.Chrome.deniedNow = function() {
- var modal = new OT.$.Modal(function(window, document) {
-
- var el = OT.$.bind(templateElement, document),
- root;
-
- root = el('OT_root OT_dialog-blackout',
- el('OT_dialog OT_dialog-allow-deny-chrome-now-denied', [
- el('OT_dialog-messages', [
- el('OT_dialog-messages-main ',
- el('OT_dialog-allow-camera-icon')
- ),
- el('OT_dialog-messages-minor',
- 'Find & click this icon to allow camera and mic access.'
- )
- ])
- ])
- );
-
- addDialogCSS(document, [], function() {
- document.body.appendChild(root);
- });
-
- });
- return modal;
- };
-
- OT.Dialogs.AllowDeny.Firefox.maybeDenied = function() {
- var modal = new OT.$.Modal(function(window, document) {
-
- var el = OT.$.bind(templateElement, document),
- close,
- root;
-
- close = el('OT_closeButton', '×')
- .on('click', function() {
- modal.trigger('closeButtonClicked');
- modal.close();
- });
-
- root = el('OT_root OT_dialog OT_dialog-allow-deny-firefox-maybe-denied', [
- close,
- el('OT_dialog-messages', [
- el('OT_dialog-messages-main', 'Please allow camera & mic access'),
- el('OT_dialog-messages-minor', [
- 'To interact with this app, follow these 3 steps:',
- el('OT_dialog-3steps', [
- el('OT_dialog-3steps-step', [
- el('OT_dialog-3steps-step-num', '1'),
- 'Reload the page, or click the camera icon ' +
- 'in the browser URL bar.'
- ]),
- el('OT_dialog-3steps-seperator'),
- el('OT_dialog-3steps-step', [
- el('OT_dialog-3steps-step-num', '2'),
- 'In the menu, select your camera & mic.'
- ]),
- el('OT_dialog-3steps-seperator'),
- el('OT_dialog-3steps-step', [
- el('OT_dialog-3steps-step-num', '3'),
- 'Click "Share Selected Devices."'
- ])
- ])
- ])
- ])
- ]);
-
- addDialogCSS(document, [], function() {
- document.body.appendChild(root);
- });
-
- });
- return modal;
- };
-
- OT.Dialogs.AllowDeny.Firefox.denied = function() {
- var modal = new OT.$.Modal(function(window, document) {
-
- var el = OT.$.bind(templateElement, document),
- btn = OT.$.bind(templateElement, document, 'OT_dialog-button OT_dialog-button-large'),
- root,
- refreshButton;
-
- refreshButton = btn('Reload')
- .on('click', function() {
- modal.trigger('refresh');
- });
-
- root = el('OT_root OT_dialog-blackout',
- el('OT_dialog OT_dialog-allow-deny-firefox-denied', [
- el('OT_dialog-messages', [
- el('OT_dialog-messages-minor',
- 'Access to camera and microphone has been denied. ' +
- 'Click the button to reload page.'
- )
- ]),
- el('OT_dialog-single-button', refreshButton)
- ])
- );
-
- addDialogCSS(document, [], function() {
- document.body.appendChild(root);
- });
-
- });
-
- return modal;
- };
-
OT.Dialogs.Plugin = {};
OT.Dialogs.Plugin.promptToInstall = function() {
- var modal = new OT.$.Modal(function(window, document) {
+ var modal = new OT.$.Modal(adjustModal(function(window, document) {
var el = OT.$.bind(templateElement, document),
btn = function(children, size) {
var classes = 'OT_dialog-button ' +
(size ? 'OT_dialog-button-' + size : 'OT_dialog-button-large'),
b = el(classes, children);
b.enable = function() {
@@ -3386,22 +3201,25 @@
downloadButton = btn('Download plugin'),
cancelButton = btn('cancel', 'small'),
refreshButton = btn('Refresh browser'),
acceptEULA,
checkbox,
close,
root;
+ OT.$.addClass(cancelButton, 'OT_dialog-no-natural-margin OT_dialog-button-block');
+ OT.$.addClass(refreshButton, 'OT_dialog-no-natural-margin');
+
function onDownload() {
modal.trigger('download');
setTimeout(function() {
root.querySelector('.OT_dialog-messages-main').innerHTML =
'Plugin installation successful';
- var sections = root.querySelectorAll('.OT_dialog-single-button-wide');
+ var sections = root.querySelectorAll('.OT_dialog-section');
OT.$.addClass(sections[0], 'OT_dialog-hidden');
OT.$.removeClass(sections[1], 'OT_dialog-hidden');
}, 3000);
}
function onRefresh() {
modal.trigger('refresh');
}
@@ -3446,127 +3264,143 @@
});
acceptEULA = linkElement.call(document,
'end-user license agreement',
'http://tokbox.com/support/ie-eula');
checkbox = checkBoxElement.call(document, null, 'acceptEULA', onToggleEULA);
- root = el('OT_root OT_dialog OT_dialog-plugin-prompt', [
- close,
- el('OT_dialog-messages', [
- el('OT_dialog-messages-main', 'This app requires real-time communication')
- ]),
- el('OT_dialog-single-button-wide', [
- el('OT_dialog-single-button-with-title', [
- el('OT_dialog-button-title', [
- checkbox,
- (function() {
- var x = el('', 'accept', 'label');
- x.setAttribute('for', checkbox.id);
- x.style.margin = '0 5px';
- return x;
- })(),
- acceptEULA
+ root = el('OT_dialog-centering', [
+ el('OT_dialog-centering-child', [
+ el('OT_root OT_dialog OT_dialog-plugin-prompt', [
+ close,
+ el('OT_dialog-messages', [
+ el('OT_dialog-messages-main', 'This app requires real-time communication')
]),
- downloadButton,
- cancelButton
- ])
- ]),
- el('OT_dialog-single-button-wide OT_dialog-hidden', [
- el('OT_dialog-single-button-with-title', [
- el('OT_dialog-button-title', [
- 'You can now enjoy webRTC enabled video via Internet Explorer.'
+ el('OT_dialog-section', [
+ el('OT_dialog-single-button-with-title', [
+ el('OT_dialog-button-title', [
+ checkbox,
+ (function() {
+ var x = el('', 'accept', 'label');
+ x.setAttribute('for', checkbox.id);
+ x.style.margin = '0 5px';
+ return x;
+ })(),
+ acceptEULA
+ ]),
+ el('OT_dialog-actions-card', [
+ downloadButton,
+ cancelButton
+ ])
+ ])
]),
- refreshButton
+ el('OT_dialog-section OT_dialog-hidden', [
+ el('OT_dialog-button-title', [
+ 'You can now enjoy webRTC enabled video via Internet Explorer.'
+ ]),
+ refreshButton
+ ])
])
])
]);
addDialogCSS(document, [], function() {
document.body.appendChild(root);
});
- });
+ }));
return modal;
};
OT.Dialogs.Plugin.promptToReinstall = function() {
- var modal = new OT.$.Modal(function(window, document) {
+ var modal = new OT.$.Modal(adjustModal(function(window, document) {
var el = OT.$.bind(templateElement, document),
close,
okayButton,
root;
close = el('OT_closeButton', '×');
- okayButton = el('OT_dialog-button', 'Okay');
+ okayButton =
+ el('OT_dialog-button OT_dialog-button-large OT_dialog-no-natural-margin', 'Okay');
OT.$.on(okayButton, 'click', function() {
modal.trigger('okay');
});
OT.$.on(close, 'click', function() {
modal.trigger('closeButtonClicked');
modal.close();
});
- root = el('OT_ROOT OT_dialog OT_dialog-plugin-reinstall', [
- close,
- el('OT_dialog-messages', [
- el('OT_dialog-messages-main', 'Reinstall Opentok Plugin'),
- el('OT_dialog-messages-minor', 'Uh oh! Try reinstalling the OpenTok plugin again to ' +
- 'enable real-time video communication for Internet Explorer.')
- ]),
- el('OT_dialog-single-button', okayButton)
+ root = el('OT_dialog-centering', [
+ el('OT_dialog-centering-child', [
+ el('OT_ROOT OT_dialog OT_dialog-plugin-reinstall', [
+ close,
+ el('OT_dialog-messages', [
+ el('OT_dialog-messages-main', 'Reinstall Opentok Plugin'),
+ el('OT_dialog-messages-minor', 'Uh oh! Try reinstalling the OpenTok plugin ' +
+ 'again to enable real-time video communication for Internet Explorer.')
+ ]),
+ el('OT_dialog-section', [
+ el('OT_dialog-single-button', okayButton)
+ ])
+ ])
+ ])
]);
addDialogCSS(document, [], function() {
document.body.appendChild(root);
});
- });
+ }));
return modal;
};
OT.Dialogs.Plugin.updateInProgress = function() {
var progressBar,
progressText,
progressValue = 0;
- var modal = new OT.$.Modal(function(window, document) {
+ var modal = new OT.$.Modal(adjustModal(function(window, document) {
var el = OT.$.bind(templateElement, document),
root;
progressText = el('OT_dialog-plugin-upgrade-percentage', '0%', 'strong');
progressBar = el('OT_dialog-progress-bar-fill');
- root = el('OT_ROOT OT_dialog OT_dialog-plugin-upgrading', [
- el('OT_dialog-messages', [
- el('OT_dialog-messages-main', [
- 'One moment please... ',
- progressText
- ]),
- el('OT_dialog-progress-bar', progressBar),
- el('OT_dialog-messages-minor', 'Please wait while the OpenTok plugin is updated')
+ root = el('OT_dialog-centering', [
+ el('OT_dialog-centering-child', [
+ el('OT_ROOT OT_dialog OT_dialog-plugin-upgrading', [
+ el('OT_dialog-messages', [
+ el('OT_dialog-messages-main', [
+ 'One moment please... ',
+ progressText
+ ]),
+ el('OT_dialog-progress-bar', progressBar),
+ el('OT_dialog-messages-minor OT_dialog-no-natural-margin',
+ 'Please wait while the OpenTok plugin is updated')
+ ])
+ ])
])
]);
addDialogCSS(document, [], function() {
document.body.appendChild(root);
if(progressValue != null) {
modal.setUpdateProgress(progressValue);
}
});
- });
+ }));
modal.setUpdateProgress = function(newProgress) {
if(progressBar && progressText) {
if(newProgress > 99) {
OT.$.css(progressBar, 'width', '');
progressText.innerHTML = '100%';
} else if(newProgress < 1) {
OT.$.css(progressBar, 'width', '0%');
@@ -3579,48 +3413,54 @@
progressValue = newProgress;
}
};
return modal;
};
OT.Dialogs.Plugin.updateComplete = function(error) {
- var modal = new OT.$.Modal(function(window, document) {
+ var modal = new OT.$.Modal(adjustModal(function(window, document) {
var el = OT.$.bind(templateElement, document),
reloadButton,
root;
- reloadButton = el('OT_dialog-button', 'Reload').on('click', function() {
- modal.trigger('reload');
- });
+ reloadButton =
+ el('OT_dialog-button OT_dialog-button-large OT_dialog-no-natural-margin', 'Reload')
+ .on('click', function() {
+ modal.trigger('reload');
+ });
var msgs;
if(error) {
msgs = ['Update Failed.', error + '' || 'NO ERROR'];
} else {
msgs = ['Update Complete.',
'The OpenTok plugin has been succesfully updated. ' +
'Please reload your browser.'];
}
- root = el('OT_root OT_dialog OT_dialog-plugin-upgraded', [
- el('OT_dialog-messages', [
- el('OT_dialog-messages-main', msgs[0]),
- el('OT_dialog-messages-minor', msgs[1])
- ]),
- el('OT_dialog-single-button', reloadButton)
+ root = el('OT_dialog-centering', [
+ el('OT_dialog-centering-child', [
+ el('OT_root OT_dialog OT_dialog-plugin-upgraded', [
+ el('OT_dialog-messages', [
+ el('OT_dialog-messages-main', msgs[0]),
+ el('OT_dialog-messages-minor', msgs[1])
+ ]),
+ el('OT_dialog-single-button', reloadButton)
+ ])
+ ])
]);
addDialogCSS(document, [], function() {
document.body.appendChild(root);
});
- });
+ }));
return modal;
};
})();
!(function(window) {
@@ -3806,24 +3646,22 @@
OT.$.eventing(_this);
return _this;
})();
})(window);
/**
- * @license TB Plugin 0.4.0.8 72b534e HEAD
+ * @license TB Plugin 0.4.0.8 59e99bc HEAD
* http://www.tokbox.com/
*
- * Copyright (c) 2014 TokBox, Inc.
- * Released under the MIT license
- * http://opensource.org/licenses/MIT
- *
- * Date: September 08 10:17:49 2014
+ * Copyright (c) 2015 TokBox, Inc.
+ *
+ * Date: January 26 03:18:16 2015
*
*/
/* jshint globalstrict: true, strict: false, undef: true, unused: false,
trailing: true, browser: true, smarttabs:true */
/* global scope:true, OT:true */
/* exported TBPlugin */
@@ -3950,16 +3788,82 @@ var shim = function shim () {
return res;
};
}
};
// tb_require('./header.js')
// tb_require('./shims.js')
+/* global OT:true */
+/* exported PluginRumorSocket */
+
+var PluginRumorSocket = function(plugin, server) {
+ var connected = false,
+ rumorID;
+
+ try {
+ rumorID = plugin._.RumorInit(server, '');
+ }
+ catch(e) {
+ OT.error('Error creating the Rumor Socket: ', e.message);
+ }
+
+ if(!rumorID) {
+ throw new Error('Could not initialise plugin rumor connection');
+ }
+
+ var socket = {
+ open: function() {
+ connected = true;
+ plugin._.RumorOpen(rumorID);
+ },
+
+ close: function(code, reason) {
+ if (!connected) return;
+ connected = false;
+
+ plugin._.RumorClose(rumorID, code, reason);
+ plugin.removeRef(this);
+ },
+
+ destroy: function() {
+ this.close();
+ },
+
+ send: function(msg) {
+ plugin._.RumorSend(rumorID, msg.type, msg.toAddress,
+ JSON.parse(JSON.stringify(msg.headers)), msg.data);
+ },
+
+ onOpen: function(callback) {
+ plugin._.SetOnRumorOpen(rumorID, callback);
+ },
+
+ onClose: function(callback) {
+ plugin._.SetOnRumorClose(rumorID, callback);
+ },
+
+ onError: function(callback) {
+ plugin._.SetOnRumorError(rumorID, callback);
+ },
+
+ onMessage: function(callback) {
+ plugin._.SetOnRumorMessage(rumorID, callback);
+ }
+ };
+
+ plugin.addRef(socket);
+ return socket;
+
+};
+
+// tb_require('./header.js')
+// tb_require('./shims.js')
+
/* jshint globalstrict: true, strict: false, undef: true, unused: true,
trailing: true, browser: true, smarttabs:true */
/* global OT:true, TBPlugin:true, pluginInfo:true, debug:true, scope:true,
_document:true */
/* exported createMediaCaptureController:true, createPeerController:true,
injectObject:true, plugins:true, mediaCaptureObject:true,
removeAllObjects:true, curryCallAsync:true */
@@ -4351,470 +4255,16 @@ var VideoContainer = function VideoConta
};
// tb_require('./header.js')
// tb_require('./shims.js')
// tb_require('./plugin_object.js')
/* jshint globalstrict: true, strict: false, undef: true, unused: true,
trailing: true, browser: true, smarttabs:true */
-/* global OT:true, TBPlugin:true, pluginInfo:true, ActiveXObject:true,
- injectObject:true, curryCallAsync:true */
-
-/* exported AutoUpdater:true */
-var AutoUpdater;
-
-(function() {
-
- var autoUpdaterController,
- updaterMimeType, // <- cached version, use getInstallerMimeType instead
- installedVersion = -1; // <- cached version, use getInstallerMimeType instead
-
-
- var versionGreaterThan = function versionGreaterThan (version1,version2) {
- if (version1 === version2) return false;
-
- var v1 = version1.split('.'),
- v2 = version2.split('.');
-
- v1 = parseFloat(parseInt(v1.shift(), 10) + '.' +
- v1.map(function(vcomp) { return parseInt(vcomp, 10); }).join(''));
-
- v2 = parseFloat(parseInt(v2.shift(), 10) + '.' +
- v2.map(function(vcomp) { return parseInt(vcomp, 10); }).join(''));
-
-
- return v1 > v2;
- };
-
-
- // Work out the full mimeType (including the currently installed version)
- // of the installer.
- var findMimeTypeAndVersion = function findMimeTypeAndVersion () {
-
- if (updaterMimeType !== void 0) {
- return updaterMimeType;
- }
-
- var activeXControlId = 'TokBox.otiePluginInstaller',
- unversionedMimeType = 'application/x-otieplugininstaller',
- plugin = navigator.plugins[activeXControlId];
-
- installedVersion = -1;
-
-
- if (plugin) {
- // Look through the supported mime-types for the version
- // There should only be one mime-type in our use case, and
- // if there's more than one they should all have the same
- // version.
- var numMimeTypes = plugin.length,
- extractVersion = new RegExp(unversionedMimeType.replace('-', '\\-') +
- ',version=([0-9]+)', 'i'),
- mimeType,
- bits;
-
- for (var i=0; i<numMimeTypes; ++i) {
- mimeType = plugin[i];
-
- // Look through the supported mimeTypes and find
- // the newest one.
- if (mimeType && mimeType.enabledPlugin &&
- (mimeType.enabledPlugin.name === plugin.name) &&
- mimeType.type.indexOf(unversionedMimeType) !== -1) {
-
- bits = extractVersion.exec(mimeType.type);
-
- if (bits !== null && versionGreaterThan(bits[1], installedVersion)) {
- installedVersion = bits[1];
- }
- }
- }
- }
- else {
- // This may mean that the installer plugin is not installed.
- // Although it could also mean that we're on IE 9 and below,
- // which does not support navigator.plugins. Fallback to
- // using 'ActiveXObject' instead.
- try {
- plugin = new ActiveXObject(activeXControlId);
- installedVersion = plugin.getMasterVersion();
- } catch(e) {
- }
- }
-
- updaterMimeType = installedVersion !== -1 ?
- unversionedMimeType + ',version=' + installedVersion :
- null;
- };
-
- var getInstallerMimeType = function getInstallerMimeType () {
- if (updaterMimeType === void 0) {
- findMimeTypeAndVersion();
- }
-
- return updaterMimeType;
- };
-
- var getInstalledVersion = function getInstalledVersion () {
- if (installedVersion === void 0) {
- findMimeTypeAndVersion();
- }
-
- return installedVersion;
- };
-
- // Version 0.4.0.4 autoupdate was broken. We want to prompt
- // for install on 0.4.0.4 or earlier. We're also including
- // earlier versions just in case...
- var hasBrokenUpdater = function () {
- var _broken = !versionGreaterThan(getInstalledVersion(), '0.4.0.4');
-
- hasBrokenUpdater = function() { return _broken; };
- return _broken;
- };
-
-
- AutoUpdater = function (plugin) {
-
- // Returns true if the version of the plugin installed on this computer
- // does not match the one expected by this version of TBPlugin.
- this.isOutOfDate = function () {
- return versionGreaterThan(pluginInfo.version, getInstalledVersion());
- };
-
- this.autoUpdate = function () {
- var modal = OT.Dialogs.Plugin.updateInProgress(),
- analytics = new OT.Analytics(),
- payload = {
- ieVersion: OT.$.browserVersion().version,
- pluginOldVersion: TBPlugin.installedVersion(),
- pluginNewVersion: TBPlugin.version()
- };
-
- var success = curryCallAsync(function() {
- analytics.logEvent({
- action: 'OTPluginAutoUpdate',
- variation: 'Success',
- partnerId: OT.APIKEY,
- payload: JSON.stringify(payload)
- });
-
- plugin.destroy();
-
- modal.close();
- OT.Dialogs.Plugin.updateComplete().on({
- reload: function() {
- window.location.reload();
- }
- });
- }),
-
- error = curryCallAsync(function(errorCode, errorMessage, systemErrorCode) {
- payload.errorCode = errorCode;
- payload.systemErrorCode = systemErrorCode;
-
- analytics.logEvent({
- action: 'OTPluginAutoUpdate',
- variation: 'Failure',
- partnerId: OT.APIKEY,
- payload: JSON.stringify(payload)
- });
-
- plugin.destroy();
-
- modal.close();
- var updateMessage = errorMessage + ' (' + errorCode +
- '). Please restart your browser and try again.';
-
- modal = OT.Dialogs.Plugin.updateComplete(updateMessage).on({
- 'reload': function() {
- modal.close();
- }
- });
-
- OT.error('autoUpdate failed: ' + errorMessage + ' (' + errorCode +
- '). Please restart your browser and try again.');
- // TODO log client event
- }),
-
- progress = curryCallAsync(function(progress) {
- modal.setUpdateProgress(progress.toFixed());
- // modalBody.innerHTML = 'Updating...' + progress.toFixed() + '%';
- });
-
- plugin._.updatePlugin(TBPlugin.pathToInstaller(), success, error, progress);
- };
-
- this.destroy = function() {
- plugin.destroy();
- };
- };
-
- AutoUpdater.get = function (completion) {
- if (autoUpdaterController) {
- completion.call(null, void 0, autoUpdaterController);
- return;
- }
-
- if (!this.isinstalled()) {
- completion.call(null, 'Plugin was not installed');
- return;
- }
-
- injectObject(getInstallerMimeType(), false, {windowless: false}, function(err, plugin) {
- if (plugin) autoUpdaterController = new AutoUpdater(plugin);
- completion.call(null, err, autoUpdaterController);
- });
- };
-
- AutoUpdater.isinstalled = function () {
- return getInstallerMimeType() !== null && !hasBrokenUpdater();
- };
-
- AutoUpdater.installedVersion = function () {
- return getInstalledVersion();
- };
-
-})();
-
-// tb_require('./header.js')
-// tb_require('./shims.js')
-// tb_require('./plugin_object.js')
-// tb_require('./video_container.js')
-
-/* jshint globalstrict: true, strict: false, undef: true, unused: true,
- trailing: true, browser: true, smarttabs:true */
-/* global OT:true, VideoContainer:true */
-/* exported MediaStream */
-
-var MediaStreamTrack = function MediaStreamTrack (mediaStreamId, options, plugin) {
- this.id = options.id;
- this.kind = options.kind;
- this.label = options.label;
- this.enabled = OT.$.castToBoolean(options.enabled);
- this.streamId = mediaStreamId;
-
- this.setEnabled = function (enabled) {
- this.enabled = OT.$.castToBoolean(enabled);
-
- if (this.enabled) {
- plugin._.enableMediaStreamTrack(mediaStreamId, this.id);
- }
- else {
- plugin._.disableMediaStreamTrack(mediaStreamId, this.id);
- }
- };
-};
-
-var MediaStream = function MediaStream (options, plugin) {
- var audioTracks = [],
- videoTracks = [];
-
- this.id = options.id;
- plugin.addRef(this);
-
- // TODO
- // this.ended =
- // this.onended =
-
- if (options.videoTracks) {
- options.videoTracks.map(function(track) {
- videoTracks.push( new MediaStreamTrack(options.id, track, plugin) );
- });
- }
-
- if (options.audioTracks) {
- options.audioTracks.map(function(track) {
- audioTracks.push( new MediaStreamTrack(options.id, track, plugin) );
- });
- }
-
- var hasTracksOfType = function (type) {
- var tracks = type === 'video' ? videoTracks : audioTracks;
-
- return OT.$.some(tracks, function(track) {
- return track.enabled;
- });
- };
-
- this.getVideoTracks = function () { return videoTracks; };
- this.getAudioTracks = function () { return audioTracks; };
-
- this.getTrackById = function (id) {
- videoTracks.concat(audioTracks).forEach(function(track) {
- if (track.id === id) return track;
- });
-
- return null;
- };
-
- this.hasVideo = function () {
- return hasTracksOfType('video');
- };
-
- this.hasAudio = function () {
- return hasTracksOfType('audio');
- };
-
- this.addTrack = function (/* MediaStreamTrack */) {
- // TODO
- };
-
- this.removeTrack = function (/* MediaStreamTrack */) {
- // TODO
- };
-
- this.stop = function() {
- plugin._.stopMediaStream(this.id);
- plugin.removeRef(this);
- };
-
- this.destroy = function() {
- this.stop();
- };
-
- // Private MediaStream API
- this._ = {
- plugin: plugin,
-
- // Get a VideoContainer to render the stream in.
- render: OT.$.bind(function() {
- return new VideoContainer(plugin, this);
- }, this)
- };
-};
-
-
-MediaStream.fromJson = function (json, plugin) {
- if (!json) return null;
- return new MediaStream( JSON.parse(json), plugin );
-};
-
-// tb_require('./header.js')
-// tb_require('./shims.js')
-
-/* global OT:true */
-/* exported PluginRumorSocket */
-
-var PluginRumorSocket = function(plugin, server) {
- var connected = false,
- rumorID;
-
- try {
- rumorID = plugin._.RumorInit(server, '');
- }
- catch(e) {
- OT.error('Error creating the Rumor Socket: ', e.message);
- }
-
- if(!rumorID) {
- throw new Error('Could not initialise plugin rumor connection');
- }
-
- var socket = {
- open: function() {
- connected = true;
- plugin._.RumorOpen(rumorID);
- },
-
- close: function(code, reason) {
- if (!connected) return;
- connected = false;
-
- plugin._.RumorClose(rumorID, code, reason);
- plugin.removeRef(this);
- },
-
- destroy: function() {
- this.close();
- },
-
- send: function(msg) {
- plugin._.RumorSend(rumorID, msg.type, msg.toAddress,
- JSON.parse(JSON.stringify(msg.headers)), msg.data);
- },
-
- onOpen: function(callback) {
- plugin._.SetOnRumorOpen(rumorID, callback);
- },
-
- onClose: function(callback) {
- plugin._.SetOnRumorClose(rumorID, callback);
- },
-
- onError: function(callback) {
- plugin._.SetOnRumorError(rumorID, callback);
- },
-
- onMessage: function(callback) {
- plugin._.SetOnRumorMessage(rumorID, callback);
- }
- };
-
- plugin.addRef(socket);
- return socket;
-
-};
-
-// tb_require('./header.js')
-// tb_require('./shims.js')
-// tb_require('./plugin_object.js')
-// tb_require('./video_container.js')
-
-/* jshint globalstrict: true, strict: false, undef: true, unused: true,
- trailing: true, browser: true, smarttabs:true */
-/* global OT:true */
-/* exported MediaConstraints */
-
-var MediaConstraints = function(userConstraints) {
- var constraints = OT.$.clone(userConstraints);
-
- this.hasVideo = constraints.video !== void 0 && constraints.video !== false;
- this.hasAudio = constraints.audio !== void 0 && constraints.audio !== false;
-
- if (constraints.video === true) constraints.video = {};
- if (constraints.audio === true) constraints.audio = {};
-
- if (this.hasVideo && !constraints.video.mandatory) {
- constraints.video.mandatory = {};
- }
-
- if (this.hasAudio && !constraints.audio.mandatory) {
- constraints.audio.mandatory = {};
- }
-
- this.screenSharing = this.hasVideo &&
- ( constraints.video.mandatory.chromeMediaSource === 'screen' ||
- constraints.video.mandatory.chromeMediaSource === 'window' );
-
- this.audio = constraints.audio;
- this.video = constraints.video;
-
- this.setVideoSource = function(sourceId) {
- if (sourceId !== void 0) constraints.video.mandatory.sourceId = sourceId;
- else delete constraints.video;
- };
-
- this.setAudioSource = function(sourceId) {
- if (sourceId !== void 0) constraints.audio.mandatory.sourceId = sourceId;
- else delete constraints.audio;
- };
-
- this.toHash = function() {
- return constraints;
- };
-};
-
-// tb_require('./header.js')
-// tb_require('./shims.js')
-// tb_require('./plugin_object.js')
-
-/* jshint globalstrict: true, strict: false, undef: true, unused: true,
- trailing: true, browser: true, smarttabs:true */
/* exported RTCStatsReport */
var RTCStatsReport = function (reports) {
this.forEach = function (callback, context) {
for (var id in reports) {
callback.call(context, reports[id]);
}
};
@@ -5033,16 +4483,404 @@ var PeerConnection = function PeerConnec
};
// tb_require('./header.js')
// tb_require('./shims.js')
// tb_require('./plugin_object.js')
+// tb_require('./video_container.js')
+
+/* jshint globalstrict: true, strict: false, undef: true, unused: true,
+ trailing: true, browser: true, smarttabs:true */
+/* global OT:true, VideoContainer:true */
+/* exported MediaStream */
+
+var MediaStreamTrack = function MediaStreamTrack (mediaStreamId, options, plugin) {
+ this.id = options.id;
+ this.kind = options.kind;
+ this.label = options.label;
+ this.enabled = OT.$.castToBoolean(options.enabled);
+ this.streamId = mediaStreamId;
+
+ this.setEnabled = function (enabled) {
+ this.enabled = OT.$.castToBoolean(enabled);
+
+ if (this.enabled) {
+ plugin._.enableMediaStreamTrack(mediaStreamId, this.id);
+ }
+ else {
+ plugin._.disableMediaStreamTrack(mediaStreamId, this.id);
+ }
+ };
+};
+
+var MediaStream = function MediaStream (options, plugin) {
+ var audioTracks = [],
+ videoTracks = [];
+
+ this.id = options.id;
+ plugin.addRef(this);
+
+ // TODO
+ // this.ended =
+ // this.onended =
+
+ if (options.videoTracks) {
+ options.videoTracks.map(function(track) {
+ videoTracks.push( new MediaStreamTrack(options.id, track, plugin) );
+ });
+ }
+
+ if (options.audioTracks) {
+ options.audioTracks.map(function(track) {
+ audioTracks.push( new MediaStreamTrack(options.id, track, plugin) );
+ });
+ }
+
+ var hasTracksOfType = function (type) {
+ var tracks = type === 'video' ? videoTracks : audioTracks;
+
+ return OT.$.some(tracks, function(track) {
+ return track.enabled;
+ });
+ };
+
+ this.getVideoTracks = function () { return videoTracks; };
+ this.getAudioTracks = function () { return audioTracks; };
+
+ this.getTrackById = function (id) {
+ videoTracks.concat(audioTracks).forEach(function(track) {
+ if (track.id === id) return track;
+ });
+
+ return null;
+ };
+
+ this.hasVideo = function () {
+ return hasTracksOfType('video');
+ };
+
+ this.hasAudio = function () {
+ return hasTracksOfType('audio');
+ };
+
+ this.addTrack = function (/* MediaStreamTrack */) {
+ // TODO
+ };
+
+ this.removeTrack = function (/* MediaStreamTrack */) {
+ // TODO
+ };
+
+ this.stop = function() {
+ plugin._.stopMediaStream(this.id);
+ plugin.removeRef(this);
+ };
+
+ this.destroy = function() {
+ this.stop();
+ };
+
+ // Private MediaStream API
+ this._ = {
+ plugin: plugin,
+
+ // Get a VideoContainer to render the stream in.
+ render: OT.$.bind(function() {
+ return new VideoContainer(plugin, this);
+ }, this)
+ };
+};
+
+
+MediaStream.fromJson = function (json, plugin) {
+ if (!json) return null;
+ return new MediaStream( JSON.parse(json), plugin );
+};
+
+// tb_require('./header.js')
+// tb_require('./shims.js')
+// tb_require('./plugin_object.js')
+// tb_require('./video_container.js')
+
+/* jshint globalstrict: true, strict: false, undef: true, unused: true,
+ trailing: true, browser: true, smarttabs:true */
+/* global OT:true */
+/* exported MediaConstraints */
+
+var MediaConstraints = function(userConstraints) {
+ var constraints = OT.$.clone(userConstraints);
+
+ this.hasVideo = constraints.video !== void 0 && constraints.video !== false;
+ this.hasAudio = constraints.audio !== void 0 && constraints.audio !== false;
+
+ if (constraints.video === true) constraints.video = {};
+ if (constraints.audio === true) constraints.audio = {};
+
+ if (this.hasVideo && !constraints.video.mandatory) {
+ constraints.video.mandatory = {};
+ }
+
+ if (this.hasAudio && !constraints.audio.mandatory) {
+ constraints.audio.mandatory = {};
+ }
+
+ this.screenSharing = this.hasVideo &&
+ ( constraints.video.mandatory.chromeMediaSource === 'screen' ||
+ constraints.video.mandatory.chromeMediaSource === 'window' );
+
+ this.audio = constraints.audio;
+ this.video = constraints.video;
+
+ this.setVideoSource = function(sourceId) {
+ if (sourceId !== void 0) constraints.video.mandatory.sourceId = sourceId;
+ else delete constraints.video;
+ };
+
+ this.setAudioSource = function(sourceId) {
+ if (sourceId !== void 0) constraints.audio.mandatory.sourceId = sourceId;
+ else delete constraints.audio;
+ };
+
+ this.toHash = function() {
+ return constraints;
+ };
+};
+
+// tb_require('./header.js')
+// tb_require('./shims.js')
+// tb_require('./plugin_object.js')
+
+/* jshint globalstrict: true, strict: false, undef: true, unused: true,
+ trailing: true, browser: true, smarttabs:true */
+/* global OT:true, TBPlugin:true, pluginInfo:true, ActiveXObject:true,
+ injectObject:true, curryCallAsync:true */
+
+/* exported AutoUpdater:true */
+var AutoUpdater;
+
+(function() {
+
+ var autoUpdaterController,
+ updaterMimeType, // <- cached version, use getInstallerMimeType instead
+ installedVersion = -1; // <- cached version, use getInstallerMimeType instead
+
+
+ var versionGreaterThan = function versionGreaterThan (version1,version2) {
+ if (version1 === version2) return false;
+
+ var v1 = version1.split('.'),
+ v2 = version2.split('.');
+
+ v1 = parseFloat(parseInt(v1.shift(), 10) + '.' +
+ v1.map(function(vcomp) { return parseInt(vcomp, 10); }).join(''));
+
+ v2 = parseFloat(parseInt(v2.shift(), 10) + '.' +
+ v2.map(function(vcomp) { return parseInt(vcomp, 10); }).join(''));
+
+
+ return v1 > v2;
+ };
+
+
+ // Work out the full mimeType (including the currently installed version)
+ // of the installer.
+ var findMimeTypeAndVersion = function findMimeTypeAndVersion () {
+
+ if (updaterMimeType !== void 0) {
+ return updaterMimeType;
+ }
+
+ var activeXControlId = 'TokBox.otiePluginInstaller',
+ unversionedMimeType = 'application/x-otieplugininstaller',
+ plugin = navigator.plugins[activeXControlId];
+
+ installedVersion = -1;
+
+
+ if (plugin) {
+ // Look through the supported mime-types for the version
+ // There should only be one mime-type in our use case, and
+ // if there's more than one they should all have the same
+ // version.
+ var numMimeTypes = plugin.length,
+ extractVersion = new RegExp(unversionedMimeType.replace('-', '\\-') +
+ ',version=([0-9]+)', 'i'),
+ mimeType,
+ bits;
+
+ for (var i=0; i<numMimeTypes; ++i) {
+ mimeType = plugin[i];
+
+ // Look through the supported mimeTypes and find
+ // the newest one.
+ if (mimeType && mimeType.enabledPlugin &&
+ (mimeType.enabledPlugin.name === plugin.name) &&
+ mimeType.type.indexOf(unversionedMimeType) !== -1) {
+
+ bits = extractVersion.exec(mimeType.type);
+
+ if (bits !== null && versionGreaterThan(bits[1], installedVersion)) {
+ installedVersion = bits[1];
+ }
+ }
+ }
+ }
+ else {
+ // This may mean that the installer plugin is not installed.
+ // Although it could also mean that we're on IE 9 and below,
+ // which does not support navigator.plugins. Fallback to
+ // using 'ActiveXObject' instead.
+ try {
+ plugin = new ActiveXObject(activeXControlId);
+ installedVersion = plugin.getMasterVersion();
+ } catch(e) {
+ }
+ }
+
+ updaterMimeType = installedVersion !== -1 ?
+ unversionedMimeType + ',version=' + installedVersion :
+ null;
+ };
+
+ var getInstallerMimeType = function getInstallerMimeType () {
+ if (updaterMimeType === void 0) {
+ findMimeTypeAndVersion();
+ }
+
+ return updaterMimeType;
+ };
+
+ var getInstalledVersion = function getInstalledVersion () {
+ if (installedVersion === void 0) {
+ findMimeTypeAndVersion();
+ }
+
+ return installedVersion;
+ };
+
+ // Version 0.4.0.4 autoupdate was broken. We want to prompt
+ // for install on 0.4.0.4 or earlier. We're also including
+ // earlier versions just in case...
+ var hasBrokenUpdater = function () {
+ var _broken = !versionGreaterThan(getInstalledVersion(), '0.4.0.4');
+
+ hasBrokenUpdater = function() { return _broken; };
+ return _broken;
+ };
+
+
+ AutoUpdater = function (plugin) {
+
+ // Returns true if the version of the plugin installed on this computer
+ // does not match the one expected by this version of TBPlugin.
+ this.isOutOfDate = function () {
+ return versionGreaterThan(pluginInfo.version, getInstalledVersion());
+ };
+
+ this.autoUpdate = function () {
+ var modal = OT.Dialogs.Plugin.updateInProgress(),
+ analytics = new OT.Analytics(),
+ payload = {
+ ieVersion: OT.$.browserVersion().version,
+ pluginOldVersion: TBPlugin.installedVersion(),
+ pluginNewVersion: TBPlugin.version()
+ };
+
+ var success = curryCallAsync(function() {
+ analytics.logEvent({
+ action: 'OTPluginAutoUpdate',
+ variation: 'Success',
+ partnerId: OT.APIKEY,
+ payload: JSON.stringify(payload)
+ });
+
+ plugin.destroy();
+
+ modal.close();
+ OT.Dialogs.Plugin.updateComplete().on({
+ reload: function() {
+ window.location.reload();
+ }
+ });
+ }),
+
+ error = curryCallAsync(function(errorCode, errorMessage, systemErrorCode) {
+ payload.errorCode = errorCode;
+ payload.systemErrorCode = systemErrorCode;
+
+ analytics.logEvent({
+ action: 'OTPluginAutoUpdate',
+ variation: 'Failure',
+ partnerId: OT.APIKEY,
+ payload: JSON.stringify(payload)
+ });
+
+ plugin.destroy();
+
+ modal.close();
+ var updateMessage = errorMessage + ' (' + errorCode +
+ '). Please restart your browser and try again.';
+
+ modal = OT.Dialogs.Plugin.updateComplete(updateMessage).on({
+ 'reload': function() {
+ modal.close();
+ }
+ });
+
+ OT.error('autoUpdate failed: ' + errorMessage + ' (' + errorCode +
+ '). Please restart your browser and try again.');
+ // TODO log client event
+ }),
+
+ progress = curryCallAsync(function(progress) {
+ modal.setUpdateProgress(progress.toFixed());
+ // modalBody.innerHTML = 'Updating...' + progress.toFixed() + '%';
+ });
+
+ plugin._.updatePlugin(TBPlugin.pathToInstaller(), success, error, progress);
+ };
+
+ this.destroy = function() {
+ plugin.destroy();
+ };
+ };
+
+ AutoUpdater.get = function (completion) {
+ if (autoUpdaterController) {
+ completion.call(null, void 0, autoUpdaterController);
+ return;
+ }
+
+ if (!this.isinstalled()) {
+ completion.call(null, 'Plugin was not installed');
+ return;
+ }
+
+ injectObject(getInstallerMimeType(), false, {windowless: false}, function(err, plugin) {
+ if (plugin) autoUpdaterController = new AutoUpdater(plugin);
+ completion.call(null, err, autoUpdaterController);
+ });
+ };
+
+ AutoUpdater.isinstalled = function () {
+ return getInstallerMimeType() !== null && !hasBrokenUpdater();
+ };
+
+ AutoUpdater.installedVersion = function () {
+ return getInstalledVersion();
+ };
+
+})();
+
+// tb_require('./header.js')
+// tb_require('./shims.js')
+// tb_require('./plugin_object.js')
// tb_require('./auto_updater.js')
// tb_require('./media_constraints.js')
// tb_require('./peer_connection.js')
// tb_require('./media_stream.js')
// tb_require('./video_container.js')
// tb_require('./rumor.js')
/* jshint globalstrict: true, strict: false, undef: true,
@@ -7012,17 +6850,17 @@ waitForDomReady();
// Map of camel-cased keys to underscored
camelCasedKeys,
browser = OT.$.browserVersion(),
send = function(data, isQos, callback) {
OT.$.post((isQos ? endPointQos : endPoint) + '?_=' + OT.$.uuid.v4(), {
body: data,
- xdomainrequest: (browser.browser === 'IE' & browser.version < 10),
+ xdomainrequest: (browser.browser === 'IE' && browser.version < 10),
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
}, callback);
},
throttledPost = function() {
// Throttle logs so that they only happen 1 at a time
@@ -9168,17 +9006,17 @@ waitForDomReady();
*
* Original source: https://github.com/inexorabletash/text-encoding
***/
(function(global) {
'use strict';
var browser = OT.$.browserVersion();
- if(browser.browser === 'IE' && browser.version < 10) {
+ if(browser && browser.browser === 'IE' && browser.version < 10) {
return; // IE 8 doesn't do websockets. No websockets, no encoding.
}
if ( (global.TextEncoder !== void 0) && (global.TextDecoder !== void 0)) {
// defer to the native ones
// @todo is this a good idea?
return;
}
@@ -13533,18 +13371,20 @@ waitForDomReady();
if (session.archives.has(dict.id)) return;
var archive = parseArchive(dict);
session.archives.add(archive);
return archive;
}
- var sessionRead;
- var sessionReadQueue = [];
+ var sessionRead,
+ sessionReadQueue = [],
+ // streams for which corresponding connectionCreated events have not been dispatched:
+ unconnectedStreams = {};
function sessionReadQueuePush(type, args) {
var triggerArgs = ['signal'];
triggerArgs.push.apply(triggerArgs, args);
sessionReadQueue.push(triggerArgs);
}
window.OT.SessionDispatcher = function(session) {
@@ -13604,25 +13444,39 @@ waitForDomReady();
});
dispatcher.on('connection#created', function(connection) {
connection = OT.Connection.fromHash(connection);
if (session.connection && connection.id !== session.connection.id) {
session.connections.add( connection );
}
+
+ OT.$.forEach(OT.$.keys(unconnectedStreams), function(streamId) {
+ var stream = unconnectedStreams[streamId];
+ if (stream && connection.id === stream.connection.id) {
+ // dispatch streamCreated event now that the connectionCreated has been dispatched
+ parseAndAddStreamToSession(stream, session);
+ delete unconnectedStreams[stream.id];
+ }
+ });
});
dispatcher.on('connection#deleted', function(connection, reason) {
connection = session.connections.get(connection);
connection.destroy(reason);
});
dispatcher.on('stream#created', function(stream, transactionId) {
- stream = parseAndAddStreamToSession(stream, session);
+ var connectionId = stream.connectionId ? stream.connectionId : stream.connection.id;
+ if (session.connections.has(connectionId)) {
+ stream = parseAndAddStreamToSession(stream, session);
+ } else {
+ unconnectedStreams[stream.id] = stream;
+ }
if (stream.publisher) {
stream.publisher.setStream(stream);
}
dispatcher.triggerCallback(transactionId, null, stream);
});
@@ -14767,16 +14621,32 @@ waitForDomReady();
this.destroy = function() {};
};
})(window);
!(function() {
+ /**
+ * Lazy instantiates an audio context and always return the same instance on following calls
+ *
+ * @returns {AudioContext}
+ */
+ OT.audioContext = function() {
+ var context = new window.AudioContext();
+ OT.audioContext = function() {
+ return context;
+ };
+ return context;
+ };
+
+})();
+!(function() {
+
/*
* A <code>RTCPeerConnection.getStats</code> based audio level sampler.
*
* It uses the the <code>getStats</code> method to get the <code>audioOutputLevel</code>.
* This implementation expects the single parameter version of the <code>getStats</code> method.
*
* Currently the <code>audioOutputLevel</code> stats is only supported in Chrome.
@@ -14929,17 +14799,150 @@ waitForDomReady();
this.stop = function() {
window.clearInterval(_intervalId);
_intervalId = null;
};
};
})(window);
+// tb_require('../../helpers/helpers.js')
+
+/* jshint globalstrict: true, strict: false, undef: true, unused: true,
+ trailing: true, browser: true, smarttabs:true */
+/* global OT */
+/* exported SDPHelpers */
+
+var findIndex = function(array, iter, ctx) {
+ if (!OT.$.isFunction(iter)) {
+ throw new TypeError('iter must be a function');
+ }
+
+ for (var i = 0, count = array.length || 0; i < count; ++i) {
+ if (i in array && iter.call(ctx, array[i], i, array)) {
+ return i;
+ }
+ }
+
+ return -1;
+};
+
+// Here are the structure of the rtpmap attribute and the media line, most of the
+// complex Regular Expressions in this code are matching against one of these two
+// formats:
+// * a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
+// * m=<media> <port>/<number of ports> <proto> <fmts>
+//
+// References:
+// * https://tools.ietf.org/html/rfc4566
+// * http://en.wikipedia.org/wiki/Session_Description_Protocol
+//
+var SDPHelpers = {
+ // Search through sdpLines to find the Media Line of type +mediaType+.
+ getMLineIndex: function getMLineIndex(sdpLines, mediaType) {
+ var targetMLine = 'm=' + mediaType;
+
+ // Find the index of the media line for +type+
+ return findIndex(sdpLines, function(line) {
+ if (line.indexOf(targetMLine) !== -1) {
+ return true;
+ }
+
+ return false;
+ });
+ },
+
+ // Extract the payload types for a give Media Line.
+ //
+ getMLinePayloadTypes: function getMLinePayloadTypes (mediaLine, mediaType) {
+ var mLineSelector = new RegExp('^m=' + mediaType +
+ ' \\d+(/\\d+)? [a-zA-Z0-9/]+(( [a-zA-Z0-9/]+)+)$', 'i');
+
+ // Get all payload types that the line supports
+ var payloadTypes = mediaLine.match(mLineSelector);
+ if (!payloadTypes || payloadTypes.length < 2) {
+ // Error, invalid M line?
+ return [];
+ }
+
+ return OT.$.trim(payloadTypes[2]).split(' ');
+ },
+
+ removeTypesFromMLine: function removeTypesFromMLine (mediaLine, payloadTypes) {
+ return mediaLine.replace(new RegExp(' ' + payloadTypes.join(' |'), 'ig') , '')
+ .replace(/\s+/g, ' ');
+ },
+
+
+ // Remove all references to a particular encodingName from a particular media type
+ //
+ removeMediaEncoding: function removeMediaEncoding (sdp, mediaType, encodingName) {
+ var sdpLines = sdp.split('\r\n'),
+ mLineIndex = SDPHelpers.getMLineIndex(sdpLines, mediaType),
+ mLine = mLineIndex > -1 ? sdpLines[mLineIndex] : void 0,
+ typesToRemove = [],
+ payloadTypes,
+ match;
+
+ if (mLineIndex === -1) {
+ // Error, missing M line
+ return sdpLines.join('\r\n');
+ }
+
+ // Get all payload types that the line supports
+ payloadTypes = SDPHelpers.getMLinePayloadTypes(mLine, mediaType);
+ if (payloadTypes.length === 0) {
+ // Error, invalid M line?
+ return sdpLines.join('\r\n');
+ }
+
+ // Find the location of all the rtpmap lines that relate to +encodingName+
+ // and any of the supported payload types
+ var matcher = new RegExp('a=rtpmap:(' + payloadTypes.join('|') + ') ' +
+ encodingName + '\\/\\d+', 'i');
+
+ sdpLines = OT.$.filter(sdpLines, function(line, index) {
+ match = line.match(matcher);
+ if (match === null) return true;
+
+ typesToRemove.push(match[1]);
+
+ if (index < mLineIndex) {
+ // This removal changed the index of the mline, track it
+ mLineIndex--;
+ }
+
+ // remove this one
+ return false;
+ });
+
+ if (typesToRemove.length > 0 && mLineIndex > -1) {
+ // Remove all the payload types and we've removed from the media line
+ sdpLines[mLineIndex] = SDPHelpers.removeTypesFromMLine(mLine, typesToRemove);
+ }
+
+ return sdpLines.join('\r\n');
+ },
+
+ // Removes all Confort Noise from +sdp+.
+ //
+ // See https://jira.tokbox.com/browse/OPENTOK-7176
+ //
+ removeComfortNoise: function removeComfortNoise (sdp) {
+ return SDPHelpers.removeMediaEncoding(sdp, 'audio', 'CN');
+ },
+
+ removeVideoCodec: function removeVideoCodec (sdp, codec) {
+ return SDPHelpers.removeMediaEncoding(sdp, 'video', codec);
+ }
+};
+
+
!(function(window) {
+ /* global SDPHelpers */
// Normalise these
var NativeRTCSessionDescription,
NativeRTCIceCandidate;
if (!TBPlugin.isInstalled()) {
// order is very important: 'RTCSessionDescription' defined in Firefox Nighly but useless
NativeRTCSessionDescription = (window.mozRTCSessionDescription ||
@@ -14998,84 +15001,16 @@ waitForDomReady();
this.processPending = function() {
while(_pendingIceCandidates.length) {
_peerConnection.addIceCandidate(_pendingIceCandidates.shift());
}
};
};
- // Removes all Confort Noise from +sdp+.
- //
- // See https://jira.tokbox.com/browse/OPENTOK-7176
- //
- var removeComfortNoise = function removeComfortNoise (sdp) {
- // a=rtpmap:<payload type> <encoding name>/<clock rate> [/<encoding parameters>]
- var matcher = /a=rtpmap:(\d+) CN\/\d+/i,
- payloadTypes = [],
- audioMediaLineIndex,
- sdpLines,
- match;
-
- // Icky code. This filter operation has two side effects in addition
- // to doing the actual filtering:
- // 1. extract all the payload types from the rtpmap CN lines
- // 2. find the index of the audio media line
- //
- sdpLines = OT.$.filter(sdp.split('\r\n'), function(line, index) {
- if (line.indexOf('m=audio') !== -1) audioMediaLineIndex = index;
-
- match = line.match(matcher);
- if (match !== null) {
- payloadTypes.push(match[1]);
-
- // remove this line as it contains CN
- return false;
- }
-
- return true;
- });
-
- if (payloadTypes.length && audioMediaLineIndex) {
- // Remove all CN payload types from the audio media line.
- sdpLines[audioMediaLineIndex] = sdpLines[audioMediaLineIndex].replace(
- new RegExp(payloadTypes.join('|'), 'ig') , '').replace(/\s+/g, ' ');
- }
-
- return sdpLines.join('\r\n');
- };
-
- var removeVideoCodec = function removeVideoCodec (sdp, codec) {
- var matcher = new RegExp('a=rtpmap:(\\d+) ' + codec + '\\/\\d+', 'i'),
- payloadTypes = [],
- videoMediaLineIndex,
- sdpLines,
- match;
-
- sdpLines = OT.$.filter(sdp.split('\r\n'), function(line, index) {
- if (line.indexOf('m=video') !== -1) videoMediaLineIndex = index;
-
- match = line.match(matcher);
- if (match !== null) {
- payloadTypes.push(match[1]);
-
- // remove this line as it contains the codec
- return false;
- }
-
- return true;
- });
-
- if (payloadTypes.length && videoMediaLineIndex) {
- sdpLines[videoMediaLineIndex] = sdpLines[videoMediaLineIndex].replace(
- new RegExp(payloadTypes.join('|'), 'ig') , '').replace(/\s+/g, ' ');
- }
-
- return sdpLines.join('\r\n');
- };
// Attempt to completely process +offer+. This will:
// * set the offer as the remote description
// * create an answer and
// * set the new answer as the location description
//
// If there are no issues, the +success+ callback will be executed on completion.
// Errors during any step will result in the +failure+ callback being executed.
@@ -15090,19 +15025,19 @@ waitForDomReady();
OT.error(message);
OT.error(errorReason);
if (failure) failure(message, errorReason, prefix);
};
};
setLocalDescription = function(answer) {
- answer.sdp = removeComfortNoise(answer.sdp);
- answer.sdp = removeVideoCodec(answer.sdp, 'ulpfec');
- answer.sdp = removeVideoCodec(answer.sdp, 'red');
+ answer.sdp = SDPHelpers.removeComfortNoise(answer.sdp);
+ answer.sdp = SDPHelpers.removeVideoCodec(answer.sdp, 'ulpfec');
+ answer.sdp = SDPHelpers.removeVideoCodec(answer.sdp, 'red');
peerConnection.setLocalDescription(
answer,
// Success
function() {
success(answer);
},
@@ -15176,19 +15111,20 @@ waitForDomReady();
OT.error(message);
OT.error(errorReason);
if (failure) failure(message, errorReason, prefix);
};
};
setLocalDescription = function(offer) {
- offer.sdp = removeComfortNoise(offer.sdp);
- offer.sdp = removeVideoCodec(offer.sdp, 'ulpfec');
- offer.sdp = removeVideoCodec(offer.sdp, 'red');
+ offer.sdp = SDPHelpers.removeComfortNoise(offer.sdp);
+ offer.sdp = SDPHelpers.removeVideoCodec(offer.sdp, 'ulpfec');
+ offer.sdp = SDPHelpers.removeVideoCodec(offer.sdp, 'red');
+
peerConnection.setLocalDescription(
offer,
// Success
function() {
success(offer);
},
@@ -16581,52 +16517,39 @@ waitForDomReady();
// Whether to display the name. Possible values are: "auto" (the name is displayed
// when the stream is first displayed and when the user mouses over the display),
// "off" (the name is not displayed), and "on" (the name is displayed).
//
// displays a name
// can be shown/hidden
// can be destroyed
OT.Chrome.NamePanel = function(options) {
- var _name = options.name,
- _bugMode = options.bugMode;
+ var _name = options.name;
if (!_name || OT.$.trim(_name).length === '') {
_name = null;
// THere's no name, just flip the mode off
options.mode = 'off';
}
this.setName = OT.$.bind(function(name) {
if (!_name) this.setDisplayMode('auto');
_name = name;
this.domElement.innerHTML = _name;
});
- this.setBugMode = OT.$.bind(function(bugMode) {
- _bugMode = bugMode;
- if(bugMode === 'off') {
- OT.$.addClass(this.domElement, 'OT_name-no-bug');
- } else {
- OT.$.removeClass(this.domElement, 'OT_name-no-bug');
- }
- }, this);
-
// Mixin common widget behaviour
OT.Chrome.Behaviour.Widget(this, {
mode: options.mode,
nodeName: 'h1',
htmlContent: _name,
htmlAttributes: {
className: 'OT_name OT_edge-bar-item'
- },
- onCreate: OT.$.bind(function() {
- this.setBugMode(_bugMode);
- }, this)
+ }
});
};
})(window);
!(function() {
OT.Chrome.MuteButton = function(options) {
@@ -16693,33 +16616,16 @@ waitForDomReady();
onDestroy: OT.$.bind(detachEvents, this)
});
};
})(window);
!(function() {
- OT.Chrome.OpenTokButton = function(options) {
-
- // Mixin common widget behaviour
- OT.Chrome.Behaviour.Widget(this, {
- mode: options ? options.mode : null,
- nodeName: 'span',
- htmlContent: 'OpenTok',
- htmlAttributes: {
- className: 'OT_opentok OT_edge-bar-item'
- }
- });
-
- };
-
-})(window);
-!(function() {
-
// Archving Chrome Widget
//
// mode (String)
// Whether to display the archving widget. Possible values are: "on" (the status is displayed
// when archiving and briefly when archving ends) and "off" (the status is not displayed)
// Whether to display the archving widget. Possible values are: "auto" (the name is displayed
// when the status is first displayed and when the user mouses over the display),
@@ -16831,45 +16737,60 @@ waitForDomReady();
var widget = this,
_meterBarElement,
_voiceOnlyIconElement,
_meterValueElement,
_value,
_maxValue = options.maxValue || 1,
_minValue = options.minValue || 0;
+ function onCreate() {
+ _meterBarElement = OT.$.createElement('div', {
+ className: 'OT_audio-level-meter__bar'
+ }, '');
+ _meterValueElement = OT.$.createElement('div', {
+ className: 'OT_audio-level-meter__value'
+ }, '');
+ _voiceOnlyIconElement = OT.$.createElement('div', {
+ className: 'OT_audio-level-meter__audio-only-img'
+ }, '');
+
+ widget.domElement.appendChild(_meterBarElement);
+ widget.domElement.appendChild(_voiceOnlyIconElement);
+ widget.domElement.appendChild(_meterValueElement);
+ }
+
+ function updateView() {
+ var percentSize = _value * 100 / (_maxValue - _minValue);
+ _meterValueElement.style.width = _meterValueElement.style.height = 2 * percentSize + '%';
+ _meterValueElement.style.top = _meterValueElement.style.right = -percentSize + '%';
+ }
+
// Mixin common widget behaviour
- OT.Chrome.Behaviour.Widget(this, {
+ var widgetOptions = {
mode: options ? options.mode : 'auto',
nodeName: 'div',
htmlAttributes: {
className: 'OT_audio-level-meter'
},
- onCreate: function() {
- _meterBarElement = OT.$.createElement('div', {
- className: 'OT_audio-level-meter__bar'
- }, '');
- _meterValueElement = OT.$.createElement('div', {
- className: 'OT_audio-level-meter__value'
- }, '');
- _voiceOnlyIconElement = OT.$.createElement('div', {
- className: 'OT_audio-level-meter__audio-only-img'
- }, '');
-
- widget.domElement.appendChild(_meterBarElement);
- widget.domElement.appendChild(_voiceOnlyIconElement);
- widget.domElement.appendChild(_meterValueElement);
- }
- });
-
- function updateView() {
- var percentSize = _value * 100 / (_maxValue - _minValue);
- _meterValueElement.style.width = _meterValueElement.style.height = 2 * percentSize + '%';
- _meterValueElement.style.top = _meterValueElement.style.right = -percentSize + '%';
- }
+ onCreate: onCreate
+ };
+
+ OT.Chrome.Behaviour.Widget(this, widgetOptions);
+
+ // override
+ var _setDisplayMode = OT.$.bind(widget.setDisplayMode, widget);
+ widget.setDisplayMode = function(mode) {
+ _setDisplayMode(mode);
+ if (mode === 'off') {
+ if (options.onPassivate) options.onPassivate();
+ } else {
+ if (options.onActivate) options.onActivate();
+ }
+ };
widget.setValue = function(value) {
_value = value;
updateView();
};
};
})(window);
@@ -17177,24 +17098,22 @@ waitForDomReady();
isValidStyle,
castValue;
_COMPONENT_STYLES = [
'showMicButton',
'showSpeakerButton',
'nameDisplayMode',
'buttonDisplayMode',
- 'backgroundImageURI',
- 'bugDisplayMode'
+ 'backgroundImageURI'
];
_validStyleValues = {
buttonDisplayMode: ['auto', 'mini', 'mini-auto', 'off', 'on'],
nameDisplayMode: ['auto', 'off', 'on'],
- bugDisplayMode: ['auto', 'off', 'on'],
audioLevelDisplayMode: ['auto', 'off', 'on'],
showSettingsButton: [true, false],
showMicButton: [true, false],
backgroundImageURI: null,
showControlBar: [true, false],
showArchiveStatus: [true, false],
videoDisabledDisplayMode: ['auto', 'off', 'on']
};
@@ -17688,38 +17607,38 @@ waitForDomReady();
_audioLevelMeter,
_analytics = new OT.Analytics(),
_validResolutions,
_validFrameRates = [ 1, 7, 15, 30 ],
_prevStats,
_state,
_iceServers,
_audioLevelCapable = OT.$.hasCapabilities('webAudio'),
- _audioLevelSampler;
+ _audioLevelSampler,
+ _publisher = this;
_validResolutions = {
'320x240': {width: 320, height: 240},
'640x480': {width: 640, height: 480},
'1280x720': {width: 1280, height: 720}
};
_prevStats = {
'timeStamp' : OT.$.now()
};
OT.$.eventing(this);
if(_audioLevelCapable) {
- _audioLevelSampler = new OT.AnalyserAudioLevelSampler(new window.AudioContext());
-
- var publisher = this;
+ _audioLevelSampler = new OT.AnalyserAudioLevelSampler(OT.audioContext());
+
var audioLevelRunner = new OT.IntervalRunner(function() {
_audioLevelSampler.sample(function(audioInputLevel) {
OT.$.requestAnimationFrame(function() {
- publisher.dispatchEvent(
+ _publisher.dispatchEvent(
new OT.AudioLevelUpdatedEvent(audioInputLevel));
});
});
}, 60);
this.on({
'audioLevelUpdated:added': function(count) {
if (count === 1) {
@@ -17733,17 +17652,16 @@ waitForDomReady();
}
});
}
OT.StylableComponent(this, {
showArchiveStatus: true,
nameDisplayMode: 'auto',
buttonDisplayMode: 'auto',
- bugDisplayMode: 'auto',
audioLevelDisplayMode: 'auto',
backgroundImageURI: null
});
/// Private Methods
var logAnalyticsEvent = function(action, variation, payloadType, payload) {
_analytics.logEvent({
action: action,
@@ -17838,19 +17756,17 @@ waitForDomReady();
cleanupLocalStream();
_webRTCStream = webOTStream;
_microphone = new OT.Microphone(_webRTCStream, !_publishProperties.publishAudio);
this.publishVideo(_publishProperties.publishVideo &&
_webRTCStream.getVideoTracks().length > 0);
this.accessAllowed = true;
- this.dispatchEvent(
- new OT.Event(OT.Event.names.ACCESS_ALLOWED, false)
- );
+ this.dispatchEvent(new OT.Event(OT.Event.names.ACCESS_ALLOWED, false));
var videoContainerOptions = {
muted: true,
error: OT.$.bind(onVideoError, this)
};
_targetElement = _container.bindVideo(_webRTCStream,
videoContainerOptions,
@@ -17858,17 +17774,17 @@ waitForDomReady();
if (err) {
onLoadFailure.call(this, err);
return;
}
onLoaded.call(this);
}, this));
- if(_audioLevelSampler) {
+ if(_audioLevelSampler && webOTStream.getAudioTracks().length > 0) {
_audioLevelSampler.webOTStream = webOTStream;
}
},
onStreamAvailableError = function(error) {
OT.error('OT.Publisher.onStreamAvailableError ' + error.name + ': ' + error.message);
@@ -17896,115 +17812,34 @@ waitForDomReady();
_state.set('Failed');
this.trigger('publishComplete', new OT.Error(OT.ExceptionCodes.UNABLE_TO_PUBLISH,
'Publisher Access Denied: Permission Denied' +
(error.message ? ': ' + error.message : '')));
logAnalyticsEvent('publish', 'Failure', 'reason',
'GetUserMedia:Publisher Access Denied: Permission Denied');
- var browser = OT.$.browserVersion();
-
- var event = new OT.Event(OT.Event.names.ACCESS_DENIED),
- defaultAction = function() {
- if(!event.isDefaultPrevented()) {
- if(browser.browser === 'Chrome') {
- if (_container) {
- _container.addError('', null, 'OT_publisher-denied-chrome');
- }
- if(!accessDialogWasOpened) {
- OT.Dialogs.AllowDeny.Chrome.previouslyDenied(window.location.hostname);
- } else {
- OT.Dialogs.AllowDeny.Chrome.deniedNow();
- }
- } else if(browser.browser === 'Firefox') {
- if(_container) {
- _container.addError('', 'Click the reload button in the URL bar to change ' +
- 'camera & mic settings.', 'OT_publisher-denied-firefox');
- }
- OT.Dialogs.AllowDeny.Firefox.denied().on({
- refresh: function() {
- window.location.reload();
- }
- });
- }
- }
- };
-
- this.dispatchEvent(event, defaultAction);
- },
-
- accessDialogPrompt,
- accessDialogChromeTimeout,
- accessDialogFirefoxTimeout,
+ this.dispatchEvent(new OT.Event(OT.Event.names.ACCESS_DENIED));
+ },
+
accessDialogWasOpened = false,
onAccessDialogOpened = function() {
accessDialogWasOpened = true;
logAnalyticsEvent('accessDialog', 'Opened', '', '');
- var browser = OT.$.browserVersion();
-
- this.dispatchEvent(
- new OT.Event(OT.Event.names.ACCESS_DIALOG_OPENED, true),
- function(event) {
- if(!event.isDefaultPrevented()) {
- if(browser.browser === 'Chrome') {
- accessDialogChromeTimeout = setTimeout(function() {
- accessDialogChromeTimeout = null;
- logAnalyticsEvent('allowDenyHelpers', 'show', 'version', 'Chrome');
- accessDialogPrompt = OT.Dialogs.AllowDeny.Chrome.initialPrompt();
- accessDialogPrompt.on('closeButtonClicked', function() {
- logAnalyticsEvent('allowDenyHelpers', 'dismissed', 'version', 'Chrome');
- });
- }, 5000);
- } else if(browser.browser === 'Firefox') {
- accessDialogFirefoxTimeout = setTimeout(function() {
- accessDialogFirefoxTimeout = null;
- logAnalyticsEvent('allowDenyHelpers', 'show', 'version', 'Firefox');
- accessDialogPrompt = OT.Dialogs.AllowDeny.Firefox.maybeDenied();
- accessDialogPrompt.on('closeButtonClicked', function() {
- logAnalyticsEvent('allowDenyHelpers', 'dismissed', 'version', 'Firefox');
- });
- }, 7000);
- }
- } else {
- logAnalyticsEvent('allowDenyHelpers', 'developerPrevented', '', '');
- }
- }
- );
+ this.dispatchEvent(new OT.Event(OT.Event.names.ACCESS_DIALOG_OPENED, true));
},
onAccessDialogClosed = function() {
logAnalyticsEvent('accessDialog', 'Closed', '', '');
- if(accessDialogChromeTimeout) {
- clearTimeout(accessDialogChromeTimeout);
- logAnalyticsEvent('allowDenyHelpers', 'notShown', 'version', 'Chrome');
- accessDialogChromeTimeout = null;
- }
-
- if(accessDialogFirefoxTimeout) {
- clearTimeout(accessDialogFirefoxTimeout);
- logAnalyticsEvent('allowDenyHelpers', 'notShown', 'version', 'Firefox');
- accessDialogFirefoxTimeout = null;
- }
-
- if(accessDialogPrompt) {
- accessDialogPrompt.close();
- var browser = OT.$.browserVersion();
- logAnalyticsEvent('allowDenyHelpers', 'closed', 'version', browser.browser);
- accessDialogPrompt = null;
- }
-
- this.dispatchEvent(
- new OT.Event(OT.Event.names.ACCESS_DIALOG_CLOSED, false)
- );
+ this.dispatchEvent( new OT.Event(OT.Event.names.ACCESS_DIALOG_CLOSED, false));
},
onVideoError = function(errorCode, errorReason) {
OT.error('OT.Publisher.onVideoError');
var message = errorReason + (errorCode ? ' (' + errorCode + ')' : '');
logAnalyticsEvent('stream', null, 'reason',
'Publisher while playing stream: ' + message);
@@ -18155,79 +17990,79 @@ waitForDomReady();
_chrome.muteButton.setDisplayMode(value);
_chrome.backingBar.setMuteMode(value);
break;
case 'audioLevelDisplayMode':
_chrome.audioLevel.setDisplayMode(value);
break;
- case 'bugDisplayMode':
- // bugDisplayMode can't be updated but is used by some partners
-
case 'backgroundImageURI':
_container.setBackgroundImageURI(value);
}
},
_createChrome = function() {
- if(this.getStyle('bugDisplayMode') === 'off') {
- logAnalyticsEvent('bugDisplayMode', 'createChrome', 'mode', 'off');
- }
if(!this.getStyle('showArchiveStatus')) {
logAnalyticsEvent('showArchiveStatus', 'createChrome', 'mode', 'off');
}
var widgets = {
backingBar: new OT.Chrome.BackingBar({
nameMode: !_publishProperties.name ? 'off' : this.getStyle('nameDisplayMode'),
muteMode: chromeButtonMode.call(this, this.getStyle('buttonDisplayMode'))
}),
name: new OT.Chrome.NamePanel({
name: _publishProperties.name,
- mode: this.getStyle('nameDisplayMode'),
- bugMode: this.getStyle('bugDisplayMode')
+ mode: this.getStyle('nameDisplayMode')
}),
muteButton: new OT.Chrome.MuteButton({
muted: _publishProperties.publishAudio === false,
mode: chromeButtonMode.call(this, this.getStyle('buttonDisplayMode'))
}),
- opentokButton: new OT.Chrome.OpenTokButton({
- mode: this.getStyle('bugDisplayMode')
- }),
-
archive: new OT.Chrome.Archiving({
show: this.getStyle('showArchiveStatus'),
archiving: false
})
};
- if(_audioLevelCapable) {
+ if (_audioLevelCapable) {
+ var audioLevelTransformer = new OT.AudioLevelTransformer();
+
+ var audioLevelUpdatedHandler = function(evt) {
+ _audioLevelMeter.setValue(audioLevelTransformer.transform(evt.audioLevel));
+ };
+
_audioLevelMeter = new OT.Chrome.AudioLevelMeter({
- mode: this.getStyle('audioLevelDisplayMode')
- });
-
- var audioLevelTransformer = new OT.AudioLevelTransformer();
- this.on('audioLevelUpdated', function(evt) {
- _audioLevelMeter.setValue(audioLevelTransformer.transform(evt.audioLevel));
+ mode: this.getStyle('audioLevelDisplayMode'),
+ onActivate: function() {
+ _publisher.on('audioLevelUpdated', audioLevelUpdatedHandler);
+ },
+ onPassivate: function() {
+ _publisher.off('audioLevelUpdated', audioLevelUpdatedHandler);
+ }
});
widgets.audioLevel = _audioLevelMeter;
}
_chrome = new OT.Chrome({
parent: _container.domElement
}).set(widgets).on({
muted: OT.$.bind(this.publishAudio, this, false),
unmuted: OT.$.bind(this.publishAudio, this, true)
});
+
+ if(_audioLevelMeter && this.getStyle('audioLevelDisplayMode') === 'auto') {
+ _audioLevelMeter[_container.audioOnly() ? 'show' : 'hide']();
+ }
},
reset = OT.$.bind(function() {
if (_chrome) {
_chrome.destroy();
_chrome = null;
}
@@ -18255,16 +18090,27 @@ waitForDomReady();
this.stream = _stream = null;
_loaded = false;
this.session = _session = null;
if (!_state.isDestroyed()) _state.set('NotPublishing');
}, this);
+ var setAudioOnly = function(audioOnly) {
+ if (_container) {
+ _container.audioOnly(audioOnly);
+ _container.showPoster(audioOnly);
+ }
+
+ if (_audioLevelMeter && _publisher.getStyle('audioLevelDisplayMode') === 'auto') {
+ _audioLevelMeter[audioOnly ? 'show' : 'hide']();
+ }
+ };
+
this.publish = function(targetElement, properties) {
OT.debug('OT.Publisher: publish');
if ( _state.isAttemptingToPublish() || _state.isPublishing() ) reset();
_state.set('GetUserMedia');
_publishProperties = OT.$.defaults(properties || {}, {
publishAudio : true,
@@ -18452,18 +18298,17 @@ waitForDomReady();
if (_session && _stream) {
_stream.setChannelActiveState('audio', value);
}
return this;
};
-
- /**
+ /**
* Starts publishing video (if it is currently not being published)
* when the <code>value</code> is <code>true</code>; stops publishing video
* (if it is currently being published) when the <code>value</code> is <code>false</code>.
*
* @param {Boolean} value Whether to start publishing video (<code>true</code>)
* or not (<code>false</code>).
*
* @see <a href="OT.html#initPublisher">OT.initPublisher()</a>
@@ -18485,20 +18330,17 @@ waitForDomReady();
// the value of publishVideo at this point. This will be tidied up shortly.
if (_webRTCStream) {
var videoTracks = _webRTCStream.getVideoTracks();
for (var i=0, num=videoTracks.length; i<num; ++i) {
videoTracks[i].setEnabled(value);
}
}
- if(_container) {
- _container.audioOnly(!value);
- _container.showPoster(!value);
- }
+ setAudioOnly(!value);
return this;
};
/**
* Deletes the Publisher object and removes it from the HTML DOM.
* <p>
@@ -18933,17 +18775,18 @@ waitForDomReady();
_audioVolume = 100,
_state,
_prevStats,
_lastSubscribeToVideoReason,
_audioLevelCapable = OT.$.hasCapabilities('audioOutputLevelStat') ||
OT.$.hasCapabilities('webAudioCapableRemoteStream'),
_audioLevelSampler,
_audioLevelRunner,
- _frameRateRestricted = false;
+ _frameRateRestricted = false,
+ _subscriber = this;
this.id = _domId;
this.widgetId = _widgetId;
this.session = _session;
_prevStats = {
timeStamp: OT.$.now()
};
@@ -18976,18 +18819,17 @@ waitForDomReady();
OT.StylableComponent(this, {
nameDisplayMode: 'auto',
buttonDisplayMode: 'auto',
audioLevelDisplayMode: 'auto',
videoDisabledIndicatorDisplayMode: 'auto',
backgroundImageURI: null,
showArchiveStatus: true,
- showMicButton: true,
- bugDisplayMode: 'auto'
+ showMicButton: true
});
var logAnalyticsEvent = function(action, variation, payloadType, payload) {
/* jshint camelcase:false*/
_analytics.logEvent({
action: action,
variation: variation,
payload_type: payloadType,
@@ -19156,17 +18998,18 @@ waitForDomReady();
width: _stream.videoDimensions.width,
height: _stream.videoDimensions.height,
videoOrientation: _stream.videoDimensions.orientation
});
onLoaded.call(this, null);
}, this));
- if (OT.$.hasCapabilities('webAudioCapableRemoteStream') && _audioLevelSampler) {
+ if (OT.$.hasCapabilities('webAudioCapableRemoteStream') && _audioLevelSampler &&
+ webOTStream.getAudioTracks().length > 0) {
_audioLevelSampler.webOTStream = webOTStream;
}
logAnalyticsEvent('createPeerConnection', 'StreamAdded', '', '');
this.trigger('streamAdded', this);
},
onRemoteStreamRemoved = function(webOTStream) {
@@ -19184,36 +19027,38 @@ waitForDomReady();
streamDestroyed = function () {
this.disconnect();
},
streamUpdated = function(event) {
switch(event.changedProperty) {
case 'videoDimensions':
+ if (!_streamContainer) {
+ // Ignore videoEmension updates before streamContainer is created OPENTOK-17253
+ break;
+ }
_streamContainer.orientation({
width: event.newValue.width,
height: event.newValue.height,
videoOrientation: event.newValue.orientation
});
break;
case 'videoDisableWarning':
_chrome.videoDisabledIndicator.setWarning(event.newValue);
this.dispatchEvent(new OT.VideoDisableWarningEvent(
event.newValue ? 'videoDisableWarning' : 'videoDisableWarningLifted'
));
break;
case 'hasVideo':
- if(_container) {
- var audioOnly = !(_stream.hasVideo && _properties.subscribeToVideo);
- _container.audioOnly(audioOnly);
- _container.showPoster(audioOnly);
- }
+
+ setAudioOnly(!(_stream.hasVideo && _properties.subscribeToVideo));
+
this.dispatchEvent(new OT.VideoEnabledChangedEvent(
_stream.hasVideo ? 'videoEnabled' : 'videoDisabled', {
reason: 'publishVideo'
}));
break;
case 'hasAudio':
// noop
@@ -19258,65 +19103,60 @@ waitForDomReady();
_chrome.muteButton.setDisplayMode(value);
_chrome.backingBar.setMuteMode(value);
break;
case 'audioLevelDisplayMode':
_chrome.audioLevel.setDisplayMode(value);
break;
- case 'bugDisplayMode':
- // bugDisplayMode can't be updated but is used by some partners
-
case 'backgroundImageURI':
_container.setBackgroundImageURI(value);
}
},
_createChrome = function() {
-
- if(this.getStyle('bugDisplayMode') === 'off') {
- logAnalyticsEvent('bugDisplayMode', 'createChrome', 'mode', 'off');
- }
var widgets = {
backingBar: new OT.Chrome.BackingBar({
nameMode: !_properties.name ? 'off' : this.getStyle('nameDisplayMode'),
muteMode: chromeButtonMode.call(this, this.getStyle('showMuteButton'))
}),
name: new OT.Chrome.NamePanel({
name: _properties.name,
- mode: this.getStyle('nameDisplayMode'),
- bugMode: this.getStyle('bugDisplayMode')
+ mode: this.getStyle('nameDisplayMode')
}),
muteButton: new OT.Chrome.MuteButton({
muted: _properties.muted,
mode: chromeButtonMode.call(this, this.getStyle('showMuteButton'))
}),
- opentokButton: new OT.Chrome.OpenTokButton({
- mode: this.getStyle('bugDisplayMode')
- }),
-
archive: new OT.Chrome.Archiving({
show: this.getStyle('showArchiveStatus'),
archiving: false
})
};
- if(_audioLevelCapable) {
+ if (_audioLevelCapable) {
+ var audioLevelTransformer = new OT.AudioLevelTransformer();
+
+ var audioLevelUpdatedHandler = function(evt) {
+ _audioLevelMeter.setValue(audioLevelTransformer.transform(evt.audioLevel));
+ };
+
_audioLevelMeter = new OT.Chrome.AudioLevelMeter({
- mode: this.getStyle('audioLevelDisplayMode')
- });
-
- var audioLevelTransformer = new OT.AudioLevelTransformer();
- this.on('audioLevelUpdated', function(evt) {
- _audioLevelMeter.setValue(audioLevelTransformer.transform(evt.audioLevel));
+ mode: this.getStyle('audioLevelDisplayMode'),
+ onActivate: function() {
+ _subscriber.on('audioLevelUpdated', audioLevelUpdatedHandler);
+ },
+ onPassivate: function() {
+ _subscriber.off('audioLevelUpdated', audioLevelUpdatedHandler);
+ }
});
widgets.audioLevel = _audioLevelMeter;
}
widgets.videoDisabledIndicator = new OT.Chrome.VideoDisabledIndicator({
mode: this.getStyle('videoDisabledDisplayMode')
});
@@ -19327,29 +19167,43 @@ waitForDomReady();
muted: function() {
muteAudio.call(this, true);
},
unmuted: function() {
muteAudio.call(this, false);
}
}, this);
+
+ if(_audioLevelMeter && this.getStyle('audioLevelDisplayMode') === 'auto') {
+ _audioLevelMeter[_container.audioOnly() ? 'show' : 'hide']();
+ }
},
_showError = function() {
// Display the error message inside the container, assuming it's
// been created by now.
if (_container) {
_container.addError(
'The stream was unable to connect due to a network error.',
'Make sure your connection isn\'t blocked by a firewall.'
);
}
};
+ var setAudioOnly = function(audioOnly) {
+ if(_container) {
+ _container.audioOnly(audioOnly);
+ _container.showPoster(audioOnly);
+ }
+
+ if (_audioLevelMeter && _subscriber.getStyle('audioLevelDisplayMode') === 'auto') {
+ _audioLevelMeter[audioOnly ? 'show' : 'hide']();
+ }
+ };
this.subscribe = function(stream) {
OT.debug('OT.Subscriber: subscribe to ' + stream.id);
if (_state.isSubscribing()) {
// @todo error
OT.error('OT.Subscriber.Subscribe: Cannot subscribe, already subscribing.');
return false;
@@ -19413,28 +19267,27 @@ waitForDomReady();
}, this);
// initialize the peer connection AFTER we've added the event listeners
_peerConnection.init();
if (OT.$.hasCapabilities('audioOutputLevelStat')) {
_audioLevelSampler = new OT.GetStatsAudioLevelSampler(_peerConnection, 'out');
} else if (OT.$.hasCapabilities('webAudioCapableRemoteStream')) {
- _audioLevelSampler = new OT.AnalyserAudioLevelSampler(new window.AudioContext());
+ _audioLevelSampler = new OT.AnalyserAudioLevelSampler(OT.audioContext());
}
if(_audioLevelSampler) {
- var subscriber = this;
// sample with interval to minimise disturbance on animation loop but dispatch the
// event with RAF since the main purpose is animation of a meter
_audioLevelRunner = new OT.IntervalRunner(function() {
_audioLevelSampler.sample(function(audioOutputLevel) {
if (audioOutputLevel !== null) {
OT.$.requestAnimationFrame(function() {
- subscriber.dispatchEvent(
+ _subscriber.dispatchEvent(
new OT.AudioLevelUpdatedEvent(audioOutputLevel));
});
}
});
}, 60);
}
} else {
logAnalyticsEvent('createPeerConnection', 'Attempt', '', '');
@@ -19744,26 +19597,23 @@ waitForDomReady();
* @see <a href="StreamPropertyChangedEvent.html">StreamPropertyChangedEvent</a>
*
* @method #subscribeToVideo
* @memberOf Subscriber
*/
this.subscribeToVideo = function(pValue, reason) {
var value = OT.$.castToBoolean(pValue, true);
- if(_container) {
- var audioOnly = !(value && _stream.hasVideo);
- _container.audioOnly(audioOnly);
- _container.showPoster(audioOnly);
- if(value && _container.video()) {
- _container.loading(value);
- _container.video().whenTimeIncrements(function(){
- _container.loading(false);
- }, this);
- }
+ setAudioOnly(!(value && _stream.hasVideo));
+
+ if ( value && _container && _container.video()) {
+ _container.loading(value);
+ _container.video().whenTimeIncrements(function() {
+ _container.loading(false);
+ }, this);
}
if (_chrome && _chrome.videoDisabledIndicator) {
_chrome.videoDisabledIndicator.disableVideo(false);
}
if (_peerConnection) {
_peerConnection.subscribeToVideo(value);
--- a/browser/config/mozconfigs/win64/l10n-mozconfig
+++ b/browser/config/mozconfigs/win64/l10n-mozconfig
@@ -1,9 +1,10 @@
. "$topsrcdir/browser/config/mozconfigs/common"
+. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
ac_add_options --enable-update-channel=${MOZ_UPDATE_CHANNEL}
ac_add_options --enable-update-packaging
ac_add_options --with-l10n-base=../../l10n
ac_add_options --with-windows-version=603
export MOZILLA_OFFICIAL=1
--- a/browser/devtools/canvasdebugger/canvasdebugger.js
+++ b/browser/devtools/canvasdebugger/canvasdebugger.js
@@ -696,17 +696,17 @@ let CallsListView = Heritage.extend(Widg
let screenshotNode = $("#screenshot-image");
screenshotNode.setAttribute("flipped", flipped);
drawBackground("screenshot-rendering", width, height, pixels);
let dimensionsNode = $("#screenshot-dimensions");
let actualWidth = (width / scaling) | 0;
let actualHeight = (height / scaling) | 0;
- dimensionsNode.setAttribute("value", actualWidth + " x " + actualHeight);
+ dimensionsNode.setAttribute("value", actualWidth + " \u00D7 " + actualHeight);
window.emit(EVENTS.CALL_SCREENSHOT_DISPLAYED);
},
/**
* Populates this container's footer with a list of thumbnails, one generated
* for each draw call in the recorded animation frame snapshot.
*
--- a/browser/devtools/canvasdebugger/test/browser_canvas-frontend-img-screenshots.js
+++ b/browser/devtools/canvasdebugger/test/browser_canvas-frontend-img-screenshots.js
@@ -15,17 +15,17 @@ function ifTestingSupported() {
let callListPopulated = once(window, EVENTS.CALL_LIST_POPULATED);
let screenshotDisplayed = once(window, EVENTS.CALL_SCREENSHOT_DISPLAYED);
SnapshotsListView._onRecordButtonClick();
yield promise.all([recordingFinished, callListPopulated, screenshotDisplayed]);
is($("#screenshot-container").hidden, false,
"The screenshot container should now be visible.");
- is($("#screenshot-dimensions").getAttribute("value"), "128 x 128",
+ is($("#screenshot-dimensions").getAttribute("value"), "128" + " \u00D7 " + "128",
"The screenshot dimensions label has the expected value.");
is($("#screenshot-image").getAttribute("flipped"), "false",
"The screenshot element should not be flipped vertically.");
ok(window.getComputedStyle($("#screenshot-image")).backgroundImage.contains("#screenshot-rendering"),
"The screenshot element should have an offscreen canvas element as a background.");
--- a/browser/devtools/inspector/test/browser_inspector_infobar_01.js
+++ b/browser/devtools/inspector/test/browser_inspector_infobar_01.js
@@ -15,33 +15,33 @@ add_task(function*() {
let testData = [
{
selector: "#top",
position: "bottom",
tag: "DIV",
id: "top",
classes: ".class1.class2",
- dims: "500 x 100"
+ dims: "500" + " \u00D7 " + "100"
},
{
selector: "#vertical",
position: "overlap",
tag: "DIV",
id: "vertical",
classes: ""
// No dims as they will vary between computers
},
{
selector: "#bottom",
position: "top",
tag: "DIV",
id: "bottom",
classes: "",
- dims: "500 x 100"
+ dims: "500" + " \u00D7 " + "100"
},
{
selector: "body",
position: "bottom",
tag: "BODY",
classes: ""
// No dims as they will vary between computers
},
--- a/browser/devtools/layoutview/test/browser_layoutview.js
+++ b/browser/devtools/layoutview/test/browser_layoutview.js
@@ -4,35 +4,35 @@
"use strict";
// Test that the layout-view displays the right values and that it updates when
// the node's style is changed
// Expected values:
let res1 = [
- {selector: "#element-size", value: "160x160"},
- {selector: ".size > span", value: "100x100"},
+ {selector: "#element-size", value: "160" + "\u00D7" + "160"},
+ {selector: ".size > span", value: "100" + "\u00D7" + "100"},
{selector: ".margin.top > span", value: 30},
{selector: ".margin.left > span", value: "auto"},
{selector: ".margin.bottom > span", value: 30},
{selector: ".margin.right > span", value: "auto"},
{selector: ".padding.top > span", value: 20},
{selector: ".padding.left > span", value: 20},
{selector: ".padding.bottom > span", value: 20},
{selector: ".padding.right > span", value: 20},
{selector: ".border.top > span", value: 10},
{selector: ".border.left > span", value: 10},
{selector: ".border.bottom > span", value: 10},
{selector: ".border.right > span", value: 10},
];
let res2 = [
- {selector: "#element-size", value: "190x210"},
- {selector: ".size > span", value: "100x150"},
+ {selector: "#element-size", value: "190" + "\u00D7" + "210"},
+ {selector: ".size > span", value: "100" + "\u00D7" + "150"},
{selector: ".margin.top > span", value: 30},
{selector: ".margin.left > span", value: "auto"},
{selector: ".margin.bottom > span", value: 30},
{selector: ".margin.right > span", value: "auto"},
{selector: ".padding.top > span", value: 20},
{selector: ".padding.left > span", value: 20},
{selector: ".padding.bottom > span", value: 20},
{selector: ".padding.right > span", value: 50},
--- a/browser/devtools/layoutview/test/browser_layoutview_update-after-navigation.js
+++ b/browser/devtools/layoutview/test/browser_layoutview_update-after-navigation.js
@@ -40,26 +40,26 @@ function*(inspector, view) {
addTest("Test that the layout-view works on the second page",
function*(inspector, view) {
info("Selecting the test node");
yield selectNode("p", inspector);
info("Checking that the layout-view shows the right value");
let sizeElt = view.doc.querySelector(".size > span");
- is(sizeElt.textContent, "100x100");
+ is(sizeElt.textContent, "100" + "\u00D7" + "100");
info("Listening for layout-view changes and modifying the size");
let onUpdated = waitForUpdate(inspector);
getNode("p").style.width = "200px";
yield onUpdated;
ok(true, "Layout-view got updated");
info("Checking that the layout-view shows the right value after update");
- is(sizeElt.textContent, "200x100");
+ is(sizeElt.textContent, "200" + "\u00D7" + "100");
});
addTest("Go back to the first page",
function*(inspector, view) {
content.history.back();
yield inspector.once("markuploaded");
});
--- a/browser/devtools/layoutview/view.js
+++ b/browser/devtools/layoutview/view.js
@@ -396,17 +396,17 @@ LayoutView.prototype = {
// If a subsequent request has been made, wait for that one instead.
if (this._lastRequest != lastRequest) {
return this._lastRequest;
}
this._lastRequest = null;
let width = layout.width;
let height = layout.height;
- let newLabel = width + "x" + height;
+ let newLabel = width + "\u00D7" + height;
if (this.sizeHeadingLabel.textContent != newLabel) {
this.sizeHeadingLabel.textContent = newLabel;
}
// If the view is dimmed, no need to do anything more.
if (this.dimmed) {
this.inspector.emit("layoutview-updated");
return null;
@@ -447,17 +447,17 @@ LayoutView.prototype = {
}
width -= this.map.borderLeft.value + this.map.borderRight.value +
this.map.paddingLeft.value + this.map.paddingRight.value;
height -= this.map.borderTop.value + this.map.borderBottom.value +
this.map.paddingTop.value + this.map.paddingBottom.value;
- let newValue = width + "x" + height;
+ let newValue = width + "\u00D7" + height;
if (this.sizeLabel.textContent != newValue) {
this.sizeLabel.textContent = newValue;
}
this.elementRules = [e.rule for (e of styleEntries)];
this.inspector.emit("layoutview-updated");
}).bind(this)).then(null, console.error);
--- a/browser/devtools/markupview/test/browser_markupview_image_tooltip.js
+++ b/browser/devtools/markupview/test/browser_markupview_image_tooltip.js
@@ -11,20 +11,20 @@
const PAGE_CONTENT = [
'<img class="local" src="chrome://branding/content/about-logo.png" />',
'<img class="data" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAADI5JREFUeNrsWwuQFNUVPf1m5z87szv7HWSWj8CigBFMEFZKiQsB1PgJwUAZg1HBpIQsKmokEhNjWUnFVPnDWBT+KolJYbRMoqUVq0yCClpqiX8sCchPWFwVlt2db7+X93pez7zu6Vn2NxsVWh8987p7pu+9555z7+tZjTGGY3kjOMa34w447oBjfKsY7i/UNM3Y8eFSAkD50Plgw03K5P9gvGv7U5ieeR3PszeREiPNX3/0DL4hjslzhm8THh+OITfXk3dhiv4GDtGPVzCaeJmPLYzuu5qJuWfuw2QTlcN1X9pwQU7LhdZ/ZAseD45cOh9hHvDkc/yAF/DNhdb5Mrr3PvBMaAYW8fMSIi2G497IMEK/YutGtAYr6+ej+nxu/NN8Ks3N7AR6HgcLz0Eg1Ljg1UcxZzi5qewIkMYLRweTr2Kzp+nmyXAd5pS3XQDd+N/4h4zgu9FI7brlXf90nMEnuwQxlvv+hosE3TuexmWeysmT4W+WxkMaLzf9Y8ATgjcUn7T9H1gqrpFq8eV1gMn6t16NhngjfoX6q4DUP032Rd4LJgpSLwJ1yzFqBG69eRkah0MVyo0Acfe+yy9AG4nMiYCkeM53KKFXncBLAXqEm+wCqZwaueq7WCmuLTcKSJmj737ol2hurA9eq9VdyiO8yWa3NNyog+SB5CZodSsQq/dfu34tJpYbBaTMzvVddDZu16q5smXf4G8zEvqm4cyaAmJPuTJk3oJWdS4WzcVtfMZbThSQckb/pYfRGgo3zNOqZnEHbJPGK4abaDCQIIsT8V/qTaBqHkLh6LzXH8XZQhbLhYKyyCC/WeHYcNdmvOgfe8skzbWL270/T3wf7tSx/lGCbTu8xlzzmCSWLc5iwmgikcCHi3Mga0Ry913vBFvQwg90l6M4ImWKfsWOp7DSWxmfpPlCFuPFfsNfKrCnPYpQKIRgqBK7D0SxYaNHwkEiJMtl0ReDp3Lc5D3PGoTo/sKngCl7a5chFqvBatKwjBd7WwqIlzB/78NcoUcp5VSgGxm+7b8eqQRGnHMO634epO4S1EZww09/iFg5UmGoESDuznP1xVhTUX1WWHPzjpd25wyH0hRxI3LGM75nxmuNEEUVpAN0XgxmPoKralakbQnWlIMQyVBD/w+3orkq4lvualjKyWwzt4MaxqspQHVhPOWG64bxYuhZXSFGWhipbSDVragOu5Y9eAsmDDUKyBA703vemVhHoueD6e9wAzJK1WfmN0Umk5GGM4kEMZcuIECqgjm0nldAqmbjwtm4VxZH5AvlADP6mx9Eqy9Q0+KqW8Ch+47FaMMYmnNGfY1iPMshoC6qFxme4wQ+0p+ARE6H3+9veWEDWgUhDhUKyFARn4jM5BNxT0XsMg7bfymGK1ov3wtjDfhL4w0HVGUVBEjDaaE+QNdrcNWch1PG4W6xrjBUXECGivg++Cva3JUT4iQUz3V2RsSVaKLwOuDT89A3HdBQoxhNC+fnVm74ual2EG893P6G+PuP4SfiO4cCBWQooL9qCWKNXPbcI37Aa/lnlZxXRt4RFONGwSDCPAHqOuqjWct1QiEMw5mChM5X4K47FyNqcd3aK9AwFH0CGYLoe1ctxk2eWi57rg5JfGp9rzC6ggCdFlAgHBDw5Yxlcg6G8SyHCjMlsgmDD9zhSeHlF+JnAgWDTQUy2NxfdwOao1UVV3pi3+bE97YSbWpLAbn6zefHNQkp1PMpIBwwvslKgIYTKM2nEpNzrGcH3FXTEal0L38kJ4uDQgEZbO4vnI173LXf5NHZaiUxtaCxyZuo/rK6LpUg54yg3zTWRAArvDcRIPZ6BqzrQ1REpmL+DNw32OKIDCb3X1qPVn8wNNMT4w2bvs+q4bAZrqBh2skaL3yyhhIIZ4i6oHkUK0RckcB8GigEyRIH4A6Mgc8fatl0/+BkkQxC9gIT4ljna1rIZW9rEdNbjJcNjsnoYj7LHWCUwpITzEgzRQKZ3XAFHbTzA3hrz8TEUUZxFBhoKpABQt/97p+w0hMZG68I8R6FtlsJT3FELndZntjM+VMnylKYq8GJI3UZaRMpquGSGFVOEfv0YZBMNzz+uvjbfzS6xQERIhlI9FcvQWNdFVb7x1zCb+QNK8vb9NsiifmI5hBgVoOCBC1sb0ab5RomqENxLO3eA1/0NDRU47q2RQNbRCUDIb7lF2CNL3ZGxEV4n08TVvZWYG4pZyV0zUdS45tyCBByOHWiyvZmxFXDCyRo1ge5+Sy0TA+8lWMiP/6O0S32exGV9Jf4fr8azdUR3zL/CZz4MtvzdX5uOYs6NDOmpkuj5Huh+7qUQSYl0ThHzw0YQzcGo6bhzEqoYq5rN3yRiYiG3Vfe2Ybm/qKA9NNZ3nNm4F7/yDkg9AN+U1mHiBcXP8zuDN76jj8hg1QyiWQigalj02BJPhK8I0zxijAjhp5zhlpLUDvS+BCy2HMAvvB4XDgL9/SXC0g/ou/5+6/xLX8w0uJrOIkXfPvyhY0F6gr7M8H0KWFYikcqAXakB+xwD9CdREBLoau7Gz3cAdSIdLFxFtJTCqRChSjnutvhDcREtzjz2Tswtz+yeNRFUeXZXtWux7C1fuoVcbd3J//ipDX3uZZDLGrwweS+UBLL5TDliVBnF8P7H+XI8aRRGsIBJg/Zlslt1+W+D1JWoSyi+kD9jfhs78t7mhZhSl+fLfY1Bdyv3I8V/qpY3B1McgN7ZFT5/vNO0I5DPLLdPBIJA8qc4h2I0QplYfDpJwHT+aj0246r5S8rToG8OjCle8wk4OLvvYGa+Ovr84uo2qBSwJS9G5egoZFLTfiEqWDtbwGfHgKOdPHcS+ai7XDzMPW/FJRLGGcxnBbK4YJC2K+h+T6Bdu5CqHqCWERd3bawb7JI+iJ735+LNaHaprBLLHBm08U3XxShEsdt+f3eTh3v7aC95Dct4RCWL5OZWh/oXBZThxAIxyOXLzBk8aiEWJID8rK3CpPOmeHaGpvCS+7EHv5FujVHUSJPLXvIFeHcNc+9xrB2gws9KZdxuLFax/WLM5gzzSm/lTXF/OdAcapyvjxPqxqHjr2v4ckX2bS2dRBrc5lSdpKjEJ9/9tdwX2WMd53ZQ2IVo3RES+UwVSpCPvYepNx4gmTGDUKIMQ4eduPnD7mx9xOn/KZKOlFbStjONxHTtR+BYAPmnoZ1Zp8wkBRwP/EL3u0F/C2hGl7vpz7vW37T3vP7if8wroKuoh8ribknX9BK5rcF+mo1qKaKyRPJTgTDjbzY8szcuLb3bpH00u35T47j7prRpwDJTxzyG0dHgxPp5bPG8VdkpfPbUg3SgoOo2mwVukb98D5EqpswZTTulCggTk4gpYhv0++wIhCJxr0+Hq1sondis0SE2oxQe3qWXwWyO4DSQg9gJ8Iiw1VFcGqXxet0N9xE4ygIxv/9W6wo9WyROEX/R+eiobYSq2vHTOR631Eiv2lRfh9dvxkumkXh92Qsx8XrAJ+7YGbWuhxOi/U+31NQmzyqNYG8N/3wfo6CRtRHcN01FzkvojohwLu0VVvDa56IS/xcj2b7nN+O+m0jqpE1wMPXZxAN9iCVThtDvH7gmiRGRpU8Lspv1Uhq4wIVdQoyuGSLNYPKUCS8+CzNURbzMmjK3i8u0U793lmuV0ef9nWQ5MGC/DiUqEUSaCtXna9RJEspZS1lrXINK/pcq+SpT50t98QKMq1FRmDfx3vxty102k0PM4ssEnvuz5+G26Ij4yDpz6z9fV8bkyIkqBFkhej0Ib+ZQ34XJK9AfozaiimqIoX3Jp3tiISrcfYpuN2+iFph/02P36PNC9fVcCnp6H9jYouKyfaWufz5Tp9tVxcUniw7IohZv4dZz81/ns67z3AYPrc2n0+Ix2q8k0PWjgBy88XaibnfK9A+5LdDY2Ivhy36fbT8Zv3Lb1U1qLqUxorXEEXIs0mjjrtxoTZWtdvigNs2sgPiujTv6DIZLld6b/V5742JZV3fUsUVFy5gdsNtKWFzUCEVbNepD1MkSMVbsb6SZm7jI3/zODtQKgUMsOw8wDZ63t5xcV1TnaEAxoc6wrqY+Fj+N4DsqOnhOIdicrQSm1MPYCPlIqHn5bbHg8/bj2D3QfZnCX3mpAICDZV8jH5kpbZqTD0W+DxaA74CWzLN2nd14OlL72J38Lf7+TjC7dadZFDoZJQPrtaIKL/G0L6ktptPZVJ8fMqHYPZOKYPMyQGadIJfDvdXwAFiZOTvDBPydf5vk4rWA+RfdhBlaF/yDDBRoMu9pfnSjv/p7DG+HXfAcQcc49v/BBgAcFAO4DmB2GQAAAAASUVORK5CYII=" />',
'<img class="remote" src="' + TEST_URL_ROOT + 'doc_markup_tooltip.png" />',
'<canvas class="canvas" width="600" height="600"></canvas>'
].join("\n");
const TEST_NODES = [
- {selector: "img.local", size: "192 x 192"},
- {selector: "img.data", size: "64 x 64"},
- {selector: "img.remote", size: "22 x 23"},
- {selector: ".canvas", size: "600 x 600"}
+ {selector: "img.local", size: "192" + " \u00D7 " + "192"},
+ {selector: "img.data", size: "64" + " \u00D7 " + "64"},
+ {selector: "img.remote", size: "22" + " \u00D7 " + "23"},
+ {selector: ".canvas", size: "600" + " \u00D7 " + "600"}
];
add_task(function*() {
yield addTab("data:text/html,markup view tooltip test");
createPage();
let {inspector} = yield openInspector();
--- a/browser/devtools/netmonitor/netmonitor-view.js
+++ b/browser/devtools/netmonitor/netmonitor-view.js
@@ -1678,17 +1678,17 @@ RequestsMenuView.prototype = Heritage.ex
},
/**
* A handler that opens the security tab in the details view if secure or
* broken security indicator is clicked.
*/
_onSecurityIconClick: function(e) {
let state = this.selectedItem.attachment.securityState;
- if (state === "broken" || state === "secure") {
+ if (state !== "insecure") {
// Choose the security tab.
NetMonitorView.NetworkDetails.widget.selectedIndex = 5;
}
},
/**
* The resize listener for this container's window.
*/
@@ -2600,17 +2600,17 @@ NetworkDetailsView.prototype = {
$("#response-content-image-encoding-value").setAttribute("value", encoding);
// Wait for the image to load in order to display the width and height.
$("#response-content-image").onload = e => {
// XUL images are majestic so they don't bother storing their dimensions
// in width and height attributes like the rest of the folk. Hack around
// this by getting the bounding client rect and subtracting the margins.
let { width, height } = e.target.getBoundingClientRect();
- let dimensions = (width - 2) + " x " + (height - 2);
+ let dimensions = (width - 2) + " \u00D7 " + (height - 2);
$("#response-content-image-dimensions-value").setAttribute("value", dimensions);
};
}
// Handle anything else.
else {
$("#response-content-textarea-box").hidden = false;
let editor = yield NetMonitorView.editor("#response-content-textarea");
editor.setMode(Editor.modes.text);
@@ -2760,20 +2760,32 @@ NetworkDetailsView.prototype = {
label.value = value;
label.setAttribute("tooltiptext", value);
}
}
let errorbox = $("#security-error");
let infobox = $("#security-information");
- if (securityInfo.state === "secure") {
+ if (securityInfo.state === "secure" || securityInfo.state === "weak") {
infobox.hidden = false;
errorbox.hidden = true;
+ // Warning icons
+ let cipher = $("#security-warning-cipher");
+ let sslv3 = $("#security-warning-sslv3");
+
+ if (securityInfo.state === "weak") {
+ cipher.hidden = securityInfo.weaknessReasons.indexOf("cipher") === -1;
+ sslv3.hidden = securityInfo.weaknessReasons.indexOf("sslv3") === -1;
+ } else {
+ cipher.hidden = true;
+ sslv3.hidden = true;
+ }
+
let enabledLabel = L10N.getStr("netmonitor.security.enabled");
let disabledLabel = L10N.getStr("netmonitor.security.disabled");
// Connection parameters
setLabel("#security-protocol-version-value", securityInfo.protocolVersion);
setLabel("#security-ciphersuite-value", securityInfo.cipherSuite);
// Host header
--- a/browser/devtools/netmonitor/netmonitor.xul
+++ b/browser/devtools/netmonitor/netmonitor.xul
@@ -501,26 +501,32 @@
class="tabpanel-summary-container"
align="center">
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.security.protocolVersion;"/>
<label id="security-protocol-version-value"
class="plain tabpanel-summary-value devtools-monospace"
crop="end"
flex="1"/>
+ <image class="security-warning-icon"
+ id="security-warning-sslv3"
+ tooltiptext="&netmonitorUI.security.warning.sslv3;" />
</hbox>
<hbox id="security-ciphersuite"
class="tabpanel-summary-container"
align="center">
<label class="plain tabpanel-summary-label"
value="&netmonitorUI.security.cipherSuite;"/>
<label id="security-ciphersuite-value"
class="plain tabpanel-summary-value devtools-monospace"
crop="end"
flex="1"/>
+ <image class="security-warning-icon"
+ id="security-warning-cipher"
+ tooltiptext="&netmonitorUI.security.warning.cipher;" />
</hbox>
</vbox>
</vbox>
<vbox id="security-info-domain"
class="tabpanel-summary-container">
<label class="plain tabpanel-summary-label"
id="security-info-host-header"/>
<vbox class="security-info-section">
--- a/browser/devtools/netmonitor/test/browser.ini
+++ b/browser/devtools/netmonitor/test/browser.ini
@@ -87,16 +87,17 @@ skip-if = e10s # Bug 1091603
skip-if = e10s # Bug 1091612
[browser_net_security-details.js]
[browser_net_security-error.js]
[browser_net_security-icon-click.js]
[browser_net_security-redirect.js]
[browser_net_security-state.js]
[browser_net_security-tab-deselect.js]
[browser_net_security-tab-visibility.js]
+[browser_net_security-warnings.js]
[browser_net_simple-init.js]
[browser_net_simple-request-data.js]
[browser_net_simple-request-details.js]
[browser_net_simple-request.js]
[browser_net_sort-01.js]
[browser_net_sort-02.js]
[browser_net_sort-03.js]
[browser_net_statistics-01.js]
--- a/browser/devtools/netmonitor/test/browser_net_content-type.js
+++ b/browser/devtools/netmonitor/test/browser_net_content-type.js
@@ -203,17 +203,17 @@ function test() {
"The image name info isn't correct.");
is(tabpanel.querySelector("#response-content-image-mime-value")
.getAttribute("value"), "image/png",
"The image mime info isn't correct.");
is(tabpanel.querySelector("#response-content-image-encoding-value")
.getAttribute("value"), "base64",
"The image encoding info isn't correct.");
is(tabpanel.querySelector("#response-content-image-dimensions-value")
- .getAttribute("value"), "16 x 16",
+ .getAttribute("value"), "16" + " \u00D7 " + "16",
"The image dimensions info isn't correct.");
deferred.resolve();
});
return deferred.promise;
}
}
--- a/browser/devtools/netmonitor/test/browser_net_security-state.js
+++ b/browser/devtools/netmonitor/test/browser_net_security-state.js
@@ -8,16 +8,17 @@
* state.
*/
add_task(function* () {
const EXPECTED_SECURITY_STATES = {
"test1.example.com": "security-state-insecure",
"example.com": "security-state-secure",
"nocert.example.com": "security-state-broken",
+ "rc4.example.com": "security-state-weak",
};
let [tab, debuggee, monitor] = yield initNetMonitor(CUSTOM_GET_URL);
let { $, EVENTS, NetMonitorView } = monitor.panelWin;
let { RequestsMenu } = NetMonitorView;
RequestsMenu.lazyUpdate = false;
yield performRequests();
@@ -65,17 +66,22 @@ add_task(function* () {
debuggee.performRequests(1, "http://test1.example.com" + CORS_SJS_PATH);
yield done;
done = waitForNetworkEvents(monitor, 1);
info("Requesting a resource over HTTPS.");
debuggee.performRequests(1, "https://example.com" + CORS_SJS_PATH);
yield done;
- is(RequestsMenu.itemCount, 3, "Three events logged.");
+ done = waitForNetworkEvents(monitor, 1);
+ info("Requesting a resource over HTTPS with RC4.");
+ debuggee.performRequests(1, "https://rc4.example.com" + CORS_SJS_PATH);
+ yield done;
+
+ is(RequestsMenu.itemCount, 4, "Four events logged.");
}
/**
* Returns a promise that's resolved once a request with security issues is
* completed.
*/
function waitForSecurityBrokenNetworkEvent() {
let awaitedEvents = [
new file mode 100644
--- /dev/null
+++ b/browser/devtools/netmonitor/test/browser_net_security-warnings.js
@@ -0,0 +1,81 @@
+/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+"use strict";
+
+/**
+ * Test that warning indicators are shown when appropriate.
+ */
+
+const TEST_CASES = [
+ {
+ desc: "no warnings",
+ uri: "https://example.com" + CORS_SJS_PATH,
+ warnCipher: false,
+ warnSSLv3: false,
+ },
+ {
+ desc: "sslv3 warning",
+ uri: "https://ssl3.example.com" + CORS_SJS_PATH,
+ warnCipher: false,
+ warnSSLv3: true,
+ },
+ {
+ desc: "cipher warning",
+ uri: "https://rc4.example.com" + CORS_SJS_PATH,
+ warnCipher: true,
+ warnSSLv3: false,
+ },
+ {
+ desc: "cipher and sslv3 warning",
+ uri: "https://ssl3rc4.example.com" + CORS_SJS_PATH,
+ warnCipher: true,
+ warnSSLv3: true,
+ },
+];
+
+add_task(function* () {
+ let [tab, debuggee, monitor] = yield initNetMonitor(CUSTOM_GET_URL);
+ let { $, EVENTS, NetMonitorView } = monitor.panelWin;
+ let { RequestsMenu, NetworkDetails } = NetMonitorView;
+ RequestsMenu.lazyUpdate = false;
+
+ info("Enabling SSLv3 for the test.");
+ yield new promise(resolve => {
+ SpecialPowers.pushPrefEnv({"set": [["security.tls.version.min", 0]]}, resolve);
+ });
+
+ let cipher = $("#security-warning-cipher");
+ let sslv3 = $("#security-warning-sslv3");
+
+ for (let test of TEST_CASES) {
+ info("Testing site with " + test.desc);
+
+ info("Performing request to " + test.uri);
+ debuggee.performRequests(1, test.uri);
+ yield waitForNetworkEvents(monitor, 1);
+
+ info("Selecting the request.");
+ RequestsMenu.selectedIndex = 0;
+
+ info("Waiting for details pane to be updated.");
+ yield monitor.panelWin.once(EVENTS.TAB_UPDATED);
+
+ if (NetworkDetails.widget.selectedIndex !== 5) {
+ info("Selecting security tab.");
+ NetworkDetails.widget.selectedIndex = 5;
+
+ info("Waiting for details pane to be updated.");
+ yield monitor.panelWin.once(EVENTS.TAB_UPDATED);
+ }
+
+ is(cipher.hidden, !test.warnCipher, "Cipher suite warning is hidden.");
+ is(sslv3.hidden, !test.warnSSLv3, "SSLv3 warning is hidden.");
+
+ RequestsMenu.clear();
+
+ }
+
+ yield teardown(monitor);
+
+});
--- a/browser/devtools/responsivedesign/responsivedesign.jsm
+++ b/browser/devtools/responsivedesign/responsivedesign.jsm
@@ -599,17 +599,17 @@ ResponsiveUI.prototype = {
/**
* Set the menuitem label of a preset.
*
* @param aMenuitem menuitem to edit.
* @param aPreset associated preset.
*/
setMenuLabel: function RUI_setMenuLabel(aMenuitem, aPreset) {
- let size = Math.round(aPreset.width) + "x" + Math.round(aPreset.height);
+ let size = Math.round(aPreset.width) + "\u00D7" + Math.round(aPreset.height);
// .inputField might be not reachable yet (async XBL loading)
if (this.menulist.inputField) {
this.menulist.inputField.value = size;
}
if (aPreset.custom) {
size = this.strings.formatStringFromName("responsiveUI.customResolution", [size], 1);
--- a/browser/devtools/responsivedesign/test/browser_responsiveui.js
+++ b/browser/devtools/responsivedesign/test/browser_responsiveui.js
@@ -205,17 +205,17 @@ function test() {
// Invalid input
initialWidth = content.innerWidth;
initialHeight = content.innerHeight;
index = instance.menulist.selectedIndex;
- let expectedValue = initialWidth + "x" + initialHeight;
+ let expectedValue = initialWidth + "\u00D7" + initialHeight;
let expectedLabel = instance.menulist.firstChild.firstChild.getAttribute("label");
userInput = "I'm wrong";
instance.menulist.inputField.value = "";
instance.menulist.focus();
processStringAsKey(userInput);
EventUtils.synthesizeKey("VK_RETURN", {});
--- a/browser/devtools/responsivedesign/test/browser_responsiveuiaddcustompreset.js
+++ b/browser/devtools/responsivedesign/test/browser_responsiveuiaddcustompreset.js
@@ -110,17 +110,17 @@ function test() {
synthesizeKeyFromKeyTag("key_responsiveUI");
yield once(mgr, "on");
is(container.getAttribute("responsivemode"), "true", "In responsive mode.");
instance = mgr.getResponsiveUIForTab(gBrowser.selectedTab);
- let customPresetIndex = getPresetIndex("456x123 (Testing preset)");
+ let customPresetIndex = getPresetIndex("456" + "\u00D7" + "123 (Testing preset)");
info(customPresetIndex);
ok(customPresetIndex >= 0, "is the previously added preset (idx = " + customPresetIndex + ") in the list of items");
instance.menulist.selectedIndex = customPresetIndex;
is(content.innerWidth, 456, "add preset, and selected in the list, dimension valid (width)");
is(content.innerHeight, 123, "add preset, and selected in the list, dimension valid (height)");
--- a/browser/devtools/shared/widgets/Tooltip.js
+++ b/browser/devtools/shared/widgets/Tooltip.js
@@ -721,17 +721,17 @@ Tooltip.prototype = {
}
vbox.appendChild(label);
}
this.content = vbox;
},
- _getImageDimensionLabel: (w, h) => w + " x " + h,
+ _getImageDimensionLabel: (w, h) => w + " \u00D7 " + h,
/**
* Fill the tooltip with a new instance of the spectrum color picker widget
* initialized with the given color, and return a promise that resolves to
* the instance of spectrum
*/
setColorPickerContent: function(color) {
let def = promise.defer();
--- a/browser/locales/en-US/chrome/browser/devtools/netmonitor.dtd
+++ b/browser/locales/en-US/chrome/browser/devtools/netmonitor.dtd
@@ -197,16 +197,24 @@
- in a "wait" state. -->
<!ENTITY netmonitorUI.timings.wait "Waiting:">
<!-- LOCALIZATION NOTE (debuggerUI.timings.receive): This is the label displayed
- in the network details timings tab identifying the amount of time spent
- in a "receive" state. -->
<!ENTITY netmonitorUI.timings.receive "Receiving:">
+<!-- LOCALIZATION NOTE (netmonitorUI.security.warning.protocol): A tooltip
+ - for warning icon that indicates a connection uses insecure protocol. -->
+<!ENTITY netmonitorUI.security.warning.sslv3 "The protocol SSL 3.0 is deprecated and insecure.">
+
+<!-- LOCALIZATION NOTE (netmonitorUI.security.warning.cipher): A tooltip
+ - for warning icon that indicates a connection uses insecure cipher suite. -->
+<!ENTITY netmonitorUI.security.warning.cipher "The cipher used for encryption is deprecated and insecure.">
+
<!-- LOCALIZATION NOTE (netmonitorUI.security.error): This is the label displayed
- in the security tab if a security error prevented the connection. -->
<!ENTITY netmonitorUI.security.error "An error occured:">
<!-- LOCALIZATION NOTE (netmonitorUI.security.protocolVersion): This is the label displayed
- in the security tab describing TLS/SSL protocol version. -->
<!ENTITY netmonitorUI.security.protocolVersion "Protocol version:">
--- a/browser/locales/en-US/chrome/browser/devtools/netmonitor.properties
+++ b/browser/locales/en-US/chrome/browser/devtools/netmonitor.properties
@@ -39,16 +39,20 @@ netmonitor.security.state.secure=The con
# channel i.e. the connection was not encrypted.
netmonitor.security.state.insecure=The connection used to fetch this resource was not encrypted.
# LOCALIZATION NOTE (netmonitor.security.state.broken)
# This string is used as an tooltip for request that failed due to security
# issues.
netmonitor.security.state.broken=A security error prevented the resource from being loaded.
+# LOCALIZATION NOTE (netmonitor.security.state.weak)
+# This string is used as an tooltip for request that had minor security issues
+netmonitor.security.state.weak=This resource was transferred over a connection that used weak encryption.
+
# LOCALIZATION NOTE (netmonitor.security.enabled):
# This string is used to indicate that a specific security feature is used by
# a connection in the security details tab.
# For example: "HTTP Strict Transport Security: Enabled"
netmonitor.security.enabled=Enabled
# LOCALIZATION NOTE (netmonitor.security.disabled):
# This string is used to indicate that a specific security feature is not used by
--- a/browser/themes/shared/devtools/netmonitor.inc.css
+++ b/browser/themes/shared/devtools/netmonitor.inc.css
@@ -173,16 +173,21 @@
list-style-image: url(chrome://browser/skin/identity-icons-generic.png);
}
.security-state-secure {
cursor: pointer;
list-style-image: url(chrome://browser/skin/identity-icons-https.png);
}
+.security-state-weak {
+ cursor: pointer;
+ list-style-image: url(chrome://browser/skin/identity-icons-https-mixed-display.png);
+}
+
.security-state-broken {
cursor: pointer;
list-style-image: url(chrome://browser/skin/identity-icons-https-mixed-active.png);
}
.requests-menu-type {
text-align: center;
width: 4em;
@@ -573,16 +578,31 @@ label.requests-menu-status-code {
#security-tabpanel {
overflow: auto;
}
#security-error-message {
white-space: pre-wrap;
}
+.security-warning-icon {
+ background-image: url(alerticon-warning.png);
+ background-size: 13px 12px;
+ -moz-margin-start: 5px;
+ vertical-align: top;
+ width: 13px;
+ height: 12px;
+}
+
+@media (min-resolution: 2dppx) {
+ .security-warning-icon {
+ background-image: url(alerticon-warning@2x.png);
+ }
+}
+
/* Custom request form */
#custom-pane {
padding: 0.6em 0.5em;
}
.custom-header {
font-size: 1.1em;
--- a/browser/themes/shared/incontentprefs/preferences.inc.css
+++ b/browser/themes/shared/incontentprefs/preferences.inc.css
@@ -20,16 +20,24 @@
button,
treecol {
/* override the * rule */
-moz-user-select: none;
}
/* Category List */
+#categories {
+ max-height: 100vh;
+}
+
+#categories > scrollbox {
+ overflow-x: hidden !important;
+}
+
.category-icon {
list-style-image: url("chrome://browser/skin/preferences/in-content/icons.png");
}
#category-general > .category-icon {
-moz-image-region: rect(0, 24px, 24px, 0);
}
--- a/configure.in
+++ b/configure.in
@@ -4101,33 +4101,16 @@ fi
if test "$BUILDING_RELEASE"; then
# Override value in defines.sh, if any
EARLY_BETA_OR_EARLIER=
elif test "$EARLY_BETA_OR_EARLIER"; then
AC_DEFINE(EARLY_BETA_OR_EARLIER)
fi
AC_SUBST(EARLY_BETA_OR_EARLIER)
-# Allow the application to provide a subconfigure script
-if test -f "${srcdir}/${MOZ_BUILD_APP}/configure.in" ; then
- do_output_subdirs() {
- if test -n "$_subconfigure_subdirs"; then
- AC_MSG_ERROR([Cannot specify more than one sub-sub-configure])
- fi
- _subconfigure_subdir="$1"
- _subconfigure_config_args="$ac_configure_args"
- }
- tmpscript=`$PYTHON -c 'import os, tempfile; print tempfile.mktemp(prefix="subscript.").replace(os.sep, "/")'` || exit 1
- m4 "${srcdir}/build/autoconf/subconfigure.m4" \
- "${srcdir}/build/autoconf/altoptions.m4" \
- "${srcdir}/${MOZ_BUILD_APP}/configure.in" > $tmpscript
- . $tmpscript
- rm -f $tmpscript
-fi
-
# Allow someone to change MOZ_APP_NAME and MOZ_APP_BASENAME in mozconfig
MOZ_ARG_WITH_STRING(app-name,
[--with-app-name=APPNAME sets MOZ_APP_NAME to APPNAME],
WITH_APP_NAME=$withval,
)
if test -n "$WITH_APP_NAME" ; then
MOZ_APP_NAME="$WITH_APP_NAME"
@@ -5959,17 +5942,16 @@ if test -n "$MOZ_ANGLE_RENDERER"; then
MOZ_DIRECTX_SDK_PATH=
fi
else
AC_MSG_RESULT([Couldn't determine the D3DX9 version for the DirectX SDK.])
MOZ_DIRECTX_SDK_PATH=
fi
else
AC_MSG_RESULT([Couldn't find an acceptable DirectX SDK for ANGLE, needed for d3dcompiler_43.])
- AC_MSG_RESULT([ Either ignore, install DirectX SDK (June 2010 version or newer), or reconfigure with --disable-webgl.])
fi
fi
######################################
# Check that we found what we needed.
MOZ_FOUND_A_D3D_COMPILER=
MOZ_FOUND_BOTH_D3D_COMPILERS=1
@@ -5985,17 +5967,16 @@ if test -n "$MOZ_ANGLE_RENDERER"; then
AC_MSG_RESULT([Found d3dcompiler DLL for XP: $MOZ_D3DCOMPILER_XP_DLL])
else
MOZ_FOUND_BOTH_D3D_COMPILERS=
fi
if test -z "$CROSS_COMPILE"; then
if test -z "MOZ_FOUND_A_D3D_COMPILER"; then
AC_MSG_ERROR([Couldn't find an acceptable D3D compiler DLL.])
- AC_MSG_ERROR([ Either install Windows SDK 8.0+, install DirectX SDK (June 2010 version or newer), or reconfigure with --disable-webgl.])
fi
if test -n "$MOZ_REQUIRE_ALL_D3DCS" -a -z "$MOZ_FOUND_BOTH_D3D_COMPILERS"; then
AC_MSG_ERROR([Both D3D compilers _43 and _46+ are required by --enable-require-d3d-compilers.])
AC_MSG_ERROR([ Install Windows SDK 8.0+, as well as DirectX SDK (June 2010 version or newer), or reconfigure without this flag.])
fi
fi
fi
@@ -7252,16 +7233,35 @@ fi # MOZ_MEMORY
AC_SUBST(MOZ_MEMORY)
AC_SUBST(MOZ_JEMALLOC3)
AC_SUBST(MOZ_NATIVE_JEMALLOC)
AC_SUBST(MOZ_CRT)
export MOZ_CRT
AC_SUBST(MOZ_GLUE_IN_PROGRAM)
AC_SUBST_LIST(WIN32_CRT_LIBS)
+# Allow the application to provide a subconfigure script.
+# This should be after 'export MOZ_NO_DEBUG_RTL=1' since
+# ldap/c-sdk/configure refers to the enviroment value.
+if test -f "${srcdir}/${MOZ_BUILD_APP}/configure.in" ; then
+ do_output_subdirs() {
+ if test -n "$_subconfigure_subdirs"; then
+ AC_MSG_ERROR([Cannot specify more than one sub-sub-configure])
+ fi
+ _subconfigure_subdir="$1"
+ _subconfigure_config_args="$ac_configure_args"
+ }
+ tmpscript=`$PYTHON -c 'import os, tempfile; print tempfile.mktemp(prefix="subscript.").replace(os.sep, "/")'` || exit 1
+ m4 "${srcdir}/build/autoconf/subconfigure.m4" \
+ "${srcdir}/build/autoconf/altoptions.m4" \
+ "${srcdir}/${MOZ_BUILD_APP}/configure.in" > $tmpscript
+ . $tmpscript
+ rm -f $tmpscript
+fi
+
dnl We need to wrap dlopen and related functions on Android because we use
dnl our own linker.
if test "$OS_TARGET" = Android; then
MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=PR_GetEnv,--wrap=PR_SetEnv"
if test "$MOZ_WIDGET_TOOLKIT" = gonk -a -n "$MOZ_NUWA_PROCESS"; then
MOZ_GLUE_WRAP_LDFLAGS="${MOZ_GLUE_WRAP_LDFLAGS} -Wl,--wrap=pthread_create,--wrap=epoll_wait,--wrap=poll,--wrap=pthread_cond_timedwait,--wrap=pthread_cond_wait,--wrap=epoll_create,--wrap=epoll_ctl,--wrap=close,--wrap=pthread_key_create,--wrap=pthread_key_delete,--wrap=socketpair,--wrap=pthread_self,--wrap=pthread_mutex_lock,--wrap=pthread_join,--wrap=pipe,--wrap=pipe2"
fi
if test "$MOZ_WIDGET_TOOLKIT" = android; then
--- a/dom/base/nsJSUtils.h
+++ b/dom/base/nsJSUtils.h
@@ -12,16 +12,17 @@
* The goal of the utility functions is to cut down on the size of
* the generated code itself.
*/
#include "mozilla/Assertions.h"
#include "jsapi.h"
#include "jsfriendapi.h"
+#include "js/Conversions.h"
#include "nsString.h"
class nsIScriptContext;
class nsIScriptGlobalObject;
namespace mozilla {
namespace dom {
class AutoJSAPI;
--- a/dom/bindings/BindingUtils.h
+++ b/dom/bindings/BindingUtils.h
@@ -4,16 +4,17 @@
* 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_BindingUtils_h__
#define mozilla_dom_BindingUtils_h__
#include "jsfriendapi.h"
#include "jswrapper.h"
+#include "js/Conversions.h"
#include "mozilla/ArrayUtils.h"
#include "mozilla/Alignment.h"
#include "mozilla/Array.h"
#include "mozilla/Assertions.h"
#include "mozilla/dom/BindingDeclarations.h"
#include "mozilla/dom/CallbackObject.h"
#include "mozilla/dom/DOMJSClass.h"
#include "mozilla/dom/DOMJSProxyHandler.h"
--- a/dom/bindings/PrimitiveConversions.h
+++ b/dom/bindings/PrimitiveConversions.h
@@ -11,16 +11,17 @@
#ifndef mozilla_dom_PrimitiveConversions_h
#define mozilla_dom_PrimitiveConversions_h
#include <limits>
#include <math.h>
#include <stdint.h>
#include "jsapi.h"
+#include "js/Conversions.h"
#include "mozilla/Assertions.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/FloatingPoint.h"
namespace mozilla {
namespace dom {
template<typename T>
--- a/dom/canvas/CanvasRenderingContext2D.cpp
+++ b/dom/canvas/CanvasRenderingContext2D.cpp
@@ -63,16 +63,17 @@
#include "nsIMemoryReporter.h"
#include "nsStyleUtil.h"
#include "CanvasImageCache.h"
#include <algorithm>
#include "jsapi.h"
#include "jsfriendapi.h"
+#include "js/Conversions.h"
#include "mozilla/Alignment.h"
#include "mozilla/Assertions.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/DebugOnly.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/ImageData.h"
#include "mozilla/dom/PBrowserParent.h"
@@ -4815,20 +4816,20 @@ CanvasRenderingContext2D::GetImageData(J
return nullptr;
}
if (!aSw || !aSh) {
error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
- int32_t x = JS_DoubleToInt32(aSx);
- int32_t y = JS_DoubleToInt32(aSy);
- int32_t wi = JS_DoubleToInt32(aSw);
- int32_t hi = JS_DoubleToInt32(aSh);
+ int32_t x = JS::ToInt32(aSx);
+ int32_t y = JS::ToInt32(aSy);
+ int32_t wi = JS::ToInt32(aSw);
+ int32_t hi = JS::ToInt32(aSh);
// Handle negative width and height by flipping the rectangle over in the
// relevant direction.
uint32_t w, h;
if (aSw < 0) {
w = -wi;
x -= w;
} else {
@@ -5011,39 +5012,39 @@ CanvasRenderingContext2D::FillRuleChange
void
CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
double dy, ErrorResult& error)
{
dom::Uint8ClampedArray arr;
DebugOnly<bool> inited = arr.Init(imageData.GetDataObject());
MOZ_ASSERT(inited);
- error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
+ error = PutImageData_explicit(JS::ToInt32(dx), JS::ToInt32(dy),
imageData.Width(), imageData.Height(),
&arr, false, 0, 0, 0, 0);
}
void
CanvasRenderingContext2D::PutImageData(ImageData& imageData, double dx,
double dy, double dirtyX,
double dirtyY, double dirtyWidth,
double dirtyHeight,
ErrorResult& error)
{
dom::Uint8ClampedArray arr;
DebugOnly<bool> inited = arr.Init(imageData.GetDataObject());
MOZ_ASSERT(inited);
- error = PutImageData_explicit(JS_DoubleToInt32(dx), JS_DoubleToInt32(dy),
+ error = PutImageData_explicit(JS::ToInt32(dx), JS::ToInt32(dy),
imageData.Width(), imageData.Height(),
&arr, true,
- JS_DoubleToInt32(dirtyX),
- JS_DoubleToInt32(dirtyY),
- JS_DoubleToInt32(dirtyWidth),
- JS_DoubleToInt32(dirtyHeight));
+ JS::ToInt32(dirtyX),
+ JS::ToInt32(dirtyY),
+ JS::ToInt32(dirtyWidth),
+ JS::ToInt32(dirtyHeight));
}
// void putImageData (in ImageData d, in float x, in float y);
// void putImageData (in ImageData d, in double x, in double y, in double dirtyX, in double dirtyY, in double dirtyWidth, in double dirtyHeight);
nsresult
CanvasRenderingContext2D::PutImageData_explicit(int32_t x, int32_t y, uint32_t w, uint32_t h,
dom::Uint8ClampedArray* aArray,
@@ -5201,18 +5202,18 @@ already_AddRefed<ImageData>
CanvasRenderingContext2D::CreateImageData(JSContext* cx, double sw,
double sh, ErrorResult& error)
{
if (!sw || !sh) {
error.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return nullptr;
}
- int32_t wi = JS_DoubleToInt32(sw);
- int32_t hi = JS_DoubleToInt32(sh);
+ int32_t wi = JS::ToInt32(sw);
+ int32_t hi = JS::ToInt32(sh);
uint32_t w = Abs(wi);
uint32_t h = Abs(hi);
return mozilla::dom::CreateImageData(cx, this, w, h, error);
}
already_AddRefed<ImageData>
CanvasRenderingContext2D::CreateImageData(JSContext* cx,
--- a/dom/events/Event.h
+++ b/dom/events/Event.h
@@ -27,16 +27,22 @@ class nsPresContext;
namespace mozilla {
namespace dom {
class EventTarget;
class WantsPopupControlCheck;
#define GENERATED_EVENT(EventClass_) class EventClass_;
#include "mozilla/dom/GeneratedEventList.h"
#undef GENERATED_EVENT
+// ExtendableEvent and InstallEvent are ServiceWorker events that are not
+// autogenerated since they have some extra methods.
+namespace workers {
+class ExtendableEvent;
+class InstallEvent;
+} // namespace workers
// Dummy class so we can cast through it to get from nsISupports to
// Event subclasses with only two non-ambiguous static casts.
class EventBase : public nsIDOMEvent
{
};
class Event : public EventBase,
@@ -99,16 +105,28 @@ public:
#define GENERATED_EVENT(EventClass_) \
virtual EventClass_* As##EventClass_() \
{ \
return nullptr; \
}
#include "mozilla/dom/GeneratedEventList.h"
#undef GENERATED_EVENT
+ // ExtendableEvent and InstallEvent are ServiceWorker events that are not
+ // autogenerated since they have some extra methods.
+ virtual workers::ExtendableEvent* AsExtendableEvent()
+ {
+ return nullptr;
+ }
+
+ virtual workers::InstallEvent* AsInstallEvent()
+ {
+ return nullptr;
+ }
+
// nsIDOMEvent Interface
NS_DECL_NSIDOMEVENT
void InitPresContextData(nsPresContext* aPresContext);
// Returns true if the event should be trusted.
bool Init(EventTarget* aGlobal);
--- a/dom/media/eme/CDMProxy.cpp
+++ b/dom/media/eme/CDMProxy.cpp
@@ -410,16 +410,17 @@ CDMProxy::OnResolveLoadSessionPromise(ui
}
static dom::MediaKeyMessageType
ToMediaKeyMessageType(GMPSessionMessageType aMessageType) {
switch (aMessageType) {
case kGMPLicenseRequest: return dom::MediaKeyMessageType::License_request;
case kGMPLicenseRenewal: return dom::MediaKeyMessageType::License_renewal;
case kGMPLicenseRelease: return dom::MediaKeyMessageType::License_release;
+ case kGMPIndividualizationRequest: return dom::MediaKeyMessageType::Individualization_request;
default: return dom::MediaKeyMessageType::License_request;
};
};
void
CDMProxy::OnSessionMessage(const nsAString& aSessionId,
GMPSessionMessageType aMessageType,
nsTArray<uint8_t>& aMessage)
--- a/dom/media/fmp4/MP4Stream.cpp
+++ b/dom/media/fmp4/MP4Stream.cpp
@@ -23,22 +23,25 @@ MP4Stream::~MP4Stream()
MOZ_ASSERT(mPinCount == 0);
}
bool
MP4Stream::BlockingReadIntoCache(int64_t aOffset, size_t aCount, Monitor* aToUnlock)
{
MOZ_ASSERT(mPinCount > 0);
CacheBlock block(aOffset, aCount);
+ if (!block.Init()) {
+ return false;
+ }
uint32_t sum = 0;
uint32_t bytesRead = 0;
do {
uint64_t offset = aOffset + sum;
- char* buffer = reinterpret_cast<char*>(block.mBuffer.get()) + sum;
+ char* buffer = block.Buffer() + sum;
uint32_t toRead = aCount - sum;
MonitorAutoUnlock unlock(*aToUnlock);
nsresult rv = mResource->ReadAt(offset, buffer, toRead, &bytesRead);
if (NS_FAILED(rv)) {
return false;
}
sum += bytesRead;
} while (sum < aCount && bytesRead > 0);
@@ -71,17 +74,17 @@ MP4Stream::ReadAt(int64_t aOffset, void*
bool
MP4Stream::CachedReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
size_t* aBytesRead)
{
// First, check our local cache.
for (size_t i = 0; i < mCache.Length(); ++i) {
if (mCache[i].mOffset == aOffset && mCache[i].mCount >= aCount) {
- memcpy(aBuffer, mCache[i].mBuffer, aCount);
+ memcpy(aBuffer, mCache[i].Buffer(), aCount);
*aBytesRead = aCount;
return true;
}
}
nsresult rv = mResource->ReadFromCache(reinterpret_cast<char*>(aBuffer),
aOffset, aCount);
if (NS_FAILED(rv)) {
--- a/dom/media/fmp4/MP4Stream.h
+++ b/dom/media/fmp4/MP4Stream.h
@@ -6,16 +6,17 @@
#ifndef MP4_STREAM_H_
#define MP4_STREAM_H_
#include "mp4_demuxer/mp4_demuxer.h"
#include "MediaResource.h"
+#include "mozilla/fallible.h"
#include "mozilla/Maybe.h"
#include "mozilla/Monitor.h"
namespace mozilla {
class Monitor;
class MP4Stream : public mp4_demuxer::Stream {
@@ -65,19 +66,33 @@ public:
private:
nsRefPtr<MediaResource> mResource;
Maybe<ReadRecord> mFailedRead;
uint32_t mPinCount;
struct CacheBlock {
CacheBlock(int64_t aOffset, size_t aCount)
- : mOffset(aOffset), mCount(aCount), mBuffer(new uint8_t[aCount]) {}
+ : mOffset(aOffset), mCount(aCount), mBuffer(nullptr) {}
int64_t mOffset;
size_t mCount;
- nsAutoArrayPtr<uint8_t> mBuffer;
+
+ bool Init()
+ {
+ mBuffer = new ((fallible_t())) char[mCount];
+ return !!mBuffer;
+ }
+
+ char* Buffer()
+ {
+ MOZ_ASSERT(mBuffer.get());
+ return mBuffer.get();
+ }
+
+ private:
+ nsAutoArrayPtr<char> mBuffer;
};
nsTArray<CacheBlock> mCache;
};
}
#endif
--- a/dom/media/gmp-plugin/fake.info
+++ b/dom/media/gmp-plugin/fake.info
@@ -1,5 +1,5 @@
Name: fake
Description: Fake GMP Plugin
Version: 1.0
-APIs: encode-video[h264], decode-video[h264], eme-decrypt-v3[fake]
+APIs: encode-video[h264], decode-video[h264], eme-decrypt-v4[fake]
Libraries: dxva2.dll
--- a/dom/media/gmp/gmp-api/gmp-decryption.h
+++ b/dom/media/gmp/gmp-api/gmp-decryption.h
@@ -67,17 +67,18 @@ enum GMPDOMException {
kGMPQuotaExceededError = 22,
kGMPTimeoutError = 23
};
enum GMPSessionMessageType {
kGMPLicenseRequest = 0,
kGMPLicenseRenewal = 1,
kGMPLicenseRelease = 2,
- kGMPMessageInvalid = 3 // Must always be last.
+ kGMPIndividualizationRequest = 3,
+ kGMPMessageInvalid = 4 // Must always be last.
};
// Time in milliseconds, as offset from epoch, 1 Jan 1970.
typedef int64_t GMPTimestamp;
// Capability definitions. The capabilities of the EME GMP are reported
// to Gecko by calling the GMPDecryptorCallback::SetCapabilities()
// callback and specifying the logical OR of the GMP_EME_CAP_* flags below.
@@ -214,17 +215,17 @@ public:
};
enum GMPSessionType {
kGMPTemporySession = 0,
kGMPPersistentSession = 1,
kGMPSessionInvalid = 2 // Must always be last.
};
-#define GMP_API_DECRYPTOR "eme-decrypt-v3"
+#define GMP_API_DECRYPTOR "eme-decrypt-v4"
// API exposed by plugin library to manage decryption sessions.
// When the Host requests this by calling GMPGetAPIFunc().
//
// API name macro: GMP_API_DECRYPTOR
// Host API: GMPDecryptorHost
class GMPDecryptor {
public:
--- a/dom/media/gstreamer/GStreamerReader.h
+++ b/dom/media/gstreamer/GStreamerReader.h
@@ -36,36 +36,36 @@ class AbstractMediaDecoder;
class GStreamerReader : public MediaDecoderReader
{
typedef gfx::IntRect IntRect;
public:
explicit GStreamerReader(AbstractMediaDecoder* aDecoder);
virtual ~GStreamerReader();
- virtual nsresult Init(MediaDecoderReader* aCloneDonor);
- virtual nsresult ResetDecode();
- virtual bool DecodeAudioData();
+ virtual nsresult Init(MediaDecoderReader* aCloneDonor) MOZ_OVERRIDE;
+ virtual nsresult ResetDecode() MOZ_OVERRIDE;
+ virtual bool DecodeAudioData() MOZ_OVERRIDE;
virtual bool DecodeVideoFrame(bool &aKeyframeSkip,
- int64_t aTimeThreshold);
+ int64_t aTimeThreshold) MOZ_OVERRIDE;
virtual nsresult ReadMetadata(MediaInfo* aInfo,
- MetadataTags** aTags);
+ MetadataTags** aTags) MOZ_OVERRIDE;
virtual nsRefPtr<SeekPromise>
Seek(int64_t aTime, int64_t aEndTime) MOZ_OVERRIDE;
- virtual nsresult GetBuffered(dom::TimeRanges* aBuffered);
+ virtual nsresult GetBuffered(dom::TimeRanges* aBuffered) MOZ_OVERRIDE;
virtual void NotifyDataArrived(const char *aBuffer,
uint32_t aLength,
int64_t aOffset) MOZ_OVERRIDE;
- virtual bool HasAudio() {
+ virtual bool HasAudio() MOZ_OVERRIDE {
return mInfo.HasAudio();
}
- virtual bool HasVideo() {
+ virtual bool HasVideo() MOZ_OVERRIDE {
return mInfo.HasVideo();
}
layers::ImageContainer* GetImageContainer() { return mDecoder->GetImageContainer(); }
virtual bool IsMediaSeekable() MOZ_OVERRIDE;
private:
--- a/dom/plugins/ipc/PluginModuleParent.h
+++ b/dom/plugins/ipc/PluginModuleParent.h
@@ -226,17 +226,17 @@ protected:
virtual nsresult BeginUpdateBackground(NPP instance,
const nsIntRect& aRect,
gfxContext** aCtx) MOZ_OVERRIDE;
virtual nsresult EndUpdateBackground(NPP instance,
gfxContext* aCtx,
const nsIntRect& aRect) MOZ_OVERRIDE;
#if defined(XP_UNIX) && !defined(XP_MACOSX) && !defined(MOZ_WIDGET_GONK)
- virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error);
+ virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPPluginFuncs* pFuncs, NPError* error) MOZ_OVERRIDE;
#else
virtual nsresult NP_Initialize(NPNetscapeFuncs* bFuncs, NPError* error) MOZ_OVERRIDE;
#endif
virtual nsresult NP_Shutdown(NPError* error) MOZ_OVERRIDE;
virtual nsresult NP_GetMIMEDescription(const char** mimeDesc) MOZ_OVERRIDE;
virtual nsresult NP_GetValue(void *future, NPPVariable aVariable,
void *aValue, NPError* error) MOZ_OVERRIDE;
--- a/dom/webidl/InstallEvent.webidl
+++ b/dom/webidl/InstallEvent.webidl
@@ -11,11 +11,11 @@
Exposed=ServiceWorker]
interface InstallEvent : ExtendableEvent {
readonly attribute ServiceWorker? activeWorker;
void replace();
};
// Should be in the spec soon to satisfy conventions about events.
// https://github.com/slightlyoff/ServiceWorker/issues/216.
-dictionary InstallEventInit : EventInit {
+dictionary InstallEventInit : ExtendableEventInit {
ServiceWorker? activeWorker = null;
};
--- a/dom/webidl/MediaKeyMessageEvent.webidl
+++ b/dom/webidl/MediaKeyMessageEvent.webidl
@@ -8,17 +8,18 @@
*
* Copyright © 2014 W3C® (MIT, ERCIM, Keio, Beihang), All Rights Reserved.
* W3C liability, trademark and document use rules apply.
*/
enum MediaKeyMessageType {
"license-request",
"license-renewal",
- "license-release"
+ "license-release",
+ "individualization-request"
};
[Pref="media.eme.enabled", Constructor(DOMString type, optional MediaKeyMessageEventInit eventInitDict)]
interface MediaKeyMessageEvent : Event {
readonly attribute MediaKeyMessageType messageType;
[Throws]
readonly attribute ArrayBuffer message;
};
--- a/dom/webidl/SVGClipPathElement.webidl
+++ b/dom/webidl/SVGClipPathElement.webidl
@@ -6,14 +6,16 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGClipPathElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedEnumeration clipPathUnits;
+ [Constant]
readonly attribute SVGAnimatedTransformList transform;
};
SVGClipPathElement implements SVGUnitTypes;
--- a/dom/webidl/SVGComponentTransferFunctionElement.webidl
+++ b/dom/webidl/SVGComponentTransferFunctionElement.webidl
@@ -14,16 +14,23 @@ interface SVGComponentTransferFunctionEl
// Component Transfer Types
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_UNKNOWN = 0;
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_IDENTITY = 1;
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_TABLE = 2;
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_DISCRETE = 3;
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_LINEAR = 4;
const unsigned short SVG_FECOMPONENTTRANSFER_TYPE_GAMMA = 5;
+ [Constant]
readonly attribute SVGAnimatedEnumeration type;
+ [Constant]
readonly attribute SVGAnimatedNumberList tableValues;
+ [Constant]
readonly attribute SVGAnimatedNumber slope;
+ [Constant]
readonly attribute SVGAnimatedNumber intercept;
+ [Constant]
readonly attribute SVGAnimatedNumber amplitude;
+ [Constant]
readonly attribute SVGAnimatedNumber exponent;
+ [Constant]
readonly attribute SVGAnimatedNumber offset;
};
--- a/dom/webidl/SVGDocument.webidl
+++ b/dom/webidl/SVGDocument.webidl
@@ -5,11 +5,11 @@
*
* The origin of this IDL file is:
* dom/interfaces/svg/nsIDOMSVGDocument.idl
*/
interface SVGDocument : Document {
[Throws]
readonly attribute DOMString domain;
- [Throws]
+ [Pure, Throws]
readonly attribute SVGElement? rootElement;
};
--- a/dom/webidl/SVGElement.webidl
+++ b/dom/webidl/SVGElement.webidl
@@ -10,16 +10,17 @@
* liability, trademark and document use rules apply.
*/
interface SVGElement : Element {
attribute DOMString id;
/* [SetterThrows]
attribute DOMString xmlbase; */
+ [Constant]
readonly attribute SVGAnimatedString className;
[PutForwards=cssText, Constant]
readonly attribute CSSStyleDeclaration style;
/*[SetterThrows]
attribute DOMString xmllang;
[SetterThrows]
attribute DOMString xmlspace;*/
--- a/dom/webidl/SVGFEBlendElement.webidl
+++ b/dom/webidl/SVGFEBlendElement.webidl
@@ -25,14 +25,17 @@ interface SVGFEBlendElement : SVGElement
const unsigned short SVG_FEBLEND_MODE_HARD_LIGHT = 9;
const unsigned short SVG_FEBLEND_MODE_SOFT_LIGHT = 10;
const unsigned short SVG_FEBLEND_MODE_DIFFERENCE = 11;
const unsigned short SVG_FEBLEND_MODE_EXCLUSION = 12;
const unsigned short SVG_FEBLEND_MODE_HUE = 13;
const unsigned short SVG_FEBLEND_MODE_SATURATION = 14;
const unsigned short SVG_FEBLEND_MODE_COLOR = 15;
const unsigned short SVG_FEBLEND_MODE_LUMINOSITY = 16;
+ [Constant]
readonly attribute SVGAnimatedString in1;
+ [Constant]
readonly attribute SVGAnimatedString in2;
+ [Constant]
readonly attribute SVGAnimatedEnumeration mode;
};
SVGFEBlendElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEColorMatrixElement.webidl
+++ b/dom/webidl/SVGFEColorMatrixElement.webidl
@@ -14,14 +14,17 @@ interface SVGFEColorMatrixElement : SVGE
// Color Matrix Types
const unsigned short SVG_FECOLORMATRIX_TYPE_UNKNOWN = 0;
const unsigned short SVG_FECOLORMATRIX_TYPE_MATRIX = 1;
const unsigned short SVG_FECOLORMATRIX_TYPE_SATURATE = 2;
const unsigned short SVG_FECOLORMATRIX_TYPE_HUEROTATE = 3;
const unsigned short SVG_FECOLORMATRIX_TYPE_LUMINANCETOALPHA = 4;
+ [Constant]
readonly attribute SVGAnimatedString in1;
+ [Constant]
readonly attribute SVGAnimatedEnumeration type;
+ [Constant]
readonly attribute SVGAnimatedNumberList values;
};
SVGFEColorMatrixElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEComponentTransferElement.webidl
+++ b/dom/webidl/SVGFEComponentTransferElement.webidl
@@ -6,12 +6,13 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFEComponentTransferElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedString in1;
};
SVGFEComponentTransferElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFECompositeElement.webidl
+++ b/dom/webidl/SVGFECompositeElement.webidl
@@ -16,18 +16,25 @@ interface SVGFECompositeElement : SVGEle
const unsigned short SVG_FECOMPOSITE_OPERATOR_UNKNOWN = 0;
const unsigned short SVG_FECOMPOSITE_OPERATOR_OVER = 1;
const unsigned short SVG_FECOMPOSITE_OPERATOR_IN = 2;
const unsigned short SVG_FECOMPOSITE_OPERATOR_OUT = 3;
const unsigned short SVG_FECOMPOSITE_OPERATOR_ATOP = 4;
const unsigned short SVG_FECOMPOSITE_OPERATOR_XOR = 5;
const unsigned short SVG_FECOMPOSITE_OPERATOR_ARITHMETIC = 6;
+ [Constant]
readonly attribute SVGAnimatedString in1;
+ [Constant]
readonly attribute SVGAnimatedString in2;
+ [Constant]
readonly attribute SVGAnimatedEnumeration operator;
+ [Constant]
readonly attribute SVGAnimatedNumber k1;
+ [Constant]
readonly attribute SVGAnimatedNumber k2;
+ [Constant]
readonly attribute SVGAnimatedNumber k3;
+ [Constant]
readonly attribute SVGAnimatedNumber k4;
};
SVGFECompositeElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEConvolveMatrixElement.webidl
+++ b/dom/webidl/SVGFEConvolveMatrixElement.webidl
@@ -13,23 +13,35 @@
interface SVGFEConvolveMatrixElement : SVGElement {
// Edge Mode Values
const unsigned short SVG_EDGEMODE_UNKNOWN = 0;
const unsigned short SVG_EDGEMODE_DUPLICATE = 1;
const unsigned short SVG_EDGEMODE_WRAP = 2;
const unsigned short SVG_EDGEMODE_NONE = 3;
+ [Constant]
readonly attribute SVGAnimatedString in1;
+ [Constant]
readonly attribute SVGAnimatedInteger orderX;
+ [Constant]
readonly attribute SVGAnimatedInteger orderY;
+ [Constant]
readonly attribute SVGAnimatedNumberList kernelMatrix;
+ [Constant]
readonly attribute SVGAnimatedNumber divisor;
+ [Constant]
readonly attribute SVGAnimatedNumber bias;
+ [Constant]
readonly attribute SVGAnimatedInteger targetX;
+ [Constant]
readonly attribute SVGAnimatedInteger targetY;
+ [Constant]
readonly attribute SVGAnimatedEnumeration edgeMode;
+ [Constant]
readonly attribute SVGAnimatedNumber kernelUnitLengthX;
+ [Constant]
readonly attribute SVGAnimatedNumber kernelUnitLengthY;
+ [Constant]
readonly attribute SVGAnimatedBoolean preserveAlpha;
};
SVGFEConvolveMatrixElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEDiffuseLightingElement.webidl
+++ b/dom/webidl/SVGFEDiffuseLightingElement.webidl
@@ -6,16 +6,21 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFEDiffuseLightingElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedString in1;
+ [Constant]
readonly attribute SVGAnimatedNumber surfaceScale;
+ [Constant]
readonly attribute SVGAnimatedNumber diffuseConstant;
+ [Constant]
readonly attribute SVGAnimatedNumber kernelUnitLengthX;
+ [Constant]
readonly attribute SVGAnimatedNumber kernelUnitLengthY;
};
SVGFEDiffuseLightingElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEDisplacementMapElement.webidl
+++ b/dom/webidl/SVGFEDisplacementMapElement.webidl
@@ -14,16 +14,21 @@ interface SVGFEDisplacementMapElement :
// Channel Selectors
const unsigned short SVG_CHANNEL_UNKNOWN = 0;
const unsigned short SVG_CHANNEL_R = 1;
const unsigned short SVG_CHANNEL_G = 2;
const unsigned short SVG_CHANNEL_B = 3;
const unsigned short SVG_CHANNEL_A = 4;
+ [Constant]
readonly attribute SVGAnimatedString in1;
+ [Constant]
readonly attribute SVGAnimatedString in2;
+ [Constant]
readonly attribute SVGAnimatedNumber scale;
+ [Constant]
readonly attribute SVGAnimatedEnumeration xChannelSelector;
+ [Constant]
readonly attribute SVGAnimatedEnumeration yChannelSelector;
};
SVGFEDisplacementMapElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEDistantLightElement.webidl
+++ b/dom/webidl/SVGFEDistantLightElement.webidl
@@ -6,11 +6,13 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFEDistantLightElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedNumber azimuth;
+ [Constant]
readonly attribute SVGAnimatedNumber elevation;
};
--- a/dom/webidl/SVGFEDropShadowElement.webidl
+++ b/dom/webidl/SVGFEDropShadowElement.webidl
@@ -6,18 +6,23 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFEDropShadowElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedString in1;
+ [Constant]
readonly attribute SVGAnimatedNumber dx;
+ [Constant]
readonly attribute SVGAnimatedNumber dy;
+ [Constant]
readonly attribute SVGAnimatedNumber stdDeviationX;
+ [Constant]
readonly attribute SVGAnimatedNumber stdDeviationY;
void setStdDeviation(float stdDeviationX, float stdDeviationY);
};
SVGFEDropShadowElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEGaussianBlurElement.webidl
+++ b/dom/webidl/SVGFEGaussianBlurElement.webidl
@@ -6,16 +6,19 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFEGaussianBlurElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedString in1;
+ [Constant]
readonly attribute SVGAnimatedNumber stdDeviationX;
+ [Constant]
readonly attribute SVGAnimatedNumber stdDeviationY;
void setStdDeviation(float stdDeviationX, float stdDeviationY);
};
SVGFEGaussianBlurElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEImageElement.webidl
+++ b/dom/webidl/SVGFEImageElement.webidl
@@ -6,13 +6,14 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFEImageElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedPreserveAspectRatio preserveAspectRatio;
};
SVGFEImageElement implements SVGFilterPrimitiveStandardAttributes;
SVGFEImageElement implements SVGURIReference;
--- a/dom/webidl/SVGFEMergeNodeElement.webidl
+++ b/dom/webidl/SVGFEMergeNodeElement.webidl
@@ -6,10 +6,11 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFEMergeNodeElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedString in1;
};
--- a/dom/webidl/SVGFEMorphologyElement.webidl
+++ b/dom/webidl/SVGFEMorphologyElement.webidl
@@ -12,15 +12,19 @@
interface SVGFEMorphologyElement : SVGElement {
// Morphology Operators
const unsigned short SVG_MORPHOLOGY_OPERATOR_UNKNOWN = 0;
const unsigned short SVG_MORPHOLOGY_OPERATOR_ERODE = 1;
const unsigned short SVG_MORPHOLOGY_OPERATOR_DILATE = 2;
+ [Constant]
readonly attribute SVGAnimatedString in1;
+ [Constant]
readonly attribute SVGAnimatedEnumeration operator;
+ [Constant]
readonly attribute SVGAnimatedNumber radiusX;
+ [Constant]
readonly attribute SVGAnimatedNumber radiusY;
};
SVGFEMorphologyElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEOffsetElement.webidl
+++ b/dom/webidl/SVGFEOffsetElement.webidl
@@ -6,14 +6,17 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFEOffsetElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedString in1;
+ [Constant]
readonly attribute SVGAnimatedNumber dx;
+ [Constant]
readonly attribute SVGAnimatedNumber dy;
};
SVGFEOffsetElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFEPointLightElement.webidl
+++ b/dom/webidl/SVGFEPointLightElement.webidl
@@ -6,12 +6,15 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFEPointLightElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedNumber x;
+ [Constant]
readonly attribute SVGAnimatedNumber y;
+ [Constant]
readonly attribute SVGAnimatedNumber z;
};
--- a/dom/webidl/SVGFESpecularLightingElement.webidl
+++ b/dom/webidl/SVGFESpecularLightingElement.webidl
@@ -6,17 +6,23 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFESpecularLightingElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedString in1;
+ [Constant]
readonly attribute SVGAnimatedNumber surfaceScale;
+ [Constant]
readonly attribute SVGAnimatedNumber specularConstant;
+ [Constant]
readonly attribute SVGAnimatedNumber specularExponent;
+ [Constant]
readonly attribute SVGAnimatedNumber kernelUnitLengthX;
+ [Constant]
readonly attribute SVGAnimatedNumber kernelUnitLengthY;
};
SVGFESpecularLightingElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFESpotLightElement.webidl
+++ b/dom/webidl/SVGFESpotLightElement.webidl
@@ -6,17 +6,25 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFESpotLightElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedNumber x;
+ [Constant]
readonly attribute SVGAnimatedNumber y;
+ [Constant]
readonly attribute SVGAnimatedNumber z;
+ [Constant]
readonly attribute SVGAnimatedNumber pointsAtX;
+ [Constant]
readonly attribute SVGAnimatedNumber pointsAtY;
+ [Constant]
readonly attribute SVGAnimatedNumber pointsAtZ;
+ [Constant]
readonly attribute SVGAnimatedNumber specularExponent;
+ [Constant]
readonly attribute SVGAnimatedNumber limitingConeAngle;
};
--- a/dom/webidl/SVGFETileElement.webidl
+++ b/dom/webidl/SVGFETileElement.webidl
@@ -6,12 +6,13 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFETileElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedString in1;
};
SVGFETileElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFETurbulenceElement.webidl
+++ b/dom/webidl/SVGFETurbulenceElement.webidl
@@ -17,17 +17,23 @@ interface SVGFETurbulenceElement : SVGEl
const unsigned short SVG_TURBULENCE_TYPE_FRACTALNOISE = 1;
const unsigned short SVG_TURBULENCE_TYPE_TURBULENCE = 2;
// Stitch Options
const unsigned short SVG_STITCHTYPE_UNKNOWN = 0;
const unsigned short SVG_STITCHTYPE_STITCH = 1;
const unsigned short SVG_STITCHTYPE_NOSTITCH = 2;
+ [Constant]
readonly attribute SVGAnimatedNumber baseFrequencyX;
+ [Constant]
readonly attribute SVGAnimatedNumber baseFrequencyY;
+ [Constant]
readonly attribute SVGAnimatedInteger numOctaves;
+ [Constant]
readonly attribute SVGAnimatedNumber seed;
+ [Constant]
readonly attribute SVGAnimatedEnumeration stitchTiles;
+ [Constant]
readonly attribute SVGAnimatedEnumeration type;
};
SVGFETurbulenceElement implements SVGFilterPrimitiveStandardAttributes;
--- a/dom/webidl/SVGFilterElement.webidl
+++ b/dom/webidl/SVGFilterElement.webidl
@@ -6,21 +6,27 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGFilterElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedEnumeration filterUnits;
+ [Constant]
readonly attribute SVGAnimatedEnumeration primitiveUnits;
+ [Constant]
readonly attribute SVGAnimatedLength x;
+ [Constant]
readonly attribute SVGAnimatedLength y;
+ [Constant]
readonly attribute SVGAnimatedLength width;
+ [Constant]
readonly attribute SVGAnimatedLength height;
// ImageData apply(ImageData source);
};
SVGFilterElement implements SVGURIReference;
SVGFilterElement implements SVGUnitTypes;
--- a/dom/webidl/SVGFilterPrimitiveStandardAttributes.webidl
+++ b/dom/webidl/SVGFilterPrimitiveStandardAttributes.webidl
@@ -7,14 +7,19 @@
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
[NoInterfaceObject]
interface SVGFilterPrimitiveStandardAttributes {
+ [Constant]
readonly attribute SVGAnimatedLength x;
+ [Constant]
readonly attribute SVGAnimatedLength y;
+ [Constant]
readonly attribute SVGAnimatedLength width;
+ [Constant]
readonly attribute SVGAnimatedLength height;
+ [Constant]
readonly attribute SVGAnimatedString result;
};
--- a/dom/webidl/SVGGradientElement.webidl
+++ b/dom/webidl/SVGGradientElement.webidl
@@ -13,15 +13,18 @@
interface SVGGradientElement : SVGElement {
// Spread Method Types
const unsigned short SVG_SPREADMETHOD_UNKNOWN = 0;
const unsigned short SVG_SPREADMETHOD_PAD = 1;
const unsigned short SVG_SPREADMETHOD_REFLECT = 2;
const unsigned short SVG_SPREADMETHOD_REPEAT = 3;
+ [Constant]
readonly attribute SVGAnimatedEnumeration gradientUnits;
+ [Constant]
readonly attribute SVGAnimatedTransformList gradientTransform;
+ [Constant]
readonly attribute SVGAnimatedEnumeration spreadMethod;
};
SVGGradientElement implements SVGURIReference;
SVGGradientElement implements SVGUnitTypes;
--- a/dom/webidl/SVGLinearGradientElement.webidl
+++ b/dom/webidl/SVGLinearGradientElement.webidl
@@ -6,13 +6,17 @@
* The origin of this IDL file is
* https://svgwg.org/svg2-draft/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGLinearGradientElement : SVGGradientElement {
+ [Constant]
readonly attribute SVGAnimatedLength x1;
+ [Constant]
readonly attribute SVGAnimatedLength y1;
+ [Constant]
readonly attribute SVGAnimatedLength x2;
+ [Constant]
readonly attribute SVGAnimatedLength y2;
};
--- a/dom/webidl/SVGMarkerElement.webidl
+++ b/dom/webidl/SVGMarkerElement.webidl
@@ -17,22 +17,29 @@ interface SVGMarkerElement : SVGElement
const unsigned short SVG_MARKERUNITS_USERSPACEONUSE = 1;
const unsigned short SVG_MARKERUNITS_STROKEWIDTH = 2;
// Marker Orientation Types
const unsigned short SVG_MARKER_ORIENT_UNKNOWN = 0;
const unsigned short SVG_MARKER_ORIENT_AUTO = 1;
const unsigned short SVG_MARKER_ORIENT_ANGLE = 2;
+ [Constant]
readonly attribute SVGAnimatedLength refX;
+ [Constant]
readonly attribute SVGAnimatedLength refY;
+ [Constant]
readonly attribute SVGAnimatedEnumeration markerUnits;
+ [Constant]
readonly attribute SVGAnimatedLength markerWidth;
+ [Constant]
readonly attribute SVGAnimatedLength markerHeight;
+ [Constant]
readonly attribute SVGAnimatedEnumeration orientType;
+ [Constant]
readonly attribute SVGAnimatedAngle orientAngle;
void setOrientToAuto();
[Throws]
void setOrientToAngle(SVGAngle angle);
};
SVGMarkerElement implements SVGFitToViewBox;
--- a/dom/webidl/SVGMaskElement.webidl
+++ b/dom/webidl/SVGMaskElement.webidl
@@ -11,18 +11,24 @@
*/
interface SVGMaskElement : SVGElement {
// Mask Types
const unsigned short SVG_MASKTYPE_LUMINANCE = 0;
const unsigned short SVG_MASKTYPE_ALPHA = 1;
+ [Constant]
readonly attribute SVGAnimatedEnumeration maskUnits;
+ [Constant]
readonly attribute SVGAnimatedEnumeration maskContentUnits;
+ [Constant]
readonly attribute SVGAnimatedLength x;
+ [Constant]
readonly attribute SVGAnimatedLength y;
+ [Constant]
readonly attribute SVGAnimatedLength width;
+ [Constant]
readonly attribute SVGAnimatedLength height;
};
SVGMaskElement implements SVGUnitTypes;
--- a/dom/webidl/SVGPathElement.webidl
+++ b/dom/webidl/SVGPathElement.webidl
@@ -6,16 +6,17 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGPathElement : SVGGraphicsElement {
+ [Constant]
readonly attribute SVGAnimatedNumber pathLength;
float getTotalLength();
[NewObject, Throws]
SVGPoint getPointAtLength(float distance);
unsigned long getPathSegAtLength(float distance);
[NewObject]
SVGPathSegClosePath createSVGPathSegClosePath();
--- a/dom/webidl/SVGPathSeg.webidl
+++ b/dom/webidl/SVGPathSeg.webidl
@@ -29,17 +29,19 @@ interface SVGPathSeg {
const unsigned short PATHSEG_LINETO_HORIZONTAL_REL = 13;
const unsigned short PATHSEG_LINETO_VERTICAL_ABS = 14;
const unsigned short PATHSEG_LINETO_VERTICAL_REL = 15;
const unsigned short PATHSEG_CURVETO_CUBIC_SMOOTH_ABS = 16;
const unsigned short PATHSEG_CURVETO_CUBIC_SMOOTH_REL = 17;
const unsigned short PATHSEG_CURVETO_QUADRATIC_SMOOTH_ABS = 18;
const unsigned short PATHSEG_CURVETO_QUADRATIC_SMOOTH_REL = 19;
+ [Pure]
readonly attribute unsigned short pathSegType;
+ [Pure]
readonly attribute DOMString pathSegTypeAsLetter;
};
interface SVGPathSegClosePath : SVGPathSeg {
};
interface SVGPathSegMovetoAbs : SVGPathSeg {
[SetterThrows]
--- a/dom/webidl/SVGRadialGradientElement.webidl
+++ b/dom/webidl/SVGRadialGradientElement.webidl
@@ -6,15 +6,20 @@
* The origin of this IDL file is
* https://svgwg.org/svg2-draft/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGRadialGradientElement : SVGGradientElement {
+ [Constant]
readonly attribute SVGAnimatedLength cx;
+ [Constant]
readonly attribute SVGAnimatedLength cy;
+ [Constant]
readonly attribute SVGAnimatedLength r;
+ [Constant]
readonly attribute SVGAnimatedLength fx;
+ [Constant]
readonly attribute SVGAnimatedLength fy;
// readonly attribute SVGAnimatedLength fr;
};
--- a/dom/webidl/SVGSVGElement.webidl
+++ b/dom/webidl/SVGSVGElement.webidl
@@ -9,19 +9,23 @@
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGViewSpec;
interface SVGSVGElement : SVGGraphicsElement {
+ [Constant]
readonly attribute SVGAnimatedLength x;
+ [Constant]
readonly attribute SVGAnimatedLength y;
+ [Constant]
readonly attribute SVGAnimatedLength width;
+ [Constant]
readonly attribute SVGAnimatedLength height;
// readonly attribute SVGRect viewport;
[Constant]
readonly attribute float pixelUnitToMillimeterX;
[Constant]
readonly attribute float pixelUnitToMillimeterY;
[Constant]
readonly attribute float screenPixelToMillimeterX;
--- a/dom/webidl/SVGStopElement.webidl
+++ b/dom/webidl/SVGStopElement.webidl
@@ -6,11 +6,12 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGStopElement : SVGElement {
+ [Constant]
readonly attribute SVGAnimatedNumber offset;
};
--- a/dom/webidl/SVGTextContentElement.webidl
+++ b/dom/webidl/SVGTextContentElement.webidl
@@ -12,17 +12,19 @@
interface SVGTextContentElement : SVGGraphicsElement {
// lengthAdjust Types
const unsigned short LENGTHADJUST_UNKNOWN = 0;
const unsigned short LENGTHADJUST_SPACING = 1;
const unsigned short LENGTHADJUST_SPACINGANDGLYPHS = 2;
+ [Constant]
readonly attribute SVGAnimatedLength textLength;
+ [Constant]
readonly attribute SVGAnimatedEnumeration lengthAdjust;
long getNumberOfChars();
float getComputedTextLength();
[Throws]
float getSubStringLength(unsigned long charnum, unsigned long nchars);
[Throws]
SVGPoint getStartPositionOfChar(unsigned long charnum);
--- a/dom/webidl/SVGTextPathElement.webidl
+++ b/dom/webidl/SVGTextPathElement.webidl
@@ -17,15 +17,18 @@ interface SVGTextPathElement : SVGTextCo
const unsigned short TEXTPATH_METHODTYPE_ALIGN = 1;
const unsigned short TEXTPATH_METHODTYPE_STRETCH = 2;
// textPath Spacing Types
const unsigned short TEXTPATH_SPACINGTYPE_UNKNOWN = 0;
const unsigned short TEXTPATH_SPACINGTYPE_AUTO = 1;
const unsigned short TEXTPATH_SPACINGTYPE_EXACT = 2;
+ [Constant]
readonly attribute SVGAnimatedLength startOffset;
+ [Constant]
readonly attribute SVGAnimatedEnumeration method;
+ [Constant]
readonly attribute SVGAnimatedEnumeration spacing;
};
SVGTextPathElement implements SVGURIReference;
--- a/dom/webidl/SVGTextPositioningElement.webidl
+++ b/dom/webidl/SVGTextPositioningElement.webidl
@@ -6,15 +6,20 @@
* The origin of this IDL file is
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
interface SVGTextPositioningElement : SVGTextContentElement {
+ [Constant]
readonly attribute SVGAnimatedLengthList x;
+ [Constant]
readonly attribute SVGAnimatedLengthList y;
+ [Constant]
readonly attribute SVGAnimatedLengthList dx;
+ [Constant]
readonly attribute SVGAnimatedLengthList dy;
+ [Constant]
readonly attribute SVGAnimatedNumberList rotate;
};
--- a/dom/webidl/SVGURIReference.webidl
+++ b/dom/webidl/SVGURIReference.webidl
@@ -7,11 +7,12 @@
* http://www.w3.org/TR/SVG2/
*
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
* liability, trademark and document use rules apply.
*/
[NoInterfaceObject]
interface SVGURIReference {
+ [Constant]
readonly attribute SVGAnimatedString href;
};
--- a/dom/workers/ServiceWorkerContainer.cpp
+++ b/dom/workers/ServiceWorkerContainer.cpp
@@ -51,17 +51,20 @@ ServiceWorkerContainer::DisconnectFromOw
void
ServiceWorkerContainer::RemoveReadyPromise()
{
nsCOMPtr<nsPIDOMWindow> window = GetOwner();
if (window) {
nsCOMPtr<nsIServiceWorkerManager> swm =
mozilla::services::GetServiceWorkerManager();
- MOZ_ASSERT(swm);
+ if (!swm) {
+ // If the browser is shutting down, we don't need to remove the promise.
+ return;
+ }
swm->RemoveReadyPromise(window);
}
}
JSObject*
ServiceWorkerContainer::WrapObject(JSContext* aCx)
{
--- a/dom/workers/ServiceWorkerEvents.h
+++ b/dom/workers/ServiceWorkerEvents.h
@@ -64,16 +64,21 @@ public:
WaitUntil(Promise& aPromise);
already_AddRefed<Promise>
GetPromise() const
{
nsRefPtr<Promise> p = mPromise;
return p.forget();
}
+
+ virtual ExtendableEvent* AsExtendableEvent() MOZ_OVERRIDE
+ {
+ return this;
+ }
};
class InstallEvent MOZ_FINAL : public ExtendableEvent
{
// FIXME(nsm): Bug 982787 will allow actually populating this.
nsRefPtr<ServiceWorker> mActiveWorker;
bool mActivateImmediately;
@@ -127,12 +132,17 @@ public:
mActivateImmediately = true;
};
bool
ActivateImmediately() const
{
return mActivateImmediately;
}
+
+ InstallEvent* AsInstallEvent() MOZ_OVERRIDE
+ {
+ return this;
+ }
};
END_WORKERS_NAMESPACE
#endif /* mozilla_dom_workers_serviceworkerevents_h__ */
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -101,36 +101,16 @@ ServiceWorkerRegistrationInfo::ServiceWo
ServiceWorkerRegistrationInfo::~ServiceWorkerRegistrationInfo()
{
if (IsControllingDocuments()) {
NS_WARNING("ServiceWorkerRegistrationInfo is still controlling documents. This can be a bug or a leak in ServiceWorker API or in any other API that takes the document alive.");
}
}
-class QueueFireUpdateFoundRunnable MOZ_FINAL : public nsRunnable
-{
- nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
-public:
- explicit QueueFireUpdateFoundRunnable(ServiceWorkerRegistrationInfo* aReg)
- : mRegistration(aReg)
- {
- MOZ_ASSERT(aReg);
- }
-
- NS_IMETHOD
- Run()
- {
- nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
- swm->FireEventOnServiceWorkerRegistrations(mRegistration,
- NS_LITERAL_STRING("updatefound"));
- return NS_OK;
- }
-};
-
//////////////////////////
// ServiceWorkerManager //
//////////////////////////
NS_IMPL_ADDREF(ServiceWorkerManager)
NS_IMPL_RELEASE(ServiceWorkerManager)
NS_INTERFACE_MAP_BEGIN(ServiceWorkerManager)
@@ -158,70 +138,118 @@ ServiceWorkerManager::CleanupServiceWork
void *aUnused)
{
aDomainInfo->mServiceWorkerRegistrationInfos.Clear();
return PL_DHASH_NEXT;
}
class ServiceWorkerRegisterJob;
-class FinishInstallRunnable MOZ_FINAL : public nsRunnable
+class ContinueLifecycleTask : public nsISupports
+{
+ NS_DECL_ISUPPORTS
+
+protected:
+ virtual ~ContinueLifecycleTask()
+ { }
+
+public:
+ virtual void ContinueAfterWorkerEvent(bool aSuccess,
+ bool aActivateImmediately) = 0;
+};
+
+NS_IMPL_ISUPPORTS0(ContinueLifecycleTask);
+
+class ContinueInstallTask MOZ_FINAL : public ContinueLifecycleTask
{
- nsMainThreadPtrHandle<nsISupports> mJob;
+ nsRefPtr<ServiceWorkerRegisterJob> mJob;
+
+public:
+ explicit ContinueInstallTask(ServiceWorkerRegisterJob* aJob)
+ : mJob(aJob)
+ { }
+
+ void ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately) MOZ_OVERRIDE;
+};
+
+class ContinueActivateTask MOZ_FINAL : public ContinueLifecycleTask
+{
+ nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
+
+public:
+ explicit ContinueActivateTask(ServiceWorkerRegistrationInfo* aReg)
+ : mRegistration(aReg)
+ { }
+
+ void
+ ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately /* unused */) MOZ_OVERRIDE
+ {
+ mRegistration->FinishActivate(aSuccess);
+ }
+};
+
+class ContinueLifecycleRunnable MOZ_FINAL : public nsRunnable
+{
+ nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
bool mSuccess;
bool mActivateImmediately;
public:
- explicit FinishInstallRunnable(const nsMainThreadPtrHandle<nsISupports>& aJob,
- bool aSuccess,
- bool aActivateImmediately)
- : mJob(aJob)
+ ContinueLifecycleRunnable(const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask,
+ bool aSuccess,
+ bool aActivateImmediately)
+ : mTask(aTask)
, mSuccess(aSuccess)
, mActivateImmediately(aActivateImmediately)
{
MOZ_ASSERT(!NS_IsMainThread());
}
NS_IMETHOD
- Run() MOZ_OVERRIDE;
+ Run() MOZ_OVERRIDE
+ {
+ AssertIsOnMainThread();
+ mTask->ContinueAfterWorkerEvent(mSuccess, mActivateImmediately);
+ return NS_OK;
+ }
};
/*
* Fires 'install' event on the ServiceWorkerGlobalScope. Modifies busy count
* since it fires the event. This is ok since there can't be nested
* ServiceWorkers, so the parent thread -> worker thread requirement for
* runnables is satisfied.
*/
-class InstallEventRunnable MOZ_FINAL : public WorkerRunnable
+class LifecycleEventWorkerRunnable MOZ_FINAL : public WorkerRunnable
{
- nsMainThreadPtrHandle<nsISupports> mJob;
- nsCString mScope;
+ nsString mEventName;
+ nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
public:
- InstallEventRunnable(WorkerPrivate* aWorkerPrivate,
- const nsMainThreadPtrHandle<nsISupports>& aJob,
- const nsCString& aScope)
- : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
- mJob(aJob),
- mScope(aScope)
+ LifecycleEventWorkerRunnable(WorkerPrivate* aWorkerPrivate,
+ const nsString& aEventName,
+ const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask)
+ : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount)
+ , mEventName(aEventName)
+ , mTask(aTask)
{
AssertIsOnMainThread();
MOZ_ASSERT(aWorkerPrivate);
}
bool
- WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+ WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
{
MOZ_ASSERT(aWorkerPrivate);
- return DispatchInstallEvent(aCx, aWorkerPrivate);
+ return DispatchLifecycleEvent(aCx, aWorkerPrivate);
}
private:
bool
- DispatchInstallEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
+ DispatchLifecycleEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
};
class ServiceWorkerUpdateFinishCallback
{
protected:
virtual ~ServiceWorkerUpdateFinishCallback()
{ }
@@ -351,17 +379,17 @@ public:
return true;
}
};
class ServiceWorkerRegisterJob MOZ_FINAL : public ServiceWorkerJob,
public nsIStreamLoaderObserver
{
- friend class FinishInstallRunnable;
+ friend class ContinueInstallTask;
nsCString mScope;
nsCString mScriptSpec;
nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
nsRefPtr<ServiceWorkerUpdateFinishCallback> mCallback;
~ServiceWorkerRegisterJob()
{ }
@@ -499,18 +527,17 @@ public:
}
// Public so our error handling code can use it.
void
Fail(const ErrorEventInit& aError)
{
MOZ_ASSERT(mCallback);
mCallback->UpdateFailed(aError);
- mCallback = nullptr;
- Done(NS_ERROR_DOM_JS_EXCEPTION);
+ FailCommon(NS_ERROR_DOM_JS_EXCEPTION);
}
// Public so our error handling code can continue with a successful worker.
void
ContinueInstall()
{
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo =
@@ -526,39 +553,38 @@ public:
swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
WhichServiceWorker::INSTALLING_WORKER);
mRegistration->mInstallingWorker = new ServiceWorkerInfo(mRegistration, mRegistration->mScriptSpec);
mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Installing);
Succeed();
- nsRefPtr<QueueFireUpdateFoundRunnable> upr =
- new QueueFireUpdateFoundRunnable(mRegistration);
+ nsCOMPtr<nsIRunnable> upr =
+ NS_NewRunnableMethodWithArg<ServiceWorkerRegistrationInfo*>(swm,
+ &ServiceWorkerManager::FireUpdateFound,
+ mRegistration);
NS_DispatchToMainThread(upr);
- // XXXnsm this leads to double fetches right now, ideally we'll be able to
- // use the persistent cache later.
- nsRefPtr<ServiceWorkerJob> upcasted = this;
- nsMainThreadPtrHandle<nsISupports> handle(
- new nsMainThreadPtrHolder<nsISupports>(upcasted));
+ nsMainThreadPtrHandle<ContinueLifecycleTask> handle(
+ new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueInstallTask(this)));
nsRefPtr<ServiceWorker> serviceWorker;
nsresult rv =
swm->CreateServiceWorker(mRegistration->mInstallingWorker->ScriptSpec(),
mRegistration->mScope,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
ContinueAfterInstallEvent(false /* success */, false /* activate immediately */);
return;
}
- nsRefPtr<InstallEventRunnable> r =
- new InstallEventRunnable(serviceWorker->GetWorkerPrivate(), handle, mRegistration->mScope);
+ nsRefPtr<LifecycleEventWorkerRunnable> r =
+ new LifecycleEventWorkerRunnable(serviceWorker->GetWorkerPrivate(), NS_LITERAL_STRING("install"), handle);
AutoJSAPI jsapi;
jsapi.Init();
r->Dispatch(jsapi.cx());
}
private:
void
@@ -629,26 +655,49 @@ private:
void
Succeed()
{
MOZ_ASSERT(mCallback);
mCallback->UpdateSucceeded(mRegistration);
mCallback = nullptr;
}
+ void
+ FailCommon(nsresult aRv)
+ {
+ mCallback = nullptr;
+ MaybeRemoveRegistration();
+ // Ensures that the job can't do anything useful from this point on.
+ mRegistration = nullptr;
+ Done(aRv);
+ }
+
// This MUST only be called when the job is still performing actions related
// to registration or update. After the spec resolves the update promise, use
// Done() with the failure code instead.
void
- Fail(nsresult rv)
+ Fail(nsresult aRv)
{
MOZ_ASSERT(mCallback);
- mCallback->UpdateFailed(rv);
- mCallback = nullptr;
- Done(rv);
+ mCallback->UpdateFailed(aRv);
+ FailCommon(aRv);
+ }
+
+ void
+ MaybeRemoveRegistration()
+ {
+ MOZ_ASSERT(mRegistration);
+ nsRefPtr<ServiceWorkerInfo> newest = mRegistration->Newest();
+ if (!newest) {
+ nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+ nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo =
+ swm->GetDomainInfo(mRegistration->mScope);
+ MOZ_ASSERT(domainInfo);
+ domainInfo->RemoveRegistration(mRegistration);
+ }
}
void
ContinueAfterInstallEvent(bool aSuccess, bool aActivateImmediately)
{
// By this point the callback should've been notified about success or fail
// and nulled.
MOZ_ASSERT(!mCallback);
@@ -661,16 +710,17 @@ private:
nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
// "If installFailed is true"
if (!aSuccess) {
mRegistration->mInstallingWorker->UpdateState(ServiceWorkerState::Redundant);
mRegistration->mInstallingWorker = nullptr;
swm->InvalidateServiceWorkerRegistrationWorker(mRegistration,
WhichServiceWorker::INSTALLING_WORKER);
+ MaybeRemoveRegistration();
return Done(NS_ERROR_DOM_ABORT_ERR);
}
// "If registration's waiting worker is not null"
if (mRegistration->mWaitingWorker) {
// FIXME(nsm): Terminate
mRegistration->mWaitingWorker->UpdateState(ServiceWorkerState::Redundant);
}
@@ -700,16 +750,22 @@ ContinueUpdateRunnable::Run()
{
AssertIsOnMainThread();
nsRefPtr<ServiceWorkerJob> job = static_cast<ServiceWorkerJob*>(mJob.get());
nsRefPtr<ServiceWorkerRegisterJob> upjob = static_cast<ServiceWorkerRegisterJob*>(job.get());
upjob->ContinueInstall();
return NS_OK;
}
+void
+ContinueInstallTask::ContinueAfterWorkerEvent(bool aSuccess, bool aActivateImmediately)
+{
+ mJob->ContinueAfterInstallEvent(aSuccess, aActivateImmediately);
+}
+
// If we return an error code here, the ServiceWorkerContainer will
// automatically reject the Promise.
NS_IMETHODIMP
ServiceWorkerManager::Register(nsIDOMWindow* aWindow,
const nsAString& aScope,
const nsAString& aScriptURL,
nsISupports** aPromise)
{
@@ -848,82 +904,86 @@ ServiceWorkerManager::Register(nsIDOMWin
nsRefPtr<ServiceWorkerRegisterJob> job =
new ServiceWorkerRegisterJob(queue, cleanedScope, spec, cb);
queue->Append(job);
promise.forget(aPromise);
return NS_OK;
}
-NS_IMETHODIMP
-FinishInstallRunnable::Run()
+/*
+ * Used to handle ExtendableEvent::waitUntil() and proceed with
+ * installation/activation.
+ */
+class LifecycleEventPromiseHandler MOZ_FINAL : public PromiseNativeHandler
{
- AssertIsOnMainThread();
- nsRefPtr<ServiceWorkerJob> job = static_cast<ServiceWorkerJob*>(mJob.get());
- nsRefPtr<ServiceWorkerRegisterJob> upjob = static_cast<ServiceWorkerRegisterJob*>(job.get());
- MOZ_ASSERT(upjob);
- upjob->ContinueAfterInstallEvent(mSuccess, mActivateImmediately);
- return NS_OK;
-}
-
-/*
- * Used to handle InstallEvent::waitUntil() and proceed with installation.
- */
-class FinishInstallHandler MOZ_FINAL : public PromiseNativeHandler
-{
- nsMainThreadPtrHandle<nsISupports> mJob;
+ nsMainThreadPtrHandle<ContinueLifecycleTask> mTask;
bool mActivateImmediately;
virtual
- ~FinishInstallHandler()
+ ~LifecycleEventPromiseHandler()
{ }
public:
- FinishInstallHandler(const nsMainThreadPtrHandle<nsISupports>& aJob,
- bool aActivateImmediately)
- : mJob(aJob)
+ LifecycleEventPromiseHandler(const nsMainThreadPtrHandle<ContinueLifecycleTask>& aTask,
+ bool aActivateImmediately)
+ : mTask(aTask)
, mActivateImmediately(aActivateImmediately)
{
MOZ_ASSERT(!NS_IsMainThread());
}
void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
{
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
- nsRefPtr<FinishInstallRunnable> r = new FinishInstallRunnable(mJob, true, mActivateImmediately);
+ nsRefPtr<ContinueLifecycleRunnable> r =
+ new ContinueLifecycleRunnable(mTask, true /* success */, mActivateImmediately);
NS_DispatchToMainThread(r);
}
void
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
{
- nsRefPtr<FinishInstallRunnable> r = new FinishInstallRunnable(mJob, false, mActivateImmediately);
+ WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
+ MOZ_ASSERT(workerPrivate);
+ workerPrivate->AssertIsOnWorkerThread();
+
+ nsRefPtr<ContinueLifecycleRunnable> r =
+ new ContinueLifecycleRunnable(mTask, false /* success */, mActivateImmediately);
NS_DispatchToMainThread(r);
}
};
bool
-InstallEventRunnable::DispatchInstallEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
+LifecycleEventWorkerRunnable::DispatchLifecycleEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
{
aWorkerPrivate->AssertIsOnWorkerThread();
MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
- InstallEventInit init;
- init.mBubbles = false;
- init.mCancelable = true;
+
+ nsRefPtr<ExtendableEvent> event;
+ nsRefPtr<EventTarget> target = aWorkerPrivate->GlobalScope();
- // FIXME(nsm): Bug 982787 pass previous active worker.
-
- // FIXME(nsm): Set error handler so we can grab handler errors.
- nsRefPtr<EventTarget> target = aWorkerPrivate->GlobalScope();
- nsRefPtr<InstallEvent> event =
- InstallEvent::Constructor(target, NS_LITERAL_STRING("install"), init);
+ if (mEventName.EqualsASCII("install")) {
+ // FIXME(nsm): Bug 982787 pass previous active worker.
+ InstallEventInit init;
+ init.mBubbles = false;
+ init.mCancelable = true;
+ event = InstallEvent::Constructor(target, mEventName, init);
+ } else if (mEventName.EqualsASCII("activate")) {
+ ExtendableEventInit init;
+ init.mBubbles = false;
+ init.mCancelable = true;
+ event = ExtendableEvent::Constructor(target, mEventName, init);
+ } else {
+ MOZ_CRASH("Unexpected lifecycle event");
+ }
event->SetTrusted(true);
nsRefPtr<Promise> waitUntilPromise;
ErrorResult result;
result = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
@@ -947,145 +1007,31 @@ InstallEventRunnable::DispatchInstallEve
waitUntilPromise = Promise::Reject(sgo, aCx,
JS::UndefinedHandleValue, result);
}
if (result.Failed()) {
return false;
}
- nsRefPtr<FinishInstallHandler> handler =
- new FinishInstallHandler(mJob, event->ActivateImmediately());
+ // activateimmediately is only relevant to "install" event.
+ bool activateImmediately = false;
+ InstallEvent* installEvent = event->AsInstallEvent();
+ if (installEvent) {
+ activateImmediately = installEvent->ActivateImmediately();
+ // FIXME(nsm): Set activeWorker to the correct thing.
+ // FIXME(nsm): Install error handler for any listener errors.
+ }
+
+ nsRefPtr<LifecycleEventPromiseHandler> handler =
+ new LifecycleEventPromiseHandler(mTask, activateImmediately);
waitUntilPromise->AppendNativeHandler(handler);
return true;
}
-class FinishActivationRunnable MOZ_FINAL : public nsRunnable
-{
- bool mSuccess;
- nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
-
-public:
- FinishActivationRunnable(bool aSuccess,
- const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
- : mSuccess(aSuccess)
- , mRegistration(aRegistration)
- {
- MOZ_ASSERT(!NS_IsMainThread());
- }
-
- NS_IMETHODIMP
- Run()
- {
- AssertIsOnMainThread();
-
- mRegistration->FinishActivate(mSuccess);
- return NS_OK;
- }
-};
-
-class FinishActivateHandler MOZ_FINAL : public PromiseNativeHandler
-{
- nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
-
-public:
- explicit FinishActivateHandler(const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
- : mRegistration(aRegistration)
- {
- MOZ_ASSERT(!NS_IsMainThread());
- }
-
- virtual
- ~FinishActivateHandler()
- { }
-
- void
- ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
- {
- nsRefPtr<FinishActivationRunnable> r = new FinishActivationRunnable(true /* success */, mRegistration);
- NS_DispatchToMainThread(r);
- }
-
- void
- RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) MOZ_OVERRIDE
- {
- nsRefPtr<FinishActivationRunnable> r = new FinishActivationRunnable(false /* success */, mRegistration);
- NS_DispatchToMainThread(r);
- }
-};
-
-class ActivateEventRunnable : public WorkerRunnable
-{
- nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> mRegistration;
-
-public:
- ActivateEventRunnable(WorkerPrivate* aWorkerPrivate,
- const nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo>& aRegistration)
- : WorkerRunnable(aWorkerPrivate, WorkerThreadModifyBusyCount),
- mRegistration(aRegistration)
- {
- MOZ_ASSERT(aWorkerPrivate);
- }
-
- bool
- WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
- {
- MOZ_ASSERT(aWorkerPrivate);
- return DispatchActivateEvent(aCx, aWorkerPrivate);
- }
-
-private:
- bool
- DispatchActivateEvent(JSContext* aCx, WorkerPrivate* aWorkerPrivate)
- {
- MOZ_ASSERT(aWorkerPrivate->IsServiceWorker());
- nsRefPtr<EventTarget> target = do_QueryObject(aWorkerPrivate->GlobalScope());
-
- // FIXME(nsm): Set activeWorker to the correct thing.
- EventInit init;
- init.mBubbles = false;
- init.mCancelable = true;
- nsRefPtr<ExtendableEvent> event =
- ExtendableEvent::Constructor(target, NS_LITERAL_STRING("activate"), init);
-
- event->SetTrusted(true);
-
- nsRefPtr<Promise> waitUntilPromise;
-
- // FIXME(nsm): Install error handler for any listener errors.
- ErrorResult result;
- result = target->DispatchDOMEvent(nullptr, event, nullptr, nullptr);
- WidgetEvent* internalEvent = event->GetInternalNSEvent();
- if (!result.Failed() && !internalEvent->mFlags.mExceptionHasBeenRisen) {
- waitUntilPromise = event->GetPromise();
- if (!waitUntilPromise) {
- nsCOMPtr<nsIGlobalObject> global =
- do_QueryObject(aWorkerPrivate->GlobalScope());
- waitUntilPromise =
- Promise::Resolve(global,
- aCx, JS::UndefinedHandleValue, result);
- }
- } else {
- nsCOMPtr<nsIGlobalObject> global =
- do_QueryObject(aWorkerPrivate->GlobalScope());
- // Continue with a canceled install.
- waitUntilPromise = Promise::Reject(global, aCx,
- JS::UndefinedHandleValue, result);
- }
-
- if (result.Failed()) {
- return false;
- }
-
- nsRefPtr<FinishActivateHandler> handler = new FinishActivateHandler(mRegistration);
- waitUntilPromise->AppendNativeHandler(handler);
- return true;
- }
-};
-
void
ServiceWorkerRegistrationInfo::TryToActivate()
{
mWaitingToActivate = true;
if (!IsControllingDocuments()) {
Activate();
}
}
@@ -1133,21 +1079,21 @@ ServiceWorkerRegistrationInfo::Activate(
swm->CreateServiceWorker(mActiveWorker->ScriptSpec(),
mScope,
getter_AddRefs(serviceWorker));
if (NS_WARN_IF(NS_FAILED(rv))) {
FinishActivate(false /* success */);
return;
}
- nsMainThreadPtrHandle<ServiceWorkerRegistrationInfo> handle(
- new nsMainThreadPtrHolder<ServiceWorkerRegistrationInfo>(this));
+ nsMainThreadPtrHandle<ContinueLifecycleTask> handle(
+ new nsMainThreadPtrHolder<ContinueLifecycleTask>(new ContinueActivateTask(this)));
- nsRefPtr<ActivateEventRunnable> r =
- new ActivateEventRunnable(serviceWorker->GetWorkerPrivate(), handle);
+ nsRefPtr<LifecycleEventWorkerRunnable> r =
+ new LifecycleEventWorkerRunnable(serviceWorker->GetWorkerPrivate(), NS_LITERAL_STRING("activate"), handle);
AutoJSAPI jsapi;
jsapi.Init();
r->Dispatch(jsapi.cx());
}
/*
* Implements the async aspects of the getRegistrations algorithm.
@@ -1470,95 +1416,127 @@ ServiceWorkerManager::CheckReadyPromise(
new ServiceWorkerRegistration(aWindow, scope);
aPromise->MaybeResolve(swr);
return true;
}
return false;
}
+class ServiceWorkerUnregisterJob MOZ_FINAL : public ServiceWorkerJob
+{
+ nsRefPtr<ServiceWorkerRegistrationInfo> mRegistration;
+ const nsCString mScope;
+ nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
+
+ ~ServiceWorkerUnregisterJob()
+ { }
+
+public:
+ ServiceWorkerUnregisterJob(ServiceWorkerJobQueue* aQueue,
+ const nsACString& aScope,
+ nsIServiceWorkerUnregisterCallback* aCallback)
+ : ServiceWorkerJob(aQueue)
+ , mScope(aScope)
+ , mCallback(aCallback)
+ {
+ AssertIsOnMainThread();
+ }
+
+ void
+ Start() MOZ_OVERRIDE
+ {
+ AssertIsOnMainThread();
+ nsCOMPtr<nsIRunnable> r =
+ NS_NewRunnableMethod(this, &ServiceWorkerUnregisterJob::UnregisterAndDone);
+ MOZ_ALWAYS_TRUE(NS_SUCCEEDED(NS_DispatchToMainThread(r)));
+ }
+
+private:
+ // You probably want UnregisterAndDone().
+ nsresult
+ Unregister()
+ {
+ AssertIsOnMainThread();
+
+ nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+
+ nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo =
+ swm->GetDomainInfo(mScope);
+ MOZ_ASSERT(domainInfo);
+
+ // "Let registration be the result of running [[Get Registration]]
+ // algorithm passing scope as the argument."
+ nsRefPtr<ServiceWorkerRegistrationInfo> registration;
+ if (!domainInfo->mServiceWorkerRegistrationInfos.Get(mScope,
+ getter_AddRefs(registration))) {
+ // "If registration is null, then, resolve promise with false."
+ return mCallback->UnregisterSucceeded(false);
+ }
+
+ MOZ_ASSERT(registration);
+
+ // "Set registration's uninstalling flag."
+ registration->mPendingUninstall = true;
+ // "Resolve promise with true"
+ nsresult rv = mCallback->UnregisterSucceeded(true);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ // "If no service worker client is using registration..."
+ if (!registration->IsControllingDocuments()) {
+ // "If registration's uninstalling flag is set.."
+ if (!registration->mPendingUninstall) {
+ return NS_OK;
+ }
+
+ // "Invoke [[Clear Registration]]..."
+ registration->Clear();
+ domainInfo->RemoveRegistration(registration);
+ }
+
+ return NS_OK;
+ }
+
+ // The unregister job is done irrespective of success or failure of any sort.
+ void
+ UnregisterAndDone()
+ {
+ Done(Unregister());
+ }
+};
+
NS_IMETHODIMP
ServiceWorkerManager::Unregister(nsIServiceWorkerUnregisterCallback* aCallback,
const nsAString& aScope)
{
AssertIsOnMainThread();
MOZ_ASSERT(aCallback);
+// This is not accessible by content, and callers should always ensure scope is
+// a correct URI, so this is wrapped in DEBUG
+#ifdef DEBUG
nsCOMPtr<nsIURI> scopeURI;
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), aScope, nullptr, nullptr);
if (NS_WARN_IF(NS_FAILED(rv))) {
return NS_ERROR_DOM_SECURITY_ERR;
}
-
- /*
- * Implements the async aspects of the unregister algorithm.
- */
- class UnregisterRunnable : public nsRunnable
- {
- nsCOMPtr<nsIServiceWorkerUnregisterCallback> mCallback;
- nsCOMPtr<nsIURI> mScopeURI;
-
- public:
- UnregisterRunnable(nsIServiceWorkerUnregisterCallback* aCallback,
- nsIURI* aScopeURI)
- : mCallback(aCallback), mScopeURI(aScopeURI)
- {
- AssertIsOnMainThread();
- }
-
- NS_IMETHODIMP
- Run()
- {
- AssertIsOnMainThread();
-
- nsRefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-
- nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo =
- swm->GetDomainInfo(mScopeURI);
- MOZ_ASSERT(domainInfo);
-
- nsCString spec;
- nsresult rv = mScopeURI->GetSpecIgnoringRef(spec);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return mCallback->UnregisterFailed();
- }
+#endif
- nsRefPtr<ServiceWorkerRegistrationInfo> registration;
- if (!domainInfo->mServiceWorkerRegistrationInfos.Get(spec,
- getter_AddRefs(registration))) {
- return mCallback->UnregisterSucceeded(false);
- }
-
- MOZ_ASSERT(registration);
-
- registration->mPendingUninstall = true;
- rv = mCallback->UnregisterSucceeded(true);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
+ NS_ConvertUTF16toUTF8 scope(aScope);
+ nsRefPtr<ServiceWorkerManager::ServiceWorkerDomainInfo> domainInfo =
+ GetDomainInfo(scope);
+ ServiceWorkerJobQueue* queue = domainInfo->GetOrCreateJobQueue(scope);
+ MOZ_ASSERT(queue);
- // The "Wait until no document is using registration" can actually be
- // handled by [[HandleDocumentUnload]] in Bug 1041340, so we simply check
- // if the document is currently in use here.
- if (!registration->IsControllingDocuments()) {
- if (!registration->mPendingUninstall) {
- return NS_OK;
- }
-
- registration->Clear();
- domainInfo->RemoveRegistration(registration);
- }
-
- return NS_OK;
- }
- };
-
- nsRefPtr<nsIRunnable> unregisterRunnable =
- new UnregisterRunnable(aCallback, scopeURI);
- return NS_DispatchToCurrentThread(unregisterRunnable);
+ nsRefPtr<ServiceWorkerUnregisterJob> job =
+ new ServiceWorkerUnregisterJob(queue, scope, aCallback);
+ queue->Append(job);
+ return NS_OK;
}
/* static */
already_AddRefed<ServiceWorkerManager>
ServiceWorkerManager::GetInstance()
{
nsCOMPtr<nsIServiceWorkerManager> swm = mozilla::services::GetServiceWorkerManager();
nsRefPtr<ServiceWorkerManager> concrete = do_QueryObject(swm);
@@ -2242,18 +2220,18 @@ ServiceWorkerManager::Update(const nsASt
}
ServiceWorkerJobQueue* queue = domainInfo->GetOrCreateJobQueue(scope);
MOZ_ASSERT(queue);
nsRefPtr<ServiceWorkerUpdateFinishCallback> cb =
new ServiceWorkerUpdateFinishCallback();
- nsRefPtr<ServiceWorkerRegisterJob> job
- = new ServiceWorkerRegisterJob(queue, registration, cb);
+ nsRefPtr<ServiceWorkerRegisterJob> job =
+ new ServiceWorkerRegisterJob(queue, registration, cb);
queue->Append(job);
return NS_OK;
}
namespace {
class MOZ_STACK_CLASS FilterRegistrationData
{
--- a/dom/workers/ServiceWorkerManager.h
+++ b/dom/workers/ServiceWorkerManager.h
@@ -270,17 +270,17 @@ class ServiceWorkerManager MOZ_FINAL : p
{
friend class ActivationRunnable;
friend class ServiceWorkerRegistrationInfo;
friend class ServiceWorkerRegisterJob;
friend class GetReadyPromiseRunnable;
friend class GetRegistrationsRunnable;
friend class GetRegistrationRunnable;
friend class QueueFireUpdateFoundRunnable;
- friend class UnregisterRunnable;
+ friend class ServiceWorkerUnregisterJob;
public:
NS_DECL_ISUPPORTS
NS_DECL_NSISERVICEWORKERMANAGER
NS_DECLARE_STATIC_IID_ACCESSOR(NS_SERVICEWORKERMANAGER_IMPL_IID)
static ServiceWorkerManager* FactoryCreate()
{
@@ -457,16 +457,23 @@ private:
QueueFireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration,
const nsAString& aName);
void
FireEventOnServiceWorkerRegistrations(ServiceWorkerRegistrationInfo* aRegistration,
const nsAString& aName);
void
+ FireUpdateFound(ServiceWorkerRegistrationInfo* aRegistration)
+ {
+ FireEventOnServiceWorkerRegistrations(aRegistration,
+ NS_LITERAL_STRING("updatefound"));
+ }
+
+ void
FireControllerChange(ServiceWorkerRegistrationInfo* aRegistration);
void
StorePendingReadyPromise(nsPIDOMWindow* aWindow, nsIURI* aURI, Promise* aPromise);
void
CheckPendingReadyPromises();
--- a/dom/workers/ServiceWorkerRegistration.cpp
+++ b/dom/workers/ServiceWorkerRegistration.cpp
@@ -159,32 +159,33 @@ ServiceWorkerRegistration::Unregister(Er
nsCOMPtr<nsIDocument> document = GetOwner()->GetExtantDoc();
if (!document) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
nsCOMPtr<nsIURI> scopeURI;
nsCOMPtr<nsIURI> baseURI = document->GetBaseURI();
+ // "If the origin of scope is not client's origin..."
nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), mScope, nullptr, baseURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
nsCOMPtr<nsIPrincipal> documentPrincipal = document->NodePrincipal();
rv = documentPrincipal->CheckMayLoad(scopeURI, true /* report */,
false /* allowIfInheritsPrinciple */);
if (NS_FAILED(rv)) {
aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
return nullptr;
}
nsAutoCString uriSpec;
- aRv = scopeURI->GetSpec(uriSpec);
+ aRv = scopeURI->GetSpecIgnoringRef(uriSpec);
if (NS_WARN_IF(aRv.Failed())) {
return nullptr;
}
nsCOMPtr<nsIServiceWorkerManager> swm =
do_GetService(SERVICEWORKERMANAGER_CONTRACTID, &rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(rv);
--- a/dom/workers/test/serviceworkers/mochitest.ini
+++ b/dom/workers/test/serviceworkers/mochitest.ini
@@ -22,14 +22,13 @@ support-files =
[test_unregister.html]
skip-if = true # bug 1094375
[test_installation_simple.html]
skip-if = true # bug 1094375
[test_get_serviced.html]
[test_install_event.html]
[test_navigator.html]
[test_scopes.html]
-skip-if = true # bug 1124743
[test_controller.html]
[test_workerUpdate.html]
skip-if = true # Enable after Bug 982726 postMessage is landed.
[test_workerUnregister.html]
skip-if = true # Enable after Bug 982726 postMessage is landed.
--- a/dom/workers/test/serviceworkers/test_installation_simple.html
+++ b/dom/workers/test/serviceworkers/test_installation_simple.html
@@ -101,16 +101,20 @@
ok(e.name === "NetworkError", "Should fail with NetworkError");
});
}
function parseError() {
var p = navigator.serviceWorker.register("parse_error_worker.js", { scope: "parse_error/" });
return p.then(function(wr) {
ok(false, "Registration should fail with parse error");
+ return navigator.serviceWorker.getRegistration("parse_error/").then(function(swr) {
+ // See https://github.com/slightlyoff/ServiceWorker/issues/547
+ is(swr, undefined, "A failed registration for a scope with no prior controllers should clear itself");
+ });
}, function(e) {
info("NSM " + e.name);
ok(e instanceof Error, "Registration should fail with parse error");
});
}
// FIXME(nsm): test for parse error when Update step doesn't happen (directly from register).
--- a/dom/workers/test/serviceworkers/test_unregister.html
+++ b/dom/workers/test/serviceworkers/test_unregister.html
@@ -81,35 +81,19 @@
return testPromise.then(function() {
div.removeChild(ifr);
});
}
function runTest() {
simpleRegister()
- .then(function(v) {
- info("simpleRegister() promise resolved");
- })
.then(testControlled)
- .then(function(v) {
- info("testControlled() promise resolved");
- }, function(e) {
- info("testControlled() promise rejected " + e);
- })
.then(unregister)
- .then(function(v) {
- info("unregister() promise resolved");
- })
.then(testUncontrolled)
- .then(function(v) {
- info("testUncontrolled() promise resolved");
- }, function(e) {
- info("testUncontrolled() promise rejected " + e);
- })
.then(function() {
SimpleTest.finish();
}).catch(function(e) {
ok(false, "Some test failed with error " + e);
SimpleTest.finish();
});
}
--- a/gfx/layers/client/TextureClient.h
+++ b/gfx/layers/client/TextureClient.h
@@ -454,17 +454,17 @@ public:
/**
* Set AsyncTransactionTracker of RemoveTextureFromCompositableAsync() transaction.
*/
virtual void SetRemoveFromCompositableTracker(AsyncTransactionTracker* aTracker) {}
/**
* This function waits until the buffer is no longer being used.
*/
- virtual void WaitForBufferOwnership() {}
+ virtual void WaitForBufferOwnership(bool aWaitReleaseFence = true) {}
/**
* Track how much of this texture is wasted.
* For example we might allocate a 256x256 tile but only use 10x10.
*/
void SetWaste(int aWasteArea) {
mWasteTracker.Update(aWasteArea, BytesPerPixel(GetFormat()));
}
--- a/gfx/layers/opengl/GrallocTextureClient.cpp
+++ b/gfx/layers/opengl/GrallocTextureClient.cpp
@@ -83,23 +83,27 @@ GrallocTextureClientOGL::ToSurfaceDescri
void
GrallocTextureClientOGL::SetRemoveFromCompositableTracker(AsyncTransactionTracker* aTracker)
{
mRemoveFromCompositableTracker = aTracker;
}
void
-GrallocTextureClientOGL::WaitForBufferOwnership()
+GrallocTextureClientOGL::WaitForBufferOwnership(bool aWaitReleaseFence)
{
if (mRemoveFromCompositableTracker) {
mRemoveFromCompositableTracker->WaitComplete();
mRemoveFromCompositableTracker = nullptr;
}
+ if (!aWaitReleaseFence) {
+ return;
+ }
+
#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 17
if (mReleaseFenceHandle.IsValid()) {
android::sp<Fence> fence = mReleaseFenceHandle.mFence;
#if ANDROID_VERSION == 17
fence->waitForever(1000, "GrallocTextureClientOGL::Lock");
// 1000 is what Android uses. It is a warning timeout in ms.
// This timeout was removed in ANDROID_VERSION 18.
#else
@@ -117,26 +121,42 @@ GrallocTextureClientOGL::Lock(OpenMode a
if (!IsValid() || !IsAllocated()) {
return false;
}
if (mMappedBuffer) {
return true;
}
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
+ WaitForBufferOwnership(false /* aWaitReleaseFence */);
+#else
WaitForBufferOwnership();
+#endif
uint32_t usage = 0;
if (aMode & OpenMode::OPEN_READ) {
usage |= GRALLOC_USAGE_SW_READ_OFTEN;
}
if (aMode & OpenMode::OPEN_WRITE) {
usage |= GRALLOC_USAGE_SW_WRITE_OFTEN;
}
- int32_t rv = mGraphicBuffer->lock(usage, reinterpret_cast<void**>(&mMappedBuffer));
+#if defined(MOZ_WIDGET_GONK) && ANDROID_VERSION >= 21
+ android::sp<Fence> fence = android::Fence::NO_FENCE;
+ if (mReleaseFenceHandle.IsValid()) {
+ fence = mReleaseFenceHandle.mFence;
+ }
+ mReleaseFenceHandle = FenceHandle();
+ int32_t rv = mGraphicBuffer->lockAsync(usage,
+ reinterpret_cast<void**>(&mMappedBuffer),
+ fence->dup());
+#else
+ int32_t rv = mGraphicBuffer->lock(usage,
+ reinterpret_cast<void**>(&mMappedBuffer));
+#endif
if (rv) {
mMappedBuffer = nullptr;
NS_WARNING("Couldn't lock graphic buffer");
return false;
}
return BufferTextureClient::Lock(aMode);
}
--- a/gfx/layers/opengl/GrallocTextureClient.h
+++ b/gfx/layers/opengl/GrallocTextureClient.h
@@ -53,17 +53,17 @@ public:
virtual bool HasInternalBuffer() const MOZ_OVERRIDE { return false; }
virtual bool IsAllocated() const MOZ_OVERRIDE;
virtual bool ToSurfaceDescriptor(SurfaceDescriptor& aOutDescriptor) MOZ_OVERRIDE;
virtual void SetRemoveFromCompositableTracker(AsyncTransactionTracker* aTracker) MOZ_OVERRIDE;
- virtual void WaitForBufferOwnership() MOZ_OVERRIDE;
+ virtual void WaitForBufferOwnership(bool aWaitReleaseFence = true) MOZ_OVERRIDE;
void InitWith(MaybeMagicGrallocBufferHandle aDesc, gfx::IntSize aSize);
void SetTextureFlags(TextureFlags aFlags) { AddFlags(aFlags); }
gfx::IntSize GetSize() const MOZ_OVERRIDE { return mSize; }
android::sp<android::GraphicBuffer> GetGraphicBuffer()
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.cpp
@@ -22,17 +22,29 @@ MacIOSurfaceTextureHostOGL::MacIOSurface
bool
MacIOSurfaceTextureHostOGL::Lock()
{
if (!mCompositor || !mSurface) {
return false;
}
if (!mTextureSource) {
- mTextureSource = new MacIOSurfaceTextureSourceOGL(mCompositor, mSurface);
+ GLuint textureHandle;
+ gl::GLContext* gl = mCompositor->gl();
+ gl->fGenTextures(1, &textureHandle);
+ gl->fBindTexture(LOCAL_GL_TEXTURE_RECTANGLE_ARB, textureHandle);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
+ gl->fTexParameteri(LOCAL_GL_TEXTURE_RECTANGLE_ARB, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
+ mSurface->CGLTexImageIOSurface2D(gl::GLContextCGL::Cast(gl)->GetCGLContext());
+
+ mTextureSource = new GLTextureSource(mCompositor, textureHandle, LOCAL_GL_TEXTURE_RECTANGLE_ARB,
+ gfx::IntSize(mSurface->GetDevicePixelWidth(),
+ mSurface->GetDevicePixelHeight()),
+ mSurface->HasAlpha() ? gfx::SurfaceFormat::R8G8B8A8:
+ gfx::SurfaceFormat::R8G8B8X8);
}
return true;
}
void
MacIOSurfaceTextureHostOGL::SetCompositor(Compositor* aCompositor)
{
CompositorOGL* glCompositor = static_cast<CompositorOGL*>(aCompositor);
--- a/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h
+++ b/gfx/layers/opengl/MacIOSurfaceTextureHostOGL.h
@@ -89,16 +89,16 @@ public:
virtual gfx::IntSize GetSize() const MOZ_OVERRIDE;
#ifdef MOZ_LAYERS_HAVE_LOG
virtual const char* Name() MOZ_OVERRIDE { return "MacIOSurfaceTextureHostOGL"; }
#endif
protected:
RefPtr<CompositorOGL> mCompositor;
- RefPtr<MacIOSurfaceTextureSourceOGL> mTextureSource;
+ RefPtr<GLTextureSource> mTextureSource;
RefPtr<MacIOSurface> mSurface;
};
}
}
#endif // MOZILLA_GFX_MACIOSURFACETEXTUREHOSTOGL_H
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -200,18 +200,18 @@ public:
{
cairo_font_face_set_user_data(mFontFace,
&sFontEntryKey,
nullptr,
nullptr);
cairo_font_face_destroy(mFontFace);
}
- virtual void ForgetHBFace();
- virtual void ReleaseGrFace(gr_face* aFace);
+ virtual void ForgetHBFace() MOZ_OVERRIDE;
+ virtual void ReleaseGrFace(gr_face* aFace) MOZ_OVERRIDE;
protected:
virtual nsresult
CopyFontTable(uint32_t aTableTag, FallibleTArray<uint8_t>& aBuffer) MOZ_OVERRIDE;
void MaybeReleaseFTFace();
private:
@@ -666,22 +666,22 @@ public:
#ifdef USE_SKIA
virtual mozilla::TemporaryRef<mozilla::gfx::GlyphRenderingOptions>
GetGlyphRenderingOptions(const TextRunDrawParams* aRunParams = nullptr) MOZ_OVERRIDE;
#endif
// return a cloned font resized and offset to simulate sub/superscript glyphs
virtual already_AddRefed<gfxFont>
- GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel);
+ GetSubSuperscriptFont(int32_t aAppUnitsPerDevPixel) MOZ_OVERRIDE;
protected:
virtual already_AddRefed<gfxFont> MakeScaledFont(gfxFontStyle *aFontStyle,
gfxFloat aFontScale);
- virtual already_AddRefed<gfxFont> GetSmallCapsFont();
+ virtual already_AddRefed<gfxFont> GetSmallCapsFont() MOZ_OVERRIDE;
private:
gfxFcFont(cairo_scaled_font_t *aCairoFont, gfxFcFontEntry *aFontEntry,
const gfxFontStyle *aFontStyle);
// key for locating a gfxFcFont corresponding to a cairo_scaled_font
static cairo_user_data_key_t sGfxFontKey;
};
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -164,17 +164,17 @@ public:
/// this gets called to be large - it is meant for critical errors only.
class CrashStatsLogForwarder: public mozilla::gfx::LogForwarder
{
public:
explicit CrashStatsLogForwarder(const char* aKey);
virtual void Log(const std::string& aString) MOZ_OVERRIDE;
- virtual std::vector<std::pair<int32_t,std::string> > StringsVectorCopy();
+ virtual std::vector<std::pair<int32_t,std::string> > StringsVectorCopy() MOZ_OVERRIDE;
void SetCircularBufferSize(uint32_t aCapacity);
private:
// Helpers for the Log()
bool UpdateStringsVector(const std::string& aString);
void UpdateCrashReport();
--- a/js/public/Conversions.h
+++ b/js/public/Conversions.h
@@ -10,20 +10,238 @@
#define js_Conversions_h
#include "mozilla/Casting.h"
#include "mozilla/FloatingPoint.h"
#include "mozilla/TypeTraits.h"
#include <math.h>
+#include "jspubtd.h"
+
+#include "js/RootingAPI.h"
+#include "js/Value.h"
+
+struct JSContext;
+
+namespace js {
+
+/* DO NOT CALL THIS. Use JS::ToBoolean. */
+extern JS_PUBLIC_API(bool)
+ToBooleanSlow(JS::HandleValue v);
+
+/* DO NOT CALL THIS. Use JS::ToNumber. */
+extern JS_PUBLIC_API(bool)
+ToNumberSlow(JSContext *cx, JS::Value v, double *dp);
+
+/* DO NOT CALL THIS. Use JS::ToInt32. */
+extern JS_PUBLIC_API(bool)
+ToInt32Slow(JSContext *cx, JS::HandleValue v, int32_t *out);
+
+/* DO NOT CALL THIS. Use JS::ToUint32. */
+extern JS_PUBLIC_API(bool)
+ToUint32Slow(JSContext *cx, JS::HandleValue v, uint32_t *out);
+
+/* DO NOT CALL THIS. Use JS::ToUint16. */
+extern JS_PUBLIC_API(bool)
+ToUint16Slow(JSContext *cx, JS::HandleValue v, uint16_t *out);
+
+/* DO NOT CALL THIS. Use JS::ToInt64. */
+extern JS_PUBLIC_API(bool)
+ToInt64Slow(JSContext *cx, JS::HandleValue v, int64_t *out);
+
+/* DO NOT CALL THIS. Use JS::ToUint64. */
+extern JS_PUBLIC_API(bool)
+ToUint64Slow(JSContext *cx, JS::HandleValue v, uint64_t *out);
+
+/* DO NOT CALL THIS. Use JS::ToString. */
+extern JS_PUBLIC_API(JSString*)
+ToStringSlow(JSContext *cx, JS::HandleValue v);
+
+/* DO NOT CALL THIS. Use JS::ToObject. */
+extern JS_PUBLIC_API(JSObject*)
+ToObjectSlow(JSContext *cx, JS::HandleValue v, bool reportScanStack);
+
+} // namespace js
+
namespace JS {
namespace detail {
+#ifdef JS_DEBUG
+/*
+ * Assert that we're not doing GC on cx, that we're in a request as
+ * needed, and that the compartments for cx and v are correct.
+ * Also check that GC would be safe at this point.
+ */
+extern JS_PUBLIC_API(void)
+AssertArgumentsAreSane(JSContext *cx, HandleValue v);
+#else
+inline void AssertArgumentsAreSane(JSContext *cx, HandleValue v)
+{}
+#endif /* JS_DEBUG */
+
+} // namespace detail
+
+/*
+ * ES6 draft 20141224, 7.1.1, second algorithm.
+ *
+ * Most users shouldn't call this -- use JS::ToBoolean, ToNumber, or ToString
+ * instead. This will typically only be called from custom convert hooks that
+ * wish to fall back to the ES6 default conversion behavior shared by most
+ * objects in JS, codified as OrdinaryToPrimitive.
+ */
+extern JS_PUBLIC_API(bool)
+OrdinaryToPrimitive(JSContext *cx, HandleObject obj, JSType type, MutableHandleValue vp);
+
+/* ES6 draft 20141224, 7.1.2. */
+MOZ_ALWAYS_INLINE bool
+ToBoolean(HandleValue v)
+{
+ if (v.isBoolean())
+ return v.toBoolean();
+ if (v.isInt32())
+ return v.toInt32() != 0;
+ if (v.isNullOrUndefined())
+ return false;
+ if (v.isDouble()) {
+ double d = v.toDouble();
+ return !mozilla::IsNaN(d) && d != 0;
+ }
+ if (v.isSymbol())
+ return true;
+
+ /* The slow path handles strings and objects. */
+ return js::ToBooleanSlow(v);
+}
+
+/* ES6 draft 20141224, 7.1.3. */
+MOZ_ALWAYS_INLINE bool
+ToNumber(JSContext *cx, HandleValue v, double *out)
+{
+ detail::AssertArgumentsAreSane(cx, v);
+
+ if (v.isNumber()) {
+ *out = v.toNumber();
+ return true;
+ }
+ return js::ToNumberSlow(cx, v, out);
+}
+
+/* ES6 draft 20141224, ToInteger (specialized for doubles). */
+inline double
+ToInteger(double d)
+{
+ if (d == 0)
+ return d;
+
+ if (!mozilla::IsFinite(d)) {
+ if (mozilla::IsNaN(d))
+ return 0;
+ return d;
+ }
+
+ return d < 0 ? ceil(d) : floor(d);
+}
+
+/* ES6 draft 20141224, 7.1.5. */
+MOZ_ALWAYS_INLINE bool
+ToInt32(JSContext *cx, JS::HandleValue v, int32_t *out)
+{
+ detail::AssertArgumentsAreSane(cx, v);
+
+ if (v.isInt32()) {
+ *out = v.toInt32();
+ return true;
+ }
+ return js::ToInt32Slow(cx, v, out);
+}
+
+/* ES6 draft 20141224, 7.1.6. */
+MOZ_ALWAYS_INLINE bool
+ToUint32(JSContext *cx, HandleValue v, uint32_t *out)
+{
+ detail::AssertArgumentsAreSane(cx, v);
+
+ if (v.isInt32()) {
+ *out = uint32_t(v.toInt32());
+ return true;
+ }
+ return js::ToUint32Slow(cx, v, out);
+}
+
+/* ES6 draft 20141224, 7.1.8. */
+MOZ_ALWAYS_INLINE bool
+ToUint16(JSContext *cx, HandleValue v, uint16_t *out)
+{
+ detail::AssertArgumentsAreSane(cx, v);
+
+ if (v.isInt32()) {
+ *out = uint16_t(v.toInt32());
+ return true;
+ }
+ return js::ToUint16Slow(cx, v, out);
+}
+
+/*
+ * Non-standard, with behavior similar to that of ToInt32, except in its
+ * producing an int64_t.
+ */
+MOZ_ALWAYS_INLINE bool
+ToInt64(JSContext *cx, HandleValue v, int64_t *out)
+{
+ detail::AssertArgumentsAreSane(cx, v);
+
+ if (v.isInt32()) {
+ *out = int64_t(v.toInt32());
+ return true;
+ }
+ return js::ToInt64Slow(cx, v, out);
+}
+
+/*
+ * Non-standard, with behavior similar to that of ToUint32, except in its
+ * producing a uint64_t.
+ */
+MOZ_ALWAYS_INLINE bool
+ToUint64(JSContext *cx, HandleValue v, uint64_t *out)
+{
+ detail::AssertArgumentsAreSane(cx, v);
+
+ if (v.isInt32()) {
+ *out = uint64_t(v.toInt32());
+ return true;
+ }
+ return js::ToUint64Slow(cx, v, out);
+}
+
+/* ES6 draft 20141224, 7.1.12. */
+MOZ_ALWAYS_INLINE JSString*
+ToString(JSContext *cx, HandleValue v)
+{
+ detail::AssertArgumentsAreSane(cx, v);
+
+ if (v.isString())
+ return v.toString();
+ return js::ToStringSlow(cx, v);
+}
+
+/* ES6 draft 20141224, 7.1.13. */
+inline JSObject *
+ToObject(JSContext *cx, HandleValue v)
+{
+ detail::AssertArgumentsAreSane(cx, v);
+
+ if (v.isObject())
+ return &v.toObject();
+ return js::ToObjectSlow(cx, v, false);
+}
+
+namespace detail {
+
/*
* Convert a double value to ResultType (an unsigned integral type) using
* ECMAScript-style semantics (that is, in like manner to how ECMAScript's
* ToInt32 converts to int32_t).
*
* If d is infinite or NaN, return 0.
* Otherwise compute d2 = sign(d) * floor(abs(d)), and return the ResultType
* value congruent to d2 mod 2**(bit width of ResultType).
@@ -273,27 +491,11 @@ ToInt64(double d)
/* WEBIDL 4.2.11 */
inline uint64_t
ToUint64(double d)
{
return detail::ToUintWidth<uint64_t>(d);
}
-/* ES5 9.4 ToInteger (specialized for doubles). */
-inline double
-ToInteger(double d)
-{
- if (d == 0)
- return d;
-
- if (!mozilla::IsFinite(d)) {
- if (mozilla::IsNaN(d))
- return 0;
- return d;
- }
-
- return d < 0 ? ceil(d) : floor(d);
-}
-
} // namespace JS
#endif /* js_Conversions_h */
--- a/js/src/builtin/Intl.cpp
+++ b/js/src/builtin/Intl.cpp
@@ -664,19 +664,25 @@ js::intl_Collator(JSContext *cx, unsigne
// intl_Collator is an intrinsic for self-hosted JavaScript, so it cannot
// be used with "new", but it still has to be treated as a constructor.
return Collator(cx, args, true);
}
static void
collator_finalize(FreeOp *fop, JSObject *obj)
{
- UCollator *coll = static_cast<UCollator*>(obj->as<NativeObject>().getReservedSlot(UCOLLATOR_SLOT).toPrivate());
- if (coll)
- ucol_close(coll);
+ // This is-undefined check shouldn't be necessary, but for internal
+ // brokenness in object allocation code. For the moment, hack around it by
+ // explicitly guarding against the possibility of the reserved slot not
+ // containing a private. See bug 949220.
+ const Value &slot = obj->as<NativeObject>().getReservedSlot(UCOLLATOR_SLOT);
+ if (!slot.isUndefined()) {
+ if (UCollator *coll = static_cast<UCollator*>(slot.toPrivate()))
+ ucol_close(coll);
+ }
}
static JSObject *
InitCollatorClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
{
RootedFunction ctor(cx, global->createConstructor(cx, &Collator, cx->names().Collator, 0));
if (!ctor)
return nullptr;
@@ -1151,20 +1157,25 @@ js::intl_NumberFormat(JSContext *cx, uns
// cannot be used with "new", but it still has to be treated as a
// constructor.
return NumberFormat(cx, args, true);
}
static void
numberFormat_finalize(FreeOp *fop, JSObject *obj)
{
- UNumberFormat *nf =
- static_cast<UNumberFormat*>(obj->as<NativeObject>().getReservedSlot(UNUMBER_FORMAT_SLOT).toPrivate());
- if (nf)
- unum_close(nf);
+ // This is-undefined check shouldn't be necessary, but for internal
+ // brokenness in object allocation code. For the moment, hack around it by
+ // explicitly guarding against the possibility of the reserved slot not
+ // containing a private. See bug 949220.
+ const Value &slot = obj->as<NativeObject>().getReservedSlot(UNUMBER_FORMAT_SLOT);
+ if (!slot.isUndefined()) {
+ if (UNumberFormat *nf = static_cast<UNumberFormat*>(slot.toPrivate()))
+ unum_close(nf);
+ }
}
static JSObject *
InitNumberFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
{
RootedFunction ctor(cx, global->createConstructor(cx, &NumberFormat, cx->names().NumberFormat, 0));
if (!ctor)
return nullptr;
@@ -1605,19 +1616,25 @@ js::intl_DateTimeFormat(JSContext *cx, u
// cannot be used with "new", but it still has to be treated as a
// constructor.
return DateTimeFormat(cx, args, true);
}
static void
dateTimeFormat_finalize(FreeOp *fop, JSObject *obj)
{
- UDateFormat *df = static_cast<UDateFormat*>(obj->as<NativeObject>().getReservedSlot(UDATE_FORMAT_SLOT).toPrivate());
- if (df)
- udat_close(df);
+ // This is-undefined check shouldn't be necessary, but for internal
+ // brokenness in object allocation code. For the moment, hack around it by
+ // explicitly guarding against the possibility of the reserved slot not
+ // containing a private. See bug 949220.
+ const Value &slot = obj->as<NativeObject>().getReservedSlot(UDATE_FORMAT_SLOT);
+ if (!slot.isUndefined()) {
+ if (UDateFormat *df = static_cast<UDateFormat*>(slot.toPrivate()))
+ udat_close(df);
+ }
}
static JSObject *
InitDateTimeFormatClass(JSContext *cx, HandleObject Intl, Handle<GlobalObject*> global)
{
RootedFunction ctor(cx, global->createConstructor(cx, &DateTimeFormat, cx->names().DateTimeFormat, 0));
if (!ctor)
return nullptr;
--- a/js/src/frontend/FullParseHandler.h
+++ b/js/src/frontend/FullParseHandler.h
@@ -2,16 +2,17 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 frontend_FullParseHandler_h
#define frontend_FullParseHandler_h
+#include "mozilla/Attributes.h"
#include "mozilla/PodOperations.h"
#include "frontend/ParseNode.h"
#include "frontend/SharedContext.h"
namespace js {
namespace frontend {
@@ -537,18 +538,40 @@ class FullParseHandler
ParseNode *newLexicalScope(ObjectBox *blockBox) {
return new_<LexicalScopeNode>(blockBox, pos());
}
void setLexicalScopeBody(ParseNode *block, ParseNode *body) {
block->pn_expr = body;
}
- bool isOperationWithoutParens(ParseNode *pn, ParseNodeKind kind) {
- return pn->isKind(kind) && !pn->isInParens();
+ ParseNode *newAssignment(ParseNodeKind kind, ParseNode *lhs, ParseNode *rhs,
+ ParseContext<FullParseHandler> *pc, JSOp op)
+ {
+ return newBinaryOrAppend(kind, lhs, rhs, pc, op);
+ }
+
+ bool isUnparenthesizedYieldExpression(ParseNode *node) {
+ return node->isKind(PNK_YIELD) && !node->isInParens();
+ }
+
+ bool isUnparenthesizedCommaExpression(ParseNode *node) {
+ return node->isKind(PNK_COMMA) && !node->isInParens();
+ }
+
+ bool isUnparenthesizedAssignment(Node node) {
+ if (node->isKind(PNK_ASSIGN) && !node->isInParens()) {
+ // PNK_ASSIGN is also (mis)used for things like |var name = expr;|.
+ // But this method is only called on actual expressions, so we can
+ // just assert the node's op is the one used for plain assignment.
+ MOZ_ASSERT(node->isOp(JSOP_NOP));
+ return true;
+ }
+
+ return false;
}
inline bool finishInitializerAssignment(ParseNode *pn, ParseNode *init, JSOp op);
void setBeginPosition(ParseNode *pn, ParseNode *oth) {
setBeginPosition(pn, oth->pn_pos.begin);
}
void setBeginPosition(ParseNode *pn, uint32_t begin) {
@@ -575,43 +598,44 @@ class FullParseHandler
return new_<ListNode>(kind, op, pos());
}
/* New list with one initial child node. kid must be non-null. */
ParseNode *newList(ParseNodeKind kind, ParseNode *kid, JSOp op = JSOP_NOP) {
return new_<ListNode>(kind, op, kid);
}
- void addList(ParseNode *pn, ParseNode *kid) {
- pn->append(kid);
+
+ ParseNode *newCommaExpressionList(ParseNode *kid) {
+ return newList(PNK_COMMA, kid, JSOP_NOP);
}
- bool isUnparenthesizedYield(ParseNode *pn) {
- return pn->isKind(PNK_YIELD) && !pn->isInParens();
+ void addList(ParseNode *list, ParseNode *kid) {
+ list->append(kid);
}
void setOp(ParseNode *pn, JSOp op) {
pn->setOp(op);
}
void setBlockId(ParseNode *pn, unsigned blockid) {
pn->pn_blockid = blockid;
}
void setFlag(ParseNode *pn, unsigned flag) {
pn->pn_dflags |= flag;
}
void setListFlag(ParseNode *pn, unsigned flag) {
MOZ_ASSERT(pn->isArity(PN_LIST));
pn->pn_xflags |= flag;
}
- ParseNode *setInParens(ParseNode *pn) {
+ MOZ_WARN_UNUSED_RESULT ParseNode *parenthesize(ParseNode *pn) {
pn->setInParens(true);
return pn;
}
- ParseNode *setLikelyIIFE(ParseNode *pn) {
- return setInParens(pn);
+ MOZ_WARN_UNUSED_RESULT ParseNode *setLikelyIIFE(ParseNode *pn) {
+ return parenthesize(pn);
}
void setPrologue(ParseNode *pn) {
pn->pn_prologue = true;
}
bool isConstant(ParseNode *pn) {
return pn->isConstant();
}
--- a/js/src/frontend/Parser.cpp
+++ b/js/src/frontend/Parser.cpp
@@ -2879,20 +2879,19 @@ Parser<ParseHandler>::condition()
{
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
Node pn = exprInParens();
if (!pn)
return null();
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
/* Check for (a = b) and warn about possible (a == b) mistype. */
- if (handler.isOperationWithoutParens(pn, PNK_ASSIGN) &&
- !report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
- {
- return null();
+ if (handler.isUnparenthesizedAssignment(pn)) {
+ if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
+ return null();
}
return pn;
}
template <typename ParseHandler>
bool
Parser<ParseHandler>::matchLabel(MutableHandle<PropertyName*> label)
{
@@ -5912,21 +5911,21 @@ Parser<ParseHandler>::expr(InvokedPredic
Node pn = assignExpr(invoked);
if (!pn)
return null();
bool matched;
if (!tokenStream.matchToken(&matched, TOK_COMMA))
return null();
if (matched) {
- Node seq = handler.newList(PNK_COMMA, pn);
+ Node seq = handler.newCommaExpressionList(pn);
if (!seq)
return null();
while (true) {
- if (handler.isUnparenthesizedYield(pn)) {
+ if (handler.isUnparenthesizedYieldExpression(pn)) {
report(ParseError, false, pn, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
return null();
}
pn = assignExpr();
if (!pn)
return null();
handler.addList(seq, pn);
@@ -6291,17 +6290,17 @@ Parser<ParseHandler>::assignExpr(Invoked
AssignmentFlavor flavor = kind == PNK_ASSIGN ? PlainAssignment : CompoundAssignment;
if (!checkAndMarkAsAssignmentLhs(lhs, flavor))
return null();
Node rhs = assignExpr();
if (!rhs)
return null();
- return handler.newBinaryOrAppend(kind, lhs, rhs, pc, op);
+ return handler.newAssignment(kind, lhs, rhs, pc, op);
}
static const char incop_name_str[][10] = {"increment", "decrement"};
template <>
bool
Parser<FullParseHandler>::checkAndMarkAsIncOperand(ParseNode *kid, TokenKind tt, bool preorder)
{
@@ -7275,20 +7274,19 @@ Parser<ParseHandler>::comprehensionIf(Ge
MUST_MATCH_TOKEN(TOK_LP, JSMSG_PAREN_BEFORE_COND);
Node cond = assignExpr();
if (!cond)
return null();
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_AFTER_COND);
/* Check for (a = b) and warn about possible (a == b) mistype. */
- if (handler.isOperationWithoutParens(cond, PNK_ASSIGN) &&
- !report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
- {
- return null();
+ if (handler.isUnparenthesizedAssignment(cond)) {
+ if (!report(ParseExtraWarning, false, null(), JSMSG_EQUAL_AS_ASSIGN))
+ return null();
}
Node then = comprehensionTail(comprehensionKind);
if (!then)
return null();
return handler.newIfStatement(begin, cond, then, null());
}
@@ -7318,17 +7316,17 @@ Parser<ParseHandler>::comprehensionTail(
if (comprehensionKind == NotGenerator)
return handler.newUnary(PNK_ARRAYPUSH, JSOP_ARRAYPUSH, begin, bodyExpr);
MOZ_ASSERT(comprehensionKind == StarGenerator);
Node yieldExpr = newYieldExpression(begin, bodyExpr);
if (!yieldExpr)
return null();
- handler.setInParens(yieldExpr);
+ yieldExpr = handler.parenthesize(yieldExpr);
return handler.newExprStatement(yieldExpr, pos().end);
}
// Parse an ES6 generator or array comprehension, starting at the first 'for'.
// The caller is responsible for matching the ending TOK_RP or TOK_RB.
template <typename ParseHandler>
typename ParseHandler::Node
@@ -7441,17 +7439,17 @@ Parser<ParseHandler>::argumentList(Node
if (!argNode)
return false;
if (spread) {
argNode = handler.newUnary(PNK_SPREAD, JSOP_NOP, begin, argNode);
if (!argNode)
return false;
}
- if (handler.isOperationWithoutParens(argNode, PNK_YIELD)) {
+ if (handler.isUnparenthesizedYieldExpression(argNode)) {
TokenKind tt;
if (!tokenStream.peekToken(&tt))
return false;
if (tt == TOK_COMMA) {
report(ParseError, false, argNode, JSMSG_BAD_GENERATOR_SYNTAX, js_yield_str);
return false;
}
}
@@ -8274,17 +8272,17 @@ Parser<ParseHandler>::parenExprOrGenerat
if (!tokenStream.matchToken(&matched, TOK_FOR))
return null();
if (matched) {
if (pc->lastYieldOffset != startYieldOffset) {
reportWithOffset(ParseError, false, pc->lastYieldOffset,
JSMSG_BAD_GENEXP_BODY, js_yield_str);
return null();
}
- if (handler.isOperationWithoutParens(pn, PNK_COMMA)) {
+ if (handler.isUnparenthesizedCommaExpression(pn)) {
report(ParseError, false, null(),
JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
return null();
}
pn = legacyGeneratorExpr(pn);
if (!pn)
return null();
handler.setBeginPosition(pn, begin);
@@ -8292,22 +8290,21 @@ Parser<ParseHandler>::parenExprOrGenerat
if (!tokenStream.getToken(&tt))
return null();
if (tt != TOK_RP) {
report(ParseError, false, null(),
JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
return null();
}
handler.setEndPosition(pn, pos().end);
- handler.setInParens(pn);
- return pn;
+ return handler.parenthesize(pn);
}
#endif /* JS_HAS_GENERATOR_EXPRS */
- pn = handler.setInParens(pn);
+ pn = handler.parenthesize(pn);
MUST_MATCH_TOKEN(TOK_RP, JSMSG_PAREN_IN_PAREN);
return pn;
}
// Legacy generator comprehensions can sometimes appear without parentheses.
// For example:
@@ -8353,17 +8350,17 @@ Parser<ParseHandler>::exprInParens()
if (!tokenStream.matchToken(&matched, TOK_FOR))
return null();
if (matched) {
if (pc->lastYieldOffset != startYieldOffset) {
reportWithOffset(ParseError, false, pc->lastYieldOffset,
JSMSG_BAD_GENEXP_BODY, js_yield_str);
return null();
}
- if (handler.isOperationWithoutParens(pn, PNK_COMMA)) {
+ if (handler.isUnparenthesizedCommaExpression(pn)) {
report(ParseError, false, null(),
JSMSG_BAD_GENERATOR_SYNTAX, js_generator_str);
return null();
}
pn = legacyGeneratorExpr(pn);
if (!pn)
return null();
handler.setBeginPosition(pn, begin);
--- a/js/src/frontend/SyntaxParseHandler.h
+++ b/js/src/frontend/SyntaxParseHandler.h
@@ -2,16 +2,18 @@
* vim: set ts=8 sts=4 et sw=4 tw=99:
* 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 frontend_SyntaxParseHandler_h
#define frontend_SyntaxParseHandler_h
+#include "mozilla/Attributes.h"
+
#include "frontend/ParseNode.h"
#include "frontend/TokenStream.h"
namespace js {
namespace frontend {
template <typename ParseHandler>
class Parser;
@@ -34,22 +36,71 @@ class SyntaxParseHandler
TokenStream &tokenStream;
public:
enum Node {
NodeFailure = 0,
NodeGeneric,
NodeName,
NodeGetProp,
- NodeString,
NodeStringExprStatement,
- NodeLValue
+ NodeLValue,
+
+ // In rare cases a parenthesized |node| doesn't have the same semantics
+ // as |node|. Each such node has a special Node value, and we use a
+ // different Node value to represent the parenthesized form. See also
+ // isUnparenthesized*(Node), newExprStatement(Node, uint32_t),
+ // parenthesize(Node), and meaningMightChangeIfParenthesized(Node).
+
+ // The directive prologue at the start of a FunctionBody or ScriptBody
+ // is the longest sequence (possibly empty) of string literal
+ // expression statements at the start of a function. Thus we need this
+ // to treat |"use strict";| as a possible Use Strict Directive and
+ // |("use strict");| as a useless statement.
+ NodeUnparenthesizedString,
+
+ // Legacy generator expressions of the form |(expr for (...))| and
+ // array comprehensions of the form |[expr for (...)]|) don't permit
+ // |expr| to be a comma expression. Thus we need this to treat
+ // |(a(), b for (x in []))| as a syntax error and
+ // |((a(), b) for (x in []))| as a generator that calls |a| and then
+ // yields |b| each time it's resumed.
+ NodeUnparenthesizedCommaExpr,
+
+ // Yield expressions currently (but not in ES6 -- a SpiderMonkey bug to
+ // fix) must generally be parenthesized. (See the uses of
+ // isUnparenthesizedYieldExpression in Parser.cpp for the rare
+ // exceptions.) Thus we need this to treat |yield 1, 2;| as a syntax
+ // error and |(yield 1), 2;| as a comma expression that will yield 1,
+ // then evaluate to 2.
+ NodeUnparenthesizedYieldExpr,
+
+ // Assignment expressions in condition contexts could be typos for
+ // equality checks. (Think |if (x = y)| versus |if (x == y)|.) Thus
+ // we need this to treat |if (x = y)| as a possible typo and
+ // |if ((x = y))| as a deliberate assignment within a condition.
+ //
+ // (Technically this isn't needed, as these are *only* extraWarnings
+ // warnings, and parsing with that option disables syntax parsing. But
+ // it seems best to be consistent, and perhaps the syntax parser will
+ // eventually enforce extraWarnings and will require this then.)
+ NodeUnparenthesizedAssignment
};
typedef Definition::Kind DefinitionNode;
+ private:
+ static bool meaningMightChangeIfParenthesized(Node node) {
+ return node == NodeUnparenthesizedString ||
+ node == NodeUnparenthesizedCommaExpr ||
+ node == NodeUnparenthesizedYieldExpr ||
+ node == NodeUnparenthesizedAssignment;
+ }
+
+
+ public:
SyntaxParseHandler(ExclusiveContext *cx, LifoAlloc &alloc,
TokenStream &tokenStream, bool foldConstants,
Parser<SyntaxParseHandler> *syntaxParser, LazyScript *lazyOuterFunction)
: lastAtom(nullptr),
tokenStream(tokenStream)
{}
static Node null() { return NodeFailure; }
@@ -64,24 +115,24 @@ class SyntaxParseHandler
Node newComputedName(Node expr, uint32_t start, uint32_t end) {
return NodeName;
}
DefinitionNode newPlaceholder(JSAtom *atom, uint32_t blockid, const TokenPos &pos) {
return Definition::PLACEHOLDER;
}
- Node newIdentifier(JSAtom *atom, const TokenPos &pos) { return NodeString; }
+ Node newIdentifier(JSAtom *atom, const TokenPos &pos) { return NodeName; }
Node newNumber(double value, DecimalPoint decimalPoint, const TokenPos &pos) { return NodeGeneric; }
Node newBooleanLiteral(bool cond, const TokenPos &pos) { return NodeGeneric; }
Node newStringLiteral(JSAtom *atom, const TokenPos &pos) {
lastAtom = atom;
lastStringPos = pos;
- return NodeString;
+ return NodeUnparenthesizedString;
}
Node newTemplateStringLiteral(JSAtom *atom, const TokenPos &pos) {
return NodeGeneric;
}
Node newCallSiteObject(uint32_t begin, unsigned blockidGen) {
return NodeGeneric;
@@ -130,28 +181,28 @@ class SyntaxParseHandler
bool addElision(Node literal, const TokenPos &pos) { return true; }
bool addSpreadElement(Node literal, uint32_t begin, Node inner) { return true; }
bool addArrayElement(Node literal, Node element) { return true; }
Node newObjectLiteral(uint32_t begin) { return NodeGeneric; }
bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; }
bool addPropertyDefinition(Node literal, Node name, Node expr, bool isShorthand = false) { return true; }
bool addMethodDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }
- Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
+ Node newYieldExpression(uint32_t begin, Node value, Node gen) { return NodeUnparenthesizedYieldExpr; }
Node newYieldStarExpression(uint32_t begin, Node value, Node gen) { return NodeGeneric; }
// Statements
Node newStatementList(unsigned blockid, const TokenPos &pos) { return NodeGeneric; }
void addStatementToList(Node list, Node stmt, ParseContext<SyntaxParseHandler> *pc) {}
bool prependInitialYield(Node stmtList, Node gen) { return true; }
Node newEmptyStatement(const TokenPos &pos) { return NodeGeneric; }
Node newExprStatement(Node expr, uint32_t end) {
- return expr == NodeString ? NodeStringExprStatement : NodeGeneric;
+ return expr == NodeUnparenthesizedString ? NodeStringExprStatement : NodeGeneric;
}
Node newIfStatement(uint32_t begin, Node cond, Node then, Node else_) { return NodeGeneric; }
Node newDoWhileStatement(Node body, Node cond, const TokenPos &pos) { return NodeGeneric; }
Node newWhileStatement(uint32_t begin, Node cond, Node body) { return NodeGeneric; }
Node newSwitchStatement(uint32_t begin, Node discriminant, Node caseList) { return NodeGeneric; }
Node newCaseOrDefault(uint32_t begin, Node expr, Node body) { return NodeGeneric; }
Node newContinueStatement(PropertyName *label, const TokenPos &pos) { return NodeGeneric; }
@@ -190,23 +241,16 @@ class SyntaxParseHandler
Node newForHead(ParseNodeKind kind, Node decls, Node lhs, Node rhs, const TokenPos &pos) {
return NodeGeneric;
}
Node newLexicalScope(ObjectBox *blockbox) { return NodeGeneric; }
void setLexicalScopeBody(Node block, Node body) {}
- bool isOperationWithoutParens(Node pn, ParseNodeKind kind) {
- // It is OK to return false here, callers should only use this method
- // for reporting strict option warnings and parsing code which the
- // syntax parser does not handle.
- return false;
- }
-
bool finishInitializerAssignment(Node pn, Node init, JSOp op) { return true; }
void setBeginPosition(Node pn, Node oth) {}
void setBeginPosition(Node pn, uint32_t begin) {}
void setEndPosition(Node pn, Node oth) {}
void setEndPosition(Node pn, uint32_t end) {}
@@ -217,29 +261,58 @@ class SyntaxParseHandler
}
Node newList(ParseNodeKind kind, JSOp op = JSOP_NOP) {
return NodeGeneric;
}
Node newList(ParseNodeKind kind, Node kid, JSOp op = JSOP_NOP) {
return NodeGeneric;
}
- void addList(Node pn, Node kid) {}
- bool isUnparenthesizedYield(Node pn) { return false; }
+
+ Node newCommaExpressionList(Node kid) {
+ return NodeUnparenthesizedCommaExpr;
+ }
+
+ void addList(Node list, Node kid) {
+ MOZ_ASSERT(list == NodeGeneric || list == NodeUnparenthesizedCommaExpr);
+ }
+
+ Node newAssignment(ParseNodeKind kind, Node lhs, Node rhs,
+ ParseContext<SyntaxParseHandler> *pc, JSOp op)
+ {
+ if (kind == PNK_ASSIGN)
+ return NodeUnparenthesizedAssignment;
+ return newBinaryOrAppend(kind, lhs, rhs, pc, op);
+ }
+
+ bool isUnparenthesizedYieldExpression(Node node) {
+ return node == NodeUnparenthesizedYieldExpr;
+ }
+
+ bool isUnparenthesizedCommaExpression(Node node) {
+ return node == NodeUnparenthesizedCommaExpr;
+ }
+
+ bool isUnparenthesizedAssignment(Node node) {
+ return node == NodeUnparenthesizedAssignment;
+ }
void setOp(Node pn, JSOp op) {}
void setBlockId(Node pn, unsigned blockid) {}
void setFlag(Node pn, unsigned flag) {}
void setListFlag(Node pn, unsigned flag) {}
- Node setInParens(Node pn) {
- // String literals enclosed by parentheses are ignored during
- // strict mode parsing.
- return (pn == NodeString) ? NodeGeneric : pn;
+ MOZ_WARN_UNUSED_RESULT Node parenthesize(Node node) {
+ if (meaningMightChangeIfParenthesized(node))
+ return NodeGeneric;
+
+ // In all other cases, the parenthesized form of |node| is equivalent
+ // to the unparenthesized form: return |node| unchanged.
+ return node;
}
- Node setLikelyIIFE(Node pn) {
+ MOZ_WARN_UNUSED_RESULT Node setLikelyIIFE(Node pn) {
return pn; // Remain in syntax-parse mode.
}
void setPrologue(Node pn) {}
bool isConstant(Node pn) { return false; }
PropertyName *isName(Node pn) {
return (pn == NodeName) ? lastAtom->asPropertyName() : nullptr;
}
--- a/js/src/gc/Verifier.cpp
+++ b/js/src/gc/Verifier.cpp
@@ -214,17 +214,16 @@ gc::GCRuntime::startVerifyPreBarriers()
trc->term = trc->edgeptr + size;
if (!trc->nodemap.init())
goto oom;
/* Create the root node. */
trc->curnode = MakeNode(trc, nullptr, JSGCTraceKind(0));
- /* We want MarkRuntime to save the roots to gcSavedRoots. */
incrementalState = MARK_ROOTS;
/* Make all the roots be edges emanating from the root node. */
markRuntime(trc);
VerifyNode *node;
node = trc->curnode;
if (trc->edgeptr == trc->term)
--- a/js/src/jit-test/tests/basic/hypot-approx.js
+++ b/js/src/jit-test/tests/basic/hypot-approx.js
@@ -16,10 +16,19 @@ assertNear(Math.hypot(1e-3, 1e-3, 1e-3),
assertNear(Math.hypot(1e300, 1e300), 1.4142135623730952e+300);
assertNear(Math.hypot(1e100, 1e200, 1e300), 1e300);
assertNear(Math.hypot(1e3, 1e-3), 1000.0000000005);
assertNear(Math.hypot(1e-300, 1e300), 1e300);
assertNear(Math.hypot(1e3, 1e-3, 1e3, 1e-3), 1414.2135623738021555);
-for (var i = 1, j = 1; i < 2; i += 0.05, j += 0.05)
+assertNear(Math.hypot(1e1, 1e2, 1e3), Math.sqrt(1e2 + 1e4 + 1e6));
+assertNear(Math.hypot(1e1, 1e2, 1e3, 1e4), Math.sqrt(1e2 + 1e4 + 1e6 + 1e8));
+
+for (var i = 1, j = 2; i < 2; i += 0.05, j += 0.05)
assertNear(Math.hypot(i, j), Math.sqrt(i * i + j * j));
+
+for (var i = 1, j = 2, k = 3; i < 2; i += 0.05, j += 0.05, k += 0.05)
+ assertNear(Math.hypot(i, j, k), Math.sqrt(i * i + j * j + k * k));
+
+for (var i = 1, j = 2, k = 3, l = 4; i < 2; i += 0.05, j += 0.05, k += 0.05, l += 0.5)
+ assertNear(Math.hypot(i, j, k, l), Math.sqrt(i * i + j * j + k * k + l * l));
--- a/js/src/jit-test/tests/basic/hypot-exact.js
+++ b/js/src/jit-test/tests/basic/hypot-exact.js
@@ -23,35 +23,52 @@ for (var inf of [Infinity, -Infinity]) {
assertEq(Math.hypot(0, 0, inf), Infinity);
assertEq(Math.hypot(inf, NaN), Infinity);
assertEq(Math.hypot(NaN, inf), Infinity);
assertEq(Math.hypot(inf, NaN, NaN), Infinity);
assertEq(Math.hypot(NaN, inf, NaN), Infinity);
assertEq(Math.hypot(NaN, NaN, inf), Infinity);
+
+ assertEq(Math.hypot(inf, NaN, NaN, NaN), Infinity);
+ assertEq(Math.hypot(NaN, inf, NaN, NaN), Infinity);
+ assertEq(Math.hypot(NaN, NaN, inf, NaN), Infinity);
+ assertEq(Math.hypot(NaN, NaN, NaN, inf), Infinity);
}
// If no argument is +∞ or −∞, and any argument is NaN, the result is NaN.
assertEq(Math.hypot(NaN), NaN);
assertEq(Math.hypot(NaN, 0), NaN);
assertEq(Math.hypot(0, NaN), NaN);
assertEq(Math.hypot(NaN, NaN), NaN);
assertEq(Math.hypot(NaN, 0, 0), NaN);
assertEq(Math.hypot(0, NaN, 0), NaN);
assertEq(Math.hypot(0, 0, NaN), NaN);
+assertEq(Math.hypot(NaN, 0, 0, 0), NaN);
+assertEq(Math.hypot(0, NaN, 0, 0), NaN);
+assertEq(Math.hypot(0, 0, NaN, 0), NaN);
+assertEq(Math.hypot(0, 0, 0, NaN), NaN);
+
assertEq(Math.hypot(Number.MAX_VALUE, Number.MIN_VALUE, NaN), NaN);
+assertEq(Math.hypot(Number.MAX_VALUE, Number.MIN_VALUE, Number.MIN_VALUE, NaN), NaN);
// If all arguments are either +0 or -0, the result is +0.
assertEq(Math.hypot(-0, -0), +0);
assertEq(Math.hypot(+0, -0), +0);
assertEq(Math.hypot(-0, -0, -0), +0);
assertEq(Math.hypot(+0, -0, -0), +0);
assertEq(Math.hypot(-0, +0, -0), +0);
assertEq(Math.hypot(+0, +0, -0), +0);
+assertEq(Math.hypot(-0, -0, -0, -0), +0);
+assertEq(Math.hypot(+0, -0, -0, -0), +0);
+assertEq(Math.hypot(-0, -0, +0, -0), +0);
+assertEq(Math.hypot(+0, +0, +0, -0), +0);
+assertEq(Math.hypot(-0, -0, -0, +0), +0);
+
// The length property of the hypot function is 2.
assertEq(Math.hypot.length, 2);
--- a/js/src/jit-test/tests/ion/dce-with-rinstructions.js
+++ b/js/src/jit-test/tests/ion/dce-with-rinstructions.js
@@ -1057,38 +1057,91 @@ function rtrunc_to_int32_object(i) {
var uceFault_trunc_to_int32_string = eval(uneval(uceFault).replace('uceFault', 'uceFault_trunc_to_int32_string'));
function rtrunc_to_int32_string(i) {
var x = (i + "0") | 0;
if (uceFault_trunc_to_int32_string(i) || uceFault_trunc_to_int32_string(i))
assertEq(x, (i + "0") | 0);
return i;
}
-var uceFault_hypot_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_number'));
-function rhypot_number(i) {
+var uceFault_hypot_number_2args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_number_2args'));
+function rhypot_number_2args(i) {
var x = Math.hypot(i, i + 1);
- if (uceFault_hypot_number(i) || uceFault_hypot_number(i))
+ if (uceFault_hypot_number_2args(i) || uceFault_hypot_number_2args(i))
assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1)));
return i;
}
-var uceFault_hypot_object = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_object'));
-function rhypot_object(i) {
+var uceFault_hypot_number_3args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_number_3args'));
+function rhypot_number_3args(i) {
+ var x = Math.hypot(i, i + 1, i + 2);
+ if (uceFault_hypot_number_3args(i) || uceFault_hypot_number_3args(i))
+ assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2)));
+ return i;
+}
+
+var uceFault_hypot_number_4args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_number_4args'));
+function rhypot_number_4args(i) {
+ var x = Math.hypot(i, i + 1, i + 2, i + 3);
+ if (uceFault_hypot_number_4args(i) || uceFault_hypot_number_4args(i))
+ assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2) + (i + 3) * (i + 3)));
+ return i;
+}
+
+var uceFault_hypot_object_2args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_object_2args'));
+function rhypot_object_2args(i) {
var t0 = i;
var t1 = i + 1;
var o0 = { valueOf: function () { return t0; } };
var o1 = { valueOf: function () { return t1; } };
var x = Math.hypot(o0, o1);
t0 = 1000;
t1 = 2000;
- if (uceFault_hypot_object(i) || uceFault_hypot_object(i) )
+ if (uceFault_hypot_object_2args(i) || uceFault_hypot_object_2args(i) )
assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1)));
return i;
}
+var uceFault_hypot_object_3args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_object_3args'));
+function rhypot_object_3args(i) {
+ var t0 = i;
+ var t1 = i + 1;
+ var t2 = i + 2;
+ var o0 = { valueOf: function () { return t0; } };
+ var o1 = { valueOf: function () { return t1; } };
+ var o2 = { valueOf: function () { return t2; } };
+ var x = Math.hypot(o0, o1, o2);
+ t0 = 1000;
+ t1 = 2000;
+ t2 = 3000;
+ if (uceFault_hypot_object_3args(i) || uceFault_hypot_object_3args(i) )
+ assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2)));
+ return i;
+}
+
+var uceFault_hypot_object_4args = eval(uneval(uceFault).replace('uceFault', 'uceFault_hypot_object_4args'));
+function rhypot_object_4args(i) {
+ var t0 = i;
+ var t1 = i + 1;
+ var t2 = i + 2;
+ var t3 = i + 3;
+ var o0 = { valueOf: function () { return t0; } };
+ var o1 = { valueOf: function () { return t1; } };
+ var o2 = { valueOf: function () { return t2; } };
+ var o3 = { valueOf: function () { return t3; } };
+ var x = Math.hypot(o0, o1, o2, o3);
+ t0 = 1000;
+ t1 = 2000;
+ t2 = 3000;
+ t3 = 4000;
+ if (uceFault_hypot_object_4args(i) || uceFault_hypot_object_4args(i) )
+ assertEq(x, Math.sqrt(i * i + (i + 1) * (i + 1) + (i + 2) * (i + 2) + (i + 3) * (i + 3)));
+ return i;
+}
+
var uceFault_sin_number = eval(uneval(uceFault).replace('uceFault', 'uceFault_sin_number'));
function rsin_number(i) {
var x = Math.sin(i);
if (uceFault_sin_number(i) || uceFault_sin_number(i))
assertEq(x, Math.sin(i));
return i;
}
@@ -1219,18 +1272,22 @@ for (i = 0; i < 100; i++) {
rtypeof(i);
rtodouble_value(i);
rtodouble_number(i);
rtofloat32_number(i);
rtofloat32_object(i);
rtrunc_to_int32_number(i);
rtrunc_to_int32_object(i);
rtrunc_to_int32_string(i);
- rhypot_number(i);
- rhypot_object(i);
+ rhypot_number_2args(i);
+ rhypot_number_3args(i);
+ rhypot_number_4args(i);
+ rhypot_object_2args(i);
+ rhypot_object_3args(i);
+ rhypot_object_4args(i);
rsin_number(i);
rsin_object(i);
rlog_number(i);
rlog_object(i);
}
// Test that we can refer multiple time to the same recover instruction, as well
// as chaining recover instructions.
--- a/js/src/jit/CodeGenerator.cpp
+++ b/js/src/jit/CodeGenerator.cpp
@@ -3903,24 +3903,35 @@ CodeGenerator::visitAtan2D(LAtan2D *lir)
MOZ_ASSERT(ToFloatRegister(lir->output()) == ReturnDoubleReg);
}
void
CodeGenerator::visitHypot(LHypot *lir)
{
Register temp = ToRegister(lir->temp());
- FloatRegister x = ToFloatRegister(lir->x());
- FloatRegister y = ToFloatRegister(lir->y());
-
- masm.setupUnalignedABICall(2, temp);
- masm.passABIArg(x, MoveOp::DOUBLE);
- masm.passABIArg(y, MoveOp::DOUBLE);
- masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaHypot), MoveOp::DOUBLE);
-
+ uint32_t numArgs = lir->numArgs();
+ masm.setupUnalignedABICall(numArgs, temp);
+
+ for (uint32_t i = 0 ; i < numArgs; ++i)
+ masm.passABIArg(ToFloatRegister(lir->getOperand(i)), MoveOp::DOUBLE);
+
+ switch(numArgs) {
+ case 2:
+ masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, ecmaHypot), MoveOp::DOUBLE);
+ break;
+ case 3:
+ masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, hypot3), MoveOp::DOUBLE);
+ break;
+ case 4:
+ masm.callWithABI(JS_FUNC_TO_DATA_PTR(void *, hypot4), MoveOp::DOUBLE);
+ break;
+ default:
+ MOZ_CRASH("Unexpected number of arguments to hypot function.");
+ }
MOZ_ASSERT(ToFloatRegister(lir->output()) == ReturnDoubleReg);
}
void
CodeGenerator::visitNewArray(LNewArray *lir)
{
Register objReg = ToRegister(lir->output());
Register tempReg = ToRegister(lir->temp());
--- a/js/src/jit/IonTypes.h
+++ b/js/src/jit/IonTypes.h
@@ -631,17 +631,24 @@ enum ABIFunctionType
// double f(int, double)
Args_Double_IntDouble = Args_Double_None |
(ArgType_Double << (ArgType_Shift * 1)) |
(ArgType_General << (ArgType_Shift * 2)),
// int f(int, double)
Args_Int_IntDouble = Args_General0 |
(ArgType_Double << (ArgType_Shift * 1)) |
- (ArgType_General << (ArgType_Shift * 2))
+ (ArgType_General << (ArgType_Shift * 2)),
+
+ // double f(double, double, double)
+ Args_Double_DoubleDoubleDouble = Args_Double_DoubleDouble | (ArgType_Double << (ArgType_Shift * 3)),
+
+ // double f(double, double, double, double)
+ Args_Double_DoubleDoubleDoubleDouble = Args_Double_DoubleDoubleDouble | (ArgType_Double << (ArgType_Shift * 4))
+
};
enum class BarrierKind : uint32_t {
// No barrier is needed.
NoBarrier,
// The barrier only has to check the value's type tag is in the TypeSet.
// Specific object types don't have to be checked.
--- a/js/src/jit/LIR-Common.h
+++ b/js/src/jit/LIR-Common.h
@@ -2960,26 +2960,50 @@ class LAtan2D : public LCallInstructionH
return getTemp(0);
}
const LDefinition *output() {
return getDef(0);
}
};
-class LHypot : public LCallInstructionHelper<1, 2, 1>
-{
+class LHypot : public LCallInstructionHelper<1, 4, 1>
+{
+ uint32_t numOperands_;
public:
LIR_HEADER(Hypot)
- LHypot(const LAllocation &x, const LAllocation &y, const LDefinition &temp) {
+ LHypot(const LAllocation &x, const LAllocation &y, const LDefinition &temp)
+ : numOperands_(2)
+ {
setOperand(0, x);
setOperand(1, y);
setTemp(0, temp);
}
+ LHypot(const LAllocation &x, const LAllocation &y, const LAllocation &z, const LDefinition &temp)
+ : numOperands_(3)
+ {
+ setOperand(0, x);
+ setOperand(1, y);
+ setOperand(2, z);
+ setTemp(0, temp);
+ }
+
+ LHypot(const LAllocation &x, const LAllocation &y, const LAllocation &z, const LAllocation &w, const LDefinition &temp)
+ : numOperands_(4)
+ {
+ setOperand(0, x);
+ setOperand(1, y);
+ setOperand(2, z);
+ setOperand(3, w);
+ setTemp(0, temp);
+ }
+
+ uint32_t numArgs() const { return numOperands_; }
+
const LAllocation *x() {
return getOperand(0);
}
const LAllocation *y() {
return getOperand(1);
}
--- a/js/src/jit/Lowering.cpp
+++ b/js/src/jit/Lowering.cpp
@@ -1301,23 +1301,44 @@ LIRGenerator::visitAtan2(MAtan2 *ins)
LAtan2D *lir = new(alloc()) LAtan2D(useRegisterAtStart(y), useRegisterAtStart(x),
tempFixed(CallTempReg0));
defineReturn(lir, ins);
}
void
LIRGenerator::visitHypot(MHypot *ins)
{
- MDefinition *x = ins->x();
- MOZ_ASSERT(x->type() == MIRType_Double);
-
- MDefinition *y = ins->y();
- MOZ_ASSERT(y->type() == MIRType_Double);
-
- LHypot *lir = new(alloc()) LHypot(useRegisterAtStart(x), useRegisterAtStart(y), tempFixed(CallTempReg0));
+ LHypot *lir = nullptr;
+ uint32_t length = ins->numOperands();
+ for (uint32_t i = 0; i < length; ++i)
+ MOZ_ASSERT(ins->getOperand(i)->type() == MIRType_Double);
+
+ switch(length) {
+ case 2:
+ lir = new(alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
+ useRegisterAtStart(ins->getOperand(1)),
+ tempFixed(CallTempReg0));
+ break;
+ case 3:
+ lir = new(alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
+ useRegisterAtStart(ins->getOperand(1)),
+ useRegisterAtStart(ins->getOperand(2)),
+ tempFixed(CallTempReg0));
+ break;
+ case 4:
+ lir = new(alloc()) LHypot(useRegisterAtStart(ins->getOperand(0)),
+ useRegisterAtStart(ins->getOperand(1)),
+ useRegisterAtStart(ins->getOperand(2)),
+ useRegisterAtStart(ins->getOperand(3)),
+ tempFixed(CallTempReg0));
+ break;
+ default:
+ MOZ_CRASH("Unexpected number of arguments to LHypot.");
+ }
+
defineReturn(lir, ins);
}
void
LIRGenerator::visitPow(MPow *ins)
{
MDefinition *input = ins->input();
MOZ_ASSERT(input->type() == MIRType_Double);
--- a/js/src/jit/MCallOptimize.cpp
+++ b/js/src/jit/MCallOptimize.cpp
@@ -997,31 +997,40 @@ IonBuilder::inlineMathAtan2(CallInfo &ca
}
IonBuilder::InliningStatus
IonBuilder::inlineMathHypot(CallInfo &callInfo)
{
if (callInfo.constructing())
return InliningStatus_NotInlined;
- if (callInfo.argc() != 2)
+ uint32_t argc = callInfo.argc();
+ if (argc < 2 || argc > 4)
return InliningStatus_NotInlined;
if (getInlineReturnType() != MIRType_Double)
return InliningStatus_NotInlined;
- MIRType argType0 = callInfo.getArg(0)->type();
- MIRType argType1 = callInfo.getArg(1)->type();
-
- if (!IsNumberType(argType0) || !IsNumberType(argType1))
+ MDefinitionVector vector(alloc());
+ if (!vector.reserve(argc))
return InliningStatus_NotInlined;
+ for (uint32_t i = 0; i < argc; ++i) {
+ MDefinition * arg = callInfo.getArg(i);
+ if (!IsNumberType(arg->type()))
+ return InliningStatus_NotInlined;
+ vector.infallibleAppend(arg);
+ }
+
callInfo.setImplicitlyUsedUnchecked();
-
- MHypot *hypot = MHypot::New(alloc(), callInfo.getArg(0), callInfo.getArg(1));
+ MHypot *hypot = MHypot::New(alloc(), vector);
+
+ if (!hypot)
+ return InliningStatus_NotInlined;
+
current->add(hypot);
current->push(hypot);
return InliningStatus_Inlined;
}
IonBuilder::InliningStatus
IonBuilder::inlineMathPow(CallInfo &callInfo)
{
--- a/js/src/jit/MIR.cpp
+++ b/js/src/jit/MIR.cpp
@@ -2226,16 +2226,28 @@ MMathFunction::trySpecializeFloat32(Temp
ConvertDefinitionToDouble<0>(alloc, input(), this);
return;
}
setResultType(MIRType_Float32);
setPolicyType(MIRType_Float32);
}
+MHypot *MHypot::New(TempAllocator &alloc, const MDefinitionVector & vector)
+{
+ uint32_t length = vector.length();
+ MHypot * hypot = new(alloc) MHypot;
+ if (!hypot->init(alloc, length))
+ return nullptr;
+
+ for (uint32_t i = 0; i < length; ++i)
+ hypot->initOperand(i, vector[i]);
+ return hypot;
+}
+
bool
MAdd::fallible() const
{
// the add is fallible if range analysis does not say that it is finite, AND
// either the truncation analysis shows that there are non-truncated uses.
if (truncateKind() >= IndirectTruncate)
return false;
if (range() && range()->hasInt32Bounds())
--- a/js/src/jit/MIR.h
+++ b/js/src/jit/MIR.h
@@ -4789,18 +4789,18 @@ class MTruncateToInt32
void computeRange(TempAllocator &alloc) MOZ_OVERRIDE;
TruncateKind operandTruncateKind(size_t index) const MOZ_OVERRIDE;
# ifdef DEBUG
bool isConsistentFloat32Use(MUse *use) const MOZ_OVERRIDE {
return true;
}
#endif
- bool writeRecoverData(CompactBufferWriter &writer) const;
- bool canRecoverOnBailout() const {
+ bool writeRecoverData(CompactBufferWriter &writer) const MOZ_OVERRIDE;
+ bool canRecoverOnBailout() const MOZ_OVERRIDE {
return input()->type() < MIRType_Symbol;
}
ALLOW_CLONE(MTruncateToInt32)
};
// Converts any type to a string
class MToString :
@@ -5502,39 +5502,28 @@ class MAtan2
return true;
}
ALLOW_CLONE(MAtan2)
};
// Inline implementation of Math.hypot().
class MHypot
- : public MBinaryInstruction,
- public MixPolicy<DoublePolicy<0>, DoublePolicy<1> >::Data
-{
- MHypot(MDefinition *y, MDefinition *x)
- : MBinaryInstruction(x, y)
+ : public MVariadicInstruction,
+ public AllDoublePolicy::Data
+{
+ MHypot()
{
setResultType(MIRType_Double);
setMovable();
}
public:
INSTRUCTION_HEADER(Hypot)
- static MHypot *New(TempAllocator &alloc, MDefinition *x, MDefinition *y) {
- return new(alloc) MHypot(y, x);
- }
-
- MDefinition *x() const {
- return getOperand(0);
- }
-
- MDefinition *y() const {
- return getOperand(1);
- }
+ static MHypot *New(TempAllocator &alloc, const MDefinitionVector &vector);
bool congruentTo(const MDefinition *ins) const MOZ_OVERRIDE {
return congruentIfOperandsEqual(ins);
}
AliasSet getAliasSet() const MOZ_OVERRIDE {
return AliasSet::None();
}
@@ -5543,17 +5532,23 @@ class MHypot
return true;
}
bool writeRecoverData(CompactBufferWriter &writer) const MOZ_OVERRIDE;
bool canRecoverOnBailout() const MOZ_OVERRIDE {
return true;
}
- ALLOW_CLONE(MHypot)
+ bool canClone() const {
+ return true;
+ }
+
+ MInstruction *clone(TempAllocator &alloc, const MDefinitionVector &inputs) const {
+ return MHypot::New(alloc, inputs);
+ }
};
// Inline implementation of Math.pow().
class MPow
: public MBinaryInstruction,
public PowPolicy::Data
{
MPow(MDefinition *input, MDefinition *power, MIRType powerType)
--- a/js/src/jit/Recover.cpp
+++ b/js/src/jit/Recover.cpp
@@ -869,33 +869,34 @@ RAtan2::recover(JSContext *cx, SnapshotI
return true;
}
bool
MHypot::writeRecoverData(CompactBufferWriter &writer) const
{
MOZ_ASSERT(canRecoverOnBailout());
writer.writeUnsigned(uint32_t(RInstruction::Recover_Hypot));
+ writer.writeUnsigned(uint32_t(numOperands()));
return true;
}
RHypot::RHypot(CompactBufferReader &reader)
+ : numOperands_(reader.readUnsigned())
{ }
bool
RHypot::recover(JSContext *cx, SnapshotIterator &iter) const
{
JS::AutoValueVector vec(cx);
- // currently, only 2 args can be saved in MIR
- if (!vec.reserve(2))
+ if (!vec.reserve(numOperands_))
return false;
- vec.infallibleAppend(iter.read());
- vec.infallibleAppend(iter.read());
+ for (uint32_t i = 0 ; i < numOperands_ ; ++i)
+ vec.infallibleAppend(iter.read());
RootedValue result(cx);
if(!js::math_hypot_handle(cx, vec, &result))
return false;
iter.storeInstructionResult(result);
return true;
--- a/js/src/jit/Recover.h
+++ b/js/src/jit/Recover.h
@@ -472,21 +472,24 @@ class RAtan2 MOZ_FINAL : public RInstruc
return 2;
}
bool recover(JSContext *cx, SnapshotIterator &iter) const;
};
class RHypot MOZ_FINAL : public RInstruction
{
+ private:
+ uint32_t numOperands_;
+
public:
RINSTRUCTION_HEADER_(Hypot)
virtual uint32_t numOperands() const {
- return 2;
+ return numOperands_;
}
bool recover(JSContext *cx, SnapshotIterator &iter) const;
};
class RMathFunction MOZ_FINAL : public RInstruction
{
private:
--- a/js/src/jit/TypePolicy.cpp
+++ b/js/src/jit/TypePolicy.cpp
@@ -90,16 +90,36 @@ ArithPolicy::adjustInputs(TempAllocator
if (!replace->typePolicy()->adjustInputs(alloc, replace))
return false;
}
return true;
}
bool
+AllDoublePolicy::adjustInputs(TempAllocator &alloc, MInstruction *ins)
+{
+ for (size_t i = 0, e = ins->numOperands(); i < e; i++) {
+ MDefinition *in = ins->getOperand(i);
+ if (in->type() == MIRType_Double)
+ continue;
+
+ MInstruction *replace = MToDouble::New(alloc, in);
+
+ ins->block()->insertBefore(ins, replace);
+ ins->replaceOperand(i, replace);
+
+ if (!replace->typePolicy()->adjustInputs(alloc, replace))
+ return false;
+ }
+
+ return true;
+}
+
+bool
ComparePolicy::adjustInputs(TempAllocator &alloc, MInstruction *def)
{
MOZ_ASSERT(def->isCompare());
MCompare *compare = def->toCompare();
// Convert Float32 operands to doubles
for (size_t i = 0; i < 2; i++) {
MDefinition *in = def->getOperand(i);
@@ -1020,16 +1040,17 @@ FilterTypeSetPolicy::adjustInputs(TempAl
_(FilterTypeSetPolicy) \
_(InstanceOfPolicy) \
_(PowPolicy) \
_(StoreTypedArrayElementStaticPolicy) \
_(StoreTypedArrayHolePolicy) \
_(StoreTypedArrayPolicy) \
_(StoreUnboxedObjectOrNullPolicy) \
_(TestPolicy) \
+ _(AllDoublePolicy) \
_(ToDoublePolicy) \
_(ToInt32Policy) \
_(ToStringPolicy) \
_(TypeBarrierPolicy)
#define TEMPLATE_TYPE_POLICY_LIST(_) \
_(BoxExceptPolicy<0, MIRType_String>) \
_(BoxPolicy<0>) \
--- a/js/src/jit/TypePolicy.h
+++ b/js/src/jit/TypePolicy.h
@@ -88,16 +88,23 @@ class BoxInputsPolicy MOZ_FINAL : public
class ArithPolicy MOZ_FINAL : public TypePolicy
{
public:
SPECIALIZATION_DATA_;
virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
};
+class AllDoublePolicy MOZ_FINAL : public TypePolicy
+{
+ public:
+ EMPTY_DATA_;
+ bool adjustInputs(TempAllocator &alloc, MInstruction *def);
+};
+
class BitwisePolicy MOZ_FINAL : public TypePolicy
{
public:
SPECIALIZATION_DATA_;
virtual bool adjustInputs(TempAllocator &alloc, MInstruction *def) MOZ_OVERRIDE;
};
class ComparePolicy MOZ_FINAL : public TypePolicy
--- a/js/src/jit/arm/MacroAssembler-arm.cpp
+++ b/js/src/jit/arm/MacroAssembler-arm.cpp
@@ -4155,16 +4155,18 @@ AssertValidABIFunctionType(uint32_t pass
case Args_Int_Double:
case Args_Float32_Float32:
case Args_Double_Double:
case Args_Double_Int:
case Args_Double_DoubleInt:
case Args_Double_DoubleDouble:
case Args_Double_IntDouble:
case Args_Int_IntDouble:
+ case Args_Double_DoubleDoubleDouble:
+ case Args_Double_DoubleDoubleDoubleDouble:
break;
default:
MOZ_CRASH("Unexpected type");
}
}
#endif
void
--- a/js/src/jit/arm/Simulator-arm.cpp
+++ b/js/src/jit/arm/Simulator-arm.cpp
@@ -1445,16 +1445,25 @@ Simulator::getFpArgs(double *x, double *
} else {
*x = get_double_from_register_pair(0);
*y = get_double_from_register_pair(2);
*z = get_register(2);
}
}
void
+Simulator::getFpFromStack(int32_t *stack, double *x)
+{
+ MOZ_ASSERT(stack && x);
+ char buffer[2 * sizeof(stack[0])];
+ memcpy(buffer, stack, 2 * sizeof(stack[0]));
+ memcpy(x, buffer, 2 * sizeof(stack[0]));
+}
+
+void
Simulator::setCallResultDouble(double result)
{
// The return value is either in r0/r1 or d0.
if (UseHardFpABI()) {
char buffer[2 * sizeof(vfp_registers_[0])];
memcpy(buffer, &result, sizeof(buffer));
// Copy result to d0.
memcpy(vfp_registers_, buffer, sizeof(buffer));
@@ -2073,16 +2082,19 @@ typedef double (*Prototype_Double_Int)(i
typedef int32_t (*Prototype_Int_Double)(double arg0);
typedef float (*Prototype_Float32_Float32)(float arg0);
typedef double (*Prototype_DoubleInt)(double arg0, int32_t arg1);
typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
typedef int32_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
+typedef double (*Prototype_Double_DoubleDoubleDouble)(double arg0, double arg1, double arg2);
+typedef double (*Prototype_Double_DoubleDoubleDoubleDouble)(double arg0, double arg1,
+ double arg2, double arg3);
// Fill the volatile registers with scratch values.
//
// Some of the ABI calls assume that the float registers are not scratched, even
// though the ABI defines them as volatile - a performance optimization. These
// are all calls passing operands in integer registers, so for now the simulator
// does not scratch any float registers for these calls. Should try to narrow it
// further in future.
@@ -2294,16 +2306,41 @@ Simulator::softwareInterrupt(SimInstruct
else
dval0 = get_double_from_register_pair(2);
Prototype_Int_IntDouble target = reinterpret_cast<Prototype_Int_IntDouble>(external);
int32_t result = target(ival, dval0);
scratchVolatileRegisters(/* scratchFloat = true */);
set_register(r0, result);
break;
}
+ case Args_Double_DoubleDoubleDouble: {
+ double dval0, dval1, dval2;
+ int32_t ival;
+ getFpArgs(&dval0, &dval1, &ival);
+ // the last argument is on stack
+ getFpFromStack(stack_pointer, &dval2);
+ Prototype_Double_DoubleDoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDoubleDouble>(external);
+ double dresult = target(dval0, dval1, dval2);
+ scratchVolatileRegisters(/* scratchFloat = true */);
+ setCallResultDouble(dresult);
+ break;
+ }
+ case Args_Double_DoubleDoubleDoubleDouble: {
+ double dval0, dval1, dval2, dval3;
+ int32_t ival;
+ getFpArgs(&dval0, &dval1, &ival);
+ // the two last arguments are on stack
+ getFpFromStack(stack_pointer, &dval2);
+ getFpFromStack(stack_pointer + 2, &dval3);
+ Prototype_Double_DoubleDoubleDoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDoubleDoubleDouble>(external);
+ double dresult = target(dval0, dval1, dval2, dval3);
+ scratchVolatileRegisters(/* scratchFloat = true */);
+ setCallResultDouble(dresult);
+ break;
+ }
default:
MOZ_CRASH("call");
}
if (single_stepping_)
single_step_callback_(single_step_callback_arg_, this, nullptr);
set_register(lr, saved_lr);
--- a/js/src/jit/arm/Simulator-arm.h
+++ b/js/src/jit/arm/Simulator-arm.h
@@ -284,16 +284,17 @@ class Simulator
bool skipCalleeSavedRegsCheck;
// Runtime call support.
static void *RedirectNativeFunction(void *nativeFunction, ABIFunctionType type);
private:
// Handle arguments and return value for runtime FP functions.
void getFpArgs(double *x, double *y, int32_t *z);
+ void getFpFromStack(int32_t *stack, double *x1);
void setCallResultDouble(double result);
void setCallResultFloat(float result);
void setCallResult(int64_t res);
void scratchVolatileRegisters(bool scratchFloat = true);
template<class ReturnType, int register_size>
ReturnType getFromVFPRegister(int reg_index);
--- a/js/src/jit/mips/Assembler-mips.cpp
+++ b/js/src/jit/mips/Assembler-mips.cpp
@@ -964,26 +964,26 @@ BufferOffset
Assembler::as_clz(Register rd, Register rs)
{
return writeInst(InstReg(op_special2, rs, rd, rd, ff_clz).encode());
}
BufferOffset
Assembler::as_ins(Register rt, Register rs, uint16_t pos, uint16_t size)
{
- MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size >= 32);
+ MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32);
Register rd;
rd = Register::FromCode(pos + size - 1);
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ins).encode());
}
BufferOffset
Assembler::as_ext(Register rt, Register rs, uint16_t pos, uint16_t size)
{
- MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size >= 32);
+ MOZ_ASSERT(pos < 32 && size != 0 && size <= 32 && pos + size != 0 && pos + size <= 32);
Register rd;
rd = Register::FromCode(size - 1);
return writeInst(InstReg(op_special3, rs, rt, rd, pos, ff_ext).encode());
}
// FP instructions
BufferOffset
Assembler::as_ld(FloatRegister fd, Register base, int32_t off)
--- a/js/src/jit/mips/MacroAssembler-mips.cpp
+++ b/js/src/jit/mips/MacroAssembler-mips.cpp
@@ -3467,16 +3467,18 @@ AssertValidABIFunctionType(uint32_t pass
case Args_Int_Double:
case Args_Float32_Float32:
case Args_Double_Double:
case Args_Double_Int:
case Args_Double_DoubleInt:
case Args_Double_DoubleDouble:
case Args_Double_IntDouble:
case Args_Int_IntDouble:
+ case Args_Double_DoubleDoubleDouble:
+ case Args_Double_DoubleDoubleDoubleDouble:
break;
default:
MOZ_CRASH("Unexpected type");
}
}
#endif
void
--- a/js/src/jit/mips/MacroAssembler-mips.h
+++ b/js/src/jit/mips/MacroAssembler-mips.h
@@ -227,17 +227,17 @@ class MacroAssemblerMIPS : public Assemb
void ma_b(Register lhs, Register rhs, Label *l, Condition c, JumpKind jumpKind = LongJump);
void ma_b(Register lhs, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump);
void ma_b(Register lhs, ImmPtr imm, Label *l, Condition c, JumpKind jumpKind = LongJump) {
ma_b(lhs, Imm32(uint32_t(imm.value)), l, c, jumpKind);
}
void ma_b(Register lhs, ImmGCPtr imm, Label *l, Condition c, JumpKind jumpKind = LongJump) {
MOZ_ASSERT(lhs != ScratchRegister);
ma_li(ScratchRegister, imm);
- ma_b(lhs, Imm32(uint32_t(imm.value)), l, c, jumpKind);
+ ma_b(lhs, ScratchRegister, l, c, jumpKind);
}
void ma_b(Register lhs, Address addr, Label *l, Condition c, JumpKind jumpKind = LongJump);
void ma_b(Address addr, Imm32 imm, Label *l, Condition c, JumpKind jumpKind = LongJump);
void ma_b(Address addr, Register rhs, Label *l, Condition c, JumpKind jumpKind = LongJump) {
MOZ_ASSERT(rhs != ScratchRegister);
ma_lw(ScratchRegister, addr);
ma_b(ScratchRegister, rhs, l, c, jumpKind);
}
--- a/js/src/jit/mips/Simulator-mips.cpp
+++ b/js/src/jit/mips/Simulator-mips.cpp
@@ -1546,16 +1546,24 @@ void
Simulator::getFpArgs(double *x, double *y, int32_t *z)
{
*x = getFpuRegisterDouble(12);
*y = getFpuRegisterDouble(14);
*z = getRegister(a2);
}
void
+Simulator::getFpFromStack(int32_t *stack, double *x)
+{
+ MOZ_ASSERT(stack);
+ MOZ_ASSERT(x);
+ memcpy(x, stack, sizeof(double));
+}
+
+void
Simulator::setCallResultDouble(double result)
{
setFpuRegisterDouble(f0, result);
}
void
Simulator::setCallResultFloat(float result)
{
@@ -1852,16 +1860,20 @@ typedef double (*Prototype_Double_Int)(i
typedef int32_t (*Prototype_Int_Double)(double arg0);
typedef float (*Prototype_Float32_Float32)(float arg0);
typedef double (*Prototype_DoubleInt)(double arg0, int32_t arg1);
typedef double (*Prototype_Double_IntDouble)(int32_t arg0, double arg1);
typedef double (*Prototype_Double_DoubleDouble)(double arg0, double arg1);
typedef int32_t (*Prototype_Int_IntDouble)(int32_t arg0, double arg1);
+typedef double (*Prototype_Double_DoubleDoubleDouble)(double arg0, double arg1, double arg2);
+typedef double (*Prototype_Double_DoubleDoubleDoubleDouble)(double arg0, double arg1,
+ double arg2, double arg3);
+
// Software interrupt instructions are used by the simulator to call into C++.
void
Simulator::softwareInterrupt(SimInstruction *instr)
{
int32_t func = instr->functionFieldRaw();
uint32_t code = (func == ff_break) ? instr->bits(25, 6) : -1;
// We first check if we met a call_rt_redirected.
@@ -2017,16 +2029,39 @@ Simulator::softwareInterrupt(SimInstruct
case Args_Int_IntDouble: {
int32_t ival = getRegister(a0);
double dval0 = getDoubleFromRegisterPair(a2);
Prototype_Int_IntDouble target = reinterpret_cast<Prototype_Int_IntDouble>(external);
int32_t result = target(ival, dval0);
setRegister(v0, result);
break;
}
+ case Args_Double_DoubleDoubleDouble: {
+ double dval0, dval1, dval2;
+ int32_t ival;
+ getFpArgs(&dval0, &dval1, &ival);
+ // the last argument is on stack
+ getFpFromStack(stack_pointer + 4, &dval2);
+ Prototype_Double_DoubleDoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDoubleDouble>(external);
+ double dresult = target(dval0, dval1, dval2);
+ setCallResultDouble(dresult);
+ break;
+ }
+ case Args_Double_DoubleDoubleDoubleDouble: {
+ double dval0, dval1, dval2, dval3;
+ int32_t ival;
+ getFpArgs(&dval0, &dval1, &ival);
+ // the two last arguments are on stack
+ getFpFromStack(stack_pointer + 4, &dval2);
+ getFpFromStack(stack_pointer + 6, &dval3);
+ Prototype_Double_DoubleDoubleDoubleDouble target = reinterpret_cast<Prototype_Double_DoubleDoubleDoubleDouble>(external);
+ double dresult = target(dval0, dval1, dval2, dval3);
+ setCallResultDouble(dresult);
+ break;
+ }
default:
MOZ_CRASH("call");
}
setRegister(ra, saved_ra);
set_pc(getRegister(ra));
#endif
} else if (func == ff_break && code <= kMaxStopCode) {
--- a/js/src/jit/mips/Simulator-mips.h
+++ b/js/src/jit/mips/Simulator-mips.h
@@ -292,16 +292,17 @@ class Simulator {
};
int16_t exceptions[kNumExceptions];
// Exceptions.
void signalExceptions();
// Handle arguments and return value for runtime FP functions.
void getFpArgs(double *x, double *y, int32_t *z);
+ void getFpFromStack(int32_t *stack, double *x);
void setCallResultDouble(double result);
void setCallResultFloat(float result);
void setCallResult(int64_t res);
void callInternal(uint8_t *entry);
// Architecture state.
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -447,28 +447,16 @@ JS_ValueToSource(JSContext *cx, HandleVa
}
JS_PUBLIC_API(bool)
JS_DoubleIsInt32(double d, int32_t *ip)
{
return mozilla::NumberIsInt32(d, ip);
}
-JS_PUBLIC_API(int32_t)
-JS_DoubleToInt32(double d)
-{
- return ToInt32(d);
-}
-
-JS_PUBLIC_API(uint32_t)
-JS_DoubleToUint32(double d)
-{
- return ToUint32(d);
-}
-
JS_PUBLIC_API(JSType)
JS_TypeOfValue(JSContext *cx, HandleValue value)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, value);
return TypeOfValue(value);
}
@@ -5937,25 +5925,25 @@ AutoGCRooter::AutoGCRooter(ContextFriend
: down(cx->autoGCRooters),
tag_(tag),
stackTop(&cx->autoGCRooters)
{
MOZ_ASSERT(this != *stackTop);
*stackTop = this;
}
-#ifdef DEBUG
+#ifdef JS_DEBUG
JS_PUBLIC_API(void)
-JS::AssertArgumentsAreSane(JSContext *cx, HandleValue value)
+JS::detail::AssertArgumentsAreSane(JSContext *cx, HandleValue value)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
assertSameCompartment(cx, value);
}
-#endif /* DEBUG */
+#endif /* JS_DEBUG */
JS_PUBLIC_API(void *)
JS_EncodeScript(JSContext *cx, HandleScript scriptArg, uint32_t *lengthp)
{
XDREncoder encoder(cx);
RootedScript script(cx, scriptArg);
if (!encoder.codeScript(&script))
return nullptr;
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -56,30 +56,16 @@ class JS_PUBLIC_API(AutoCheckRequestDept
#else
# define CHECK_REQUEST(cx) \
((void) 0)
#endif /* JS_DEBUG */
-#ifdef JS_DEBUG
-/*
- * Assert that we're not doing GC on cx, that we're in a request as
- * needed, and that the compartments for cx and v are correct.
- * Also check that GC would be safe at this point.
- */
-JS_PUBLIC_API(void)
-AssertArgumentsAreSane(JSContext *cx, JS::HandleValue v);
-#else
-inline void AssertArgumentsAreSane(JSContext *cx, JS::HandleValue v) {
- /* Do nothing */
-}
-#endif /* JS_DEBUG */
-
/* AutoValueArray roots an internal fixed-size array of Values. */
template <size_t N>
class AutoValueArray : public AutoGCRooter
{
const size_t length_;
Value elements_[N];
public:
@@ -1105,207 +1091,19 @@ extern JS_PUBLIC_API(JSFunction *)
JS_ValueToFunction(JSContext *cx, JS::HandleValue v);
extern JS_PUBLIC_API(JSFunction *)
JS_ValueToConstructor(JSContext *cx, JS::HandleValue v);
extern JS_PUBLIC_API(JSString *)
JS_ValueToSource(JSContext *cx, JS::Handle<JS::Value> v);
-namespace js {
-/*
- * DO NOT CALL THIS. Use JS::ToNumber
- */
-extern JS_PUBLIC_API(bool)
-ToNumberSlow(JSContext *cx, JS::Value v, double *dp);
-
-/*
- * DO NOT CALL THIS. Use JS::ToBoolean
- */
-extern JS_PUBLIC_API(bool)
-ToBooleanSlow(JS::HandleValue v);
-
-/*
- * DO NOT CALL THIS. Use JS::ToString
- */
-extern JS_PUBLIC_API(JSString*)
-ToStringSlow(JSContext *cx, JS::HandleValue v);
-
-/*
- * DO NOT CALL THIS. Use JS::ToObject.
- */
-extern JS_PUBLIC_API(JSObject*)
-ToObjectSlow(JSContext *cx, JS::HandleValue vp, bool reportScanStack);
-
-} /* namespace js */
-
-namespace JS {
-
-/* ES5 9.3 ToNumber. */
-MOZ_ALWAYS_INLINE bool
-ToNumber(JSContext *cx, HandleValue v, double *out)
-{
- AssertArgumentsAreSane(cx, v);
-
- if (v.isNumber()) {
- *out = v.toNumber();
- return true;
- }
- return js::ToNumberSlow(cx, v, out);
-}
-
-MOZ_ALWAYS_INLINE bool
-ToBoolean(HandleValue v)
-{
- if (v.isBoolean())
- return v.toBoolean();
- if (v.isInt32())
- return v.toInt32() != 0;
- if (v.isNullOrUndefined())
- return false;
- if (v.isDouble()) {
- double d = v.toDouble();
- return !mozilla::IsNaN(d) && d != 0;
- }
- if (v.isSymbol())
- return true;
-
- /* The slow path handles strings and objects. */
- return js::ToBooleanSlow(v);
-}
-
-MOZ_ALWAYS_INLINE JSString*
-ToString(JSContext *cx, HandleValue v)
-{
- if (v.isString())
- return v.toString();
- return js::ToStringSlow(cx, v);
-}
-
-/* ES5 9.9 ToObject. */
-MOZ_ALWAYS_INLINE JSObject*
-ToObject(JSContext *cx, HandleValue vp)
-{
- if (vp.isObject())
- return &vp.toObject();
- return js::ToObjectSlow(cx, vp, false);
-}
-
-/*
- * Implements ES6 draft rev 28 (2014 Oct 14) 7.1.1, second algorithm.
- *
- * Most users should not call this -- use JS::ToNumber, ToBoolean, or ToString
- * instead. This should only be called from custom convert hooks. It implements
- * the default conversion behavior shared by most objects in JS, so it's useful
- * as a fallback.
- */
-extern JS_PUBLIC_API(bool)
-OrdinaryToPrimitive(JSContext *cx, JS::HandleObject obj, JSType type,
- JS::MutableHandleValue vp);
-
-} /* namespace JS */
-
extern JS_PUBLIC_API(bool)
JS_DoubleIsInt32(double d, int32_t *ip);
-extern JS_PUBLIC_API(int32_t)
-JS_DoubleToInt32(double d);
-
-extern JS_PUBLIC_API(uint32_t)
-JS_DoubleToUint32(double d);
-
-
-namespace js {
-/* DO NOT CALL THIS. Use JS::ToUint16. */
-extern JS_PUBLIC_API(bool)
-ToUint16Slow(JSContext *cx, JS::HandleValue v, uint16_t *out);
-
-/* DO NOT CALL THIS. Use JS::ToInt32. */
-extern JS_PUBLIC_API(bool)
-ToInt32Slow(JSContext *cx, JS::HandleValue v, int32_t *out);
-
-/* DO NOT CALL THIS. Use JS::ToUint32. */
-extern JS_PUBLIC_API(bool)
-ToUint32Slow(JSContext *cx, JS::HandleValue v, uint32_t *out);
-
-/* DO NOT CALL THIS. Use JS::ToInt64. */
-extern JS_PUBLIC_API(bool)
-ToInt64Slow(JSContext *cx, JS::HandleValue v, int64_t *out);
-
-/* DO NOT CALL THIS. Use JS::ToUint64. */
-extern JS_PUBLIC_API(bool)
-ToUint64Slow(JSContext *cx, JS::HandleValue v, uint64_t *out);
-} /* namespace js */
-
-namespace JS {
-
-MOZ_ALWAYS_INLINE bool
-ToUint16(JSContext *cx, JS::HandleValue v, uint16_t *out)
-{
- AssertArgumentsAreSane(cx, v);
-
- if (v.isInt32()) {
- *out = uint16_t(v.toInt32());
- return true;
- }
- return js::ToUint16Slow(cx, v, out);
-}
-
-MOZ_ALWAYS_INLINE bool
-ToInt32(JSContext *cx, JS::HandleValue v, int32_t *out)
-{
- AssertArgumentsAreSane(cx, v);
-
- if (v.isInt32()) {
- *out = v.toInt32();
- return true;
- }
- return js::ToInt32Slow(cx, v, out);
-}
-
-MOZ_ALWAYS_INLINE bool
-ToUint32(JSContext *cx, JS::HandleValue v, uint32_t *out)
-{
- AssertArgumentsAreSane(cx, v);
-
- if (v.isInt32()) {
- *out = uint32_t(v.toInt32());
- return true;
- }
- return js::ToUint32Slow(cx, v, out);
-}
-
-MOZ_ALWAYS_INLINE bool
-ToInt64(JSContext *cx, JS::HandleValue v, int64_t *out)
-{
- AssertArgumentsAreSane(cx, v);
-
- if (v.isInt32()) {
- *out = int64_t(v.toInt32());
- return true;
- }
- return js::ToInt64Slow(cx, v, out);
-}
-
-MOZ_ALWAYS_INLINE bool
-ToUint64(JSContext *cx, JS::HandleValue v, uint64_t *out)
-{
- AssertArgumentsAreSane(cx, v);
-
- if (v.isInt32()) {
- /* Account for sign extension of negatives into the longer 64bit space. */
- *out = uint64_t(int64_t(v.toInt32()));
- return true;
- }
- return js::ToUint64Slow(cx, v, out);
-}
-
-
-} /* namespace JS */
-
extern JS_PUBLIC_API(JSType)
JS_TypeOfValue(JSContext *cx, JS::Handle<JS::Value> v);
extern JS_PUBLIC_API(bool)
JS_StrictlyEqual(JSContext *cx, jsval v1, jsval v2, bool *equal);
extern JS_PUBLIC_API(bool)
JS_LooselyEqual(JSContext *cx, JS::Handle<JS::Value> v1, JS::Handle<JS::Value> v2, bool *equal);
--- a/js/src/jsmath.cpp
+++ b/js/src/jsmath.cpp
@@ -1373,16 +1373,60 @@ js::ecmaHypot(double x, double y)
*/
if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y)) {
return mozilla::PositiveInfinity<double>();
}
#endif
return hypot(x, y);
}
+static inline
+void
+hypot_step(double &scale, double &sumsq, double x)
+{
+ double xabs = mozilla::Abs(x);
+ if (scale < xabs) {
+ sumsq = 1 + sumsq * (scale / xabs) * (scale / xabs);
+ scale = xabs;
+ } else if (scale != 0) {
+ sumsq += (xabs / scale) * (xabs / scale);
+ }
+}
+
+double
+js::hypot4(double x, double y, double z, double w)
+{
+ /* Check for infinity or NaNs so that we can return immediatelly.
+ * Does not need to be WIN_XP specific as ecmaHypot
+ */
+ if (mozilla::IsInfinite(x) || mozilla::IsInfinite(y) ||
+ mozilla::IsInfinite(z) || mozilla::IsInfinite(w))
+ return mozilla::PositiveInfinity<double>();
+
+ if (mozilla::IsNaN(x) || mozilla::IsNaN(y) || mozilla::IsNaN(z) ||
+ mozilla::IsNaN(w))
+ return GenericNaN();
+
+ double scale = 0;
+ double sumsq = 1;
+
+ hypot_step(scale, sumsq, x);
+ hypot_step(scale, sumsq, y);
+ hypot_step(scale, sumsq, z);
+ hypot_step(scale, sumsq, w);
+
+ return scale * sqrt(sumsq);
+}
+
+double
+js::hypot3(double x, double y, double z)
+{
+ return hypot4(x, y, z, 0.0);
+}
+
bool
js::math_hypot(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
return math_hypot_handle(cx, args, args.rval());
}
bool
@@ -1413,24 +1457,17 @@ js::math_hypot_handle(JSContext *cx, Han
if (!ToNumber(cx, args[i], &x))
return false;
isInfinite |= mozilla::IsInfinite(x);
isNaN |= mozilla::IsNaN(x);
if (isInfinite || isNaN)
continue;
- double xabs = mozilla::Abs(x);
-
- if (scale < xabs) {
- sumsq = 1 + sumsq * (scale / xabs) * (scale / xabs);
- scale = xabs;
- } else if (scale != 0) {
- sumsq += (xabs / scale) * (xabs / scale);
- }
+ hypot_step(scale, sumsq, x);
}
double result = isInfinite ? PositiveInfinity<double>() :
isNaN ? GenericNaN() :
scale * sqrt(sumsq);
res.setNumber(result);
return true;
}
--- a/js/src/jsmath.h
+++ b/js/src/jsmath.h
@@ -240,16 +240,22 @@ extern bool
math_asinh(JSContext *cx, unsigned argc, js::Value *vp);
extern bool
math_atanh(JSContext *cx, unsigned argc, js::Value *vp);
extern double
ecmaHypot(double x, double y);
+extern double
+hypot3(double x, double y, double z);
+
+extern double
+hypot4(double x, double y, double z, double w);
+
extern bool
math_hypot(JSContext *cx, unsigned argc, Value *vp);
extern bool
math_hypot_handle(JSContext *cx, HandleValueArray args, MutableHandleValue res);
extern bool
math_trunc(JSContext *cx, unsigned argc, Value *vp);
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3555,17 +3555,17 @@ js::PrimitiveToObject(JSContext *cx, con
/*
* Invokes the ES5 ToObject algorithm on vp, returning the result. If vp might
* already be an object, use ToObject. reportCantConvert controls how null and
* undefined errors are reported.
*
* Callers must handle the already-object case.
*/
JSObject *
-js::ToObjectSlow(JSContext *cx, HandleValue val, bool reportScanStack)
+js::ToObjectSlow(JSContext *cx, JS::HandleValue val, bool reportScanStack)
{
MOZ_ASSERT(!val.isMagic());
MOZ_ASSERT(!val.isObject());
if (val.isNullOrUndefined()) {
if (reportScanStack) {
js_ReportIsNullOrUndefined(cx, JSDVG_SEARCH_STACK, val, NullPtr());
} else {
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -15,16 +15,17 @@
* values, called slots. The map/slot pointer pair is GC'ed, while the map
* is reference counted and the slot vector is malloc'ed.
*/
#include "mozilla/MemoryReporting.h"
#include "gc/Barrier.h"
#include "gc/Marking.h"
+#include "js/Conversions.h"
#include "js/GCAPI.h"
#include "js/HeapAPI.h"
#include "vm/Shape.h"
#include "vm/String.h"
#include "vm/Xdr.h"
namespace JS {
struct ClassInfo;
--- a/js/src/shell/OSObject.cpp
+++ b/js/src/shell/OSObject.cpp
@@ -16,16 +16,18 @@
#else
#include <sys/wait.h>
#include <unistd.h>
#endif
// For JSFunctionSpecWithHelp
#include "jsfriendapi.h"
+#include "js/Conversions.h"
+
using namespace JS;
static bool
os_getenv(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
if (args.length() < 1) {
JS_ReportError(cx, "os.getenv requires 1 argument");
--- a/js/src/tests/ecma_6/Comprehensions/error-messages.js
+++ b/js/src/tests/ecma_6/Comprehensions/error-messages.js
@@ -26,72 +26,74 @@ const GENERIC = error("(for
const BAD_GENERATOR_SYNTAX = error("(for (x of []) x, 1)").message;
const MISSING_SEMI = error("yield 1").message;
const MISSING_PAREN = error("(yield 1)").message;
const PAREN_PAREN = error("(foo").message;
const FOR_OF_PAREN = error("(for (x of y, z) w)").message;
const cases = [
// Expressions involving yield without a value, not currently implemented. Many
-// of these errors would need to be updated.
-//{ expr: "yield", top: TOP_YIELD, fun: null, gen: GENEXP_YIELD, desc: "simple yield" },
-//{ expr: "1, yield", top: TOP_YIELD, fun: null, gen: GENEXP_YIELD, desc: "simple yield at end of list" },
-//{ expr: "yield, 1", top: TOP_YIELD, fun: YIELD_PAREN, gen: YIELD_PAREN, desc: "simple yield in list" },
-//{ expr: "(yield)", top: TOP_YIELD, fun: null, gen: GENEXP_YIELD, desc: "simple yield, parenthesized" },
-//{ expr: "(1, yield)", top: TOP_YIELD, fun: null, gen: GENEXP_YIELD, desc: "simple yield at end of list, parenthesized" },
-//{ expr: "(yield, 1)", top: TOP_YIELD, fun: YIELD_PAREN, gen: YIELD_PAREN, desc: "simple yield in list, parenthesized" },
-//{ expr: "((((yield))))", top: TOP_YIELD, fun: null, gen: GENEXP_YIELD, desc: "deeply nested yield" },
-//{ expr: "(for (x of []) yield)", top: TOP_YIELD, fun: GENERIC, gen: GENERIC, desc: "simple yield in genexp" },
-//{ expr: "(for (x of []) yield, 1)", top: TOP_YIELD, fun: YIELD_PAREN, gen: YIELD_PAREN, desc: "simple yield in list in genexp" },
-//{ expr: "(for (x of []) 1, yield)", top: TOP_YIELD, fun: GENERIC, gen: GENERIC, desc: "simple yield at end of list in genexp" },
-//{ expr: "(for (x of []) (yield))", top: TOP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, desc: "simple yield, parenthesized in genexp" },
-//{ expr: "(for (x of []) 1, (yield))", top: TOP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, desc: "simple yield, parenthesized in list in genexp" },
-//{ expr: "(for (x of []) (1, yield))", top: TOP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, desc: "simple yield at end of list, parenthesized in genexp" },
-//{ expr: "(for (x of []) 1, (2, yield))", top: TOP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, desc: "simple yield at end of list, parenthesized in list in genexp" },
-//{ expr: "(for (x of []) (yield, 1))", top: TOP_YIELD, fun: YIELD_PAREN, gen: YIELD_PAREN, desc: "simple yield in list, parenthesized in genexp" },
-//{ expr: "(for (x of []) 1, (yield, 2))", top: TOP_YIELD, fun: YIELD_PAREN, gen: YIELD_PAREN, desc: "simple yield in list, parenthesized in list in genexp" },
+// of these errors would need to be updated. (Note: line numbers below might be
+// mere placeholders, not actually the expected correct behavior -- check before
+// blindly uncommenting.)
+//{ expr: "yield", top: [TOP_YIELD, 777], fun: null, gen: [GENEXP_YIELD, 2], desc: "simple yield" },
+//{ expr: "1, yield", top: [TOP_YIELD, 777], fun: null, gen: [GENEXP_YIELD, 2], desc: "simple yield at end of list" },
+//{ expr: "yield, 1", top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], desc: "simple yield in list" },
+//{ expr: "(yield)", top: [TOP_YIELD, 777], fun: null, gen: [GENEXP_YIELD, 2], desc: "simple yield, parenthesized" },
+//{ expr: "(1, yield)", top: [TOP_YIELD, 777], fun: null, gen: [GENEXP_YIELD, 2], desc: "simple yield at end of list, parenthesized" },
+//{ expr: "(yield, 1)", top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], desc: "simple yield in list, parenthesized" },
+//{ expr: "((((yield))))", top: [TOP_YIELD, 777], fun: null, gen: [GENEXP_YIELD, 2], desc: "deeply nested yield" },
+//{ expr: "(for (x of []) yield)", top: [TOP_YIELD, 777], fun: [GENERIC, 777], gen: [GENERIC, 777], desc: "simple yield in genexp" },
+//{ expr: "(for (x of []) yield, 1)", top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], desc: "simple yield in list in genexp" },
+//{ expr: "(for (x of []) 1, yield)", top: [TOP_YIELD, 777], fun: [GENERIC, 777], gen: [GENERIC, 777], desc: "simple yield at end of list in genexp" },
+//{ expr: "(for (x of []) (yield))", top: [TOP_YIELD, 777], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], desc: "simple yield, parenthesized in genexp" },
+//{ expr: "(for (x of []) 1, (yield))", top: [TOP_YIELD, 777], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], desc: "simple yield, parenthesized in list in genexp" },
+//{ expr: "(for (x of []) (1, yield))", top: [TOP_YIELD, 777], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], desc: "simple yield at end of list, parenthesized in genexp" },
+//{ expr: "(for (x of []) 1, (2, yield))", top: [TOP_YIELD, 777], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], desc: "simple yield at end of list, parenthesized in list in genexp" },
+//{ expr: "(for (x of []) (yield, 1))", top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], desc: "simple yield in list, parenthesized in genexp" },
+//{ expr: "(for (x of []) 1, (yield, 2))", top: [TOP_YIELD, 777], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], desc: "simple yield in list, parenthesized in list in genexp" },
//{ expr: "(for (x of []) (function*() { yield }))", top: null, fun: null, gen: null, desc: "legal yield in nested function" },
// yield expressions
- { expr: "yield 1", top: MISSING_SEMI, fun: MISSING_SEMI, gen: null, genexp: GENEXP_YIELD, desc: "yield w/ arg" },
- { expr: "1, yield 2", top: MISSING_SEMI, fun: MISSING_SEMI, gen: null, genexp: FOR_OF_PAREN, desc: "yield w/ arg at end of list" },
- { expr: "yield 1, 2", top: MISSING_SEMI, fun: MISSING_SEMI, gen: null, genexp: FOR_OF_PAREN, desc: "yield w/ arg in list" },
- { expr: "(yield 1)", top: MISSING_PAREN, fun: MISSING_PAREN, gen: null, genexp: GENEXP_YIELD, desc: "yield w/ arg, parenthesized" },
- { expr: "(1, yield 2)", top: MISSING_PAREN, fun: MISSING_PAREN, gen: null, genexp: GENEXP_YIELD, desc: "yield w/ arg at end of list, parenthesized" },
- { expr: "(yield 1, 2)", top: MISSING_PAREN, fun: MISSING_PAREN, gen: null, genexp: YIELD_PAREN, desc: "yield w/ arg in list, parenthesized" },
+ { expr: "yield 1", top: [MISSING_SEMI, 2], fun: [MISSING_SEMI, 2], gen: null, genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg" },
+ { expr: "1, yield 2", top: [MISSING_SEMI, 2], fun: [MISSING_SEMI, 2], gen: null, genexp: [FOR_OF_PAREN, 1], desc: "yield w/ arg at end of list" },
+ { expr: "yield 1, 2", top: [MISSING_SEMI, 2], fun: [MISSING_SEMI, 2], gen: [YIELD_PAREN, 3], genexp: [FOR_OF_PAREN, 3], desc: "yield w/ arg in list" },
+ { expr: "(yield 1)", top: [MISSING_PAREN, 2], fun: [MISSING_PAREN, 2], gen: null, genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg, parenthesized" },
+ { expr: "(1, yield 2)", top: [MISSING_PAREN, 2], fun: [MISSING_PAREN, 2], gen: null, genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg at end of list, parenthesized" },
+ { expr: "(yield 1, 2)", top: [MISSING_PAREN, 2], fun: [MISSING_PAREN, 2], gen: [YIELD_PAREN, 3], genexp: [YIELD_PAREN, 2], desc: "yield w/ arg in list, parenthesized" },
// deeply nested yield expressions
- { expr: "((((yield 1))))", top: MISSING_PAREN, fun: MISSING_PAREN, gen: null, genexp: GENEXP_YIELD, desc: "deeply nested yield w/ arg" },
+ { expr: "((((yield 1))))", top: [MISSING_PAREN, 2], fun: [MISSING_PAREN, 2], gen: null, genexp: [GENEXP_YIELD, 2], desc: "deeply nested yield w/ arg" },
// arguments
{ expr: "arguments", top: null, fun: null, gen: null, genexp: null, desc: "arguments in list" },
- { expr: "1, arguments", top: null, fun: null, gen: null, genexp: FOR_OF_PAREN, desc: "arguments in list" },
+ { expr: "1, arguments", top: null, fun: null, gen: null, genexp: [FOR_OF_PAREN, 1], desc: "arguments in list" },
// yield in generator expressions
- { expr: "(for (x of []) yield 1)", top: GENEXP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, genexp: GENEXP_YIELD, desc: "yield w/ arg in genexp" },
- { expr: "(for (x of []) yield 1, 2)", top: GENEXP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, genexp: GENEXP_YIELD, desc: "yield w/ arg in list in genexp" },
- { expr: "(for (x of []) 1, yield 2)", top: PAREN_PAREN, fun: PAREN_PAREN, gen: PAREN_PAREN, genexp: PAREN_PAREN, desc: "yield w/ arg at end of list in genexp" },
- { expr: "(for (x of []) (yield 1))", top: GENEXP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, genexp: GENEXP_YIELD, desc: "yield w/ arg, parenthesized in genexp" },
- { expr: "(for (x of []) 1, (yield 2))", top: PAREN_PAREN, fun: PAREN_PAREN, gen: PAREN_PAREN, genexp: PAREN_PAREN, desc: "yield w/ arg, parenthesized in list in genexp" },
- { expr: "(for (x of []) (1, yield 2))", top: GENEXP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, genexp: GENEXP_YIELD, desc: "yield w/ arg at end of list, parenthesized in genexp" },
- { expr: "(for (x of []) 1, (2, yield 3))", top: PAREN_PAREN, fun: PAREN_PAREN, gen: PAREN_PAREN, genexp: PAREN_PAREN, desc: "yield w/ arg at end of list, parenthesized in list in genexp" },
- { expr: "(for (x of []) (yield 1, 2))", top: YIELD_PAREN, fun: YIELD_PAREN, gen: YIELD_PAREN, genexp: YIELD_PAREN, desc: "yield w/ arg in list, parenthesized in genexp" },
- { expr: "(for (x of []) 1, (yield 2, 3))", top: PAREN_PAREN, fun: PAREN_PAREN, gen: PAREN_PAREN, genexp: PAREN_PAREN, desc: "yield w/ arg in list, parenthesized in list in genexp" },
+ { expr: "(for (x of []) yield 1)", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg in genexp" },
+ { expr: "(for (x of []) yield 1, 2)", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg in list in genexp" },
+ { expr: "(for (x of []) 1, yield 2)", top: [PAREN_PAREN, 1], fun: [PAREN_PAREN, 1], gen: [PAREN_PAREN, 1], genexp: [PAREN_PAREN, 1], desc: "yield w/ arg at end of list in genexp" },
+ { expr: "(for (x of []) (yield 1))", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg, parenthesized in genexp" },
+ { expr: "(for (x of []) 1, (yield 2))", top: [PAREN_PAREN, 1], fun: [PAREN_PAREN, 1], gen: [PAREN_PAREN, 1], genexp: [PAREN_PAREN, 1], desc: "yield w/ arg, parenthesized in list in genexp" },
+ { expr: "(for (x of []) (1, yield 2))", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "yield w/ arg at end of list, parenthesized in genexp" },
+ { expr: "(for (x of []) 1, (2, yield 3))", top: [PAREN_PAREN, 1], fun: [PAREN_PAREN, 1], gen: [PAREN_PAREN, 1], genexp: [PAREN_PAREN, 1], desc: "yield w/ arg at end of list, parenthesized in list in genexp" },
+ { expr: "(for (x of []) (yield 1, 2))", top: [YIELD_PAREN, 2], fun: [YIELD_PAREN, 2], gen: [YIELD_PAREN, 2], genexp: [YIELD_PAREN, 2], desc: "yield w/ arg in list, parenthesized in genexp" },
+ { expr: "(for (x of []) 1, (yield 2, 3))", top: [PAREN_PAREN, 1], fun: [PAREN_PAREN, 1], gen: [PAREN_PAREN, 1], genexp: [PAREN_PAREN, 1], desc: "yield w/ arg in list, parenthesized in list in genexp" },
// deeply nested yield in generator expressions
- { expr: "(for (x of []) (((1, yield 2))))", top: GENEXP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, genexp: GENEXP_YIELD, desc: "deeply nested yield in genexp" },
- { expr: "(for (y of []) (for (x of []) ((1, yield 2))))", top: GENEXP_YIELD, fun: GENEXP_YIELD, gen: GENEXP_YIELD, genexp: GENEXP_YIELD, desc: "deeply nested yield in multiple genexps" },
+ { expr: "(for (x of []) (((1, yield 2))))", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "deeply nested yield in genexp" },
+ { expr: "(for (y of []) (for (x of []) ((1, yield 2))))", top: [GENEXP_YIELD, 2], fun: [GENEXP_YIELD, 2], gen: [GENEXP_YIELD, 2], genexp: [GENEXP_YIELD, 2], desc: "deeply nested yield in multiple genexps" },
// arguments in generator expressions
{ expr: "(for (x of []) arguments)", top: null, fun: null, gen: null, genexp: null, desc: "simple arguments in genexp" },
- { expr: "(for (x of []) 1, arguments)", top: BAD_GENERATOR_SYNTAX, fun: BAD_GENERATOR_SYNTAX, gen: BAD_GENERATOR_SYNTAX, genexp: BAD_GENERATOR_SYNTAX, desc: "arguments in list in genexp" },
+ { expr: "(for (x of []) 1, arguments)", top: [BAD_GENERATOR_SYNTAX, 1], fun: [BAD_GENERATOR_SYNTAX, 1], gen: [BAD_GENERATOR_SYNTAX, 1], genexp: [BAD_GENERATOR_SYNTAX, 1], desc: "arguments in list in genexp" },
{ expr: "(for (x of []) (arguments))", top: null, fun: null, gen: null, genexp: null, desc: "arguments, parenthesized in genexp" },
- { expr: "(for (x of []) 1, (arguments))", top: BAD_GENERATOR_SYNTAX, fun: BAD_GENERATOR_SYNTAX, gen: BAD_GENERATOR_SYNTAX, genexp: BAD_GENERATOR_SYNTAX, desc: "arguments, parenthesized in list in genexp" },
+ { expr: "(for (x of []) 1, (arguments))", top: [BAD_GENERATOR_SYNTAX, 1], fun: [BAD_GENERATOR_SYNTAX, 1], gen: [BAD_GENERATOR_SYNTAX, 1], genexp: [BAD_GENERATOR_SYNTAX, 1], desc: "arguments, parenthesized in list in genexp" },
{ expr: "(for (x of []) (1, arguments))", top: null, fun: null, gen: null, genexp: null, desc: "arguments in list, parenthesized in genexp" },
- { expr: "(for (x of []) 1, (2, arguments))", top: BAD_GENERATOR_SYNTAX, fun: BAD_GENERATOR_SYNTAX, gen: BAD_GENERATOR_SYNTAX, genexp: BAD_GENERATOR_SYNTAX, desc: "arguments in list, parenthesized in list in genexp" },
+ { expr: "(for (x of []) 1, (2, arguments))", top: [BAD_GENERATOR_SYNTAX, 1], fun: [BAD_GENERATOR_SYNTAX, 1], gen: [BAD_GENERATOR_SYNTAX, 1], genexp: [BAD_GENERATOR_SYNTAX, 1], desc: "arguments in list, parenthesized in list in genexp" },
// deeply nested arguments in generator expressions
{ expr: "(for (x of []) (((1, arguments))))", top: null, fun: null, gen: null, genexp: null, desc: "deeply nested arguments in genexp" },
{ expr: "(for (y of []) (for (x of []) ((1, arguments))))", top: null, fun: null, gen: null, genexp: null, desc: "deeply nested arguments in multiple genexps" },
// legal yield/arguments in nested function
{ expr: "(for (x of []) (function*() { yield 1 }))", top: null, fun: null, gen: null, genexp: null, desc: "legal yield in nested function" },
{ expr: "(for (x of []) (function() { arguments }))", top: null, fun: null, gen: null, genexp: null, desc: "legal arguments in nested function" },
@@ -105,25 +107,24 @@ test();
function splitKeyword(str) {
return str.
// replace(/[)] yield/, ')\nyield\n').
replace(/yield ([0-9])/, '\nyield $1\n').
replace(/yield([^ ]|$)/, '\nyield\n$1').
replace(/arguments/, '\narguments\n');
}
-function expectError1(err, ctx, msg) {
+function expectError1(err, ctx, msg, lineNumber) {
reportCompare('object', typeof err, 'exn for: ' + msg);
reportCompare(ctx, err.message, 'exn message for: ' + msg);
- if (ctx !== BAD_GENERATOR_SYNTAX && ctx != PAREN_PAREN && ctx != FOR_OF_PAREN)
- reportCompare(2, err.lineNumber, 'exn token for: ' + msg);
+ reportCompare(lineNumber, err.lineNumber, 'exn token for: ' + msg);
}
-function expectError(expr, wrapCtx, expect, msg) {
- expectError1(error(wrapCtx(expr)), expect, msg);
+function expectError(expr, wrapCtx, [expect, lineNumber], msg) {
+ expectError1(error(wrapCtx(expr)), expect, msg, lineNumber);
}
function expectSuccess(err, msg) {
reportCompare(null, err, 'parse: ' + msg);
}
function atTop(str) { return str }
function inFun(str) { return '(function(){' + str + '})' }
new file mode 100644
--- /dev/null
+++ b/js/src/tests/ecma_6/Expressions/delete-name-parenthesized-early-error-strict-mode.js
@@ -0,0 +1,76 @@
+// Any copyright is dedicated to the Public Domain.
+// http://creativecommons.org/licenses/publicdomain/
+
+//-----------------------------------------------------------------------------
+var BUGNUMBER = 1111101;
+var summary =
+ "delete (foo), delete ((foo)), and so on are strict mode early errors";
+
+print(BUGNUMBER + ": " + summary);
+
+/**************
+ * BEGIN TEST *
+ **************/
+
+function checkSyntaxError(code)
+{
+ function helper(maker)
+ {
+ var earlyError = false;
+ try
+ {
+ var f = maker(code);
+
+ var error = "no early error, created a function with code <" + code + ">";
+ try
+ {
+ f();
+ error += ", and the function can be called without error";
+ }
+ catch (e)
+ {
+ error +=", and calling the function throws " + e;
+ }
+
+ throw new Error(error);
+ }
+ catch (e)
+ {
+ assertEq(e instanceof SyntaxError, true,
+ "expected syntax error, got " + e);
+ }
+ }
+
+ helper(Function);
+ helper(eval);
+}
+
+checkSyntaxError("function f() { 'use strict'; delete escape; } f();");
+checkSyntaxError("function f() { 'use strict'; delete escape; }");
+checkSyntaxError("function f() { 'use strict'; delete (escape); } f();");
+checkSyntaxError("function f() { 'use strict'; delete (escape); }");
+checkSyntaxError("function f() { 'use strict'; delete ((escape)); } f();");
+checkSyntaxError("function f() { 'use strict'; delete ((escape)); }");
+
+// Meanwhile, non-strict all of these should work
+
+function checkFine(code)
+{
+ Function(code);
+ (1, eval)(code); // indirect, to be consistent w/above
+}
+
+checkFine("function f() { delete escape; } f();");
+checkFine("function f() { delete escape; }");
+checkFine("function f() { delete (escape); } f();");
+checkFine("function f() { delete (escape); }");
+checkFine("function f() { delete ((escape)); } f();");
+checkFine("function f() { delete ((escape)); }");
+
+
+/******************************************************************************/
+
+if (typeof reportCompare === "function")
+ reportCompare(true, true);
+
+print("Tests complete");
--- a/js/src/tests/ecma_6/Generators/syntax.js
+++ b/js/src/tests/ecma_6/Generators/syntax.js
@@ -29,17 +29,17 @@ function* g() { (yield 3) + (yield 4); }
function* g() { yield; }
function* g() { yield }
function* g() {
yield
}
function* g() { (yield) }
function* g() { [yield] }
function* g() { {yield} }
-function* g() { yield, yield }
+function* g() { (yield), (yield) }
function* g() { yield; yield }
function* g() { (yield) ? yield : yield }
function* g() {
(yield)
? yield
: yield
}
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -491,32 +491,16 @@ class PerThreadData : public PerThreadDa
* thread is associated. This is private because accessing the
* fields of this runtime can provoke race conditions, so the
* intention is that access will be mediated through safe
* functions like |runtimeFromMainThread| and |associatedWith()| below.
*/
JSRuntime *runtime_;
public:
- /*
- * We save all conservative scanned roots in this vector so that
- * conservative scanning can be "replayed" deterministically. In DEBUG mode,
- * this allows us to run a non-incremental GC after every incremental GC to
- * ensure that no objects were missed.
- */
-#ifdef DEBUG
- struct SavedGCRoot {
- void *thing;
- JSGCTraceKind kind;
-
- SavedGCRoot(void *thing, JSGCTraceKind kind) : thing(thing), kind(kind) {}
- };
- js::Vector<SavedGCRoot, 0, js::SystemAllocPolicy> gcSavedRoots;
-#endif
-
#ifdef JS_TRACE_LOGGING
TraceLoggerThread *traceLogger;
#endif
/* Pointer to the current AutoFlushICache. */
js::jit::AutoFlushICache *autoFlushICache_;
public:
--- a/media/gmp-clearkey/0.1/clearkey.info
+++ b/media/gmp-clearkey/0.1/clearkey.info
@@ -1,4 +1,4 @@
Name: clearkey
Description: ClearKey decrypt-only GMP plugin
Version: 0.1
-APIs: eme-decrypt-v3[org.w3.clearkey]
+APIs: eme-decrypt-v4[org.w3.clearkey]
--- a/media/mtransport/nr_socket_prsock.cpp
+++ b/media/mtransport/nr_socket_prsock.cpp
@@ -688,19 +688,67 @@ int NrSocket::read(void* buf, size_t max
ABORT(R_EOD);
*len = (size_t)status; // Guaranteed to be > 0
_status = 0;
abort:
return(_status);
}
+NS_IMPL_ISUPPORTS(NrSocketIpcProxy, nsIUDPSocketInternal)
+
+nsresult
+NrSocketIpcProxy::Init(const nsRefPtr<NrSocketIpc>& socket)
+{
+ nsresult rv;
+ sts_thread_ = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) {
+ MOZ_ASSERT(false, "Failed to get STS thread");
+ return rv;
+ }
+
+ socket_ = socket;
+ return NS_OK;
+}
+
+NrSocketIpcProxy::~NrSocketIpcProxy()
+{
+ // Send our ref to STS to be released
+ RUN_ON_THREAD(sts_thread_,
+ mozilla::WrapRelease(socket_.forget()),
+ NS_DISPATCH_NORMAL);
+}
+
+// IUDPSocketInternal interfaces
+// callback while error happened in UDP socket operation
+NS_IMETHODIMP NrSocketIpcProxy::CallListenerError(const nsACString &message,
+ const nsACString &filename,
+ uint32_t line_number) {
+ return socket_->CallListenerError(message, filename, line_number);
+}
+
+// callback while receiving UDP packet
+NS_IMETHODIMP NrSocketIpcProxy::CallListenerReceivedData(const nsACString &host,
+ uint16_t port,
+ const uint8_t *data,
+ uint32_t data_length) {
+ return socket_->CallListenerReceivedData(host, port, data, data_length);
+}
+
+// callback while UDP socket is opened
+NS_IMETHODIMP NrSocketIpcProxy::CallListenerOpened() {
+ return socket_->CallListenerOpened();
+}
+
+// callback while UDP socket is closed
+NS_IMETHODIMP NrSocketIpcProxy::CallListenerClosed() {
+ return socket_->CallListenerClosed();
+}
+
// NrSocketIpc Implementation
-NS_IMPL_ISUPPORTS(NrSocketIpc, nsIUDPSocketInternal)
-
NrSocketIpc::NrSocketIpc(const nsCOMPtr<nsIEventTarget> &main_thread)
: err_(false),
state_(NR_INIT),
main_thread_(main_thread),
monitor_("NrSocketIpc") {
}
// IUDPSocketInternal interfaces
@@ -1017,17 +1065,25 @@ void NrSocketIpc::create_m(const nsACStr
MOZ_ASSERT(false, "Failed to create UDPSocketChild");
mon.NotifyAll();
return;
}
socket_child_ = new nsMainThreadPtrHolder<nsIUDPSocketChild>(socketChild);
socket_child_->SetFilterName(nsCString("stun"));
- if (NS_FAILED(socket_child_->Bind(this, host, port,
+ nsRefPtr<NrSocketIpcProxy> proxy(new NrSocketIpcProxy);
+ rv = proxy->Init(this);
+ if (NS_FAILED(rv)) {
+ err_ = true;
+ mon.NotifyAll();
+ return;
+ }
+
+ if (NS_FAILED(socket_child_->Bind(proxy, host, port,
/* reuse = */ false,
/* loopback = */ false))) {
err_ = true;
MOZ_ASSERT(false, "Failed to create UDP socket");
mon.NotifyAll();
return;
}
}
@@ -1102,17 +1158,17 @@ static nr_socket_vtbl nr_socket_local_vt
nr_socket_local_getaddr,
nr_socket_local_connect,
nr_socket_local_write,
nr_socket_local_read,
nr_socket_local_close
};
int nr_socket_local_create(nr_transport_addr *addr, nr_socket **sockp) {
- NrSocketBase *sock = nullptr;
+ RefPtr<NrSocketBase> sock;
// create IPC bridge for content process
if (XRE_GetProcessType() == GeckoProcessType_Default) {
sock = new NrSocket();
} else {
nsCOMPtr<nsIThread> main_thread;
NS_GetMainThread(getter_AddRefs(main_thread));
sock = new NrSocketIpc(main_thread.get());
@@ -1124,25 +1180,26 @@ int nr_socket_local_create(nr_transport_
if (r)
ABORT(r);
r = nr_socket_create_int(static_cast<void *>(sock),
sock->vtbl(), sockp);
if (r)
ABORT(r);
- // Add a reference so that we can delete it in destroy()
- sock->AddRef();
-
_status = 0;
+ {
+ // We will release this reference in destroy(), not exactly the normal
+ // ownership model, but it is what it is.
+ NrSocketBase* dummy = sock.forget().take();
+ (void)dummy;
+ }
+
abort:
- if (_status) {
- delete sock;
- }
return _status;
}
static int nr_socket_local_destroy(void **objp) {
if(!objp || !*objp)
return 0;
--- a/media/mtransport/nr_socket_prsock.h
+++ b/media/mtransport/nr_socket_prsock.h
@@ -183,30 +183,38 @@ struct nr_udp_message {
PRNetAddr from;
nsAutoPtr<DataBuffer> data;
private:
~nr_udp_message() {}
DISALLOW_COPY_ASSIGN(nr_udp_message);
};
-class NrSocketIpc : public NrSocketBase,
- public nsIUDPSocketInternal {
+class NrSocketIpc : public NrSocketBase {
public:
enum NrSocketIpcState {
NR_INIT,
NR_CONNECTING,
NR_CONNECTED,
NR_CLOSING,
NR_CLOSED,
};
- NS_DECL_THREADSAFE_ISUPPORTS
- NS_DECL_NSIUDPSOCKETINTERNAL
+ NS_INLINE_DECL_THREADSAFE_REFCOUNTING(NrSocketIpc)
+
+ NS_IMETHODIMP CallListenerError(const nsACString &message,
+ const nsACString &filename,
+ uint32_t line_number);
+ NS_IMETHODIMP CallListenerReceivedData(const nsACString &host,
+ uint16_t port,
+ const uint8_t *data,
+ uint32_t data_length);
+ NS_IMETHODIMP CallListenerOpened();
+ NS_IMETHODIMP CallListenerClosed();
explicit NrSocketIpc(const nsCOMPtr<nsIEventTarget> &main_thread);
// Implementations of the NrSocketBase APIs
virtual int create(nr_transport_addr *addr) MOZ_OVERRIDE;
virtual int sendto(const void *msg, size_t len,
int flags, nr_transport_addr *to) MOZ_OVERRIDE;
virtual int recvfrom(void * buf, size_t maxlen,
@@ -235,16 +243,32 @@ private:
std::queue<RefPtr<nr_udp_message> > received_msgs_;
nsMainThreadPtrHandle<nsIUDPSocketChild> socket_child_;
nsCOMPtr<nsIEventTarget> sts_thread_;
const nsCOMPtr<nsIEventTarget> main_thread_;
ReentrantMonitor monitor_;
};
+// The socket child holds onto one of these, which just passes callbacks
+// through and makes sure the ref to the NrSocketIpc is released on STS.
+class NrSocketIpcProxy : public nsIUDPSocketInternal {
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+ NS_DECL_NSIUDPSOCKETINTERNAL
+
+ nsresult Init(const nsRefPtr<NrSocketIpc>& socket);
+
+private:
+ virtual ~NrSocketIpcProxy();
+
+ nsRefPtr<NrSocketIpc> socket_;
+ nsCOMPtr<nsIEventTarget> sts_thread_;
+};
+
int nr_netaddr_to_transport_addr(const net::NetAddr *netaddr,
nr_transport_addr *addr,
int protocol);
int nr_praddr_to_transport_addr(const PRNetAddr *praddr,
nr_transport_addr *addr,
int protocol, int keep);
int nr_transport_addr_get_addrstring_and_port(nr_transport_addr *addr,
nsACString *host, int32_t *port);
--- a/media/mtransport/runnable_utils.h
+++ b/media/mtransport/runnable_utils.h
@@ -91,11 +91,30 @@ RUN_ON_THREAD(nsIEventTarget *thread, de
MOZ_ASSERT(NS_SUCCEEDED(rv)); \
MOZ_ASSERT(on); \
} \
} while(0)
#else
#define ASSERT_ON_THREAD(t)
#endif
+template <class T>
+class DispatchedRelease : public detail::runnable_args_base<detail::NoResult> {
+public:
+ explicit DispatchedRelease(already_AddRefed<T>& ref) : ref_(ref) {}
+
+ NS_IMETHOD Run() {
+ ref_ = nullptr;
+ return NS_OK;
+ }
+private:
+ nsRefPtr<T> ref_;
+};
+
+template <typename T>
+DispatchedRelease<T>* WrapRelease(already_AddRefed<T>&& ref)
+{
+ return new DispatchedRelease<T>(ref);
+}
+
} /* namespace mozilla */
#endif
--- a/media/mtransport/third_party/nICEr/src/stun/stun_server_ctx.c
+++ b/media/mtransport/third_party/nICEr/src/stun/stun_server_ctx.c
@@ -104,16 +104,17 @@ static int nr_stun_server_client_create(
ABORT(R_NO_MEMORY);
if(!(clnt->username=r_strdup(user)))
ABORT(R_NO_MEMORY);
if(r=r_data_copy(&clnt->password,pass))
ABORT(r);
+ r_log(NR_LOG_STUN,LOG_DEBUG,"STUN-SERVER(%s)/CLIENT(%s): Adding client for %s",ctx->label, client_label, user);
clnt->stun_server_cb=cb;
clnt->cb_arg=cb_arg;
*clntp = clnt;
_status=0;
abort:
if(_status){
nr_stun_server_destroy_client(clnt);
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.cpp
@@ -208,16 +208,17 @@ PeerConnectionImpl* PeerConnectionImpl::
NS_IMETHODIMP PeerConnectionMedia::ProtocolProxyQueryHandler::
OnProxyAvailable(nsICancelable *request,
nsIChannel *aChannel,
nsIProxyInfo *proxyinfo,
nsresult result) {
CSFLogInfo(logTag, "%s: Proxy Available: %d", __FUNCTION__, (int)result);
if (NS_SUCCEEDED(result) && proxyinfo) {
+ CSFLogInfo(logTag, "%s: Had proxyinfo", __FUNCTION__);
nsresult rv;
nsCString httpsProxyHost;
int32_t httpsProxyPort;
rv = proxyinfo->GetHost(httpsProxyHost);
if (NS_FAILED(rv)) {
CSFLogError(logTag, "%s: Failed to get proxy server host", __FUNCTION__);
return rv;
@@ -238,17 +239,17 @@ OnProxyAvailable(nsICancelable *request,
CSFLogError(logTag, "%s: Failed to set proxy server (ICE ctx unavailable)",
__FUNCTION__);
}
}
if (result != NS_ERROR_ABORT) {
// NS_ERROR_ABORT means that the PeerConnectionMedia is no longer waiting
pcm_->mProxyResolveCompleted = true;
- pcm_->GatherIfReady();
+ pcm_->FlushIceCtxOperationQueueIfReady();
}
return NS_OK;
}
NS_IMPL_ISUPPORTS(PeerConnectionMedia::ProtocolProxyQueryHandler, nsIProtocolProxyCallback)
PeerConnectionMedia::PeerConnectionMedia(PeerConnectionImpl *parent)
@@ -256,17 +257,16 @@ PeerConnectionMedia::PeerConnectionMedia
mParentHandle(parent->GetHandle()),
mParentName(parent->GetName()),
mAllowIceLoopback(false),
mIceCtx(nullptr),
mDNSResolver(new mozilla::NrIceResolver()),
mUuidGen(MakeUnique<PCUuidGenerator>()),
mMainThread(mParent->GetMainThread()),
mSTSThread(mParent->GetSTSThread()),
- mTransportsUpdated(false),
mProxyResolveCompleted(false) {
nsresult rv;
nsCOMPtr<nsIProtocolProxyService> pps =
do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
if (NS_FAILED(rv)) {
CSFLogError(logTag, "%s: Failed to get proxy service: %d", __FUNCTION__, (int)rv);
return;
@@ -395,17 +395,16 @@ PeerConnectionMedia::UpdateTransports(co
pwd,
candidates),
NS_DISPATCH_NORMAL);
}
// TODO(bug 1017888): Need to deal properly with renegotatiation.
// For now just start gathering.
- mTransportsUpdated = true;
GatherIfReady();
}
nsresult PeerConnectionMedia::UpdateMediaPipelines(
const mozilla::JsepSession& session) {
size_t numPairs = session.GetNegotiatedTrackPairCount();
mozilla::MediaPipelineFactory factory(this);
const mozilla::JsepTrackPair* pair;
@@ -462,26 +461,27 @@ PeerConnectionMedia::StartIceChecks(cons
} else {
CSFLogDebug(logTag, "Transport %u has %u components",
static_cast<unsigned>(i),
static_cast<unsigned>(transport->mComponents));
numComponentsByLevel.push_back(transport->mComponents);
}
}
- RUN_ON_THREAD(GetSTSThread(),
- WrapRunnable(
- RefPtr<PeerConnectionMedia>(this),
- &PeerConnectionMedia::StartIceChecks_s,
- session.IsIceControlling(),
- session.RemoteIsIceLite(),
- // Copy, just in case API changes to return a ref
- std::vector<std::string>(session.GetIceOptions()),
- numComponentsByLevel),
- NS_DISPATCH_NORMAL);
+ nsRefPtr<nsIRunnable> runnable(
+ WrapRunnable(
+ RefPtr<PeerConnectionMedia>(this),
+ &PeerConnectionMedia::StartIceChecks_s,
+ session.IsIceControlling(),
+ session.RemoteIsIceLite(),
+ // Copy, just in case API changes to return a ref
+ std::vector<std::string>(session.GetIceOptions()),
+ numComponentsByLevel));
+
+ PerformOrEnqueueIceCtxOperation(runnable);
}
void
PeerConnectionMedia::StartIceChecks_s(
bool aIsControlling,
bool aIsIceLite,
const std::vector<std::string>& aIceOptionsList,
const std::vector<size_t>& aComponentCountByLevel) {
@@ -552,26 +552,52 @@ PeerConnectionMedia::AddIceCandidate_s(c
if (NS_FAILED(rv)) {
CSFLogError(logTag, "Couldn't process ICE candidate at level %u",
aMLine);
return;
}
}
void
+PeerConnectionMedia::FlushIceCtxOperationQueueIfReady()
+{
+ ASSERT_ON_THREAD(mMainThread);
+
+ if (IsIceCtxReady()) {
+ for (auto i = mQueuedIceCtxOperations.begin();
+ i != mQueuedIceCtxOperations.end();
+ ++i) {
+ GetSTSThread()->Dispatch(*i, NS_DISPATCH_NORMAL);
+ }
+ mQueuedIceCtxOperations.clear();
+ }
+}
+
+void
+PeerConnectionMedia::PerformOrEnqueueIceCtxOperation(
+ const nsRefPtr<nsIRunnable>& runnable)
+{
+ ASSERT_ON_THREAD(mMainThread);
+
+ if (IsIceCtxReady()) {
+ GetSTSThread()->Dispatch(runnable, NS_DISPATCH_NORMAL);
+ } else {
+ mQueuedIceCtxOperations.push_back(runnable);
+ }
+}
+
+void
PeerConnectionMedia::GatherIfReady() {
ASSERT_ON_THREAD(mMainThread);
- if (mTransportsUpdated && mProxyResolveCompleted) {
- RUN_ON_THREAD(GetSTSThread(),
- WrapRunnable(
- RefPtr<PeerConnectionMedia>(this),
- &PeerConnectionMedia::EnsureIceGathering_s),
- NS_DISPATCH_NORMAL);
- }
+ nsRefPtr<nsIRunnable> runnable(WrapRunnable(
+ RefPtr<PeerConnectionMedia>(this),
+ &PeerConnectionMedia::EnsureIceGathering_s));
+
+ PerformOrEnqueueIceCtxOperation(runnable);
}
void
PeerConnectionMedia::EnsureIceGathering_s() {
if (mIceCtx->gathering_state() == NrIceCtx::ICE_CTX_GATHER_INIT) {
if (mProxyServer) {
mIceCtx->SetProxyServer(*mProxyServer);
}
--- a/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
+++ b/media/webrtc/signaling/src/peerconnection/PeerConnectionMedia.h
@@ -461,16 +461,18 @@ class PeerConnectionMedia : public sigsl
// Manage ICE transports.
void UpdateIceMediaStream_s(size_t aMLine, size_t aComponentCount,
bool aHasAttrs,
const std::string& aUfrag,
const std::string& aPassword,
const std::vector<std::string>& aCandidateList);
void GatherIfReady();
+ void FlushIceCtxOperationQueueIfReady();
+ void PerformOrEnqueueIceCtxOperation(const nsRefPtr<nsIRunnable>& runnable);
void EnsureIceGathering_s();
void StartIceChecks_s(bool aIsControlling,
bool aIsIceLite,
const std::vector<std::string>& aIceOptionsList,
const std::vector<size_t>& aComponentCountByLevel);
// Process a trickle ICE candidate.
void AddIceCandidate_s(const std::string& aCandidate, const std::string& aMid,
@@ -492,16 +494,19 @@ class PeerConnectionMedia : public sigsl
void IceGatheringStateChange_m(mozilla::NrIceCtx* ctx,
mozilla::NrIceCtx::GatheringState state);
void IceConnectionStateChange_m(mozilla::NrIceCtx* ctx,
mozilla::NrIceCtx::ConnectionState state);
void OnCandidateFound_m(const std::string &candidate, uint16_t aMLine);
void EndOfLocalCandidates_m(const std::string& aDefaultAddr,
uint16_t aDefaultPort,
uint16_t aMLine);
+ bool IsIceCtxReady() const {
+ return mProxyResolveCompleted;
+ }
// The parent PC
PeerConnectionImpl *mParent;
// and a loose handle on it for event driven stuff
std::string mParentHandle;
std::string mParentName;
@@ -534,18 +539,21 @@ class PeerConnectionMedia : public sigsl
mozilla::UniquePtr<PCUuidGenerator> mUuidGen;
// The main thread.
nsCOMPtr<nsIThread> mMainThread;
// The STS thread.
nsCOMPtr<nsIEventTarget> mSTSThread;
- // Used to track when transports are updated and are ready to start gathering
- bool mTransportsUpdated;
+ // Used whenever we need to dispatch a runnable to STS to tweak something
+ // on our ICE ctx, but are not ready to do so at the moment (eg; we are
+ // waiting to get a callback with our http proxy config before we start
+ // gathering or start checking)
+ std::vector<nsRefPtr<nsIRunnable>> mQueuedIceCtxOperations;
// Used to cancel any ongoing proxy request.
nsCOMPtr<nsICancelable> mProxyRequest;
// Used to track the state of the request.
bool mProxyResolveCompleted;
// Used to store the result of the request.
--- a/mozglue/build/WindowsDllBlocklist.cpp
+++ b/mozglue/build/WindowsDllBlocklist.cpp
@@ -154,16 +154,22 @@ static DllBlockInfo sWindowsDllBlocklist
{ "libredir2.dll", 0x5385B7ED, DllBlockInfo::USE_TIMESTAMP },
// Crashes with RoboForm2Go written against old SDK, bug 988311
{ "rf-firefox-22.dll", ALL_VERSIONS },
// Crashes with DesktopTemperature, bug 1046382
{ "dtwxsvc.dll", 0x53153234, DllBlockInfo::USE_TIMESTAMP },
+ // Startup crashes with Lenovo Onekey Theater, bug 1123778
+ { "activedetect32.dll", UNVERSIONED },
+ { "activedetect64.dll", UNVERSIONED },
+ { "windowsapihookdll32.dll", UNVERSIONED },
+ { "windowsapihookdll64.dll", UNVERSIONED },
+
{ nullptr, 0 }
};
#ifndef STATUS_DLL_NOT_FOUND
#define STATUS_DLL_NOT_FOUND ((DWORD)0xC0000135L)
#endif
// define this for very verbose dll load debug spew
--- a/netwerk/cache2/CacheFile.cpp
+++ b/netwerk/cache2/CacheFile.cpp
@@ -607,18 +607,19 @@ CacheFile::OnMetadataWritten(nsresult aR
LOG(("CacheFile::OnMetadataWritten() [this=%p, rv=0x%08x]", this, aResult));
MOZ_ASSERT(mWritingMetadata);
mWritingMetadata = false;
MOZ_ASSERT(!mMemoryOnly);
MOZ_ASSERT(!mOpeningFile);
- if (NS_FAILED(aResult)) {
+ if (NS_WARN_IF(NS_FAILED(aResult))) {
// TODO close streams with an error ???
+ SetError(aResult);
}
if (mOutput || mInputs.Length() || mChunks.Count())
return NS_OK;
if (IsDirty())
WriteMetadataIfNeededLocked();
--- a/netwerk/cache2/CacheFileIOManager.cpp
+++ b/netwerk/cache2/CacheFileIOManager.cpp
@@ -701,16 +701,20 @@ public:
nsresult rv;
MOZ_EVENT_TRACER_EXEC(static_cast<nsIRunnable*>(this), "net::cache::write-background");
if (mHandle->IsClosed()) {
rv = NS_ERROR_NOT_INITIALIZED;
} else {
rv = CacheFileIOManager::gInstance->WriteInternal(
mHandle, mOffset, mBuf, mCount, mValidate);
+ if (NS_FAILED(rv) && !mCallback) {
+ // No listener is going to handle the error, doom the file
+ CacheFileIOManager::gInstance->DoomFileInternal(mHandle);
+ }
}
MOZ_EVENT_TRACER_DONE(static_cast<nsIRunnable*>(this), "net::cache::write-background");
MOZ_EVENT_TRACER_EXEC(static_cast<nsIRunnable*>(this), "net::cache::write-result");
if (mCallback) {
mCallback->OnDataWritten(mHandle, mBuf, rv);
} else {
free(const_cast<char *>(mBuf));
--- a/security/pkix/test/gtest/pkixbuild_tests.cpp
+++ b/security/pkix/test/gtest/pkixbuild_tests.cpp
@@ -137,17 +137,17 @@ private:
}
Result IsChainValid(const DERArray&, Time) override
{
return Success;
}
Result VerifySignedData(const SignedDataWithSignature& signedData,
- Input subjectPublicKeyInfo)
+ Input subjectPublicKeyInfo) override
{
return TestVerifySignedData(signedData, subjectPublicKeyInfo);
}
Result DigestBuf(Input item, /*out*/ uint8_t *digestBuf, size_t digestBufLen)
override
{
ADD_FAILURE();
--- a/services/sync/tests/unit/head_helpers.js
+++ b/services/sync/tests/unit/head_helpers.js
@@ -1,13 +1,14 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
Cu.import("resource://services-common/async.js");
Cu.import("resource://testing-common/services/common/utils.js");
+Cu.import("resource://testing-common/PlacesTestUtils.jsm");
let provider = {
getFile: function(prop, persistent) {
persistent.value = true;
switch (prop) {
case "ExtPrefDL":
return [Services.dirsvc.get("CurProcD", Ci.nsIFile)];
default:
--- a/services/sync/tests/unit/test_history_engine.js
+++ b/services/sync/tests/unit/test_history_engine.js
@@ -1,30 +1,32 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
-Cu.import("resource://gre/modules/PlacesUtils.jsm");
Cu.import("resource://services-sync/constants.js");
Cu.import("resource://services-sync/engines/history.js");
Cu.import("resource://services-sync/engines.js");
Cu.import("resource://services-sync/identity.js");
Cu.import("resource://services-sync/record.js");
Cu.import("resource://services-sync/service.js");
Cu.import("resource://services-sync/util.js");
Cu.import("resource://testing-common/services/sync/utils.js");
Service.engineManager.clear();
+add_test(function test_setup() {
+ PlacesTestUtils.clearHistory().then(run_next_test);
+});
+
add_test(function test_processIncoming_mobile_history_batched() {
_("SyncEngine._processIncoming works on history engine.");
let FAKE_DOWNLOAD_LIMIT = 100;
Svc.Prefs.set("client.type", "mobile");
- PlacesUtils.history.removeAllPages();
Service.engineManager.register(HistoryEngine);
// A collection that logs each GET
let collection = new ServerCollection();
collection.get_log = [];
collection._get = collection.get;
collection.get = function (options) {
this.get_log.push(options);
@@ -125,20 +127,21 @@ add_test(function test_processIncoming_m
do_check_eq(collection.get_log[j].limit, undefined);
if (i < Math.floor((234 - 50) / MOBILE_BATCH_SIZE))
do_check_eq(collection.get_log[j].ids.length, MOBILE_BATCH_SIZE);
else
do_check_eq(collection.get_log[j].ids.length, 234 % MOBILE_BATCH_SIZE);
}
} finally {
- PlacesUtils.history.removeAllPages();
- server.stop(do_test_finished);
- Svc.Prefs.resetBranch("");
- Service.recordManager.clearCache();
+ PlacesTestUtils.clearHistory().then(() => {
+ server.stop(do_test_finished);
+ Svc.Prefs.resetBranch("");
+ Service.recordManager.clearCache();
+ });
}
});
function run_test() {
generateNewKeys(Service.collectionKeys);
run_next_test();
}
--- a/services/sync/tests/unit/test_history_store.js
+++ b/services/sync/tests/unit/test_history_store.js
@@ -57,17 +57,17 @@ function onNextTitleChanged(callback) {
// Ensure exceptions from inside callbacks leads to test failures while
// we still clean up properly.
function ensureThrows(func) {
return function() {
try {
func.apply(this, arguments);
} catch (ex) {
- PlacesUtils.history.removeAllPages();
+ PlacesTestUtils.clearHistory();
do_throw(ex);
}
};
}
let store = new HistoryEngine(Service)._store;
function applyEnsureNoFailures(records) {
do_check_eq(store.applyIncomingBatch(records).length, 0);
@@ -295,11 +295,10 @@ add_test(function test_remove() {
do_check_eq(queryres.length, 0);
queryres = queryHistoryVisits(tburi);
do_check_eq(queryres.length, 0);
run_next_test();
});
add_test(function cleanup() {
_("Clean up.");
- PlacesUtils.history.removeAllPages();
- run_next_test();
+ PlacesTestUtils.clearHistory().then(run_next_test);
});
--- a/services/sync/tests/unit/test_history_tracker.js
+++ b/services/sync/tests/unit/test_history_tracker.js
@@ -194,11 +194,10 @@ add_test(function test_stop_tracking_twi
Utils.nextTick(function() {
do_check_empty(tracker.changedIDs);
run_next_test();
});
});
add_test(function cleanup() {
_("Clean up.");
- PlacesUtils.history.removeAllPages();
- run_next_test();
+ PlacesTestUtils.clearHistory().then(run_next_test);
});
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -907,34 +907,50 @@ public:
if (mHistory->IsShuttingDown()) {
// If we were already shutting down, we cannot insert the URIs.
return NS_OK;
}
mozStorageTransaction transaction(mDBConn, false,
mozIStorageConnection::TRANSACTION_IMMEDIATE);
- VisitData* lastPlace = nullptr;
+ VisitData* lastFetchedPlace = nullptr;
for (nsTArray<VisitData>::size_type i = 0; i < mPlaces.Length(); i++) {
VisitData& place = mPlaces.ElementAt(i);
VisitData& referrer = mReferrers.ElementAt(i);
+ // Fetching from the database can overwrite this information, so save it
+ // apart.
+ bool typed = place.typed;
+ bool hidden = place.hidden;
+
// We can avoid a database lookup if it's the same place as the last
// visit we added.
- bool known = lastPlace && lastPlace->IsSamePlaceAs(place);
+ bool known = lastFetchedPlace && lastFetchedPlace->IsSamePlaceAs(place);
if (!known) {
nsresult rv = mHistory->FetchPageInfo(place, &known);
if (NS_FAILED(rv)) {
if (!!mCallback) {
nsCOMPtr<nsIRunnable> event =
new NotifyPlaceInfoCallback(mCallback, place, true, rv);
return NS_DispatchToMainThread(event);
}
return NS_OK;
}
+ lastFetchedPlace = &mPlaces.ElementAt(i);
+ }
+
+ // If any transition is typed, ensure the page is marked as typed.
+ if (typed != lastFetchedPlace->typed) {
+ place.typed = true;
+ }
+
+ // If any transition is visible, ensure the page is marked as visible.
+ if (hidden != lastFetchedPlace->hidden) {
+ place.hidden = false;
}
FetchReferrerInfo(referrer, place);
nsresult rv = DoDatabaseInserts(known, place, referrer);
if (!!mCallback) {
nsCOMPtr<nsIRunnable> event =
new NotifyPlaceInfoCallback(mCallback, place, true, rv);
@@ -948,18 +964,16 @@ public:
NS_ENSURE_SUCCESS(rv, rv);
// Notify about title change if needed.
if ((!known && !place.title.IsVoid()) || place.titleChanged) {
event = new NotifyTitleObservers(place.spec, place.title, place.guid);
rv = NS_DispatchToMainThread(event);
NS_ENSURE_SUCCESS(rv, rv);
}
-
- lastPlace = &mPlaces.ElementAt(i);
}
nsresult rv = transaction.Commit();
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
private:
@@ -2286,34 +2300,25 @@ History::FetchPageInfo(VisitData& _place
_place.title = title;
}
// Otherwise, just indicate if the title has changed.
else {
_place.titleChanged = !(_place.title.Equals(title) ||
(_place.title.IsEmpty() && title.IsVoid()));
}
- if (_place.hidden) {
- // If this transition was hidden, it is possible that others were not.
- // Any one visible transition makes this location visible. If database
- // has location as visible, reflect that in our data structure.
- int32_t hidden;
- rv = stmt->GetInt32(3, &hidden);
- NS_ENSURE_SUCCESS(rv, rv);
- _place.hidden = !!hidden;
- }
-
- if (!_place.typed) {
- // If this transition wasn't typed, others might have been. If database
- // has location as typed, reflect that in our data structure.
- int32_t typed;
- rv = stmt->GetInt32(4, &typed);
- NS_ENSURE_SUCCESS(rv, rv);
- _place.typed = !!typed;
- }
+ int32_t hidden;
+ rv = stmt->GetInt32(3, &hidden);
+ NS_ENSURE_SUCCESS(rv, rv);
+ _place.hidden = !!hidden;
+
+ int32_t typed;
+ rv = stmt->GetInt32(4, &typed);
+ NS_ENSURE_SUCCESS(rv, rv);
+ _place.typed = !!typed;
rv = stmt->GetInt32(5, &_place.frecency);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
MOZ_DEFINE_MALLOC_SIZE_OF(HistoryMallocSizeOf)
--- a/toolkit/components/places/tests/unit/test_async_history_api.js
+++ b/toolkit/components/places/tests/unit/test_async_history_api.js
@@ -19,67 +19,61 @@ const RECENT_EVENT_THRESHOLD = 15 * 60 *
*
* @param [optional] aTransitionType
* The transition type of the visit. Defaults to TRANSITION_LINK if not
* provided.
* @param [optional] aVisitTime
* The time of the visit. Defaults to now if not provided.
*/
function VisitInfo(aTransitionType,
- aVisitTime)
-{
+ aVisitTime) {
this.transitionType =
aTransitionType === undefined ? TRANSITION_LINK : aTransitionType;
this.visitDate = aVisitTime || Date.now() * 1000;
}
function promiseUpdatePlaces(aPlaces) {
- let deferred = Promise.defer();
- PlacesUtils.asyncHistory.updatePlaces(aPlaces, {
- _errors: [],
- _results: [],
- handleError: function handleError(aResultCode, aPlace) {
- this._errors.push({ resultCode: aResultCode, info: aPlace});
- },
- handleResult: function handleResult(aPlace) {
- this._results.push(aPlace);
- },
- handleCompletion: function handleCompletion() {
- deferred.resolve({ errors: this._errors, results: this._results });
- }
+ return new Promise((resolve, reject) => {
+ PlacesUtils.asyncHistory.updatePlaces(aPlaces, {
+ _errors: [],
+ _results: [],
+ handleError(aResultCode, aPlace) {
+ this._errors.push({ resultCode: aResultCode, info: aPlace});
+ },
+ handleResult(aPlace) {
+ this._results.push(aPlace);
+ },
+ handleCompletion() {
+ resolve({ errors: this._errors, results: this._results });
+ }
+ });
});
-
- return deferred.promise;
}
/**
* Listens for a title change notification, and calls aCallback when it gets it.
*
* @param aURI
* The URI of the page we expect a notification for.
* @param aExpectedTitle
* The expected title of the URI we expect a notification for.
* @param aCallback
* The method to call when we have gotten the proper notification about
* the title changing.
*/
function TitleChangedObserver(aURI,
aExpectedTitle,
- aCallback)
-{
+ aCallback) {
this.uri = aURI;
this.expectedTitle = aExpectedTitle;
this.callback = aCallback;
}
TitleChangedObserver.prototype = {
__proto__: NavHistoryObserver.prototype,
- onTitleChanged: function(aURI,
- aTitle,
- aGUID)
- {
+ onTitleChanged(aURI, aTitle, aGUID) {
do_log_info("onTitleChanged(" + aURI.spec + ", " + aTitle + ", " + aGUID + ")");
if (!this.uri.equals(aURI)) {
return;
}
do_check_eq(aTitle, this.expectedTitle);
do_check_guid_for_uri(aURI, aGUID);
this.callback();
},
@@ -143,24 +137,22 @@ function do_check_title_for_uri(aURI,
do_check_true(stmt.executeStep(), stack);
do_check_eq(stmt.row.title, aTitle, stack);
stmt.finalize();
}
////////////////////////////////////////////////////////////////////////////////
//// Test Functions
-function test_interface_exists()
-{
+add_task(function* test_interface_exists() {
let history = Cc["@mozilla.org/browser/history;1"].getService(Ci.nsISupports);
do_check_true(history instanceof Ci.mozIAsyncHistory);
-}
+});
-function test_invalid_uri_throws()
-{
+add_task(function* test_invalid_uri_throws() {
// First, test passing in nothing.
let place = {
visits: [
new VisitInfo(),
],
};
try {
yield promiseUpdatePlaces(place);
@@ -183,20 +175,19 @@ function test_invalid_uri_throws()
try {
yield promiseUpdatePlaces(place);
do_throw("Should have thrown!");
}
catch (e) {
do_check_eq(e.result, Cr.NS_ERROR_INVALID_ARG);
}
}
-}
+});
-function test_invalid_places_throws()
-{
+add_task(function* test_invalid_places_throws() {
// First, test passing in nothing.
try {
PlacesUtils.asyncHistory.updatePlaces();
do_throw("Should have thrown!");
}
catch (e) {
do_check_eq(e.result, Cr.NS_ERROR_XPC_NOT_ENOUGH_ARGS);
}
@@ -214,20 +205,19 @@ function test_invalid_places_throws()
try {
yield promiseUpdatePlaces(value);
do_throw("Should have thrown!");
}
catch (e) {
do_check_eq(e.result, Cr.NS_ERROR_INVALID_ARG);
}
}
-}
+});
-function test_invalid_guid_throws()
-{
+add_task(function* test_invalid_guid_throws() {
// First check invalid length guid.
let place = {
guid: "BAD_GUID",
uri: NetUtil.newURI(TEST_DOMAIN + "test_invalid_guid_throws"),
visits: [
new VisitInfo(),
],
};
@@ -244,20 +234,19 @@ function test_invalid_guid_throws()
do_check_eq(place.guid.length, 12);
try {
yield promiseUpdatePlaces(place);
do_throw("Should have thrown!");
}
catch (e) {
do_check_eq(e.result, Cr.NS_ERROR_INVALID_ARG);
}
-}
+});
-function test_no_visits_throws()
-{
+add_task(function* test_no_visits_throws() {
const TEST_URI =
NetUtil.newURI(TEST_DOMAIN + "test_no_id_or_guid_no_visits_throws");
const TEST_GUID = "_RANDOMGUID_";
const TEST_PLACEID = 2;
let log_test_conditions = function(aPlace) {
let str = "Testing place with " +
(aPlace.uri ? "uri" : "no uri") + ", " +
@@ -285,56 +274,53 @@ function test_no_visits_throws()
do_throw("Should have thrown!");
}
catch (e) {
do_check_eq(e.result, Cr.NS_ERROR_INVALID_ARG);
}
}
}
}
-}
+});
-function test_add_visit_no_date_throws()
-{
+add_task(function* test_add_visit_no_date_throws() {
let place = {
uri: NetUtil.newURI(TEST_DOMAIN + "test_add_visit_no_date_throws"),
visits: [
new VisitInfo(),
],
};
delete place.visits[0].visitDate;
try {
yield promiseUpdatePlaces(place);
do_throw("Should have thrown!");
}
catch (e) {
do_check_eq(e.result, Cr.NS_ERROR_INVALID_ARG);
}
-}
+});
-function test_add_visit_no_transitionType_throws()
-{
+add_task(function* test_add_visit_no_transitionType_throws() {
let place = {
uri: NetUtil.newURI(TEST_DOMAIN + "test_add_visit_no_transitionType_throws"),
visits: [
new VisitInfo(),
],
};
delete place.visits[0].transitionType;
try {
yield promiseUpdatePlaces(place);
do_throw("Should have thrown!");
}
catch (e) {
do_check_eq(e.result, Cr.NS_ERROR_INVALID_ARG);
}
-}
+});
-function test_add_visit_invalid_transitionType_throws()
-{
+add_task(function* test_add_visit_invalid_transitionType_throws() {
// First, test something that has a transition type lower than the first one.
let place = {
uri: NetUtil.newURI(TEST_DOMAIN +
"test_add_visit_invalid_transitionType_throws"),
visits: [