diff --git a/accessible/windows/msaa/AccessibleWrap.h b/accessible/windows/msaa/AccessibleWrap.h index c35bd9eb862..26a94f69463 100644 --- a/accessible/windows/msaa/AccessibleWrap.h +++ b/accessible/windows/msaa/AccessibleWrap.h @@ -41,118 +41,118 @@ public: // construction, destruction NS_DECL_ISUPPORTS_INHERITED public: // IUnknown methods - see iunknown.h for documentation - STDMETHODIMP QueryInterface(REFIID, void**); + STDMETHODIMP QueryInterface(REFIID, void**) override; // Return the registered OLE class ID of this object's CfDataObj. CLSID GetClassID() const; public: // COM interface IAccessible virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accParent( - /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispParent); + /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispParent) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChildCount( - /* [retval][out] */ long __RPC_FAR *pcountChildren); + /* [retval][out] */ long __RPC_FAR *pcountChildren) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accChild( /* [in] */ VARIANT varChild, - /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild); + /* [retval][out] */ IDispatch __RPC_FAR *__RPC_FAR *ppdispChild) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accName( /* [optional][in] */ VARIANT varChild, - /* [retval][out] */ BSTR __RPC_FAR *pszName); + /* [retval][out] */ BSTR __RPC_FAR *pszName) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accValue( /* [optional][in] */ VARIANT varChild, - /* [retval][out] */ BSTR __RPC_FAR *pszValue); + /* [retval][out] */ BSTR __RPC_FAR *pszValue) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accDescription( /* [optional][in] */ VARIANT varChild, - /* [retval][out] */ BSTR __RPC_FAR *pszDescription); + /* [retval][out] */ BSTR __RPC_FAR *pszDescription) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accRole( /* [optional][in] */ VARIANT varChild, - /* [retval][out] */ VARIANT __RPC_FAR *pvarRole); + /* [retval][out] */ VARIANT __RPC_FAR *pvarRole) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accState( /* [optional][in] */ VARIANT varChild, - /* [retval][out] */ VARIANT __RPC_FAR *pvarState); + /* [retval][out] */ VARIANT __RPC_FAR *pvarState) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accHelp( /* [optional][in] */ VARIANT varChild, - /* [retval][out] */ BSTR __RPC_FAR *pszHelp); + /* [retval][out] */ BSTR __RPC_FAR *pszHelp) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accHelpTopic( /* [out] */ BSTR __RPC_FAR *pszHelpFile, /* [optional][in] */ VARIANT varChild, - /* [retval][out] */ long __RPC_FAR *pidTopic); + /* [retval][out] */ long __RPC_FAR *pidTopic) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accKeyboardShortcut( /* [optional][in] */ VARIANT varChild, - /* [retval][out] */ BSTR __RPC_FAR *pszKeyboardShortcut); + /* [retval][out] */ BSTR __RPC_FAR *pszKeyboardShortcut) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accFocus( - /* [retval][out] */ VARIANT __RPC_FAR *pvarChild); + /* [retval][out] */ VARIANT __RPC_FAR *pvarChild) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accSelection( - /* [retval][out] */ VARIANT __RPC_FAR *pvarChildren); + /* [retval][out] */ VARIANT __RPC_FAR *pvarChildren) override; virtual /* [id][propget] */ HRESULT STDMETHODCALLTYPE get_accDefaultAction( /* [optional][in] */ VARIANT varChild, - /* [retval][out] */ BSTR __RPC_FAR *pszDefaultAction); + /* [retval][out] */ BSTR __RPC_FAR *pszDefaultAction) override; virtual /* [id] */ HRESULT STDMETHODCALLTYPE accSelect( /* [in] */ long flagsSelect, - /* [optional][in] */ VARIANT varChild); + /* [optional][in] */ VARIANT varChild) override; virtual /* [id] */ HRESULT STDMETHODCALLTYPE accLocation( /* [out] */ long __RPC_FAR *pxLeft, /* [out] */ long __RPC_FAR *pyTop, /* [out] */ long __RPC_FAR *pcxWidth, /* [out] */ long __RPC_FAR *pcyHeight, - /* [optional][in] */ VARIANT varChild); + /* [optional][in] */ VARIANT varChild) override; virtual /* [id] */ HRESULT STDMETHODCALLTYPE accNavigate( /* [in] */ long navDir, /* [optional][in] */ VARIANT varStart, - /* [retval][out] */ VARIANT __RPC_FAR *pvarEndUpAt); + /* [retval][out] */ VARIANT __RPC_FAR *pvarEndUpAt) override; virtual /* [id] */ HRESULT STDMETHODCALLTYPE accHitTest( /* [in] */ long xLeft, /* [in] */ long yTop, - /* [retval][out] */ VARIANT __RPC_FAR *pvarChild); + /* [retval][out] */ VARIANT __RPC_FAR *pvarChild) override; virtual /* [id] */ HRESULT STDMETHODCALLTYPE accDoDefaultAction( - /* [optional][in] */ VARIANT varChild); + /* [optional][in] */ VARIANT varChild) override; virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_accName( /* [optional][in] */ VARIANT varChild, - /* [in] */ BSTR szName); + /* [in] */ BSTR szName) override; virtual /* [id][propput] */ HRESULT STDMETHODCALLTYPE put_accValue( /* [optional][in] */ VARIANT varChild, - /* [in] */ BSTR szValue); + /* [in] */ BSTR szValue) override; // IDispatch (support of scripting languages like VB) - virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo); + virtual HRESULT STDMETHODCALLTYPE GetTypeInfoCount(UINT *pctinfo) override; virtual HRESULT STDMETHODCALLTYPE GetTypeInfo(UINT iTInfo, LCID lcid, - ITypeInfo **ppTInfo); + ITypeInfo **ppTInfo) override; virtual HRESULT STDMETHODCALLTYPE GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, - DISPID *rgDispId); + DISPID *rgDispId) override; virtual HRESULT STDMETHODCALLTYPE Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, - UINT *puArgErr); + UINT *puArgErr) override; // Accessible - virtual nsresult HandleAccEvent(AccEvent* aEvent); + virtual nsresult HandleAccEvent(AccEvent* aEvent) override; virtual void Shutdown() override; // Helper methods diff --git a/b2g/app/moz.build b/b2g/app/moz.build index 8e9815e4146..e9b2b3afaa5 100644 --- a/b2g/app/moz.build +++ b/b2g/app/moz.build @@ -28,11 +28,8 @@ USE_LIBS += [ for var in ('MOZ_APP_NAME', 'MOZ_APP_VERSION', 'MOZ_UPDATER'): DEFINES[var] = CONFIG[var] -GENERATED_INCLUDES += [ - '/build', -] - LOCAL_INCLUDES += [ + '!/build', '/toolkit/xre', '/xpcom/base', '/xpcom/build', diff --git a/browser/app/moz.build b/browser/app/moz.build index be76aa2ed27..70b1453e7f5 100644 --- a/browser/app/moz.build +++ b/browser/app/moz.build @@ -24,11 +24,8 @@ FINAL_TARGET_FILES.defaults.profile += ['profile/prefs.js'] DEFINES['APP_VERSION'] = CONFIG['MOZ_APP_VERSION'] -GENERATED_INCLUDES += [ - '/build', -] - LOCAL_INCLUDES += [ + '!/build', '/toolkit/xre', '/xpcom/base', '/xpcom/build', diff --git a/browser/components/loop/.eslintrc b/browser/components/loop/.eslintrc index 3b9850e0222..40e0be30386 100644 --- a/browser/components/loop/.eslintrc +++ b/browser/components/loop/.eslintrc @@ -17,6 +17,7 @@ "_": false, "Backbone": false, "chai": false, + "classNames": false, "console": false, "loop": true, "MozActivity": false, diff --git a/browser/components/loop/content/conversation.html b/browser/components/loop/content/conversation.html index aa6b8af8d68..a01f02450fa 100644 --- a/browser/components/loop/content/conversation.html +++ b/browser/components/loop/content/conversation.html @@ -23,6 +23,7 @@ + diff --git a/browser/components/loop/content/js/panel.js b/browser/components/loop/content/js/panel.js index e98c7dfcb26..cb58e863a23 100644 --- a/browser/components/loop/content/js/panel.js +++ b/browser/components/loop/content/js/panel.js @@ -165,7 +165,7 @@ loop.panel = (function(_, mozL10n) { }, render: function() { - var cx = React.addons.classSet; + var cx = classNames; if (!this.props.displayed) { return null; @@ -245,7 +245,7 @@ loop.panel = (function(_, mozL10n) { }, render: function() { - var cx = React.addons.classSet; + var cx = classNames; var accountEntryCSSClass = this._isSignedIn() ? "entry-settings-signout" : "entry-settings-signin"; var notificationsLabel = this.props.mozLoop.doNotDisturb ? "settings_menu_item_turnnotificationson" : @@ -436,7 +436,7 @@ loop.panel = (function(_, mozL10n) { }, render: function() { - var roomClasses = React.addons.classSet({ + var roomClasses = classNames({ "room-entry": true, "room-active": this._isActive(), "room-opened": this.props.isOpenedRoom @@ -588,7 +588,7 @@ loop.panel = (function(_, mozL10n) { }, render: function() { - var dropdownClasses = React.addons.classSet({ + var dropdownClasses = classNames({ "dropdown-menu": true, "dropdown-menu-up": this.state.openDirUp }); diff --git a/browser/components/loop/content/js/panel.jsx b/browser/components/loop/content/js/panel.jsx index a0821b91861..857b5b432f3 100644 --- a/browser/components/loop/content/js/panel.jsx +++ b/browser/components/loop/content/js/panel.jsx @@ -165,7 +165,7 @@ loop.panel = (function(_, mozL10n) { }, render: function() { - var cx = React.addons.classSet; + var cx = classNames; if (!this.props.displayed) { return null; @@ -245,7 +245,7 @@ loop.panel = (function(_, mozL10n) { }, render: function() { - var cx = React.addons.classSet; + var cx = classNames; var accountEntryCSSClass = this._isSignedIn() ? "entry-settings-signout" : "entry-settings-signin"; var notificationsLabel = this.props.mozLoop.doNotDisturb ? "settings_menu_item_turnnotificationson" : @@ -436,7 +436,7 @@ loop.panel = (function(_, mozL10n) { }, render: function() { - var roomClasses = React.addons.classSet({ + var roomClasses = classNames({ "room-entry": true, "room-active": this._isActive(), "room-opened": this.props.isOpenedRoom @@ -588,7 +588,7 @@ loop.panel = (function(_, mozL10n) { }, render: function() { - var dropdownClasses = React.addons.classSet({ + var dropdownClasses = classNames({ "dropdown-menu": true, "dropdown-menu-up": this.state.openDirUp }); diff --git a/browser/components/loop/content/js/roomViews.js b/browser/components/loop/content/js/roomViews.js index ebe91b58cf5..92f4fc31610 100644 --- a/browser/components/loop/content/js/roomViews.js +++ b/browser/components/loop/content/js/roomViews.js @@ -199,7 +199,7 @@ loop.roomViews = (function(mozL10n) { return null; } - var cx = React.addons.classSet; + var cx = classNames; var shareDropdown = cx({ "share-service-dropdown": true, "dropdown-menu": true, @@ -330,7 +330,7 @@ loop.roomViews = (function(mozL10n) { return null; } - var cx = React.addons.classSet; + var cx = classNames; return ( React.createElement("div", {className: "room-invitation-overlay"}, React.createElement("div", {className: "room-invitation-content"}, @@ -546,7 +546,7 @@ loop.roomViews = (function(mozL10n) { var urlDescription = url && url.description || ""; var location = url && url.location || ""; - var cx = React.addons.classSet; + var cx = classNames; var availableContext = this.state.availableContext; return ( React.createElement("div", {className: "room-context"}, diff --git a/browser/components/loop/content/js/roomViews.jsx b/browser/components/loop/content/js/roomViews.jsx index a8349efc58f..de976577092 100644 --- a/browser/components/loop/content/js/roomViews.jsx +++ b/browser/components/loop/content/js/roomViews.jsx @@ -199,7 +199,7 @@ loop.roomViews = (function(mozL10n) { return null; } - var cx = React.addons.classSet; + var cx = classNames; var shareDropdown = cx({ "share-service-dropdown": true, "dropdown-menu": true, @@ -330,7 +330,7 @@ loop.roomViews = (function(mozL10n) { return null; } - var cx = React.addons.classSet; + var cx = classNames; return (
@@ -546,7 +546,7 @@ loop.roomViews = (function(mozL10n) { var urlDescription = url && url.description || ""; var location = url && url.location || ""; - var cx = React.addons.classSet; + var cx = classNames; var availableContext = this.state.availableContext; return (
diff --git a/browser/components/loop/content/panel.html b/browser/components/loop/content/panel.html index 71924073861..3ae4cd4f098 100644 --- a/browser/components/loop/content/panel.html +++ b/browser/components/loop/content/panel.html @@ -17,6 +17,7 @@ + diff --git a/browser/components/loop/content/shared/js/textChatView.js b/browser/components/loop/content/shared/js/textChatView.js index ae6a58ba10b..d0be68cdef9 100644 --- a/browser/components/loop/content/shared/js/textChatView.js +++ b/browser/components/loop/content/shared/js/textChatView.js @@ -48,7 +48,7 @@ loop.shared.views.chat = (function(mozL10n) { }, render: function() { - var classes = React.addons.classSet({ + var classes = classNames({ "text-chat-entry": true, "received": this.props.type === CHAT_MESSAGE_TYPES.RECEIVED, "sent": this.props.type === CHAT_MESSAGE_TYPES.SENT, @@ -165,7 +165,7 @@ loop.shared.views.chat = (function(mozL10n) { /* Keep track of the last printed timestamp. */ var lastTimestamp = 0; - var entriesClasses = React.addons.classSet({ + var entriesClasses = classNames({ "text-chat-entries": true }); @@ -395,7 +395,7 @@ loop.shared.views.chat = (function(mozL10n) { return item.type === CHAT_MESSAGE_TYPES.SENT; }); - var textChatViewClasses = React.addons.classSet({ + var textChatViewClasses = classNames({ "text-chat-view": true, "text-chat-entries-empty": !messageList.length, "text-chat-disabled": !this.state.textChatEnabled diff --git a/browser/components/loop/content/shared/js/textChatView.jsx b/browser/components/loop/content/shared/js/textChatView.jsx index 2d0a9988122..a2b879c72d4 100644 --- a/browser/components/loop/content/shared/js/textChatView.jsx +++ b/browser/components/loop/content/shared/js/textChatView.jsx @@ -48,7 +48,7 @@ loop.shared.views.chat = (function(mozL10n) { }, render: function() { - var classes = React.addons.classSet({ + var classes = classNames({ "text-chat-entry": true, "received": this.props.type === CHAT_MESSAGE_TYPES.RECEIVED, "sent": this.props.type === CHAT_MESSAGE_TYPES.SENT, @@ -165,7 +165,7 @@ loop.shared.views.chat = (function(mozL10n) { /* Keep track of the last printed timestamp. */ var lastTimestamp = 0; - var entriesClasses = React.addons.classSet({ + var entriesClasses = classNames({ "text-chat-entries": true }); @@ -395,7 +395,7 @@ loop.shared.views.chat = (function(mozL10n) { return item.type === CHAT_MESSAGE_TYPES.SENT; }); - var textChatViewClasses = React.addons.classSet({ + var textChatViewClasses = classNames({ "text-chat-view": true, "text-chat-entries-empty": !messageList.length, "text-chat-disabled": !this.state.textChatEnabled diff --git a/browser/components/loop/content/shared/js/views.js b/browser/components/loop/content/shared/js/views.js index d2a5262c917..53a90c95367 100644 --- a/browser/components/loop/content/shared/js/views.js +++ b/browser/components/loop/content/shared/js/views.js @@ -70,7 +70,7 @@ loop.shared.views = (function(_, mozL10n) { }, _getClasses: function() { - var cx = React.addons.classSet; + var cx = classNames; // classes var classesObj = { "btn": true, @@ -170,7 +170,7 @@ loop.shared.views = (function(_, mozL10n) { return null; } - var cx = React.addons.classSet; + var cx = classNames; var isActive = this.props.state === SCREEN_SHARE_STATES.ACTIVE; var screenShareClasses = cx({ @@ -304,7 +304,7 @@ loop.shared.views = (function(_, mozL10n) { * Recover the needed info for generating an specific menu Item */ getItemInfo: function(menuItem) { - var cx = React.addons.classSet; + var cx = classNames; switch (menuItem.id) { case "help": return { @@ -362,7 +362,7 @@ loop.shared.views = (function(_, mozL10n) { return null; } - var cx = React.addons.classSet; + var cx = classNames; var settingsDropdownMenuClasses = cx({ "settings-menu": true, "dropdown-menu": true, @@ -494,7 +494,7 @@ loop.shared.views = (function(_, mozL10n) { return null; } - var cx = React.addons.classSet; + var cx = classNames; var conversationToolbarCssClasses = cx({ "conversation-toolbar": true, "idle": this.state.idle @@ -642,7 +642,7 @@ loop.shared.views = (function(_, mozL10n) { }, render: function() { - var cx = React.addons.classSet; + var cx = classNames; var classObject = { button: true, disabled: this.props.disabled }; if (this.props.additionalClass) { classObject[this.props.additionalClass] = true; @@ -675,7 +675,7 @@ loop.shared.views = (function(_, mozL10n) { }, render: function() { - var cx = React.addons.classSet; + var cx = classNames; var classObject = { "button-group": true }; if (this.props.additionalClass) { classObject[this.props.additionalClass] = true; @@ -742,7 +742,7 @@ loop.shared.views = (function(_, mozL10n) { }, render: function() { - var cx = React.addons.classSet; + var cx = classNames; var wrapperClasses = { "checkbox-wrapper": true, disabled: this.props.disabled @@ -860,7 +860,7 @@ loop.shared.views = (function(_, mozL10n) { "shared/img/icons-16x16.svg#globe"; } - var wrapperClasses = React.addons.classSet({ + var wrapperClasses = classNames({ "context-wrapper": true, "clicks-allowed": this.props.allowClick }); @@ -1076,17 +1076,17 @@ loop.shared.views = (function(_, mozL10n) { }, render: function() { - var remoteStreamClasses = React.addons.classSet({ + var remoteStreamClasses = classNames({ "remote": true, "focus-stream": !this.props.displayScreenShare }); - var screenShareStreamClasses = React.addons.classSet({ + var screenShareStreamClasses = classNames({ "screen": true, "focus-stream": this.props.displayScreenShare }); - var mediaWrapperClasses = React.addons.classSet({ + var mediaWrapperClasses = classNames({ "media-wrapper": true, "receiving-screen-share": this.props.displayScreenShare, "showing-local-streams": this.props.localSrcMediaElement || diff --git a/browser/components/loop/content/shared/js/views.jsx b/browser/components/loop/content/shared/js/views.jsx index b90eaebbf3c..5e8965b0a0b 100644 --- a/browser/components/loop/content/shared/js/views.jsx +++ b/browser/components/loop/content/shared/js/views.jsx @@ -70,7 +70,7 @@ loop.shared.views = (function(_, mozL10n) { }, _getClasses: function() { - var cx = React.addons.classSet; + var cx = classNames; // classes var classesObj = { "btn": true, @@ -170,7 +170,7 @@ loop.shared.views = (function(_, mozL10n) { return null; } - var cx = React.addons.classSet; + var cx = classNames; var isActive = this.props.state === SCREEN_SHARE_STATES.ACTIVE; var screenShareClasses = cx({ @@ -304,7 +304,7 @@ loop.shared.views = (function(_, mozL10n) { * Recover the needed info for generating an specific menu Item */ getItemInfo: function(menuItem) { - var cx = React.addons.classSet; + var cx = classNames; switch (menuItem.id) { case "help": return { @@ -362,7 +362,7 @@ loop.shared.views = (function(_, mozL10n) { return null; } - var cx = React.addons.classSet; + var cx = classNames; var settingsDropdownMenuClasses = cx({ "settings-menu": true, "dropdown-menu": true, @@ -494,7 +494,7 @@ loop.shared.views = (function(_, mozL10n) { return null; } - var cx = React.addons.classSet; + var cx = classNames; var conversationToolbarCssClasses = cx({ "conversation-toolbar": true, "idle": this.state.idle @@ -642,7 +642,7 @@ loop.shared.views = (function(_, mozL10n) { }, render: function() { - var cx = React.addons.classSet; + var cx = classNames; var classObject = { button: true, disabled: this.props.disabled }; if (this.props.additionalClass) { classObject[this.props.additionalClass] = true; @@ -675,7 +675,7 @@ loop.shared.views = (function(_, mozL10n) { }, render: function() { - var cx = React.addons.classSet; + var cx = classNames; var classObject = { "button-group": true }; if (this.props.additionalClass) { classObject[this.props.additionalClass] = true; @@ -742,7 +742,7 @@ loop.shared.views = (function(_, mozL10n) { }, render: function() { - var cx = React.addons.classSet; + var cx = classNames; var wrapperClasses = { "checkbox-wrapper": true, disabled: this.props.disabled @@ -860,7 +860,7 @@ loop.shared.views = (function(_, mozL10n) { "shared/img/icons-16x16.svg#globe"; } - var wrapperClasses = React.addons.classSet({ + var wrapperClasses = classNames({ "context-wrapper": true, "clicks-allowed": this.props.allowClick }); @@ -1076,17 +1076,17 @@ loop.shared.views = (function(_, mozL10n) { }, render: function() { - var remoteStreamClasses = React.addons.classSet({ + var remoteStreamClasses = classNames({ "remote": true, "focus-stream": !this.props.displayScreenShare }); - var screenShareStreamClasses = React.addons.classSet({ + var screenShareStreamClasses = classNames({ "screen": true, "focus-stream": this.props.displayScreenShare }); - var mediaWrapperClasses = React.addons.classSet({ + var mediaWrapperClasses = classNames({ "media-wrapper": true, "receiving-screen-share": this.props.displayScreenShare, "showing-local-streams": this.props.localSrcMediaElement || diff --git a/browser/components/loop/content/shared/libs/classnames-2.2.0.js b/browser/components/loop/content/shared/libs/classnames-2.2.0.js new file mode 100644 index 00000000000..0d336d9cb9c --- /dev/null +++ b/browser/components/loop/content/shared/libs/classnames-2.2.0.js @@ -0,0 +1,48 @@ +/*! + Copyright (c) 2015 Jed Watson. + Licensed under the MIT License (MIT), see + http://jedwatson.github.io/classnames +*/ +/* global define */ + +(function () { + 'use strict'; + + var hasOwn = {}.hasOwnProperty; + + function classNames () { + var classes = ''; + + for (var i = 0; i < arguments.length; i++) { + var arg = arguments[i]; + if (!arg) continue; + + var argType = typeof arg; + + if (argType === 'string' || argType === 'number') { + classes += ' ' + arg; + } else if (Array.isArray(arg)) { + classes += ' ' + classNames.apply(null, arg); + } else if (argType === 'object') { + for (var key in arg) { + if (hasOwn.call(arg, key) && arg[key]) { + classes += ' ' + key; + } + } + } + } + + return classes.substr(1); + } + + if (typeof module !== 'undefined' && module.exports) { + module.exports = classNames; + } else if (typeof define === 'function' && typeof define.amd === 'object' && define.amd) { + // register as 'classnames', consistent with npm package name + define('classnames', function () { + return classNames; + }); + } else { + window.classNames = classNames; + } +}()); diff --git a/browser/components/loop/jar.mn b/browser/components/loop/jar.mn index 0d06c3f801c..083139a3e15 100644 --- a/browser/components/loop/jar.mn +++ b/browser/components/loop/jar.mn @@ -114,6 +114,7 @@ browser.jar: #endif content/browser/loop/shared/libs/lodash-3.9.3.js (content/shared/libs/lodash-3.9.3.js) content/browser/loop/shared/libs/backbone-1.2.1.js (content/shared/libs/backbone-1.2.1.js) + content/browser/loop/shared/libs/classnames-2.2.0.js (content/shared/libs/classnames-2.2.0.js) # Shared sounds content/browser/loop/shared/sounds/ringtone.ogg (content/shared/sounds/ringtone.ogg) diff --git a/browser/components/loop/standalone/content/js/standaloneRoomViews.js b/browser/components/loop/standalone/content/js/standaloneRoomViews.js index ba356a777db..0247f8a8ce9 100644 --- a/browser/components/loop/standalone/content/js/standaloneRoomViews.js +++ b/browser/components/loop/standalone/content/js/standaloneRoomViews.js @@ -80,7 +80,7 @@ loop.standaloneRoomViews = (function(mozL10n) { mozL10n.get("rooms_room_joined_own_conversation_label") : mozL10n.get("rooms_room_join_label"); - var buttonClasses = React.addons.classSet({ + var buttonClasses = classNames({ btn: true, "btn-info": true, disabled: this.state.roomState === ROOM_STATES.JOINED @@ -325,7 +325,7 @@ loop.standaloneRoomViews = (function(mozL10n) { var isChrome = utils.isChrome(navigator.userAgent); var isFirefox = utils.isFirefox(navigator.userAgent); var isOpera = utils.isOpera(navigator.userAgent); - var promptMediaMessageClasses = React.addons.classSet({ + var promptMediaMessageClasses = classNames({ "prompt-media-message": true, "chrome": isChrome, "firefox": isFirefox, diff --git a/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx b/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx index c810d4d7417..077132d241d 100644 --- a/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx +++ b/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx @@ -80,7 +80,7 @@ loop.standaloneRoomViews = (function(mozL10n) { mozL10n.get("rooms_room_joined_own_conversation_label") : mozL10n.get("rooms_room_join_label"); - var buttonClasses = React.addons.classSet({ + var buttonClasses = classNames({ btn: true, "btn-info": true, disabled: this.state.roomState === ROOM_STATES.JOINED @@ -325,7 +325,7 @@ loop.standaloneRoomViews = (function(mozL10n) { var isChrome = utils.isChrome(navigator.userAgent); var isFirefox = utils.isFirefox(navigator.userAgent); var isOpera = utils.isOpera(navigator.userAgent); - var promptMediaMessageClasses = React.addons.classSet({ + var promptMediaMessageClasses = classNames({ "prompt-media-message": true, "chrome": isChrome, "firefox": isFirefox, diff --git a/browser/components/loop/standalone/content/webappEntryPoint.js b/browser/components/loop/standalone/content/webappEntryPoint.js index 8ff77d65664..d8460530117 100644 --- a/browser/components/loop/standalone/content/webappEntryPoint.js +++ b/browser/components/loop/standalone/content/webappEntryPoint.js @@ -38,9 +38,11 @@ if (typeof __PROD__ !== "undefined") { // pull in the unbuilt version from node_modules require("expose?React!react"); require("expose?React!react/addons"); + require("expose?classNames!classnames"); } else { // our development server setup doesn't yet handle real modules, so for now... require("shared/libs/react-0.12.2.js"); + require("shared/libs/classnames-2.2.0.js"); } diff --git a/browser/components/loop/standalone/package.json b/browser/components/loop/standalone/package.json index 961a42691ff..0675f6793d2 100644 --- a/browser/components/loop/standalone/package.json +++ b/browser/components/loop/standalone/package.json @@ -12,6 +12,7 @@ }, "dependencies": {}, "devDependencies": { + "classnames": "2.2.x", "compression": "1.5.x", "eslint": "1.6.x", "eslint-plugin-mozilla": "../../../../testing/eslint-plugin-mozilla", diff --git a/browser/components/loop/test/desktop-local/index.html b/browser/components/loop/test/desktop-local/index.html index d2c924ab21a..1b6446ad0f0 100644 --- a/browser/components/loop/test/desktop-local/index.html +++ b/browser/components/loop/test/desktop-local/index.html @@ -31,6 +31,7 @@ + diff --git a/browser/components/loop/test/karma/karma.coverage.desktop.js b/browser/components/loop/test/karma/karma.coverage.desktop.js index 3ad8a42dd43..8ad6f46eb20 100644 --- a/browser/components/loop/test/karma/karma.coverage.desktop.js +++ b/browser/components/loop/test/karma/karma.coverage.desktop.js @@ -12,6 +12,7 @@ module.exports = function(config) { baseConfig.files = baseConfig.files.concat([ "content/libs/l10n.js", "content/shared/libs/react-0.12.2.js", + "content/shared/libs/classnames-2.2.0.js", "content/shared/libs/lodash-3.9.3.js", "content/shared/libs/backbone-1.2.1.js", "test/shared/vendor/*.js", diff --git a/browser/components/loop/test/karma/karma.coverage.shared_standalone.js b/browser/components/loop/test/karma/karma.coverage.shared_standalone.js index 6f6e40454f9..7d511f42b0e 100644 --- a/browser/components/loop/test/karma/karma.coverage.shared_standalone.js +++ b/browser/components/loop/test/karma/karma.coverage.shared_standalone.js @@ -14,6 +14,7 @@ module.exports = function(config) { "content/shared/libs/lodash-3.9.3.js", "content/shared/libs/backbone-1.2.1.js", "content/shared/libs/react-0.12.2.js", + "content/shared/libs/classnames-2.2.0.js", "content/shared/libs/sdk.js", "test/shared/vendor/*.js", "test/karma/head.js", // Add test fixture container diff --git a/browser/components/loop/test/shared/index.html b/browser/components/loop/test/shared/index.html index 969dc7b3724..507d2f183a4 100644 --- a/browser/components/loop/test/shared/index.html +++ b/browser/components/loop/test/shared/index.html @@ -30,6 +30,7 @@ + diff --git a/browser/components/loop/test/standalone/index.html b/browser/components/loop/test/standalone/index.html index 1094249fd48..00278b91afe 100644 --- a/browser/components/loop/test/standalone/index.html +++ b/browser/components/loop/test/standalone/index.html @@ -31,6 +31,7 @@ + diff --git a/browser/components/loop/ui/index.html b/browser/components/loop/ui/index.html index ea5f205d146..06bbda26cc6 100644 --- a/browser/components/loop/ui/index.html +++ b/browser/components/loop/ui/index.html @@ -28,6 +28,7 @@ + diff --git a/browser/components/loop/ui/ui-showcase.js b/browser/components/loop/ui/ui-showcase.js index 95a139092cd..0b21db52cd3 100644 --- a/browser/components/loop/ui/ui-showcase.js +++ b/browser/components/loop/ui/ui-showcase.js @@ -556,7 +556,7 @@ width += 2; } - var cx = React.addons.classSet; + var cx = classNames; return ( React.createElement("div", {className: "example"}, React.createElement("h3", {id: this.makeId()}, diff --git a/browser/components/loop/ui/ui-showcase.jsx b/browser/components/loop/ui/ui-showcase.jsx index ddf52e12d34..fe8884d6e61 100644 --- a/browser/components/loop/ui/ui-showcase.jsx +++ b/browser/components/loop/ui/ui-showcase.jsx @@ -556,7 +556,7 @@ width += 2; } - var cx = React.addons.classSet; + var cx = classNames; return (

diff --git a/build.gradle b/build.gradle index 7b834f0f0d3..d8ac18b8cdc 100644 --- a/build.gradle +++ b/build.gradle @@ -115,7 +115,6 @@ idea { excludeDirs -= file(topobjdir) excludeDirs += files(file(topobjdir).listFiles()) excludeDirs -= file("${topobjdir}/gradle") - excludeDirs -= file("${topobjdir}/mobile") } if (!mozconfig.substs.MOZ_INSTALL_TRACKING) { diff --git a/build/mach_bootstrap.py b/build/mach_bootstrap.py index 9b24aeb4af4..6d6f6ef453b 100644 --- a/build/mach_bootstrap.py +++ b/build/mach_bootstrap.py @@ -41,25 +41,6 @@ Note: `{mach} mercurial-setup` does not make any changes without prompting you first. '''.strip() -OLD_MERCURIAL_TOOLS = ''' -*** MERCURIAL CONFIGURATION POTENTIALLY OUT OF DATE *** - -mach has detected that it has been a while since you have run -`{mach} mercurial-setup`. - -Having the latest Mercurial tools and configuration should lead to a better, -more productive experience when working on Mozilla projects. - -Please run `{mach} mercurial-setup` now. - -Reminder: `{mach} mercurial-setup` does not make any changes without -prompting you first. - -To avoid this message in the future, run `{mach} mercurial-setup` once a month. -Or, schedule `{mach} mercurial-setup --update-only` to run automatically in -the background at least once a month. -'''.strip() - MERCURIAL_SETUP_FATAL_INTERVAL = 31 * 24 * 60 * 60 @@ -281,9 +262,6 @@ def bootstrap(topsrcdir, mozilla_dir=None): if mtime is None: print(NO_MERCURIAL_SETUP.format(mach=sys.argv[0]), file=sys.stderr) sys.exit(2) - elif time.time() - mtime > MERCURIAL_SETUP_FATAL_INTERVAL: - print(OLD_MERCURIAL_TOOLS.format(mach=sys.argv[0]), file=sys.stderr) - sys.exit(2) def populate_context(context, key=None): if key is None: diff --git a/chrome/moz.build b/chrome/moz.build index c4ee0f64f5f..724f39cb32e 100644 --- a/chrome/moz.build +++ b/chrome/moz.build @@ -28,11 +28,8 @@ include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' -GENERATED_INCLUDES += [ - '/xpcom', -] - LOCAL_INCLUDES += [ + '!/xpcom', '/dom/base', '/netwerk/base', '/netwerk/protocol/res', diff --git a/devtools/client/debugger/test/mochitest/browser.ini b/devtools/client/debugger/test/mochitest/browser.ini index 3083a63cc8f..267de1c9a57 100644 --- a/devtools/client/debugger/test/mochitest/browser.ini +++ b/devtools/client/debugger/test/mochitest/browser.ini @@ -416,7 +416,7 @@ skip-if = e10s && debug [browser_dbg_search-sources-03.js] skip-if = e10s && debug [browser_dbg_search-symbols.js] -skip-if = e10s && debug +skip-if = (e10s && debug) || os == "linux" # Bug 1132375 [browser_dbg_searchbox-help-popup-01.js] skip-if = e10s && debug [browser_dbg_searchbox-help-popup-02.js] diff --git a/docshell/base/nsIContentViewer.idl b/docshell/base/nsIContentViewer.idl index 507a5f41e27..6d53ecd59db 100644 --- a/docshell/base/nsIContentViewer.idl +++ b/docshell/base/nsIContentViewer.idl @@ -31,10 +31,9 @@ class nsDOMNavigationTiming; [ptr] native nsDOMNavigationTimingPtr(nsDOMNavigationTiming); [ref] native nsIContentViewerTArray(nsTArray >); -[scriptable, builtinclass, uuid(702e0a92-7d63-490e-b5ee-d247e6bd4588)] +[scriptable, builtinclass, uuid(fbd04c99-e149-473f-8a68-44f53d82f98b)] interface nsIContentViewer : nsISupports { - [noscript] void init(in nsIWidgetPtr aParentWidget, [const] in nsIntRectRef aBounds); @@ -245,27 +244,6 @@ interface nsIContentViewer : nsISupports */ [noscript] void appendSubtree(in nsIContentViewerTArray array); - /** - * Set the maximum line width for the document. - * NOTE: This will generate a reflow! - * - * @param maxLineWidth The maximum width of any line boxes on the page, - * in CSS pixels. - */ - void changeMaxLineBoxWidth(in int32_t maxLineBoxWidth); - - /** - * Instruct the refresh driver to discontinue painting until further - * notice. - */ - void pausePainting(); - - /** - * Instruct the refresh driver to resume painting after a previous call to - * pausePainting(). - */ - void resumePainting(); - /* * Render the document as if being viewed on a device with the specified * media type. This will cause a reflow. diff --git a/dom/base/DOMException.cpp b/dom/base/DOMException.cpp index 8c7b480805f..d9af6d6034c 100644 --- a/dom/base/DOMException.cpp +++ b/dom/base/DOMException.cpp @@ -87,6 +87,9 @@ enum DOM4ErrorTypeCodeMap { BtAuthFailureError = 0, BtRmtDevDownError = 0, BtAuthRejectedError = 0, + + /* Push API errors */ + PermissionDeniedError = 0, }; #define DOM4_MSG_DEF(name, message, nsresult) {(nsresult), name, #name, message}, diff --git a/dom/base/domerr.msg b/dom/base/domerr.msg index bf6e5b03793..5c8a63d87ae 100644 --- a/dom/base/domerr.msg +++ b/dom/base/domerr.msg @@ -151,5 +151,11 @@ DOM4_MSG_DEF(InvalidStateError, "A mutation operation was attempted on a file st DOM4_MSG_DEF(AbortError, "A request was aborted, for example through a call to FileHandle.abort.", NS_ERROR_DOM_FILEHANDLE_ABORT_ERR) DOM4_MSG_DEF(QuotaExceededError, "The current file handle exceeded its quota limitations.", NS_ERROR_DOM_FILEHANDLE_QUOTA_ERR) +/* Push API errors. */ +DOM4_MSG_DEF(InvalidStateError, "Invalid service worker registration.", NS_ERROR_DOM_PUSH_INVALID_REGISTRATION_ERR) +DOM4_MSG_DEF(PermissionDeniedError, "User denied permission to use the Push API.", NS_ERROR_DOM_PUSH_DENIED_ERR) +DOM4_MSG_DEF(AbortError, "Error retrieving push subscription.", NS_ERROR_DOM_PUSH_ABORT_ERR) +DOM4_MSG_DEF(NetworkError, "Push service unreachable.", NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE) + DOM_MSG_DEF(NS_ERROR_DOM_JS_EXCEPTION, "A callback threw an exception") DOM_MSG_DEF(NS_ERROR_DOM_DOMEXCEPTION, "A DOMException was thrown") diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 11afb6378c2..a0be3224045 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -386,30 +386,14 @@ CandidatesTraverse(CustomElementHashKey* aKey, return PL_DHASH_NEXT; } -struct CustomDefinitionTraceArgs -{ - const TraceCallbacks& callbacks; - void* closure; -}; - -static PLDHashOperator -CustomDefinitionTrace(CustomElementHashKey *aKey, - CustomElementDefinition *aData, - void *aArg) -{ - CustomDefinitionTraceArgs* traceArgs = static_cast(aArg); - MOZ_ASSERT(aData, "Definition must not be null"); - traceArgs->callbacks.Trace(&aData->mPrototype, "mCustomDefinitions prototype", - traceArgs->closure); - return PL_DHASH_NEXT; -} - NS_IMPL_CYCLE_COLLECTION_CLASS(Registry) NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(Registry) - CustomDefinitionTraceArgs customDefinitionArgs = { aCallbacks, aClosure }; - tmp->mCustomDefinitions.EnumerateRead(CustomDefinitionTrace, - &customDefinitionArgs); + for (auto iter = tmp->mCustomDefinitions.Iter(); !iter.Done(); iter.Next()) { + aCallbacks.Trace(&iter.UserData()->mPrototype, + "mCustomDefinitions prototype", + aClosure); + } NS_IMPL_CYCLE_COLLECTION_TRACE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Registry) @@ -941,57 +925,16 @@ nsExternalResourceMap::RequestResource(nsIURI* aURI, return nullptr; } -struct -nsExternalResourceEnumArgs -{ - nsIDocument::nsSubDocEnumFunc callback; - void *data; -}; - -static PLDHashOperator -ExternalResourceEnumerator(nsIURI* aKey, - nsExternalResourceMap::ExternalResource* aData, - void* aClosure) -{ - nsExternalResourceEnumArgs* args = - static_cast(aClosure); - bool next = - aData->mDocument ? args->callback(aData->mDocument, args->data) : true; - return next ? PL_DHASH_NEXT : PL_DHASH_STOP; -} - void nsExternalResourceMap::EnumerateResources(nsIDocument::nsSubDocEnumFunc aCallback, void* aData) { - nsExternalResourceEnumArgs args = { aCallback, aData }; - mMap.EnumerateRead(ExternalResourceEnumerator, &args); -} - -static PLDHashOperator -ExternalResourceTraverser(nsIURI* aKey, - nsExternalResourceMap::ExternalResource* aData, - void* aClosure) -{ - nsCycleCollectionTraversalCallback *cb = - static_cast(aClosure); - - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, - "mExternalResourceMap.mMap entry" - "->mDocument"); - cb->NoteXPCOMChild(aData->mDocument); - - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, - "mExternalResourceMap.mMap entry" - "->mViewer"); - cb->NoteXPCOMChild(aData->mViewer); - - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, - "mExternalResourceMap.mMap entry" - "->mLoadGroup"); - cb->NoteXPCOMChild(aData->mLoadGroup); - - return PL_DHASH_NEXT; + for (auto iter = mMap.Iter(); !iter.Done(); iter.Next()) { + nsExternalResourceMap::ExternalResource* resource = iter.UserData(); + if (resource->mDocument && !aCallback(resource->mDocument, aData)) { + break; + } + } } void @@ -999,7 +942,24 @@ nsExternalResourceMap::Traverse(nsCycleCollectionTraversalCallback* aCallback) c { // mPendingLoads will get cleared out as the requests complete, so // no need to worry about those here. - mMap.EnumerateRead(ExternalResourceTraverser, aCallback); + for (auto iter = mMap.ConstIter(); !iter.Done(); iter.Next()) { + nsExternalResourceMap::ExternalResource* resource = iter.UserData(); + + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback, + "mExternalResourceMap.mMap entry" + "->mDocument"); + aCallback->NoteXPCOMChild(resource->mDocument); + + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback, + "mExternalResourceMap.mMap entry" + "->mViewer"); + aCallback->NoteXPCOMChild(resource->mViewer); + + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*aCallback, + "mExternalResourceMap.mMap entry" + "->mLoadGroup"); + aCallback->NoteXPCOMChild(resource->mLoadGroup); + } } static PLDHashOperator diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 1653edd3c7a..eee2ef1863e 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -121,26 +121,17 @@ nsFrameMessageManager::~nsFrameMessageManager() } } -static PLDHashOperator -CycleCollectorTraverseListeners(const nsAString& aKey, - nsAutoTObserverArray* aListeners, - void* aCb) -{ - nsCycleCollectionTraversalCallback* cb = - static_cast (aCb); - uint32_t count = aListeners->Length(); - for (uint32_t i = 0; i < count; ++i) { - NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(*cb, "listeners[i] mStrongListener"); - cb->NoteXPCOMChild(aListeners->ElementAt(i).mStrongListener.get()); - } - return PL_DHASH_NEXT; -} - NS_IMPL_CYCLE_COLLECTION_CLASS(nsFrameMessageManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameMessageManager) - tmp->mListeners.EnumerateRead(CycleCollectorTraverseListeners, - static_cast(&cb)); + for (auto iter = tmp->mListeners.Iter(); !iter.Done(); iter.Next()) { + nsAutoTObserverArray* listeners = iter.UserData(); + uint32_t count = listeners->Length(); + for (uint32_t i = 0; i < count; ++i) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "listeners[i] mStrongListener"); + cb.NoteXPCOMChild(listeners->ElementAt(i).mStrongListener.get()); + } + } NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChildManagers) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS @@ -419,35 +410,6 @@ nsFrameMessageManager::RemoveMessageListener(const nsAString& aMessage, return NS_OK; } -#ifdef DEBUG -typedef struct -{ - nsCOMPtr mCanonical; - nsWeakPtr mWeak; -} CanonicalCheckerParams; - -static PLDHashOperator -CanonicalChecker(const nsAString& aKey, - nsAutoTObserverArray* aListeners, - void* aParams) -{ - CanonicalCheckerParams* params = - static_cast (aParams); - - uint32_t count = aListeners->Length(); - for (uint32_t i = 0; i < count; i++) { - if (!aListeners->ElementAt(i).mWeakListener) { - continue; - } - nsCOMPtr otherCanonical = - do_QueryReferent(aListeners->ElementAt(i).mWeakListener); - MOZ_ASSERT((params->mCanonical == otherCanonical) == - (params->mWeak == aListeners->ElementAt(i).mWeakListener)); - } - return PL_DHASH_NEXT; -} -#endif - NS_IMETHODIMP nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessage, nsIMessageListener* aListener) @@ -461,10 +423,17 @@ nsFrameMessageManager::AddWeakMessageListener(const nsAString& aMessage, // this to happen; it will break e.g. RemoveWeakMessageListener. So let's // check that we're not getting ourselves into that situation. nsCOMPtr canonical = do_QueryInterface(aListener); - CanonicalCheckerParams params; - params.mCanonical = canonical; - params.mWeak = weak; - mListeners.EnumerateRead(CanonicalChecker, (void*)¶ms); + for (auto iter = mListeners.Iter(); !iter.Done(); iter.Next()) { + nsAutoTObserverArray* listeners = iter.UserData(); + uint32_t count = listeners->Length(); + for (uint32_t i = 0; i < count; i++) { + nsWeakPtr weakListener = listeners->ElementAt(i).mWeakListener; + if (weakListener) { + nsCOMPtr otherCanonical = do_QueryReferent(weakListener); + MOZ_ASSERT((canonical == otherCanonical) == (weak == weakListener)); + } + } + } #endif nsAutoTObserverArray* listeners = @@ -1488,55 +1457,45 @@ protected: NS_IMPL_ISUPPORTS(MessageManagerReporter, nsIMemoryReporter) -static PLDHashOperator -CollectMessageListenerData(const nsAString& aKey, - nsAutoTObserverArray* aListeners, - void* aData) -{ - MessageManagerReferentCount* referentCount = - static_cast(aData); - - uint32_t listenerCount = aListeners->Length(); - if (!listenerCount) { - return PL_DHASH_NEXT; - } - - nsString key(aKey); - uint32_t oldCount = 0; - referentCount->mMessageCounter.Get(key, &oldCount); - uint32_t currentCount = oldCount + listenerCount; - referentCount->mMessageCounter.Put(key, currentCount); - - // Keep track of messages that have a suspiciously large - // number of referents (symptom of leak). - if (currentCount == MessageManagerReporter::kSuspectReferentCount) { - referentCount->mSuspectMessages.AppendElement(key); - } - - for (uint32_t i = 0; i < listenerCount; ++i) { - const nsMessageListenerInfo& listenerInfo = - aListeners->ElementAt(i); - if (listenerInfo.mWeakListener) { - nsCOMPtr referent = - do_QueryReferent(listenerInfo.mWeakListener); - if (referent) { - referentCount->mWeakAlive++; - } else { - referentCount->mWeakDead++; - } - } else { - referentCount->mStrong++; - } - } - return PL_DHASH_NEXT; -} - void MessageManagerReporter::CountReferents(nsFrameMessageManager* aMessageManager, MessageManagerReferentCount* aReferentCount) { - aMessageManager->mListeners.EnumerateRead(CollectMessageListenerData, - aReferentCount); + for (auto it = aMessageManager->mListeners.Iter(); !it.Done(); it.Next()) { + nsAutoTObserverArray* listeners = + it.UserData(); + uint32_t listenerCount = listeners->Length(); + if (listenerCount == 0) { + continue; + } + + nsString key(it.Key()); + uint32_t oldCount = 0; + aReferentCount->mMessageCounter.Get(key, &oldCount); + uint32_t currentCount = oldCount + listenerCount; + aReferentCount->mMessageCounter.Put(key, currentCount); + + // Keep track of messages that have a suspiciously large + // number of referents (symptom of leak). + if (currentCount == MessageManagerReporter::kSuspectReferentCount) { + aReferentCount->mSuspectMessages.AppendElement(key); + } + + for (uint32_t i = 0; i < listenerCount; ++i) { + const nsMessageListenerInfo& listenerInfo = listeners->ElementAt(i); + if (listenerInfo.mWeakListener) { + nsCOMPtr referent = + do_QueryReferent(listenerInfo.mWeakListener); + if (referent) { + aReferentCount->mWeakAlive++; + } else { + aReferentCount->mWeakDead++; + } + } else { + aReferentCount->mStrong++; + } + } + } // Add referent count in child managers because the listeners // participate in messages dispatched from parent message manager. @@ -2182,24 +2141,20 @@ NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult) return NS_OK; } -static PLDHashOperator -CycleCollectorMarkListeners(const nsAString& aKey, - nsAutoTObserverArray* aListeners, - void* aData) -{ - uint32_t count = aListeners->Length(); - for (uint32_t i = 0; i < count; i++) { - if (aListeners->ElementAt(i).mStrongListener) { - xpc_TryUnmarkWrappedGrayObject(aListeners->ElementAt(i).mStrongListener); - } - } - return PL_DHASH_NEXT; -} - bool nsFrameMessageManager::MarkForCC() { - mListeners.EnumerateRead(CycleCollectorMarkListeners, nullptr); + for (auto iter = mListeners.Iter(); !iter.Done(); iter.Next()) { + nsAutoTObserverArray* listeners = iter.UserData(); + uint32_t count = listeners->Length(); + for (uint32_t i = 0; i < count; i++) { + nsCOMPtr strongListener = + listeners->ElementAt(i).mStrongListener; + if (strongListener) { + xpc_TryUnmarkWrappedGrayObject(strongListener); + } + } + } if (mRefCnt.IsPurple()) { mRefCnt.RemovePurple(); diff --git a/dom/base/test/chrome/cpows_child.js b/dom/base/test/chrome/cpows_child.js index ff94f771f04..8736375b522 100644 --- a/dom/base/test/chrome/cpows_child.js +++ b/dom/base/test/chrome/cpows_child.js @@ -20,6 +20,7 @@ var Cu = Components.utils; lifetime_test, cancel_test, cancel_test2, + unsafe_test, ]; function go() { @@ -337,3 +338,20 @@ function cancel_test2(finish) if (fin1 && fin2) finish(); }); } + +function unsafe_test(finish) +{ + if (!is_remote) { + // Only run this test when running out-of-process. + finish(); + return; + } + + function f() {} + + sendAsyncMessage("cpows:unsafe", null, {f}); + addMessageListener("cpows:unsafe_done", msg => { + sendRpcMessage("cpows:safe", null, {f}); + addMessageListener("cpows:safe_done", finish); + }); +} diff --git a/dom/base/test/chrome/cpows_parent.xul b/dom/base/test/chrome/cpows_parent.xul index 66345993671..1e65628536e 100644 --- a/dom/base/test/chrome/cpows_parent.xul +++ b/dom/base/test/chrome/cpows_parent.xul @@ -390,6 +390,33 @@ msg.target.messageManager.sendAsyncMessage("cpows:cancel_test2_done"); } + function recvUnsafe(msg) { + let failed = false; + + const PREF_UNSAFE_FORBIDDEN = "dom.ipc.cpows.forbid-unsafe-from-browser"; + opener.wrappedJSObject.SpecialPowers.setBoolPref(PREF_UNSAFE_FORBIDDEN, true); + try { + msg.objects.f(); + } catch (e if /unsafe CPOW usage forbidden/.test(String(e))) { + failed = true; + } + opener.wrappedJSObject.SpecialPowers.clearUserPref(PREF_UNSAFE_FORBIDDEN); + ok(failed, "CPOW should fail when unsafe"); + msg.target.messageManager.sendAsyncMessage("cpows:unsafe_done"); + } + + function recvSafe(msg) { + const PREF_UNSAFE_FORBIDDEN = "dom.ipc.cpows.forbid-unsafe-from-browser"; + opener.wrappedJSObject.SpecialPowers.setBoolPref(PREF_UNSAFE_FORBIDDEN, true); + try { + msg.objects.f(); + } catch (e if /unsafe CPOW usage forbidden/.test(String(e))) { + ok(false, "cpow failed"); + } + opener.wrappedJSObject.SpecialPowers.clearUserPref(PREF_UNSAFE_FORBIDDEN); + msg.target.messageManager.sendAsyncMessage("cpows:safe_done"); + } + function run_tests(type) { info("Running tests: " + type); var node = document.getElementById('cpowbrowser_' + type); @@ -429,6 +456,8 @@ mm.addMessageListener("cpows:cancel_test", recvCancelTest); mm.addMessageListener("cpows:cancel_sync_message", recvCancelSyncMessage); mm.addMessageListener("cpows:cancel_test2", recvCancelTest2); + mm.addMessageListener("cpows:unsafe", recvUnsafe); + mm.addMessageListener("cpows:safe", recvSafe); mm.loadFrameScript("chrome://mochitests/content/chrome/dom/base/test/chrome/cpows_child.js", true); } diff --git a/dom/bindings/test/moz.build b/dom/bindings/test/moz.build index 1b81ad3e6e3..eeadfee342d 100644 --- a/dom/bindings/test/moz.build +++ b/dom/bindings/test/moz.build @@ -41,8 +41,8 @@ WEBIDL_EXAMPLE_INTERFACES += [ 'TestExampleProxyInterface', ] -GENERATED_INCLUDES += ['..'] LOCAL_INCLUDES += [ + '!..', '/dom/bindings', '/js/xpconnect/src', '/js/xpconnect/wrappers', diff --git a/dom/canvas/WebGLContextDraw.cpp b/dom/canvas/WebGLContextDraw.cpp index 47afcbf0473..05d9707271e 100644 --- a/dom/canvas/WebGLContextDraw.cpp +++ b/dom/canvas/WebGLContextDraw.cpp @@ -7,6 +7,7 @@ #include "GLContext.h" #include "mozilla/CheckedInt.h" +#include "mozilla/UniquePtrExtensions.h" #include "WebGLBuffer.h" #include "WebGLContextUtils.h" #include "WebGLFramebuffer.h" @@ -580,7 +581,7 @@ WebGLContext::DoFakeVertexAttrib0(GLuint vertexCount) GetAndFlushUnderlyingGLErrors(); if (mFakeVertexAttrib0BufferStatus == WebGLVertexAttrib0Status::EmulatedInitializedArray) { - UniquePtr array(new (fallible) GLfloat[4 * vertexCount]); + auto array = MakeUniqueFallible(4 * vertexCount); if (!array) { ErrorOutOfMemory("Fake attrib0 array."); return false; diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index ad3ad3d04ee..34a9ebaaefd 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -52,6 +52,7 @@ #include "mozilla/dom/ToJSValue.h" #include "mozilla/Endian.h" #include "mozilla/RefPtr.h" +#include "mozilla/UniquePtrExtensions.h" namespace mozilla { @@ -1622,7 +1623,7 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width, uint32_t subrect_byteLength = (subrect_height-1)*subrect_alignedRowSize + subrect_plainRowSize; // create subrect buffer, call glReadPixels, copy pixels into destination buffer, delete subrect buffer - UniquePtr subrect_data(new (fallible) GLubyte[subrect_byteLength]); + auto subrect_data = MakeUniqueFallible(subrect_byteLength); if (!subrect_data) return ErrorOutOfMemory("readPixels: subrect_data"); diff --git a/dom/canvas/test/captureStream_common.js b/dom/canvas/test/captureStream_common.js index 91be55ed513..6b9b4c66a8f 100644 --- a/dom/canvas/test/captureStream_common.js +++ b/dom/canvas/test/captureStream_common.js @@ -25,6 +25,7 @@ function CaptureStreamTestHelper(width, height) { CaptureStreamTestHelper.prototype = { /* Predefined colors for use in the methods below. */ black: { data: [0, 0, 0, 255], name: "black" }, + blackTransparent: { data: [0, 0, 0, 0], name: "blackTransparent" }, green: { data: [0, 255, 0, 255], name: "green" }, red: { data: [255, 0, 0, 255], name: "red" }, @@ -52,55 +53,90 @@ CaptureStreamTestHelper.prototype = { video.srcObject.requestFrame(); }, - /* Tests the top left pixel of |video| against |refData|. Format [R,G,B,A]. */ - testPixel: function (video, refData, threshold) { + /* + * Returns the pixel at (|offsetX|, |offsetY|) (from top left corner) of + * |video| as an array of the pixel's color channels: [R,G,B,A]. + */ + getPixel: function (video, offsetX, offsetY) { + offsetX = offsetX || 0; // Set to 0 if not passed in. + offsetY = offsetY || 0; // Set to 0 if not passed in. var ctxout = this.cout.getContext('2d'); ctxout.drawImage(video, 0, 0); - var pixel = ctxout.getImageData(0, 0, 1, 1).data; - return pixel.every((val, i) => Math.abs(val - refData[i]) <= threshold); + return ctxout.getImageData(offsetX, offsetY, 1, 1).data; }, /* - * Returns a promise that resolves when the pixel matches. Use |threshold| - * for fuzzy matching the color on each channel, in the range [0,255]. + * Returns true if px lies within the per-channel |threshold| of the + * referenced color for all channels. px is on the form of an array of color + * channels, [R,G,B,A]. Each channel is in the range [0, 255]. */ - waitForPixel: function (video, refColor, threshold, infoString) { + isPixel: function (px, refColor, threshold) { + threshold = threshold || 0; // Default to 0 (exact match) if not passed in. + return px.every((ch, i) => Math.abs(ch - refColor.data[i]) <= threshold); + }, + + /* + * Returns true if px lies further away than |threshold| of the + * referenced color for any channel. px is on the form of an array of color + * channels, [R,G,B,A]. Each channel is in the range [0, 255]. + */ + isPixelNot: function (px, refColor, threshold) { + if (threshold === undefined) { + // Default to 127 (should be sufficiently far away) if not passed in. + threshold = 127; + } + return px.some((ch, i) => Math.abs(ch - refColor.data[i]) > threshold); + }, + + /* + * Returns a promise that resolves when the provided function |test| + * returns true. + */ + waitForPixel: function (video, offsetX, offsetY, test, timeout) { return new Promise(resolve => { - info("Testing " + video.id + " against [" + refColor.data.join(',') + "]"); + const startTime = video.currentTime; CaptureStreamTestHelper2D.prototype.clear.call(this, this.cout); - video.ontimeupdate = () => { - if (this.testPixel(video, refColor.data, threshold)) { - ok(true, video.id + " " + infoString); - video.ontimeupdate = null; - resolve(); + var ontimeupdate = () => { + const pixelMatch = test(this.getPixel(video, offsetX, offsetY)); + if (!pixelMatch && + (!timeout || video.currentTime < startTime + (timeout / 1000.0))) { + // No match yet and, + // No timeout (waiting indefinitely) or |timeout| has not passed yet. + return; } + video.removeEventListener("timeupdate", ontimeupdate); + resolve(pixelMatch); }; + video.addEventListener("timeupdate", ontimeupdate); }); }, /* - * Returns a promise that resolves after |timeout| ms of playback or when a - * pixel of |video| becomes the color |refData|. The test is failed if the + * Returns a promise that resolves when the top left pixel of |video| matches + * on all channels. Use |threshold| for fuzzy matching the color on each + * channel, in the range [0,255]. + */ + waitForPixelColor: function (video, refColor, threshold, infoString) { + info("Waiting for video " + video.id + " to match [" + + refColor.data.join(',') + "] - " + refColor.name + + " (" + infoString + ")"); + return this.waitForPixel(video, 0, 0, + px => this.isPixel(px, refColor, threshold)) + .then(() => ok(true, video.id + " " + infoString)); + }, + + /* + * Returns a promise that resolves after |timeout| ms of playback or when the + * top left pixel of |video| becomes |refColor|. The test is failed if the * timeout is not reached. */ - waitForPixelToTimeout: function (video, refColor, threshold, timeout, infoString) { - return new Promise(resolve => { - info("Waiting for " + video.id + " to time out after " + timeout + - "ms against [" + refColor.data.join(',') + "] - " + refColor.name); - CaptureStreamTestHelper2D.prototype.clear.call(this, this.cout); - var startTime = video.currentTime; - video.ontimeupdate = () => { - if (this.testPixel(video, refColor.data, threshold)) { - ok(false, video.id + " " + infoString); - video.ontimeupdate = null; - resolve(); - } else if (video.currentTime > startTime + (timeout / 1000.0)) { - ok(true, video.id + " " + infoString); - video.ontimeupdate = null; - resolve(); - } - }; - }); + waitForPixelColorTimeout: function (video, refColor, threshold, timeout, infoString) { + info("Waiting for " + video.id + " to time out after " + timeout + + "ms against [" + refColor.data.join(',') + "] - " + refColor.name); + return this.waitForPixel(video, 0, 0, + px => this.isPixel(px, refColor, threshold), + timeout) + .then(result => ok(!result, video.id + " " + infoString)); }, /* Create an element of type |type| with id |id| and append it to the body. */ diff --git a/dom/canvas/test/test_capture.html b/dom/canvas/test/test_capture.html index ec2902b3ac9..69222d75a9e 100644 --- a/dom/canvas/test/test_capture.html +++ b/dom/canvas/test/test_capture.html @@ -23,15 +23,21 @@ function checkDrawColorInitialRed() { vmanual.srcObject = c.captureStream(0); vrate.srcObject = c.captureStream(10); - ok(h.testPixel(vauto, [0, 0, 0, 0], 0), "vauto hould not be drawn to before stable state"); - ok(h.testPixel(vrate, [0, 0, 0, 0], 0), "vrate Should not be drawn to before stable state"); - ok(h.testPixel(vmanual, [0, 0, 0, 0], 0), "vmanual Should not be drawn to before stable state"); + ok(h.isPixel(h.getPixel(vauto), h.blackTransparent, 0), + "vauto should not be drawn to before stable state"); + ok(h.isPixel(h.getPixel(vrate), h.blackTransparent, 0), + "vrate should not be drawn to before stable state"); + ok(h.isPixel(h.getPixel(vmanual), h.blackTransparent, 0), + "vmanual should not be drawn to before stable state"); return Promise.resolve() - .then(() => h.waitForPixel(vauto, h.red, 0, "should become red automatically")) - .then(() => h.waitForPixel(vrate, h.red, 0, "should become red automatically")) - .then(() => h.waitForPixel(vmanual, h.red, 0, "should become red when we get" + - " to stable state (first frame)")); + .then(() => h.waitForPixelColor(vauto, h.red, 0, + "should become red automatically")) + .then(() => h.waitForPixelColor(vrate, h.red, 0, + "should become red automatically")) + .then(() => h.waitForPixelColor(vmanual, h.red, 0, + "should become red when we get" + + " to stable state (first frame)")); } function checkDrawColorGreen() { @@ -40,11 +46,15 @@ function checkDrawColorGreen() { var drawing = h.startDrawing(() => h.drawColor(c, h.green)); return Promise.resolve() - .then(() => h.waitForPixel(vauto, h.green, 0, "should become green automatically")) - .then(() => h.waitForPixel(vrate, h.green, 0, "should become green automatically")) - .then(() => h.waitForPixel(vmanual, h.red, 0, "should still be red")) + .then(() => h.waitForPixelColor(vauto, h.green, 0, + "should become green automatically")) + .then(() => h.waitForPixelColor(vrate, h.green, 0, + "should become green automatically")) + .then(() => h.waitForPixelColor(vmanual, h.red, 0, + "should still be red")) .then(() => h.requestFrame(vmanual)) - .then(() => h.waitForPixel(vmanual, h.green, 0, "should become green after requstFrame()")) + .then(() => h.waitForPixelColor(vmanual, h.green, 0, + "should become green after requstFrame()")) .catch(err => ok(false, "checkDrawColorGreen failed: ", err)) .then(() => drawing.stop()); } @@ -54,10 +64,12 @@ function checkRequestFrameOrderGuarantee() { "call results in the expected frame seen in the stream."); return Promise.resolve() - .then(() => h.waitForPixel(vmanual, h.green, 0, "should still be green")) + .then(() => h.waitForPixelColor(vmanual, h.green, 0, + "should still be green")) .then(() => h.drawColor(c, h.red)) // 1. Draw canvas red .then(() => h.requestFrame(vmanual)) // 2. Immediately request a frame - .then(() => h.waitForPixel(vmanual, h.red, 0, "should become red after call order test")) + .then(() => h.waitForPixelColor(vmanual, h.red, 0, + "should become red after call order test")) } function checkDrawImageNotCleanRed() { @@ -74,11 +86,14 @@ function checkDrawImageNotCleanRed() { }) .then(() => drawing = h.startDrawing(() => ctx.drawImage(notCleanRed, 0, 0, c.width, c.height))) .then(() => h.testNotClean(c)) - .then(() => h.waitForPixelToTimeout(vauto, h.red, 0, 1000, "should not become red")) - .then(() => h.waitForPixelToTimeout(vrate, h.red, 0, 0, "should not become red")) - .then(() => h.waitForPixel(vmanual, h.green, 0, "should still be green")) + .then(() => h.waitForPixelColorTimeout(vauto, h.red, 0, 1000, + "should not become red")) + .then(() => h.isPixelNot(h.getPixel(vrate), h.red, 250, + "should not have become red")) + .then(() => h.waitForPixelColor(vmanual, h.green, 0, "should still be green")) .then(() => h.requestFrame(vmanual)) - .then(() => h.waitForPixelToTimeout(vmanual, h.red, 0, 1000, "should not become red")) + .then(() => h.waitForPixelColorTimeout(vmanual, h.red, 0, 1000, + "should not become red")) .catch(err => ok(false, "checkDrawImageNotCleanRed failed: ", err)) .then(() => drawing.stop()); } diff --git a/dom/canvas/test/webgl-mochitest/test_capture.html b/dom/canvas/test/webgl-mochitest/test_capture.html index 489d6787236..fc27b35e734 100644 --- a/dom/canvas/test/webgl-mochitest/test_capture.html +++ b/dom/canvas/test/webgl-mochitest/test_capture.html @@ -54,14 +54,21 @@ function checkClearColorInitialRed() { vmanual.srcObject = c.captureStream(0); vrate.srcObject = c.captureStream(10); - ok(h.testPixel(vauto, [0, 0, 0, 0], 0), "Should not be drawn to before stable state"); - ok(h.testPixel(vrate, [0, 0, 0, 0], 0), "Should not be drawn to before stable state"); - ok(h.testPixel(vmanual, [0, 0, 0, 0], 0), "Should not be drawn to before stable state"); + ok(h.isPixel(h.getPixel(vauto), h.blackTransparent, 0, + "vauto should not be drawn to before stable state")); + ok(h.isPixel(h.getPixel(vrate), h.blackTransparent, 0, + "vrate should not be drawn to before stable state")); + ok(h.isPixel(h.getPixel(vmanual), h.blackTransparent, 0, + "vmanual should not be drawn to before stable state")); return Promise.resolve() - .then(() => h.waitForPixel(vauto, h.red, 0, "should become red automatically")) - .then(() => h.waitForPixel(vrate, h.red, 0, "should become red automatically")) - .then(() => h.waitForPixel(vmanual, h.red, 0, "should become red when we get to stable state (first frame)")) + .then(() => h.waitForPixelColor(vauto, h.red, 0, + "should become red automatically")) + .then(() => h.waitForPixelColor(vrate, h.red, 0, + "should become red automatically")) + .then(() => h.waitForPixelColor(vmanual, h.red, 0, + "should become red when we get to stable " + + "state (first frame)")) } function checkDrawColorGreen() { @@ -69,11 +76,15 @@ function checkDrawColorGreen() { var drawing = h.startDrawing(h.drawColor.bind(h, c, h.green)); checkGLError('after DrawColor'); return Promise.resolve() - .then(() => h.waitForPixel(vauto, h.green, 0, "should become green automatically")) - .then(() => h.waitForPixel(vrate, h.green, 0, "should become green automatically")) - .then(() => h.waitForPixel(vmanual, h.red, 0, "should still be red")) + .then(() => h.waitForPixelColor(vauto, h.green, 0, + "should become green automatically")) + .then(() => h.waitForPixelColor(vrate, h.green, 0, + "should become green automatically")) + .then(() => h.waitForPixelColor(vmanual, h.red, 0, + "should still be red")) .then(() => h.requestFrame(vmanual)) - .then(() => h.waitForPixel(vmanual, h.green, 0, "should become green after requstFrame()")) + .then(() => h.waitForPixelColor(vmanual, h.green, 0, + "should become green after requstFrame()")) .then(() => drawing.stop()); } @@ -81,11 +92,15 @@ function checkClearColorRed() { info("Checking that clearing to red works."); var drawing = h.startDrawing(h.clearColor.bind(h, c, h.red)); return Promise.resolve() - .then(() => h.waitForPixel(vauto, h.red, 0, "should become red automatically")) - .then(() => h.waitForPixel(vrate, h.red, 0, "should become red automatically")) - .then(() => h.waitForPixel(vmanual, h.green, 0, "should still be green")) + .then(() => h.waitForPixelColor(vauto, h.red, 0, + "should become red automatically")) + .then(() => h.waitForPixelColor(vrate, h.red, 0, + "should become red automatically")) + .then(() => h.waitForPixelColor(vmanual, h.green, 0, + "should still be green")) .then(() => h.requestFrame(vmanual)) - .then(() => h.waitForPixel(vmanual, h.red, 0, "should become red after requestFrame()")) + .then(() => h.waitForPixelColor(vmanual, h.red, 0, + "should become red after requestFrame()")) .then(() => drawing.stop()); } @@ -93,10 +108,11 @@ function checkRequestFrameOrderGuarantee() { info("Checking that requestFrame() immediately after a draw " + "call results in the expected frame seen in the stream."); return Promise.resolve() - .then(() => h.waitForPixel(vmanual, h.red, 0, "should still be red")) + .then(() => h.waitForPixelColor(vmanual, h.red, 0, "should still be red")) .then(() => h.drawColor(c, h.green)) // 1. Draw canvas green .then(() => h.requestFrame(vmanual)) // 2. Immediately request a frame - .then(() => h.waitForPixel(vmanual, h.green, 0, "should become green after call order test")) + .then(() => h.waitForPixelColor(vmanual, h.green, 0, + "should become green after call order test")) } function finish() { diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 643bd698427..9643e67c03b 100755 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -1910,28 +1910,6 @@ ContentParent::OnChannelError() PContentParent::OnChannelError(); } -void -ContentParent::OnBeginSyncTransaction() { - if (XRE_IsParentProcess()) { - nsCOMPtr console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); - JSContext *cx = nsContentUtils::GetCurrentJSContext(); - if (!sDisableUnsafeCPOWWarnings) { - if (console && cx) { - nsAutoString filename; - uint32_t lineno = 0, column = 0; - nsJSUtils::GetCallingLocation(cx, filename, &lineno, &column); - nsCOMPtr error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID)); - error->Init(NS_LITERAL_STRING("unsafe CPOW usage"), filename, - EmptyString(), lineno, column, - nsIScriptError::warningFlag, "chrome javascript"); - console->LogMessage(error); - } else { - NS_WARNING("Unsafe synchronous IPC message"); - } - } - } -} - void ContentParent::OnChannelConnected(int32_t pid) { diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h index 4797cd07bfd..3000c155003 100644 --- a/dom/ipc/ContentParent.h +++ b/dom/ipc/ContentParent.h @@ -327,8 +327,6 @@ public: virtual void OnChannelError() override; - virtual void OnBeginSyncTransaction() override; - virtual PCrashReporterParent* AllocPCrashReporterParent(const NativeThreadId& tid, const uint32_t& processType) override; diff --git a/dom/media/MediaManager.cpp b/dom/media/MediaManager.cpp index 730f669d4f6..eb15ed4f3db 100644 --- a/dom/media/MediaManager.cpp +++ b/dom/media/MediaManager.cpp @@ -1415,25 +1415,22 @@ MediaManager::EnumerateRawDevices(uint64_t aWindowId, RefPtr p = new PledgeSourceSet(); uint32_t id = mOutstandingPledges.Append(*p); - // Check if the preference for using audio/video loopback devices is - // enabled. This is currently used for automated media tests only. - // - // If present (and we're doing non-exotic cameras and microphones) use them - // instead of our built-in fake devices, except if fake tracks are requested - // (a feature of the built-in ones only). - nsAdoptingCString audioLoopDev, videoLoopDev; - if (!aFakeTracks) { - if (aVideoType == dom::MediaSourceEnum::Camera) { - audioLoopDev = Preferences::GetCString("media.audio_loopback_dev"); + if (!aFake) { + // Fake stream not requested. The entire device stack is available. + // Loop in loopback devices if they are set, and their respective type is + // requested. This is currently used for automated media tests only. + if (aVideoType == MediaSourceEnum::Camera) { videoLoopDev = Preferences::GetCString("media.video_loopback_dev"); - - if (aFake && !audioLoopDev.IsEmpty() && !videoLoopDev.IsEmpty()) { - aFake = false; - } - } else { - aFake = false; } + if (aAudioType == MediaSourceEnum::Microphone) { + audioLoopDev = Preferences::GetCString("media.audio_loopback_dev"); + } + } + + if (!aFake) { + // Fake tracks only make sense when we have a fake stream. + aFakeTracks = false; } MediaManager::PostTask(FROM_HERE, NewTaskFrom([id, aWindowId, audioLoopDev, diff --git a/dom/media/encoder/moz.build b/dom/media/encoder/moz.build index 6def7f46985..853b0d6d3b9 100644 --- a/dom/media/encoder/moz.build +++ b/dom/media/encoder/moz.build @@ -42,13 +42,16 @@ FINAL_LIBRARY = 'xul' # These includes are from Android JB, for use of MediaCodec. LOCAL_INCLUDES += ['/ipc/chromium/src'] -CXXFLAGS += [ - '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/native/opengl/include', - 'frameworks/native/include', - 'frameworks/av/include/media', + +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['ANDROID_VERSION'] > '15': + LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ + 'frameworks/av/include/media', + 'frameworks/native/include', + 'frameworks/native/opengl/include', + ] + ] -] include('/ipc/chromium/chromium-config.mozbuild') diff --git a/dom/media/omx/moz.build b/dom/media/omx/moz.build index aec361e2071..543cd5e4d46 100644 --- a/dom/media/omx/moz.build +++ b/dom/media/omx/moz.build @@ -97,20 +97,26 @@ LOCAL_INCLUDES += [ '/ipc/chromium/src', ] -CXXFLAGS += [ - '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'dalvik/libnativehelper/include/nativehelper', - 'frameworks/av/include/media', - 'frameworks/base/include', - 'frameworks/base/include/binder', - 'frameworks/base/include/utils', - 'frameworks/base/include/media', - 'frameworks/base/include/media/stagefright/openmax', - 'frameworks/base/media/libstagefright/include', - 'frameworks/native/opengl/include', - 'frameworks/native/include', - 'hardware/libhardware/include/', +if CONFIG['ANDROID_VERSION'] == '15': + LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ + 'dalvik/libnativehelper/include/nativehelper', + 'frameworks/base/include', + 'frameworks/base/include/binder', + 'frameworks/base/include/media', + 'frameworks/base/include/media/stagefright/openmax', + 'frameworks/base/include/utils', + 'frameworks/base/media/libstagefright/include', + 'hardware/libhardware/include', + ] ] +else: + LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ + 'frameworks/av/include/media', + 'frameworks/native/include', + 'frameworks/native/opengl/include', + ] ] if CONFIG['ANDROID_VERSION'] > '15': diff --git a/dom/media/platforms/gonk/moz.build b/dom/media/platforms/gonk/moz.build index eb5f2b2c72c..5dbc0a6705c 100644 --- a/dom/media/platforms/gonk/moz.build +++ b/dom/media/platforms/gonk/moz.build @@ -33,7 +33,7 @@ if CONFIG['GNU_CC'] or CONFIG['CLANG_CL']: FINAL_LIBRARY = 'xul' -CXXFLAGS += [ - '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ +LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ 'frameworks/native/opengl/include',] ] diff --git a/dom/media/systemservices/moz.build b/dom/media/systemservices/moz.build index 74300776e71..27a5f68ac7c 100644 --- a/dom/media/systemservices/moz.build +++ b/dom/media/systemservices/moz.build @@ -40,12 +40,14 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': EXPORTS += ['OSXRunLoopSingleton.h'] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - CXXFLAGS += [ - '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/wilhelm/include', - 'system/media/wilhelm/include', + if CONFIG['ANDROID_VERSION'] >= '17': + LOCAL_INCLUDES += [ + '%' + '%s/frameworks/wilhelm/include' % CONFIG['ANDROID_SOURCE'], + ] + else: + LOCAL_INCLUDES += [ + '%' + '%s/system/media/wilhelm/include' % CONFIG['ANDROID_SOURCE'], ] - ] if CONFIG['_MSC_VER']: DEFINES['__PRETTY_FUNCTION__'] = '__FUNCSIG__' diff --git a/dom/media/test/test_mediarecorder_record_canvas_captureStream.html b/dom/media/test/test_mediarecorder_record_canvas_captureStream.html index 21456b93539..7f440fba9dd 100644 --- a/dom/media/test/test_mediarecorder_record_canvas_captureStream.html +++ b/dom/media/test/test_mediarecorder_record_canvas_captureStream.html @@ -56,7 +56,7 @@ function startTest() { SimpleTest.finish(); }; document.getElementById("content").appendChild(video); - helper.waitForPixel(video, helper.red, 128, "Should become red") + helper.waitForPixelColor(video, helper.red, 128, "Should become red") .then(SimpleTest.finish); }; diff --git a/dom/media/tests/mochitest/identity/identityPcTest.js b/dom/media/tests/mochitest/identity/identityPcTest.js index e5c9d9b423b..e5fcbc5db87 100644 --- a/dom/media/tests/mochitest/identity/identityPcTest.js +++ b/dom/media/tests/mochitest/identity/identityPcTest.js @@ -20,7 +20,6 @@ function identityPcTest(remoteOptions) { }], [remoteOptions || { audio: true, video: true, - fake: true, peerIdentity: id1 }]); test.pcLocal.setIdentityProvider('test1.example.com', 'idp.js'); diff --git a/dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html b/dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html index 1d686f533f4..5ea0f5c779b 100644 --- a/dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html +++ b/dom/media/tests/mochitest/identity/test_peerConnection_asymmetricIsolation.html @@ -20,8 +20,7 @@ function theTest() { // side is isolated anyway. identityPcTest({ audio: true, - video: true, - fake: true + video: true }); } runNetworkTest(theTest); diff --git a/dom/media/tests/mochitest/mochitest.ini b/dom/media/tests/mochitest/mochitest.ini index dc08b192ee9..8aef9ab7306 100644 --- a/dom/media/tests/mochitest/mochitest.ini +++ b/dom/media/tests/mochitest/mochitest.ini @@ -150,6 +150,7 @@ skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' & [test_peerConnection_throwInCallbacks.html] skip-if = toolkit == 'gonk' || buildapp == 'mulet' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) [test_peerConnection_toJSON.html] +[test_peerConnection_trackDisabling.html] [test_peerConnection_twoAudioStreams.html] skip-if = toolkit == 'gonk' || buildapp == 'mulet' || (android_version == '18' && debug) # b2g (Bug 1059867), android(Bug 1189784, timeouts on 4.3 emulator) diff --git a/dom/media/tests/mochitest/test_enumerateDevices.html b/dom/media/tests/mochitest/test_enumerateDevices.html index 06565e26abb..5a160cf4a9b 100644 --- a/dom/media/tests/mochitest/test_enumerateDevices.html +++ b/dom/media/tests/mochitest/test_enumerateDevices.html @@ -46,27 +46,24 @@ runTest(() => .then(() => mustSucceed("unknown plain deviceId on video", () => navigator.mediaDevices.getUserMedia({ video: { deviceId: "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=" }, - fake: true, }))) .then(() => mustSucceed("unknown plain deviceId on audio", () => navigator.mediaDevices.getUserMedia({ audio: { deviceId: "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=" }, - fake: true, }))) .then(() => mustFailWith("unknown exact deviceId on video", "OverconstrainedError", "deviceId", () => navigator.mediaDevices.getUserMedia({ video: { deviceId: { exact: "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=" } }, - fake: true, }))) .then(() => mustFailWith("unknown exact deviceId on audio", "OverconstrainedError", "deviceId", () => navigator.mediaDevices.getUserMedia({ audio: { deviceId: { exact: "unknown9qHr8B0JIbcHlbl9xR+jMbZZ8WyoPfpCXPfc=" } }, - fake: true, }))) - // Check the special case of no devices found (these prefs override fake). - .then(() => pushPrefs(["media.audio_loopback_dev", "none"], + // Check the special case of no devices found. + .then(() => pushPrefs(["media.navigator.streams.fake", false], + ["media.audio_loopback_dev", "none"], ["media.video_loopback_dev", "none"])) .then(() => navigator.mediaDevices.enumerateDevices()) .then(devices => ok(devices.length === 0, "No devices found"))); diff --git a/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html b/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html index d3d1a0c3755..9753c669b36 100644 --- a/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html +++ b/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html @@ -25,8 +25,11 @@ var testVideo = createMediaElement('video', 'testVideo'); return Promise.resolve() - .then(() => getUserMedia({ video: { mediaSource: "browser", - scrollWithPage: true } })) + .then(() => getUserMedia({ + video: { mediaSource: "browser", + scrollWithPage: true }, + fake: false + })) .then(stream => { var playback = new LocalMediaStreamPlayback(testVideo, stream); return playback.playMediaWithDeprecatedStreamStop(false); @@ -38,7 +41,8 @@ viewportOffsetY: 0, viewportWidth: 100, viewportHeight: 100 - } + }, + fake: false })) .then(stream => { var playback = new LocalMediaStreamPlayback(testVideo, stream); diff --git a/dom/media/tests/mochitest/test_getUserMedia_constraints.html b/dom/media/tests/mochitest/test_getUserMedia_constraints.html index 88d0d8993ce..9acb61a253a 100644 --- a/dom/media/tests/mochitest/test_getUserMedia_constraints.html +++ b/dom/media/tests/mochitest/test_getUserMedia_constraints.html @@ -16,16 +16,13 @@ createHTML({ title: "Test getUserMedia constraints", bug: "882145" }); var tests = [ // Each test here tests a different constraint or codepath. { message: "unknown required constraint on video ignored", - constraints: { video: { somethingUnknown: { exact: 0 } }, - fake: true }, + constraints: { video: { somethingUnknown: { exact: 0 } } }, error: null }, { message: "unknown required constraint on audio ignored", - constraints: { audio: { somethingUnknown: { exact: 0 } }, - fake: true }, + constraints: { audio: { somethingUnknown: { exact: 0 } } }, error: null }, { message: "audio overconstrained by facingMode ignored", - constraints: { audio: { facingMode: { exact: 'left' } }, - fake: true }, + constraints: { audio: { facingMode: { exact: 'left' } } }, error: null }, { message: "full screensharing requires permission", constraints: { video: { mediaSource: 'screen' } }, @@ -51,8 +48,7 @@ var tests = [ constraints: { }, error: "NotSupportedError" }, { message: "Success-path: optional video facingMode + audio ignoring facingMode", - constraints: { fake: true, - audio: { mediaSource: 'microphone', + constraints: { audio: { mediaSource: 'microphone', facingMode: 'left', foo: 0, advanced: [{ facingMode: 'environment' }, @@ -66,7 +62,7 @@ var tests = [ { bar: 0 }] } }, error: null }, { message: "legacy facingMode ignored", - constraints: { video: { mandatory: { facingMode: 'left' } }, fake: true }, + constraints: { video: { mandatory: { facingMode: 'left' } } }, error: null }, ]; diff --git a/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html b/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html index 108e4f83a17..f680beb533b 100644 --- a/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html +++ b/dom/media/tests/mochitest/test_getUserMedia_peerIdentity.html @@ -13,7 +13,7 @@ createHTML({ }); function theTest() { function testPeerIdentityConstraint(withConstraint) { - var config = { audio: true, video: true, fake: true }; + var config = { audio: true, video: true }; if (withConstraint) { config.peerIdentity = 'user@example.com'; } diff --git a/dom/media/tests/mochitest/test_peerConnection_callbacks.html b/dom/media/tests/mochitest/test_peerConnection_callbacks.html index fb634f1e00e..8bf4b106daf 100644 --- a/dom/media/tests/mochitest/test_peerConnection_callbacks.html +++ b/dom/media/tests/mochitest/test_peerConnection_callbacks.html @@ -65,7 +65,7 @@ runNetworkTest(function() { is(v2.currentTime, 0, "v2.currentTime is zero at outset"); // not testing legacy gUM here - navigator.mediaDevices.getUserMedia({ fake: true, video: true, audio: true }) + navigator.mediaDevices.getUserMedia({ video: true, audio: true }) .then(stream => pc1.addStream(v1.mozSrcObject = stream)) .then(() => pcall(pc1, pc1.createOffer)) .then(offer => pcall(pc1, pc1.setLocalDescription, offer)) diff --git a/dom/media/tests/mochitest/test_peerConnection_captureStream_canvas_2d.html b/dom/media/tests/mochitest/test_peerConnection_captureStream_canvas_2d.html index cf82d4e28a7..624d641d11c 100644 --- a/dom/media/tests/mochitest/test_peerConnection_captureStream_canvas_2d.html +++ b/dom/media/tests/mochitest/test_peerConnection_captureStream_canvas_2d.html @@ -39,7 +39,8 @@ runNetworkTest(() => { ok(!!vremote, "Should have remote video element for pcRemote"); }, function WAIT_FOR_REMOTE_GREEN() { - return h.waitForPixel(vremote, h.green, 128, "pcRemote's remote should become green"); + return h.waitForPixelColor(vremote, h.green, 128, + "pcRemote's remote should become green"); }, function DRAW_LOCAL_RED() { // After requesting a frame it will be captured at the time of next render. @@ -49,7 +50,8 @@ runNetworkTest(() => { h.drawColor(canvas, h.red); }, function WAIT_FOR_REMOTE_RED() { - return h.waitForPixel(vremote, h.red, 128, "pcRemote's remote should become red"); + return h.waitForPixelColor(vremote, h.red, 128, + "pcRemote's remote should become red"); } ]); test.run(); diff --git a/dom/media/tests/mochitest/test_peerConnection_captureStream_canvas_webgl.html b/dom/media/tests/mochitest/test_peerConnection_captureStream_canvas_webgl.html index 3b9377563db..02e4018d459 100644 --- a/dom/media/tests/mochitest/test_peerConnection_captureStream_canvas_webgl.html +++ b/dom/media/tests/mochitest/test_peerConnection_captureStream_canvas_webgl.html @@ -89,7 +89,8 @@ runNetworkTest(() => { ok(!!vremote, "Should have remote video element for pcRemote"); }, function WAIT_FOR_REMOTE_GREEN() { - return h.waitForPixel(vremote, h.green, 128, "pcRemote's remote should become green"); + return h.waitForPixelColor(vremote, h.green, 128, + "pcRemote's remote should become green"); }, function REQUEST_FRAME(test) { // After requesting a frame it will be captured at the time of next render. @@ -101,7 +102,8 @@ runNetworkTest(() => { h.drawColor(canvas, h.red); }, function WAIT_FOR_REMOTE_RED() { - return h.waitForPixel(vremote, h.red, 128, "pcRemote's remote should become red"); + return h.waitForPixelColor(vremote, h.red, 128, + "pcRemote's remote should become red"); } ]); test.run(); diff --git a/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html b/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html index 52f0f77e120..41b302e42c1 100644 --- a/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html +++ b/dom/media/tests/mochitest/test_peerConnection_promiseSendOnly.html @@ -36,7 +36,7 @@ is(v2.currentTime, 0, "v2.currentTime is zero at outset"); - navigator.mediaDevices.getUserMedia({ fake: true, video: true, audio: true }) + navigator.mediaDevices.getUserMedia({ video: true, audio: true }) .then(stream => pc1.addStream(v1.srcObject = stream)) .then(() => pc1.createOffer({})) // check that createOffer accepts arg. .then(offer => pc1.setLocalDescription(offer)) diff --git a/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html b/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html index 7f3a4d4bd8d..62546311a32 100644 --- a/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html +++ b/dom/media/tests/mochitest/test_peerConnection_replaceTrack.html @@ -30,7 +30,7 @@ var newTrack; var audiotrack; - return navigator.mediaDevices.getUserMedia({video:true, audio:true, fake:true}) + return navigator.mediaDevices.getUserMedia({video:true, audio:true}) .then(newStream => { window.grip = newStream; newTrack = newStream.getVideoTracks()[0]; @@ -112,7 +112,8 @@ var sourceNode = test.audioCtx.createOscillator(); sourceNode.type = 'sine'; - // We need a frequency not too close to the fake audio track (1kHz). + // We need a frequency not too close to the fake audio track + // (440Hz for loopback devices, 1kHz for fake tracks). sourceNode.frequency.value = 2000; sourceNode.start(); @@ -157,7 +158,7 @@ is(e.name, "InvalidParameterError", "addTrack existing track should fail"); } - return navigator.mediaDevices.getUserMedia({video:true, fake: true}) + return navigator.mediaDevices.getUserMedia({video:true}) .then(differentStream => { var track = differentStream.getVideoTracks()[0]; try { diff --git a/dom/media/tests/mochitest/test_peerConnection_replaceVideoThenRenegotiate.html b/dom/media/tests/mochitest/test_peerConnection_replaceVideoThenRenegotiate.html index 1693e9e78ef..5e36d7a5e02 100644 --- a/dom/media/tests/mochitest/test_peerConnection_replaceVideoThenRenegotiate.html +++ b/dom/media/tests/mochitest/test_peerConnection_replaceVideoThenRenegotiate.html @@ -21,7 +21,7 @@ var oldstream = test.pcLocal._pc.getLocalStreams()[0]; var oldtrack = oldstream.getVideoTracks()[0]; var sender = test.pcLocal._pc.getSenders()[0]; - return navigator.mediaDevices.getUserMedia({video:true, fake:true}) + return navigator.mediaDevices.getUserMedia({video:true}) .then(newstream => { var newtrack = newstream.getVideoTracks()[0]; return test.pcLocal.senderReplaceTrack(0, newtrack, newstream.id); diff --git a/dom/media/tests/mochitest/test_peerConnection_throwInCallbacks.html b/dom/media/tests/mochitest/test_peerConnection_throwInCallbacks.html index 7c0dec1859b..ad5cb7d868e 100644 --- a/dom/media/tests/mochitest/test_peerConnection_throwInCallbacks.html +++ b/dom/media/tests/mochitest/test_peerConnection_throwInCallbacks.html @@ -48,7 +48,7 @@ runNetworkTest(function () { pc2 = new RTCPeerConnection(); // Test success callbacks (happy path) - navigator.mozGetUserMedia({video:true, fake: true}, function(video1) { + navigator.mozGetUserMedia({video:true}, function(video1) { pc1.addStream(video1); pc1.createOffer(function(offer) { pc1.setLocalDescription(offer, function() { diff --git a/dom/media/tests/mochitest/test_peerConnection_trackDisabling.html b/dom/media/tests/mochitest/test_peerConnection_trackDisabling.html new file mode 100644 index 00000000000..9ab1bbc0efd --- /dev/null +++ b/dom/media/tests/mochitest/test_peerConnection_trackDisabling.html @@ -0,0 +1,95 @@ + + + + + + + +
+
+
+ + diff --git a/dom/media/webaudio/ConvolverNode.cpp b/dom/media/webaudio/ConvolverNode.cpp index c13964fdf24..7764617422d 100644 --- a/dom/media/webaudio/ConvolverNode.cpp +++ b/dom/media/webaudio/ConvolverNode.cpp @@ -96,7 +96,6 @@ public: } mReverb = new WebCore::Reverb(mBuffer, mBufferLength, - WEBAUDIO_BLOCK_SIZE, MaxFFTSize, 2, mUseBackgroundThreads, mNormalize, mSampleRate); } @@ -153,7 +152,7 @@ public: } aOutput->AllocateChannels(2); - mReverb->process(&input, aOutput, WEBAUDIO_BLOCK_SIZE); + mReverb->process(&input, aOutput); } virtual bool IsActive() const override diff --git a/dom/media/webaudio/blink/DirectConvolver.cpp b/dom/media/webaudio/blink/DirectConvolver.cpp deleted file mode 100644 index 43461ad37e1..00000000000 --- a/dom/media/webaudio/blink/DirectConvolver.cpp +++ /dev/null @@ -1,347 +0,0 @@ -/* - * Copyright (C) 2012 Intel Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "DirectConvolver.h" -#include "mozilla/PodOperations.h" - -using namespace mozilla; - -namespace WebCore { - -DirectConvolver::DirectConvolver(size_t inputBlockSize) - : m_inputBlockSize(inputBlockSize) -{ - m_buffer.SetLength(inputBlockSize * 2); - PodZero(m_buffer.Elements(), inputBlockSize * 2); -} - -void DirectConvolver::process(const nsTArray* convolutionKernel, const float* sourceP, float* destP, size_t framesToProcess) -{ - MOZ_ASSERT(framesToProcess == m_inputBlockSize); - if (framesToProcess != m_inputBlockSize) - return; - - // Only support kernelSize <= m_inputBlockSize - size_t kernelSize = convolutionKernel->Length(); - MOZ_ASSERT(kernelSize <= m_inputBlockSize); - if (kernelSize > m_inputBlockSize) - return; - - const float* kernelP = convolutionKernel->Elements(); - - // Sanity check - bool isCopyGood = kernelP && sourceP && destP && m_buffer.Elements(); - MOZ_ASSERT(isCopyGood); - if (!isCopyGood) - return; - - float* inputP = m_buffer.Elements() + m_inputBlockSize; - - // Copy samples to 2nd half of input buffer. - memcpy(inputP, sourceP, sizeof(float) * framesToProcess); - - // FIXME: The macro can be further optimized to avoid pipeline stalls. One possibility is to maintain 4 separate sums and change the macro to CONVOLVE_FOUR_SAMPLES. -#define CONVOLVE_ONE_SAMPLE \ - sum += inputP[i - j] * kernelP[j]; \ - j++; - - size_t i = 0; - while (i < framesToProcess) { - size_t j = 0; - float sum = 0; - - // FIXME: SSE optimization may be applied here. - if (kernelSize == 32) { - CONVOLVE_ONE_SAMPLE // 1 - CONVOLVE_ONE_SAMPLE // 2 - CONVOLVE_ONE_SAMPLE // 3 - CONVOLVE_ONE_SAMPLE // 4 - CONVOLVE_ONE_SAMPLE // 5 - CONVOLVE_ONE_SAMPLE // 6 - CONVOLVE_ONE_SAMPLE // 7 - CONVOLVE_ONE_SAMPLE // 8 - CONVOLVE_ONE_SAMPLE // 9 - CONVOLVE_ONE_SAMPLE // 10 - - CONVOLVE_ONE_SAMPLE // 11 - CONVOLVE_ONE_SAMPLE // 12 - CONVOLVE_ONE_SAMPLE // 13 - CONVOLVE_ONE_SAMPLE // 14 - CONVOLVE_ONE_SAMPLE // 15 - CONVOLVE_ONE_SAMPLE // 16 - CONVOLVE_ONE_SAMPLE // 17 - CONVOLVE_ONE_SAMPLE // 18 - CONVOLVE_ONE_SAMPLE // 19 - CONVOLVE_ONE_SAMPLE // 20 - - CONVOLVE_ONE_SAMPLE // 21 - CONVOLVE_ONE_SAMPLE // 22 - CONVOLVE_ONE_SAMPLE // 23 - CONVOLVE_ONE_SAMPLE // 24 - CONVOLVE_ONE_SAMPLE // 25 - CONVOLVE_ONE_SAMPLE // 26 - CONVOLVE_ONE_SAMPLE // 27 - CONVOLVE_ONE_SAMPLE // 28 - CONVOLVE_ONE_SAMPLE // 29 - CONVOLVE_ONE_SAMPLE // 30 - - CONVOLVE_ONE_SAMPLE // 31 - CONVOLVE_ONE_SAMPLE // 32 - - } else if (kernelSize == 64) { - CONVOLVE_ONE_SAMPLE // 1 - CONVOLVE_ONE_SAMPLE // 2 - CONVOLVE_ONE_SAMPLE // 3 - CONVOLVE_ONE_SAMPLE // 4 - CONVOLVE_ONE_SAMPLE // 5 - CONVOLVE_ONE_SAMPLE // 6 - CONVOLVE_ONE_SAMPLE // 7 - CONVOLVE_ONE_SAMPLE // 8 - CONVOLVE_ONE_SAMPLE // 9 - CONVOLVE_ONE_SAMPLE // 10 - - CONVOLVE_ONE_SAMPLE // 11 - CONVOLVE_ONE_SAMPLE // 12 - CONVOLVE_ONE_SAMPLE // 13 - CONVOLVE_ONE_SAMPLE // 14 - CONVOLVE_ONE_SAMPLE // 15 - CONVOLVE_ONE_SAMPLE // 16 - CONVOLVE_ONE_SAMPLE // 17 - CONVOLVE_ONE_SAMPLE // 18 - CONVOLVE_ONE_SAMPLE // 19 - CONVOLVE_ONE_SAMPLE // 20 - - CONVOLVE_ONE_SAMPLE // 21 - CONVOLVE_ONE_SAMPLE // 22 - CONVOLVE_ONE_SAMPLE // 23 - CONVOLVE_ONE_SAMPLE // 24 - CONVOLVE_ONE_SAMPLE // 25 - CONVOLVE_ONE_SAMPLE // 26 - CONVOLVE_ONE_SAMPLE // 27 - CONVOLVE_ONE_SAMPLE // 28 - CONVOLVE_ONE_SAMPLE // 29 - CONVOLVE_ONE_SAMPLE // 30 - - CONVOLVE_ONE_SAMPLE // 31 - CONVOLVE_ONE_SAMPLE // 32 - CONVOLVE_ONE_SAMPLE // 33 - CONVOLVE_ONE_SAMPLE // 34 - CONVOLVE_ONE_SAMPLE // 35 - CONVOLVE_ONE_SAMPLE // 36 - CONVOLVE_ONE_SAMPLE // 37 - CONVOLVE_ONE_SAMPLE // 38 - CONVOLVE_ONE_SAMPLE // 39 - CONVOLVE_ONE_SAMPLE // 40 - - CONVOLVE_ONE_SAMPLE // 41 - CONVOLVE_ONE_SAMPLE // 42 - CONVOLVE_ONE_SAMPLE // 43 - CONVOLVE_ONE_SAMPLE // 44 - CONVOLVE_ONE_SAMPLE // 45 - CONVOLVE_ONE_SAMPLE // 46 - CONVOLVE_ONE_SAMPLE // 47 - CONVOLVE_ONE_SAMPLE // 48 - CONVOLVE_ONE_SAMPLE // 49 - CONVOLVE_ONE_SAMPLE // 50 - - CONVOLVE_ONE_SAMPLE // 51 - CONVOLVE_ONE_SAMPLE // 52 - CONVOLVE_ONE_SAMPLE // 53 - CONVOLVE_ONE_SAMPLE // 54 - CONVOLVE_ONE_SAMPLE // 55 - CONVOLVE_ONE_SAMPLE // 56 - CONVOLVE_ONE_SAMPLE // 57 - CONVOLVE_ONE_SAMPLE // 58 - CONVOLVE_ONE_SAMPLE // 59 - CONVOLVE_ONE_SAMPLE // 60 - - CONVOLVE_ONE_SAMPLE // 61 - CONVOLVE_ONE_SAMPLE // 62 - CONVOLVE_ONE_SAMPLE // 63 - CONVOLVE_ONE_SAMPLE // 64 - - } else if (kernelSize == 128) { - CONVOLVE_ONE_SAMPLE // 1 - CONVOLVE_ONE_SAMPLE // 2 - CONVOLVE_ONE_SAMPLE // 3 - CONVOLVE_ONE_SAMPLE // 4 - CONVOLVE_ONE_SAMPLE // 5 - CONVOLVE_ONE_SAMPLE // 6 - CONVOLVE_ONE_SAMPLE // 7 - CONVOLVE_ONE_SAMPLE // 8 - CONVOLVE_ONE_SAMPLE // 9 - CONVOLVE_ONE_SAMPLE // 10 - - CONVOLVE_ONE_SAMPLE // 11 - CONVOLVE_ONE_SAMPLE // 12 - CONVOLVE_ONE_SAMPLE // 13 - CONVOLVE_ONE_SAMPLE // 14 - CONVOLVE_ONE_SAMPLE // 15 - CONVOLVE_ONE_SAMPLE // 16 - CONVOLVE_ONE_SAMPLE // 17 - CONVOLVE_ONE_SAMPLE // 18 - CONVOLVE_ONE_SAMPLE // 19 - CONVOLVE_ONE_SAMPLE // 20 - - CONVOLVE_ONE_SAMPLE // 21 - CONVOLVE_ONE_SAMPLE // 22 - CONVOLVE_ONE_SAMPLE // 23 - CONVOLVE_ONE_SAMPLE // 24 - CONVOLVE_ONE_SAMPLE // 25 - CONVOLVE_ONE_SAMPLE // 26 - CONVOLVE_ONE_SAMPLE // 27 - CONVOLVE_ONE_SAMPLE // 28 - CONVOLVE_ONE_SAMPLE // 29 - CONVOLVE_ONE_SAMPLE // 30 - - CONVOLVE_ONE_SAMPLE // 31 - CONVOLVE_ONE_SAMPLE // 32 - CONVOLVE_ONE_SAMPLE // 33 - CONVOLVE_ONE_SAMPLE // 34 - CONVOLVE_ONE_SAMPLE // 35 - CONVOLVE_ONE_SAMPLE // 36 - CONVOLVE_ONE_SAMPLE // 37 - CONVOLVE_ONE_SAMPLE // 38 - CONVOLVE_ONE_SAMPLE // 39 - CONVOLVE_ONE_SAMPLE // 40 - - CONVOLVE_ONE_SAMPLE // 41 - CONVOLVE_ONE_SAMPLE // 42 - CONVOLVE_ONE_SAMPLE // 43 - CONVOLVE_ONE_SAMPLE // 44 - CONVOLVE_ONE_SAMPLE // 45 - CONVOLVE_ONE_SAMPLE // 46 - CONVOLVE_ONE_SAMPLE // 47 - CONVOLVE_ONE_SAMPLE // 48 - CONVOLVE_ONE_SAMPLE // 49 - CONVOLVE_ONE_SAMPLE // 50 - - CONVOLVE_ONE_SAMPLE // 51 - CONVOLVE_ONE_SAMPLE // 52 - CONVOLVE_ONE_SAMPLE // 53 - CONVOLVE_ONE_SAMPLE // 54 - CONVOLVE_ONE_SAMPLE // 55 - CONVOLVE_ONE_SAMPLE // 56 - CONVOLVE_ONE_SAMPLE // 57 - CONVOLVE_ONE_SAMPLE // 58 - CONVOLVE_ONE_SAMPLE // 59 - CONVOLVE_ONE_SAMPLE // 60 - - CONVOLVE_ONE_SAMPLE // 61 - CONVOLVE_ONE_SAMPLE // 62 - CONVOLVE_ONE_SAMPLE // 63 - CONVOLVE_ONE_SAMPLE // 64 - CONVOLVE_ONE_SAMPLE // 65 - CONVOLVE_ONE_SAMPLE // 66 - CONVOLVE_ONE_SAMPLE // 67 - CONVOLVE_ONE_SAMPLE // 68 - CONVOLVE_ONE_SAMPLE // 69 - CONVOLVE_ONE_SAMPLE // 70 - - CONVOLVE_ONE_SAMPLE // 71 - CONVOLVE_ONE_SAMPLE // 72 - CONVOLVE_ONE_SAMPLE // 73 - CONVOLVE_ONE_SAMPLE // 74 - CONVOLVE_ONE_SAMPLE // 75 - CONVOLVE_ONE_SAMPLE // 76 - CONVOLVE_ONE_SAMPLE // 77 - CONVOLVE_ONE_SAMPLE // 78 - CONVOLVE_ONE_SAMPLE // 79 - CONVOLVE_ONE_SAMPLE // 80 - - CONVOLVE_ONE_SAMPLE // 81 - CONVOLVE_ONE_SAMPLE // 82 - CONVOLVE_ONE_SAMPLE // 83 - CONVOLVE_ONE_SAMPLE // 84 - CONVOLVE_ONE_SAMPLE // 85 - CONVOLVE_ONE_SAMPLE // 86 - CONVOLVE_ONE_SAMPLE // 87 - CONVOLVE_ONE_SAMPLE // 88 - CONVOLVE_ONE_SAMPLE // 89 - CONVOLVE_ONE_SAMPLE // 90 - - CONVOLVE_ONE_SAMPLE // 91 - CONVOLVE_ONE_SAMPLE // 92 - CONVOLVE_ONE_SAMPLE // 93 - CONVOLVE_ONE_SAMPLE // 94 - CONVOLVE_ONE_SAMPLE // 95 - CONVOLVE_ONE_SAMPLE // 96 - CONVOLVE_ONE_SAMPLE // 97 - CONVOLVE_ONE_SAMPLE // 98 - CONVOLVE_ONE_SAMPLE // 99 - CONVOLVE_ONE_SAMPLE // 100 - - CONVOLVE_ONE_SAMPLE // 101 - CONVOLVE_ONE_SAMPLE // 102 - CONVOLVE_ONE_SAMPLE // 103 - CONVOLVE_ONE_SAMPLE // 104 - CONVOLVE_ONE_SAMPLE // 105 - CONVOLVE_ONE_SAMPLE // 106 - CONVOLVE_ONE_SAMPLE // 107 - CONVOLVE_ONE_SAMPLE // 108 - CONVOLVE_ONE_SAMPLE // 109 - CONVOLVE_ONE_SAMPLE // 110 - - CONVOLVE_ONE_SAMPLE // 111 - CONVOLVE_ONE_SAMPLE // 112 - CONVOLVE_ONE_SAMPLE // 113 - CONVOLVE_ONE_SAMPLE // 114 - CONVOLVE_ONE_SAMPLE // 115 - CONVOLVE_ONE_SAMPLE // 116 - CONVOLVE_ONE_SAMPLE // 117 - CONVOLVE_ONE_SAMPLE // 118 - CONVOLVE_ONE_SAMPLE // 119 - CONVOLVE_ONE_SAMPLE // 120 - - CONVOLVE_ONE_SAMPLE // 121 - CONVOLVE_ONE_SAMPLE // 122 - CONVOLVE_ONE_SAMPLE // 123 - CONVOLVE_ONE_SAMPLE // 124 - CONVOLVE_ONE_SAMPLE // 125 - CONVOLVE_ONE_SAMPLE // 126 - CONVOLVE_ONE_SAMPLE // 127 - CONVOLVE_ONE_SAMPLE // 128 - } else { - while (j < kernelSize) { - // Non-optimized using actual while loop. - CONVOLVE_ONE_SAMPLE - } - } - destP[i++] = sum; - } - - // Copy 2nd half of input buffer to 1st half. - memcpy(m_buffer.Elements(), inputP, sizeof(float) * framesToProcess); -} - -void DirectConvolver::reset() -{ - PodZero(m_buffer.Elements(), m_buffer.Length()); -} - -} // namespace WebCore diff --git a/dom/media/webaudio/blink/DirectConvolver.h b/dom/media/webaudio/blink/DirectConvolver.h deleted file mode 100644 index 5732da64968..00000000000 --- a/dom/media/webaudio/blink/DirectConvolver.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2012 Intel Inc. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DirectConvolver_h -#define DirectConvolver_h - -#include "nsTArray.h" -#include "mozilla/MemoryReporting.h" - -namespace WebCore { - -class DirectConvolver { -public: - explicit DirectConvolver(size_t inputBlockSize); - - void process(const nsTArray* convolutionKernel, const float* sourceP, float* destP, size_t framesToProcess); - - void reset(); - - size_t sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const - { - size_t amount = aMallocSizeOf(this); - amount += m_buffer.ShallowSizeOfExcludingThis(aMallocSizeOf); - return amount; - } - - -private: - size_t m_inputBlockSize; - - nsTArray m_buffer; -}; - -} // namespace WebCore - -#endif // DirectConvolver_h diff --git a/dom/media/webaudio/blink/FFTConvolver.cpp b/dom/media/webaudio/blink/FFTConvolver.cpp index 9d3305c7d1e..8694073ae21 100644 --- a/dom/media/webaudio/blink/FFTConvolver.cpp +++ b/dom/media/webaudio/blink/FFTConvolver.cpp @@ -33,10 +33,11 @@ using namespace mozilla; namespace WebCore { -FFTConvolver::FFTConvolver(size_t fftSize) +FFTConvolver::FFTConvolver(size_t fftSize, size_t renderPhase) : m_frame(fftSize) - , m_readWriteIndex(0) + , m_readWriteIndex(renderPhase % (fftSize / 2)) { + MOZ_ASSERT(fftSize >= 2 * WEBAUDIO_BLOCK_SIZE); m_inputBuffer.SetLength(fftSize); PodZero(m_inputBuffer.Elements(), fftSize); m_outputBuffer.SetLength(fftSize); @@ -60,67 +61,47 @@ size_t FFTConvolver::sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) co return aMallocSizeOf(this) + sizeOfExcludingThis(aMallocSizeOf); } -void FFTConvolver::process(FFTBlock* fftKernel, const float* sourceP, float* destP, size_t framesToProcess) +const float* FFTConvolver::process(FFTBlock* fftKernel, const float* sourceP) { size_t halfSize = fftSize() / 2; - // framesToProcess must be an exact multiple of halfSize, - // or halfSize is a multiple of framesToProcess when halfSize > framesToProcess. - bool isGood = !(halfSize % framesToProcess && framesToProcess % halfSize); - MOZ_ASSERT(isGood); - if (!isGood) - return; + // WEBAUDIO_BLOCK_SIZE must be an exact multiple of halfSize, + // halfSize must be a multiple of WEBAUDIO_BLOCK_SIZE + // and > WEBAUDIO_BLOCK_SIZE. + MOZ_ASSERT(halfSize % WEBAUDIO_BLOCK_SIZE == 0 && + WEBAUDIO_BLOCK_SIZE <= halfSize); - size_t numberOfDivisions = halfSize <= framesToProcess ? (framesToProcess / halfSize) : 1; - size_t divisionSize = numberOfDivisions == 1 ? framesToProcess : halfSize; + // Copy samples to input buffer (note contraint above!) + float* inputP = m_inputBuffer.Elements(); - for (size_t i = 0; i < numberOfDivisions; ++i, sourceP += divisionSize, destP += divisionSize) { - // Copy samples to input buffer (note contraint above!) - float* inputP = m_inputBuffer.Elements(); + MOZ_ASSERT(sourceP && inputP && m_readWriteIndex + WEBAUDIO_BLOCK_SIZE <= m_inputBuffer.Length()); - // Sanity check - bool isCopyGood1 = sourceP && inputP && m_readWriteIndex + divisionSize <= m_inputBuffer.Length(); - MOZ_ASSERT(isCopyGood1); - if (!isCopyGood1) - return; + memcpy(inputP + m_readWriteIndex, sourceP, sizeof(float) * WEBAUDIO_BLOCK_SIZE); - memcpy(inputP + m_readWriteIndex, sourceP, sizeof(float) * divisionSize); + float* outputP = m_outputBuffer.Elements(); + m_readWriteIndex += WEBAUDIO_BLOCK_SIZE; - // Copy samples from output buffer - float* outputP = m_outputBuffer.Elements(); + // Check if it's time to perform the next FFT + if (m_readWriteIndex == halfSize) { + // The input buffer is now filled (get frequency-domain version) + m_frame.PerformFFT(m_inputBuffer.Elements()); + m_frame.Multiply(*fftKernel); + m_frame.GetInverseWithoutScaling(m_outputBuffer.Elements()); - // Sanity check - bool isCopyGood2 = destP && outputP && m_readWriteIndex + divisionSize <= m_outputBuffer.Length(); - MOZ_ASSERT(isCopyGood2); - if (!isCopyGood2) - return; + // Overlap-add 1st half from previous time + AudioBufferAddWithScale(m_lastOverlapBuffer.Elements(), 1.0f, + m_outputBuffer.Elements(), halfSize); - memcpy(destP, outputP + m_readWriteIndex, sizeof(float) * divisionSize); - m_readWriteIndex += divisionSize; + // Finally, save 2nd half of result + MOZ_ASSERT(m_outputBuffer.Length() == 2 * halfSize && m_lastOverlapBuffer.Length() == halfSize); - // Check if it's time to perform the next FFT - if (m_readWriteIndex == halfSize) { - // The input buffer is now filled (get frequency-domain version) - m_frame.PerformFFT(m_inputBuffer.Elements()); - m_frame.Multiply(*fftKernel); - m_frame.GetInverseWithoutScaling(m_outputBuffer.Elements()); + memcpy(m_lastOverlapBuffer.Elements(), m_outputBuffer.Elements() + halfSize, sizeof(float) * halfSize); - // Overlap-add 1st half from previous time - AudioBufferAddWithScale(m_lastOverlapBuffer.Elements(), 1.0f, - m_outputBuffer.Elements(), halfSize); - - // Finally, save 2nd half of result - bool isCopyGood3 = m_outputBuffer.Length() == 2 * halfSize && m_lastOverlapBuffer.Length() == halfSize; - MOZ_ASSERT(isCopyGood3); - if (!isCopyGood3) - return; - - memcpy(m_lastOverlapBuffer.Elements(), m_outputBuffer.Elements() + halfSize, sizeof(float) * halfSize); - - // Reset index back to start for next time - m_readWriteIndex = 0; - } + // Reset index back to start for next time + m_readWriteIndex = 0; } + + return outputP + m_readWriteIndex; } void FFTConvolver::reset() @@ -129,4 +110,10 @@ void FFTConvolver::reset() m_readWriteIndex = 0; } +size_t FFTConvolver::latencyFrames() const +{ + return std::max(fftSize()/2, WEBAUDIO_BLOCK_SIZE) - + WEBAUDIO_BLOCK_SIZE; +} + } // namespace WebCore diff --git a/dom/media/webaudio/blink/FFTConvolver.h b/dom/media/webaudio/blink/FFTConvolver.h index 53cebf8c876..118c6baef5a 100644 --- a/dom/media/webaudio/blink/FFTConvolver.h +++ b/dom/media/webaudio/blink/FFTConvolver.h @@ -40,24 +40,29 @@ using mozilla::FFTBlock; class FFTConvolver { public: - // fftSize must be a power of two - explicit FFTConvolver(size_t fftSize); + // |fftSize| must be a power of two. + // + // |renderPhase| is the initial offset in the initially zero input buffer. + // It is coordinated with the other stages, so they don't all do their + // FFTs at the same time. + explicit FFTConvolver(size_t fftSize, size_t renderPhase = 0); + // Process WEBAUDIO_BLOCK_SIZE elements of array |sourceP| and return a + // pointer to an output array of the same size. + // // |fftKernel| must be pre-scaled for FFTBlock::GetInverseWithoutScaling(). // - // For now, with multiple calls to Process(), framesToProcess MUST add up EXACTLY to fftSize / 2 - // // FIXME: Later, we can do more sophisticated buffering to relax this requirement... - // - // The input to output latency is equal to fftSize / 2 - // - // Processing in-place is allowed... - void process(FFTBlock* fftKernel, const float* sourceP, float* destP, size_t framesToProcess); + const float* process(FFTBlock* fftKernel, const float* sourceP); void reset(); size_t fftSize() const { return m_frame.FFTSize(); } + // The input to output latency is up to fftSize / 2, but alignment of the + // FFTs with the blocks reduces this by one block. + size_t latencyFrames() const; + size_t sizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; size_t sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; diff --git a/dom/media/webaudio/blink/HRTFElevation.cpp b/dom/media/webaudio/blink/HRTFElevation.cpp index f53943d6c56..c6e04308859 100644 --- a/dom/media/webaudio/blink/HRTFElevation.cpp +++ b/dom/media/webaudio/blink/HRTFElevation.cpp @@ -76,19 +76,19 @@ size_t HRTFElevation::fftSizeForSampleRate(float sampleRate) // This is the size if we were to use all raw response samples. unsigned resampledLength = floorf(ResponseFrameSize * sampleRate / rawSampleRate); - // Keep things semi-sane, with max FFT size of 1024 and minimum of 4. - // "size |= 3" ensures a minimum of 4 (with the size++ below) and sets the - // 2 least significant bits for rounding up to the next power of 2 below. + // Keep things semi-sane, with max FFT size of 1024. unsigned size = min(resampledLength, 1023U); - size |= 3; + // Ensure a minimum of 2 * WEBAUDIO_BLOCK_SIZE (with the size++ below) for + // FFTConvolver and set the 8 least significant bits for rounding up to + // the next power of 2 below. + size |= 2 * WEBAUDIO_BLOCK_SIZE - 1; // Round up to the next power of 2, making the FFT size no more than twice // the impulse response length. This doubles size for values that are - // already powers of 2. This works by filling in 7 bits to right of the + // already powers of 2. This works by filling in alls bit to right of the // most significant bit. The most significant bit is no greater than - // 1 << 9, and the least significant 2 bits were already set above. + // 1 << 9, and the least significant 8 bits were already set above, so + // there is at most one bit to add. size |= (size >> 1); - size |= (size >> 2); - size |= (size >> 4); size++; MOZ_ASSERT((size & (size - 1)) == 0); diff --git a/dom/media/webaudio/blink/HRTFPanner.cpp b/dom/media/webaudio/blink/HRTFPanner.cpp index 11c27289419..c97ce47670f 100644 --- a/dom/media/webaudio/blink/HRTFPanner.cpp +++ b/dom/media/webaudio/blink/HRTFPanner.cpp @@ -59,11 +59,6 @@ HRTFPanner::HRTFPanner(float sampleRate, already_AddRefed da { MOZ_ASSERT(m_databaseLoader); MOZ_COUNT_CTOR(HRTFPanner); - - m_tempL1.SetLength(RenderingQuantum); - m_tempR1.SetLength(RenderingQuantum); - m_tempL2.SetLength(RenderingQuantum); - m_tempR2.SetLength(RenderingQuantum); } HRTFPanner::~HRTFPanner() @@ -81,10 +76,6 @@ size_t HRTFPanner::sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) cons amount += m_convolverL2.sizeOfExcludingThis(aMallocSizeOf); amount += m_convolverR2.sizeOfExcludingThis(aMallocSizeOf); amount += m_delayLine.SizeOfExcludingThis(aMallocSizeOf); - amount += m_tempL1.ShallowSizeOfExcludingThis(aMallocSizeOf); - amount += m_tempL2.ShallowSizeOfExcludingThis(aMallocSizeOf); - amount += m_tempR1.ShallowSizeOfExcludingThis(aMallocSizeOf); - amount += m_tempR2.ShallowSizeOfExcludingThis(aMallocSizeOf); return amount; } @@ -256,23 +247,26 @@ void HRTFPanner::pan(double desiredAzimuth, double elevation, const AudioBlock* bool needsCrossfading = m_crossfadeIncr; - // Have the convolvers render directly to the final destination if we're not cross-fading. - float* convolutionDestinationL1 = needsCrossfading ? m_tempL1.Elements() : destinationL; - float* convolutionDestinationR1 = needsCrossfading ? m_tempR1.Elements() : destinationR; - float* convolutionDestinationL2 = needsCrossfading ? m_tempL2.Elements() : destinationL; - float* convolutionDestinationR2 = needsCrossfading ? m_tempR2.Elements() : destinationR; + const float* convolutionDestinationL1; + const float* convolutionDestinationR1; + const float* convolutionDestinationL2; + const float* convolutionDestinationR2; // Now do the convolutions. // Note that we avoid doing convolutions on both sets of convolvers if we're not currently cross-fading. if (m_crossfadeSelection == CrossfadeSelection1 || needsCrossfading) { - m_convolverL1.process(kernelL1->fftFrame(), destinationL, convolutionDestinationL1, WEBAUDIO_BLOCK_SIZE); - m_convolverR1.process(kernelR1->fftFrame(), destinationR, convolutionDestinationR1, WEBAUDIO_BLOCK_SIZE); + convolutionDestinationL1 = + m_convolverL1.process(kernelL1->fftFrame(), destinationL); + convolutionDestinationR1 = + m_convolverR1.process(kernelR1->fftFrame(), destinationR); } if (m_crossfadeSelection == CrossfadeSelection2 || needsCrossfading) { - m_convolverL2.process(kernelL2->fftFrame(), destinationL, convolutionDestinationL2, WEBAUDIO_BLOCK_SIZE); - m_convolverR2.process(kernelR2->fftFrame(), destinationR, convolutionDestinationR2, WEBAUDIO_BLOCK_SIZE); + convolutionDestinationL2 = + m_convolverL2.process(kernelL2->fftFrame(), destinationL); + convolutionDestinationR2 = + m_convolverR2.process(kernelR2->fftFrame(), destinationR); } if (needsCrossfading) { @@ -298,6 +292,18 @@ void HRTFPanner::pan(double desiredAzimuth, double elevation, const AudioBlock* m_crossfadeX = 0; m_crossfadeIncr = 0; } + } else { + const float* sourceL; + const float* sourceR; + if (m_crossfadeSelection == CrossfadeSelection1) { + sourceL = convolutionDestinationL1; + sourceR = convolutionDestinationR1; + } else { + sourceL = convolutionDestinationL2; + sourceR = convolutionDestinationR2; + } + PodCopy(destinationL, sourceL, WEBAUDIO_BLOCK_SIZE); + PodCopy(destinationR, sourceR, WEBAUDIO_BLOCK_SIZE); } } @@ -307,10 +313,12 @@ int HRTFPanner::maxTailFrames() const // response, there is additional tail time from the approximations in the // implementation. Because HRTFPanner is implemented with a DelayKernel // and a FFTConvolver, the tailTime of the HRTFPanner is the sum of the - // tailTime of the DelayKernel and the tailTime of the FFTConvolver. - // The FFTConvolver has a tail time of fftSize(), including latency of - // fftSize()/2. - return m_delayLine.MaxDelayTicks() + fftSize(); + // tailTime of the DelayKernel and the tailTime of the FFTConvolver. The + // FFTs of the convolver are fftSize(), half of which is latency, but this + // is aligned with blocks and so is reduced by the one block which is + // processed immediately. + return m_delayLine.MaxDelayTicks() + + m_convolverL1.fftSize()/2 + m_convolverL1.latencyFrames(); } } // namespace WebCore diff --git a/dom/media/webaudio/blink/Reverb.cpp b/dom/media/webaudio/blink/Reverb.cpp index a54f92978b4..39f9d59c935 100644 --- a/dom/media/webaudio/blink/Reverb.cpp +++ b/dom/media/webaudio/blink/Reverb.cpp @@ -77,7 +77,7 @@ static float calculateNormalizationScale(ThreadSharedFloatArrayBufferList* respo return scale; } -Reverb::Reverb(ThreadSharedFloatArrayBufferList* impulseResponse, size_t impulseResponseBufferLength, size_t renderSliceSize, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads, bool normalize, float sampleRate) +Reverb::Reverb(ThreadSharedFloatArrayBufferList* impulseResponse, size_t impulseResponseBufferLength, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads, bool normalize, float sampleRate) { float scale = 1; @@ -101,7 +101,7 @@ Reverb::Reverb(ThreadSharedFloatArrayBufferList* impulseResponse, size_t impulse } } - initialize(irChannels, impulseResponseBufferLength, renderSliceSize, + initialize(irChannels, impulseResponseBufferLength, maxFFTSize, numberOfChannels, useBackgroundThreads); } @@ -121,7 +121,7 @@ size_t Reverb::sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const void Reverb::initialize(const nsTArray& impulseResponseBuffer, - size_t impulseResponseBufferLength, size_t renderSliceSize, + size_t impulseResponseBufferLength, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads) { m_impulseResponseLength = impulseResponseBufferLength; @@ -135,10 +135,10 @@ void Reverb::initialize(const nsTArray& impulseResponseBuffer, const float* channel = impulseResponseBuffer[i]; size_t length = impulseResponseBufferLength; - nsAutoPtr convolver(new ReverbConvolver(channel, length, renderSliceSize, maxFFTSize, convolverRenderPhase, useBackgroundThreads)); + nsAutoPtr convolver(new ReverbConvolver(channel, length, maxFFTSize, convolverRenderPhase, useBackgroundThreads)); m_convolvers.AppendElement(convolver.forget()); - convolverRenderPhase += renderSliceSize; + convolverRenderPhase += WEBAUDIO_BLOCK_SIZE; } // For "True" stereo processing we allocate a temporary buffer to avoid repeatedly allocating it in the process() method. @@ -149,12 +149,12 @@ void Reverb::initialize(const nsTArray& impulseResponseBuffer, } } -void Reverb::process(const AudioBlock* sourceBus, AudioBlock* destinationBus, size_t framesToProcess) +void Reverb::process(const AudioBlock* sourceBus, AudioBlock* destinationBus) { // Do a fairly comprehensive sanity check. // If these conditions are satisfied, all of the source and destination pointers will be valid for the various matrixing cases. bool isSafeToProcess = sourceBus && destinationBus && sourceBus->ChannelCount() > 0 && destinationBus->mChannelData.Length() > 0 - && framesToProcess <= MaxFrameSize && framesToProcess <= size_t(sourceBus->GetDuration()) && framesToProcess <= size_t(destinationBus->GetDuration()); + && WEBAUDIO_BLOCK_SIZE <= MaxFrameSize && WEBAUDIO_BLOCK_SIZE <= size_t(sourceBus->GetDuration()) && WEBAUDIO_BLOCK_SIZE <= size_t(destinationBus->GetDuration()); MOZ_ASSERT(isSafeToProcess); if (!isSafeToProcess) @@ -175,28 +175,28 @@ void Reverb::process(const AudioBlock* sourceBus, AudioBlock* destinationBus, si // 2 -> 2 -> 2 const float* sourceBusR = static_cast(sourceBus->mChannelData[1]); float* destinationChannelR = static_cast(const_cast(destinationBus->mChannelData[1])); - m_convolvers[0]->process(sourceBusL, sourceBus->GetDuration(), destinationChannelL, destinationBus->GetDuration(), framesToProcess); - m_convolvers[1]->process(sourceBusR, sourceBus->GetDuration(), destinationChannelR, destinationBus->GetDuration(), framesToProcess); + m_convolvers[0]->process(sourceBusL, destinationChannelL); + m_convolvers[1]->process(sourceBusR, destinationChannelR); } else if (numInputChannels == 1 && numOutputChannels == 2 && numReverbChannels == 2) { // 1 -> 2 -> 2 for (int i = 0; i < 2; ++i) { float* destinationChannel = static_cast(const_cast(destinationBus->mChannelData[i])); - m_convolvers[i]->process(sourceBusL, sourceBus->GetDuration(), destinationChannel, destinationBus->GetDuration(), framesToProcess); + m_convolvers[i]->process(sourceBusL, destinationChannel); } } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 2) { // 1 -> 1 -> 2 - m_convolvers[0]->process(sourceBusL, sourceBus->GetDuration(), destinationChannelL, destinationBus->GetDuration(), framesToProcess); + m_convolvers[0]->process(sourceBusL, destinationChannelL); // simply copy L -> R float* destinationChannelR = static_cast(const_cast(destinationBus->mChannelData[1])); - bool isCopySafe = destinationChannelL && destinationChannelR && size_t(destinationBus->GetDuration()) >= framesToProcess; + bool isCopySafe = destinationChannelL && destinationChannelR && size_t(destinationBus->GetDuration()) >= WEBAUDIO_BLOCK_SIZE; MOZ_ASSERT(isCopySafe); if (!isCopySafe) return; - PodCopy(destinationChannelR, destinationChannelL, framesToProcess); + PodCopy(destinationChannelR, destinationChannelL, WEBAUDIO_BLOCK_SIZE); } else if (numInputChannels == 1 && numReverbChannels == 1 && numOutputChannels == 1) { // 1 -> 1 -> 1 - m_convolvers[0]->process(sourceBusL, sourceBus->GetDuration(), destinationChannelL, destinationBus->GetDuration(), framesToProcess); + m_convolvers[0]->process(sourceBusL, destinationChannelL); } else if (numInputChannels == 2 && numReverbChannels == 4 && numOutputChannels == 2) { // 2 -> 4 -> 2 ("True" stereo) const float* sourceBusR = static_cast(sourceBus->mChannelData[1]); @@ -206,12 +206,12 @@ void Reverb::process(const AudioBlock* sourceBus, AudioBlock* destinationBus, si float* tempChannelR = static_cast(const_cast(m_tempBuffer.mChannelData[1])); // Process left virtual source - m_convolvers[0]->process(sourceBusL, sourceBus->GetDuration(), destinationChannelL, destinationBus->GetDuration(), framesToProcess); - m_convolvers[1]->process(sourceBusL, sourceBus->GetDuration(), destinationChannelR, destinationBus->GetDuration(), framesToProcess); + m_convolvers[0]->process(sourceBusL, destinationChannelL); + m_convolvers[1]->process(sourceBusL, destinationChannelR); // Process right virtual source - m_convolvers[2]->process(sourceBusR, sourceBus->GetDuration(), tempChannelL, m_tempBuffer.GetDuration(), framesToProcess); - m_convolvers[3]->process(sourceBusR, sourceBus->GetDuration(), tempChannelR, m_tempBuffer.GetDuration(), framesToProcess); + m_convolvers[2]->process(sourceBusR, tempChannelL); + m_convolvers[3]->process(sourceBusR, tempChannelR); AudioBufferAddWithScale(tempChannelL, 1.0f, destinationChannelL, sourceBus->GetDuration()); AudioBufferAddWithScale(tempChannelR, 1.0f, destinationChannelR, sourceBus->GetDuration()); @@ -224,12 +224,12 @@ void Reverb::process(const AudioBlock* sourceBus, AudioBlock* destinationBus, si float* tempChannelR = static_cast(const_cast(m_tempBuffer.mChannelData[1])); // Process left virtual source - m_convolvers[0]->process(sourceBusL, sourceBus->GetDuration(), destinationChannelL, destinationBus->GetDuration(), framesToProcess); - m_convolvers[1]->process(sourceBusL, sourceBus->GetDuration(), destinationChannelR, destinationBus->GetDuration(), framesToProcess); + m_convolvers[0]->process(sourceBusL, destinationChannelL); + m_convolvers[1]->process(sourceBusL, destinationChannelR); // Process right virtual source - m_convolvers[2]->process(sourceBusL, sourceBus->GetDuration(), tempChannelL, m_tempBuffer.GetDuration(), framesToProcess); - m_convolvers[3]->process(sourceBusL, sourceBus->GetDuration(), tempChannelR, m_tempBuffer.GetDuration(), framesToProcess); + m_convolvers[2]->process(sourceBusL, tempChannelL); + m_convolvers[3]->process(sourceBusL, tempChannelR); AudioBufferAddWithScale(tempChannelL, 1.0f, destinationChannelL, sourceBus->GetDuration()); AudioBufferAddWithScale(tempChannelR, 1.0f, destinationChannelR, sourceBus->GetDuration()); @@ -240,15 +240,4 @@ void Reverb::process(const AudioBlock* sourceBus, AudioBlock* destinationBus, si } } -void Reverb::reset() -{ - for (size_t i = 0; i < m_convolvers.Length(); ++i) - m_convolvers[i]->reset(); -} - -size_t Reverb::latencyFrames() const -{ - return !m_convolvers.IsEmpty() ? m_convolvers[0]->latencyFrames() : 0; -} - } // namespace WebCore diff --git a/dom/media/webaudio/blink/Reverb.h b/dom/media/webaudio/blink/Reverb.h index fd4445ec333..35e72283dcd 100644 --- a/dom/media/webaudio/blink/Reverb.h +++ b/dom/media/webaudio/blink/Reverb.h @@ -48,18 +48,22 @@ public: enum { MaxFrameSize = 256 }; // renderSliceSize is a rendering hint, so the FFTs can be optimized to not all occur at the same time (very bad when rendering on a real-time thread). - Reverb(mozilla::ThreadSharedFloatArrayBufferList* impulseResponseBuffer, size_t impulseResponseBufferLength, size_t renderSliceSize, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads, bool normalize, float sampleRate); + Reverb(mozilla::ThreadSharedFloatArrayBufferList* impulseResponseBuffer, + size_t impulseResponseBufferLength, size_t maxFFTSize, + size_t numberOfChannels, bool useBackgroundThreads, bool normalize, + float sampleRate); - void process(const mozilla::AudioBlock* sourceBus, mozilla::AudioBlock* destinationBus, size_t framesToProcess); - void reset(); + void process(const mozilla::AudioBlock* sourceBus, + mozilla::AudioBlock* destinationBus); size_t impulseResponseLength() const { return m_impulseResponseLength; } - size_t latencyFrames() const; size_t sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; private: - void initialize(const nsTArray& impulseResponseBuffer, size_t impulseResponseBufferLength, size_t renderSliceSize, size_t maxFFTSize, size_t numberOfChannels, bool useBackgroundThreads); + void initialize(const nsTArray& impulseResponseBuffer, + size_t impulseResponseBufferLength, size_t maxFFTSize, + size_t numberOfChannels, bool useBackgroundThreads); size_t m_impulseResponseLength; diff --git a/dom/media/webaudio/blink/ReverbAccumulationBuffer.cpp b/dom/media/webaudio/blink/ReverbAccumulationBuffer.cpp index 6b92e9983e9..18d22289444 100644 --- a/dom/media/webaudio/blink/ReverbAccumulationBuffer.cpp +++ b/dom/media/webaudio/blink/ReverbAccumulationBuffer.cpp @@ -76,7 +76,7 @@ void ReverbAccumulationBuffer::updateReadIndex(int* readIndex, size_t numberOfFr *readIndex = (*readIndex + numberOfFrames) % m_buffer.Length(); } -int ReverbAccumulationBuffer::accumulate(float* source, size_t numberOfFrames, int* readIndex, size_t delayFrames) +int ReverbAccumulationBuffer::accumulate(const float* source, size_t numberOfFrames, int* readIndex, size_t delayFrames) { size_t bufferLength = m_buffer.Length(); diff --git a/dom/media/webaudio/blink/ReverbAccumulationBuffer.h b/dom/media/webaudio/blink/ReverbAccumulationBuffer.h index e07e71061ce..97ee94d271d 100644 --- a/dom/media/webaudio/blink/ReverbAccumulationBuffer.h +++ b/dom/media/webaudio/blink/ReverbAccumulationBuffer.h @@ -50,7 +50,7 @@ public: // We need to pass in and update readIndex here, since each ReverbConvolverStage may be running in // a different thread than the realtime thread calling ReadAndClear() and maintaining m_readIndex // Returns the writeIndex where the accumulation took place - int accumulate(float* source, size_t numberOfFrames, int* readIndex, size_t delayFrames); + int accumulate(const float* source, size_t numberOfFrames, int* readIndex, size_t delayFrames); size_t readIndex() const { return m_readIndex; } void updateReadIndex(int* readIndex, size_t numberOfFrames) const; diff --git a/dom/media/webaudio/blink/ReverbConvolver.cpp b/dom/media/webaudio/blink/ReverbConvolver.cpp index 34212864d96..5d386df6a02 100644 --- a/dom/media/webaudio/blink/ReverbConvolver.cpp +++ b/dom/media/webaudio/blink/ReverbConvolver.cpp @@ -49,29 +49,32 @@ const int InputBufferSize = 8 * 16384; // This was found to be a good value on Mac OS X, and may work well on other platforms as well, assuming // the very rough scheduling latencies are similar on these time-scales. Of course, this code may need to be // tuned for individual platforms if this assumption is found to be incorrect. -const size_t RealtimeFrameLimit = 8192 + 4096; // ~278msec @ 44.1KHz +const size_t RealtimeFrameLimit = 8192 + 4096 // ~278msec @ 44.1KHz + - WEBAUDIO_BLOCK_SIZE; +// First stage will have size MinFFTSize - successive stages will double in +// size each time until we hit the maximum size. +const size_t MinFFTSize = 256; +// If we are using background threads then don't exceed this FFT size for the +// stages which run in the real-time thread. This avoids having only one or +// two large stages (size 16384 or so) at the end which take a lot of time +// every several processing slices. This way we amortize the cost over more +// processing slices. +const size_t MaxRealtimeFFTSize = 4096; -const size_t MinFFTSize = 128; -const size_t MaxRealtimeFFTSize = 2048; - -ReverbConvolver::ReverbConvolver(const float* impulseResponseData, size_t impulseResponseLength, size_t renderSliceSize, size_t maxFFTSize, size_t convolverRenderPhase, bool useBackgroundThreads) +ReverbConvolver::ReverbConvolver(const float* impulseResponseData, + size_t impulseResponseLength, + size_t maxFFTSize, + size_t convolverRenderPhase, + bool useBackgroundThreads) : m_impulseResponseLength(impulseResponseLength) - , m_accumulationBuffer(impulseResponseLength + renderSliceSize) + , m_accumulationBuffer(impulseResponseLength + WEBAUDIO_BLOCK_SIZE) , m_inputBuffer(InputBufferSize) - , m_minFFTSize(MinFFTSize) // First stage will have this size - successive stages will double in size each time - , m_maxFFTSize(maxFFTSize) // until we hit m_maxFFTSize , m_backgroundThread("ConvolverWorker") , m_backgroundThreadCondition(&m_backgroundThreadLock) , m_useBackgroundThreads(useBackgroundThreads) , m_wantsToExit(false) , m_moreInputBuffered(false) { - // If we are using background threads then don't exceed this FFT size for the - // stages which run in the real-time thread. This avoids having only one or two - // large stages (size 16384 or so) at the end which take a lot of time every several - // processing slices. This way we amortize the cost over more processing slices. - m_maxRealtimeFFTSize = MaxRealtimeFFTSize; - // For the moment, a good way to know if we have real-time constraint is to check if we're using background threads. // Otherwise, assume we're being run from a command-line tool. bool hasRealtimeConstraint = useBackgroundThreads; @@ -79,12 +82,13 @@ ReverbConvolver::ReverbConvolver(const float* impulseResponseData, size_t impuls const float* response = impulseResponseData; size_t totalResponseLength = impulseResponseLength; - // The total latency is zero because the direct-convolution is used in the leading portion. + // The total latency is zero because the first FFT stage is small enough + // to return output in the first block. size_t reverbTotalLatency = 0; size_t stageOffset = 0; - int i = 0; - size_t fftSize = m_minFFTSize; + size_t stagePhase = 0; + size_t fftSize = MinFFTSize; while (stageOffset < totalResponseLength) { size_t stageSize = fftSize / 2; @@ -94,11 +98,13 @@ ReverbConvolver::ReverbConvolver(const float* impulseResponseData, size_t impuls stageSize = totalResponseLength - stageOffset; // This "staggers" the time when each FFT happens so they don't all happen at the same time - int renderPhase = convolverRenderPhase + i * renderSliceSize; + int renderPhase = convolverRenderPhase + stagePhase; - bool useDirectConvolver = !stageOffset; - - nsAutoPtr stage(new ReverbConvolverStage(response, totalResponseLength, reverbTotalLatency, stageOffset, stageSize, fftSize, renderPhase, renderSliceSize, &m_accumulationBuffer, useDirectConvolver)); + nsAutoPtr stage + (new ReverbConvolverStage(response, totalResponseLength, + reverbTotalLatency, stageOffset, stageSize, + fftSize, renderPhase, + &m_accumulationBuffer)); bool isBackgroundStage = false; @@ -108,18 +114,35 @@ ReverbConvolver::ReverbConvolver(const float* impulseResponseData, size_t impuls } else m_stages.AppendElement(stage.forget()); + // Figure out next FFT size + fftSize *= 2; + stageOffset += stageSize; - ++i; - if (!useDirectConvolver) { - // Figure out next FFT size - fftSize *= 2; + if (hasRealtimeConstraint && !isBackgroundStage + && fftSize > MaxRealtimeFFTSize) { + fftSize = MaxRealtimeFFTSize; + // Custom phase positions for all but the first of the realtime + // stages of largest size. These spread out the work of the + // larger realtime stages. None of the FFTs of size 1024, 2048 or + // 4096 are performed when processing the same block. The first + // MaxRealtimeFFTSize = 4096 stage, at the end of the doubling, + // performs its FFT at block 7. The FFTs of size 2048 are + // performed in blocks 3 + 8 * n and size 1024 at 1 + 4 * n. + const uint32_t phaseLookup[] = { 14, 0, 10, 4 }; + stagePhase = WEBAUDIO_BLOCK_SIZE * + phaseLookup[m_stages.Length() % ArrayLength(phaseLookup)]; + } else if (fftSize > maxFFTSize) { + fftSize = maxFFTSize; + // A prime offset spreads out FFTs in a way that all + // available phase positions will be used if there are sufficient + // stages. + stagePhase += 5 * WEBAUDIO_BLOCK_SIZE; + } else if (stageSize > WEBAUDIO_BLOCK_SIZE) { + // As the stages are doubling in size, the next FFT will occur + // mid-way between FFTs for this stage. + stagePhase = stageSize - WEBAUDIO_BLOCK_SIZE; } - - if (hasRealtimeConstraint && !isBackgroundStage && fftSize > m_maxRealtimeFFTSize) - fftSize = m_maxRealtimeFFTSize; - if (fftSize > m_maxFFTSize) - fftSize = m_maxFFTSize; } // Start up background thread @@ -199,25 +222,16 @@ void ReverbConvolver::backgroundThreadEntry() int readIndex; while ((readIndex = m_backgroundStages[0]->inputReadIndex()) != writeIndex) { // FIXME: do better to detect buffer overrun... - // The ReverbConvolverStages need to process in amounts which evenly divide half the FFT size - const int SliceSize = MinFFTSize / 2; - // Accumulate contributions from each stage for (size_t i = 0; i < m_backgroundStages.Length(); ++i) - m_backgroundStages[i]->processInBackground(this, SliceSize); + m_backgroundStages[i]->processInBackground(this); } } } -void ReverbConvolver::process(const float* sourceChannelData, size_t sourceChannelLength, - float* destinationChannelData, size_t destinationChannelLength, - size_t framesToProcess) +void ReverbConvolver::process(const float* sourceChannelData, + float* destinationChannelData) { - bool isSafe = sourceChannelData && destinationChannelData && sourceChannelLength >= framesToProcess && destinationChannelLength >= framesToProcess; - MOZ_ASSERT(isSafe); - if (!isSafe) - return; - const float* source = sourceChannelData; float* destination = destinationChannelData; bool isDataSafe = source && destination; @@ -226,14 +240,14 @@ void ReverbConvolver::process(const float* sourceChannelData, size_t sourceChann return; // Feed input buffer (read by all threads) - m_inputBuffer.write(source, framesToProcess); + m_inputBuffer.write(source, WEBAUDIO_BLOCK_SIZE); // Accumulate contributions from each stage for (size_t i = 0; i < m_stages.Length(); ++i) - m_stages[i]->process(source, framesToProcess); + m_stages[i]->process(source); // Finally read from accumulation buffer - m_accumulationBuffer.readAndClear(destination, framesToProcess); + m_accumulationBuffer.readAndClear(destination, WEBAUDIO_BLOCK_SIZE); // Now that we've buffered more input, wake up our background thread. @@ -249,21 +263,4 @@ void ReverbConvolver::process(const float* sourceChannelData, size_t sourceChann } } -void ReverbConvolver::reset() -{ - for (size_t i = 0; i < m_stages.Length(); ++i) - m_stages[i]->reset(); - - for (size_t i = 0; i < m_backgroundStages.Length(); ++i) - m_backgroundStages[i]->reset(); - - m_accumulationBuffer.reset(); - m_inputBuffer.reset(); -} - -size_t ReverbConvolver::latencyFrames() const -{ - return 0; -} - } // namespace WebCore diff --git a/dom/media/webaudio/blink/ReverbConvolver.h b/dom/media/webaudio/blink/ReverbConvolver.h index 14b2ff2573c..b7eea45b868 100644 --- a/dom/media/webaudio/blink/ReverbConvolver.h +++ b/dom/media/webaudio/blink/ReverbConvolver.h @@ -50,13 +50,13 @@ public: // For certain tweaky de-convolving applications the phase errors add up quickly and lead to non-sensical results with // larger FFT sizes and single-precision floats. In these cases 2048 is a good size. // If not doing multi-threaded convolution, then should not go > 8192. - ReverbConvolver(const float* impulseResponseData, size_t impulseResponseLength, size_t renderSliceSize, size_t maxFFTSize, size_t convolverRenderPhase, bool useBackgroundThreads); + ReverbConvolver(const float* impulseResponseData, + size_t impulseResponseLength, size_t maxFFTSize, + size_t convolverRenderPhase, bool useBackgroundThreads); ~ReverbConvolver(); - void process(const float* sourceChannelData, size_t sourceChannelLength, - float* destinationChannelData, size_t destinationChannelLength, - size_t framesToProcess); - void reset(); + void process(const float* sourceChannelData, + float* destinationChannelData); size_t impulseResponseLength() const { return m_impulseResponseLength; } @@ -65,8 +65,6 @@ public: bool useBackgroundThreads() const { return m_useBackgroundThreads; } void backgroundThreadEntry(); - size_t latencyFrames() const; - size_t sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; private: nsTArray > m_stages; @@ -78,13 +76,6 @@ private: // One or more background threads read from this input buffer which is fed from the realtime thread. ReverbInputBuffer m_inputBuffer; - // First stage will be of size m_minFFTSize. Each next stage will be twice as big until we hit m_maxFFTSize. - size_t m_minFFTSize; - size_t m_maxFFTSize; - - // But don't exceed this size in the real-time thread (if we're doing background processing). - size_t m_maxRealtimeFFTSize; - // Background thread and synchronization base::Thread m_backgroundThread; Lock m_backgroundThreadLock; diff --git a/dom/media/webaudio/blink/ReverbConvolverStage.cpp b/dom/media/webaudio/blink/ReverbConvolverStage.cpp index fe6a0929cbb..055098e887d 100644 --- a/dom/media/webaudio/blink/ReverbConvolverStage.cpp +++ b/dom/media/webaudio/blink/ReverbConvolverStage.cpp @@ -37,54 +37,32 @@ using namespace mozilla; namespace WebCore { -ReverbConvolverStage::ReverbConvolverStage(const float* impulseResponse, size_t, size_t reverbTotalLatency, size_t stageOffset, size_t stageLength, - size_t fftSize, size_t renderPhase, size_t renderSliceSize, ReverbAccumulationBuffer* accumulationBuffer, bool directMode) +ReverbConvolverStage::ReverbConvolverStage(const float* impulseResponse, size_t, + size_t reverbTotalLatency, + size_t stageOffset, + size_t stageLength, + size_t fftSize, size_t renderPhase, + ReverbAccumulationBuffer* accumulationBuffer) : m_accumulationBuffer(accumulationBuffer) , m_accumulationReadIndex(0) , m_inputReadIndex(0) - , m_directMode(directMode) { MOZ_ASSERT(impulseResponse); MOZ_ASSERT(accumulationBuffer); - if (!m_directMode) { - m_fftKernel = new FFTBlock(fftSize); - m_fftKernel->PadAndMakeScaledDFT(impulseResponse + stageOffset, stageLength); - m_fftConvolver = new FFTConvolver(fftSize); - } else { - m_directKernel.SetLength(fftSize / 2); - PodCopy(m_directKernel.Elements(), impulseResponse + stageOffset, fftSize / 2); - m_directConvolver = new DirectConvolver(renderSliceSize); - } - m_temporaryBuffer.SetLength(renderSliceSize); - PodZero(m_temporaryBuffer.Elements(), m_temporaryBuffer.Length()); + m_fftKernel = new FFTBlock(fftSize); + m_fftKernel->PadAndMakeScaledDFT(impulseResponse + stageOffset, stageLength); + m_fftConvolver = new FFTConvolver(fftSize, renderPhase); // The convolution stage at offset stageOffset needs to have a corresponding delay to cancel out the offset. size_t totalDelay = stageOffset + reverbTotalLatency; - // But, the FFT convolution itself incurs fftSize / 2 latency, so subtract this out... - size_t halfSize = fftSize / 2; - if (!m_directMode) { - MOZ_ASSERT(totalDelay >= halfSize); - if (totalDelay >= halfSize) - totalDelay -= halfSize; - } + // But, the FFT convolution itself incurs latency, so subtract this out... + size_t fftLatency = m_fftConvolver->latencyFrames(); + MOZ_ASSERT(totalDelay >= fftLatency); + totalDelay -= fftLatency; - // We divide up the total delay, into pre and post delay sections so that we can schedule at exactly the moment when the FFT will happen. - // This is coordinated with the other stages, so they don't all do their FFTs at the same time... - int maxPreDelayLength = std::min(halfSize, totalDelay); - m_preDelayLength = totalDelay > 0 ? renderPhase % maxPreDelayLength : 0; - if (m_preDelayLength > totalDelay) - m_preDelayLength = 0; - - m_postDelayLength = totalDelay - m_preDelayLength; - m_preReadWriteIndex = 0; - m_framesProcessed = 0; // total frames processed so far - - size_t delayBufferSize = m_preDelayLength < fftSize ? fftSize : m_preDelayLength; - delayBufferSize = delayBufferSize < renderSliceSize ? renderSliceSize : delayBufferSize; - m_preDelayBuffer.SetLength(delayBufferSize); - PodZero(m_preDelayBuffer.Elements(), m_preDelayBuffer.Length()); + m_postDelayLength = totalDelay; } size_t ReverbConvolverStage::sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const @@ -99,101 +77,31 @@ size_t ReverbConvolverStage::sizeOfIncludingThis(mozilla::MallocSizeOf aMallocSi amount += m_fftConvolver->sizeOfIncludingThis(aMallocSizeOf); } - amount += m_preDelayBuffer.ShallowSizeOfExcludingThis(aMallocSizeOf); - amount += m_temporaryBuffer.ShallowSizeOfExcludingThis(aMallocSizeOf); - amount += m_directKernel.ShallowSizeOfExcludingThis(aMallocSizeOf); - - if (m_directConvolver) { - amount += m_directConvolver->sizeOfIncludingThis(aMallocSizeOf); - } - return amount; } -void ReverbConvolverStage::processInBackground(ReverbConvolver* convolver, size_t framesToProcess) +void ReverbConvolverStage::processInBackground(ReverbConvolver* convolver) { ReverbInputBuffer* inputBuffer = convolver->inputBuffer(); - float* source = inputBuffer->directReadFrom(&m_inputReadIndex, framesToProcess); - process(source, framesToProcess); + float* source = inputBuffer->directReadFrom(&m_inputReadIndex, + WEBAUDIO_BLOCK_SIZE); + process(source); } -void ReverbConvolverStage::process(const float* source, size_t framesToProcess) +void ReverbConvolverStage::process(const float* source) { MOZ_ASSERT(source); if (!source) return; - // Deal with pre-delay stream : note special handling of zero delay. + // Now, run the convolution (into the delay buffer). + // An expensive FFT will happen every fftSize / 2 frames. + const float* output = m_fftConvolver->process(m_fftKernel, source); - const float* preDelayedSource; - float* preDelayedDestination; - float* temporaryBuffer; - bool isTemporaryBufferSafe = false; - if (m_preDelayLength > 0) { - // Handles both the read case (call to process() ) and the write case (memcpy() ) - bool isPreDelaySafe = m_preReadWriteIndex + framesToProcess <= m_preDelayBuffer.Length(); - MOZ_ASSERT(isPreDelaySafe); - if (!isPreDelaySafe) - return; - - isTemporaryBufferSafe = framesToProcess <= m_temporaryBuffer.Length(); - - preDelayedDestination = m_preDelayBuffer.Elements() + m_preReadWriteIndex; - preDelayedSource = preDelayedDestination; - temporaryBuffer = m_temporaryBuffer.Elements(); - } else { - // Zero delay - preDelayedDestination = 0; - preDelayedSource = source; - temporaryBuffer = m_preDelayBuffer.Elements(); - - isTemporaryBufferSafe = framesToProcess <= m_preDelayBuffer.Length(); - } - - MOZ_ASSERT(isTemporaryBufferSafe); - if (!isTemporaryBufferSafe) - return; - - if (m_framesProcessed < m_preDelayLength) { - // For the first m_preDelayLength frames don't process the convolver, instead simply buffer in the pre-delay. - // But while buffering the pre-delay, we still need to update our index. - m_accumulationBuffer->updateReadIndex(&m_accumulationReadIndex, framesToProcess); - } else { - // Now, run the convolution (into the delay buffer). - // An expensive FFT will happen every fftSize / 2 frames. - // We process in-place here... - if (!m_directMode) - m_fftConvolver->process(m_fftKernel, preDelayedSource, temporaryBuffer, framesToProcess); - else - m_directConvolver->process(&m_directKernel, preDelayedSource, temporaryBuffer, framesToProcess); - - // Now accumulate into reverb's accumulation buffer. - m_accumulationBuffer->accumulate(temporaryBuffer, framesToProcess, &m_accumulationReadIndex, m_postDelayLength); - } - - // Finally copy input to pre-delay. - if (m_preDelayLength > 0) { - memcpy(preDelayedDestination, source, sizeof(float) * framesToProcess); - m_preReadWriteIndex += framesToProcess; - - MOZ_ASSERT(m_preReadWriteIndex <= m_preDelayLength); - if (m_preReadWriteIndex >= m_preDelayLength) - m_preReadWriteIndex = 0; - } - - m_framesProcessed += framesToProcess; -} - -void ReverbConvolverStage::reset() -{ - if (!m_directMode) - m_fftConvolver->reset(); - else - m_directConvolver->reset(); - PodZero(m_preDelayBuffer.Elements(), m_preDelayBuffer.Length()); - m_accumulationReadIndex = 0; - m_inputReadIndex = 0; - m_framesProcessed = 0; + // Now accumulate into reverb's accumulation buffer. + m_accumulationBuffer->accumulate(output, WEBAUDIO_BLOCK_SIZE, + &m_accumulationReadIndex, + m_postDelayLength); } } // namespace WebCore diff --git a/dom/media/webaudio/blink/ReverbConvolverStage.h b/dom/media/webaudio/blink/ReverbConvolverStage.h index 73879477bed..3dfe81bbdf1 100644 --- a/dom/media/webaudio/blink/ReverbConvolverStage.h +++ b/dom/media/webaudio/blink/ReverbConvolverStage.h @@ -29,7 +29,6 @@ #ifndef ReverbConvolverStage_h #define ReverbConvolverStage_h -#include "DirectConvolver.h" #include "FFTConvolver.h" #include "nsTArray.h" @@ -49,14 +48,12 @@ class ReverbConvolverStage { public: // renderPhase is useful to know so that we can manipulate the pre versus post delay so that stages will perform // their heavy work (FFT processing) on different slices to balance the load in a real-time thread. - ReverbConvolverStage(const float* impulseResponse, size_t responseLength, size_t reverbTotalLatency, size_t stageOffset, size_t stageLength, size_t fftSize, size_t renderPhase, size_t renderSliceSize, ReverbAccumulationBuffer*, bool directMode = false); + ReverbConvolverStage(const float* impulseResponse, size_t responseLength, size_t reverbTotalLatency, size_t stageOffset, size_t stageLength, size_t fftSize, size_t renderPhase, ReverbAccumulationBuffer*); - // WARNING: framesToProcess must be such that it evenly divides the delay buffer size (stage_offset). - void process(const float* source, size_t framesToProcess); + // |source| must point to an array of WEBAUDIO_BLOCK_SIZE elements. + void process(const float* source); - void processInBackground(ReverbConvolver* convolver, size_t framesToProcess); - - void reset(); + void processInBackground(ReverbConvolver* convolver); // Useful for background processing int inputReadIndex() const { return m_inputReadIndex; } @@ -67,22 +64,13 @@ private: nsAutoPtr m_fftKernel; nsAutoPtr m_fftConvolver; - nsTArray m_preDelayBuffer; - ReverbAccumulationBuffer* m_accumulationBuffer; int m_accumulationReadIndex; int m_inputReadIndex; - size_t m_preDelayLength; size_t m_postDelayLength; - size_t m_preReadWriteIndex; - size_t m_framesProcessed; nsTArray m_temporaryBuffer; - - bool m_directMode; - nsTArray m_directKernel; - nsAutoPtr m_directConvolver; }; } // namespace WebCore diff --git a/dom/media/webaudio/blink/moz.build b/dom/media/webaudio/blink/moz.build index 196609f03ca..fd622d0749a 100644 --- a/dom/media/webaudio/blink/moz.build +++ b/dom/media/webaudio/blink/moz.build @@ -6,7 +6,6 @@ UNIFIED_SOURCES += [ 'Biquad.cpp', - 'DirectConvolver.cpp', 'DynamicsCompressor.cpp', 'DynamicsCompressorKernel.cpp', 'FFTConvolver.cpp', diff --git a/dom/plugins/test/mochitest/browser.ini b/dom/plugins/test/mochitest/browser.ini index ea83e339555..076b7e4c5d3 100644 --- a/dom/plugins/test/mochitest/browser.ini +++ b/dom/plugins/test/mochitest/browser.ini @@ -12,4 +12,4 @@ skip-if = (!e10s || os != "win") [browser_tabswitchbetweenplugins.js] skip-if = (!e10s || os != "win") [browser_pluginscroll.js] -skip-if = (!e10s || os != "win") +skip-if = (true || !e10s || os != "win") # Bug 1213631 diff --git a/dom/push/Push.js b/dom/push/Push.js index d1e1f3e5a0d..d85611e1805 100644 --- a/dom/push/Push.js +++ b/dom/push/Push.js @@ -68,9 +68,12 @@ Push.prototype = { debug("askPermission"); return this.createPromise((resolve, reject) => { - function permissionDenied() { - reject("PermissionDeniedError"); - } + let permissionDenied = () => { + reject(new this._window.DOMException( + "User denied permission to use the Push API", + "PermissionDeniedError" + )); + }; let permission = Ci.nsIPermissionManager.UNKNOWN_ACTION; try { @@ -190,7 +193,10 @@ PushEndpointCallback.prototype = { onPushEndpoint: function(ok, endpoint, keyLen, key) { let {pushManager} = this; if (!Components.isSuccessCode(ok)) { - this.reject("AbortError"); + this.reject(new pushManager._window.DOMException( + "Error retrieving push subscription", + "AbortError" + )); return; } diff --git a/dom/push/PushManager.cpp b/dom/push/PushManager.cpp index 5fdbc3707af..5a4044b0cdf 100644 --- a/dom/push/PushManager.cpp +++ b/dom/push/PushManager.cpp @@ -426,12 +426,13 @@ public: do_CreateInstance("@mozilla.org/push/PushClient;1"); if (!client) { callback->OnUnsubscribe(NS_ERROR_FAILURE, false); + return NS_OK; } nsCOMPtr principal = mProxy->GetWorkerPrivate()->GetPrincipal(); if (NS_WARN_IF(NS_FAILED(client->Unsubscribe(mScope, principal, callback)))) { callback->OnUnsubscribe(NS_ERROR_FAILURE, false); - return NS_ERROR_FAILURE; + return NS_OK; } return NS_OK; } @@ -521,7 +522,7 @@ public: promise->MaybeResolve(sub); } } else { - promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR); + promise->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR); } mProxy->CleanUp(aCx); @@ -647,7 +648,7 @@ public: if (NS_WARN_IF(NS_FAILED(rv))) { callback->OnPushEndpoint(NS_ERROR_FAILURE, EmptyString(), 0, nullptr); - return rv; + return NS_OK; } return NS_OK; @@ -677,7 +678,7 @@ WorkerPushManager::PerformSubscriptionAction(SubscriptionAction aAction, ErrorRe RefPtr proxy = PromiseWorkerProxy::Create(worker, p); if (!proxy) { - p->MaybeReject(NS_ERROR_DOM_ABORT_ERR); + p->MaybeReject(NS_ERROR_DOM_PUSH_ABORT_ERR); return p.forget(); } diff --git a/dom/push/test/test_permissions.html b/dom/push/test/test_permissions.html index 9ae76f55e39..508978f69c9 100644 --- a/dom/push/test/test_permissions.html +++ b/dom/push/test/test_permissions.html @@ -49,7 +49,8 @@ http://creativecommons.org/licenses/publicdomain/ yield registration.pushManager.subscribe(); ok(false, "subscribe() should fail because no permission for push"); } catch (error) { - ok(true, "subscribe() could not register for push notification"); + ok(error instanceof DOMException, "Wrong exception type"); + is(error.name, "PermissionDeniedError", "Wrong exception name"); } }); diff --git a/dom/svg/SVGSwitchElement.h b/dom/svg/SVGSwitchElement.h index ce7b7965557..1fbf5fd92ea 100644 --- a/dom/svg/SVGSwitchElement.h +++ b/dom/svg/SVGSwitchElement.h @@ -21,7 +21,7 @@ typedef SVGGraphicsElement SVGSwitchElementBase; class SVGSwitchElement final : public SVGSwitchElementBase { - friend class nsSVGSwitchFrame; + friend class ::nsSVGSwitchFrame; protected: friend nsresult (::NS_NewSVGSwitchElement(nsIContent **aResult, already_AddRefed&& aNodeInfo)); diff --git a/dom/system/gonk/moz.build b/dom/system/gonk/moz.build index 3552b6fb1ee..14c2d4e5455 100644 --- a/dom/system/gonk/moz.build +++ b/dom/system/gonk/moz.build @@ -66,9 +66,9 @@ UNIFIED_SOURCES += [ ] if CONFIG['ANDROID_VERSION'] >= '17': - CXXFLAGS += ['-I%s/frameworks/av/media/mtp' % CONFIG['ANDROID_SOURCE']] + LOCAL_INCLUDES += ['%' + '%s/frameworks/av/media/mtp' % CONFIG['ANDROID_SOURCE']] else: - CXXFLAGS += ['-I%s/frameworks/base/media/mtp' % CONFIG['ANDROID_SOURCE']] + LOCAL_INCLUDES += ['%' + '%s/frameworks/base/media/mtp' % CONFIG['ANDROID_SOURCE']] if CONFIG['ENABLE_TESTS']: XPCSHELL_TESTS_MANIFESTS += ['tests/xpcshell.ini'] diff --git a/gfx/angle/moz.build b/gfx/angle/moz.build index 479c374f4d9..a13e401542c 100644 --- a/gfx/angle/moz.build +++ b/gfx/angle/moz.build @@ -129,7 +129,7 @@ if CONFIG['GNU_CXX']: ] if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']: - CXXFLAGS += ['-I\'%s/include/\'' % CONFIG['MOZ_DIRECTX_SDK_PATH']] + LOCAL_INCLUDES += ['%' + '%s/include/' % CONFIG['MOZ_DIRECTX_SDK_PATH']] DEFINES['_CRT_SECURE_NO_DEPRECATE'] = True DEFINES['_HAS_EXCEPTIONS'] = 0 diff --git a/gfx/angle/src/libANGLE/moz.build b/gfx/angle/src/libANGLE/moz.build index b29440b033c..d38c3de81d6 100644 --- a/gfx/angle/src/libANGLE/moz.build +++ b/gfx/angle/src/libANGLE/moz.build @@ -277,7 +277,7 @@ if CONFIG['GNU_CXX']: ] if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']: - CXXFLAGS += ['-I\'%s/include/\'' % CONFIG['MOZ_DIRECTX_SDK_PATH']] + LOCAL_INCLUDES += ['%' + '%s/include/' % CONFIG['MOZ_DIRECTX_SDK_PATH']] DEFINES['_CRT_SECURE_NO_DEPRECATE'] = True DEFINES['_HAS_EXCEPTIONS'] = 0 diff --git a/gfx/angle/src/libEGL/moz.build b/gfx/angle/src/libEGL/moz.build index d4d25ab5784..f4cd9ebffd7 100644 --- a/gfx/angle/src/libEGL/moz.build +++ b/gfx/angle/src/libEGL/moz.build @@ -33,7 +33,7 @@ if CONFIG['GNU_CXX']: ] if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']: - CXXFLAGS += ['-I\'%s/include/\'' % CONFIG['MOZ_DIRECTX_SDK_PATH']] + LOCAL_INCLUDES += ['%' + '%s/include/' % CONFIG['MOZ_DIRECTX_SDK_PATH']] DEFINES['_CRT_SECURE_NO_DEPRECATE'] = True DEFINES['_HAS_EXCEPTIONS'] = 0 diff --git a/gfx/angle/src/libGLESv2/moz.build b/gfx/angle/src/libGLESv2/moz.build index 96c840389c2..561b266f484 100644 --- a/gfx/angle/src/libGLESv2/moz.build +++ b/gfx/angle/src/libGLESv2/moz.build @@ -39,7 +39,7 @@ if CONFIG['GNU_CXX']: ] if CONFIG['MOZ_DIRECTX_SDK_PATH'] and not CONFIG['MOZ_HAS_WINSDK_WITH_D3D']: - CXXFLAGS += ['-I\'%s/include/\'' % CONFIG['MOZ_DIRECTX_SDK_PATH']] + LOCAL_INCLUDES += ['%' + '%s/include/' % CONFIG['MOZ_DIRECTX_SDK_PATH']] DEFINES['_CRT_SECURE_NO_DEPRECATE'] = True DEFINES['_HAS_EXCEPTIONS'] = 0 diff --git a/gfx/gl/GLUploadHelpers.h b/gfx/gl/GLUploadHelpers.h index 5ce7875fc24..46db6fe0681 100644 --- a/gfx/gl/GLUploadHelpers.h +++ b/gfx/gl/GLUploadHelpers.h @@ -9,8 +9,7 @@ #include "GLDefs.h" #include "mozilla/gfx/Types.h" #include "nsPoint.h" - -class nsIntRegion; +#include "nsRegionFwd.h" namespace mozilla { diff --git a/gfx/gl/moz.build b/gfx/gl/moz.build index 6a0b78e62f9..2a10bbf99be 100644 --- a/gfx/gl/moz.build +++ b/gfx/gl/moz.build @@ -86,7 +86,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': UNIFIED_SOURCES += ['SharedSurfaceGralloc.cpp'] EXPORTS += ['SharedSurfaceGralloc.h'] LOCAL_INCLUDES += ['/widget/gonk'] - CXXFLAGS += ['-I%s/%s' % (CONFIG['ANDROID_SOURCE'], 'hardware/libhardware/include')] + LOCAL_INCLUDES += ['%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], 'hardware/libhardware/include')] if gl_provider == 'CGL': # These files include Mac headers that are unfriendly to unified builds diff --git a/gfx/layers/Compositor.h b/gfx/layers/Compositor.h index 5b7d830bfdb..77ebeac5ccb 100644 --- a/gfx/layers/Compositor.h +++ b/gfx/layers/Compositor.h @@ -106,7 +106,6 @@ */ class nsIWidget; -class nsIntRegion; namespace mozilla { namespace gfx { diff --git a/gfx/layers/ReadbackProcessor.h b/gfx/layers/ReadbackProcessor.h index 4ca78205ec2..b07f796c32f 100644 --- a/gfx/layers/ReadbackProcessor.h +++ b/gfx/layers/ReadbackProcessor.h @@ -8,9 +8,8 @@ #include // for uint64_t #include "nsRect.h" // for mozilla::gfx::IntRect +#include "nsRegionFwd.h" // for nsIntRegion #include "nsTArray.h" // for nsTArray - -class nsIntRegion; namespace mozilla { namespace layers { diff --git a/gfx/layers/apz/util/APZCCallbackHelper.cpp b/gfx/layers/apz/util/APZCCallbackHelper.cpp index ce510f92ad0..20fdcef01d2 100644 --- a/gfx/layers/apz/util/APZCCallbackHelper.cpp +++ b/gfx/layers/apz/util/APZCCallbackHelper.cpp @@ -161,8 +161,14 @@ SetDisplayPortMargins(nsIPresShell* aPresShell, return; } + bool hadDisplayPort = nsLayoutUtils::GetDisplayPort(aContent); ScreenMargin margins = aMetrics.GetDisplayPortMargins(); nsLayoutUtils::SetDisplayPortMargins(aContent, aPresShell, margins, 0); + if (!hadDisplayPort) { + nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors( + aContent->GetPrimaryFrame(), nsLayoutUtils::RepaintMode::Repaint); + } + CSSRect baseCSS = aMetrics.CalculateCompositedRectInCssPixels(); nsRect base(0, 0, baseCSS.width * nsPresContext::AppUnitsPerCSSPixel(), @@ -237,6 +243,7 @@ APZCCallbackHelper::UpdateRootFrame(FrameMetrics& aMetrics) // adjusts the display port margins, so do it before we set those. ScrollFrame(content, aMetrics); + MOZ_ASSERT(nsLayoutUtils::GetDisplayPort(content)); SetDisplayPortMargins(shell, content, aMetrics); } @@ -304,6 +311,8 @@ APZCCallbackHelper::InitializeRootDisplayport(nsIPresShell* aPresShell) // nsRootBoxFrame::BuildDisplayList. nsLayoutUtils::SetDisplayPortMargins(content, aPresShell, ScreenMargin(), 0, nsLayoutUtils::RepaintMode::DoNotRepaint); + nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors( + content->GetPrimaryFrame(), nsLayoutUtils::RepaintMode::DoNotRepaint); } } @@ -551,15 +560,6 @@ APZCCallbackHelper::FireSingleTapEvent(const LayoutDevicePoint& aPoint, DispatchSynthesizedMouseEvent(eMouseUp, time, aPoint, aModifiers, aWidget); } -static nsIScrollableFrame* -GetScrollableAncestorFrame(nsIFrame* aTarget) -{ - uint32_t flags = nsLayoutUtils::SCROLLABLE_ALWAYS_MATCH_ROOT - | nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE - | nsLayoutUtils::SCROLLABLE_FIXEDPOS_FINDS_ROOT; - return nsLayoutUtils::GetNearestScrollableFrame(aTarget, flags); -} - static dom::Element* GetDisplayportElementFor(nsIScrollableFrame* aScrollableFrame) { @@ -610,7 +610,7 @@ PrepareForSetTargetAPZCNotification(nsIWidget* aWidget, nsIFrame* target = nsLayoutUtils::GetFrameForPoint(aRootFrame, point, nsLayoutUtils::IGNORE_ROOT_SCROLL_FRAME); nsIScrollableFrame* scrollAncestor = target - ? GetScrollableAncestorFrame(target) + ? nsLayoutUtils::GetAsyncScrollableAncestorFrame(target) : aRootFrame->PresContext()->PresShell()->GetRootScrollFrameAsScrollable(); // Assuming that if there's no scrollAncestor, there's already a displayPort. @@ -651,8 +651,17 @@ PrepareForSetTargetAPZCNotification(nsIWidget* aWidget, } APZCCH_LOG("%p didn't have a displayport, so setting one...\n", dpElement.get()); - return nsLayoutUtils::CalculateAndSetDisplayPortMargins( + bool activated = nsLayoutUtils::CalculateAndSetDisplayPortMargins( scrollAncestor, nsLayoutUtils::RepaintMode::Repaint); + if (!activated) { + return false; + } + + nsIFrame* frame = do_QueryFrame(scrollAncestor); + nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(frame, + nsLayoutUtils::RepaintMode::Repaint); + + return true; } static void diff --git a/gfx/layers/composite/ImageHost.cpp b/gfx/layers/composite/ImageHost.cpp index 0c7a1ef0eec..b240c1cf3ce 100644 --- a/gfx/layers/composite/ImageHost.cpp +++ b/gfx/layers/composite/ImageHost.cpp @@ -17,8 +17,6 @@ #include "nsPrintfCString.h" // for nsPrintfCString #include "nsString.h" // for nsAutoCString -class nsIntRegion; - #define BIAS_TIME_MS 1.0 namespace mozilla { diff --git a/gfx/layers/composite/ImageHost.h b/gfx/layers/composite/ImageHost.h index e77afa9a006..c710705e647 100644 --- a/gfx/layers/composite/ImageHost.h +++ b/gfx/layers/composite/ImageHost.h @@ -20,10 +20,9 @@ #include "mozilla/mozalloc.h" // for operator delete #include "nsCOMPtr.h" // for already_AddRefed #include "nsRect.h" // for mozilla::gfx::IntRect +#include "nsRegionFwd.h" // for nsIntRegion #include "nscore.h" // for nsACString -class nsIntRegion; - namespace mozilla { namespace gfx { class Matrix4x4; diff --git a/gfx/layers/layerviewer/hide.png b/gfx/layers/layerviewer/hide.png new file mode 100644 index 00000000000..9a92e2c1b1e Binary files /dev/null and b/gfx/layers/layerviewer/hide.png differ diff --git a/gfx/layers/layerviewer/index.html b/gfx/layers/layerviewer/index.html new file mode 100644 index 00000000000..3ad835df567 --- /dev/null +++ b/gfx/layers/layerviewer/index.html @@ -0,0 +1,47 @@ + + + + GFX Display List & Layer Visualizer + + + + + + +

GFX Layers dump visualizer:

+ Paste your display list or layers dump into this textarea:
+ +
+ +
+
+ Help: To get a layers dump go to about:config and set layout.display-list.dump;true or layers.dump;true. + + + diff --git a/gfx/layers/layerviewer/layerTreeView.js b/gfx/layers/layerviewer/layerTreeView.js new file mode 100644 index 00000000000..e5ecac2511a --- /dev/null +++ b/gfx/layers/layerviewer/layerTreeView.js @@ -0,0 +1,885 @@ +function toFixed(num, fixed) { + fixed = fixed || 0; + fixed = Math.pow(10, fixed); + return Math.floor(num * fixed) / fixed; +} +function createElement(name, props) { + var el = document.createElement(name); + + for (var key in props) { + if (key === "style") { + for (var styleName in props.style) { + el.style[styleName] = props.style[styleName]; + } + } else { + el[key] = props[key]; + } + } + + return el; +} + +function parseDisplayList(lines) { + var root = { + line: "DisplayListRoot 0", + name: "DisplayListRoot", + address: "0x0", + frame: "Root", + children: [], + }; + + var objectAtIndentation = { + "-1": root, + }; + + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + + var layerObject = { + line: line, + children: [], + } + if (!root) { + root = layerObject; + } + + var matches = line.match("(\\s*)(\\w+)\\sp=(\\w+)\\sf=(.*?)\\((.*?)\\)\\s(z=(\\w+)\\s)?(.*?)?( layer=(\\w+))?$"); + if (!matches) { + dump("Failed to match: " + line + "\n"); + continue; + } + + var indentation = Math.floor(matches[1].length / 2); + objectAtIndentation[indentation] = layerObject; + var parent = objectAtIndentation[indentation - 1]; + if (parent) { + parent.children.push(layerObject); + } + + layerObject.name = matches[2]; + layerObject.address = matches[3]; // Use 0x prefix to be consistent with layer dump + layerObject.frame = matches[4]; + layerObject.contentDescriptor = matches[5]; + layerObject.z = matches[7]; + var rest = matches[8]; + if (matches[10]) { // WrapList don't provide a layer + layerObject.layer = matches[10]; + } + layerObject.rest = rest; + + // the content node name doesn't have a prefix, this makes the parsing easier + rest = "content" + rest; + + var fields = {}; + var nesting = 0; + var startIndex; + var lastSpace = -1; + var lastFieldStart = -1; + for (var j = 0; j < rest.length; j++) { + if (rest.charAt(j) == '(') { + nesting++; + if (nesting == 1) { + startIndex = j; + } + } else if (rest.charAt(j) == ')') { + nesting--; + if (nesting == 0) { + var name = rest.substring(lastSpace + 1, startIndex); + var value = rest.substring(startIndex + 1, j); + + var rectMatches = value.match("^(.*?),(.*?),(.*?),(.*?)$") + if (rectMatches) { + layerObject[name] = [ + parseFloat(rectMatches[1]), + parseFloat(rectMatches[2]), + parseFloat(rectMatches[3]), + parseFloat(rectMatches[4]), + ]; + } else { + layerObject[name] = value; + } + } + } else if (nesting == 0 && rest.charAt(j) == ' ') { + lastSpace = j; + } + } + //dump("FIELDS: " + JSON.stringify(fields) + "\n"); + } + return root; +} + +function trim(s){ + return ( s || '' ).replace( /^\s+|\s+$/g, '' ); +} + +function getDataURI(str) { + if (str.indexOf("data:image/png;base64,") == 0) { + return str; + } + + var matches = str.match("data:image/lz4bgra;base64,([0-9]+),([0-9]+),([0-9]+),(.*)"); + if (!matches) + return null; + + var canvas = document.createElement("canvas"); + var w = parseInt(matches[1]); + var stride = parseInt(matches[2]); + var h = parseInt(matches[3]); + canvas.width = w; + canvas.height = h; + + // TODO handle stride + + var binary_string = window.atob(matches[4]); + var len = binary_string.length; + var bytes = new Uint8Array(len); + var decoded = new Uint8Array(stride * h); + for (var i = 0; i < len; i++) { + var ascii = binary_string.charCodeAt(i); + bytes[i] = ascii; + } + + var ctxt = canvas.getContext("2d"); + var out = ctxt.createImageData(w, h); + buffer = LZ4_uncompressChunk(bytes, decoded); + + for (var x = 0; x < w; x++) { + for (var y = 0; y < h; y++) { + out.data[4 * x + 4 * y * w + 0] = decoded[4 * x + y * stride + 2]; + out.data[4 * x + 4 * y * w + 1] = decoded[4 * x + y * stride + 1]; + out.data[4 * x + 4 * y * w + 2] = decoded[4 * x + y * stride + 0]; + out.data[4 * x + 4 * y * w + 3] = decoded[4 * x + y * stride + 3]; + } + } + + ctxt.putImageData(out, 0, 0); + return canvas.toDataURL(); +} + +function parseLayers(layersDumpLines) { + function parseMatrix2x3(str) { + str = trim(str); + + // Something like '[ 1 0; 0 1; 0 158; ]' + var matches = str.match("^\\[ (.*?) (.*?); (.*?) (.*?); (.*?) (.*?); \\]$"); + if (!matches) { + return null; + } + + var matrix = [ + [parseFloat(matches[1]), parseFloat(matches[2])], + [parseFloat(matches[3]), parseFloat(matches[4])], + [parseFloat(matches[5]), parseFloat(matches[6])], + ]; + + return matrix; + } + function parseColor(str) { + str = trim(str); + + // Something like 'rgba(0, 0, 0, 0)' + var colorMatches = str.match("^rgba\\((.*), (.*), (.*), (.*)\\)$"); + if (!colorMatches) { + return null; + } + + var color = { + r: colorMatches[1], + g: colorMatches[2], + b: colorMatches[3], + a: colorMatches[4], + }; + return color; + } + function parseFloat_cleo(str) { + str = trim(str); + + // Something like 2.000 + if (parseFloat(str) == str) { + return parseFloat(str); + } + + return null; + } + function parseRect2D(str) { + str = trim(str); + + // Something like '(x=0, y=0, w=2842, h=158)' + var rectMatches = str.match("^\\(x=(.*?), y=(.*?), w=(.*?), h=(.*?)\\)$"); + if (!rectMatches) { + return null; + } + + var rect = [ + parseFloat(rectMatches[1]), parseFloat(rectMatches[2]), + parseFloat(rectMatches[3]), parseFloat(rectMatches[4]), + ]; + return rect; + } + function parseRegion(str) { + str = trim(str); + + // Something like '< (x=0, y=0, w=2842, h=158); (x=0, y=1718, w=2842, h=500); >' + if (str.charAt(0) != '<' || str.charAt(str.length - 1) != '>') { + return null; + } + + var region = []; + str = trim(str.substring(1, str.length - 1)); + while (str != "") { + var rectMatches = str.match("^\\(x=(.*?), y=(.*?), w=(.*?), h=(.*?)\\);(.*)$"); + if (!rectMatches) { + return null; + } + + var rect = [ + parseFloat(rectMatches[1]), parseFloat(rectMatches[2]), + parseFloat(rectMatches[3]), parseFloat(rectMatches[4]), + ]; + str = trim(rectMatches[5]); + region.push(rect); + } + return region; + } + + var LAYERS_LINE_REGEX = "(\\s*)(\\w+)\\s\\((\\w+)\\)(.*)"; + + var root; + var objectAtIndentation = []; + for (var i = 0; i < layersDumpLines.length; i++) { + // Something like 'ThebesLayerComposite (0x12104cc00) [shadow-visible=< (x=0, y=0, w=1920, h=158); >] [visible=< (x=0, y=0, w=1920, h=158); >] [opaqueContent] [valid=< (x=0, y=0, w=1920, h=2218); >]' + var line = layersDumpLines[i].name || layersDumpLines[i]; + + var tileMatches = line.match("(\\s*)Tile \\(x=(.*), y=(.*)\\): (.*)"); + if (tileMatches) { + var indentation = Math.floor(matches[1].length / 2); + var x = tileMatches[2]; + var y = tileMatches[3]; + var dataUri = tileMatches[4]; + var parent = objectAtIndentation[indentation - 1]; + var tiles = parent.tiles || {}; + + tiles[x] = tiles[x] || {}; + tiles[x][y] = dataUri; + + parent.tiles = tiles; + + continue; + } + + var surfaceMatches = line.match("(\\s*)Surface: (.*)"); + if (surfaceMatches) { + var indentation = Math.floor(matches[1].length / 2); + var parent = objectAtIndentation[indentation - 1] || objectAtIndentation[indentation - 2]; + + var surfaceURI = surfaceMatches[2]; + if (parent.surfaceURI != null) { + console.log("error: surfaceURI already set for this layer " + parent.line); + } + parent.surfaceURI = surfaceURI; + + // Look for the buffer-rect offset + var contentHostLine = layersDumpLines[i - 2].name || layersDumpLines[i - 2]; + var matches = contentHostLine.match(LAYERS_LINE_REGEX); + if (matches) { + var contentHostRest = matches[4]; + parent.contentHostProp = {}; + parseProperties(contentHostRest, parent.contentHostProp); + } + + continue; + } + + var layerObject = { + line: line, + children: [], + } + if (!root) { + root = layerObject; + } + + var matches = line.match(LAYERS_LINE_REGEX); + if (!matches) { + continue; // Something like a texturehost dump. Safe to ignore + } + + if (matches[2].indexOf("TiledContentHost") != -1 || + matches[2].indexOf("GrallocTextureHostOGL") != -1 || + matches[2].indexOf("ContentHost") != -1 || + matches[2].indexOf("ContentClient") != -1 || + matches[2].indexOf("MemoryTextureHost") != -1 || + matches[2].indexOf("ImageHost") != -1) { + continue; // We're already pretty good at visualizing these + } + + var indentation = Math.floor(matches[1].length / 2); + objectAtIndentation[indentation] = layerObject; + for (var c = indentation + 1; c < objectAtIndentation.length; c++) { + objectAtIndentation[c] = null; + } + if (indentation > 0) { + var parent = objectAtIndentation[indentation - 1]; + while (!parent) { + indentation--; + parent = objectAtIndentation[indentation - 1]; + } + + parent.children.push(layerObject); + } + + layerObject.name = matches[2]; + layerObject.address = matches[3]; + + var rest = matches[4]; + + function parseProperties(rest, layerObject) { + var fields = []; + var nesting = 0; + var startIndex; + for (var j = 0; j < rest.length; j++) { + if (rest.charAt(j) == '[') { + nesting++; + if (nesting == 1) { + startIndex = j; + } + } else if (rest.charAt(j) == ']') { + nesting--; + if (nesting == 0) { + fields.push(rest.substring(startIndex + 1, j)); + } + } + } + + for (var j = 0; j < fields.length; j++) { + // Something like 'valid=< (x=0, y=0, w=1920, h=2218); >' or 'opaqueContent' + var field = fields[j]; + //dump("FIELD: " + field + "\n"); + var parts = field.split("=", 2); + var fieldName = parts[0]; + var rest = field.substring(fieldName.length + 1); + if (parts.length == 1) { + layerObject[fieldName] = "true"; + layerObject[fieldName].type = "bool"; + continue; + } + var float = parseFloat_cleo(rest); + if (float) { + layerObject[fieldName] = float; + layerObject[fieldName].type = "float"; + continue; + } + var region = parseRegion(rest); + if (region) { + layerObject[fieldName] = region; + layerObject[fieldName].type = "region"; + continue; + } + var rect = parseRect2D(rest); + if (rect) { + layerObject[fieldName] = rect; + layerObject[fieldName].type = "rect2d"; + continue; + } + var matrix = parseMatrix2x3(rest); + if (matrix) { + layerObject[fieldName] = matrix; + layerObject[fieldName].type = "matrix2x3"; + continue; + } + var color = parseColor(rest); + if (color) { + layerObject[fieldName] = color; + layerObject[fieldName].type = "color"; + continue; + } + if (rest[0] == '{' && rest[rest.length - 1] == '}') { + var object = {}; + parseProperties(rest.substring(1, rest.length - 2).trim(), object); + layerObject[fieldName] = object; + layerObject[fieldName].type = "object"; + continue; + } + fieldName = fieldName.split(" ")[0]; + layerObject[fieldName] = rest[0]; + layerObject[fieldName].type = "string"; + } + } + parseProperties(rest, layerObject); + + if (!layerObject['shadow-transform']) { + // No shadow transform = identify + layerObject['shadow-transform'] = [[1, 0], [0, 1], [0, 0]]; + } + + // Compute screenTransformX/screenTransformY + // TODO Fully support transforms + if (layerObject['shadow-transform'] && layerObject['transform']) { + layerObject['screen-transform'] = [layerObject['shadow-transform'][2][0], layerObject['shadow-transform'][2][1]]; + var currIndentation = indentation - 1; + while (currIndentation >= 0) { + var transform = objectAtIndentation[currIndentation]['shadow-transform'] || objectAtIndentation[currIndentation]['transform']; + if (transform) { + layerObject['screen-transform'][0] += transform[2][0]; + layerObject['screen-transform'][1] += transform[2][1]; + } + currIndentation--; + } + } + + //dump("Fields: " + JSON.stringify(fields) + "\n"); + } + root.compositeTime = layersDumpLines.compositeTime; + //dump("OBJECTS: " + JSON.stringify(root) + "\n"); + return root; +} +function populateLayers(root, displayList, pane, previewParent, hasSeenRoot, contentScale, rootPreviewParent) { + + contentScale = contentScale || 1; + rootPreviewParent = rootPreviewParent || previewParent; + + function getDisplayItemForLayer(displayList) { + var items = []; + if (!displayList) { + return items; + } + if (displayList.layer == root.address) { + items.push(displayList); + } + for (var i = 0; i < displayList.children.length; i++) { + var subDisplayItems = getDisplayItemForLayer(displayList.children[i]); + for (var j = 0; j < subDisplayItems.length; j++) { + items.push(subDisplayItems[j]); + } + } + return items; + } + var elem = createElement("div", { + className: "layerObjectDescription", + textContent: root.line, + style: { + whiteSpace: "pre", + }, + onmouseover: function() { + if (this.layerViewport) { + this.layerViewport.classList.add("layerHover"); + } + }, + onmouseout: function() { + if (this.layerViewport) { + this.layerViewport.classList.remove("layerHover"); + } + }, + }); + var icon = createElement("img", { + src: "show.png", + style: { + width: "12px", + height: "12px", + marginLeft: "4px", + marginRight: "4px", + cursor: "pointer", + }, + onclick: function() { + if (this.layerViewport) { + if (this.layerViewport.style.visibility == "hidden") { + this.layerViewport.style.visibility = ""; + this.src = "show.png" + } else { + this.layerViewport.style.visibility = "hidden"; + this.src = "hide.png" + } + } + } + }); + elem.insertBefore(icon, elem.firstChild); + pane.appendChild(elem); + + if (root["shadow-visible"] || root["visible"]) { + var visibleRegion = root["shadow-visible"] || root["visible"]; + var layerViewport = createElement("div", { + id: root.address + "_viewport", + style: { + position: "absolute", + pointerEvents: "none", + }, + }); + elem.layerViewport = layerViewport; + icon.layerViewport = layerViewport; + var layerViewportMatrix = [1, 0, 0, 1, 0, 0]; + if (root["shadow-clip"] || root["clip"]) { + var clip = root["shadow-clip"] || root["clip"] + var clipElem = createElement("div", { + id: root.address + "_clip", + style: { + left: clip[0]+"px", + top: clip[1]+"px", + width: clip[2]+"px", + height: clip[3]+"px", + position: "absolute", + overflow: "hidden", + pointerEvents: "none", + }, + }); + layerViewportMatrix[4] += -clip[0]; + layerViewportMatrix[5] += -clip[1]; + layerViewport.style.transform = "translate(-" + clip[0] + "px, -" + clip[1] + "px" + ")"; + } + if (root["shadow-transform"] || root["transform"]) { + var matrix = root["shadow-transform"] || root["transform"]; + layerViewportMatrix[0] = matrix[0][0]; + layerViewportMatrix[1] = matrix[0][1]; + layerViewportMatrix[2] = matrix[1][0]; + layerViewportMatrix[3] = matrix[1][1]; + layerViewportMatrix[4] += matrix[2][0]; + layerViewportMatrix[5] += matrix[2][1]; + } + layerViewport.style.transform = "matrix(" + layerViewportMatrix[0] + "," + layerViewportMatrix[1] + "," + layerViewportMatrix[2] + "," + layerViewportMatrix[3] + "," + layerViewportMatrix[4] + "," + layerViewportMatrix[5] + ")"; + if (!hasSeenRoot) { + hasSeenRoot = true; + layerViewport.style.transform = "scale(" + 1/contentScale + "," + 1/contentScale + ")"; + } + if (clipElem) { + previewParent.appendChild(clipElem); + clipElem.appendChild(layerViewport); + } else { + previewParent.appendChild(layerViewport); + } + previewParent = layerViewport; + for (var i = 0; i < visibleRegion.length; i++) { + var rect2d = visibleRegion[i]; + var layerPreview = createElement("div", { + id: root.address + "_visible_part" + i + "-" + visibleRegion.length, + className: "layerPreview", + style: { + position: "absolute", + left: rect2d[0] + "px", + top: rect2d[1] + "px", + width: rect2d[2] + "px", + height: rect2d[3] + "px", + overflow: "hidden", + border: "solid 1px black", + background: 'url("noise.png"), linear-gradient(rgba(255, 255, 255, 0.5), rgba(255, 255, 255, 0.2))', + }, + }); + layerViewport.appendChild(layerPreview); + + function isInside(rect1, rect2) { + if (rect1[0] + rect1[2] < rect2[0] && rect2[0] + rect2[2] < rect1[0] && + rect1[1] + rect1[3] < rect2[1] && rect2[1] + rect2[3] < rect1[1]) { + return true; + } + return true; + } + + var hasImg = false; + // Add tile img objects for this part + var previewOffset = rect2d; + + if (root.tiles) { + hasImg = true; + for (var x in root.tiles) { + for (var y in root.tiles[x]) { + if (isInside(rect2d, [x, y, 512, 512])) { + var tileImgElem = createElement("img", { + src: getDataURI(root.tiles[x][y]), + style: { + position: "absolute", + left: (x - previewOffset[0]) + "px", + top: (y - previewOffset[1]) + "px", + pointerEvents: "auto", + }, + }); + layerPreview.appendChild(tileImgElem); + } + } + } + layerPreview.style.background = ""; + } else if (root.surfaceURI) { + hasImg = true; + var offsetX = 0; + var offsetY = 0; + if (root.contentHostProp && root.contentHostProp['buffer-rect']) { + offsetX = root.contentHostProp['buffer-rect'][0]; + offsetY = root.contentHostProp['buffer-rect'][1]; + } + var surfaceImgElem = createElement("img", { + src: getDataURI(root.surfaceURI), + style: { + position: "absolute", + left: (offsetX - previewOffset[0]) + "px", + top: (offsetY - previewOffset[1]) + "px", + pointerEvents: "auto", + }, + }); + layerPreview.appendChild(surfaceImgElem); + layerPreview.style.background = ""; + } else if (root.color) { + hasImg = true; + layerPreview.style.background = "rgba(" + root.color.r + ", " + root.color.g + ", " + root.color.b + ", " + root.color.a + ")"; + } + + if (hasImg || true) { + layerPreview.mouseoverElem = elem; + layerPreview.onmouseenter = function() { + this.mouseoverElem.onmouseover(); + } + layerPreview.onmouseout = function() { + this.mouseoverElem.onmouseout(); + } + } + } + + var layerDisplayItems = getDisplayItemForLayer(displayList); + for (var i = 0; i < layerDisplayItems.length; i++) { + var displayItem = layerDisplayItems[i]; + var displayElem = createElement("div", { + className: "layerObjectDescription", + textContent: " " + trim(displayItem.line), + style: { + whiteSpace: "pre", + }, + displayItem: displayItem, + layerViewport: layerViewport, + onmouseover: function() { + if (this.diPreview) { + this.diPreview.classList.add("displayHover"); + + var description = ""; + if (this.displayItem.contentDescriptor) { + description += "Content: " + this.displayItem.contentDescriptor; + } else { + description += "Content: Unknown"; + } + description += "
Item: " + this.displayItem.name + " (" + this.displayItem.address + ")"; + description += "
Layer: " + root.name + " (" + root.address + ")"; + if (this.displayItem.frame) { + description += "
Frame: " + this.displayItem.frame; + } + if (this.displayItem.layerBounds) { + description += "
Bounds: [" + toFixed(this.displayItem.layerBounds[0] / 60, 2) + ", " + toFixed(this.displayItem.layerBounds[1] / 60, 2) + ", " + toFixed(this.displayItem.layerBounds[2] / 60, 2) + ", " + toFixed(this.displayItem.layerBounds[3] / 60, 2) + "] (CSS Pixels)"; + } + if (this.displayItem.z) { + description += "
Z: " + this.displayItem.z; + } + // At the end + if (this.displayItem.rest) { + description += "
" + this.displayItem.rest; + } + + var box = this.diPreview.getBoundingClientRect(); + var pageBox = document.body.getBoundingClientRect(); + this.diPreview.tooltip = createElement("div", { + className: "csstooltip", + innerHTML: description, + style: { + top: Math.min(box.bottom, document.documentElement.clientHeight - 150) + "px", + left: box.left + "px", + } + }); + + document.body.appendChild(this.diPreview.tooltip); + } + }, + onmouseout: function() { + if (this.diPreview) { + this.diPreview.classList.remove("displayHover"); + document.body.removeChild(this.diPreview.tooltip); + } + }, + }); + + var icon = createElement("img", { + style: { + width: "12px", + height: "12px", + marginLeft: "4px", + marginRight: "4px", + } + }); + displayElem.insertBefore(icon, displayElem.firstChild); + pane.appendChild(displayElem); + // bounds doesn't adjust for within the layer. It's not a bad fallback but + // will have the wrong offset + var rect2d = displayItem.layerBounds || displayItem.bounds; + if (rect2d) { // This doesn't place them corectly + var appUnitsToPixels = 60 / contentScale; + diPreview = createElement("div", { + id: "displayitem_" + displayItem.content + "_" + displayItem.address, + className: "layerPreview", + style: { + position: "absolute", + left: rect2d[0]/appUnitsToPixels + "px", + top: rect2d[1]/appUnitsToPixels + "px", + width: rect2d[2]/appUnitsToPixels + "px", + height: rect2d[3]/appUnitsToPixels + "px", + border: "solid 1px gray", + pointerEvents: "auto", + }, + displayElem: displayElem, + onmouseover: function() { + this.displayElem.onmouseover(); + }, + onmouseout: function() { + this.displayElem.onmouseout(); + }, + }); + + layerViewport.appendChild(diPreview); + displayElem.diPreview = diPreview; + } + } + } + + for (var i = 0; i < root.children.length; i++) { + populateLayers(root.children[i], displayList, pane, previewParent, hasSeenRoot, contentScale, rootPreviewParent); + } +} + +// This function takes a stdout snippet and finds the frames +function parseMultiLineDump(log) { + var lines = log.split("\n"); + + var container = createElement("div", { + style: { + height: "100%", + position: "relative", + }, + }); + + var layerManagerFirstLine = "[a-zA-Z]*LayerManager \\(.*$\n"; + var nextLineStartWithSpace = "([ \\t].*$\n)*"; + var layersRegex = "(" + layerManagerFirstLine + nextLineStartWithSpace + ")"; + + var startLine = "Painting --- after optimization:\n"; + var endLine = "Painting --- layer tree:" + var displayListRegex = "(" + startLine + "(.*\n)*?" + endLine + ")"; + + var regex = new RegExp(layersRegex + "|" + displayListRegex, "gm"); + var matches = log.match(regex); + console.log(matches); + window.matches = matches; + + var matchList = createElement("span", { + style: { + height: "95%", + width: "10%", + position: "relative", + border: "solid black 2px", + display: "inline-block", + float: "left", + overflow: "auto", + }, + }); + container.appendChild(matchList); + var contents = createElement("span", { + style: { + height: "95%", + width: "88%", + display: "inline-block", + }, + textContent: "Click on a frame on the left to view the layer tree", + }); + container.appendChild(contents); + + var lastDisplayList = null; + var frameID = 1; + for (let i = 0; i < matches.length; i++) { + var currMatch = matches[i]; + + if (currMatch.indexOf(startLine) == 0) { + // Display list match + var matchLines = matches[i].split("\n") + lastDisplayList = parseDisplayList(matchLines); + } else { + // Layer tree match: + let displayList = lastDisplayList; + lastDisplayList = null; + var currFrameDiv = createElement("a", { + style: { + padding: "3px", + display: "block", + }, + href: "#", + textContent: "LayerTree " + (frameID++), + onclick: function() { + contents.innerHTML = ""; + var matchLines = matches[i].split("\n") + var dumpDiv = parseDump(matchLines, displayList); + contents.appendChild(dumpDiv); + } + }); + matchList.appendChild(currFrameDiv); + } + } + + return container; +} + +function parseDump(log, displayList, compositeTitle, compositeTime) { + compositeTitle |= ""; + compositeTime |= 0 + + var container = createElement("div", { + style: { + background: "white", + height: "100%", + position: "relative", + }, + }); + + if (compositeTitle == null && compositeTime == null) { + var titleDiv = createElement("div", { + className: "treeColumnHeader", + style: { + width: "100%", + }, + textContent: compositeTitle + (compositeTitle ? " (near " + compositeTime.toFixed(0) + " ms)" : ""), + }); + container.appendChild(titleDiv); + } + + var mainDiv = createElement("div", { + style: { + position: "absolute", + top: "16px", + left: "0px", + right: "0px", + bottom: "0px", + }, + }); + container.appendChild(mainDiv); + + var layerListPane = createElement("div", { + style: { + cssFloat: "left", + height: "100%", + width: "300px", + overflowY: "scroll", + }, + }); + mainDiv.appendChild(layerListPane); + + var previewDiv = createElement("div", { + style: { + position: "absolute", + left: "300px", + right: "0px", + top: "0px", + bottom: "0px", + overflow: "auto", + }, + }); + mainDiv.appendChild(previewDiv); + + var root = parseLayers(log); + populateLayers(root, displayList, layerListPane, previewDiv); + return container; +} + +function tab_showLayersDump(layersDumpLines, compositeTitle, compositeTime) { + var container = parseDump(layersDumpLines, compositeTitle, compositeTime); + + gTabWidget.addTab("LayerTree", container); + gTabWidget.selectTab("LayerTree"); +} + diff --git a/gfx/layers/layerviewer/noise.png b/gfx/layers/layerviewer/noise.png new file mode 100755 index 00000000000..01d340aaa90 Binary files /dev/null and b/gfx/layers/layerviewer/noise.png differ diff --git a/gfx/layers/layerviewer/show.png b/gfx/layers/layerviewer/show.png new file mode 100644 index 00000000000..7038b660c8f Binary files /dev/null and b/gfx/layers/layerviewer/show.png differ diff --git a/gfx/layers/layerviewer/tree.css b/gfx/layers/layerviewer/tree.css new file mode 100644 index 00000000000..6b26d729b5b --- /dev/null +++ b/gfx/layers/layerviewer/tree.css @@ -0,0 +1,36 @@ +html, body { + height: 100%; + overflow: hidden; +} +.layerObjectDescription:hover { + background-color: #E8E8E8; +} + +.layerHover > .layerPreview::after { + position: absolute; + top: 0; right: 0; bottom: 0; left: 0; + background-color: inherit; + content: ""; + background-color: rgba(0,0,0,0.2); + box-shadow: -2px 2px 0 #FFF; +} + +@keyframes layerHoverAnimation { + 0% { transform: scale(1); } + 50% { transform: scale(1.2); } + 100% { transform: scale(1); } +} + +.displayHover { + background: rgba(0, 128, 0, 0.8); +} + +.layerHover > .layerPreview { + animation: layerHoverAnimation 200ms; + animation-transform-origin: 50% 50%; + background: gold !important; + box-shadow: 10px 10px 5px #888888; + border-color: blue !important; + z-index: 10; +} + diff --git a/gfx/layers/moz.build b/gfx/layers/moz.build index 5853c319b0a..a2a404df4b2 100644 --- a/gfx/layers/moz.build +++ b/gfx/layers/moz.build @@ -228,11 +228,12 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': 'opengl/GrallocTextureHost.cpp', ] LOCAL_INCLUDES += ['/widget/gonk'] - CXXFLAGS += [ - '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'system/core/libsync/include' - ] - ] + if CONFIG['ANDROID_VERSION'] >= '21': + LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ + 'system/core/libsync/include' + ] + ] SOURCES += [ 'ipc/ShadowLayerUtilsGralloc.cpp', ] @@ -403,14 +404,21 @@ if CONFIG['MOZ_DEBUG']: if CONFIG['MOZ_ENABLE_D3D10_LAYER']: DEFINES['MOZ_ENABLE_D3D10_LAYER'] = True -CXXFLAGS += [ - '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/base/include/media/stagefright', - 'frameworks/base/include/media/stagefright/openmax', - 'frameworks/av/include/media/stagefright', - 'frameworks/native/include/media/openmax', +if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': + if CONFIG['ANDROID_VERSION'] > '17': + includes = [ + 'frameworks/av/include/media/stagefright', + 'frameworks/native/include/media/openmax', + ] + else: + includes = [ + 'frameworks/base/include/media/stagefright', + 'frameworks/base/include/media/stagefright/openmax', + ] + + LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in includes ] -] if CONFIG['ENABLE_TESTS']: DIRS += ['apz/test/gtest'] diff --git a/gfx/layers/opengl/TextureHostOGL.h b/gfx/layers/opengl/TextureHostOGL.h index 92bc5b51756..efdc19a7ce3 100644 --- a/gfx/layers/opengl/TextureHostOGL.h +++ b/gfx/layers/opengl/TextureHostOGL.h @@ -29,10 +29,9 @@ #include "nsCOMPtr.h" // for already_AddRefed #include "nsDebug.h" // for NS_WARNING #include "nsISupportsImpl.h" // for TextureImage::Release, etc +#include "nsRegionFwd.h" // for nsIntRegion #include "OGLShaderProgram.h" // for ShaderProgramType, etc -class nsIntRegion; - namespace mozilla { namespace gfx { class DataSourceSurface; diff --git a/gfx/src/RegionTyped.h b/gfx/src/RegionTyped.h deleted file mode 100644 index dab5481461a..00000000000 --- a/gfx/src/RegionTyped.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#ifndef mozilla_RegionTyped_h -#define mozilla_RegionTyped_h - -#include "nsRegion.h" -#include "mozilla/gfx/Rect.h" - -namespace mozilla { - -namespace gfx { - -template -class IntRegionTyped : - public BaseIntRegion, IntRectTyped, IntPointTyped, IntMarginTyped> -{ - typedef BaseIntRegion, IntRectTyped, IntPointTyped, IntMarginTyped> Super; -public: - // Forward constructors. - IntRegionTyped() {} - MOZ_IMPLICIT IntRegionTyped(const IntRectTyped& aRect) : Super(aRect) {} - IntRegionTyped(const IntRegionTyped& aRegion) : Super(aRegion) {} - IntRegionTyped(IntRegionTyped&& aRegion) : Super(mozilla::Move(aRegion)) {} - - // Assignment operators need to be forwarded as well, otherwise the compiler - // will declare deleted ones. - IntRegionTyped& operator=(const IntRegionTyped& aRegion) - { - return Super::operator=(aRegion); - } - IntRegionTyped& operator=(IntRegionTyped&& aRegion) - { - return Super::operator=(mozilla::Move(aRegion)); - } - - static IntRegionTyped FromUntyped(const nsIntRegion& aRegion) - { - return IntRegionTyped(aRegion.Impl()); - } -private: - // This is deliberately private, so calling code uses FromUntyped(). - explicit IntRegionTyped(const nsRegion& aRegion) : Super(aRegion) {} -}; - -} // namespace gfx - -} // namespace mozilla - - - -#endif /* mozilla_RegionTyped_h */ diff --git a/gfx/src/moz.build b/gfx/src/moz.build index 156aa1f7ce9..19879c4b3eb 100644 --- a/gfx/src/moz.build +++ b/gfx/src/moz.build @@ -32,6 +32,7 @@ EXPORTS += [ 'nsPoint.h', 'nsRect.h', 'nsRegion.h', + 'nsRegionFwd.h', 'nsRenderingContext.h', 'nsSize.h', 'nsThemeConstants.h', @@ -42,10 +43,6 @@ EXPORTS.mozilla += [ 'AppUnits.h', ] -EXPORTS.mozilla.gfx += [ - 'RegionTyped.h', -] - if CONFIG['MOZ_X11']: EXPORTS.mozilla += ['X11Util.h'] SOURCES += [ diff --git a/gfx/src/nsIScriptableRegion.idl b/gfx/src/nsIScriptableRegion.idl index 84ee20bf071..1e32fdd1bae 100644 --- a/gfx/src/nsIScriptableRegion.idl +++ b/gfx/src/nsIScriptableRegion.idl @@ -7,7 +7,7 @@ #include "nsISupports.idl" %{C++ -class nsIntRegion; +#include "nsRegionFwd.h" %} native nsIntRegion(nsIntRegion); diff --git a/gfx/src/nsRegion.h b/gfx/src/nsRegion.h index 315db6d78e3..0244c842c7a 100644 --- a/gfx/src/nsRegion.h +++ b/gfx/src/nsRegion.h @@ -15,11 +15,11 @@ #include "nsPoint.h" // for nsIntPoint, nsPoint #include "nsRect.h" // for mozilla::gfx::IntRect, nsRect #include "nsMargin.h" // for nsIntMargin +#include "nsRegionFwd.h" // for nsIntRegion #include "nsStringGlue.h" // for nsCString #include "xpcom-config.h" // for CPP_THROW_NEW #include "mozilla/Move.h" // for mozilla::Move -class nsIntRegion; namespace mozilla { namespace gfx { class Matrix4x4; @@ -821,30 +821,42 @@ private: } }; -} // namespace gfx -} // namespace mozilla - -class nsIntRegion : public mozilla::gfx::BaseIntRegion +template +class IntRegionTyped : + public BaseIntRegion, IntRectTyped, IntPointTyped, IntMarginTyped> { + typedef BaseIntRegion, IntRectTyped, IntPointTyped, IntMarginTyped> Super; public: // Forward constructors. - nsIntRegion() {} - MOZ_IMPLICIT nsIntRegion(const mozilla::gfx::IntRect& aRect) : BaseIntRegion(aRect) {} - nsIntRegion(const nsIntRegion& aRegion) : BaseIntRegion(aRegion) {} - nsIntRegion(nsIntRegion&& aRegion) : BaseIntRegion(mozilla::Move(aRegion)) {} + IntRegionTyped() {} + MOZ_IMPLICIT IntRegionTyped(const IntRectTyped& aRect) : Super(aRect) {} + IntRegionTyped(const IntRegionTyped& aRegion) : Super(aRegion) {} + IntRegionTyped(IntRegionTyped&& aRegion) : Super(mozilla::Move(aRegion)) {} // Assignment operators need to be forwarded as well, otherwise the compiler // will declare deleted ones. - nsIntRegion& operator=(const nsIntRegion& aRegion) + IntRegionTyped& operator=(const IntRegionTyped& aRegion) { - return BaseIntRegion::operator=(aRegion); + return Super::operator=(aRegion); } - nsIntRegion& operator=(nsIntRegion&& aRegion) + IntRegionTyped& operator=(IntRegionTyped&& aRegion) { - return BaseIntRegion::operator=(mozilla::Move(aRegion)); + return Super::operator=(mozilla::Move(aRegion)); } + + static IntRegionTyped FromUntyped(const IntRegionTyped& aRegion) + { + return IntRegionTyped(aRegion.Impl()); + } +private: + // This is deliberately private, so calling code uses FromUntyped(). + explicit IntRegionTyped(const nsRegion& aRegion) : Super(aRegion) {} }; +} // namespace gfx +} // namespace mozilla + +typedef mozilla::gfx::IntRegion nsIntRegion; typedef nsIntRegion::RectIterator nsIntRegionRectIterator; #endif diff --git a/gfx/src/nsRegionFwd.h b/gfx/src/nsRegionFwd.h new file mode 100644 index 00000000000..6d5345d1458 --- /dev/null +++ b/gfx/src/nsRegionFwd.h @@ -0,0 +1,26 @@ +/* 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 nsRegionFwd_h__ +#define nsRegionFwd_h__ + +// Forward declare enough things to define the typedef |nsIntRegion|. + +namespace mozilla { +namespace gfx { + +struct UnknownUnits; + +template +class IntRegionTyped; + +typedef IntRegionTyped IntRegion; + +} // namespace gfx +} // namespace mozilla + +typedef mozilla::gfx::IntRegion nsIntRegion; + +#endif diff --git a/gfx/thebes/gfxTypes.h b/gfx/thebes/gfxTypes.h index 1dad160e60d..64ad9e1ef6d 100644 --- a/gfx/thebes/gfxTypes.h +++ b/gfx/thebes/gfxTypes.h @@ -47,24 +47,28 @@ enum class gfxBreakPriority { /** * The format for an image surface. For all formats with alpha data, 0 * means transparent, 1 or 255 means fully opaque. + * + * XXX: it's vital that the values here match the values in cairo_format_t, + * otherwise gfxCairoFormatToImageFormat() and gfxImageFormatToCairoFormat() + * won't work. */ enum class gfxImageFormat { - ARGB32, ///< ARGB data in native endianness, using premultiplied alpha - RGB24, ///< xRGB data in native endianness - A8, ///< Only an alpha channel - RGB16_565, ///< RGB_565 data in native endianness + ARGB32 = 0, ///< ARGB data in native endianness, using premultiplied alpha + RGB24 = 1, ///< xRGB data in native endianness + A8 = 2, ///< Only an alpha channel + RGB16_565 = 4, ///< RGB_565 data in native endianness Unknown }; // XXX: temporary // This works because the gfxImageFormat enum is defined so as to match the -// _cairo_format enum. +// cairo_format_t enum. #define gfxCairoFormatToImageFormat(aFormat) \ ((gfxImageFormat)aFormat) // XXX: temporary // This works because the gfxImageFormat enum is defined so as to match the -// _cairo_format enum. +// cairo_format_t enum. #define gfxImageFormatToCairoFormat(aFormat) \ ((cairo_format_t)aFormat) diff --git a/gfx/thebes/gfxUtils.cpp b/gfx/thebes/gfxUtils.cpp index fa992730278..01f4a0a4fbf 100644 --- a/gfx/thebes/gfxUtils.cpp +++ b/gfx/thebes/gfxUtils.cpp @@ -21,6 +21,7 @@ #include "mozilla/gfx/Logging.h" #include "mozilla/Maybe.h" #include "mozilla/RefPtr.h" +#include "mozilla/UniquePtrExtensions.h" #include "mozilla/Vector.h" #include "nsComponentManagerUtils.h" #include "nsIClipboardHelper.h" @@ -1560,7 +1561,7 @@ gfxUtils::GetImageBuffer(gfx::DataSourceSurface* aSurface, return nullptr; uint32_t bufferSize = aSurface->GetSize().width * aSurface->GetSize().height * 4; - UniquePtr imageBuffer(new (fallible) uint8_t[bufferSize]); + auto imageBuffer = MakeUniqueFallible(bufferSize); if (!imageBuffer) { aSurface->Unmap(); return nullptr; diff --git a/gfx/thebes/gfxUtils.h b/gfx/thebes/gfxUtils.h index 97ebd27494e..a90987445b1 100644 --- a/gfx/thebes/gfxUtils.h +++ b/gfx/thebes/gfxUtils.h @@ -13,13 +13,13 @@ #include "mozilla/UniquePtr.h" #include "nsColor.h" #include "nsPrintfCString.h" +#include "nsRegionFwd.h" #include "mozilla/gfx/Rect.h" class gfxASurface; class gfxDrawable; class nsIInputStream; class nsIGfxInfo; -class nsIntRegion; class nsIPresShell; namespace mozilla { diff --git a/hal/moz.build b/hal/moz.build index ba9abffd856..a046bdcd43f 100644 --- a/hal/moz.build +++ b/hal/moz.build @@ -174,7 +174,7 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - CXXFLAGS += ['-I%s/hardware/libhardware_legacy/include' % CONFIG['ANDROID_SOURCE']] + LOCAL_INCLUDES += ['%' + '%s/hardware/libhardware_legacy/include' % CONFIG['ANDROID_SOURCE']] CFLAGS += CONFIG['GLIB_CFLAGS'] CFLAGS += CONFIG['MOZ_DBUS_GLIB_CFLAGS'] diff --git a/image/encoders/bmp/nsBMPEncoder.cpp b/image/encoders/bmp/nsBMPEncoder.cpp index 8f02ef564bc..4484faa3e41 100644 --- a/image/encoders/bmp/nsBMPEncoder.cpp +++ b/image/encoders/bmp/nsBMPEncoder.cpp @@ -5,6 +5,7 @@ #include "nsCRT.h" #include "mozilla/Endian.h" +#include "mozilla/UniquePtrExtensions.h" #include "nsBMPEncoder.h" #include "prprf.h" #include "nsString.h" @@ -187,9 +188,8 @@ nsBMPEncoder::AddImageFrame(const uint8_t* aData, return NS_ERROR_INVALID_ARG; } - UniquePtr row(new (fallible) - uint8_t[mBMPInfoHeader.width * - BytesPerPixel(mBMPInfoHeader.bpp)]); + auto row = MakeUniqueFallible(mBMPInfoHeader.width * + BytesPerPixel(mBMPInfoHeader.bpp)); if (!row) { return NS_ERROR_OUT_OF_MEMORY; } diff --git a/ipc/chromium/chromium-config.mozbuild b/ipc/chromium/chromium-config.mozbuild index 53bd38348dc..c6f5de45c51 100644 --- a/ipc/chromium/chromium-config.mozbuild +++ b/ipc/chromium/chromium-config.mozbuild @@ -5,14 +5,11 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. LOCAL_INCLUDES += [ + '!/ipc/ipdl/_ipdlheaders', '/ipc/chromium/src', '/ipc/glue', ] -GENERATED_INCLUDES += [ - '/ipc/ipdl/_ipdlheaders', -] - if CONFIG['OS_ARCH'] == 'WINNT': OS_LIBS += [ 'psapi', diff --git a/ipc/chromium/src/third_party/libeventcommon.mozbuild b/ipc/chromium/src/third_party/libeventcommon.mozbuild index f5736187bfe..bb8f41bcf40 100644 --- a/ipc/chromium/src/third_party/libeventcommon.mozbuild +++ b/ipc/chromium/src/third_party/libeventcommon.mozbuild @@ -31,7 +31,7 @@ else: if os_posix and not CONFIG['MOZ_NATIVE_LIBEVENT']: DEFINES['HAVE_CONFIG_H'] = True LOCAL_INCLUDES += sorted([ - libevent_path_prefix + '/libevent', - libevent_path_prefix + '/libevent/include', - libevent_path_prefix + '/libevent/' + libevent_include_suffix, + 'libevent', + 'libevent/include', + 'libevent/' + libevent_include_suffix, ]) diff --git a/ipc/glue/GeckoChildProcessHost.cpp b/ipc/glue/GeckoChildProcessHost.cpp index 6c0271575e3..519cb1618d1 100644 --- a/ipc/glue/GeckoChildProcessHost.cpp +++ b/ipc/glue/GeckoChildProcessHost.cpp @@ -101,11 +101,11 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType, mPrivileges(aPrivileges), mMonitor("mozilla.ipc.GeckChildProcessHost.mMonitor"), mProcessState(CREATING_CHANNEL), - mDelegate(nullptr), #if defined(MOZ_SANDBOX) && defined(XP_WIN) mEnableSandboxLogging(false), mSandboxLevel(0), #endif + mDelegate(nullptr), mChildProcessHandle(0) #if defined(MOZ_WIDGET_COCOA) , mChildTask(MACH_PORT_NULL) diff --git a/ipc/glue/MessageChannel.cpp b/ipc/glue/MessageChannel.cpp index 1388b6502b9..805489894c5 100644 --- a/ipc/glue/MessageChannel.cpp +++ b/ipc/glue/MessageChannel.cpp @@ -848,9 +848,6 @@ MessageChannel::Send(Message* aMsg, Message* aReply) AssertWorkerThread(); mMonitor->AssertNotCurrentThreadOwns(); - if (mCurrentTransaction == 0) - mListener->OnBeginSyncTransaction(); - #ifdef OS_WIN SyncStackFrame frame(this, false); NeuteredWindowRegion neuteredRgn(mFlags & REQUIRE_DEFERRED_MESSAGE_PROTECTION); diff --git a/ipc/glue/MessageChannel.h b/ipc/glue/MessageChannel.h index 41143c0594d..b0cc491279a 100644 --- a/ipc/glue/MessageChannel.h +++ b/ipc/glue/MessageChannel.h @@ -143,6 +143,7 @@ class MessageChannel : HasResultCodes return !mCxxStackFrames.empty(); } + bool IsInTransaction() const { return mCurrentTransaction != 0; } void CancelCurrentTransaction(); /** diff --git a/ipc/glue/MessageLink.h b/ipc/glue/MessageLink.h index ff6b8b96b87..06632467449 100644 --- a/ipc/glue/MessageLink.h +++ b/ipc/glue/MessageLink.h @@ -88,10 +88,6 @@ class MessageListener virtual void OnExitedCall() { NS_RUNTIMEABORT("default impl shouldn't be invoked"); } - /* This callback is called when a sync message is sent that begins a new IPC transaction - (i.e., when it is not part of an existing sequence of nested messages). */ - virtual void OnBeginSyncTransaction() { - } virtual RacyInterruptPolicy MediateInterruptRace(const Message& parent, const Message& child) { diff --git a/js/ipc/JavaScriptChild.h b/js/ipc/JavaScriptChild.h index 474064b6519..f5eb2daba96 100644 --- a/js/ipc/JavaScriptChild.h +++ b/js/ipc/JavaScriptChild.h @@ -25,6 +25,8 @@ class JavaScriptChild : public JavaScriptBase void drop(JSObject* obj); + bool allowMessage(JSContext* cx) override { return true; } + protected: virtual bool isParent() override { return false; } virtual JSObject* scopeForTargetObjects() override; diff --git a/js/ipc/JavaScriptParent.cpp b/js/ipc/JavaScriptParent.cpp index 19d99c9e9a8..fa65efb5706 100644 --- a/js/ipc/JavaScriptParent.cpp +++ b/js/ipc/JavaScriptParent.cpp @@ -48,6 +48,54 @@ JavaScriptParent::init() return true; } +static bool +ForbidUnsafeBrowserCPOWs() +{ + static bool result; + static bool cached = false; + if (!cached) { + cached = true; + Preferences::AddBoolVarCache(&result, "dom.ipc.cpows.forbid-unsafe-from-browser", false); + } + return result; +} + +bool +JavaScriptParent::allowMessage(JSContext* cx) +{ + MessageChannel* channel = GetIPCChannel(); + if (channel->IsInTransaction()) + return true; + + if (ForbidUnsafeBrowserCPOWs()) { + if (JSObject* global = JS::CurrentGlobalOrNull(cx)) { + if (!JS::AddonIdOfObject(global)) { + JS_ReportError(cx, "unsafe CPOW usage forbidden"); + return false; + } + } + } + + static bool disableUnsafeCPOWWarnings = PR_GetEnv("DISABLE_UNSAFE_CPOW_WARNINGS"); + if (!disableUnsafeCPOWWarnings) { + nsCOMPtr console(do_GetService(NS_CONSOLESERVICE_CONTRACTID)); + if (console && cx) { + nsAutoString filename; + uint32_t lineno = 0, column = 0; + nsJSUtils::GetCallingLocation(cx, filename, &lineno, &column); + nsCOMPtr error(do_CreateInstance(NS_SCRIPTERROR_CONTRACTID)); + error->Init(NS_LITERAL_STRING("unsafe CPOW usage"), filename, + EmptyString(), lineno, column, + nsIScriptError::warningFlag, "chrome javascript"); + console->LogMessage(error); + } else { + NS_WARNING("Unsafe synchronous IPC message"); + } + } + + return true; +} + void JavaScriptParent::trace(JSTracer* trc) { diff --git a/js/ipc/JavaScriptParent.h b/js/ipc/JavaScriptParent.h index b0fe4025508..aa379c81e7a 100644 --- a/js/ipc/JavaScriptParent.h +++ b/js/ipc/JavaScriptParent.h @@ -25,6 +25,8 @@ class JavaScriptParent : public JavaScriptBase void drop(JSObject* obj); + bool allowMessage(JSContext* cx) override; + mozilla::ipc::IProtocol* CloneProtocol(Channel* aChannel, ProtocolCloneContext* aCtx) override; diff --git a/js/ipc/WrapperOwner.cpp b/js/ipc/WrapperOwner.cpp index 3b7646c2055..60093070352 100644 --- a/js/ipc/WrapperOwner.cpp +++ b/js/ipc/WrapperOwner.cpp @@ -150,6 +150,9 @@ const CPOWProxyHandler CPOWProxyHandler::singleton; JS_ReportError(cx, "cannot use a CPOW whose process is gone"); \ return false; \ } \ + if (!owner->allowMessage(cx)) { \ + return false; \ + } \ { \ CPOWTimer timer(cx); \ return owner->call args; \ @@ -978,8 +981,9 @@ InstanceOf(JSObject* proxy, const nsID* id, bool* bp) } bool -DOMInstanceOf(JSContext* cx, JSObject* proxy, int prototypeID, int depth, bool* bp) +DOMInstanceOf(JSContext* cx, JSObject* proxyArg, int prototypeID, int depth, bool* bp) { + RootedObject proxy(cx, proxyArg); FORWARD(domInstanceOf, (cx, proxy, prototypeID, depth, bp)); } diff --git a/js/ipc/WrapperOwner.h b/js/ipc/WrapperOwner.h index 757c8fd2853..2e05d1d2c5d 100644 --- a/js/ipc/WrapperOwner.h +++ b/js/ipc/WrapperOwner.h @@ -74,6 +74,8 @@ class WrapperOwner : public virtual JavaScriptShared bool active() { return !inactive_; } + virtual bool allowMessage(JSContext* cx) = 0; + void drop(JSObject* obj); void updatePointer(JSObject* obj, const JSObject* old); diff --git a/js/src/configure.in b/js/src/configure.in index de198cbdff3..5e06e09b24f 100644 --- a/js/src/configure.in +++ b/js/src/configure.in @@ -350,7 +350,10 @@ case "$target" in # that behavior) that it's better to turn it off. # _CRT_SECURE_NO_WARNINGS disables warnings about using MSVC-specific # secure CRT functions. - CXXFLAGS="$CXXFLAGS -wd4345 -wd4351 -wd4800 -D_CRT_SECURE_NO_WARNINGS" + # MSVC warning C4819 warns some UTF-8 characters (e.g. copyright sign) + # on non-Western system locales even if it is in a comment. + CFLAGS="$CFLAGS -wd4819" + CXXFLAGS="$CXXFLAGS -wd4345 -wd4351 -wd4800 -wd4819 -D_CRT_SECURE_NO_WARNINGS" AC_LANG_SAVE AC_LANG_C AC_TRY_COMPILE([#include ], diff --git a/js/src/gdb/moz.build b/js/src/gdb/moz.build index e385acaafdf..56378f76728 100644 --- a/js/src/gdb/moz.build +++ b/js/src/gdb/moz.build @@ -23,8 +23,10 @@ UNIFIED_SOURCES += [ DEFINES['EXPORT_JS_API'] = True -LOCAL_INCLUDES += ['..'] -GENERATED_INCLUDES += ['..'] +LOCAL_INCLUDES += [ + '!..', + '..', +] USE_LIBS += [ 'static:js', diff --git a/js/src/jsapi-tests/moz.build b/js/src/jsapi-tests/moz.build index 9ad38d24ddb..c62193e2d3a 100644 --- a/js/src/jsapi-tests/moz.build +++ b/js/src/jsapi-tests/moz.build @@ -104,8 +104,10 @@ if CONFIG['ENABLE_ION']: DEFINES['EXPORT_JS_API'] = True -LOCAL_INCLUDES += ['..'] -GENERATED_INCLUDES += ['..'] +LOCAL_INCLUDES += [ + '!..', + '..', +] USE_LIBS += [ 'static:js', diff --git a/js/src/moz.build b/js/src/moz.build index 146f44e2055..a8f87d8a694 100644 --- a/js/src/moz.build +++ b/js/src/moz.build @@ -541,8 +541,8 @@ if CONFIG['JS_HAS_CTYPES']: 'ctypes/Library.cpp', ] if not CONFIG['MOZ_NATIVE_FFI']: - GENERATED_INCLUDES += [ - 'ctypes/libffi/include', + LOCAL_INCLUDES += [ + '!ctypes/libffi/include', ] if CONFIG['MOZ_VTUNE']: diff --git a/js/src/shell/moz.build b/js/src/shell/moz.build index be315c60bbf..bb35df206c3 100644 --- a/js/src/shell/moz.build +++ b/js/src/shell/moz.build @@ -24,8 +24,10 @@ if CONFIG['_MSC_VER']: # for PGO. NO_PGO = True -LOCAL_INCLUDES += ['..'] -GENERATED_INCLUDES += ['..'] +LOCAL_INCLUDES += [ + '!..', + '..', +] OS_LIBS += CONFIG['EDITLINE_LIBS'] OS_LIBS += CONFIG['MOZ_ZLIB_LIBS'] diff --git a/layout/base/Units.h b/layout/base/Units.h index 13e99709276..f02231ca1c4 100644 --- a/layout/base/Units.h +++ b/layout/base/Units.h @@ -10,11 +10,11 @@ #include "mozilla/gfx/Coord.h" #include "mozilla/gfx/Point.h" #include "mozilla/gfx/Rect.h" -#include "mozilla/gfx/RegionTyped.h" #include "mozilla/gfx/ScaleFactor.h" #include "mozilla/gfx/ScaleFactors2D.h" -#include "nsRect.h" #include "nsMargin.h" +#include "nsRect.h" +#include "nsRegion.h" #include "mozilla/AppUnits.h" #include "mozilla/TypeTraits.h" diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index 794fb8b8ad3..1ccf4788bfa 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -2832,29 +2832,6 @@ nsDocumentViewer::CallChildren(CallChildFunc aFunc, void* aClosure) } } -struct LineBoxInfo -{ - nscoord mMaxLineBoxWidth; -}; - -static void -ChangeChildPaintingEnabled(nsIContentViewer* aChild, void* aClosure) -{ - bool* enablePainting = (bool*) aClosure; - if (*enablePainting) { - aChild->ResumePainting(); - } else { - aChild->PausePainting(); - } -} - -static void -ChangeChildMaxLineBoxWidth(nsIContentViewer* aChild, void* aClosure) -{ - struct LineBoxInfo* lbi = (struct LineBoxInfo*) aClosure; - aChild->ChangeMaxLineBoxWidth(lbi->mMaxLineBoxWidth); -} - struct ZoomInfo { float mZoom; @@ -3284,52 +3261,6 @@ NS_IMETHODIMP nsDocumentViewer::AppendSubtree(nsTArrayPausePainting(); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsDocumentViewer::ResumePainting() -{ - bool enablePaint = true; - CallChildren(ChangeChildPaintingEnabled, &enablePaint); - - nsIPresShell* presShell = GetPresShell(); - if (presShell) { - presShell->ResumePainting(); - } - - return NS_OK; -} - -NS_IMETHODIMP -nsDocumentViewer::ChangeMaxLineBoxWidth(int32_t aMaxLineBoxWidth) -{ - // Change the max line box width for all children. - struct LineBoxInfo lbi = { aMaxLineBoxWidth }; - CallChildren(ChangeChildMaxLineBoxWidth, &lbi); - - // Now, change our max line box width. - // Convert to app units, since our input is in CSS pixels. - nscoord mlbw = nsPresContext::CSSPixelsToAppUnits(aMaxLineBoxWidth); - nsIPresShell* presShell = GetPresShell(); - if (presShell) { - presShell->SetMaxLineBoxWidth(mlbw); - } - - return NS_OK; -} - NS_IMETHODIMP nsDocumentViewer::GetContentSize(int32_t* aWidth, int32_t* aHeight) { diff --git a/layout/base/nsIPresShell.h b/layout/base/nsIPresShell.h index 609bbcaf592..d25009d9b47 100644 --- a/layout/base/nsIPresShell.h +++ b/layout/base/nsIPresShell.h @@ -36,6 +36,7 @@ #include "nsCompatibility.h" #include "nsFrameManagerBase.h" #include "nsRect.h" +#include "nsRegionFwd.h" #include "mozFlushType.h" #include "nsWeakReference.h" #include // for FILE definition @@ -69,7 +70,6 @@ class nsFrameManager; class nsILayoutHistoryState; class nsIReflowCallback; class nsIDOMNode; -class nsIntRegion; class nsIStyleSheet; class nsCSSFrameConstructor; class nsISelection; @@ -140,10 +140,10 @@ typedef struct CapturingContentInfo { mozilla::StaticRefPtr mContent; } CapturingContentInfo; -// b07c5323-3061-4ca9-95ed-84cccbffadac +// 0ff43c2e-5688-464f-a23f-a3de223df684 #define NS_IPRESSHELL_IID \ -{ 0xb07c5323, 0x3061, 0x4ca9, \ - { 0x95, 0xed, 0x84, 0xcc, 0xcb, 0xff, 0xad, 0xac } } +{ 0x0ff43c2e, 0x5688, 0x464f, \ + { 0xa2, 0x3f, 0xa3, 0xde, 0x22, 0x3d, 0xf6, 0x84 } } // debug VerifyReflow flags #define VERIFY_REFLOW_ON 0x01 @@ -936,20 +936,6 @@ public: */ bool IsPaintingSuppressed() const { return mPaintingSuppressed; } - /** - * Pause painting by freezing the refresh driver of this and all parent - * presentations. This may not have the desired effect if this pres shell - * has its own refresh driver. - */ - virtual void PausePainting() = 0; - - /** - * Resume painting by thawing the refresh driver of this and all parent - * presentations. This may not have the desired effect if this pres shell - * has its own refresh driver. - */ - virtual void ResumePainting() = 0; - /** * Unsuppress painting. */ @@ -1089,7 +1075,7 @@ public: * such as the file name in a file upload widget, and we might choose not * to paint themes. * set RENDER_IGNORE_VIEWPORT_SCROLLING to ignore - * clipping/scrolling/scrollbar painting due to scrolling in the viewport + * clipping and scrollbar painting due to scrolling in the viewport * set RENDER_CARET to draw the caret if one would be visible * (by default the caret is never drawn) * set RENDER_USE_LAYER_MANAGER to force rendering to go through @@ -1102,8 +1088,11 @@ public: * set RENDER_ASYNC_DECODE_IMAGES to avoid having images synchronously * decoded during rendering. * (by default images decode synchronously with RenderDocument) - * set RENDER_DOCUMENT_RELATIVE to interpret |aRect| relative to the - * document instead of the CSS viewport + * set RENDER_DOCUMENT_RELATIVE to render the document as if there has been + * no scrolling and interpret |aRect| relative to the document instead of the + * CSS viewport. Only considered if RENDER_IGNORE_VIEWPORT_SCROLLING is set + * or the document is in ignore viewport scrolling mode + * (nsIPresShell::SetIgnoreViewportScrolling/IgnoringViewportScrolling). * @param aBackgroundColor a background color to render onto * @param aRenderedContext the gfxContext to render to. We render so that * one CSS pixel in the source document is rendered to one unit in the current @@ -1670,32 +1659,6 @@ public: virtual void ThemeChanged() = 0; virtual void BackingScaleFactorChanged() = 0; - nscoord MaxLineBoxWidth() { - return mMaxLineBoxWidth; - } - - void SetMaxLineBoxWidth(nscoord aMaxLineBoxWidth); - - /** - * Returns whether or not there is a reflow on zoom event pending. A reflow - * on zoom event is a change to the max line box width, followed by a reflow. - * This subsequent reflow event should treat all frames as though they resized - * horizontally (and thus reflow all their descendants), rather than marking - * all frames dirty from the root. This is the way the pres shell indicates - * that an hresize reflow should take place during reflow state construction. - */ - bool IsReflowOnZoomPending() { - return mReflowOnZoomPending; - } - - /** - * Clear the flag indicating whether a reflow on zoom event is pending. This - * is performed at the very end of DoReflow(). - */ - void ClearReflowOnZoomPending() { - mReflowOnZoomPending = false; - } - /** * Documents belonging to an invisible DocShell must not be painted ever. */ @@ -1829,19 +1792,10 @@ protected: bool mFontSizeInflationForceEnabled; bool mFontSizeInflationDisabledInMasterProcess; bool mFontSizeInflationEnabled; - bool mPaintingIsFrozen; // Dirty bit indicating that mFontSizeInflationEnabled needs to be recomputed. bool mFontSizeInflationEnabledIsDirty; - // Flag to indicate whether or not there is a reflow on zoom event pending. - // See IsReflowOnZoomPending() for more information. - bool mReflowOnZoomPending; - - // The maximum width of a line box. Text on a single line that exceeds this - // width will be wrapped. A value of 0 indicates that no limit is enforced. - nscoord mMaxLineBoxWidth; - // If a document belongs to an invisible DocShell, this flag must be set // to true, so we can avoid any paint calls for widget related to this // presshell. diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 839e05aca9a..8507f47b9dc 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -3127,6 +3127,42 @@ nsLayoutUtils::GetOrMaybeCreateDisplayPort(nsDisplayListBuilder& aBuilder, return haveDisplayPort; } +nsIScrollableFrame* +nsLayoutUtils::GetAsyncScrollableAncestorFrame(nsIFrame* aTarget) +{ + uint32_t flags = nsLayoutUtils::SCROLLABLE_ALWAYS_MATCH_ROOT + | nsLayoutUtils::SCROLLABLE_ONLY_ASYNC_SCROLLABLE + | nsLayoutUtils::SCROLLABLE_FIXEDPOS_FINDS_ROOT; + return nsLayoutUtils::GetNearestScrollableFrame(aTarget, flags); +} + +void +nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors(nsIFrame* aFrame, + RepaintMode aRepaintMode) +{ + nsIFrame* frame = aFrame; + while (frame) { + frame = nsLayoutUtils::GetCrossDocParentFrame(frame); + if (!frame) { + break; + } + nsIScrollableFrame* scrollAncestor = GetAsyncScrollableAncestorFrame(frame); + if (!scrollAncestor) { + break; + } + frame = do_QueryFrame(scrollAncestor); + MOZ_ASSERT(frame); + MOZ_ASSERT(scrollAncestor->WantAsyncScroll() || + frame->PresContext()->PresShell()->GetRootScrollFrame() == frame); + if (nsLayoutUtils::AsyncPanZoomEnabled(frame) && + !nsLayoutUtils::GetDisplayPort(frame->GetContent())) { + nsLayoutUtils::SetDisplayPortMargins( + frame->GetContent(), frame->PresContext()->PresShell(), ScreenMargin(), 0, + aRepaintMode); + } + } +} + nsresult nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFrame, const nsRegion& aDirtyRegion, nscolor aBackstop, diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h index 4845b0b95dc..261266a6baa 100644 --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -1048,9 +1048,11 @@ public: * to force rendering to use the widget's layer manager for testing * or speed. PAINT_WIDGET_LAYERS must be set if aRenderingContext is null. * If PAINT_DOCUMENT_RELATIVE is used, the visible region is interpreted - * as being relative to the document. (Normally it's relative to the CSS - * viewport.) PAINT_TO_WINDOW sets painting to window to true on the display - * list builder even if we can't tell that we are painting to the window. + * as being relative to the document (normally it's relative to the CSS + * viewport) and the document is painted as if no scrolling has occured. + * Only considered if nsIPresShell::IgnoringViewportScrolling is true. + * PAINT_TO_WINDOW sets painting to window to true on the display list + * builder even if we can't tell that we are painting to the window. * If PAINT_EXISTING_TRANSACTION is set, then BeginTransaction() has already * been called on aFrame's widget's layer manager and should not be * called again. @@ -2702,6 +2704,15 @@ public: nsRect aDisplayPortBase, nsRect* aOutDisplayport); + static nsIScrollableFrame* GetAsyncScrollableAncestorFrame(nsIFrame* aTarget); + + /** + * Sets a zero margin display port on all proper ancestors of aFrame that + * are async scrollable. + */ + static void SetZeroMarginDisplayPortOnAsyncScrollableAncestors(nsIFrame* aFrame, + RepaintMode aRepaintMode); + static bool IsOutlineStyleAutoEnabled(); static void SetBSizeFromFontMetrics(const nsIFrame* aFrame, diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index d0c8818c803..5020f3e13e9 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -789,8 +789,6 @@ PresShell::PresShell() mScrollPositionClampingScrollPortSizeSet = false; - mMaxLineBoxWidth = 0; - static bool addedSynthMouseMove = false; if (!addedSynthMouseMove) { Preferences::AddBoolVarCache(&sSynthMouseMove, @@ -804,7 +802,6 @@ PresShell::PresShell() addedPointerEventEnabled = true; } - mPaintingIsFrozen = false; mHasCSSBackgroundColor = true; mIsLastChromeOnlyEscapeKeyConsumed = false; mHasReceivedPaintMessage = false; @@ -828,13 +825,6 @@ PresShell::~PresShell() mLastCallbackEventRequest == nullptr, "post-reflow queues not empty. This means we're leaking"); - // Verify that if painting was frozen, but we're being removed from the tree, - // that we now re-enable painting on our refresh driver, since it may need to - // be re-used by another presentation. - if (mPaintingIsFrozen) { - mPresContext->RefreshDriver()->Thaw(); - } - #ifdef DEBUG MOZ_ASSERT(mPresArenaAllocCount == 0, "Some pres arena objects were not freed"); @@ -1869,7 +1859,7 @@ PresShell::ResizeReflowIgnoreOverride(nscoord aWidth, nscoord aHeight) DoReflow(rootFrame, true); } - DidDoReflow(true, false); + DidDoReflow(true); } } @@ -6591,22 +6581,6 @@ PresShell::RecordMouseLocation(WidgetGUIEvent* aEvent) } } -static PLDHashOperator -FindAnyTarget(const uint32_t& aKey, RefPtr& aData, - void* aAnyTarget) -{ - if (aData) { - dom::EventTarget* target = aData->GetTarget(); - if (target) { - nsCOMPtr* content = - static_cast*>(aAnyTarget); - *content = do_QueryInterface(target); - return PL_DHASH_STOP; - } - } - return PL_DHASH_NEXT; -} - nsIFrame* GetNearestFrameContainingPresShell(nsIPresShell* aPresShell) { nsView* view = aPresShell->GetViewManager()->GetRootView(); @@ -7314,7 +7288,18 @@ PresShell::HandleEvent(nsIFrame* aFrame, // the capture list nsCOMPtr anyTarget; if (TouchManager::gCaptureTouchList->Count() > 0 && touchEvent->touches.Length() > 1) { - TouchManager::gCaptureTouchList->Enumerate(&FindAnyTarget, &anyTarget); + for (auto iter = TouchManager::gCaptureTouchList->Iter(); + !iter.Done(); + iter.Next()) { + RefPtr& touch = iter.Data(); + if (touch) { + dom::EventTarget* target = touch->GetTarget(); + if (target) { + anyTarget = do_QueryInterface(target); + break; + } + } + } } for (int32_t i = touchEvent->touches.Length(); i; ) { @@ -8854,7 +8839,7 @@ PresShell::WillDoReflow() } void -PresShell::DidDoReflow(bool aInterruptible, bool aWasInterrupted) +PresShell::DidDoReflow(bool aInterruptible) { mFrameConstructor->EndUpdate(); @@ -8875,10 +8860,6 @@ PresShell::DidDoReflow(bool aInterruptible, bool aWasInterrupted) } mPresContext->NotifyMissingFonts(); - - if (!aWasInterrupted) { - ClearReflowOnZoomPending(); - } } DOMHighResTimeStamp @@ -9229,7 +9210,7 @@ PresShell::ProcessReflowCommands(bool aInterruptible) // Exiting the scriptblocker might have killed us if (!mIsDestroying) { - DidDoReflow(aInterruptible, interrupted); + DidDoReflow(aInterruptible); } // DidDoReflow might have killed us @@ -10889,39 +10870,6 @@ nsIPresShell::FontSizeInflationEnabled() return mFontSizeInflationEnabled; } -void -nsIPresShell::SetMaxLineBoxWidth(nscoord aMaxLineBoxWidth) -{ - NS_ASSERTION(aMaxLineBoxWidth >= 0, "attempting to set max line box width to a negative value"); - - if (mMaxLineBoxWidth != aMaxLineBoxWidth) { - mMaxLineBoxWidth = aMaxLineBoxWidth; - mReflowOnZoomPending = true; - FrameNeedsReflow(GetRootFrame(), nsIPresShell::eResize, - NS_FRAME_HAS_DIRTY_CHILDREN); - } -} - -void -PresShell::PausePainting() -{ - if (GetPresContext()->RefreshDriver()->PresContext() != GetPresContext()) - return; - - mPaintingIsFrozen = true; - GetPresContext()->RefreshDriver()->Freeze(); -} - -void -PresShell::ResumePainting() -{ - if (GetPresContext()->RefreshDriver()->PresContext() != GetPresContext()) - return; - - mPaintingIsFrozen = false; - GetPresContext()->RefreshDriver()->Thaw(); -} - void nsIPresShell::SyncWindowProperties(nsView* aView) { diff --git a/layout/base/nsPresShell.h b/layout/base/nsPresShell.h index d099d25bd37..a2a48dfcd59 100644 --- a/layout/base/nsPresShell.h +++ b/layout/base/nsPresShell.h @@ -436,10 +436,8 @@ protected: * Callback handler for whether reflow happened. * * @param aInterruptible Whether or not reflow interruption is allowed. - * @param aWasInterrupted Whether or not the reflow was interrupted earlier. - * */ - void DidDoReflow(bool aInterruptible, bool aWasInterrupted); + void DidDoReflow(bool aInterruptible); // ProcessReflowCommands returns whether we processed all our dirty roots // without interruptions. bool ProcessReflowCommands(bool aInterruptible); @@ -732,9 +730,6 @@ protected: virtual void ThemeChanged() override { mPresContext->ThemeChanged(); } virtual void BackingScaleFactorChanged() override { mPresContext->UIResolutionChanged(); } - virtual void PausePainting() override; - virtual void ResumePainting() override; - void UpdateImageVisibility(); void UpdateActivePointerState(mozilla::WidgetGUIEvent* aEvent); diff --git a/layout/base/tests/mochitest.ini b/layout/base/tests/mochitest.ini index 67679e77afa..9a65019a593 100644 --- a/layout/base/tests/mochitest.ini +++ b/layout/base/tests/mochitest.ini @@ -199,7 +199,6 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android' || e1 [test_bug731777.html] [test_bug761572.html] [test_bug770106.html] -[test_maxLineBoxWidth.html] [test_remote_frame.html] skip-if = (buildapp == 'b2g' && toolkit != 'gonk') #Bug 931116, b2g desktop specific, initial triage [test_remote_passpointerevents.html] diff --git a/layout/base/tests/test_maxLineBoxWidth.html b/layout/base/tests/test_maxLineBoxWidth.html deleted file mode 100644 index d8b0431cacd..00000000000 --- a/layout/base/tests/test_maxLineBoxWidth.html +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - Test for Bug 780258 - - - - - - -Mozilla Bug 780258 -

- - -
-
-
- - diff --git a/layout/build/moz.build b/layout/build/moz.build index 83318f31b36..6272b01d4a4 100644 --- a/layout/build/moz.build +++ b/layout/build/moz.build @@ -85,17 +85,18 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': LOCAL_INCLUDES += [ '/dom/system/gonk', ] - CXXFLAGS += [ - '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'dalvik/libnativehelper/include/nativehelper', - 'frameworks/base/include', - 'frameworks/base/include/binder', - 'frameworks/base/include/utils', - 'frameworks/base/include/media', - 'frameworks/base/include/media/stagefright/openmax', - 'frameworks/base/media/libstagefright/include', + if CONFIG['ANDROID_VERSION'] == '15': + LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ + 'dalvik/libnativehelper/include/nativehelper', + 'frameworks/base/include', + 'frameworks/base/include/binder', + 'frameworks/base/include/media', + 'frameworks/base/include/media/stagefright/openmax', + 'frameworks/base/include/utils', + 'frameworks/base/media/libstagefright/include', + ] ] - ] if CONFIG['MOZ_B2G_FM']: LOCAL_INCLUDES += [ diff --git a/layout/generic/nsGfxScrollFrame.cpp b/layout/generic/nsGfxScrollFrame.cpp index 8b25b2bf15b..08ea83d63d6 100644 --- a/layout/generic/nsGfxScrollFrame.cpp +++ b/layout/generic/nsGfxScrollFrame.cpp @@ -1875,6 +1875,8 @@ ScrollFrameHelper::ScrollFrameHelper(nsContainerFrame* aOuter, ScreenMargin(), 0, nsLayoutUtils::RepaintMode::DoNotRepaint); + nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors( + mOuter, nsLayoutUtils::RepaintMode::DoNotRepaint); } } @@ -2136,6 +2138,10 @@ ScrollFrameHelper::ScrollToWithOrigin(nsPoint aScrollPosition, nsLayoutUtils::CalculateAndSetDisplayPortMargins( mOuter->GetScrollTargetFrame(), nsLayoutUtils::RepaintMode::DoNotRepaint); + nsIFrame* frame = do_QueryFrame(mOuter->GetScrollTargetFrame()); + nsLayoutUtils::SetZeroMarginDisplayPortOnAsyncScrollableAncestors( + frame, + nsLayoutUtils::RepaintMode::DoNotRepaint); } // Schedule a paint to ensure that the frame metrics get updated on diff --git a/layout/generic/nsHTMLReflowState.cpp b/layout/generic/nsHTMLReflowState.cpp index 37816b92557..0adacc20dd4 100644 --- a/layout/generic/nsHTMLReflowState.cpp +++ b/layout/generic/nsHTMLReflowState.cpp @@ -514,10 +514,9 @@ void nsHTMLReflowState::InitResizeFlags(nsPresContext* aPresContext, nsIAtom* aFrameType) { const WritingMode wm = mWritingMode; // just a shorthand - bool isIResize = (frame->ISize(wm) != - ComputedISize() + - ComputedLogicalBorderPadding().IStartEnd(wm)) || - aPresContext->PresShell()->IsReflowOnZoomPending(); + bool isIResize = + frame->ISize(wm) != + ComputedISize() + ComputedLogicalBorderPadding().IStartEnd(wm); if ((frame->GetStateBits() & NS_FRAME_FONT_INFLATION_FLOW_ROOT) && nsLayoutUtils::FontSizeInflationEnabled(aPresContext)) { diff --git a/layout/generic/nsLineLayout.cpp b/layout/generic/nsLineLayout.cpp index 55f958e0e6b..f57c98d52be 100644 --- a/layout/generic/nsLineLayout.cpp +++ b/layout/generic/nsLineLayout.cpp @@ -211,23 +211,6 @@ nsLineLayout::BeginLineReflow(nscoord aICoord, nscoord aBCoord, psd->mIEnd = aICoord + aISize; mContainerSize = aContainerSize; - // If we're in a constrained block-size frame, then we don't allow a - // max line box width to take effect. - if (!(LineContainerFrame()->GetStateBits() & - NS_FRAME_IN_CONSTRAINED_BSIZE)) { - - // If the available size is greater than the maximum line box width (if - // specified), then we need to adjust the line box width to be at the max - // possible width. - nscoord maxLineBoxWidth = - LineContainerFrame()->PresContext()->PresShell()->MaxLineBoxWidth(); - - if (maxLineBoxWidth > 0 && - psd->mIEnd - psd->mIStart > maxLineBoxWidth) { - psd->mIEnd = psd->mIStart + maxLineBoxWidth; - } - } - mBStartEdge = aBCoord; psd->mNoWrap = !mStyleText->WhiteSpaceCanWrapStyle() || mSuppressLineWrap; diff --git a/layout/style/CSSStyleSheet.cpp b/layout/style/CSSStyleSheet.cpp index 4bc98188f04..9a71201dfae 100644 --- a/layout/style/CSSStyleSheet.cpp +++ b/layout/style/CSSStyleSheet.cpp @@ -2332,12 +2332,6 @@ CSSStyleSheet::ReparseSheet(const nsAString& aInput) return NS_OK; } -/* virtual */ nsIURI* -CSSStyleSheet::GetOriginalURI() const -{ - return mInner->mOriginalSheetURI; -} - /* virtual */ JSObject* CSSStyleSheet::WrapObject(JSContext* aCx, JS::Handle aGivenProto) diff --git a/layout/style/CSSStyleSheet.h b/layout/style/CSSStyleSheet.h index 1192fc5da1b..4abf42e857c 100644 --- a/layout/style/CSSStyleSheet.h +++ b/layout/style/CSSStyleSheet.h @@ -224,7 +224,7 @@ public: /* Get the URI this sheet was originally loaded from, if any. Can return null */ - virtual nsIURI* GetOriginalURI() const; + nsIURI* GetOriginalURI() const { return mInner->mOriginalSheetURI; } // nsICSSLoaderObserver interface NS_IMETHOD StyleSheetLoaded(CSSStyleSheet* aSheet, bool aWasAlternate, diff --git a/layout/style/Loader.cpp b/layout/style/Loader.cpp index e899c6ba37a..26d210daacb 100644 --- a/layout/style/Loader.cpp +++ b/layout/style/Loader.cpp @@ -437,7 +437,7 @@ SheetLoadData::SheetLoadData(Loader* aLoader, SheetLoadData::~SheetLoadData() { - NS_IF_RELEASE(mNext); + NS_CSS_NS_RELEASE_LIST_MEMBER(SheetLoadData, this, mNext); } NS_IMETHODIMP diff --git a/layout/style/crashtests/1186768-1.xhtml b/layout/style/crashtests/1186768-1.xhtml new file mode 100644 index 00000000000..22608557df5 --- /dev/null +++ b/layout/style/crashtests/1186768-1.xhtml @@ -0,0 +1,10 @@ + + + + +
+
+ +
+ + diff --git a/layout/style/crashtests/1221902.html b/layout/style/crashtests/1221902.html new file mode 100644 index 00000000000..4186a38b95d --- /dev/null +++ b/layout/style/crashtests/1221902.html @@ -0,0 +1,38002 @@ + diff --git a/layout/style/crashtests/crashtests.list b/layout/style/crashtests/crashtests.list index d93807c42f9..c541ed9fdf8 100644 --- a/layout/style/crashtests/crashtests.list +++ b/layout/style/crashtests/crashtests.list @@ -125,9 +125,11 @@ load 1161366-1.html load 1163446-1.html load 1164813-1.html load 1167782-1.html +load 1186768-1.xhtml load 1200568-1.html load 1206105-1.html load border-image-visited-link.html load font-face-truncated-src.html load large_border_image_width.html load long-url-list-stack-overflow.html +load 1221902.html diff --git a/layout/style/nsCSSValue.h b/layout/style/nsCSSValue.h index 6648c3423cf..6c27d6e2ccb 100644 --- a/layout/style/nsCSSValue.h +++ b/layout/style/nsCSSValue.h @@ -50,6 +50,18 @@ class CSSStyleSheet; cur = dlm_next; \ } \ } +// Ditto, but use NS_RELEASE instead of 'delete' (bug 1221902). +#define NS_CSS_NS_RELEASE_LIST_MEMBER(type_, ptr_, member_) \ + { \ + type_ *cur = (ptr_)->member_; \ + (ptr_)->member_ = nullptr; \ + while (cur) { \ + type_ *dlm_next = cur->member_; \ + cur->member_ = nullptr; \ + NS_RELEASE(cur); \ + cur = dlm_next; \ + } \ + } // Clones a linked list iteratively to avoid blowing up the stack. // If it fails to clone the entire list then 'to_' is deleted and diff --git a/layout/style/nsRuleNode.cpp b/layout/style/nsRuleNode.cpp index bdb211208cf..23eb44fea96 100644 --- a/layout/style/nsRuleNode.cpp +++ b/layout/style/nsRuleNode.cpp @@ -3846,24 +3846,50 @@ nsRuleNode::SetFont(nsPresContext* aPresContext, nsStyleContext* aContext, &scriptLevelAdjustedUnconstrainedParentSize); NS_ASSERTION(!aUsedStartStruct || aFont->mScriptUnconstrainedSize == aFont->mSize, "If we have a start struct, we should have reset everything coming in here"); + + // Compute whether we're affected by scriptMinSize *before* calling + // SetFontSize, since aParentFont might be the same as aFont. If it + // is, calling SetFontSize might throw off our calculation. + bool affectedByScriptMinSize = + aParentFont->mSize != aParentFont->mScriptUnconstrainedSize || + scriptLevelAdjustedParentSize != + scriptLevelAdjustedUnconstrainedParentSize; + SetFontSize(aPresContext, aRuleData, aFont, aParentFont, &aFont->mSize, systemFont, aParentFont->mSize, scriptLevelAdjustedParentSize, aUsedStartStruct, atRoot, aConditions); - if (aParentFont->mSize == aParentFont->mScriptUnconstrainedSize && - scriptLevelAdjustedParentSize == scriptLevelAdjustedUnconstrainedParentSize) { + if (!aPresContext->Document()->GetMathMLEnabled()) { + MOZ_ASSERT(!affectedByScriptMinSize); + // If MathML is not enabled, we don't need to mark this node as + // uncacheable. If it becomes enabled, code in + // nsMathMLElementFactory will rebuild the rule tree and style data + // when MathML is first enabled (see nsMathMLElement::BindToTree). + aFont->mScriptUnconstrainedSize = aFont->mSize; + } else if (!affectedByScriptMinSize) { // Fast path: we have not been affected by scriptminsize so we don't // need to call SetFontSize again to compute the // scriptminsize-unconstrained size. This is OK even if we have a // start struct, because if we have a start struct then 'font-size' // was specified and so scriptminsize has no effect. aFont->mScriptUnconstrainedSize = aFont->mSize; + // It's possible we could, in the future, have a different parent, + // which would lead to a different affectedByScriptMinSize. + aConditions.SetUncacheable(); } else { + // see previous else-if + aConditions.SetUncacheable(); + + // Use a separate conditions object because it might get a + // *different* font-size dependency. We can ignore it because we've + // already called SetUncacheable. + RuleNodeCacheConditions unconstrainedConditions; + SetFontSize(aPresContext, aRuleData, aFont, aParentFont, &aFont->mScriptUnconstrainedSize, systemFont, aParentFont->mScriptUnconstrainedSize, scriptLevelAdjustedUnconstrainedParentSize, - aUsedStartStruct, atRoot, aConditions); + aUsedStartStruct, atRoot, unconstrainedConditions); } NS_ASSERTION(aFont->mScriptUnconstrainedSize <= aFont->mSize, "scriptminsize should never be making things bigger"); diff --git a/layout/style/test/mochitest.ini b/layout/style/test/mochitest.ini index 40c7148cb1a..fc057db0ca0 100644 --- a/layout/style/test/mochitest.ini +++ b/layout/style/test/mochitest.ini @@ -176,6 +176,7 @@ support-files = BitPattern.woff file_font_loading_api_vframe.html [test_garbage_at_end_of_declarations.html] +skip-if = (toolkit == 'gonk' && debug) # Bug 1186440 [test_grid_container_shorthands.html] [test_grid_item_shorthands.html] [test_grid_shorthand_serialization.html] diff --git a/layout/svg/nsSVGIntegrationUtils.h b/layout/svg/nsSVGIntegrationUtils.h index f8781aa83e5..00514e042d8 100644 --- a/layout/svg/nsSVGIntegrationUtils.h +++ b/layout/svg/nsSVGIntegrationUtils.h @@ -9,13 +9,13 @@ #include "gfxMatrix.h" #include "gfxRect.h" #include "nsAutoPtr.h" +#include "nsRegionFwd.h" class gfxContext; class gfxDrawable; class nsDisplayList; class nsDisplayListBuilder; class nsIFrame; -class nsIntRegion; struct nsRect; diff --git a/media/libcubeb/src/moz.build b/media/libcubeb/src/moz.build index 3a11a25c090..a01a4ced249 100644 --- a/media/libcubeb/src/moz.build +++ b/media/libcubeb/src/moz.build @@ -63,12 +63,14 @@ if CONFIG['OS_TARGET'] == 'Android': FINAL_LIBRARY = 'gkmedias' if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - CFLAGS += [ - '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/wilhelm/include', - 'system/media/wilhelm/include', + if CONFIG['ANDROID_VERSION'] >= '17': + LOCAL_INCLUDES += [ + '%' + '%s/frameworks/wilhelm/include' % CONFIG['ANDROID_SOURCE'], + ] + else: + LOCAL_INCLUDES += [ + '%' + '%s/system/media/wilhelm/include' % CONFIG['ANDROID_SOURCE'], ] - ] CFLAGS += CONFIG['MOZ_ALSA_CFLAGS'] CFLAGS += CONFIG['MOZ_PULSEAUDIO_CFLAGS'] diff --git a/media/omx-plugin/moz.build b/media/omx-plugin/moz.build index 529bab2077a..12b939effab 100644 --- a/media/omx-plugin/moz.build +++ b/media/omx-plugin/moz.build @@ -33,20 +33,22 @@ if CONFIG['GNU_CXX']: CXXFLAGS += ['-Wno-multichar'] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk': - CXXFLAGS += [ - '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'dalvik/libnativehelper/include/nativehelper', - 'frameworks/base/include/', - 'frameworks/base/include/binder/', - 'frameworks/base/include/utils/', - 'frameworks/base/include/media/', - 'frameworks/base/include/media/stagefright/openmax', - 'frameworks/base/media/libstagefright/include', - 'frameworks/base/native/include', - 'system/core/include', - 'hardware/libhardware/include', - ] - ] + if CONFIG['ANDROID_VERSION'] == '15': + LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ + 'dalvik/libnativehelper/include/nativehelper', + 'frameworks/base/include/', + 'frameworks/base/include/binder/', + 'frameworks/base/include/media/', + 'frameworks/base/include/media/stagefright/openmax', + 'frameworks/base/include/utils/', + 'frameworks/base/media/libstagefright/include', + 'frameworks/base/native/include', + 'hardware/libhardware/include', + 'system/core/include', + ] + ] + EXTRA_DSO_LDOPTS += [ '-lutils', '-lstagefright', diff --git a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp index cc1ba2682e0..05d0ed0038b 100644 --- a/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp +++ b/media/webrtc/signaling/src/mediapipeline/MediaPipeline.cpp @@ -45,6 +45,7 @@ #include "mozilla/gfx/Point.h" #include "mozilla/gfx/Types.h" #include "mozilla/UniquePtr.h" +#include "mozilla/UniquePtrExtensions.h" #include "logging.h" @@ -1179,7 +1180,7 @@ void MediaPipelineTransmit::PipelineListener::ProcessVideoChunk( int half_height = (size.height + 1) >> 1; int c_size = half_width * half_height; int buffer_size = YSIZE(size.width, size.height) + 2 * c_size; - UniquePtr yuv_scoped(new (fallible) uint8[buffer_size]); + auto yuv_scoped = MakeUniqueFallible(buffer_size); if (!yuv_scoped) return; uint8* yuv = yuv_scoped.get(); diff --git a/media/webrtc/signaling/test/common.build b/media/webrtc/signaling/test/common.build index babf9b6c94a..b3bb19f04b5 100644 --- a/media/webrtc/signaling/test/common.build +++ b/media/webrtc/signaling/test/common.build @@ -11,10 +11,8 @@ for var in ('MOZILLA_EXTERNAL_LINKAGE', 'USE_FAKE_MEDIA_STREAMS', 'USE_FAKE_PCOB 'NR_SOCKET_IS_VOID_PTR', 'HAVE_STRDUP'): DEFINES[var] = True -GENERATED_INCLUDES += [ - '/dom/bindings', -] LOCAL_INCLUDES += [ + '!/dom/bindings', '/dom/media/', '/ipc/chromium/src', '/media/mtransport', diff --git a/memory/build/moz.build b/memory/build/moz.build index efeb9c8e427..3595bc663c7 100644 --- a/memory/build/moz.build +++ b/memory/build/moz.build @@ -27,7 +27,7 @@ if CONFIG['MOZ_JEMALLOC4']: SOURCES += [ 'mozjemalloc_compat.c', ] - GENERATED_INCLUDES += ['../jemalloc/src/include'] + LOCAL_INCLUDES += ['!../jemalloc/src/include'] if CONFIG['_MSC_VER']: LOCAL_INCLUDES += ['/memory/jemalloc/src/include/msvc_compat'] if not CONFIG['HAVE_INTTYPES_H']: diff --git a/memory/jemalloc/moz.build b/memory/jemalloc/moz.build index ed05a2d1578..55c84c67979 100644 --- a/memory/jemalloc/moz.build +++ b/memory/jemalloc/moz.build @@ -69,8 +69,10 @@ if CONFIG['GNU_CC']: DEFINES['abort'] = 'moz_abort' -GENERATED_INCLUDES += ['src/include'] -LOCAL_INCLUDES += ['src/include'] +LOCAL_INCLUDES += [ + '!src/include', + 'src/include', +] # We allow warnings for third-party code that can be updated from upstream. ALLOW_COMPILER_WARNINGS = True diff --git a/memory/mozalloc/moz.build b/memory/mozalloc/moz.build index 35a3e0c1115..33f599199af 100644 --- a/memory/mozalloc/moz.build +++ b/memory/mozalloc/moz.build @@ -36,8 +36,6 @@ FINAL_LIBRARY = 'mozglue' # The strndup declaration in string.h is in an ifdef __USE_GNU section DEFINES['_GNU_SOURCE'] = True -GENERATED_INCLUDES += ['/xpcom'] - DISABLE_STL_WRAPPING = True DEFINES['IMPL_MFBT'] = True @@ -45,7 +43,10 @@ DEFINES['IMPL_MFBT'] = True if CONFIG['_MSC_VER']: DIRS += ['staticruntime'] -LOCAL_INCLUDES += ['/memory/build'] +LOCAL_INCLUDES += [ + '!/xpcom', + '/memory/build', +] DIST_INSTALL = True diff --git a/memory/mozalloc/staticruntime/moz.build b/memory/mozalloc/staticruntime/moz.build index e4efea85278..e0a6b9def6a 100644 --- a/memory/mozalloc/staticruntime/moz.build +++ b/memory/mozalloc/staticruntime/moz.build @@ -19,7 +19,7 @@ UNIFIED_SOURCES += [ '../mozalloc_oom.cpp', ] -GENERATED_INCLUDES += ['/xpcom'] +LOCAL_INCLUDES += ['!/xpcom'] DISABLE_STL_WRAPPING = True diff --git a/memory/replace/jemalloc/moz.build b/memory/replace/jemalloc/moz.build index 1918de4763e..7518f245101 100644 --- a/memory/replace/jemalloc/moz.build +++ b/memory/replace/jemalloc/moz.build @@ -26,7 +26,7 @@ USE_LIBS += [ DEFINES['MOZ_JEMALLOC4'] = True DEFINES['MOZ_REPLACE_JEMALLOC'] = True -GENERATED_INCLUDES += ['../../jemalloc/src/include'] +LOCAL_INCLUDES += ['!../../jemalloc/src/include'] if CONFIG['_MSC_VER']: LOCAL_INCLUDES += ['/memory/jemalloc/src/include/msvc_compat'] if not CONFIG['HAVE_INTTYPES_H']: diff --git a/mfbt/UniquePtrExtensions.h b/mfbt/UniquePtrExtensions.h new file mode 100644 index 00000000000..65b07ed2ee0 --- /dev/null +++ b/mfbt/UniquePtrExtensions.h @@ -0,0 +1,42 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* Useful extensions to UniquePtr. */ + +#ifndef mozilla_UniquePtrExtensions_h +#define mozilla_UniquePtrExtensions_h + +#include "mozilla/fallible.h" +#include "mozilla/UniquePtr.h" + +namespace mozilla { + +/** + * MakeUniqueFallible works exactly like MakeUnique, except that the memory + * allocation performed is done fallibly, i.e. it can return nullptr. + */ +template +typename detail::UniqueSelector::SingleObject +MakeUniqueFallible(Args&&... aArgs) +{ + return UniquePtr(new (fallible) T(Forward(aArgs)...)); +} + +template +typename detail::UniqueSelector::UnknownBound +MakeUniqueFallible(decltype(sizeof(int)) aN) +{ + typedef typename RemoveExtent::Type ArrayType; + return UniquePtr(new (fallible) ArrayType[aN]()); +} + +template +typename detail::UniqueSelector::KnownBound +MakeUniqueFallible(Args&&... aArgs) = delete; + +} // namespace mozilla + +#endif // mozilla_UniquePtrExtensions_h diff --git a/mfbt/moz.build b/mfbt/moz.build index 4678f6d060d..f4ae83fbf40 100644 --- a/mfbt/moz.build +++ b/mfbt/moz.build @@ -89,6 +89,7 @@ EXPORTS.mozilla = [ 'Types.h', 'TypeTraits.h', 'UniquePtr.h', + 'UniquePtrExtensions.h', 'Variant.h', 'Vector.h', 'WeakPtr.h', diff --git a/mobile/android/base/AndroidManifest.xml b/mobile/android/base/AndroidManifest.xml new file mode 100644 index 00000000000..decb23df4fd --- /dev/null +++ b/mobile/android/base/AndroidManifest.xml @@ -0,0 +1,6 @@ + + + + diff --git a/mobile/android/base/DataReportingNotification.java b/mobile/android/base/DataReportingNotification.java index 62fe79cbee3..a4988b190fd 100644 --- a/mobile/android/base/DataReportingNotification.java +++ b/mobile/android/base/DataReportingNotification.java @@ -78,7 +78,7 @@ public class DataReportingNotification { Intent prefIntent = new Intent(GeckoApp.ACTION_LAUNCH_SETTINGS); prefIntent.setClassName(AppConstants.ANDROID_PACKAGE_NAME, AppConstants.MOZ_ANDROID_BROWSER_INTENT_CLASS); - GeckoPreferences.setResourceToOpen(prefIntent, "preferences_vendor"); + GeckoPreferences.setResourceToOpen(prefIntent, "preferences_privacy"); prefIntent.putExtra(ALERT_NAME_DATAREPORTING_NOTIFICATION, true); PendingIntent contentIntent = PendingIntent.getActivity(context, 0, prefIntent, PendingIntent.FLAG_UPDATE_CURRENT); diff --git a/mobile/android/base/android-services.mozbuild b/mobile/android/base/android-services.mozbuild index 31be309cdea..84d3361c35f 100644 --- a/mobile/android/base/android-services.mozbuild +++ b/mobile/android/base/android-services.mozbuild @@ -850,6 +850,7 @@ sync_java_files = [ 'browserid/verifier/BrowserIDVerifierException.java', 'browserid/VerifyingPublicKey.java', 'fxa/AccountLoader.java', + 'fxa/activities/CustomColorPreference.java', 'fxa/activities/FxAccountAbstractActivity.java', 'fxa/activities/FxAccountAbstractSetupActivity.java', 'fxa/activities/FxAccountAbstractUpdateCredentialsActivity.java', diff --git a/mobile/android/base/build.gradle b/mobile/android/base/build.gradle new file mode 100644 index 00000000000..b6c33de56df --- /dev/null +++ b/mobile/android/base/build.gradle @@ -0,0 +1,131 @@ +buildDir "${topobjdir}/gradle/build/mobile/android/base" + +apply plugin: 'com.android.library' + +android { + compileSdkVersion 23 + buildToolsVersion "23.0.1" + + defaultConfig { + targetSdkVersion 22 + minSdkVersion 9 + } + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_7 + targetCompatibility JavaVersion.VERSION_1_7 + } + + lintOptions { + abortOnError false + } + + sourceSets { + main { + manifest.srcFile 'AndroidManifest.xml' + java { + srcDir "${topobjdir}/gradle/base/src" + exclude 'org/mozilla/gecko/resources/**' + + srcDir "${topsrcdir}/mobile/android/search/java" + srcDir "${topsrcdir}/mobile/android/javaaddons/java" + + if (mozconfig.substs.MOZ_ANDROID_MLS_STUMBLER) { + srcDir "${topsrcdir}/mobile/android/stumbler/java" + } + + if (!mozconfig.substs.MOZ_CRASHREPORTER) { + exclude 'org/mozilla/gecko/CrashReporter.java' + } + + if (!mozconfig.substs.MOZ_NATIVE_DEVICES) { + exclude 'org/mozilla/gecko/ChromeCast.java' + exclude 'org/mozilla/gecko/GeckoMediaPlayer.java' + exclude 'org/mozilla/gecko/MediaPlayerManager.java' + } + + if (mozconfig.substs.MOZ_WEBRTC) { + srcDir "${topsrcdir}/media/webrtc/trunk/webrtc/modules/audio_device/android/java/src" + srcDir "${topsrcdir}/media/webrtc/trunk/webrtc/modules/video_capture/android/java/src" + srcDir "${topsrcdir}/media/webrtc/trunk/webrtc/modules/video_render/android/java/src" + } + + if (mozconfig.substs.MOZ_INSTALL_TRACKING) { + exclude 'org/mozilla/gecko/adjust/StubAdjustHelper.java' + } else { + exclude 'org/mozilla/gecko/adjust/AdjustHelper.java' + } + + srcDir "${project.buildDir}/generated/source/preprocessed_code" // See syncPreprocessedCode. + } + + res { + srcDir "${topsrcdir}/${mozconfig.substs.MOZ_BRANDING_DIRECTORY}/res" + srcDir "${project.buildDir}/generated/source/preprocessed_resources" // See syncPreprocessedResources. + srcDir 'resources' + if (mozconfig.substs.MOZ_CRASHREPORTER) { + srcDir 'crashreporter/res' + } + } + } + + test { + java { + srcDir "${topsrcdir}/mobile/android/tests/background/junit4/src" + } + + resources { + srcDir "${topsrcdir}/mobile/android/tests/background/junit4/resources" + } + } + } +} + +task syncPreprocessedCode(type: Sync, dependsOn: rootProject.generateCodeAndResources) { + into("${project.buildDir}/generated/source/preprocessed_code") + from("${topobjdir}/mobile/android/base/generated/preprocessed") +} + +task syncPreprocessedResources(type: Sync, dependsOn: rootProject.generateCodeAndResources) { + into("${project.buildDir}/generated/source/preprocessed_resources") + from("${topobjdir}/mobile/android/base/res") +} + +android.libraryVariants.all { variant -> + variant.preBuild.dependsOn syncPreprocessedCode + variant.preBuild.dependsOn syncPreprocessedResources +} + +dependencies { + compile 'com.android.support:support-v4:23.0.1' + compile 'com.android.support:appcompat-v7:23.0.1' + compile 'com.android.support:recyclerview-v7:23.0.1' + compile 'com.android.support:design:23.0.1' + + if (mozconfig.substs.MOZ_NATIVE_DEVICES) { + compile 'com.android.support:mediarouter-v7:23.0.1' + compile 'com.google.android.gms:play-services-basement:8.1.0' + compile 'com.google.android.gms:play-services-base:8.1.0' + compile 'com.google.android.gms:play-services-cast:8.1.0' + } + + if (mozconfig.substs.MOZ_ANDROID_GCM) { + compile 'com.google.android.gms:play-services-basement:8.1.0' + compile 'com.google.android.gms:play-services-base:8.1.0' + compile 'com.google.android.gms:play-services-gcm:8.1.0' + } + + compile project(':thirdparty') + + testCompile 'junit:junit:4.12' + testCompile 'org.robolectric:robolectric:3.0' + testCompile 'org.simpleframework:simple-http:4.1.13' +} + +apply plugin: 'idea' + +idea { + module { + excludeDirs += file("${topobjdir}/gradle/base/src/org/mozilla/gecko/resources") + } +} diff --git a/mobile/android/base/fxa/activities/CustomColorPreference.java b/mobile/android/base/fxa/activities/CustomColorPreference.java new file mode 100644 index 00000000000..5c4d7f3ccaf --- /dev/null +++ b/mobile/android/base/fxa/activities/CustomColorPreference.java @@ -0,0 +1,52 @@ +/* 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/. */ + +package org.mozilla.gecko.fxa.activities; + +import org.mozilla.gecko.R; +import android.content.Context; +import android.content.res.TypedArray; +import android.preference.Preference; +import android.util.AttributeSet; +import android.view.View; +import android.widget.TextView; + + /** + * This preference is used to define custom colors for both title and summary texts. + * Color code #777777 (placeholder_grey) is used as the fallback color for both title and summary. + */ +public class CustomColorPreference extends Preference { + private int mTitleColor; + private int mSummaryColor; + + public CustomColorPreference(Context context) { + super(context); + } + + public CustomColorPreference(Context context, AttributeSet attrs) { + super(context, attrs); + init(context, attrs); + } + + public CustomColorPreference(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + init(context, attrs); + } + + public void init(Context context, AttributeSet attrs) { + TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CustomColorPreference); + mTitleColor = a.getColor(R.styleable.CustomColorPreference_titleColor, R.color.placeholder_grey); + mSummaryColor = a.getColor(R.styleable.CustomColorPreference_summaryColor, R.color.placeholder_grey); + a.recycle(); + } + + @Override + protected void onBindView(View view) { + super.onBindView(view); + final TextView title = (TextView) view.findViewById(android.R.id.title); + final TextView summary = (TextView) view.findViewById(android.R.id.summary); + title.setTextColor(mTitleColor); + summary.setTextColor(mSummaryColor); + } +} diff --git a/mobile/android/base/lint.xml b/mobile/android/base/lint.xml new file mode 100644 index 00000000000..b1cc083dee2 --- /dev/null +++ b/mobile/android/base/lint.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/mobile/android/base/preferences/GeckoPreferenceFragment.java b/mobile/android/base/preferences/GeckoPreferenceFragment.java index 2ae04fe758a..4551c23eb36 100644 --- a/mobile/android/base/preferences/GeckoPreferenceFragment.java +++ b/mobile/android/base/preferences/GeckoPreferenceFragment.java @@ -98,8 +98,8 @@ public class GeckoPreferenceFragment extends PreferenceFragment { // We need this because we can launch straight into this category // from the Data Reporting notification. - if (res == R.xml.preferences_vendor) { - return getString(R.string.pref_category_vendor); + if (res == R.xml.preferences_privacy) { + return getString(R.string.pref_category_privacy_short); } // from the Awesomescreen with the magnifying glass. diff --git a/mobile/android/base/resources/values/attrs.xml b/mobile/android/base/resources/values/attrs.xml index d11a33d17e4..a3cc181449f 100644 --- a/mobile/android/base/resources/values/attrs.xml +++ b/mobile/android/base/resources/values/attrs.xml @@ -168,6 +168,11 @@ + + + + + diff --git a/mobile/android/base/resources/xml/fxaccount_status_prefscreen.xml b/mobile/android/base/resources/xml/fxaccount_status_prefscreen.xml index 88b16e27497..59e447ebee7 100644 --- a/mobile/android/base/resources/xml/fxaccount_status_prefscreen.xml +++ b/mobile/android/base/resources/xml/fxaccount_status_prefscreen.xml @@ -1,6 +1,7 @@ + xmlns:gecko="http://schemas.android.com/apk/res-auto" + android:key="status_screen"> - Cu.reportError("Error adding tab to reading list: " + e)); UITelemetry.addEvent("save.1", "pageaction", null, "reader"); + Reader._buttonHistogram.add(Reader._buttonHistogramValues.LONG_TAP); }, }, @@ -247,6 +264,9 @@ var Reader = { if (browser.isArticle) { showPageAction("drawable://reader", Strings.reader.GetStringFromName("readerView.enter")); + this._buttonHistogram.add(this._buttonHistogramValues.SHOWN); + } else { + this._buttonHistogram.add(this._buttonHistogramValues.HIDDEN); } }, diff --git a/mozglue/android/moz.build b/mozglue/android/moz.build index 71d87af80af..88cf3701149 100644 --- a/mozglue/android/moz.build +++ b/mozglue/android/moz.build @@ -26,8 +26,8 @@ for var in ('ANDROID_PACKAGE_NAME', if CONFIG['MOZ_FOLD_LIBS']: DEFINES['MOZ_FOLD_LIBS'] = True -GENERATED_INCLUDES += ['/build'] LOCAL_INCLUDES += [ + '!/build', '../linker', '/db/sqlite3/src', '/ipc/chromium/src', diff --git a/netwerk/build/moz.build b/netwerk/build/moz.build index e9ca940fa32..a3ba3c7ceac 100644 --- a/netwerk/build/moz.build +++ b/netwerk/build/moz.build @@ -73,6 +73,6 @@ if CONFIG['MOZ_RTSP']: '/netwerk/protocol/rtsp', ] -GENERATED_INCLUDES += [ - '/netwerk/dns', +LOCAL_INCLUDES += [ + '!/netwerk/dns', ] diff --git a/netwerk/dns/mdns/libmdns/moz.build b/netwerk/dns/mdns/libmdns/moz.build index 1615f3a070e..2012f423d14 100644 --- a/netwerk/dns/mdns/libmdns/moz.build +++ b/netwerk/dns/mdns/libmdns/moz.build @@ -17,8 +17,8 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['ANDROID_VERSION'] >= '16 'nsDNSServiceDiscovery.cpp', ] - CXXFLAGS += [ - '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ + LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ 'external/mdnsresponder/mDNSShared', ] ] diff --git a/netwerk/dns/moz.build b/netwerk/dns/moz.build index d1d259e1218..49ed50ef72d 100644 --- a/netwerk/dns/moz.build +++ b/netwerk/dns/moz.build @@ -67,7 +67,7 @@ LOCAL_INCLUDES += [ ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk' and CONFIG['ANDROID_VERSION'] > '19': - CXXFLAGS += ['-I%s/bionic/libc/dns/include' % CONFIG['ANDROID_SOURCE']] + LOCAL_INCLUDES += ['%' + '%s/bionic/libc/dns/include' % CONFIG['ANDROID_SOURCE']] if CONFIG['ENABLE_INTL_API']: DEFINES['IDNA2008'] = True diff --git a/netwerk/protocol/rtsp/moz.build b/netwerk/protocol/rtsp/moz.build index 655507dac8f..13d491cd1d5 100644 --- a/netwerk/protocol/rtsp/moz.build +++ b/netwerk/protocol/rtsp/moz.build @@ -66,8 +66,8 @@ for var in ('IMPL_NS_NET', 'FORCE_PR_LOG'): DEFINES[var] = True if CONFIG['ANDROID_VERSION'] == '15': - CXXFLAGS += ['-I%s/frameworks/base/media/libstagefright/mpeg2ts' % CONFIG['ANDROID_SOURCE']] + LOCAL_INCLUDES += ['%' + '%s/frameworks/base/media/libstagefright/mpeg2ts' % CONFIG['ANDROID_SOURCE']] else: - CXXFLAGS += ['-I%s/frameworks/av/media/libstagefright/mpeg2ts' % CONFIG['ANDROID_SOURCE']] + LOCAL_INCLUDES += ['%' + '%s/frameworks/av/media/libstagefright/mpeg2ts' % CONFIG['ANDROID_SOURCE']] CXXFLAGS += ['-Wno-multichar'] diff --git a/python/mozbuild/mozbuild/backend/recursivemake.py b/python/mozbuild/mozbuild/backend/recursivemake.py index 33767778b34..ee8962ef0fd 100644 --- a/python/mozbuild/mozbuild/backend/recursivemake.py +++ b/python/mozbuild/mozbuild/backend/recursivemake.py @@ -24,6 +24,11 @@ from mozpack.manifests import ( ) import mozpack.path as mozpath +from mozbuild.frontend.context import ( + Path, + SourcePath, + ObjDirPath, +) from .common import CommonBackend from ..frontend.data import ( AndroidAssetsDirs, @@ -42,7 +47,6 @@ from ..frontend.data import ( ExternalLibrary, FinalTargetFiles, GeneratedFile, - GeneratedInclude, GeneratedSources, HostDefines, HostLibrary, @@ -556,9 +560,6 @@ class RecursiveMakeBackend(CommonBackend): elif isinstance(obj, LocalInclude): self._process_local_include(obj.path, backend_file) - elif isinstance(obj, GeneratedInclude): - self._process_generated_include(obj.path, backend_file) - elif isinstance(obj, PerSourceFlag): self._process_per_source_flag(obj, backend_file) @@ -868,6 +869,21 @@ class RecursiveMakeBackend(CommonBackend): ensureParentDir(mozpath.join(self.environment.topobjdir, 'dist', 'foo')) + def _pretty_path(self, path, backend_file): + assert isinstance(path, Path) + if isinstance(path, SourcePath): + if path.full_path.startswith(backend_file.srcdir): + return '$(srcdir)' + path.full_path[len(backend_file.srcdir):] + if path.full_path.startswith(self.environment.topsrcdir): + return '$(topsrcdir)' + path.full_path[len(self.environment.topsrcdir):] + elif isinstance(path, ObjDirPath): + if path.full_path.startswith(backend_file.objdir): + return path.full_path[len(backend_file.objdir) + 1:] + if path.full_path.startswith(self.environment.topobjdir): + return '$(DEPTH)' + path.full_path[len(self.environment.topobjdir):] + + return path.full_path + def _process_unified_sources(self, obj): backend_file = self._get_backend_file_for(obj) @@ -1219,18 +1235,11 @@ INSTALL_TARGETS += %(prefix)s self.backend_input_files |= obj.manifest.manifests def _process_local_include(self, local_include, backend_file): - if local_include.startswith('/'): - path = '$(topsrcdir)' + path = self._pretty_path(local_include, backend_file) + if ' ' in path: + backend_file.write('LOCAL_INCLUDES += -I\'%s\'\n' % path) else: - path = '$(srcdir)/' - backend_file.write('LOCAL_INCLUDES += -I%s%s\n' % (path, local_include)) - - def _process_generated_include(self, generated_include, backend_file): - if generated_include.startswith('/'): - path = self.environment.topobjdir.replace('\\', '/') - else: - path = '' - backend_file.write('LOCAL_INCLUDES += -I%s%s\n' % (path, generated_include)) + backend_file.write('LOCAL_INCLUDES += -I%s\n' % path) def _process_per_source_flag(self, per_source_flag, backend_file): for flag in per_source_flag.flags: diff --git a/python/mozbuild/mozbuild/backend/visualstudio.py b/python/mozbuild/mozbuild/backend/visualstudio.py index 51dd2e298b6..11aa573cede 100644 --- a/python/mozbuild/mozbuild/backend/visualstudio.py +++ b/python/mozbuild/mozbuild/backend/visualstudio.py @@ -136,13 +136,8 @@ class VisualStudioBackend(CommonBackend): self._paths_to_defines.setdefault(reldir, {}).update(obj.defines) elif isinstance(obj, LocalInclude): - p = obj.path includes = self._paths_to_includes.setdefault(reldir, []) - - if p.startswith('/'): - includes.append(os.path.join('$(TopSrcDir)', p[1:])) - else: - includes.append(os.path.join('$(TopSrcDir)', reldir, p)) + includes.append(obj.path.full_path) # Just acknowledge everything. return True diff --git a/python/mozbuild/mozbuild/frontend/context.py b/python/mozbuild/mozbuild/frontend/context.py index 51991237b2e..34fec486b83 100644 --- a/python/mozbuild/mozbuild/frontend/context.py +++ b/python/mozbuild/mozbuild/frontend/context.py @@ -1077,11 +1077,6 @@ VARIABLES = { This variable only has an effect when building with MSVC. """, None), - 'GENERATED_INCLUDES' : (StrictOrderingOnAppendList, list, - """Directories generated by the build system to be searched for include - files by the compiler. - """, None), - 'HOST_SOURCES': (ContextDerivedTypedList(SourcePath, StrictOrderingOnAppendList), list, """Source code files to compile with the host compiler. @@ -1169,7 +1164,7 @@ VARIABLES = { """List of system libraries for host programs and libraries. """, None), - 'LOCAL_INCLUDES': (StrictOrderingOnAppendList, list, + 'LOCAL_INCLUDES': (ContextDerivedTypedList(Path, StrictOrderingOnAppendList), list, """Additional directories to be searched for include files by the compiler. """, None), @@ -2110,6 +2105,16 @@ DEPRECATION_HINTS = { GENERATED_SOURCES += [ 'foo.cpp'] ''', + + 'GENERATED_INCLUDES': ''' + Please use + + LOCAL_INCLUDES += [ '!foo' ] + + instead of + + GENERATED_INCLUDES += [ 'foo' ] + ''', } # Make sure that all template variables have a deprecation hint. diff --git a/python/mozbuild/mozbuild/frontend/data.py b/python/mozbuild/mozbuild/frontend/data.py index 4352c96db70..358b94c7499 100644 --- a/python/mozbuild/mozbuild/frontend/data.py +++ b/python/mozbuild/mozbuild/frontend/data.py @@ -648,18 +648,6 @@ class LocalInclude(ContextDerived): self.path = path -class GeneratedInclude(ContextDerived): - """Describes an individual generated include path.""" - - __slots__ = ( - 'path', - ) - - def __init__(self, context, path): - ContextDerived.__init__(self, context) - - self.path = path - class PerSourceFlag(ContextDerived): """Describes compiler flags specified for individual source files.""" diff --git a/python/mozbuild/mozbuild/frontend/emitter.py b/python/mozbuild/mozbuild/frontend/emitter.py index 6370fd7e2e2..64b33ba0a6c 100644 --- a/python/mozbuild/mozbuild/frontend/emitter.py +++ b/python/mozbuild/mozbuild/frontend/emitter.py @@ -38,7 +38,6 @@ from .data import ( FinalTargetFiles, GeneratedEventWebIDLFile, GeneratedFile, - GeneratedInclude, GeneratedSources, GeneratedWebIDLFile, ExampleWebIDLInterface, @@ -659,7 +658,6 @@ class TreeMetadataEmitter(LoggingMixin): ('GENERATED_EVENTS_WEBIDL_FILES', GeneratedEventWebIDLFile), ('GENERATED_WEBIDL_FILES', GeneratedWebIDLFile), ('IPDL_SOURCES', IPDLFile), - ('GENERATED_INCLUDES', GeneratedInclude), ('PREPROCESSED_TEST_WEBIDL_FILES', PreprocessedTestWebIDLFile), ('PREPROCESSED_WEBIDL_FILES', PreprocessedWebIDLFile), ('TEST_WEBIDL_FILES', TestWebIDLFile), @@ -671,17 +669,11 @@ class TreeMetadataEmitter(LoggingMixin): yield klass(context, name) for local_include in context.get('LOCAL_INCLUDES', []): - if local_include.startswith('/'): - path = context.config.topsrcdir - relative_include = local_include[1:] - else: - path = context.srcdir - relative_include = local_include - - actual_include = os.path.join(path, relative_include) - if not os.path.exists(actual_include): + if (not isinstance(local_include, ObjDirPath) and + not os.path.exists(local_include.full_path)): raise SandboxValidationError('Path specified in LOCAL_INCLUDES ' - 'does not exist: %s (resolved to %s)' % (local_include, actual_include), context) + 'does not exist: %s (resolved to %s)' % (local_include, + local_include.full_path), context) yield LocalInclude(context, local_include) final_target_files = context.get('FINAL_TARGET_FILES') diff --git a/python/mozbuild/mozbuild/frontend/gyp_reader.py b/python/mozbuild/mozbuild/frontend/gyp_reader.py index 4b29ba6a628..84724d3b72f 100644 --- a/python/mozbuild/mozbuild/frontend/gyp_reader.py +++ b/python/mozbuild/mozbuild/frontend/gyp_reader.py @@ -221,10 +221,10 @@ def read_from_gyp(config, path, output, vars, non_unified_sources = set()): # Add some features to all contexts. Put here in case LOCAL_INCLUDES # order matters. context['LOCAL_INCLUDES'] += [ + '!/ipc/ipdl/_ipdlheaders', '/ipc/chromium/src', '/ipc/glue', ] - context['GENERATED_INCLUDES'] += ['/ipc/ipdl/_ipdlheaders'] # These get set via VC project file settings for normal GYP builds. if config.substs['OS_TARGET'] == 'WINNT': context['DEFINES']['UNICODE'] = True diff --git a/python/mozbuild/mozbuild/test/backend/data/generated_includes/moz.build b/python/mozbuild/mozbuild/test/backend/data/generated_includes/moz.build index b4c71617b90..876a842eeb3 100644 --- a/python/mozbuild/mozbuild/test/backend/data/generated_includes/moz.build +++ b/python/mozbuild/mozbuild/test/backend/data/generated_includes/moz.build @@ -2,4 +2,4 @@ # Any copyright is dedicated to the Public Domain. # http://creativecommons.org/publicdomain/zero/1.0/ -GENERATED_INCLUDES += ['/bar/baz', 'foo'] +LOCAL_INCLUDES += ['!/bar/baz', '!foo'] diff --git a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py index 56ca2ac48bc..ff6767e49f0 100644 --- a/python/mozbuild/mozbuild/test/backend/test_recursivemake.py +++ b/python/mozbuild/mozbuild/test/backend/test_recursivemake.py @@ -610,7 +610,7 @@ class TestRecursiveMakeBackend(BackendTester): lines = [l.strip() for l in open(backend_path, 'rt').readlines()[2:]] expected = [ - 'LOCAL_INCLUDES += -I$(topsrcdir)/bar/baz', + 'LOCAL_INCLUDES += -I$(srcdir)/bar/baz', 'LOCAL_INCLUDES += -I$(srcdir)/foo', ] @@ -627,7 +627,7 @@ class TestRecursiveMakeBackend(BackendTester): topobjdir = env.topobjdir.replace('\\', '/') expected = [ - 'LOCAL_INCLUDES += -I%s/bar/baz' % topobjdir, + 'LOCAL_INCLUDES += -Ibar/baz', 'LOCAL_INCLUDES += -Ifoo', ] diff --git a/python/mozbuild/mozbuild/test/frontend/data/generated_includes/moz.build b/python/mozbuild/mozbuild/test/frontend/data/generated_includes/moz.build index b4c71617b90..876a842eeb3 100644 --- a/python/mozbuild/mozbuild/test/frontend/data/generated_includes/moz.build +++ b/python/mozbuild/mozbuild/test/frontend/data/generated_includes/moz.build @@ -2,4 +2,4 @@ # Any copyright is dedicated to the Public Domain. # http://creativecommons.org/publicdomain/zero/1.0/ -GENERATED_INCLUDES += ['/bar/baz', 'foo'] +LOCAL_INCLUDES += ['!/bar/baz', '!foo'] diff --git a/python/mozbuild/mozbuild/test/frontend/test_emitter.py b/python/mozbuild/mozbuild/test/frontend/test_emitter.py index e46191ad63b..4cd0fd14947 100644 --- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py +++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py @@ -18,7 +18,6 @@ from mozbuild.frontend.data import ( DirectoryTraversal, Exports, GeneratedFile, - GeneratedInclude, GeneratedSources, HostDefines, HostSources, @@ -647,15 +646,33 @@ class TestEmitterBasic(unittest.TestCase): self.assertEqual(local_includes, expected) + local_includes = [o.path.full_path + for o in objs if isinstance(o, LocalInclude)] + expected = [ + mozpath.join(reader.config.topsrcdir, 'bar/baz'), + mozpath.join(reader.config.topsrcdir, 'foo'), + ] + + self.assertEqual(local_includes, expected) + def test_generated_includes(self): """Test that GENERATED_INCLUDES is emitted correctly.""" reader = self.reader('generated_includes') objs = self.read_topsrcdir(reader) - generated_includes = [o.path for o in objs if isinstance(o, GeneratedInclude)] + generated_includes = [o.path for o in objs if isinstance(o, LocalInclude)] expected = [ - '/bar/baz', - 'foo', + '!/bar/baz', + '!foo', + ] + + self.assertEqual(generated_includes, expected) + + generated_includes = [o.path.full_path + for o in objs if isinstance(o, LocalInclude)] + expected = [ + mozpath.join(reader.config.topobjdir, 'bar/baz'), + mozpath.join(reader.config.topobjdir, 'foo'), ] self.assertEqual(generated_includes, expected) diff --git a/security/manager/pki/moz.build b/security/manager/pki/moz.build index a29e6ca6785..826c7b4dbbb 100644 --- a/security/manager/pki/moz.build +++ b/security/manager/pki/moz.build @@ -19,8 +19,8 @@ UNIFIED_SOURCES += [ 'nsPKIModule.cpp', ] -GENERATED_INCLUDES += [ - '/dist/public/nss', +LOCAL_INCLUDES += [ + '!/dist/public/nss', ] FINAL_LIBRARY = 'xul' diff --git a/security/manager/ssl/moz.build b/security/manager/ssl/moz.build index 59a47bca666..66639347aed 100644 --- a/security/manager/ssl/moz.build +++ b/security/manager/ssl/moz.build @@ -161,8 +161,8 @@ LOCAL_INCLUDES += [ '/security/pkix/include', ] -GENERATED_INCLUDES += [ - '/dist/public/nss', +LOCAL_INCLUDES += [ + '!/dist/public/nss', ] if CONFIG['NSS_DISABLE_DBM']: diff --git a/settings.gradle b/settings.gradle index f37309b0589..db0e215ef37 100644 --- a/settings.gradle +++ b/settings.gradle @@ -21,14 +21,32 @@ if (json.substs.MOZ_BUILD_APP != 'mobile/android') { throw new GradleException("Building with Gradle is only supported for Fennec, i.e., MOZ_BUILD_APP == 'mobile/android'."); } +def srcdir = { dst, src -> + def d = java.nio.file.Paths.get("${json.topobjdir}/gradle/${dst}") + def s = java.nio.file.Paths.get("${json.topsrcdir}/${src}") + try { + java.nio.file.Files.createDirectories(d.getParent()) + } catch (java.nio.file.FileAlreadyExistsException e) { + // Do nothing. + } + try { + java.nio.file.Files.createSymbolicLink(d, s) + } catch (java.nio.file.FileAlreadyExistsException e) { + // Do nothing. + } +} + +// Since base/ doesn't have the correct package prefix directory structure, we +// still need to symlink. +srcdir('base/src/org/mozilla/gecko', 'mobile/android/base') + include ':app' include ':base' include ':omnijar' include ':thirdparty' -def gradleRoot = new File("${json.topobjdir}/mobile/android/gradle") project(':app').projectDir = new File("${json.topsrcdir}/mobile/android/app") -project(':base').projectDir = new File(gradleRoot, 'base') +project(':base').projectDir = new File("${json.topsrcdir}/mobile/android/base") project(':omnijar').projectDir = new File("${json.topsrcdir}/mobile/android/app/omnijar") project(':thirdparty').projectDir = new File("${json.topsrcdir}/mobile/android/thirdparty") diff --git a/testing/specialpowers/content/specialpowersAPI.js b/testing/specialpowers/content/specialpowersAPI.js index 5347acc57bd..7916a30b020 100644 --- a/testing/specialpowers/content/specialpowersAPI.js +++ b/testing/specialpowers/content/specialpowersAPI.js @@ -1447,14 +1447,6 @@ SpecialPowersAPI.prototype = { Services.console.reset(); }, - getMaxLineBoxWidth: function(window) { - return this._getMUDV(window).maxLineBoxWidth; - }, - - setMaxLineBoxWidth: function(window, width) { - this._getMUDV(window).changeMaxLineBoxWidth(width); - }, - getFullZoom: function(window) { return this._getMUDV(window).fullZoom; }, diff --git a/testing/talos/talos/output.py b/testing/talos/talos/output.py index cd3316a61ba..adca9b426c2 100755 --- a/testing/talos/talos/output.py +++ b/testing/talos/talos/output.py @@ -517,15 +517,23 @@ class PerfherderOutput(Output): test.test_config['filters']) vals.extend([[i['value'], j] for i, j in filtered_results]) for val, page in filtered_results: + measurement_metadata = {} + if test.test_config.get('lower_is_better') is not None: + measurement_metadata['lowerIsBetter'] = test.test_config['lower_is_better'] + if test.test_config.get('unit'): + measurement_metadata['unit'] = test.test_config['unit'] if page == 'NULL': summary['subtests'][test.name()] = val + summary['subtests'][test.name()].update(measurement_metadata) else: summary['subtests'][page] = val - + summary['subtests'][page].update(measurement_metadata) suite_summary = self.construct_results(vals, testname=test.name()) summary['suite'] = suite_summary + if test.test_config.get('lower_is_better') is not None: + summary['lowerIsBetter'] = test.test_config['lower_is_better'] test_result['summary'] = summary for result, values in results.items(): diff --git a/testing/talos/talos/test.py b/testing/talos/talos/test.py index fc41eac75c7..039622ba8cd 100644 --- a/testing/talos/talos/test.py +++ b/testing/talos/talos/test.py @@ -30,6 +30,7 @@ class Test(object): keys = [] desktop = True filters = filter.ignore_first.prepare(1) + filter.median.prepare() + lower_is_better = True @classmethod def name(cls): @@ -137,6 +138,7 @@ class ts_paint(TsBase): rss = False mainthread = False responsiveness = False + unit = 'ms' @register_test() @@ -159,6 +161,7 @@ class sessionrestore(TsBase): reinstall = ['sessionstore.js', 'sessionCheckpoints.json'] # Restore the session preferences = {'browser.startup.page': 3} + unit = 'ms' @register_test() @@ -189,6 +192,7 @@ class tpaint(TsBase): sps_profile_entries = 2000000 tpmozafterpaint = True filters = filter.ignore_first.prepare(5) + filter.median.prepare() + unit = 'ms' @register_test() @@ -204,6 +208,7 @@ class tresize(TsBase): sps_profile_entries = 1000000 tpmozafterpaint = True filters = filter.ignore_first.prepare(5) + filter.median.prepare() + unit = 'ms' # Media Test @@ -240,7 +245,8 @@ class PageloaderTest(Test): 'timeout', 'shutdown', 'responsiveness', 'profile_path', 'xperf_providers', 'xperf_user_providers', 'xperf_stackwalk', 'filters', 'preferences', 'extensions', 'setup', 'cleanup', - 'test_name_extension'] + 'test_name_extension', 'lower_is_better', 'unit'] + unit = 'ms' @register_test() @@ -386,6 +392,7 @@ class glterrain(PageloaderTest): 'docshell.event_starvation_delay_hint': 1, 'dom.send_after_paint_to_content': False} filters = filter.ignore_first.prepare(1) + filter.median.prepare() + unit = 'frame interval' @register_test() @@ -475,6 +482,7 @@ class tp5o_scroll(PageloaderTest): 'docshell.event_starvation_delay_hint': 1, 'dom.send_after_paint_to_content': False} filters = filter.ignore_first.prepare(1) + filter.median.prepare() + unit = '1/FPS' @register_test() @@ -494,6 +502,8 @@ class v8_7(PageloaderTest): tpmozafterpaint = False preferences = {'dom.send_after_paint_to_content': False} filters = filter.v8_subtest.prepare() + unit = 'score' + lower_is_better = False @register_test() @@ -527,11 +537,14 @@ class tcanvasmark(PageloaderTest): tpmozafterpaint = False preferences = {'dom.send_after_paint_to_content': False} filters = filter.ignore_first.prepare(1) + filter.median.prepare() + unit = 'score' + lower_is_better = False class dromaeo(PageloaderTest): """abstract base class for dramaeo tests""" filters = filter.dromaeo.prepare() + lower_is_better = False @register_test() diff --git a/toolkit/components/extensions/Extension.jsm b/toolkit/components/extensions/Extension.jsm index 4e3d75be089..4df110cba30 100644 --- a/toolkit/components/extensions/Extension.jsm +++ b/toolkit/components/extensions/Extension.jsm @@ -4,7 +4,7 @@ "use strict"; -this.EXPORTED_SYMBOLS = ["Extension"]; +this.EXPORTED_SYMBOLS = ["Extension", "ExtensionData"]; /* * This file is the main entry point for extensions. When an extension @@ -33,8 +33,12 @@ XPCOMUtils.defineLazyModuleGetter(this, "NetUtil", "resource://gre/modules/NetUtil.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "OS", + "resource://gre/modules/osfile.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "Task", + "resource://gre/modules/Task.jsm"); Cu.import("resource://gre/modules/ExtensionManagement.jsm"); @@ -58,6 +62,7 @@ var { MessageBroker, Messenger, injectAPI, + extend, flushJarCache, } = ExtensionUtils; @@ -322,13 +327,335 @@ var GlobalManager = { }, }; +// Represents the data contained in an extension, contained either +// in a directory or a zip file, which may or may not be installed. +// This class implements the functionality of the Extension class, +// primarily related to manifest parsing and localization, which is +// useful prior to extension installation or initialization. +// +// No functionality of this class is guaranteed to work before +// |readManifest| has been called, and completed. +this.ExtensionData = function(rootURI) +{ + this.rootURI = rootURI; + + this.manifest = null; + this.id = null; + // Map(locale-name -> message-map) + // Contains a key for each loaded locale, each of which is a + // JSON-compatible object with a property for each message + // in that locale. + this.localeMessages = new Map(); + this.selectedLocale = null; + this._promiseLocales = null; + + this.errors = []; +} + +ExtensionData.prototype = { + get logger() { + let id = this.id || ""; + return Log.repository.getLogger(LOGGER_ID_BASE + id); + }, + + // Report an error about the extension's manifest file. + manifestError(message) { + this.packagingError(`Reading manifest: ${message}`); + }, + + // Report an error about the extension's general packaging. + packagingError(message) { + this.errors.push(message); + this.logger.error(`Loading extension '${this.id}': ${message}`); + }, + + // https://developer.chrome.com/extensions/i18n + localizeMessage(message, substitutions, locale = this.selectedLocale) { + let messages = {}; + if (this.localeMessages.has(locale)) { + messages = this.localeMessages.get(locale); + } + + if (message in messages) { + let str = messages[message].message; + + if (!substitutions) { + substitutions = []; + } else if (!Array.isArray(substitutions)) { + substitutions = [substitutions]; + } + + // https://developer.chrome.com/extensions/i18n-messages + // |str| may contain substrings of the form $1 or $PLACEHOLDER$. + // In the former case, we replace $n with substitutions[n - 1]. + // In the latter case, we consult the placeholders array. + // The placeholder may itself use $n to refer to substitutions. + let replacer = (matched, name) => { + if (name.length == 1 && name[0] >= '1' && name[0] <= '9') { + return substitutions[parseInt(name) - 1]; + } else { + let content = messages[message].placeholders[name].content; + if (content[0] == '$') { + return replacer(matched, content[1]); + } else { + return content; + } + } + }; + return str.replace(/\$([A-Za-z_@]+)\$/, replacer) + .replace(/\$([0-9]+)/, replacer) + .replace(/\$\$/, "$"); + } + + // Check for certain pre-defined messages. + if (message == "@@extension_id") { + if ("uuid" in this) { + // Per Chrome, this isn't available before an ID is guaranteed + // to have been assigned, namely, in manifest files. + // This should only be present in instances of the |Extension| + // subclass. + return this.uuid; + } + } else if (message == "@@ui_locale") { + return Locale.getLocale(); + } else if (message == "@@bidi_dir") { + return "ltr"; // FIXME + } + + Cu.reportError(`Unknown localization message ${message}`); + return "??"; + }, + + // Localize a string, replacing all |__MSG_(.*)__| tokens with the + // matching string from the current locale, as determined by + // |this.selectedLocale|. + // + // This may not be called before calling either |initLocale| or + // |initAllLocales|. + localize(str, locale = this.selectedLocale) { + if (!str) { + return str; + } + + return str.replace(/__MSG_([A-Za-z0-9@_]+?)__/g, (matched, message) => { + return this.localizeMessage(message, [], locale); + }); + }, + + // If a "default_locale" is specified in that manifest, returns it + // as a Gecko-compatible locale string. Otherwise, returns null. + get defaultLocale() { + if ("default_locale" in this.manifest) { + return this.normalizeLocaleCode(this.manifest.default_locale); + } + + return null; + }, + + // Normalizes a Chrome-compatible locale code to the appropriate + // Gecko-compatible variant. Currently, this means simply + // replacing underscores with hyphens. + normalizeLocaleCode(locale) { + return String.replace(locale, /_/g, "-"); + }, + + readDirectory: Task.async(function* (path) { + if (this.rootURI instanceof Ci.nsIFileURL) { + let uri = NetUtil.newURI(this.rootURI.resolve("./" + path)); + let fullPath = uri.QueryInterface(Ci.nsIFileURL).file.path; + + let iter = new OS.File.DirectoryIterator(fullPath); + let results = []; + + try { + yield iter.forEach(entry => { + results.push(entry); + }); + } catch (e) {} + iter.close(); + + // Always return a list, even if the directory does not exist (or is + // not a directory) for symmetry with the ZipReader behavior. + return results; + } + + if (!(this.rootURI instanceof Ci.nsIJARURI && + this.rootURI.JARFile instanceof Ci.nsIFileURL)) { + throw Error("Invalid extension root URL"); + } + + // FIXME: We need a way to do this without main thread IO. + + let file = this.rootURI.JARFile.file; + let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(Ci.nsIZipReader); + try { + zipReader.open(file); + + let results = []; + + // Normalize the directory path. + path = path.replace(/\/\/+/g, "/").replace(/^\/|\/$/g, "") + "/"; + + // Escape pattern metacharacters. + let pattern = path.replace(/[[\]()?*~|$\\]/g, "\\$&"); + + let enumerator = zipReader.findEntries(pattern + "*"); + while (enumerator.hasMore()) { + let name = enumerator.getNext(); + if (!name.startsWith(path)) { + throw new Error("Unexpected ZipReader entry"); + } + + // The enumerator returns the full path of all entries. + // Trim off the leading path, and filter out entries from + // subdirectories. + name = name.slice(path.length); + if (name && !/\/./.test(name)) { + results.push({ + name: name.replace("/", ""), + isDir: name.endsWith("/"), + }); + } + } + + return results; + } finally { + zipReader.close(); + } + }), + + readJSON(path) { + return new Promise((resolve, reject) => { + let uri = this.rootURI.resolve(`./${path}`); + + NetUtil.asyncFetch({uri, loadUsingSystemPrincipal: true}, (inputStream, status) => { + if (!Components.isSuccessCode(status)) { + reject(new Error(status)); + return; + } + try { + let text = NetUtil.readInputStreamToString(inputStream, inputStream.available()); + resolve(JSON.parse(text)); + } catch (e) { + reject(e); + } + }); + }); + }, + + // Reads the extension's |manifest.json| file, and stores its + // parsed contents in |this.manifest|. + readManifest() { + return this.readJSON("manifest.json").then(manifest => { + this.manifest = manifest; + + try { + this.id = this.manifest.applications.gecko.id; + } catch (e) {} + + if (typeof this.id != "string") { + this.manifestError("Missing required `applications.gecko.id` property"); + } + + return manifest; + }); + }, + + // Reads the locale file for the given Gecko-compatible locale code, and + // stores its parsed contents in |this.localeMessages.get(locale)|. + readLocaleFile: Task.async(function* (locale) { + let locales = yield this.promiseLocales(); + let dir = locales.get(locale); + let file = `_locales/${dir}/messages.json`; + + let messages = {}; + try { + messages = yield this.readJSON(file); + } catch (e) { + this.packagingError(`Loading locale file ${file}: ${e}`); + } + + this.localeMessages.set(locale, messages); + return messages; + }), + + // Reads the list of locales available in the extension, and returns a + // Promise which resolves to a Map upon completion. + // Each map key is a Gecko-compatible locale code, and each value is the + // "_locales" subdirectory containing that locale: + // + // Map(gecko-locale-code -> locale-directory-name) + promiseLocales() { + if (!this._promiseLocales) { + this._promiseLocales = Task.spawn(function* () { + let locales = new Map(); + + let entries = yield this.readDirectory("_locales"); + for (let file of entries) { + if (file.isDir) { + let locale = this.normalizeLocaleCode(file.name); + locales.set(locale, file.name); + } + } + + return locales; + }.bind(this)); + } + + return this._promiseLocales; + }, + + // Reads the locale messages for all locales, and returns a promise which + // resolves to a Map of locale messages upon completion. Each key in the map + // is a Gecko-compatible locale code, and each value is a locale data object + // as returned by |readLocaleFile|. + initAllLocales: Task.async(function* () { + let locales = yield this.promiseLocales(); + + yield Promise.all(Array.from(locales.keys(), + locale => this.readLocaleFile(locale))); + + let defaultLocale = this.defaultLocale; + if (defaultLocale) { + if (!locales.has(defaultLocale)) { + this.manifestError('Value for "default_locale" property must correspond to ' + + 'a directory in "_locales/". Not found: ' + + JSON.stringify(`_locales/${default_locale}/`)); + } + } else if (this.localeMessages.size) { + this.manifestError('The "default_locale" property is required when a ' + + '"_locales/" directory is present.'); + } + + return this.localeMessages; + }), + + // Reads the locale file for the given Gecko-compatible locale code, or the + // default locale if no locale code is given, and sets it as the currently + // selected locale on success. + // + // If no locales are unavailable, resolves to |null|. + initLocale: Task.async(function* (locale = this.defaultLocale) { + if (locale == null) { + return null; + } + + let localeData = yield this.readLocaleFile(locale); + + this.selectedLocale = locale; + return localeData; + }), +}; + // We create one instance of this class per extension. |addonData| // comes directly from bootstrap.js when initializing. this.Extension = function(addonData) { + ExtensionData.call(this, addonData.resourceURI); + let uuidGenerator = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator); let uuid = uuidGenerator.generateUUID().number; - uuid = uuid.substring(1, uuid.length - 1); // Strip of { and } off the UUID. + uuid = uuid.slice(1, -1); // Strip of { and } off the UUID. this.uuid = uuid; if (addonData.cleanupFile) { @@ -341,9 +668,6 @@ this.Extension = function(addonData) this.id = addonData.id; this.baseURI = Services.io.newURI("moz-extension://" + uuid, null, null); this.baseURI.QueryInterface(Ci.nsIURL); - this.manifest = null; - this.localeMessages = null; - this.logger = Log.repository.getLogger(LOGGER_ID_BASE + this.id.replace(/\./g, "-")); this.principal = this.createPrincipal(); this.views = new Set(); @@ -475,7 +799,7 @@ this.Extension.generate = function(id, data) }); } -Extension.prototype = { +Extension.prototype = extend(Object.create(ExtensionData.prototype), { on(hook, f) { return this.emitter.on(hook, f); }, @@ -505,11 +829,6 @@ Extension.prototype = { return common == this.baseURI.spec; }, - // Report an error about the extension's manifest file. - manifestError(message) { - this.logger.error(`Loading extension '${this.id}': ${message}`); - }, - // Representation of the extension to send to content // processes. This should include anything the content process might // need. @@ -526,147 +845,6 @@ Extension.prototype = { }; }, - // https://developer.chrome.com/extensions/i18n - localizeMessage(message, substitutions) { - if (message in this.localeMessages) { - let str = this.localeMessages[message].message; - - if (!substitutions) { - substitutions = []; - } - if (!Array.isArray(substitutions)) { - substitutions = [substitutions]; - } - - // https://developer.chrome.com/extensions/i18n-messages - // |str| may contain substrings of the form $1 or $PLACEHOLDER$. - // In the former case, we replace $n with substitutions[n - 1]. - // In the latter case, we consult the placeholders array. - // The placeholder may itself use $n to refer to substitutions. - let replacer = (matched, name) => { - if (name.length == 1 && name[0] >= '1' && name[0] <= '9') { - return substitutions[parseInt(name) - 1]; - } else { - let content = this.localeMessages[message].placeholders[name].content; - if (content[0] == '$') { - return replacer(matched, content[1]); - } else { - return content; - } - } - }; - return str.replace(/\$([A-Za-z_@]+)\$/, replacer) - .replace(/\$([0-9]+)/, replacer) - .replace(/\$\$/, "$"); - } - - // Check for certain pre-defined messages. - if (message == "@@extension_id") { - return this.id; - } else if (message == "@@ui_locale") { - return Locale.getLocale(); - } else if (message == "@@bidi_dir") { - return "ltr"; // FIXME - } - - Cu.reportError(`Unknown localization message ${message}`); - return "??"; - }, - - localize(str) { - if (!str) { - return str; - } - - if (str.startsWith("__MSG_") && str.endsWith("__")) { - let message = str.substring("__MSG_".length, str.length - "__".length); - return this.localizeMessage(message); - } - - return str; - }, - - readJSON(uri) { - return new Promise((resolve, reject) => { - NetUtil.asyncFetch({uri, loadUsingSystemPrincipal: true}, (inputStream, status) => { - if (!Components.isSuccessCode(status)) { - reject(status); - return; - } - let text = NetUtil.readInputStreamToString(inputStream, inputStream.available()); - try { - resolve(JSON.parse(text)); - } catch (e) { - reject(e); - } - }); - }); - }, - - readManifest() { - let manifestURI = Services.io.newURI("manifest.json", null, this.baseURI); - return this.readJSON(manifestURI); - }, - - readLocaleFile(locale) { - let dir = locale.replace("-", "_"); - let url = `_locales/${dir}/messages.json`; - let uri = Services.io.newURI(url, null, this.baseURI); - return this.readJSON(uri); - }, - - readLocaleMessages() { - let locales = []; - - // We need to base this off of this.addonData.resourceURI rather - // than baseURI since baseURI is a moz-extension URI, which always - // QIs to nsIFileURL. - let uri = Services.io.newURI("_locales", null, this.addonData.resourceURI); - if (uri instanceof Ci.nsIFileURL) { - let file = uri.file; - let enumerator; - try { - enumerator = file.directoryEntries; - } catch (e) { - return {}; - } - while (enumerator.hasMoreElements()) { - let file = enumerator.getNext().QueryInterface(Ci.nsIFile); - locales.push({ - name: file.leafName, - locales: [file.leafName.replace("_", "-")] - }); - } - } - - if (uri instanceof Ci.nsIJARURI && uri.JARFile instanceof Ci.nsIFileURL) { - let file = uri.JARFile.file; - let zipReader = Cc["@mozilla.org/libjar/zip-reader;1"].createInstance(Ci.nsIZipReader); - try { - zipReader.open(file); - let enumerator = zipReader.findEntries("_locales/*"); - while (enumerator.hasMore()) { - let name = enumerator.getNext(); - let match = name.match(new RegExp("_locales\/([^/]*)")); - if (match && match[1]) { - locales.push({ - name: match[1], - locales: [match[1].replace("_", "-")] - }); - } - } - } finally { - zipReader.close(); - } - } - - let locale = Locale.findClosestLocale(locales); - if (locale) { - return this.readLocaleFile(locale.name).catch(() => {}); - } - return {}; - }, - broadcast(msg, data) { return new Promise(resolve => { let count = Services.ppmm.childCount; @@ -723,6 +901,24 @@ Extension.prototype = { this.onShutdown.delete(obj); }, + // Reads the locale file for the given Gecko-compatible locale code, or if + // no locale is given, the available locale closest to the UI locale. + // Sets the currently selected locale on success. + initLocale: Task.async(function* (locale = undefined) { + if (locale === undefined) { + let locales = yield this.promiseLocales(); + + let localeList = Object.keys(locales).map(locale => { + return { name: locale, locales: [locale] }; + }); + + let match = Locale.findClosestLocale(localeList); + locale = match ? match.name : this.defaultLocale; + } + + return ExtensionData.prototype.initLocale.call(this, locale); + }), + startup() { try { ExtensionManagement.startupExtension(this.uuid, this.addonData.resourceURI, this); @@ -730,21 +926,20 @@ Extension.prototype = { return Promise.reject(e); } - return Promise.all([this.readManifest(), this.readLocaleMessages()]).then(([manifest, messages]) => { + return this.readManifest().then(() => { + return this.initLocale(); + }).then(() => { if (this.hasShutdown) { return; } GlobalManager.init(this); - this.manifest = manifest; - this.localeMessages = messages; - Management.emit("startup", this); - return this.runManifest(manifest); + return this.runManifest(this.manifest); }).catch(e => { - dump(`Extension error: ${e} ${e.fileName}:${e.lineNumber}\n`); + dump(`Extension error: ${e} ${e.filename}:${e.lineNumber}\n`); Cu.reportError(e); throw e; }); @@ -808,5 +1003,5 @@ Extension.prototype = { get name() { return this.localize(this.manifest.name); }, -}; +}); diff --git a/toolkit/components/extensions/ExtensionUtils.jsm b/toolkit/components/extensions/ExtensionUtils.jsm index c1cb5562f19..c7b7b90bcc2 100644 --- a/toolkit/components/extensions/ExtensionUtils.jsm +++ b/toolkit/components/extensions/ExtensionUtils.jsm @@ -64,6 +64,21 @@ function runSafe(context, f, ...args) return runSafeWithoutClone(f, ...args); } +// Extend the object |obj| with the property descriptors of each object in +// |args|. +function extend(obj, ...args) { + for (let arg of args) { + let props = [...Object.getOwnPropertyNames(arg), + ...Object.getOwnPropertySymbols(arg)]; + for (let prop of props) { + let descriptor = Object.getOwnPropertyDescriptor(arg, prop); + Object.defineProperty(obj, prop, descriptor); + } + } + + return obj; +} + // Similar to a WeakMap, but returns a particular default value for // |get| if a key is not present. function DefaultWeakMap(defaultValue) @@ -602,5 +617,6 @@ this.ExtensionUtils = { injectAPI, MessageBroker, Messenger, + extend, flushJarCache, }; diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 54a000329af..f98e94b2e0c 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -9093,6 +9093,7 @@ }, "READER_MODE_SERIALIZE_DOM_MS": { "expires_in_version": "50", + "alert_emails": ["mleibovic@mozilla.com"], "kind": "exponential", "high": "5000", "n_buckets": 15, @@ -9100,6 +9101,7 @@ }, "READER_MODE_WORKER_PARSE_MS": { "expires_in_version": "50", + "alert_emails": ["mleibovic@mozilla.com"], "kind": "exponential", "high": "10000", "n_buckets": 30, @@ -9107,6 +9109,7 @@ }, "READER_MODE_DOWNLOAD_MS": { "expires_in_version": "50", + "alert_emails": ["mleibovic@mozilla.com"], "kind": "exponential", "low": 50, "high": "40000", @@ -9115,16 +9118,25 @@ }, "READER_MODE_PARSE_RESULT" : { "expires_in_version": "50", + "alert_emails": ["mleibovic@mozilla.com"], "kind": "enumerated", "n_values": 5, "description": "The result of trying to parse a document to show in reader view (0=Success, 1=Error too many elements, 2=Error in worker, 3=Error no article)" }, "READER_MODE_DOWNLOAD_RESULT" : { "expires_in_version": "50", + "alert_emails": ["mleibovic@mozilla.com"], "kind": "enumerated", "n_values": 5, "description": "The result of trying to download a document to show in reader view (0=Success, 1=Error XHR, 2=Error no document)" }, + "FENNEC_READER_VIEW_BUTTON" : { + "expires_in_version": "50", + "alert_emails": ["mleibovic@mozilla.com"], + "kind": "enumerated", + "n_values": 10, + "description": "Bug 1219240: Measures user interaction with the reader view button (0=Button hidden, 1=Button shown, 2=Tap to enter reader view, 3=Tap to exit reader view, 4=Long tap)" + }, "PERMISSIONS_SQL_CORRUPTED": { "expires_in_version": "never", "kind": "count", diff --git a/toolkit/content/license.html b/toolkit/content/license.html index f2aebac3f99..d4bfec7c5c9 100644 --- a/toolkit/content/license.html +++ b/toolkit/content/license.html @@ -81,6 +81,7 @@
  • bspatch License
  • Cairo Component Licenses
  • Chromium License
  • +
  • classnames License
  • CodeMirror License
  • cubic-bezier License
  • D3 License
  • @@ -2718,6 +2719,36 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +
    + +

    classnames License

    + +

    This license applies to the file + browser/components/loop/content/shared/libs/classnames-*.js. +

    + +
    +Copyright (c) 2015 Jed Watson
    +
    +Permission is hereby granted, free of charge, to any person obtaining a copy
    +of this software and associated documentation files (the "Software"), to deal
    +in the Software without restriction, including without limitation the rights
    +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    +copies of the Software, and to permit persons to whom the Software is
    +furnished to do so, subject to the following conditions:
    +
    +The above copyright notice and this permission notice shall be included in all
    +copies or substantial portions of the Software.
    +
    +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    +SOFTWARE.
    +
    +

    CodeMirror License

    diff --git a/toolkit/mozapps/extensions/internal/XPIProvider.jsm b/toolkit/mozapps/extensions/internal/XPIProvider.jsm index eb978d7ab70..61316b83741 100644 --- a/toolkit/mozapps/extensions/internal/XPIProvider.jsm +++ b/toolkit/mozapps/extensions/internal/XPIProvider.jsm @@ -22,6 +22,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "ChromeManifestParser", "resource://gre/modules/ChromeManifestParser.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager", "resource://gre/modules/LightweightThemeManager.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ExtensionData", + "resource://gre/modules/Extension.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "Locale", "resource://gre/modules/Locale.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", @@ -828,15 +830,20 @@ function getRDFProperty(aDs, aResource, aProperty) { /** * Reads an AddonInternal object from a manifest stream. * - * @param aStream - * An open stream to read the manifest from + * @param aUri + * A |file:| or |jar:| URL for the manifest * @return an AddonInternal object * @throws if the install manifest in the stream is corrupt or could not * be read */ -function loadManifestFromWebManifest(aStream) { - let decoder = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON); - let manifest = decoder.decodeFromStream(aStream, aStream.available()); +var loadManifestFromWebManifest = Task.async(function* loadManifestFromWebManifest(aUri) { + // We're passed the URI for the manifest file. Get the URI for its + // parent directory. + let uri = NetUtil.newURI("./", null, aUri); + + let extension = new ExtensionData(uri); + + let manifest = yield extension.readManifest(); function findProp(obj, current, properties) { if (properties.length == 0) @@ -903,30 +910,46 @@ function loadManifestFromWebManifest(aStream) { addon.applyBackgroundUpdates = AddonManager.AUTOUPDATE_DEFAULT; - addon.defaultLocale = { - name: getProp("name"), - description: getOptionalProp("description"), - creator: null, - homepageURL: null, + function getLocale(aLocale) { + let result = { + name: extension.localize(getProp("name"), aLocale), + description: extension.localize(getOptionalProp("description"), aLocale), + creator: null, + homepageURL: null, - developers: null, - translators: null, - contributors: null, + developers: null, + translators: null, + contributors: null, + locales: [aLocale], + }; + return result; } + // Read the list of available locales, and pre-load messages for + // all locales. + let locales = yield extension.initAllLocales(); + + // If there were any errors loading the extension, bail out now. + if (extension.errors.length) + throw new Error("Extension is invalid"); + + addon.defaultLocale = getLocale(extension.defaultLocale); + addon.locales = Array.from(locales.keys(), getLocale); + + delete addon.defaultLocale.locales; + addon.targetApplications = [{ id: TOOLKIT_ID, minVersion: AddonManagerPrivate.webExtensionsMinPlatformVersion, maxVersion: "*", }]; - addon.locales = []; addon.targetPlatforms = []; addon.userDisabled = false; addon.softDisabled = addon.blocklistState == Blocklist.STATE_SOFTBLOCKED; return addon; -} +}); /** * Reads an AddonInternal object from an RDF stream. @@ -1251,8 +1274,19 @@ var loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir, aInstal return size; } - function loadFromRDF(aFile, aStream) { - let addon = loadManifestFromRDF(Services.io.newFileURI(aFile), aStream); + function loadFromRDF(aUri) { + let fis = Cc["@mozilla.org/network/file-input-stream;1"]. + createInstance(Ci.nsIFileInputStream); + fis.init(aUri.file, -1, -1, false); + let bis = Cc["@mozilla.org/network/buffered-input-stream;1"]. + createInstance(Ci.nsIBufferedInputStream); + bis.init(fis, 4096); + try { + var addon = loadManifestFromRDF(aUri, bis); + } finally { + bis.close(); + fis.close(); + } let iconFile = aDir.clone(); iconFile.append("icon.png"); @@ -1283,32 +1317,21 @@ var loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir, aInstal "install manifest"); } - let fis = Cc["@mozilla.org/network/file-input-stream;1"]. - createInstance(Ci.nsIFileInputStream); - fis.init(file, -1, -1, false); - let bis = Cc["@mozilla.org/network/buffered-input-stream;1"]. - createInstance(Ci.nsIBufferedInputStream); - bis.init(fis, 4096); + let uri = Services.io.newFileURI(file).QueryInterface(Ci.nsIFileURL); - try { - let addon = file.leafName == FILE_WEB_MANIFEST ? - loadManifestFromWebManifest(bis) : - loadFromRDF(file, bis); + let addon = file.leafName == FILE_WEB_MANIFEST ? + yield loadManifestFromWebManifest(uri) : + loadFromRDF(uri); - addon._sourceBundle = aDir.clone(); - addon._installLocation = aInstallLocation; - addon.size = getFileSize(aDir); - addon.signedState = yield verifyDirSignedState(aDir, addon); - addon.appDisabled = !isUsableAddon(addon); + addon._sourceBundle = aDir.clone(); + addon._installLocation = aInstallLocation; + addon.size = getFileSize(aDir); + addon.signedState = yield verifyDirSignedState(aDir, addon); + addon.appDisabled = !isUsableAddon(addon); - defineSyncGUID(addon); + defineSyncGUID(addon); - return addon; - } - finally { - bis.close(); - fis.close(); - } + return addon; }); /** @@ -1320,9 +1343,17 @@ var loadManifestFromDir = Task.async(function* loadManifestFromDir(aDir, aInstal * @throws if the XPI file does not contain a valid install manifest */ var loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(aZipReader, aInstallLocation) { - function loadFromRDF(aStream) { - let uri = buildJarURI(aZipReader.file, FILE_RDF_MANIFEST); - let addon = loadManifestFromRDF(uri, aStream); + function loadFromRDF(aUri) { + let zis = aZipReader.getInputStream(entry); + let bis = Cc["@mozilla.org/network/buffered-input-stream;1"]. + createInstance(Ci.nsIBufferedInputStream); + bis.init(zis, 4096); + try { + var addon = loadManifestFromRDF(aUri, bis); + } finally { + bis.close(); + zis.close(); + } if (aZipReader.hasEntry("icon.png")) { addon.icons[32] = "icon.png"; @@ -1335,7 +1366,7 @@ var loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(a // Binary components can only be loaded from unpacked addons. if (addon.unpack) { - uri = buildJarURI(aZipReader.file, "chrome.manifest"); + let uri = buildJarURI(aZipReader.file, "chrome.manifest"); let chromeManifest = ChromeManifestParser.parseSync(uri); addon.hasBinaryComponents = ChromeManifestParser.hasType(chromeManifest, "binary-component"); @@ -1352,35 +1383,26 @@ var loadManifestFromZipReader = Task.async(function* loadManifestFromZipReader(a "install manifest"); } - let zis = aZipReader.getInputStream(entry); - let bis = Cc["@mozilla.org/network/buffered-input-stream;1"]. - createInstance(Ci.nsIBufferedInputStream); - bis.init(zis, 4096); + let uri = buildJarURI(aZipReader.file, entry); - try { - let addon = entry == FILE_WEB_MANIFEST ? - loadManifestFromWebManifest(bis) : - loadFromRDF(bis); + let addon = entry == FILE_WEB_MANIFEST ? + yield loadManifestFromWebManifest(uri) : + loadFromRDF(uri); - addon._sourceBundle = aZipReader.file; - addon._installLocation = aInstallLocation; + addon._sourceBundle = aZipReader.file; + addon._installLocation = aInstallLocation; - addon.size = 0; - let entries = aZipReader.findEntries(null); - while (entries.hasMore()) - addon.size += aZipReader.getEntry(entries.getNext()).realSize; + addon.size = 0; + let entries = aZipReader.findEntries(null); + while (entries.hasMore()) + addon.size += aZipReader.getEntry(entries.getNext()).realSize; - addon.signedState = yield verifyZipSignedState(aZipReader.file, addon); - addon.appDisabled = !isUsableAddon(addon); + addon.signedState = yield verifyZipSignedState(aZipReader.file, addon); + addon.appDisabled = !isUsableAddon(addon); - defineSyncGUID(addon); + defineSyncGUID(addon); - return addon; - } - finally { - bis.close(); - zis.close(); - } + return addon; }); /** diff --git a/toolkit/mozapps/extensions/test/addons/webextension_3/_locales/en/messages.json b/toolkit/mozapps/extensions/test/addons/webextension_3/_locales/en/messages.json new file mode 100644 index 00000000000..91971760e77 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/webextension_3/_locales/en/messages.json @@ -0,0 +1,10 @@ +{ + "name": { + "message": "foo", + "description": "foo" + }, + "desc": { + "message": "bar", + "description": "bar" + } +} diff --git a/toolkit/mozapps/extensions/test/addons/webextension_3/_locales/fr/messages.json b/toolkit/mozapps/extensions/test/addons/webextension_3/_locales/fr/messages.json new file mode 100644 index 00000000000..daeac60bb94 --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/webextension_3/_locales/fr/messages.json @@ -0,0 +1,10 @@ +{ + "name": { + "message": "le foo", + "description": "foo" + }, + "desc": { + "message": "le bar", + "description": "bar" + } +} diff --git a/toolkit/mozapps/extensions/test/addons/webextension_3/manifest.json b/toolkit/mozapps/extensions/test/addons/webextension_3/manifest.json new file mode 100644 index 00000000000..d4ccddfea3a --- /dev/null +++ b/toolkit/mozapps/extensions/test/addons/webextension_3/manifest.json @@ -0,0 +1,12 @@ +{ + "name": "Web Extension __MSG_name__", + "description": "Descripton __MSG_desc__ of add-on", + "version": "1.0", + "manifest_version": 2, + "default_locale": "en", + "applications": { + "gecko": { + "id": "webextension3@tests.mozilla.org" + } + } +} diff --git a/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js b/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js index 0e3d50d4a82..671d033f2a9 100644 --- a/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js +++ b/toolkit/mozapps/extensions/test/xpcshell/test_webextension.js @@ -4,6 +4,8 @@ const ID = "webextension1@tests.mozilla.org"; +const PREF_SELECTED_LOCALE = "general.useragent.locale"; + const profileDir = gProfD.clone(); profileDir.append("extensions"); @@ -142,6 +144,33 @@ add_task(function*() { yield promiseRestartManager(); }); +add_task(function* test_manifest_localization() { + const ID = "webextension3@tests.mozilla.org"; + + yield promiseInstallAllFiles([do_get_addon("webextension_3")], true); + + let addon = yield promiseAddonByID(ID); + + equal(addon.name, "Web Extension foo"); + equal(addon.description, "Descripton bar of add-on"); + + Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "fr-FR"); + yield promiseRestartManager(); + + addon = yield promiseAddonByID(ID); + + equal(addon.name, "Web Extension le foo"); + equal(addon.description, "Descripton le bar of add-on"); + + Services.prefs.setCharPref(PREF_SELECTED_LOCALE, "de"); + yield promiseRestartManager(); + + addon = yield promiseAddonByID(ID); + + equal(addon.name, "Web Extension foo"); + equal(addon.description, "Descripton bar of add-on"); +}); + // Missing ID should cause a failure add_task(function*() { writeWebManifestForExtension({ diff --git a/webapprt/gtk/moz.build b/webapprt/gtk/moz.build index 61faeac5a8a..f9b7c40be5d 100644 --- a/webapprt/gtk/moz.build +++ b/webapprt/gtk/moz.build @@ -12,8 +12,8 @@ SOURCES += [ 'webapprt.cpp', ] -GENERATED_INCLUDES += ['/build'] LOCAL_INCLUDES += [ + '!/build', '/toolkit/xre', '/xpcom/base', '/xpcom/build', diff --git a/webapprt/mac/moz.build b/webapprt/mac/moz.build index f7ee46a0bfa..d638864ea12 100644 --- a/webapprt/mac/moz.build +++ b/webapprt/mac/moz.build @@ -15,8 +15,8 @@ SOURCES += [ DEFINES['XPCOM_GLUE'] = True -GENERATED_INCLUDES += ['/build'] LOCAL_INCLUDES += [ + '!/build', '/toolkit/xre', '/xpcom/base', '/xpcom/build', diff --git a/webapprt/win/moz.build b/webapprt/win/moz.build index 9c159253e53..fad25344c2b 100644 --- a/webapprt/win/moz.build +++ b/webapprt/win/moz.build @@ -20,8 +20,8 @@ DEFINES['APP_VERSION'] = CONFIG['FIREFOX_VERSION'] # Statically link against the CRT USE_STATIC_LIBS = True -GENERATED_INCLUDES += ['/build'] LOCAL_INCLUDES += [ + '!/build', '/toolkit/xre', '/xpcom/base', '/xpcom/build', diff --git a/widget/cocoa/TextInputHandler.mm b/widget/cocoa/TextInputHandler.mm index 420bcea67e8..bc846c26037 100644 --- a/widget/cocoa/TextInputHandler.mm +++ b/widget/cocoa/TextInputHandler.mm @@ -1936,8 +1936,8 @@ TextInputHandler::HandleFlagsChanged(NSEvent* aNativeEvent) timestamp:[aNativeEvent timestamp] windowNumber:[aNativeEvent windowNumber] context:[aNativeEvent context] - characters:nil - charactersIgnoringModifiers:nil + characters:@"" + charactersIgnoringModifiers:@"" isARepeat:NO keyCode:keyCode]; DispatchKeyEventForFlagsChanged(event, dispatchKeyDown); diff --git a/widget/cocoa/VibrancyManager.h b/widget/cocoa/VibrancyManager.h index bc3b6b3bb5c..3a6a8e93f9b 100644 --- a/widget/cocoa/VibrancyManager.h +++ b/widget/cocoa/VibrancyManager.h @@ -17,7 +17,6 @@ @class NSColor; @class NSView; class nsChildView; -class nsIntRegion; namespace mozilla { diff --git a/widget/cocoa/nsNativeThemeCocoa.mm b/widget/cocoa/nsNativeThemeCocoa.mm index 6b6565c2fae..32650cd300b 100644 --- a/widget/cocoa/nsNativeThemeCocoa.mm +++ b/widget/cocoa/nsNativeThemeCocoa.mm @@ -526,24 +526,24 @@ nsNativeThemeCocoa::nsNativeThemeCocoa() // before the main event-loop pool is in place nsAutoreleasePool pool; - mDisclosureButtonCell = [[NSButtonCell alloc] initTextCell:nil]; + mDisclosureButtonCell = [[NSButtonCell alloc] initTextCell:@""]; [mDisclosureButtonCell setBezelStyle:NSRoundedDisclosureBezelStyle]; [mDisclosureButtonCell setButtonType:NSPushOnPushOffButton]; [mDisclosureButtonCell setHighlightsBy:NSPushInCellMask]; - mHelpButtonCell = [[NSButtonCell alloc] initTextCell:nil]; + mHelpButtonCell = [[NSButtonCell alloc] initTextCell:@""]; [mHelpButtonCell setBezelStyle:NSHelpButtonBezelStyle]; [mHelpButtonCell setButtonType:NSMomentaryPushInButton]; [mHelpButtonCell setHighlightsBy:NSPushInCellMask]; - mPushButtonCell = [[NSButtonCell alloc] initTextCell:nil]; + mPushButtonCell = [[NSButtonCell alloc] initTextCell:@""]; [mPushButtonCell setButtonType:NSMomentaryPushInButton]; [mPushButtonCell setHighlightsBy:NSPushInCellMask]; - mRadioButtonCell = [[RadioButtonCell alloc] initTextCell:nil]; + mRadioButtonCell = [[RadioButtonCell alloc] initTextCell:@""]; [mRadioButtonCell setButtonType:NSRadioButton]; - mCheckboxCell = [[CheckboxCell alloc] initTextCell:nil]; + mCheckboxCell = [[CheckboxCell alloc] initTextCell:@""]; [mCheckboxCell setButtonType:NSSwitchButton]; [mCheckboxCell setAllowsMixedState:YES]; diff --git a/widget/gonk/libdisplay/moz.build b/widget/gonk/libdisplay/moz.build index 3cb1426eec2..25dbe859abc 100644 --- a/widget/gonk/libdisplay/moz.build +++ b/widget/gonk/libdisplay/moz.build @@ -52,12 +52,18 @@ DEFINES['XPCOM_GLUE'] = True DISABLE_STL_WRAPPING = True -CXXFLAGS += [ - '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ - 'frameworks/native/include/gui', - 'frameworks/native/opengl/include', +if CONFIG['ANDROID_VERSION'] > '15': + LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ + 'frameworks/native/include/gui', + 'frameworks/native/opengl/include', + 'system/core/libsuspend/include', + ] + ] + +LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ 'hardware/libhardware/include', 'hardware/libhardware_legacy/include', - 'system/core/libsuspend/include', ] ] diff --git a/widget/gonk/moz.build b/widget/gonk/moz.build index 69cd0467651..ae3bd58a4b0 100644 --- a/widget/gonk/moz.build +++ b/widget/gonk/moz.build @@ -96,10 +96,14 @@ if CONFIG['ANDROID_VERSION'] != '15': if CONFIG['MOZ_OMX_DECODER']: DEFINES['MOZ_OMX_DECODER'] = True -CXXFLAGS += [ - '-I%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ +if CONFIG['ANDROID_VERSION'] > '15': + LOCAL_INCLUDES += [ + '%' + '%s/frameworks/native/opengl/include' % CONFIG['ANDROID_SOURCE'], + ] + +LOCAL_INCLUDES += [ + '%' + '%s/%s' % (CONFIG['ANDROID_SOURCE'], d) for d in [ 'hardware/libhardware/include', 'hardware/libhardware_legacy/include', - 'frameworks/native/opengl/include', ] ] diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index f0b7dd2390a..1c3c156d8fb 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -11,6 +11,7 @@ #include "mozilla/MouseEvents.h" #include "mozilla/TextEvents.h" #include "mozilla/TouchEvents.h" +#include "mozilla/UniquePtrExtensions.h" #include #include "GeckoProfiler.h" @@ -2322,7 +2323,7 @@ nsWindow::UpdateAlpha(gfxPattern* aPattern, nsIntRect aBoundsRect) int32_t stride = GetAlignedStride<4>(BytesPerPixel(SurfaceFormat::A8) * aBoundsRect.width); int32_t bufferSize = stride * aBoundsRect.height; - UniquePtr imageBuffer(new (std::nothrow) uint8_t[bufferSize]); + auto imageBuffer = MakeUniqueFallible(bufferSize); RefPtr drawTarget = gfxPlatform::GetPlatform()-> CreateDrawTargetForData(imageBuffer.get(), aBoundsRect.Size(), stride, SurfaceFormat::A8); diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 23ce84804b2..bea27cbe4bf 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -17,6 +17,7 @@ #include "nsTArray.h" #include "nsITheme.h" #include "nsITimer.h" +#include "nsRegionFwd.h" #include "nsXULAppAPI.h" #include "mozilla/Maybe.h" #include "mozilla/EventForwards.h" @@ -36,7 +37,6 @@ class nsIRollupListener; class imgIContainer; class nsIContent; class ViewWrapper; -class nsIntRegion; class nsIScreen; class nsIRunnable; diff --git a/widget/nsIWidgetListener.h b/widget/nsIWidgetListener.h index 2be27145933..76b87073f06 100644 --- a/widget/nsIWidgetListener.h +++ b/widget/nsIWidgetListener.h @@ -10,8 +10,9 @@ #include "mozilla/EventForwards.h" #include "mozilla/TimeStamp.h" +#include "nsRegionFwd.h" + class nsView; -class nsIntRegion; class nsIPresShell; class nsIWidget; class nsIXULWindow; diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h index d8093d2e8e4..df690c731da 100644 --- a/widget/windows/nsWindow.h +++ b/widget/windows/nsWindow.h @@ -28,6 +28,7 @@ #include "mozilla/MouseEvents.h" #include "mozilla/TimeStamp.h" #include "nsMargin.h" +#include "nsRegionFwd.h" #include "nsWinGesture.h" @@ -49,7 +50,6 @@ class nsNativeDragTarget; class nsIRollupListener; -class nsIntRegion; class imgIContainer; namespace mozilla { diff --git a/xpcom/base/ErrorList.h b/xpcom/base/ErrorList.h index a46c06ddfd6..9ae973fde0a 100644 --- a/xpcom/base/ErrorList.h +++ b/xpcom/base/ErrorList.h @@ -926,6 +926,16 @@ ERROR(NS_ERROR_DOM_ANIM_NO_TARGET_ERR, FAILURE(2)), #undef MODULE + /* ======================================================================= */ + /* 40: NS_ERROR_MODULE_DOM_PUSH */ + /* ======================================================================= */ +#define MODULE NS_ERROR_MODULE_DOM_PUSH + ERROR(NS_ERROR_DOM_PUSH_INVALID_REGISTRATION_ERR, FAILURE(1)), + ERROR(NS_ERROR_DOM_PUSH_DENIED_ERR, FAILURE(2)), + ERROR(NS_ERROR_DOM_PUSH_ABORT_ERR, FAILURE(3)), + ERROR(NS_ERROR_DOM_PUSH_SERVICE_UNREACHABLE, FAILURE(4)), +#undef MODULE + /* ======================================================================= */ /* 51: NS_ERROR_MODULE_GENERAL */ /* ======================================================================= */ diff --git a/xpcom/base/nsError.h b/xpcom/base/nsError.h index 7fccef1f8d8..cc8f47d0b83 100644 --- a/xpcom/base/nsError.h +++ b/xpcom/base/nsError.h @@ -77,6 +77,7 @@ #define NS_ERROR_MODULE_DOM_BLUETOOTH 37 #define NS_ERROR_MODULE_SIGNED_APP 38 #define NS_ERROR_MODULE_DOM_ANIM 39 +#define NS_ERROR_MODULE_DOM_PUSH 40 /* NS_ERROR_MODULE_GENERAL should be used by modules that do not * care if return code values overlap. Callers of methods that diff --git a/xpcom/build/moz.build b/xpcom/build/moz.build index f6a5800e384..b524063fccd 100644 --- a/xpcom/build/moz.build +++ b/xpcom/build/moz.build @@ -79,8 +79,8 @@ FINAL_LIBRARY = 'xul' DEFINES['_IMPL_NS_STRINGAPI'] = True DEFINES['OMNIJAR_NAME'] = CONFIG['OMNIJAR_NAME'] -GENERATED_INCLUDES += ['..'] LOCAL_INCLUDES += [ + '!..', '../base', '../components', '../ds', diff --git a/xpcom/components/moz.build b/xpcom/components/moz.build index 03a057f8da2..7b2ebef4559 100644 --- a/xpcom/components/moz.build +++ b/xpcom/components/moz.build @@ -44,8 +44,8 @@ if CONFIG['GNU_CXX']: FINAL_LIBRARY = 'xul' -GENERATED_INCLUDES += ['..'] LOCAL_INCLUDES += [ + '!..', '../base', '../build', '../ds', diff --git a/xpcom/glue/nsTArray.h b/xpcom/glue/nsTArray.h index 498ff36a984..10465ea824d 100644 --- a/xpcom/glue/nsTArray.h +++ b/xpcom/glue/nsTArray.h @@ -27,6 +27,7 @@ #include "nsQuickSort.h" #include "nsDebug.h" #include "nsISupportsImpl.h" +#include "nsRegionFwd.h" #include namespace JS { @@ -35,7 +36,6 @@ class Heap; } /* namespace JS */ class nsRegion; -class nsIntRegion; namespace mozilla { namespace layers { struct TileClient; diff --git a/xpcom/io/moz.build b/xpcom/io/moz.build index f05e7850c02..45732e4cbf2 100644 --- a/xpcom/io/moz.build +++ b/xpcom/io/moz.build @@ -134,4 +134,4 @@ FINAL_LIBRARY = 'xul' if CONFIG['OS_ARCH'] == 'Linux' and 'lib64' in CONFIG['libdir']: DEFINES['HAVE_USR_LIB64_DIR'] = True -GENERATED_INCLUDES += ['..'] +LOCAL_INCLUDES += ['!..'] diff --git a/xpcom/libxpcomrt/moz.build b/xpcom/libxpcomrt/moz.build index c2e0884ab08..cb58cc5a727 100644 --- a/xpcom/libxpcomrt/moz.build +++ b/xpcom/libxpcomrt/moz.build @@ -119,8 +119,8 @@ if CONFIG['INTEL_ARCHITECTURE']: sse_string_path = '/xpcom/string/nsUTF8UtilsSSE2.cpp' SOURCES[sse_string_path].flags += CONFIG['SSE2_FLAGS'] -GENERATED_INCLUDES += ['..'] LOCAL_INCLUDES = [ + '!..', '../base', '../build', '../components', diff --git a/xpcom/typelib/xpt/moz.build b/xpcom/typelib/xpt/moz.build index c238a4b6fff..e798c4501cc 100644 --- a/xpcom/typelib/xpt/moz.build +++ b/xpcom/typelib/xpt/moz.build @@ -22,8 +22,10 @@ EXPORTS += [ FINAL_LIBRARY = 'xul' -GENERATED_INCLUDES += ['/xpcom/base'] -LOCAL_INCLUDES += ['/xpcom/base'] +LOCAL_INCLUDES += [ + '!/xpcom/base', + '/xpcom/base', +] if CONFIG['_MSC_VER']: CFLAGS += ['-Zl'] diff --git a/xpfe/components/windowds/nsWindowDataSource.cpp b/xpfe/components/windowds/nsWindowDataSource.cpp index 519b7089f80..cdeb3a13423 100644 --- a/xpfe/components/windowds/nsWindowDataSource.cpp +++ b/xpfe/components/windowds/nsWindowDataSource.cpp @@ -265,23 +265,6 @@ nsWindowDataSource::OnCloseWindow(nsIXULWindow *window) return NS_OK; } -struct findWindowClosure { - nsIRDFResource* targetResource; - nsIXULWindow *resultWindow; -}; - -static PLDHashOperator -findWindow(nsIXULWindow* aWindow, nsIRDFResource* aResource, void* aClosure) -{ - findWindowClosure* closure = static_cast(aClosure); - - if (aResource == closure->targetResource) { - closure->resultWindow = aWindow; - return PL_DHASH_STOP; - } - return PL_DHASH_NEXT; -} - // nsIWindowDataSource implementation NS_IMETHODIMP @@ -297,20 +280,23 @@ nsWindowDataSource::GetWindowForResource(const char *aResourceString, getter_AddRefs(windowResource)); // now reverse-lookup in the hashtable - findWindowClosure closure = { windowResource.get(), nullptr }; - mWindowResources.EnumerateRead(findWindow, &closure); - if (closure.resultWindow) { + for (auto iter = mWindowResources.Iter(); !iter.Done(); iter.Next()) { + nsIXULWindow* window = iter.Key(); + nsIRDFResource* resource = iter.UserData(); - // this sucks, we have to jump through docshell to go from - // nsIXULWindow -> nsIDOMWindow - nsCOMPtr docShell; - closure.resultWindow->GetDocShell(getter_AddRefs(docShell)); + if (resource == windowResource) { + // This sucks, we have to jump through docshell to go from + // nsIXULWindow -> nsIDOMWindow. + nsCOMPtr docShell; + window->GetDocShell(getter_AddRefs(docShell)); - if (docShell) { - nsCOMPtr result = do_GetInterface(docShell); + if (docShell) { + nsCOMPtr result = do_GetInterface(docShell); - *aResult = result; - NS_IF_ADDREF(*aResult); + *aResult = result; + NS_IF_ADDREF(*aResult); + } + break; } }