author | Carsten "Tomcat" Book <cbook@mozilla.com> |
Tue, 09 Dec 2014 12:51:54 +0100 | |
changeset 218820 | acf5660d2048565ea7095f55697dbb1817dd617a |
parent 218744 | 9045013a21cd5ec910d243c4f9a3d8579f7367b5 (current diff) |
parent 218819 | d4dfb076f5f13ff200b7ecff51ba376d64dcf86d (diff) |
child 218833 | 47f0671e2c65bc2db2bf121f02ad1ed393da2b95 |
push id | 27944 |
push user | cbook@mozilla.com |
push date | Tue, 09 Dec 2014 11:54:28 +0000 |
treeherder | mozilla-central@acf5660d2048 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | merge |
milestone | 37.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/accessible/base/moz.build +++ b/accessible/base/moz.build @@ -92,8 +92,10 @@ else: ] FINAL_LIBRARY = 'xul' if CONFIG['MOZ_ENABLE_GTK']: CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS'] include('/ipc/chromium/chromium-config.mozbuild') + +FAIL_ON_WARNINGS = True
--- a/accessible/generic/moz.build +++ b/accessible/generic/moz.build @@ -52,8 +52,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co else: LOCAL_INCLUDES += [ '/accessible/other', ] FINAL_LIBRARY = 'xul' include('/ipc/chromium/chromium-config.mozbuild') + +FAIL_ON_WARNINGS = True
--- a/accessible/html/moz.build +++ b/accessible/html/moz.build @@ -38,8 +38,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co '/accessible/mac', ] else: LOCAL_INCLUDES += [ '/accessible/other', ] FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/accessible/mac/moz.build +++ b/accessible/mac/moz.build @@ -33,8 +33,10 @@ LOCAL_INCLUDES += [ '/accessible/xul', '/layout/generic', '/layout/xul', '/widget', '/widget/cocoa', ] FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/accessible/xul/moz.build +++ b/accessible/xul/moz.build @@ -43,8 +43,10 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'co '/accessible/mac', ] else: LOCAL_INCLUDES += [ '/accessible/other', ] FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/b2g/chrome/content/shell.js +++ b/b2g/chrome/content/shell.js @@ -720,16 +720,18 @@ var CustomEventManager = { break; case 'system-message-listener-ready': Services.obs.notifyObservers(null, 'system-message-listener-ready', null); break; case 'captive-portal-login-cancel': CaptivePortalLoginHelper.handleEvent(detail); break; case 'inputmethod-update-layouts': + case 'inputregistry-add': + case 'inputregistry-remove': KeyboardHelper.handleEvent(detail); break; case 'do-command': DoCommandHelper.handleEvent(detail.cmd); break; } } } @@ -863,17 +865,27 @@ let IndexedDBPromptHelper = { observer.observe(null, responseTopic, Ci.nsIPermissionManager.DENY_ACTION); }, 0); } } let KeyboardHelper = { handleEvent: function keyboard_handleEvent(detail) { - Keyboard.setLayouts(detail.layouts); + switch (detail.type) { + case 'inputmethod-update-layouts': + Keyboard.setLayouts(detail.layouts); + + break; + case 'inputregistry-add': + case 'inputregistry-remove': + Keyboard.inputRegistryGlue.returnMessage(detail); + + break; + } } }; // This is the backend for Gaia's screenshot feature. Gaia requests a // screenshot by sending a mozContentEvent with detail.type set to // 'take-screenshot'. Then we take a screenshot and send a // mozChromeEvent with detail.type set to 'take-screenshot-success' // and detail.file set to the an image/png blob
--- a/browser/base/content/test/general/browser.ini +++ b/browser/base/content/test/general/browser.ini @@ -485,10 +485,9 @@ skip-if = e10s [browser_addCertException.js] skip-if = e10s # Bug 1100687 - test directly manipulates content (content.document.getElementById) [browser_bug1045809.js] [browser_e10s_switchbrowser.js] [browser_blockHPKP.js] skip-if = e10s # bug 1100687 - test directly manipulates content (content.document.getElementById) [browser_mcb_redirect.js] skip-if = e10s # bug 1084504 - [e10s] Mixed content detection does not take redirection into account -[browser_updatecommands.js] [browser_windowactivation.js]
deleted file mode 100644 --- a/browser/base/content/test/general/browser_updatecommands.js +++ /dev/null @@ -1,93 +0,0 @@ -let testPage = "data:text/html,<body><input id='input1' value='value'><select size=2><option val=1>One</select></body>"; - -let browser; - -function test() { - waitForExplicitFinish(); - - gURLBar.focus(); - - var tab = gBrowser.addTab(); - browser = gBrowser.getBrowserForTab(tab); - gBrowser.selectedTab = tab; - - addEventListener("commandupdate", checkTest, false); - - function runFirstTest(event) { - browser.removeEventListener("load", runFirstTest, true); - doTest(); - } - - browser.addEventListener("load", runFirstTest, true); - browser.contentWindow.location = testPage; -} - -let currentTest; - -let tests = [ - // Switch focus to 'input1'. Paste and select all should be enabled. - { name: "focus input", test: function() { EventUtils.synthesizeKey("VK_TAB", {}) }, - commands: { "cmd_copy" : true, "cmd_paste": true, "cmd_selectAll" : true, "cmd_undo" : false, "cmd_redo": false } }, - - // Move cursor to end which will deselect the text. Copy should be disabled but paste and select all should still be enabled. - { name: "cursor right", test: function() { EventUtils.synthesizeKey("VK_RIGHT", {}) }, - commands: { "cmd_copy" : false, "cmd_paste": true, "cmd_selectAll" : true, "cmd_undo" : false, "cmd_redo": false } }, - - // Select all of the text. Copy should become enabled. - { name: "select all", test: function() { EventUtils.synthesizeKey("a", { accelKey: true }) }, - commands: { "cmd_copy" : true, "cmd_paste": true, "cmd_selectAll" : true, "cmd_undo" : false, "cmd_redo": false } }, - - // Replace the text with 'c'. Copy should now be disabled and undo enabled. - { name: "change value", test: function() { EventUtils.synthesizeKey("c", {}) }, - commands: { "cmd_copy" : false, "cmd_paste": true, "cmd_selectAll" : true, "cmd_undo" : true, "cmd_redo": false } }, - - // Undo. Undo should be disabled and redo enabled. The text is reselected so copy is enabled. - { name: "undo", test: function() { EventUtils.synthesizeKey("z", {accelKey: true }) }, - commands: { "cmd_copy" : true, "cmd_paste": true, "cmd_selectAll" : true, "cmd_undo" : false, "cmd_redo": true } }, - - // Switch focus to the select. Only select all should now be enabled. - { name: "focus select", test: function() { EventUtils.synthesizeKey("VK_TAB", {}) }, - commands: { "cmd_copy" : false, "cmd_paste": false, "cmd_selectAll" : true, "cmd_undo" : false, "cmd_redo": false } }, -]; - -function doTest() -{ - if (!tests.length) { - removeEventListener("commandupdate", checkTest, false); - gBrowser.removeCurrentTab(); - finish(); - return; - } - - currentTest = tests.shift(); - currentTest.test(); -} - -function checkTest(event) -{ - // Ignore commandupdates before the test starts - if (document.activeElement != browser || !currentTest) { - return; - } - - // Skip events fired on command updaters other than the main edit menu one. - if (event.target != document.getElementById("editMenuCommandSetAll")) { - return; - } - - for (let command in currentTest.commands) { - // Command updates can come several at a time, and, especially with multiple - // processes, the updates can come asynchronously. Handle this by just waiting - // until the command have the correct state. The test will timeout if the - // correct command update never occurs. - if ((document.getElementById(command).getAttribute("disabled") != "true") != currentTest.commands[command]) { - return; - } - - is(document.getElementById(command).getAttribute("disabled") != "true", currentTest.commands[command], - currentTest["name"] + " " + command); - } - - currentTest = null; // prevent the check from running again - SimpleTest.executeSoon(doTest); -}
--- a/build/automation.py.in +++ b/build/automation.py.in @@ -502,17 +502,17 @@ class Automation(object): # override the user's choice here. See bug 1049688. env.setdefault('MOZ_DISABLE_NONLOCAL_CONNECTIONS', '1') env['GNOME_DISABLE_CRASH_DIALOG'] = '1' env['XRE_NO_WINDOWS_CRASH_DIALOG'] = '1' env['NS_TRACE_MALLOC_DISABLE_STACKS'] = '1' # Set WebRTC logging in case it is not set yet - env.setdefault('NSPR_LOG_MODULES', 'signaling:5,mtransport:5,datachannel:5') + env.setdefault('NSPR_LOG_MODULES', 'signaling:5,mtransport:5,datachannel:5,jsep:5,MediaPipelineFactory:5') env.setdefault('R_LOG_LEVEL', '6') env.setdefault('R_LOG_DESTINATION', 'stderr') env.setdefault('R_LOG_VERBOSE', '1') # ASan specific environment stuff if self.IS_ASAN and (self.IS_LINUX or self.IS_MAC): # Symbolizer support llvmsym = os.path.join(xrePath, "llvm-symbolizer")
--- a/build/automationutils.py +++ b/build/automationutils.py @@ -405,17 +405,17 @@ def environment(xrePath, env=None, crash # Crash on non-local network connections by default. # MOZ_DISABLE_NONLOCAL_CONNECTIONS can be set to "0" to temporarily # enable non-local connections for the purposes of local testing. Don't # override the user's choice here. See bug 1049688. env.setdefault('MOZ_DISABLE_NONLOCAL_CONNECTIONS', '1') # Set WebRTC logging in case it is not set yet - env.setdefault('NSPR_LOG_MODULES', 'signaling:5,mtransport:5,datachannel:5') + env.setdefault('NSPR_LOG_MODULES', 'signaling:5,mtransport:5,datachannel:5,jsep:5,MediaPipelineFactory:5') env.setdefault('R_LOG_LEVEL', '6') env.setdefault('R_LOG_DESTINATION', 'stderr') env.setdefault('R_LOG_VERBOSE', '1') # ASan specific environment stuff asan = bool(mozinfo.info.get("asan")) if asan and (mozinfo.isLinux or mozinfo.isMac): try:
--- a/caps/moz.build +++ b/caps/moz.build @@ -33,8 +33,9 @@ MSVC_ENABLE_PGO = True LOCAL_INCLUDES += [ '/dom/base', '/js/xpconnect/src', ] FINAL_LIBRARY = 'xul' +FAIL_ON_WARNINGS = True
--- a/chrome/moz.build +++ b/chrome/moz.build @@ -37,8 +37,10 @@ GENERATED_INCLUDES += [ LOCAL_INCLUDES += [ '/netwerk/base/src', '/netwerk/protocol/res', '/xpcom/components' ] if CONFIG['MOZ_ENABLE_GTK']: CXXFLAGS += CONFIG['TK_CFLAGS'] + +FAIL_ON_WARNINGS = True
--- a/dom/base/nsFocusManager.cpp +++ b/dom/base/nsFocusManager.cpp @@ -21,17 +21,16 @@ #include "nsIDocShell.h" #include "nsIDocShellTreeOwner.h" #include "nsLayoutUtils.h" #include "nsIPresShell.h" #include "nsFrameTraversal.h" #include "nsIWebNavigation.h" #include "nsCaret.h" #include "nsIBaseWindow.h" -#include "nsIXULWindow.h" #include "nsViewManager.h" #include "nsFrameSelection.h" #include "mozilla/dom/Selection.h" #include "nsXULPopupManager.h" #include "nsIScriptObjectPrincipal.h" #include "nsIPrincipal.h" #include "nsIObserverService.h" #include "nsIObjectFrame.h" @@ -730,20 +729,17 @@ nsFocusManager::WindowRaised(nsIDOMWindo nsCOMPtr<nsIPresShell> presShell = currentDocShell->GetPresShell(); if (presShell) { // disable selection mousedown state on activation // XXXndeakin P3 not sure if this is necessary, but it doesn't hurt nsRefPtr<nsFrameSelection> frameSelection = presShell->FrameSelection(); frameSelection->SetDragState(false); } - // If there is no nsIXULWindow, then this is an embedded or child process window. - // Pass false for aWindowRaised so that commands get updated. - nsCOMPtr<nsIXULWindow> xulWin(do_GetInterface(baseWindow)); - Focus(currentWindow, currentFocus, 0, true, false, xulWin != nullptr, true); + Focus(currentWindow, currentFocus, 0, true, false, true, true); return NS_OK; } NS_IMETHODIMP nsFocusManager::WindowLowered(nsIDOMWindow* aWindow) { nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
--- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -9265,46 +9265,16 @@ nsGlobalWindow::ShowModalDialog(const ns ErrorResult rv; nsCOMPtr<nsIVariant> retVal = ShowModalDialog(aURI, aArgs, aOptions, rv); retVal.forget(aRetVal); return rv.ErrorCode(); } -class ChildCommandDispatcher : public nsRunnable -{ -public: - ChildCommandDispatcher(nsGlobalWindow* aWindow, - nsITabChild* aTabChild, - const nsAString& aAction) - : mWindow(aWindow), mTabChild(aTabChild), mAction(aAction) {} - - NS_IMETHOD Run() - { - nsCOMPtr<nsPIWindowRoot> root = mWindow->GetTopWindowRoot(); - if (!root) { - return NS_OK; - } - - nsTArray<nsCString> enabledCommands, disabledCommands; - root->GetEnabledDisabledCommands(enabledCommands, disabledCommands); - if (enabledCommands.Length() || disabledCommands.Length()) { - mTabChild->EnableDisableCommands(mAction, enabledCommands, disabledCommands); - } - - return NS_OK; - } - -private: - nsRefPtr<nsGlobalWindow> mWindow; - nsCOMPtr<nsITabChild> mTabChild; - nsString mAction; -}; - class CommandDispatcher : public nsRunnable { public: CommandDispatcher(nsIDOMXULCommandDispatcher* aDispatcher, const nsAString& aAction) : mDispatcher(aDispatcher), mAction(aAction) {} NS_IMETHOD Run() @@ -9314,22 +9284,16 @@ public: nsCOMPtr<nsIDOMXULCommandDispatcher> mDispatcher; nsString mAction; }; NS_IMETHODIMP nsGlobalWindow::UpdateCommands(const nsAString& anAction, nsISelection* aSel, int16_t aReason) { - // If this is a child process, redirect to the parent process. - if (nsCOMPtr<nsITabChild> child = do_GetInterface(GetDocShell())) { - nsContentUtils::AddScriptRunner(new ChildCommandDispatcher(this, child, anAction)); - return NS_OK; - } - nsPIDOMWindow *rootWindow = nsGlobalWindow::GetPrivateRoot(); if (!rootWindow) return NS_OK; nsCOMPtr<nsIDOMXULDocument> xulDoc = do_QueryInterface(rootWindow->GetExtantDoc()); // See if we contain a XUL document. // selectionchange action is only used for mozbrowser, not for XUL. So we bypass
--- a/dom/base/nsPIWindowRoot.h +++ b/dom/base/nsPIWindowRoot.h @@ -10,37 +10,34 @@ #include "nsISupports.h" #include "mozilla/dom/EventTarget.h" class nsPIDOMWindow; class nsIControllers; class nsIController; #define NS_IWINDOWROOT_IID \ -{ 0x728a2682, 0x55c0, 0x4860, \ - { 0x82, 0x6b, 0x0c, 0x30, 0x0a, 0xac, 0xaa, 0x60 } } +{ 0x3f71f50c, 0xa7e0, 0x43bc, \ + { 0xac, 0x25, 0x4d, 0xbb, 0x88, 0x7b, 0x21, 0x09 } } class nsPIWindowRoot : public mozilla::dom::EventTarget { public: NS_DECLARE_STATIC_IID_ACCESSOR(NS_IWINDOWROOT_IID) virtual nsPIDOMWindow* GetWindow()=0; // get and set the node that is the context of a popup menu virtual nsIDOMNode* GetPopupNode() = 0; virtual void SetPopupNode(nsIDOMNode* aNode) = 0; virtual nsresult GetControllerForCommand(const char *aCommand, nsIController** aResult) = 0; virtual nsresult GetControllers(nsIControllers** aResult) = 0; - virtual void GetEnabledDisabledCommands(nsTArray<nsCString>& aEnabledCommands, - nsTArray<nsCString>& aDisabledCommands) = 0; - virtual void SetParentTarget(mozilla::dom::EventTarget* aTarget) = 0; virtual mozilla::dom::EventTarget* GetParentTarget() = 0; virtual nsIDOMWindow* GetOwnerGlobal() MOZ_OVERRIDE = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsPIWindowRoot, NS_IWINDOWROOT_IID) #endif // nsPIWindowRoot_h__
--- a/dom/base/nsWindowRoot.cpp +++ b/dom/base/nsWindowRoot.cpp @@ -276,85 +276,16 @@ nsWindowRoot::GetControllerForCommand(co // XXXndeakin P3 is this casting safe? nsGlobalWindow *win = static_cast<nsGlobalWindow*>(focusedWindow.get()); focusedWindow = win->GetPrivateParent(); } return NS_OK; } -void -nsWindowRoot::GetEnabledDisabledCommandsForControllers(nsIControllers* aControllers, - nsTHashtable<nsCharPtrHashKey>& aCommandsHandled, - nsTArray<nsCString>& aEnabledCommands, - nsTArray<nsCString>& aDisabledCommands) -{ - uint32_t controllerCount; - aControllers->GetControllerCount(&controllerCount); - for (uint32_t c = 0; c < controllerCount; c++) { - nsCOMPtr<nsIController> controller; - aControllers->GetControllerAt(c, getter_AddRefs(controller)); - - nsCOMPtr<nsICommandController> commandController(do_QueryInterface(controller)); - if (commandController) { - uint32_t commandsCount; - char** commands; - if (NS_SUCCEEDED(commandController->GetSupportedCommands(&commandsCount, &commands))) { - for (uint32_t e = 0; e < commandsCount; e++) { - // Use a hash to determine which commands have already been handled by - // earlier controllers, as the earlier controller's result should get - // priority. - if (!aCommandsHandled.Contains(commands[e])) { - aCommandsHandled.PutEntry(commands[e]); - - bool enabled = false; - controller->IsCommandEnabled(commands[e], &enabled); - - const nsDependentCSubstring commandStr(commands[e], strlen(commands[e])); - if (enabled) { - aEnabledCommands.AppendElement(commandStr); - } else { - aDisabledCommands.AppendElement(commandStr); - } - } - } - - NS_FREE_XPCOM_ALLOCATED_POINTER_ARRAY(commandsCount, commands); - } - } - } -} - -void -nsWindowRoot::GetEnabledDisabledCommands(nsTArray<nsCString>& aEnabledCommands, - nsTArray<nsCString>& aDisabledCommands) -{ - nsTHashtable<nsCharPtrHashKey> commandsHandled; - - nsCOMPtr<nsIControllers> controllers; - GetControllers(getter_AddRefs(controllers)); - if (controllers) { - GetEnabledDisabledCommandsForControllers(controllers, commandsHandled, - aEnabledCommands, aDisabledCommands); - } - - nsCOMPtr<nsPIDOMWindow> focusedWindow; - nsFocusManager::GetFocusedDescendant(mWindow, true, getter_AddRefs(focusedWindow)); - while (focusedWindow) { - focusedWindow->GetControllers(getter_AddRefs(controllers)); - if (controllers) { - GetEnabledDisabledCommandsForControllers(controllers, commandsHandled, - aEnabledCommands, aDisabledCommands); - } - - nsGlobalWindow* win = static_cast<nsGlobalWindow*>(focusedWindow.get()); - focusedWindow = win->GetPrivateParent(); - } -} - nsIDOMNode* nsWindowRoot::GetPopupNode() { return mPopupNode; } void nsWindowRoot::SetPopupNode(nsIDOMNode* aNode)
--- a/dom/base/nsWindowRoot.h +++ b/dom/base/nsWindowRoot.h @@ -18,18 +18,16 @@ class EventChainPreVisitor; } // namespace mozilla #include "mozilla/Attributes.h" #include "mozilla/EventListenerManager.h" #include "nsIDOMEventTarget.h" #include "nsPIWindowRoot.h" #include "nsCycleCollectionParticipant.h" #include "nsAutoPtr.h" -#include "nsTHashtable.h" -#include "nsHashKeys.h" class nsWindowRoot : public nsPIWindowRoot { public: explicit nsWindowRoot(nsPIDOMWindow* aWindow); NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_NSIDOMEVENTTARGET @@ -49,19 +47,16 @@ public: // nsPIWindowRoot virtual nsPIDOMWindow* GetWindow() MOZ_OVERRIDE; virtual nsresult GetControllers(nsIControllers** aResult) MOZ_OVERRIDE; virtual nsresult GetControllerForCommand(const char * aCommand, nsIController** _retval) MOZ_OVERRIDE; - virtual void GetEnabledDisabledCommands(nsTArray<nsCString>& aEnabledCommands, - nsTArray<nsCString>& aDisabledCommands) MOZ_OVERRIDE; - virtual nsIDOMNode* GetPopupNode() MOZ_OVERRIDE; virtual void SetPopupNode(nsIDOMNode* aNode) MOZ_OVERRIDE; virtual void SetParentTarget(mozilla::dom::EventTarget* aTarget) MOZ_OVERRIDE { mParent = aTarget; } virtual mozilla::dom::EventTarget* GetParentTarget() MOZ_OVERRIDE { return mParent; } @@ -72,21 +67,16 @@ public: virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE; NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_AMBIGUOUS(nsWindowRoot, nsIDOMEventTarget) protected: virtual ~nsWindowRoot(); - void GetEnabledDisabledCommandsForControllers(nsIControllers* aControllers, - nsTHashtable<nsCharPtrHashKey>& aCommandsHandled, - nsTArray<nsCString>& aEnabledCommands, - nsTArray<nsCString>& aDisabledCommands); - // Members nsCOMPtr<nsPIDOMWindow> mWindow; // We own the manager, which owns event listeners attached to us. nsRefPtr<mozilla::EventListenerManager> mListenerManager; // [Strong] nsCOMPtr<nsIDOMNode> mPopupNode; // [OWNER] nsCOMPtr<mozilla::dom::EventTarget> mParent; };
--- a/dom/base/test/TestCSPParser.cpp +++ b/dom/base/test/TestCSPParser.cpp @@ -273,19 +273,19 @@ nsresult TestIgnoreUpperLowerCasePolicie { "script-src 'SHA256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='", "script-src 'sha256-siVR8vAcqP06h2ppeNwqgjr0yZ6yned4X2VF84j4GmI='" } }; uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); return runTestSuite(policies, policyCount, 1); } -// ============================= TestIgnorePaths ======================== +// ============================= TestPaths ======================== -nsresult TestIgnorePaths() { +nsresult TestPaths() { static const PolicyTest policies[] = { { "script-src http://www.example.com", "script-src http://www.example.com" }, { "script-src http://www.example.com/", "script-src http://www.example.com/" }, { "script-src http://www.example.com/path-1", @@ -355,16 +355,22 @@ nsresult TestIgnorePaths() { { "report-uri http://www.example.com:8888/asdf", "report-uri http://www.example.com:8888/asdf" }, { "report-uri http://www.example.com:8888/path_1/path_2", "report-uri http://www.example.com:8888/path_1/path_2" }, { "report-uri http://www.example.com:8888/path_1/path_2/report.sjs&301", "report-uri http://www.example.com:8888/path_1/path_2/report.sjs&301" }, { "report-uri /examplepath", "report-uri http://www.selfuri.com/examplepath" }, + { "connect-src http://www.example.com/foo%3Bsessionid=12%2C34", + "connect-src http://www.example.com/foo;sessionid=12,34" }, + { "connect-src http://www.example.com/foo%3bsessionid=12%2c34", + "connect-src http://www.example.com/foo;sessionid=12,34" }, + { "connect-src http://test.com/pathIncludingAz19-._~!$&'()*+=:@", + "connect-src http://test.com/pathincludingaz19-._~!$&'()*+=:@" }, }; uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); return runTestSuite(policies, policyCount, 1); } // ============================= TestSimplePolicies ======================== @@ -487,16 +493,20 @@ nsresult TestPoliciesWithInvalidSrc() { { "script-src http://www.example.com:88/.js", "script-src 'none'" }, { "script-src http://www.example.com:88.js", "script-src 'none'" }, { "script-src http://www.example.com:*.js", "script-src 'none'" }, { "script-src http://www.example.com:*.", "script-src 'none'" }, + { "connect-src http://www.example.com/foo%zz;", + "connect-src 'none'" }, + { "script-src https://foo.com/%$", + "script-src 'none'" }, }; uint32_t policyCount = sizeof(policies) / sizeof(PolicyTest); return runTestSuite(policies, policyCount, 1); } // ============================= TestBadPolicies ======================== @@ -1078,17 +1088,17 @@ int main(int argc, char** argv) { ScopedXPCOM xpcom("ContentSecurityPolicyParser"); if (xpcom.failed()) { return 1; } if (NS_FAILED(TestDirectives())) { return 1; } if (NS_FAILED(TestKeywords())) { return 1; } if (NS_FAILED(TestIgnoreUpperLowerCasePolicies())) { return 1; } - if (NS_FAILED(TestIgnorePaths())) { return 1; } + if (NS_FAILED(TestPaths())) { return 1; } if (NS_FAILED(TestSimplePolicies())) { return 1; } if (NS_FAILED(TestPoliciesWithInvalidSrc())) { return 1; } if (NS_FAILED(TestBadPolicies())) { return 1; } if (NS_FAILED(TestGoodGeneratedPolicies())) { return 1; } if (NS_FAILED(TestBadGeneratedPolicies())) { return 1; } if (NS_FAILED(TestGoodGeneratedPoliciesForPathHandling())) { return 1; } if (NS_FAILED(TestBadGeneratedPoliciesForPathHandling())) { return 1; } if (NS_FAILED(TestShorteningPolicies())) { return 1; }
--- a/dom/base/test/csp/file_csp_redirects_main.html +++ b/dom/base/test/csp/file_csp_redirects_main.html @@ -15,16 +15,18 @@ var tests = { "font-src": thisSite+page+ "frame-src": thisSite+page+"?testid=frame-src&csp=1", "img-src": thisSite+page+"?testid=img-src&csp=1", "media-src": thisSite+page+"?testid=media-src&csp=1", "object-src": thisSite+page+"?testid=object-src&csp=1", "script-src": thisSite+page+"?testid=script-src&csp=1", "style-src": thisSite+page+"?testid=style-src&csp=1", "worker": thisSite+page+"?testid=worker&csp=1", "xhr-src": thisSite+page+"?testid=xhr-src&csp=1", + "script-src-from-worker": thisSite+page+"?testid=script-src-from-worker&csp=1", + "img-src-from-css": thisSite+page+"?testid=img-src-from-css&csp=1", }; var container = document.getElementById("container"); // load each test in its own iframe for (tid in tests) { var i = document.createElement("iframe"); i.id = tid;
--- a/dom/base/test/csp/file_csp_redirects_page.sjs +++ b/dom/base/test/csp/file_csp_redirects_page.sjs @@ -71,9 +71,26 @@ function handleRequest(request, response return; } // script that XHR's to a resource that redirects to another site if (query["testid"] == "xhr-src") { response.write('<script src="'+resource+'?res=xhr"></script>'); return; } + + // for bug949706 + if (query["testid"] == "img-src-from-css") { + // loads a stylesheet, which in turn loads an image that redirects. + response.write('<link rel="stylesheet" type="text/css" href="'+resource+'?res=cssLoader&id=img-src-redir-from-css">'); + return; + } + + if (query["testid"] == "script-src-from-worker") { + // loads a script; launches a worker; that worker uses importscript; which then gets redirected + // So it's: + // <script "res=loadWorkerThatImports"> + // .. loads Worker("res=importScriptWorker") + // .. calls importScript("res=script") + response.write('<script src="'+resource+'?res=loadWorkerThatImports&id=script-src-redir-from-worker"></script>'); + return; + } }
--- a/dom/base/test/csp/file_csp_redirects_resource.sjs +++ b/dom/base/test/csp/file_csp_redirects_resource.sjs @@ -87,16 +87,44 @@ function handleRequest(request, response // web worker resource if (query["res"] == "worker") { response.setHeader("Content-Type", "application/javascript", false); response.write("worker script data..."); return; } + // internal stylesheet that loads an image from an external site + if (query["res"] == "cssLoader") { + let bgURL = thisSite + resource + '?redir=other&res=image&id=' + query["id"]; + response.setHeader("Content-Type", "text/css", false); + response.write("body { background:url('" + bgURL + "'); }"); + return; + } + + // script that loads an internal worker that uses importScripts on a redirect + // to an external script. + if (query["res"] == "loadWorkerThatImports") { + // this creates a worker (same origin) that imports a redirecting script. + let workerURL = thisSite + resource + '?res=importScriptWorker&id=' + query["id"]; + response.setHeader("Content-Type", "application/javascript", false); + response.write("var w=new Worker('" + workerURL + "'); w.onmessage=function(event){ alert(event.data); }"); + return; + } + + // source for a worker that simply calls importScripts on a script that + // redirects. + if (query["res"] == "importScriptWorker") { + // this is code for a worker that imports a redirected script. + let scriptURL = thisSite + resource + "?redir=other&res=script&id=" + query["id"]; + response.setHeader("Content-Type", "application/javascript", false); + response.write("importScripts('" + scriptURL + "');"); + return; + } + // script that invokes XHR if (query["res"] == "xhr") { response.setHeader("Content-Type", "text/html", false); var resp = 'var x = new XMLHttpRequest(); x.open("GET", "' + otherSite + resource+'?res=xhr-resp&testid=xhr-src-redir", false); ' + 'x.send(null);'; response.write(resp); return;
new file mode 100644 --- /dev/null +++ b/dom/base/test/csp/file_worker_redirect.html @@ -0,0 +1,9 @@ +<!DOCTYPE HTML> +<html> + <head> + <title>Bug 949706 - CSP: Correct handling of web workers importing scripts that get redirected</title> + </head> + <body> + <script src="file_worker_redirect.sjs?stage_0_script_loads_worker"></script> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/base/test/csp/file_worker_redirect.sjs @@ -0,0 +1,37 @@ +// testserver customized for the needs of: +// Bug 949706 - CSP: Correct handling of web workers importing scripts that get redirected + +function handleRequest(request, response) +{ + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "text/html", false); + + var query = request.queryString; + + if (query === "stage_0_script_loads_worker") { + var newWorker = + "var myWorker = new Worker(\"file_worker_redirect.sjs?stage_1_worker_import_scripts\");" + + "myWorker.onmessage = function (event) { parent.checkResult(\"allowed\"); };" + + "myWorker.onerror = function (event) { parent.checkResult(\"blocked\"); };"; + response.write(newWorker); + return; + } + + if (query === "stage_1_worker_import_scripts") { + response.write("importScripts(\"file_worker_redirect.sjs?stage_2_redirect_imported_script\");"); + return; + } + + if (query === "stage_2_redirect_imported_script") { + var newLocation = + "http://test1.example.com/tests/dom/base/test/csp/file_worker_redirect.sjs?stage_3_target_script"; + response.setStatusLine("1.1", 302, "Found"); + response.setHeader("Location", newLocation, false); + return; + } + + if (query === "stage_3_target_script") { + response.write("postMessage(\"imported script loaded\");"); + return; + } +}
--- a/dom/base/test/csp/mochitest.ini +++ b/dom/base/test/csp/mochitest.ini @@ -96,16 +96,18 @@ support-files = file_subframe_run_js_if_allowed.html file_subframe_run_js_if_allowed.html^headers^ file_leading_wildcard.html file_multi_policy_injection_bypass.html file_multi_policy_injection_bypass.html^headers^ file_multi_policy_injection_bypass_2.html file_multi_policy_injection_bypass_2.html^headers^ file_form-action.html + file_worker_redirect.html + file_worker_redirect.sjs [test_base-uri.html] [test_connect-src.html] [test_CSP.html] [test_csp_allow_https_schemes.html] skip-if = buildapp == 'b2g' #no ssl support [test_CSP_bug663567.html] [test_CSP_bug802872.html] @@ -142,8 +144,9 @@ skip-if = buildapp == 'b2g' # intermitte skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490) [test_303_redirect.html] skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490) [test_307_redirect.html] skip-if = buildapp == 'b2g' # intermittent orange (bug 1028490) [test_subframe_run_js_if_allowed.html] [test_leading_wildcard.html] [test_multi_policy_injection_bypass.html] +[test_worker_redirect.html]
--- a/dom/base/test/csp/test_csp_redirects.html +++ b/dom/base/test/csp/test_csp_redirects.html @@ -81,16 +81,20 @@ var testExpectedResults = { "font-src": "script-src": true, "script-src-redir": false, "style-src": true, "style-src-redir": false, "worker": true, "worker-redir": false, "xhr-src": true, "xhr-src-redir": false, + "script-src-from-worker": true, /* test runs */ + "script-src-redir-from-worker": false, /* redir is blocked */ + "img-src-from-css": true, /* test runs */ + "img-src-redir-from-css": false, /* redir is blocked */ }; // takes the name of the test, the URL that was tested, and whether the // load occurred var testResult = function(testName, url, result) { log(" testName: "+testName+", result: "+result+", expected: "+testExpectedResults[testName]+"\n"); is(result, testExpectedResults[testName], testName+" test: "+url);
new file mode 100644 --- /dev/null +++ b/dom/base/test/csp/test_worker_redirect.html @@ -0,0 +1,76 @@ +<!DOCTYPE HTML> +<html> +<head> + <title>Bug 949706 - CSP: Correct handling of web workers importing scripts that get redirected</title> + <!-- Including SimpleTest.js so we can use waitForExplicitFinish !--> + <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" /> +</head> +<body> + <div id="content" style="visibility: hidden"> + <iframe style="width:100%;" id="testframe"></iframe> + </div> + +<script class="testbody" type="text/javascript"> + +/* Description of the test: + * We load a page that loads a script which then instantiates a web worker, + * where that web worker then imports a script which gets redirected. + * We verify that the CSP applies correctly after the imported script of + * the worker gets redirected. More specifically, the test works as follows: + * + * test_worker_redirect.html + * -> loads file_worker_redirect.html file into iframe + * -> loads worker file_worker_redirect.sjs?stage_0_script_loads_worker + * -> creates script file_worker_redirect.sjs?stage_1_worker_import_scripts + * -> redirects script file_worker_redirect.sjs?stage_2_redirect_imported_script + * -> loads target script file_worker_redirect.sjs?stage_3_target_script + * + * Please note that we have to use 'unsafe-eval' in the policy + * so that workers are actually permitted by the CSP. + * + * The main test is loaded using: + * http://mochi.test:8888 + * where the imported script gets redirected to: + * http://test1.example.com + */ + +var tests = [ + { + policy: "default-src 'self'; script-src 'self' 'unsafe-eval' http://test1.example.com;", + expected: "allowed" + }, + { + policy: "default-src 'self'; script-src 'self' 'unsafe-eval';", + expected: "blocked", + }, +]; + +var counter = 0; +var curTest; + +function checkResult(aResult) { + is(aResult, curTest.expected, "Should be (" + curTest.expected + ") in Test " + counter + "!"); + loadNextTest(); +} + +function loadNextTest() { + if (counter == tests.length) { + SimpleTest.finish(); + return; + } + curTest = tests[counter++]; + var src = "file_csp_testserver.sjs"; + // append the file that should be served + src += "?file=" + escape("tests/dom/base/test/csp/file_worker_redirect.html"); + // append the CSP that should be used to serve the file + src += "&csp=" + escape(curTest.policy); + document.getElementById("testframe").src = src; +} + +SimpleTest.waitForExplicitFinish(); +loadNextTest(); + +</script> +</body> +</html>
--- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -857,17 +857,17 @@ DOMInterfaces = { }, 'Path2D': { 'nativeType': 'mozilla::dom::CanvasPath', 'headerFile': 'CanvasRenderingContext2D.h' }, 'PeerConnectionImpl': { - 'nativeType': 'sipcc::PeerConnectionImpl', + 'nativeType': 'mozilla::PeerConnectionImpl', 'headerFile': 'PeerConnectionImpl.h', 'wrapperCache': False }, 'Performance': [{ 'nativeType': 'nsPerformance', }, {
--- a/dom/bindings/moz.build +++ b/dom/bindings/moz.build @@ -59,16 +59,17 @@ LOCAL_INCLUDES += [ '/dom/xslt/xpath', '/dom/xul', '/js/ipc', '/js/xpconnect/src', '/js/xpconnect/wrappers', '/layout/style', '/layout/xul/tree', '/media/mtransport', + '/media/webrtc/', '/media/webrtc/signaling/src/common/time_profiling', '/media/webrtc/signaling/src/peerconnection', ] UNIFIED_SOURCES += [ 'BindingUtils.cpp', 'CallbackInterface.cpp', 'CallbackObject.cpp',
--- a/dom/inputmethod/Keyboard.jsm +++ b/dom/inputmethod/Keyboard.jsm @@ -14,16 +14,46 @@ Cu.import('resource://gre/modules/Servic Cu.import("resource://gre/modules/XPCOMUtils.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "ppmm", "@mozilla.org/parentprocessmessagemanager;1", "nsIMessageBroadcaster"); XPCOMUtils.defineLazyModuleGetter(this, "SystemAppProxy", "resource://gre/modules/SystemAppProxy.jsm"); +XPCOMUtils.defineLazyGetter(this, "appsService", function() { + return Cc["@mozilla.org/AppsService;1"].getService(Ci.nsIAppsService); +}); + +let Utils = { + getMMFromMessage: function u_getMMFromMessage(msg) { + let mm; + try { + mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner) + .frameLoader.messageManager; + } catch(e) { + mm = msg.target; + } + + return mm; + }, + checkPermissionForMM: function u_checkPermissionForMM(mm, permName) { + let testing = false; + try { + testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing"); + } catch (e) { } + + if (testing) { + return true; + } + + return mm.assertPermission(permName); + } +}; + this.Keyboard = { _formMM: null, // The current web page message manager. _keyboardMM: null, // The keyboard app message manager. _keyboardID: -1, // The keyboard app's ID number. -1 = invalid _nextKeyboardID: 0, // The ID number counter. _systemMessageName: [ 'SetValue', 'RemoveFocus', 'SetSelectedOption', 'SetSelectedOptions' ], @@ -67,16 +97,18 @@ this.Keyboard = { for (let name of this._messageNames) { ppmm.addMessageListener('Keyboard:' + name, this); } for (let name of this._systemMessageName) { ppmm.addMessageListener('System:' + name, this); } + + this.inputRegistryGlue = new InputRegistryGlue(); }, observe: function keyboardObserve(subject, topic, data) { let frameLoader = subject.QueryInterface(Ci.nsIFrameLoader); let mm = frameLoader.messageManager; if (topic == 'oop-frameloader-crashed') { if (this.formMM == mm) { @@ -117,39 +149,28 @@ this.Keyboard = { let isKeyboardRegistration = msg.name == "Keyboard:Register" || msg.name == "Keyboard:Unregister"; if (msg.name.indexOf("Keyboard:") === 0 || msg.name.indexOf("System:") === 0) { if (!this.formMM && !isKeyboardRegistration) { return; } - try { - mm = msg.target.QueryInterface(Ci.nsIFrameLoaderOwner) - .frameLoader.messageManager; - } catch(e) { - mm = msg.target; - } + mm = Utils.getMMFromMessage(msg); // That should never happen. if (!mm) { dump("!! No message manager found for " + msg.name); return; } - let testing = false; - try { - testing = Services.prefs.getBoolPref("dom.mozInputMethod.testing"); - } catch (e) { - } - let perm = (msg.name.indexOf("Keyboard:") === 0) ? "input" : "input-manage"; - if (!isKeyboardRegistration && !testing && - !mm.assertPermission(perm)) { + + if (!isKeyboardRegistration && !Utils.checkPermissionForMM(mm, perm)) { dump("Keyboard message " + msg.name + " from a content process with no '" + perm + "' privileges."); return; } } // we don't process kb messages (other than register) // if they come from a kb that we're currently not regsitered for. @@ -359,9 +380,98 @@ this.Keyboard = { // cache the layouts so on init we can respond immediately instead // of going back and forth between keyboard_manager this._layouts = layouts; this.sendToKeyboard('Keyboard:LayoutsChange', layouts); } }; +function InputRegistryGlue() { + this._messageId = 0; + this._msgMap = new Map(); + + ppmm.addMessageListener('InputRegistry:Add', this); + ppmm.addMessageListener('InputRegistry:Remove', this); +}; + +InputRegistryGlue.prototype.receiveMessage = function(msg) { + let mm = Utils.getMMFromMessage(msg); + + if (!Utils.checkPermissionForMM(mm, 'input')) { + dump("InputRegistryGlue message " + msg.name + + " from a content process with no 'input' privileges."); + return; + } + + switch (msg.name) { + case 'InputRegistry:Add': + this.addInput(msg, mm); + + break; + + case 'InputRegistry:Remove': + this.removeInput(msg, mm); + + break; + } +}; + +InputRegistryGlue.prototype.addInput = function(msg, mm) { + let msgId = this._messageId++; + this._msgMap.set(msgId, { + mm: mm, + requestId: msg.data.requestId + }); + + let manifestURL = appsService.getManifestURLByLocalId(msg.data.appId); + + SystemAppProxy.dispatchEvent({ + type: 'inputregistry-add', + id: msgId, + manifestURL: manifestURL, + inputId: msg.data.inputId, + inputManifest: msg.data.inputManifest + }); +}; + +InputRegistryGlue.prototype.removeInput = function(msg, mm) { + let msgId = this._messageId++; + this._msgMap.set(msgId, { + mm: mm, + requestId: msg.data.requestId + }); + + let manifestURL = appsService.getManifestURLByLocalId(msg.data.appId); + + SystemAppProxy.dispatchEvent({ + type: 'inputregistry-remove', + id: msgId, + manifestURL: manifestURL, + inputId: msg.data.inputId + }); +}; + +InputRegistryGlue.prototype.returnMessage = function(detail) { + if (!this._msgMap.has(detail.id)) { + return; + } + + let { mm, requestId } = this._msgMap.get(detail.id); + this._msgMap.delete(detail.id); + + if (Cu.isDeadWrapper(mm)) { + return; + } + + if (!('error' in detail)) { + mm.sendAsyncMessage('InputRegistry:Result:OK', { + requestId: requestId + }); + } else { + mm.sendAsyncMessage('InputRegistry:Result:Error', { + error: detail.error, + requestId: requestId + }); + } +}; + this.Keyboard.init();
--- a/dom/inputmethod/MozKeyboard.js +++ b/dom/inputmethod/MozKeyboard.js @@ -144,16 +144,18 @@ MozInputMethodManager.prototype = { /** * ============================================== * InputMethod * ============================================== */ function MozInputMethod() { } MozInputMethod.prototype = { + __proto__: DOMRequestIpcHelper.prototype, + _inputcontext: null, _wrappedInputContext: null, _layouts: {}, _window: null, _isSystem: false, _isKeyboard: true, classID: Components.ID("{4607330d-e7d2-40a4-9eb8-43967eae0142}"), @@ -191,60 +193,77 @@ MozInputMethod.prototype = { this._isKeyboard = false; return; } cpmm.addWeakMessageListener('Keyboard:FocusChange', this); cpmm.addWeakMessageListener('Keyboard:SelectionChange', this); cpmm.addWeakMessageListener('Keyboard:GetContext:Result:OK', this); cpmm.addWeakMessageListener('Keyboard:LayoutsChange', this); + cpmm.addWeakMessageListener('InputRegistry:Result:OK', this); + cpmm.addWeakMessageListener('InputRegistry:Result:Error', this); }, uninit: function mozInputMethodUninit() { this._window = null; this._mgmt = null; Services.obs.removeObserver(this, "inner-window-destroyed"); if (!this._isKeyboard) { return; } cpmm.removeWeakMessageListener('Keyboard:FocusChange', this); cpmm.removeWeakMessageListener('Keyboard:SelectionChange', this); cpmm.removeWeakMessageListener('Keyboard:GetContext:Result:OK', this); cpmm.removeWeakMessageListener('Keyboard:LayoutsChange', this); + cpmm.removeWeakMessageListener('InputRegistry:Result:OK', this); + cpmm.removeWeakMessageListener('InputRegistry:Result:Error', this); this.setActive(false); }, receiveMessage: function mozInputMethodReceiveMsg(msg) { - if (!WindowMap.isActive(this._window)) { + if (!msg.name.startsWith('InputRegistry') && + !WindowMap.isActive(this._window)) { return; } - let json = msg.json; + let data = msg.data; + let resolver = ('requestId' in data) ? + this.takePromiseResolver(data.requestId) : null; switch(msg.name) { case 'Keyboard:FocusChange': - if (json.type !== 'blur') { + if (data.type !== 'blur') { // XXX Bug 904339 could receive 'text' event twice - this.setInputContext(json); + this.setInputContext(data); } else { this.setInputContext(null); } break; case 'Keyboard:SelectionChange': if (this.inputcontext) { - this._inputcontext.updateSelectionContext(json, false); + this._inputcontext.updateSelectionContext(data, false); } break; case 'Keyboard:GetContext:Result:OK': - this.setInputContext(json); + this.setInputContext(data); break; case 'Keyboard:LayoutsChange': - this._layouts = json; + this._layouts = data; + break; + + case 'InputRegistry:Result:OK': + resolver.resolve(); + + break; + + case 'InputRegistry:Result:Error': + resolver.reject(data.error); + break; } }, observe: function mozInputMethodObserve(subject, topic, data) { let wId = subject.QueryInterface(Ci.nsISupportsPRUint64).data; if (wId == this.innerWindowID) this.uninit(); @@ -325,16 +344,41 @@ MozInputMethod.prototype = { // Deactive current input method. cpmmSendAsyncMessageWithKbID(this, 'Keyboard:Unregister', {}); if (this._inputcontext) { this.setInputContext(null); } } }, + addInput: function(inputId, inputManifest) { + return this._sendPromise(function(resolverId) { + let appId = this._window.document.nodePrincipal.appId; + + cpmm.sendAsyncMessage('InputRegistry:Add', { + requestId: resolverId, + inputId: inputId, + inputManifest: inputManifest, + appId: appId + }); + }.bind(this)); + }, + + removeInput: function(inputId) { + return this._sendPromise(function(resolverId) { + let appId = this._window.document.nodePrincipal.appId; + + cpmm.sendAsyncMessage('InputRegistry:Remove', { + requestId: resolverId, + inputId: inputId, + appId: appId + }); + }.bind(this)); + }, + setValue: function(value) { this._ensureIsSystem(); cpmm.sendAsyncMessage('System:SetValue', { 'value': value }); }, setSelectedOption: function(index) { @@ -356,16 +400,24 @@ MozInputMethod.prototype = { cpmm.sendAsyncMessage('System:RemoveFocus', {}); }, _ensureIsSystem: function() { if (!this._isSystem) { throw new this._window.DOMError("Security", "Should have 'input-manage' permssion."); } + }, + + _sendPromise: function(callback) { + let self = this; + return this.createPromise(function(resolve, reject) { + let resolverId = self.getPromiseResolverId({ resolve: resolve, reject: reject }); + callback(resolverId); + }); } }; /** * ============================================== * InputContext * ============================================== */
--- a/dom/interfaces/base/moz.build +++ b/dom/interfaces/base/moz.build @@ -26,17 +26,16 @@ XPIDL_SOURCES += [ 'nsIDOMScreen.idl', 'nsIDOMWindow.idl', 'nsIDOMWindowCollection.idl', 'nsIDOMWindowUtils.idl', 'nsIFocusManager.idl', 'nsIFrameRequestCallback.idl', 'nsIIdleObserver.idl', 'nsIQueryContentEventResult.idl', - 'nsIRemoteBrowser.idl', 'nsIServiceWorkerManager.idl', 'nsIStructuredCloneContainer.idl', 'nsITabChild.idl', 'nsITabParent.idl', ] XPIDL_MODULE = 'dom_base'
deleted file mode 100644 --- a/dom/interfaces/base/nsIRemoteBrowser.idl +++ /dev/null @@ -1,26 +0,0 @@ -/* This Source Code Form is subject to the terms of the Mozilla Public - * License, v. 2.0. If a copy of the MPL was not distributed with this - * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ - -#include "nsISupports.idl" - -[scriptable, uuid(C8379366-F79F-4D25-89A6-22BEC0A93D16)] -interface nsIRemoteBrowser : nsISupports -{ - /* - * Called by the child to inform the parent that a command update has occurred - * and the supplied set of commands are now enabled and disabled. - * - * @param action command updater action - * @param enabledLength length of enabledCommands array - * @param enabledCommands commands to enable - * @param disabledLength length of disabledCommands array - * @param disabledCommand commands to disable - */ - void enableDisableCommands(in AString action, - in unsigned long enabledLength, - [array, size_is(enabledLength)] in string enabledCommands, - in unsigned long disabledLength, - [array, size_is(disabledLength)] in string disabledCommands); -}; -
--- a/dom/interfaces/base/nsITabChild.idl +++ b/dom/interfaces/base/nsITabChild.idl @@ -2,25 +2,18 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "domstubs.idl" interface nsIContentFrameMessageManager; interface nsIWebBrowserChrome3; -native CommandsArray(nsTArray<nsCString>); -[ref] native CommandsArrayRef(nsTArray<nsCString>); - -[scriptable, uuid(7227bac4-b6fe-4090-aeb4-bc288b790925)] +[scriptable, uuid(2eb3bc54-78bf-40f2-b301-a5b5b70f7da0)] interface nsITabChild : nsISupports { readonly attribute nsIContentFrameMessageManager messageManager; attribute nsIWebBrowserChrome3 webBrowserChrome; [notxpcom] void sendRequestFocus(in boolean canFocus); - - [noscript, notxpcom] void enableDisableCommands(in AString action, - in CommandsArrayRef enabledCommands, - in CommandsArrayRef disabledCommands); };
--- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -239,24 +239,16 @@ parent: prio(urgent) sync EndIMEComposition(bool cancel) returns (nsString composition); /** * Request that the parent process move focus to the browser's frame. If * canRaise is true, the window can be raised if it is inactive. */ RequestFocus(bool canRaise); - /** - * Indicate, based on the current state, that some commands are enabled and - * some are disabled. - */ - EnableDisableCommands(nsString action, - nsCString[] enabledCommands, - nsCString[] disabledCommands); - prio(urgent) sync GetInputContext() returns (int32_t IMEEnabled, int32_t IMEOpen, intptr_t NativeIMEContext); prio(urgent) async SetInputContext(int32_t IMEEnabled, int32_t IMEOpen, nsString type, nsString inputmode,
--- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -3221,25 +3221,16 @@ TabChild::SetWebBrowserChrome(nsIWebBrow } void TabChild::SendRequestFocus(bool aCanFocus) { PBrowserChild::SendRequestFocus(aCanFocus); } -void -TabChild::EnableDisableCommands(const nsAString& aAction, - nsTArray<nsCString>& aEnabledCommands, - nsTArray<nsCString>& aDisabledCommands) -{ - PBrowserChild::SendEnableDisableCommands(PromiseFlatString(aAction), - aEnabledCommands, aDisabledCommands); -} - bool TabChild::DoSendBlockingMessage(JSContext* aCx, const nsAString& aMessage, const StructuredCloneData& aData, JS::Handle<JSObject *> aCpows, nsIPrincipal* aPrincipal, InfallibleTArray<nsString>* aJSONRetVal, bool aIsSync)
--- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -42,17 +42,16 @@ #include "nsIInterfaceRequestorUtils.h" #include "nsILoadInfo.h" #include "nsIPromptFactory.h" #include "nsIURI.h" #include "nsIWebBrowserChrome.h" #include "nsIWindowCreator2.h" #include "nsIXULBrowserWindow.h" #include "nsIXULWindow.h" -#include "nsIRemoteBrowser.h" #include "nsViewManager.h" #include "nsIWidget.h" #include "nsIWindowWatcher.h" #include "nsOpenURIInFrameParams.h" #include "nsPIDOMWindow.h" #include "nsPIWindowWatcher.h" #include "nsPresShell.h" #include "nsPrintfCString.h" @@ -1463,47 +1462,16 @@ TabParent::RecvRequestFocus(const bool& if (aCanRaise) flags |= nsIFocusManager::FLAG_RAISE; nsCOMPtr<nsIDOMElement> node = do_QueryInterface(mFrameElement); fm->SetFocus(node, flags); return true; } -bool -TabParent::RecvEnableDisableCommands(const nsString& aAction, - const nsTArray<nsCString>& aEnabledCommands, - const nsTArray<nsCString>& aDisabledCommands) -{ - nsCOMPtr<nsIRemoteBrowser> remoteBrowser = do_QueryInterface(mFrameElement); - if (remoteBrowser) { - nsAutoArrayPtr<const char*> enabledCommands, disabledCommands; - - if (aEnabledCommands.Length()) { - enabledCommands = new const char* [aEnabledCommands.Length()]; - for (uint32_t c = 0; c < aEnabledCommands.Length(); c++) { - enabledCommands[c] = aEnabledCommands[c].get(); - } - } - - if (aDisabledCommands.Length()) { - disabledCommands = new const char* [aDisabledCommands.Length()]; - for (uint32_t c = 0; c < aDisabledCommands.Length(); c++) { - disabledCommands[c] = aDisabledCommands[c].get(); - } - } - - remoteBrowser->EnableDisableCommands(aAction, - aEnabledCommands.Length(), enabledCommands, - aDisabledCommands.Length(), disabledCommands); - } - - return true; -} - nsIntPoint TabParent::GetChildProcessOffset() { // The "toplevel widget" in child processes is always at position // 0,0. Map the event coordinates to match that. nsIntPoint offset(0, 0); nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
--- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -186,19 +186,16 @@ public: virtual bool RecvSetInputContext(const int32_t& aIMEEnabled, const int32_t& aIMEOpen, const nsString& aType, const nsString& aInputmode, const nsString& aActionHint, const int32_t& aCause, const int32_t& aFocusChange) MOZ_OVERRIDE; virtual bool RecvRequestFocus(const bool& aCanRaise) MOZ_OVERRIDE; - virtual bool RecvEnableDisableCommands(const nsString& aAction, - const nsTArray<nsCString>& aEnabledCommands, - const nsTArray<nsCString>& aDisabledCommands) MOZ_OVERRIDE; virtual bool RecvSetCursor(const uint32_t& aValue, const bool& aForce) MOZ_OVERRIDE; virtual bool RecvSetBackgroundColor(const nscolor& aValue) MOZ_OVERRIDE; virtual bool RecvSetStatus(const uint32_t& aType, const nsString& aStatus) MOZ_OVERRIDE; virtual bool RecvIsParentWindowMainWidgetVisible(bool* aIsVisible); virtual bool RecvShowTooltip(const uint32_t& aX, const uint32_t& aY, const nsString& aTooltip); virtual bool RecvHideTooltip(); virtual bool RecvGetDPI(float* aValue) MOZ_OVERRIDE; virtual bool RecvGetDefaultScale(double* aValue) MOZ_OVERRIDE;
--- a/dom/media/MediaDataDecodedListener.h +++ b/dom/media/MediaDataDecodedListener.h @@ -15,18 +15,16 @@ namespace mozilla { class MediaDecoderStateMachine; class MediaData; // A RequestSampleCallback implementation that forwards samples onto the // MediaDecoderStateMachine via tasks that run on the supplied task queue. template<class Target> class MediaDataDecodedListener : public RequestSampleCallback { public: - using RequestSampleCallback::NotDecodedReason; - MediaDataDecodedListener(Target* aTarget, MediaTaskQueue* aTaskQueue) : mMonitor("MediaDataDecodedListener") , mTaskQueue(aTaskQueue) , mTarget(aTarget) { MOZ_ASSERT(aTarget); MOZ_ASSERT(aTaskQueue); @@ -47,17 +45,18 @@ public: if (!mTarget || !mTaskQueue) { // We've been shutdown, abort. return; } RefPtr<nsIRunnable> task(new DeliverVideoTask(aSample, mTarget)); mTaskQueue->Dispatch(task); } - virtual void OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason) MOZ_OVERRIDE { + virtual void OnNotDecoded(MediaData::Type aType, + MediaDecoderReader::NotDecodedReason aReason) MOZ_OVERRIDE { MonitorAutoLock lock(mMonitor); if (!mTarget || !mTaskQueue) { // We've been shutdown, abort. return; } RefPtr<nsIRunnable> task(new DeliverNotDecodedTask(aType, aReason, mTarget)); mTaskQueue->Dispatch(task); } @@ -128,17 +127,17 @@ private: private: nsRefPtr<VideoData> mSample; RefPtr<Target> mTarget; }; class DeliverNotDecodedTask : public nsRunnable { public: DeliverNotDecodedTask(MediaData::Type aType, - RequestSampleCallback::NotDecodedReason aReason, + MediaDecoderReader::NotDecodedReason aReason, Target* aTarget) : mType(aType) , mReason(aReason) , mTarget(aTarget) { MOZ_COUNT_CTOR(DeliverNotDecodedTask); } protected: @@ -148,17 +147,17 @@ private: } public: NS_METHOD Run() { mTarget->OnNotDecoded(mType, mReason); return NS_OK; } private: MediaData::Type mType; - RequestSampleCallback::NotDecodedReason mReason; + MediaDecoderReader::NotDecodedReason mReason; RefPtr<Target> mTarget; }; Monitor mMonitor; RefPtr<MediaTaskQueue> mTaskQueue; RefPtr<Target> mTarget; };
--- a/dom/media/MediaDecoder.cpp +++ b/dom/media/MediaDecoder.cpp @@ -456,17 +456,16 @@ MediaDecoder::MediaDecoder() : MOZ_COUNT_CTOR(MediaDecoder); MOZ_ASSERT(NS_IsMainThread()); MediaMemoryTracker::AddMediaDecoder(this); #ifdef PR_LOGGING if (!gMediaDecoderLog) { gMediaDecoderLog = PR_NewLogModule("MediaDecoder"); } #endif - mAudioChannel = AudioChannelService::GetDefaultAudioChannel(); } bool MediaDecoder::Init(MediaDecoderOwner* aOwner) { MOZ_ASSERT(NS_IsMainThread()); mOwner = aOwner; mVideoFrameContainer = aOwner->GetVideoFrameContainer();
--- a/dom/media/MediaDecoderReader.cpp +++ b/dom/media/MediaDecoderReader.cpp @@ -22,16 +22,26 @@ namespace mozilla { #ifdef PR_LOGGING extern PRLogModuleInfo* gMediaDecoderLog; #define DECODER_LOG(x, ...) \ PR_LOG(gMediaDecoderLog, PR_LOG_DEBUG, ("Decoder=%p " x, mDecoder, ##__VA_ARGS__)) #else #define DECODER_LOG(x, ...) #endif +PRLogModuleInfo* gMediaPromiseLog; + +void +EnsureMediaPromiseLog() +{ + if (!gMediaPromiseLog) { + gMediaPromiseLog = PR_NewLogModule("MediaPromise"); + } +} + class VideoQueueMemoryFunctor : public nsDequeFunctor { public: VideoQueueMemoryFunctor() : mSize(0) {} MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf); virtual void* operator()(void* aObject) { const VideoData* v = static_cast<const VideoData*>(aObject); @@ -64,16 +74,17 @@ MediaDecoderReader::MediaDecoderReader(A , mIgnoreAudioOutputFormat(false) , mStartTime(-1) , mTaskQueueIsBorrowed(false) , mAudioDiscontinuity(false) , mVideoDiscontinuity(false) , mShutdown(false) { MOZ_COUNT_CTOR(MediaDecoderReader); + EnsureMediaPromiseLog(); } MediaDecoderReader::~MediaDecoderReader() { MOZ_ASSERT(mShutdown); ResetDecode(); MOZ_COUNT_DTOR(MediaDecoderReader); } @@ -199,17 +210,17 @@ MediaDecoderReader::RequestVideoData(boo if (VideoQueue().GetSize() > 0) { nsRefPtr<VideoData> v = VideoQueue().PopFront(); if (v && mVideoDiscontinuity) { v->mDiscontinuity = true; mVideoDiscontinuity = false; } GetCallback()->OnVideoDecoded(v); } else if (VideoQueue().IsFinished()) { - GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, RequestSampleCallback::END_OF_STREAM); + GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, END_OF_STREAM); } } void MediaDecoderReader::RequestAudioData() { while (AudioQueue().GetSize() == 0 && !AudioQueue().IsFinished()) { @@ -232,17 +243,17 @@ MediaDecoderReader::RequestAudioData() nsRefPtr<AudioData> a = AudioQueue().PopFront(); if (mAudioDiscontinuity) { a->mDiscontinuity = true; mAudioDiscontinuity = false; } GetCallback()->OnAudioDecoded(a); return; } else if (AudioQueue().IsFinished()) { - GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::END_OF_STREAM); + GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, END_OF_STREAM); return; } } void MediaDecoderReader::SetCallback(RequestSampleCallback* aCallback) { mSampleDecodedCallback = aCallback; @@ -302,22 +313,23 @@ AudioDecodeRendezvous::OnAudioDecoded(Au MonitorAutoLock mon(mMonitor); mSample = aSample; mStatus = NS_OK; mHaveResult = true; mon.NotifyAll(); } void -AudioDecodeRendezvous::OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason) +AudioDecodeRendezvous::OnNotDecoded(MediaData::Type aType, + MediaDecoderReader::NotDecodedReason aReason) { MOZ_ASSERT(aType == MediaData::AUDIO_DATA); MonitorAutoLock mon(mMonitor); mSample = nullptr; - mStatus = aReason == DECODE_ERROR ? NS_ERROR_FAILURE : NS_OK; + mStatus = aReason == MediaDecoderReader::DECODE_ERROR ? NS_ERROR_FAILURE : NS_OK; mHaveResult = true; mon.NotifyAll(); } void AudioDecodeRendezvous::Reset() { MonitorAutoLock mon(mMonitor);
--- a/dom/media/MediaDecoderReader.h +++ b/dom/media/MediaDecoderReader.h @@ -25,16 +25,23 @@ class SharedDecoderManager; // Encapsulates the decoding and reading of media data. Reading can either // synchronous and done on the calling "decode" thread, or asynchronous and // performed on a background thread, with the result being returned by // callback. Never hold the decoder monitor when calling into this class. // Unless otherwise specified, methods and fields of this class can only // be accessed on the decode task queue. class MediaDecoderReader { public: + enum NotDecodedReason { + END_OF_STREAM, + DECODE_ERROR, + WAITING_FOR_DATA, + CANCELED + }; + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDecoderReader) explicit MediaDecoderReader(AbstractMediaDecoder* aDecoder); // Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE // on failure. virtual nsresult Init(MediaDecoderReader* aCloneDonor) = 0; @@ -285,58 +292,51 @@ private: // Interface that callers to MediaDecoderReader::Request{Audio,Video}Data() // must implement to receive the requested samples asynchronously. // This object is refcounted, and cycles must be broken by calling // BreakCycles() during shutdown. class RequestSampleCallback { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(RequestSampleCallback) - enum NotDecodedReason { - END_OF_STREAM, - DECODE_ERROR, - WAITING_FOR_DATA, - CANCELED - }; - // Receives the result of a RequestAudioData() call. virtual void OnAudioDecoded(AudioData* aSample) = 0; // Receives the result of a RequestVideoData() call. virtual void OnVideoDecoded(VideoData* aSample) = 0; // Called when a RequestAudioData() or RequestVideoData() call can't be // fulfiled. The reason is passed as aReason. - virtual void OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason) = 0; + virtual void OnNotDecoded(MediaData::Type aType, + MediaDecoderReader::NotDecodedReason aReason) = 0; virtual void OnSeekCompleted(nsresult aResult) = 0; // Called during shutdown to break any reference cycles. virtual void BreakCycles() = 0; protected: virtual ~RequestSampleCallback() {} }; // A RequestSampleCallback implementation that can be passed to the // MediaDecoderReader to block the thread requesting an audio sample until // the audio decode is complete. This is used to adapt the asynchronous // model of the MediaDecoderReader to a synchronous model. class AudioDecodeRendezvous : public RequestSampleCallback { public: - using RequestSampleCallback::NotDecodedReason; - AudioDecodeRendezvous(); ~AudioDecodeRendezvous(); // RequestSampleCallback implementation. Called when decode is complete. // Note: aSample is null at end of stream. virtual void OnAudioDecoded(AudioData* aSample) MOZ_OVERRIDE; virtual void OnVideoDecoded(VideoData* aSample) MOZ_OVERRIDE {} - virtual void OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason) MOZ_OVERRIDE; + virtual void OnNotDecoded(MediaData::Type aType, + MediaDecoderReader::NotDecodedReason aReason) MOZ_OVERRIDE; virtual void OnSeekCompleted(nsresult aResult) MOZ_OVERRIDE {}; virtual void BreakCycles() MOZ_OVERRIDE {}; void Reset(); // Returns failure on error, or NS_OK. // If *aSample is null, EOS has been reached. nsresult Await(nsRefPtr<AudioData>& aSample);
--- a/dom/media/MediaDecoderStateMachine.cpp +++ b/dom/media/MediaDecoderStateMachine.cpp @@ -800,56 +800,56 @@ MediaDecoderStateMachine::Push(VideoData UpdateReadyState(); DispatchDecodeTasksIfNeeded(); mDecoder->GetReentrantMonitor().NotifyAll(); } } void MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType, - RequestSampleCallback::NotDecodedReason aReason) + MediaDecoderReader::NotDecodedReason aReason) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); SAMPLE_LOG("OnNotDecoded (aType=%u, aReason=%u)", aType, aReason); bool isAudio = aType == MediaData::AUDIO_DATA; MOZ_ASSERT_IF(!isAudio, aType == MediaData::VIDEO_DATA); // This callback means that the pending request is dead. if (isAudio) { mAudioRequestPending = false; } else { mVideoRequestPending = false; } // If this is a decode error, delegate to the generic error path. - if (aReason == RequestSampleCallback::DECODE_ERROR) { + if (aReason == MediaDecoderReader::DECODE_ERROR) { DecodeError(); return; } // If the decoder is waiting for data, we need to make sure that the requests // are cleared, which happened above. Additionally, if we're out of decoded // samples, we need to switch to buffering mode. - if (aReason == RequestSampleCallback::WAITING_FOR_DATA) { + if (aReason == MediaDecoderReader::WAITING_FOR_DATA) { bool outOfSamples = isAudio ? !AudioQueue().GetSize() : !VideoQueue().GetSize(); if (outOfSamples) { StartBuffering(); } return; } - if (aReason == RequestSampleCallback::CANCELED) { + if (aReason == MediaDecoderReader::CANCELED) { DispatchDecodeTasksIfNeeded(); return; } // This is an EOS. Finish off the queue, and then handle things based on our // state. - MOZ_ASSERT(aReason == RequestSampleCallback::END_OF_STREAM); + MOZ_ASSERT(aReason == MediaDecoderReader::END_OF_STREAM); if (!isAudio && mState == DECODER_STATE_SEEKING && mCurrentSeekTarget.IsValid() && mFirstVideoFrameAfterSeek) { // Null sample. Hit end of stream. If we have decoded a frame, // insert it into the queue so that we have something to display. // We make sure to do this before invoking VideoQueue().Finish() // below. VideoQueue().Push(mFirstVideoFrameAfterSeek); mFirstVideoFrameAfterSeek = nullptr;
--- a/dom/media/MediaDecoderStateMachine.h +++ b/dom/media/MediaDecoderStateMachine.h @@ -368,17 +368,17 @@ public: // decoded we preroll, until playback starts. The first time playback starts // the state machine is free to return to prerolling normally. Note // "prerolling" in this context refers to when we decode and buffer decoded // samples in advance of when they're needed for playback. void SetMinimizePrerollUntilPlaybackStarts(); void OnAudioDecoded(AudioData* aSample); void OnVideoDecoded(VideoData* aSample); - void OnNotDecoded(MediaData::Type aType, RequestSampleCallback::NotDecodedReason aReason); + void OnNotDecoded(MediaData::Type aType, MediaDecoderReader::NotDecodedReason aReason); void OnSeekCompleted(nsresult aResult); private: void AcquireMonitorAndInvokeDecodeError(); protected: virtual ~MediaDecoderStateMachine();
new file mode 100644 --- /dev/null +++ b/dom/media/MediaPromise.cpp @@ -0,0 +1,27 @@ +/* -*- 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/. */ + +#include "MediaPromise.h" +#include "MediaTaskQueue.h" +#include "nsThreadUtils.h" + +namespace mozilla { +namespace detail { + +nsresult +DispatchMediaPromiseRunnable(MediaTaskQueue* aTaskQueue, nsIRunnable* aRunnable) +{ + return aTaskQueue->ForceDispatch(aRunnable); +} + +nsresult +DispatchMediaPromiseRunnable(nsIEventTarget* aEventTarget, nsIRunnable* aRunnable) +{ + return aEventTarget->Dispatch(aRunnable, NS_DISPATCH_NORMAL); +} + +} +} // namespace mozilla
new file mode 100644 --- /dev/null +++ b/dom/media/MediaPromise.h @@ -0,0 +1,394 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et cindent: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#if !defined(MediaPromise_h_) +#define MediaPromise_h_ + +#include "prlog.h" + +#include "nsTArray.h" +#include "nsThreadUtils.h" + +#include "mozilla/DebugOnly.h" +#include "mozilla/Maybe.h" +#include "mozilla/Mutex.h" +#include "mozilla/Monitor.h" + +/* Polyfill __func__ on MSVC for consumers to pass to the MediaPromise API. */ +#ifdef _MSC_VER +#define __func__ __FUNCTION__ +#endif + +class nsIEventTarget; +namespace mozilla { + +extern PRLogModuleInfo* gMediaPromiseLog; +void EnsureMediaPromiseLog(); + +#define PROMISE_LOG(x, ...) \ + MOZ_ASSERT(gMediaPromiseLog); \ + PR_LOG(gMediaPromiseLog, PR_LOG_DEBUG, (x, ##__VA_ARGS__)) + +class MediaTaskQueue; +namespace detail { + +nsresult DispatchMediaPromiseRunnable(MediaTaskQueue* aQueue, nsIRunnable* aRunnable); +nsresult DispatchMediaPromiseRunnable(nsIEventTarget* aTarget, nsIRunnable* aRunnable); + +} // namespace detail + +/* + * A promise manages an asynchronous request that may or may not be able to be + * fulfilled immediately. When an API returns a promise, the consumer may attach + * callbacks to be invoked (asynchronously, on a specified thread) when the + * request is either completed (resolved) or cannot be completed (rejected). + * + * By default, resolve and reject callbacks are always invoked on the same thread + * where Then() was invoked. + */ +template<typename T> class MediaPromiseHolder; +template<typename ResolveValueT, typename RejectValueT> +class MediaPromise +{ +public: + typedef ResolveValueT ResolveValueType; + typedef RejectValueT RejectValueType; + + NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaPromise) + MediaPromise(const char* aCreationSite) + : mCreationSite(aCreationSite) + , mMutex("MediaPromise Mutex") + { + MOZ_COUNT_CTOR(MediaPromise); + PROMISE_LOG("%s creating MediaPromise (%p)", mCreationSite, this); + } + +protected: + + /* + * A ThenValue tracks a single consumer waiting on the promise. When a consumer + * invokes promise->Then(...), a ThenValue is created. Once the Promise is + * resolved or rejected, a {Resolve,Reject}Runnable is dispatched, which + * invokes the resolve/reject method and then deletes the ThenValue. + */ + class ThenValueBase + { + public: + class ResolveRunnable : public nsRunnable + { + public: + ResolveRunnable(ThenValueBase* aThenValue, ResolveValueType aResolveValue) + : mThenValue(aThenValue) + , mResolveValue(aResolveValue) + { + MOZ_COUNT_CTOR(ResolveRunnable); + } + + ~ResolveRunnable() + { + MOZ_COUNT_DTOR(ResolveRunnable); + MOZ_ASSERT(!mThenValue); + } + + NS_IMETHODIMP Run() + { + PROMISE_LOG("ResolveRunnable::Run() [this=%p]", this); + mThenValue->DoResolve(mResolveValue); + + delete mThenValue; + mThenValue = nullptr; + return NS_OK; + } + + private: + ThenValueBase* mThenValue; + ResolveValueType mResolveValue; + }; + + class RejectRunnable : public nsRunnable + { + public: + RejectRunnable(ThenValueBase* aThenValue, RejectValueType aRejectValue) + : mThenValue(aThenValue) + , mRejectValue(aRejectValue) + { + MOZ_COUNT_CTOR(RejectRunnable); + } + + ~RejectRunnable() + { + MOZ_COUNT_DTOR(RejectRunnable); + MOZ_ASSERT(!mThenValue); + } + + NS_IMETHODIMP Run() + { + PROMISE_LOG("RejectRunnable::Run() [this=%p]", this); + mThenValue->DoReject(mRejectValue); + + delete mThenValue; + mThenValue = nullptr; + return NS_OK; + } + + private: + ThenValueBase* mThenValue; + RejectValueType mRejectValue; + }; + + ThenValueBase(const char* aCallSite) : mCallSite(aCallSite) + { + MOZ_COUNT_CTOR(ThenValueBase); + } + + virtual void Dispatch(MediaPromise *aPromise) = 0; + + protected: + // This may only be deleted by {Resolve,Reject}Runnable::Run. + virtual ~ThenValueBase() { MOZ_COUNT_DTOR(ThenValueBase); } + + virtual void DoResolve(ResolveValueType aResolveValue) = 0; + virtual void DoReject(RejectValueType aRejectValue) = 0; + + const char* mCallSite; + }; + + template<typename TargetType, typename ThisType, + typename ResolveMethodType, typename RejectMethodType> + class ThenValue : public ThenValueBase + { + public: + ThenValue(TargetType* aResponseTarget, ThisType* aThisVal, + ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod, + const char* aCallSite) + : ThenValueBase(aCallSite) + , mResponseTarget(aResponseTarget) + , mThisVal(aThisVal) + , mResolveMethod(aResolveMethod) + , mRejectMethod(aRejectMethod) {} + + void Dispatch(MediaPromise *aPromise) MOZ_OVERRIDE + { + aPromise->mMutex.AssertCurrentThreadOwns(); + MOZ_ASSERT(!aPromise->IsPending()); + bool resolved = aPromise->mResolveValue.isSome(); + nsRefPtr<nsRunnable> runnable = + resolved ? static_cast<nsRunnable*>(new (typename ThenValueBase::ResolveRunnable)(this, aPromise->mResolveValue.ref())) + : static_cast<nsRunnable*>(new (typename ThenValueBase::RejectRunnable)(this, aPromise->mRejectValue.ref())); + PROMISE_LOG("%s Then() call made from %s [Runnable=%p, Promise=%p, ThenValue=%p]", + resolved ? "Resolving" : "Rejecting", ThenValueBase::mCallSite, + runnable.get(), aPromise, this); + DebugOnly<nsresult> rv = detail::DispatchMediaPromiseRunnable(mResponseTarget, runnable); + MOZ_ASSERT(NS_SUCCEEDED(rv)); + } + + protected: + virtual void DoResolve(ResolveValueType aResolveValue) + { + ((*mThisVal).*mResolveMethod)(aResolveValue); + } + + virtual void DoReject(RejectValueType aRejectValue) + { + ((*mThisVal).*mRejectMethod)(aRejectValue); + } + + virtual ~ThenValue() {} + + private: + nsRefPtr<TargetType> mResponseTarget; + nsRefPtr<ThisType> mThisVal; + ResolveMethodType mResolveMethod; + RejectMethodType mRejectMethod; + }; +public: + + template<typename TargetType, typename ThisType, + typename ResolveMethodType, typename RejectMethodType> + void Then(TargetType* aResponseTarget, const char* aCallSite, ThisType* aThisVal, + ResolveMethodType aResolveMethod, RejectMethodType aRejectMethod) + { + MutexAutoLock lock(mMutex); + ThenValueBase* thenValue = new ThenValue<TargetType, ThisType, ResolveMethodType, + RejectMethodType>(aResponseTarget, aThisVal, + aResolveMethod, aRejectMethod, + aCallSite); + PROMISE_LOG("%s invoking Then() [this=%p, thenValue=%p, aThisVal=%p, isPending=%d]", + aCallSite, this, thenValue, aThisVal, (int) IsPending()); + if (!IsPending()) { + thenValue->Dispatch(this); + } else { + mThenValues.AppendElement(thenValue); + } + } + + void ChainTo(already_AddRefed<MediaPromise> aChainedPromise, const char* aCallSite) + { + MutexAutoLock lock(mMutex); + nsRefPtr<MediaPromise> chainedPromise = aChainedPromise; + PROMISE_LOG("%s invoking Chain() [this=%p, chainedPromise=%p, isPending=%d]", + aCallSite, this, chainedPromise.get(), (int) IsPending()); + if (!IsPending()) { + ForwardTo(chainedPromise); + } else { + mChainedPromises.AppendElement(chainedPromise); + } + } + + void Resolve(ResolveValueType aResolveValue, const char* aResolveSite) + { + MutexAutoLock lock(mMutex); + MOZ_ASSERT(IsPending()); + PROMISE_LOG("%s resolving MediaPromise (%p created at %s)", aResolveSite, this, mCreationSite); + mResolveValue.emplace(aResolveValue); + DispatchAll(); + } + + void Reject(RejectValueType aRejectValue, const char* aRejectSite) + { + MutexAutoLock lock(mMutex); + MOZ_ASSERT(IsPending()); + PROMISE_LOG("%s rejecting MediaPromise (%p created at %s)", aRejectSite, this, mCreationSite); + mRejectValue.emplace(aRejectValue); + DispatchAll(); + } + +protected: + bool IsPending() { return mResolveValue.isNothing() && mRejectValue.isNothing(); } + void DispatchAll() + { + mMutex.AssertCurrentThreadOwns(); + for (size_t i = 0; i < mThenValues.Length(); ++i) + mThenValues[i]->Dispatch(this); + mThenValues.Clear(); + + for (size_t i = 0; i < mChainedPromises.Length(); ++i) { + ForwardTo(mChainedPromises[i]); + } + mChainedPromises.Clear(); + } + + void ForwardTo(MediaPromise* aOther) + { + MOZ_ASSERT(!IsPending()); + if (mResolveValue.isSome()) { + aOther->Resolve(mResolveValue.ref(), "<chained promise>"); + } else { + aOther->Reject(mRejectValue.ref(), "<chained promise>"); + } + } + + ~MediaPromise() + { + MOZ_COUNT_DTOR(MediaPromise); + PROMISE_LOG("MediaPromise::~MediaPromise [this=%p]", this); + MOZ_ASSERT(!IsPending()); + MOZ_ASSERT(mThenValues.IsEmpty()); + MOZ_ASSERT(mChainedPromises.IsEmpty()); + }; + + const char* mCreationSite; // For logging + Mutex mMutex; + Maybe<ResolveValueType> mResolveValue; + Maybe<RejectValueType> mRejectValue; + nsTArray<ThenValueBase*> mThenValues; + nsTArray<nsRefPtr<MediaPromise>> mChainedPromises; +}; + +/* + * Class to encapsulate a promise for a particular role. Use this as the member + * variable for a class whose method returns a promise. + */ +template<typename PromiseType> +class MediaPromiseHolder +{ +public: + MediaPromiseHolder() + : mMonitor(nullptr) {} + + ~MediaPromiseHolder() { MOZ_ASSERT(!mPromise); } + + already_AddRefed<PromiseType> Ensure(const char* aMethodName) { + if (mMonitor) { + mMonitor->AssertCurrentThreadOwns(); + } + if (!mPromise) { + mPromise = new PromiseType(aMethodName); + } + nsRefPtr<PromiseType> p = mPromise; + return p.forget(); + } + + // Provide a Monitor that should always be held when accessing this instance. + void SetMonitor(Monitor* aMonitor) { mMonitor = aMonitor; } + + bool IsEmpty() + { + if (mMonitor) { + mMonitor->AssertCurrentThreadOwns(); + } + return !mPromise; + } + + already_AddRefed<PromiseType> Steal() + { + if (mMonitor) { + mMonitor->AssertCurrentThreadOwns(); + } + + nsRefPtr<PromiseType> p = mPromise; + mPromise = nullptr; + return p.forget(); + } + + void Resolve(typename PromiseType::ResolveValueType aResolveValue, + const char* aMethodName) + { + if (mMonitor) { + mMonitor->AssertCurrentThreadOwns(); + } + MOZ_ASSERT(mPromise); + mPromise->Resolve(aResolveValue, aMethodName); + mPromise = nullptr; + } + + void ResolveIfExists(typename PromiseType::ResolveValueType aResolveValue, + const char* aMethodName) + { + if (!IsEmpty()) { + Resolve(aResolveValue, aMethodName); + } + } + + void Reject(typename PromiseType::RejectValueType aRejectValue, + const char* aMethodName) + { + if (mMonitor) { + mMonitor->AssertCurrentThreadOwns(); + } + MOZ_ASSERT(mPromise); + mPromise->Reject(aRejectValue, aMethodName); + mPromise = nullptr; + } + + void RejectIfExists(typename PromiseType::RejectValueType aRejectValue, + const char* aMethodName) + { + if (!IsEmpty()) { + Reject(aRejectValue, aMethodName); + } + } + +private: + Monitor* mMonitor; + nsRefPtr<PromiseType> mPromise; +}; + +#undef PROMISE_LOG + +} // namespace mozilla + +#endif
--- a/dom/media/MediaTaskQueue.cpp +++ b/dom/media/MediaTaskQueue.cpp @@ -30,27 +30,34 @@ MediaTaskQueue::~MediaTaskQueue() nsresult MediaTaskQueue::Dispatch(TemporaryRef<nsIRunnable> aRunnable) { MonitorAutoLock mon(mQueueMonitor); return DispatchLocked(aRunnable, AbortIfFlushing); } nsresult +MediaTaskQueue::ForceDispatch(TemporaryRef<nsIRunnable> aRunnable) +{ + MonitorAutoLock mon(mQueueMonitor); + return DispatchLocked(aRunnable, Forced); +} + +nsresult MediaTaskQueue::DispatchLocked(TemporaryRef<nsIRunnable> aRunnable, DispatchMode aMode) { mQueueMonitor.AssertCurrentThreadOwns(); if (mIsFlushing && aMode == AbortIfFlushing) { return NS_ERROR_ABORT; } if (mIsShutdown) { return NS_ERROR_FAILURE; } - mTasks.push(aRunnable); + mTasks.push(TaskQueueEntry(aRunnable, aMode == Forced)); if (mIsRunning) { return NS_OK; } RefPtr<nsIRunnable> runner(new Runner(this)); nsresult rv = mPool->Dispatch(runner, NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) { NS_WARNING("Failed to dispatch runnable to run MediaTaskQueue"); return rv; @@ -135,34 +142,47 @@ MediaTaskQueue::BeginShutdown() mon.NotifyAll(); } nsresult MediaTaskQueue::FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable) { MonitorAutoLock mon(mQueueMonitor); AutoSetFlushing autoFlush(this); - while (!mTasks.empty()) { - mTasks.pop(); - } + FlushLocked(); nsresult rv = DispatchLocked(aRunnable, IgnoreFlushing); NS_ENSURE_SUCCESS(rv, rv); AwaitIdleLocked(); return NS_OK; } void MediaTaskQueue::Flush() { MonitorAutoLock mon(mQueueMonitor); AutoSetFlushing autoFlush(this); - while (!mTasks.empty()) { + FlushLocked(); + AwaitIdleLocked(); +} + +void +MediaTaskQueue::FlushLocked() +{ + mQueueMonitor.AssertCurrentThreadOwns(); + MOZ_ASSERT(mIsFlushing); + + // Clear the tasks, but preserve those with mForceDispatch by re-appending + // them to the queue. + size_t numTasks = mTasks.size(); + for (size_t i = 0; i < numTasks; ++i) { + if (mTasks.front().mForceDispatch) { + mTasks.push(mTasks.front()); + } mTasks.pop(); } - AwaitIdleLocked(); } bool MediaTaskQueue::IsEmpty() { MonitorAutoLock mon(mQueueMonitor); return mTasks.empty(); } @@ -186,17 +206,17 @@ MediaTaskQueue::Runner::Run() MonitorAutoLock mon(mQueue->mQueueMonitor); MOZ_ASSERT(mQueue->mIsRunning); mQueue->mRunningThread = NS_GetCurrentThread(); if (mQueue->mTasks.size() == 0) { mQueue->mIsRunning = false; mon.NotifyAll(); return NS_OK; } - event = mQueue->mTasks.front(); + event = mQueue->mTasks.front().mRunnable; mQueue->mTasks.pop(); } MOZ_ASSERT(event); // Note that dropping the queue monitor before running the task, and // taking the monitor again after the task has run ensures we have memory // fences enforced. This means that if the object we're calling wasn't // designed to be threadsafe, it will be, provided we're only calling it
--- a/dom/media/MediaTaskQueue.h +++ b/dom/media/MediaTaskQueue.h @@ -29,16 +29,20 @@ class MediaTaskQueue MOZ_FINAL { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaTaskQueue) explicit MediaTaskQueue(TemporaryRef<SharedThreadPool> aPool); nsresult Dispatch(TemporaryRef<nsIRunnable> aRunnable); + // This should only be used for things that absolutely can't afford to be + // flushed. Normal operations should use Dispatch. + nsresult ForceDispatch(TemporaryRef<nsIRunnable> aRunnable); + nsresult SyncDispatch(TemporaryRef<nsIRunnable> aRunnable); nsresult FlushAndDispatch(TemporaryRef<nsIRunnable> aRunnable); // Removes all pending tasks from the task queue, and blocks until // the currently running task (if any) finishes. void Flush(); @@ -63,28 +67,37 @@ public: private: // Blocks until all task finish executing. Called internally by methods // that need to wait until the task queue is idle. // mQueueMonitor must be held. void AwaitIdleLocked(); - enum DispatchMode { AbortIfFlushing, IgnoreFlushing }; + enum DispatchMode { AbortIfFlushing, IgnoreFlushing, Forced }; nsresult DispatchLocked(TemporaryRef<nsIRunnable> aRunnable, DispatchMode aMode); + void FlushLocked(); RefPtr<SharedThreadPool> mPool; // Monitor that protects the queue and mIsRunning; Monitor mQueueMonitor; + struct TaskQueueEntry { + RefPtr<nsIRunnable> mRunnable; + bool mForceDispatch; + + TaskQueueEntry(TemporaryRef<nsIRunnable> aRunnable, bool aForceDispatch = false) + : mRunnable(aRunnable), mForceDispatch(aForceDispatch) {} + }; + // Queue of tasks to run. - std::queue<RefPtr<nsIRunnable>> mTasks; + std::queue<TaskQueueEntry> mTasks; // The thread currently running the task queue. We store a reference // to this so that IsCurrentThreadIn() can tell if the current thread // is the thread currently running in the task queue. RefPtr<nsIThread> mRunningThread; // True if we've dispatched an event to the pool to execute events from // the queue.
--- a/dom/media/PeerConnection.js +++ b/dom/media/PeerConnection.js @@ -20,17 +20,17 @@ const PC_ICE_CONTRACT = "@mozilla.org/do const PC_SESSION_CONTRACT = "@mozilla.org/dom/rtcsessiondescription;1"; const PC_MANAGER_CONTRACT = "@mozilla.org/dom/peerconnectionmanager;1"; const PC_STATS_CONTRACT = "@mozilla.org/dom/rtcstatsreport;1"; const PC_IDENTITY_CONTRACT = "@mozilla.org/dom/rtcidentityassertion;1"; const PC_STATIC_CONTRACT = "@mozilla.org/dom/peerconnectionstatic;1"; const PC_SENDER_CONTRACT = "@mozilla.org/dom/rtpsender;1"; const PC_RECEIVER_CONTRACT = "@mozilla.org/dom/rtpreceiver;1"; -const PC_CID = Components.ID("{00e0e20d-1494-4776-8e0e-0f0acbea3c79}"); +const PC_CID = Components.ID("{bdc2e533-b308-4708-ac8e-a8bfade6d851}"); const PC_OBS_CID = Components.ID("{d1748d4c-7f6a-4dc5-add6-d55b7678537e}"); const PC_ICE_CID = Components.ID("{02b9970c-433d-4cc2-923d-f7028ac66073}"); const PC_SESSION_CID = Components.ID("{1775081b-b62d-4954-8ffe-a067bbf508a7}"); const PC_MANAGER_CID = Components.ID("{7293e901-2be3-4c02-b4bd-cbef6fc24f78}"); const PC_STATS_CID = Components.ID("{7fe6e18b-0da3-4056-bf3b-440ef3809e06}"); const PC_IDENTITY_CID = Components.ID("{1abc7499-3c54-43e0-bd60-686e2703f072}"); const PC_STATIC_CID = Components.ID("{0fb47c47-a205-4583-a9fc-cbadf8c95880}"); const PC_SENDER_CID = Components.ID("{4fff5d46-d827-4cd4-a970-8fd53977440e}"); @@ -844,17 +844,17 @@ RTCPeerConnection.prototype = { }, _addIceCandidate: function(cand, onSuccess, onError) { this._onAddIceCandidateSuccess = onSuccess || null; this._onAddIceCandidateError = onError || null; this._impl.addIceCandidate(cand.candidate, cand.sdpMid || "", (cand.sdpMLineIndex === null) ? 0 : - cand.sdpMLineIndex + 1); + cand.sdpMLineIndex); }, addStream: function(stream) { stream.getTracks().forEach(track => this.addTrack(track, stream)); }, removeStream: function(stream) { // Bug 844295: Not implementing this functionality. @@ -1117,17 +1117,17 @@ PeerConnectionObserver.prototype = { this._dompc = dompc._innerObject; }, newError: function(code, message) { // These strings must match those defined in the WebRTC spec. const reasonName = [ "", "InternalError", - "InternalError", + "InvalidCandidateError", "InvalidParameter", "InvalidStateError", "InvalidSessionDescriptionError", "IncompatibleSessionDescriptionError", "InternalError", "IncompatibleMediaStreamTrackError", "InternalError" ]; @@ -1216,17 +1216,17 @@ PeerConnectionObserver.prototype = { onIceCandidate: function(level, mid, candidate) { if (candidate == "") { this.foundIceCandidate(null); } else { this.foundIceCandidate(new this._dompc._win.mozRTCIceCandidate( { candidate: candidate, sdpMid: mid, - sdpMLineIndex: level - 1 + sdpMLineIndex: level } )); } }, // This method is primarily responsible for updating iceConnectionState. // This state is defined in the WebRTC specification as follows:
--- a/dom/media/PeerConnection.manifest +++ b/dom/media/PeerConnection.manifest @@ -1,20 +1,20 @@ -component {00e0e20d-1494-4776-8e0e-0f0acbea3c79} PeerConnection.js +component {bdc2e533-b308-4708-ac8e-a8bfade6d851} PeerConnection.js component {d1748d4c-7f6a-4dc5-add6-d55b7678537e} PeerConnection.js component {02b9970c-433d-4cc2-923d-f7028ac66073} PeerConnection.js component {1775081b-b62d-4954-8ffe-a067bbf508a7} PeerConnection.js component {7293e901-2be3-4c02-b4bd-cbef6fc24f78} PeerConnection.js component {7fe6e18b-0da3-4056-bf3b-440ef3809e06} PeerConnection.js component {1abc7499-3c54-43e0-bd60-686e2703f072} PeerConnection.js component {0fb47c47-a205-4583-a9fc-cbadf8c95880} PeerConnection.js component {4fff5d46-d827-4cd4-a970-8fd53977440e} PeerConnection.js component {d974b814-8fde-411c-8c45-b86791b81030} PeerConnection.js -contract @mozilla.org/dom/peerconnection;1 {00e0e20d-1494-4776-8e0e-0f0acbea3c79} +contract @mozilla.org/dom/peerconnection;1 {bdc2e533-b308-4708-ac8e-a8bfade6d851} contract @mozilla.org/dom/peerconnectionobserver;1 {d1748d4c-7f6a-4dc5-add6-d55b7678537e} contract @mozilla.org/dom/rtcicecandidate;1 {02b9970c-433d-4cc2-923d-f7028ac66073} contract @mozilla.org/dom/rtcsessiondescription;1 {1775081b-b62d-4954-8ffe-a067bbf508a7} contract @mozilla.org/dom/peerconnectionmanager;1 {7293e901-2be3-4c02-b4bd-cbef6fc24f78} contract @mozilla.org/dom/rtcstatsreport;1 {7fe6e18b-0da3-4056-bf3b-440ef3809e06} contract @mozilla.org/dom/rtcidentityassertion;1 {1abc7499-3c54-43e0-bd60-686e2703f072} contract @mozilla.org/dom/peerconnectionstatic;1 {0fb47c47-a205-4583-a9fc-cbadf8c95880} contract @mozilla.org/dom/rtpsender;1 {4fff5d46-d827-4cd4-a970-8fd53977440e}
--- a/dom/media/android/moz.build +++ b/dom/media/android/moz.build @@ -20,8 +20,10 @@ UNIFIED_SOURCES += [ ] LOCAL_INCLUDES += [ '/dom/base', '/dom/html', ] FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/dom/media/bridge/IPeerConnection.idl +++ b/dom/media/bridge/IPeerConnection.idl @@ -54,16 +54,17 @@ interface IPeerConnection : nsISupports /* for 'type' in DataChannelInit dictionary */ const unsigned short kDataChannelReliable = 0; const unsigned short kDataChannelPartialReliableRexmit = 1; const unsigned short kDataChannelPartialReliableTimed = 2; /* Constants for 'name' in error callbacks */ const unsigned long kNoError = 0; // Test driver only + const unsigned long kInvalidCandidate = 2; const unsigned long kInvalidMediastreamTrack = 3; const unsigned long kInvalidState = 4; const unsigned long kInvalidSessionDescription = 5; const unsigned long kIncompatibleSessionDescription = 6; const unsigned long kIncompatibleMediaStreamTrack = 8; const unsigned long kInternalError = 9; const unsigned long kMaxErrorType = 9; // Same as final error };
--- a/dom/media/bridge/MediaModule.cpp +++ b/dom/media/bridge/MediaModule.cpp @@ -16,27 +16,27 @@ #include "stun_udp_socket_filter.h" NS_DEFINE_NAMED_CID(NS_STUN_UDP_SOCKET_FILTER_HANDLER_CID) NS_GENERIC_FACTORY_CONSTRUCTOR(nsStunUDPSocketFilterHandler) -namespace sipcc +namespace mozilla { -// Factory defined in sipcc::, defines sipcc::PeerConnectionImplConstructor +// Factory defined in mozilla::, defines mozilla::PeerConnectionImplConstructor NS_GENERIC_FACTORY_CONSTRUCTOR(PeerConnectionImpl) } // Defines kPEERCONNECTION_CID NS_DEFINE_NAMED_CID(PEERCONNECTION_CID); static const mozilla::Module::CIDEntry kCIDs[] = { - { &kPEERCONNECTION_CID, false, nullptr, sipcc::PeerConnectionImplConstructor }, + { &kPEERCONNECTION_CID, false, nullptr, mozilla::PeerConnectionImplConstructor }, { &kNS_STUN_UDP_SOCKET_FILTER_HANDLER_CID, false, nullptr, nsStunUDPSocketFilterHandlerConstructor }, { nullptr } }; static const mozilla::Module::ContractIDEntry kContracts[] = { { PEERCONNECTION_CONTRACTID, &kPEERCONNECTION_CID }, { NS_STUN_UDP_SOCKET_FILTER_HANDLER_CONTRACTID, &kNS_STUN_UDP_SOCKET_FILTER_HANDLER_CID }, { nullptr }
--- a/dom/media/bridge/moz.build +++ b/dom/media/bridge/moz.build @@ -12,17 +12,17 @@ XPIDL_MODULE = 'peerconnection' SOURCES += [ 'MediaModule.cpp', ] LOCAL_INCLUDES += [ '/ipc/chromium/src', '/media/mtransport', - '/media/webrtc/signaling/include', + '/media/mtransport', + '/media/webrtc/', '/media/webrtc/signaling/src/common/time_profiling', '/media/webrtc/signaling/src/media-conduit', '/media/webrtc/signaling/src/mediapipeline', '/media/webrtc/signaling/src/peerconnection', - '/media/webrtc/signaling/src/sipcc/include', ] FINAL_LIBRARY = 'xul'
--- a/dom/media/fmp4/MP4Reader.cpp +++ b/dom/media/fmp4/MP4Reader.cpp @@ -661,18 +661,17 @@ MP4Reader::ReturnOutput(MediaData* aData } else if (aTrack == kVideo) { GetCallback()->OnVideoDecoded(static_cast<VideoData*>(aData)); } } void MP4Reader::ReturnEOS(TrackType aTrack) { - GetCallback()->OnNotDecoded(aTrack == kAudio ? MediaData::AUDIO_DATA : MediaData::VIDEO_DATA, - RequestSampleCallback::END_OF_STREAM); + GetCallback()->OnNotDecoded(aTrack == kAudio ? MediaData::AUDIO_DATA : MediaData::VIDEO_DATA, END_OF_STREAM); } MP4Sample* MP4Reader::PopSample(TrackType aTrack) { switch (aTrack) { case kAudio: return mDemuxer->DemuxAudioSample(); @@ -748,18 +747,17 @@ MP4Reader::InputExhausted(TrackType aTra void MP4Reader::Error(TrackType aTrack) { DecoderData& data = GetDecoderData(aTrack); { MonitorAutoLock mon(data.mMonitor); data.mError = true; } - GetCallback()->OnNotDecoded(aTrack == kVideo ? MediaData::VIDEO_DATA : MediaData::AUDIO_DATA, - RequestSampleCallback::DECODE_ERROR); + GetCallback()->OnNotDecoded(aTrack == kVideo ? MediaData::VIDEO_DATA : MediaData::AUDIO_DATA, DECODE_ERROR); } void MP4Reader::Flush(TrackType aTrack) { MOZ_ASSERT(GetTaskQueue()->IsCurrentThreadIn()); VLOG("Flush(%s) BEGIN", TrackTypeToStr(aTrack)); DecoderData& data = GetDecoderData(aTrack); @@ -779,18 +777,17 @@ MP4Reader::Flush(TrackType aTrack) { MonitorAutoLock mon(data.mMonitor); data.mIsFlushing = false; data.mOutput.Clear(); data.mNumSamplesInput = 0; data.mNumSamplesOutput = 0; data.mInputExhausted = false; if (data.mOutputRequested) { - GetCallback()->OnNotDecoded(aTrack == kVideo ? MediaData::VIDEO_DATA : MediaData::AUDIO_DATA, - RequestSampleCallback::CANCELED); + GetCallback()->OnNotDecoded(aTrack == kVideo ? MediaData::VIDEO_DATA : MediaData::AUDIO_DATA, CANCELED); } data.mOutputRequested = false; data.mDiscontinuity = true; } if (aTrack == kVideo) { mQueuedVideoSample = nullptr; } VLOG("Flush(%s) END", TrackTypeToStr(aTrack)); @@ -805,18 +802,17 @@ MP4Reader::SkipVideoDemuxToNextKeyFrame( Flush(kVideo); // Loop until we reach the next keyframe after the threshold. while (true) { nsAutoPtr<MP4Sample> compressed(PopSample(kVideo)); if (!compressed) { // EOS, or error. Let the state machine know. - GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, - RequestSampleCallback::END_OF_STREAM); + GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, END_OF_STREAM); { MonitorAutoLock mon(mVideo.mMonitor); mVideo.mDemuxEOS = true; } return false; } parsed++; if (!compressed->is_sync_point ||
--- a/dom/media/gmp/rlz/moz.build +++ b/dom/media/gmp/rlz/moz.build @@ -13,9 +13,12 @@ USE_STATIC_LIBS = True UNIFIED_SOURCES += [ 'lib/string_utils.cc', 'win/lib/machine_id_win.cc', ] LOCAL_INCLUDES += [ '..', -] \ No newline at end of file +] + +if CONFIG['GNU_CXX']: + FAIL_ON_WARNINGS = True
--- a/dom/media/mediasource/MediaSourceReader.cpp +++ b/dom/media/mediasource/MediaSourceReader.cpp @@ -95,17 +95,17 @@ MediaSourceReader::IsWaitingMediaResourc } void MediaSourceReader::RequestAudioData() { MSE_DEBUGV("MediaSourceReader(%p)::RequestAudioData", this); if (!mAudioReader) { MSE_DEBUG("MediaSourceReader(%p)::RequestAudioData called with no audio reader", this); - GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::DECODE_ERROR); + GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, DECODE_ERROR); return; } mAudioIsSeeking = false; SwitchAudioReader(mLastAudioTime); mAudioReader->RequestAudioData(); } void @@ -134,17 +134,17 @@ MediaSourceReader::OnAudioDecoded(AudioD void MediaSourceReader::RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) { MSE_DEBUGV("MediaSourceReader(%p)::RequestVideoData(%d, %lld)", this, aSkipToNextKeyframe, aTimeThreshold); if (!mVideoReader) { MSE_DEBUG("MediaSourceReader(%p)::RequestVideoData called with no video reader", this); - GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, RequestSampleCallback::DECODE_ERROR); + GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, DECODE_ERROR); return; } if (aSkipToNextKeyframe) { mTimeThreshold = aTimeThreshold; mDropAudioBeforeThreshold = true; mDropVideoBeforeThreshold = true; } mVideoIsSeeking = false; @@ -172,27 +172,26 @@ MediaSourceReader::OnVideoDecoded(VideoD // switching away from. if (!mVideoIsSeeking) { mLastVideoTime = aSample->mTime + aSample->mDuration; } GetCallback()->OnVideoDecoded(aSample); } void -MediaSourceReader::OnNotDecoded(MediaData::Type aType, RequestSampleCallback::NotDecodedReason aReason) +MediaSourceReader::OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason) { MSE_DEBUG("MediaSourceReader(%p)::OnNotDecoded aType=%u aReason=%u IsEnded: %d", this, aType, aReason, IsEnded()); - if (aReason == RequestSampleCallback::DECODE_ERROR || - aReason == RequestSampleCallback::CANCELED) { + if (aReason == DECODE_ERROR || aReason == CANCELED) { GetCallback()->OnNotDecoded(aType, aReason); return; } // End of stream. Force switching past this stream to another reader by // switching to the end of the buffered range. - MOZ_ASSERT(aReason == RequestSampleCallback::END_OF_STREAM); + MOZ_ASSERT(aReason == END_OF_STREAM); nsRefPtr<MediaDecoderReader> reader = aType == MediaData::AUDIO_DATA ? mAudioReader : mVideoReader; // Find the closest approximation to the end time for this stream. // mLast{Audio,Video}Time differs from the actual end time because of // Bug 1065207 - the duration of a WebM fragment is an estimate not the // actual duration. In the case of audio time an example of where they // differ would be the actual sample duration being small but the @@ -223,23 +222,23 @@ MediaSourceReader::OnNotDecoded(MediaDat } if (aType == MediaData::VIDEO_DATA && SwitchVideoReader(*time + EOS_FUZZ_US)) { RequestVideoData(false, 0); return; } // If the entire MediaSource is done, generate an EndOfStream. if (IsEnded()) { - GetCallback()->OnNotDecoded(aType, RequestSampleCallback::END_OF_STREAM); + GetCallback()->OnNotDecoded(aType, END_OF_STREAM); return; } // We don't have the data the caller wants. Tell that we're waiting for JS to // give us more data. - GetCallback()->OnNotDecoded(aType, RequestSampleCallback::WAITING_FOR_DATA); + GetCallback()->OnNotDecoded(aType, WAITING_FOR_DATA); } void MediaSourceReader::Shutdown() { MediaDecoderReader::Shutdown(); for (uint32_t i = 0; i < mTrackBuffers.Length(); ++i) { mTrackBuffers[i]->Shutdown();
--- a/dom/media/mediasource/MediaSourceReader.h +++ b/dom/media/mediasource/MediaSourceReader.h @@ -49,17 +49,17 @@ public: void RequestAudioData() MOZ_OVERRIDE; void OnAudioDecoded(AudioData* aSample); void RequestVideoData(bool aSkipToNextKeyframe, int64_t aTimeThreshold) MOZ_OVERRIDE; void OnVideoDecoded(VideoData* aSample); - void OnNotDecoded(MediaData::Type aType, RequestSampleCallback::NotDecodedReason aReason); + void OnNotDecoded(MediaData::Type aType, NotDecodedReason aReason); void OnSeekCompleted(nsresult aResult); bool HasVideo() MOZ_OVERRIDE { return mInfo.HasVideo(); }
--- a/dom/media/mediasource/TrackBuffer.cpp +++ b/dom/media/mediasource/TrackBuffer.cpp @@ -62,17 +62,17 @@ public: mDecoder = nullptr; return NS_OK; } private: nsRefPtr<SourceBufferDecoder> mDecoder; }; -MOZ_STACK_CLASS class DecodersToInitialize MOZ_FINAL { +class MOZ_STACK_CLASS DecodersToInitialize MOZ_FINAL { public: explicit DecodersToInitialize(TrackBuffer* aOwner) : mOwner(aOwner) { } ~DecodersToInitialize() {
--- a/dom/media/moz.build +++ b/dom/media/moz.build @@ -100,16 +100,17 @@ EXPORTS += [ 'MediaData.h', 'MediaDataDecodedListener.h', 'MediaDecoder.h', 'MediaDecoderOwner.h', 'MediaDecoderReader.h', 'MediaDecoderStateMachine.h', 'MediaInfo.h', 'MediaMetadataManager.h', + 'MediaPromise.h', 'MediaQueue.h', 'MediaRecorder.h', 'MediaResource.h', 'MediaSegment.h', 'MediaStreamGraph.h', 'MediaTaskQueue.h', 'MediaTrack.h', 'MediaTrackList.h', @@ -176,16 +177,17 @@ UNIFIED_SOURCES += [ 'MediaCache.cpp', 'MediaData.cpp', 'MediaDecoder.cpp', 'MediaDecoderReader.cpp', 'MediaDecoderStateMachine.cpp', 'MediaDecoderStateMachineScheduler.cpp', 'MediaDevices.cpp', 'MediaManager.cpp', + 'MediaPromise.cpp', 'MediaRecorder.cpp', 'MediaResource.cpp', 'MediaShutdownManager.cpp', 'MediaStreamError.cpp', 'MediaStreamGraph.cpp', 'MediaStreamTrack.cpp', 'MediaTaskQueue.cpp', 'MediaTrack.cpp',
--- a/dom/media/omx/MediaCodecReader.cpp +++ b/dom/media/omx/MediaCodecReader.cpp @@ -483,17 +483,17 @@ MediaCodecReader::DecodeAudioDataTask() if (mAudioTrack.mDiscontinuity) { a->mDiscontinuity = true; mAudioTrack.mDiscontinuity = false; } GetCallback()->OnAudioDecoded(a); } } if (AudioQueue().AtEndOfStream()) { - GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::END_OF_STREAM); + GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, END_OF_STREAM); } return result; } bool MediaCodecReader::DecodeVideoFrameTask(int64_t aTimeThreshold) { bool result = DecodeVideoFrameSync(aTimeThreshold); @@ -503,17 +503,17 @@ MediaCodecReader::DecodeVideoFrameTask(i if (mVideoTrack.mDiscontinuity) { v->mDiscontinuity = true; mVideoTrack.mDiscontinuity = false; } GetCallback()->OnVideoDecoded(v); } } if (VideoQueue().AtEndOfStream()) { - GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, RequestSampleCallback::END_OF_STREAM); + GetCallback()->OnNotDecoded(MediaData::VIDEO_DATA, END_OF_STREAM); } return result; } bool MediaCodecReader::HasAudio() { return mInfo.mAudio.mHasAudio;
--- a/dom/media/systemservices/moz.build +++ b/dom/media/systemservices/moz.build @@ -35,8 +35,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk 'frameworks/wilhelm/include', 'system/media/wilhelm/include', ] ] include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/dom/media/tests/mochitest/identity/test_fingerprints.html +++ b/dom/media/tests/mochitest/identity/test_fingerprints.html @@ -48,17 +48,17 @@ function makeFingerprints(algo, digest) } return fingerprints; } var fingerprintRegex = /^a=fingerprint:(\S+) (\S+)/m; var identityRegex = /^a=identity:(\S+)/m; function fingerprintSdp(fingerprints) { - return fingerprints.map(fp => "a=fInGeRpRiNt=" + fp.algorithm + + return fingerprints.map(fp => "a=fInGeRpRiNt:" + fp.algorithm + " " + fp.digest + "\n").join(""); } // Firefox only uses a single fingerprint // that doesn't mean we can't have SDP that describes two function testMultipleFingerprints() { // this one fails setRemoteDescription if the identity is not good var pcStrict = new mozRTCPeerConnection({ peerIdentity: 'someone@example.com'}); @@ -73,30 +73,30 @@ function testMultipleFingerprints() { } navigator.mozGetUserMedia({ audio: true, fake: true }, function(stream) { ok(stream, "Got fake stream"); pcDouble.addStream(stream); pcDouble.createOffer(function(offer) { ok(offer, "Got offer"); - var m = offer.sdp.match(fingerprintRegex); - if (!m) { + var fp = offer.sdp.match(fingerprintRegex); + if (!fp) { finished(false, "No fingerprint in offer SDP"); return; } - var fingerprints = makeFingerprints(m[1], m[2]); + var fingerprints = makeFingerprints(fp[1], fp[2]); getIdentityAssertion(fingerprints, function(assertion) { ok(assertion, "Should have assertion"); - var sdp = offer.sdp.slice(0, m.index) + + var sdp = offer.sdp.slice(0, fp.index) + "a=identity:" + assertion + "\n" + fingerprintSdp(fingerprints.slice(1)) + - offer.sdp.slice(m.index); + offer.sdp.slice(fp.index); var desc = new mozRTCSessionDescription({ type: "offer", sdp: sdp }); pcStrict.setRemoteDescription(desc, function() { finished(true, "session description was OK"); }, function(err) { finished(false, "error setting the session description: " + err); }); });
--- a/dom/media/tests/mochitest/mochitest.ini +++ b/dom/media/tests/mochitest/mochitest.ini @@ -123,10 +123,17 @@ skip-if = toolkit == 'gonk' # b2g (Bug 1 skip-if = toolkit == 'gonk' # b2g (Bug 1059867) [test_peerConnection_setRemoteOfferInHaveLocalOffer.html] skip-if = toolkit == 'gonk' # b2g (Bug 1059867) [test_peerConnection_throwInCallbacks.html] skip-if = toolkit == 'gonk' # b2g(Bug 960442, video support for WebRTC is disabled on b2g) [test_peerConnection_toJSON.html] skip-if = toolkit == 'gonk' # b2g (Bug 1059867) +# multistream is not ready quite yet (bug 1056650) +# [test_peerConnection_twoAudioStreams.html] +# [test_peerConnection_twoAudioVideoStreams.html] +# [test_peerConnection_twoAudioVideoStreamsCombined.html] +# [test_peerConnection_twoVideoStreams.html] +# [test_peerConnection_addSecondAudioStream.html] + # Bug 950317: Hack for making a cleanup hook after finishing all WebRTC cases [test_zmedia_cleanup.html]
--- a/dom/media/tests/mochitest/pc.js +++ b/dom/media/tests/mochitest/pc.js @@ -1750,51 +1750,53 @@ PeerConnectionWrapper.prototype = { element.play(); }, /** * Requests all the media streams as specified in the constrains property. * * @param {function} onSuccess * Callback to execute if all media has been requested successfully + * @param {array} constraintsList + * Array of constraints for GUM calls */ - getAllUserMedia : function PCW_GetAllUserMedia(onSuccess) { + getAllUserMedia : function PCW_GetAllUserMedia(constraintsList, onSuccess) { var self = this; - function _getAllUserMedia(constraintsList, index) { + function _getAllUserMedia(index) { if (index < constraintsList.length) { var constraints = constraintsList[index]; getUserMedia(constraints, function (stream) { var type = ''; if (constraints.audio) { type = 'audio'; } if (constraints.video) { type += 'video'; } self.attachMedia(stream, type, 'local'); - _getAllUserMedia(constraintsList, index + 1); + _getAllUserMedia(index + 1); }, generateErrorCallback()); } else { onSuccess(); } } - if (this.constraints.length === 0) { + if (constraintsList.length === 0) { info("Skipping GUM: no UserMedia requested"); onSuccess(); } else { - info("Get " + this.constraints.length + " local streams"); - _getAllUserMedia(this.constraints, 0); + info("Get " + constraintsList.length + " local streams"); + _getAllUserMedia(0); } }, /** * Create a new data channel instance * * @param {Object} options * Options which get forwarded to nsIPeerConnection.createDataChannel @@ -2169,23 +2171,23 @@ PeerConnectionWrapper.prototype = { * @param constraints * The contraint to be examined. */ countAudioTracksInMediaConstraint : function PCW_countAudioTracksInMediaConstraint(constraints) { if ((!constraints) || (constraints.length === 0)) { return 0; } - var audioTracks = 0; + var numAudioTracks = 0; for (var i = 0; i < constraints.length; i++) { if (constraints[i].audio) { - audioTracks++; + numAudioTracks++; } } - return audioTracks; + return numAudioTracks; }, /** * Checks for audio in given offer options. * * @param options * The options to be examined. */ @@ -2218,23 +2220,23 @@ PeerConnectionWrapper.prototype = { * @param constraint * The contraint to be examined. */ countVideoTracksInMediaConstraint : function PCW_countVideoTracksInMediaConstraint(constraints) { if ((!constraints) || (constraints.length === 0)) { return 0; } - var videoTracks = 0; + var numVideoTracks = 0; for (var i = 0; i < constraints.length; i++) { if (constraints[i].video) { - videoTracks++; + numVideoTracks++; } } - return videoTracks; + return numVideoTracks; }, /** * Checks for video in given offer options. * * @param options * The options to be examined. */ @@ -2267,39 +2269,39 @@ PeerConnectionWrapper.prototype = { * @param streams * An array of streams (as returned by getLocalStreams()) to be * examined. */ countAudioTracksInStreams : function PCW_countAudioTracksInStreams(streams) { if (!streams || (streams.length === 0)) { return 0; } - var audioTracks = 0; + var numAudioTracks = 0; streams.forEach(function(st) { - audioTracks += st.getAudioTracks().length; + numAudioTracks += st.getAudioTracks().length; }); - return audioTracks; + return numAudioTracks; }, /* * Counts the amount of video tracks in a given set of streams. * * @param streams * An array of streams (as returned by getLocalStreams()) to be * examined. */ countVideoTracksInStreams: function PCW_countVideoTracksInStreams(streams) { if (!streams || (streams.length === 0)) { return 0; } - var videoTracks = 0; + var numVideoTracks = 0; streams.forEach(function(st) { - videoTracks += st.getVideoTracks().length; + numVideoTracks += st.getVideoTracks().length; }); - return videoTracks; + return numVideoTracks; }, /** * Checks that we are getting the media tracks we expect. * * @param {object} constraintsRemote * The media constraints of the local and remote peer connection object */ @@ -2362,20 +2364,19 @@ PeerConnectionWrapper.prototype = { if (!self.onAddStreamFired) { onSuccess(); } }, 60000); } }, verifySdp : function PCW_verifySdp(desc, expectedType, offerConstraintsList, - answerConstraintsList, offerOptions, trickleIceCallback) { + offerOptions, trickleIceCallback) { info("Examining this SessionDescription: " + JSON.stringify(desc)); info("offerConstraintsList: " + JSON.stringify(offerConstraintsList)); - info("answerConstraintsList: " + JSON.stringify(answerConstraintsList)); info("offerOptions: " + JSON.stringify(offerOptions)); ok(desc, "SessionDescription is not null"); is(desc.type, expectedType, "SessionDescription type is " + expectedType); ok(desc.sdp.length > 10, "SessionDescription body length is plausible"); ok(desc.sdp.contains("a=ice-ufrag"), "ICE username is present in SDP"); ok(desc.sdp.contains("a=ice-pwd"), "ICE password is present in SDP"); ok(desc.sdp.contains("a=fingerprint"), "ICE fingerprint is present in SDP"); //TODO: update this for loopback support bug 1027350 @@ -2385,35 +2386,33 @@ PeerConnectionWrapper.prototype = { trickleIceCallback(false); } else { info("No ICE candidate in SDP -> requiring trickle ICE"); trickleIceCallback(true); } //TODO: how can we check for absence/presence of m=application? var audioTracks = - Math.max(this.countAudioTracksInMediaConstraint(offerConstraintsList), - this.countAudioTracksInMediaConstraint(answerConstraintsList)) || + this.countAudioTracksInMediaConstraint(offerConstraintsList) || this.audioInOfferOptions(offerOptions); info("expected audio tracks: " + audioTracks); if (audioTracks == 0) { ok(!desc.sdp.contains("m=audio"), "audio m-line is absent from SDP"); } else { ok(desc.sdp.contains("m=audio"), "audio m-line is present in SDP"); ok(desc.sdp.contains("a=rtpmap:109 opus/48000/2"), "OPUS codec is present in SDP"); //TODO: ideally the rtcp-mux should be for the m=audio, and not just // anywhere in the SDP (JS SDP parser bug 1045429) ok(desc.sdp.contains("a=rtcp-mux"), "RTCP Mux is offered in SDP"); } var videoTracks = - Math.max(this.countVideoTracksInMediaConstraint(offerConstraintsList), - this.countVideoTracksInMediaConstraint(answerConstraintsList)) || + this.countVideoTracksInMediaConstraint(offerConstraintsList) || this.videoInOfferOptions(offerOptions); info("expected video tracks: " + videoTracks); if (videoTracks == 0) { ok(!desc.sdp.contains("m=video"), "video m-line is absent from SDP"); } else { ok(desc.sdp.contains("m=video"), "video m-line is present in SDP"); if (this.h264) { @@ -2632,16 +2631,56 @@ PeerConnectionWrapper.prototype = { (lIp === serverIp || rIp === serverIp), "One peer uses a relay"); } else { info("P2P configured"); ok(((lType !== "relayed") && (rType !== "relayed")), "Pure peer to peer call without a relay"); } }, /** + * Compares amount of established ICE connection according to ICE candidate + * pairs in the stats reporting with the expected amount of connection based + * on the constraints. + * + * @param {object} stats + * The stats to check for ICE candidate pairs + * @param {object} counters + * The counters for media and data tracks based on constraints + * @param {object} answer + * The SDP answer to check for SDP bundle support + */ + checkStatsIceConnections : function PCW_checkStatsIceConnections(stats, + offerConstraintsList, offerOptions, numDataTracks, answer) { + var numIceConnections = 0; + Object.keys(stats).forEach(function(key) { + if ((stats[key].type === "candidatepair") && stats[key].selected) { + numIceConnections += 1; + } + }); + info("ICE connections according to stats: " + numIceConnections); + if (answer.sdp.contains('a=group:BUNDLE')) { + is(numIceConnections, 1, "stats reports exactly 1 ICE connection"); + } else { + // This code assumes that no media sections have been rejected due to + // codec mismatch or other unrecoverable negotiation failures. + var numAudioTracks = + this.countAudioTracksInMediaConstraint(offerConstraintsList) || + this.audioInOfferOptions(offerOptions); + + var numVideoTracks = + this.countVideoTracksInMediaConstraint(offerConstraintsList) || + this.videoInOfferOptions(offerOptions); + + var numAudioVideoDataTracks = numAudioTracks + numVideoTracks + numDataTracks; + info("expected audio + video + data tracks: " + numAudioVideoDataTracks); + is(numAudioVideoDataTracks, numIceConnections, "stats ICE connections matches expected A/V tracks"); + } + }, + + /** * Property-matching function for finding a certain stat in passed-in stats * * @param {object} stats * The stats to check from this PeerConnectionWrapper * @param {object} props * The properties to look for * @returns {boolean} Whether an entry containing all match-props was found. */
--- a/dom/media/tests/mochitest/templates.js +++ b/dom/media/tests/mochitest/templates.js @@ -106,25 +106,25 @@ var commandsPeerConnection = [ function (test) { test.pcRemote.logSignalingState(); test.next(); } ], [ 'PC_LOCAL_GUM', function (test) { - test.pcLocal.getAllUserMedia(function () { + test.pcLocal.getAllUserMedia(test.pcLocal.constraints, function () { test.next(); }); } ], [ 'PC_REMOTE_GUM', function (test) { - test.pcRemote.getAllUserMedia(function () { + test.pcRemote.getAllUserMedia(test.pcRemote.constraints, function () { test.next(); }); } ], [ 'PC_LOCAL_CHECK_INITIAL_SIGNALINGSTATE', function (test) { is(test.pcLocal.signalingState, STABLE, @@ -227,28 +227,28 @@ var commandsPeerConnection = [ test.next(); }); } ], [ 'PC_LOCAL_SANE_LOCAL_SDP', function (test) { test.pcLocal.verifySdp(test._local_offer, "offer", - test._offer_constraints, test._answer_constraints, test._offer_options, + test._offer_constraints, test._offer_options, function(trickle) { test.pcLocal.localRequiresTrickleIce = trickle; }); test.next(); } ], [ 'PC_REMOTE_SANE_REMOTE_SDP', function (test) { test.pcRemote.verifySdp(test._local_offer, "offer", - test._offer_constraints, test._answer_constraints, test._offer_options, + test._offer_constraints, test._offer_options, function (trickle) { test.pcRemote.remoteRequiresTrickleIce = trickle; }); test.next(); } ], [ 'PC_REMOTE_CREATE_ANSWER', @@ -351,28 +351,28 @@ var commandsPeerConnection = [ } ); } ], [ 'PC_REMOTE_SANE_LOCAL_SDP', function (test) { test.pcRemote.verifySdp(test._remote_answer, "answer", - test._offer_constraints, test._answer_constraints, test._offer_options, + test._offer_constraints, test._offer_options, function (trickle) { test.pcRemote.localRequiresTrickleIce = trickle; }); test.next(); } ], [ 'PC_LOCAL_SANE_REMOTE_SDP', function (test) { test.pcLocal.verifySdp(test._remote_answer, "answer", - test._offer_constraints, test._answer_constraints, test._offer_options, + test._offer_constraints, test._offer_options, function (trickle) { test.pcLocal.remoteRequiresTrickleIce = trickle; }); test.next(); } ], [ 'PC_LOCAL_WAIT_FOR_ICE_CONNECTED', @@ -518,16 +518,42 @@ var commandsPeerConnection = [ function (test) { test.pcRemote.getStats(null, function(stats) { test.pcRemote.checkStatsIceConnectionType(stats); test.next(); }); } ], [ + 'PC_LOCAL_CHECK_ICE_CONNECTIONS', + function (test) { + test.pcLocal.getStats(null, function(stats) { + test.pcLocal.checkStatsIceConnections(stats, + test._offer_constraints, + test._offer_options, + 0, + test.originalAnswer); + test.next(); + }); + } + ], + [ + 'PC_REMOTE_CHECK_ICE_CONNECTIONS', + function (test) { + test.pcRemote.getStats(null, function(stats) { + test.pcRemote.checkStatsIceConnections(stats, + test._offer_constraints, + test._offer_options, + 0, + test.originalAnswer); + test.next(); + }); + } + ], + [ 'PC_LOCAL_CHECK_GETSTATS_AUDIOTRACK_OUTBOUND', function (test) { var pc = test.pcLocal; var stream = pc._pc.getLocalStreams()[0]; var track = stream && stream.getAudioTracks()[0]; if (track) { var msg = "pcLocal.HasStat outbound audio rtp "; pc.getStats(track, function(stats) { @@ -723,17 +749,17 @@ var commandsDataChannel = [ function (test) { test.pcRemote.logSignalingState(); test.next(); } ], [ 'PC_LOCAL_GUM', function (test) { - test.pcLocal.getAllUserMedia(function () { + test.pcLocal.getAllUserMedia(test.pcLocal.constraints, function () { test.next(); }); } ], [ 'PC_LOCAL_INITIAL_SIGNALINGSTATE', function (test) { is(test.pcLocal.signalingState, STABLE, @@ -747,17 +773,17 @@ var commandsDataChannel = [ is(test.pcLocal.iceConnectionState, ICE_NEW, "Initial local ICE connection state is 'new'"); test.next(); } ], [ 'PC_REMOTE_GUM', function (test) { - test.pcRemote.getAllUserMedia(function () { + test.pcRemote.getAllUserMedia(test.pcRemote.constraints, function () { test.next(); }); } ], [ 'PC_REMOTE_INITIAL_SIGNALINGSTATE', function (test) { is(test.pcRemote.signalingState, STABLE, @@ -862,28 +888,28 @@ var commandsDataChannel = [ test.next(); }); } ], [ 'PC_LOCAL_SANE_LOCAL_SDP', function (test) { test.pcLocal.verifySdp(test._local_offer, "offer", - test._offer_constraints, test._answer_constraints, test._offer_options, + test._offer_constraints, test._offer_options, function(trickle) { test.pcLocal.localRequiresTrickleIce = trickle; }); test.next(); } ], [ 'PC_REMOTE_SANE_REMOTE_SDP', function (test) { test.pcRemote.verifySdp(test._local_offer, "offer", - test._offer_constraints, test._answer_constraints, test._offer_options, + test._offer_constraints, test._offer_options, function (trickle) { test.pcRemote.remoteRequiresTrickleIce = trickle; }); test.next(); } ], [ 'PC_REMOTE_CREATE_ANSWER', @@ -966,28 +992,28 @@ var commandsDataChannel = [ } ); } ], [ 'PC_REMOTE_SANE_LOCAL_SDP', function (test) { test.pcRemote.verifySdp(test._remote_answer, "answer", - test._offer_constraints, test._answer_constraints, test._offer_options, + test._offer_constraints, test._offer_options, function (trickle) { test.pcRemote.localRequiresTrickleIce = trickle; }); test.next(); } ], [ 'PC_LOCAL_SANE_REMOTE_SDP', function (test) { test.pcLocal.verifySdp(test._remote_answer, "answer", - test._offer_constraints, test._answer_constraints, test._offer_options, + test._offer_constraints, test._offer_options, function (trickle) { test.pcLocal.remoteRequiresTrickleIce = trickle; }); test.next(); } ], [ 'PC_LOCAL_WAIT_FOR_ICE_CONNECTED', @@ -1125,16 +1151,42 @@ var commandsDataChannel = [ 'PC_REMOTE_CHECK_MEDIA_FLOW_PRESENT', function (test) { test.pcRemote.checkMediaFlowPresent(function () { test.next(); }); } ], [ + 'PC_LOCAL_CHECK_ICE_CONNECTIONS', + function (test) { + test.pcLocal.getStats(null, function(stats) { + test.pcLocal.checkStatsIceConnections(stats, + test._offer_constraints, + test._offer_options, + 1, + test.originalAnswer); + test.next(); + }); + } + ], + [ + 'PC_REMOTE_CHECK_ICE_CONNECTIONS', + function (test) { + test.pcRemote.getStats(null, function(stats) { + test.pcRemote.checkStatsIceConnections(stats, + test._offer_constraints, + test._offer_options, + 1, + test.originalAnswer); + test.next(); + }); + } + ], + [ 'SEND_MESSAGE', function (test) { var message = "Lorem ipsum dolor sit amet"; test.send(message, function (channel, data) { is(data, message, "Message correctly transmitted from pcLocal to pcRemote."); test.next();
new file mode 100644 --- /dev/null +++ b/dom/media/tests/mochitest/test_peerConnection_addSecondAudioStream.html @@ -0,0 +1,102 @@ +<!DOCTYPE HTML> +<html> +<head> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="head.js"></script> + <script type="application/javascript" src="mediaStreamPlayback.js"></script> + <script type="application/javascript" src="pc.js"></script> + <script type="application/javascript" src="templates.js"></script> + <script type="application/javascript" src="turnConfig.js"></script> +</head> +<body> +<pre id="test"> +<script type="application/javascript"> + createHTML({ + bug: "1091242", + title: "Renegotiation: add second audio stream" + }); + + var test; + runNetworkTest(function (options) { + test = new PeerConnectionTest(options); + test.chain.append([ + [ + 'PC_LOCAL_SETUP_NEGOTIATION_CALLBACK', + function (test) { + test.pcLocal.onNegotiationneededFired = false; + test.pcLocal._pc.onnegotiationneeded = function (anEvent) { + info("pcLocal.onnegotiationneeded fired"); + test.pcLocal.onNegotiationneededFired = true; + }; + test.next(); + } + ], + [ + 'PC_LOCAL_ADD_SECOND_STREAM', + function (test) { + test.pcLocal.getAllUserMedia([{audio: true}], function () { + test.next(); + }); + } + ], + [ + 'PC_LOCAL_CREATE_NEW_OFFER', + function (test) { + ok(test.pcLocal.onNegotiationneededFired, "onnegotiationneeded"); + test.createOffer(test.pcLocal, function (offer) { + test._new_offer = offer; + test.next(); + }); + } + ], + [ + 'PC_LOCAL_SET_NEW_LOCAL_DESCRIPTION', + function (test) { + test.setLocalDescription(test.pcLocal, test._new_offer, HAVE_LOCAL_OFFER, function () { + test.next(); + }); + } + ], + [ + 'PC_REMOTE_SET_NEW_REMOTE_DESCRIPTION', + function (test) { + test.setRemoteDescription(test.pcRemote, test._new_offer, HAVE_REMOTE_OFFER, function () { + test.next(); + }); + } + ], + [ + 'PC_REMOTE_CREATE_NEW_ANSWER', + function (test) { + test.createAnswer(test.pcRemote, function (answer) { + test._new_answer = answer; + test.next(); + }); + } + ], + [ + 'PC_REMOTE_SET_NEW_LOCAL_DESCRIPTION', + function (test) { + test.setLocalDescription(test.pcRemote, test._new_answer, STABLE, function () { + test.next(); + }); + } + ], + [ + 'PC_LOCAL_SET_NEW_REMOTE_DESCRIPTION', + function (test) { + test.setRemoteDescription(test.pcLocal, test._new_answer, STABLE, function () { + test.next(); + }); + } + ] + // TODO(bug 1093835): figure out how to verify if media flows through the new stream + ]); + test.setMediaConstraints([{audio: true}], [{audio: true}]); + test.run(); + }); +</script> +</pre> +</body> +</html>
--- a/dom/media/tests/mochitest/test_peerConnection_offerRequiresReceiveAudio.html +++ b/dom/media/tests/mochitest/test_peerConnection_offerRequiresReceiveAudio.html @@ -13,17 +13,17 @@ <script type="application/javascript"> createHTML({ bug: "850275", title: "Simple offer media constraint test with audio" }); runNetworkTest(function() { var test = new PeerConnectionTest(); - + test.setMediaConstraints([], [{audio: true}]); // TODO: Stop using old constraint-like RTCOptions soon (Bug 1064223). // Watch out for case-difference when fixing: { offerToReceiveAudio: true } test.setOfferOptions({ mandatory: { OfferToReceiveAudio: true } }); test.run(); }); </script> </pre> </body>
--- a/dom/media/tests/mochitest/test_peerConnection_offerRequiresReceiveVideo.html +++ b/dom/media/tests/mochitest/test_peerConnection_offerRequiresReceiveVideo.html @@ -13,16 +13,17 @@ <script type="application/javascript"> createHTML({ bug: "850275", title: "Simple offer media constraint test with video" }); runNetworkTest(function() { var test = new PeerConnectionTest(); + test.setMediaConstraints([], [{video: true}]); // TODO: Stop using old constraint-like RTCOptions soon (Bug 1064223). // Watch out for case-difference when fixing: { offerToReceiveVideo: true } test.setOfferOptions({ optional: [{ OfferToReceiveVideo: true }] }); test.run(); }); </script> </pre> </body>
--- a/dom/media/tests/mochitest/test_peerConnection_offerRequiresReceiveVideoAudio.html +++ b/dom/media/tests/mochitest/test_peerConnection_offerRequiresReceiveVideoAudio.html @@ -13,18 +13,16 @@ <script type="application/javascript"> createHTML({ bug: "850275", title: "Simple offer media constraint test with video/audio" }); runNetworkTest(function() { var test = new PeerConnectionTest(); - test.setOfferOptions({ - offerToReceiveVideo: true, - offerToReceiveAudio: true - }); + test.setMediaConstraints([], [{audio: true, video: true}]); + test.setOfferOptions({ offerToReceiveVideo: true, offerToReceiveAudio: true }); test.run(); }); </script> </pre> </body> </html>
new file mode 100644 --- /dev/null +++ b/dom/media/tests/mochitest/test_peerConnection_twoAudioStreams.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<head> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="head.js"></script> + <script type="application/javascript" src="mediaStreamPlayback.js"></script> + <script type="application/javascript" src="pc.js"></script> + <script type="application/javascript" src="templates.js"></script> + <script type="application/javascript" src="turnConfig.js"></script> +</head> +<body> +<pre id="test"> +<script type="application/javascript"> + createHTML({ + bug: "1091242", + title: "Multistream: Two audio streams" + }); + + var test; + runNetworkTest(function (options) { + test = new PeerConnectionTest(options); + test.setMediaConstraints([{audio: true}, {audio: true}], + [{audio: true}, {audio: true}]); + test.run(); + }); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/media/tests/mochitest/test_peerConnection_twoAudioVideoStreams.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<head> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="head.js"></script> + <script type="application/javascript" src="mediaStreamPlayback.js"></script> + <script type="application/javascript" src="pc.js"></script> + <script type="application/javascript" src="templates.js"></script> + <script type="application/javascript" src="turnConfig.js"></script> +</head> +<body> +<pre id="test"> +<script type="application/javascript"> + + createHTML({ + bug: "1091242", + title: "Multistream: Two audio streams, two video streams" + }); + + var test; + runNetworkTest(function (options) { + test = new PeerConnectionTest(options); + test.setMediaConstraints([{audio: true}, {video: true}, {audio: true}, + {video: true}], + [{audio: true}, {video: true}, {audio: true}, + {video: true}]); + test.run(); + }); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/media/tests/mochitest/test_peerConnection_twoAudioVideoStreamsCombined.html @@ -0,0 +1,33 @@ +<!DOCTYPE HTML> +<html> +<head> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="head.js"></script> + <script type="application/javascript" src="mediaStreamPlayback.js"></script> + <script type="application/javascript" src="pc.js"></script> + <script type="application/javascript" src="templates.js"></script> + <script type="application/javascript" src="turnConfig.js"></script> +</head> +<body> +<pre id="test"> +<script type="application/javascript"> + + createHTML({ + bug: "1091242", + title: "Multistream: Two audio/video streams" + }); + + var test; + runNetworkTest(function (options) { + test = new PeerConnectionTest(options); + test.setMediaConstraints([{audio: true, video: true}, + {audio: true, video: true}], + [{audio: true, video: true}, + {audio: true, video: true}]); + test.run(); + }); +</script> +</pre> +</body> +</html>
new file mode 100644 --- /dev/null +++ b/dom/media/tests/mochitest/test_peerConnection_twoVideoStreams.html @@ -0,0 +1,30 @@ +<!DOCTYPE HTML> +<html> +<head> + <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/> + <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script> + <script type="application/javascript" src="head.js"></script> + <script type="application/javascript" src="mediaStreamPlayback.js"></script> + <script type="application/javascript" src="pc.js"></script> + <script type="application/javascript" src="templates.js"></script> + <script type="application/javascript" src="turnConfig.js"></script> +</head> +<body> +<pre id="test"> +<script type="application/javascript"> + createHTML({ + bug: "1091242", + title: "Multistream: Two video streams" + }); + + var test; + runNetworkTest(function (options) { + test = new PeerConnectionTest(options); + test.setMediaConstraints([{video: true}, {video: true}], + [{video: true}, {video: true}]); + test.run(); + }); +</script> +</pre> +</body> +</html>
--- a/dom/media/webaudio/blink/moz.build +++ b/dom/media/webaudio/blink/moz.build @@ -26,8 +26,10 @@ UNIFIED_SOURCES += [ include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' LOCAL_INCLUDES += [ '/dom/media/webaudio', ] +if CONFIG['GNU_CXX']: + FAIL_ON_WARNINGS = True
--- a/dom/media/webm/WebMReader.cpp +++ b/dom/media/webm/WebMReader.cpp @@ -738,17 +738,17 @@ bool WebMReader::DecodeOpus(const unsign if (channels > 8) { return false; } if (mPaddingDiscarded) { // Discard padding should be used only on the final packet, so // decoding after a padding discard is invalid. LOG(PR_LOG_DEBUG, ("Opus error, discard padding on interstitial packet")); - GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::DECODE_ERROR); + GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, DECODE_ERROR); return false; } // Maximum value is 63*2880, so there's no chance of overflow. int32_t frames_number = opus_packet_get_nb_frames(aData, aLength); if (frames_number <= 0) { return false; // Invalid packet header. } @@ -792,30 +792,30 @@ bool WebMReader::DecodeOpus(const unsign mSkip -= skipFrames; } int64_t discardPadding = 0; (void) nestegg_packet_discard_padding(aPacket, &discardPadding); if (discardPadding < 0) { // Negative discard padding is invalid. LOG(PR_LOG_DEBUG, ("Opus error, negative discard padding")); - GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::DECODE_ERROR); + GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, DECODE_ERROR); return false; } if (discardPadding > 0) { CheckedInt64 discardFrames = UsecsToFrames(discardPadding / NS_PER_USEC, mInfo.mAudio.mRate); if (!discardFrames.isValid()) { NS_WARNING("Int overflow in DiscardPadding"); return false; } if (discardFrames.value() > frames) { // Discarding more than the entire packet is invalid. LOG(PR_LOG_DEBUG, ("Opus error, discard padding larger than packet")); - GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, RequestSampleCallback::DECODE_ERROR); + GetCallback()->OnNotDecoded(MediaData::AUDIO_DATA, DECODE_ERROR); return false; } LOG(PR_LOG_DEBUG, ("Opus decoder discarding %d of %d frames", int32_t(discardFrames.value()), frames)); // Padding discard is only supposed to happen on the final packet. // Record the discard so we can return an error if another packet is // decoded. mPaddingDiscarded = true;
--- a/dom/media/webspeech/recognition/moz.build +++ b/dom/media/webspeech/recognition/moz.build @@ -38,8 +38,10 @@ UNIFIED_SOURCES += [ LOCAL_INCLUDES += [ '/dom/base', ] include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/dom/plugins/ipc/interpose/moz.build +++ b/dom/plugins/ipc/interpose/moz.build @@ -8,8 +8,10 @@ SharedLibrary('plugin_child_interpose') UNIFIED_SOURCES += [ "%s.mm" % (LIBRARY_NAME) ] UNIFIED_SOURCES += [ 'plugin_child_quirks.mm', ] OS_LIBS += ['-framework Carbon'] + +FAIL_ON_WARNINGS = True
--- a/dom/security/nsCSPParser.cpp +++ b/dom/security/nsCSPParser.cpp @@ -40,16 +40,25 @@ static const char16_t UNDERLINE = '_' static const char16_t TILDE = '~'; static const char16_t WILDCARD = '*'; static const char16_t WHITESPACE = ' '; static const char16_t SINGLEQUOTE = '\''; static const char16_t OPEN_CURL = '{'; static const char16_t CLOSE_CURL = '}'; static const char16_t NUMBER_SIGN = '#'; static const char16_t QUESTIONMARK = '?'; +static const char16_t PERCENT_SIGN = '%'; +static const char16_t EXCLAMATION = '!'; +static const char16_t DOLLAR = '$'; +static const char16_t AMPERSAND = '&'; +static const char16_t OPENBRACE = '('; +static const char16_t CLOSINGBRACE = ')'; +static const char16_t COMMA = ','; +static const char16_t EQUALS = '='; +static const char16_t ATSYMBOL = '@'; static uint32_t kSubHostPathCharacterCutoff = 512; static const char* kHashSourceValidFns [] = { "sha256", "sha384", "sha512" }; static const uint32_t kHashSourceValidFnsLen = 3; /* ===== nsCSPTokenizer ==================== */ @@ -135,16 +144,24 @@ isCharacterToken(char16_t aSymbol) } bool isNumberToken(char16_t aSymbol) { return (aSymbol >= '0' && aSymbol <= '9'); } +bool +isValidHexDig(char16_t aHexDig) +{ + return (isNumberToken(aHexDig) || + (aHexDig >= 'A' && aHexDig <= 'F') || + (aHexDig >= 'a' && aHexDig <= 'f')); +} + void nsCSPParser::resetCurChar(const nsAString& aToken) { mCurChar = aToken.BeginReading(); mEndChar = aToken.EndReading(); resetCurValue(); } @@ -152,24 +169,128 @@ nsCSPParser::resetCurChar(const nsAStrin // number sign ("#") character, or by the end of the URI. // http://tools.ietf.org/html/rfc3986#section-3.3 bool nsCSPParser::atEndOfPath() { return (atEnd() || peek(QUESTIONMARK) || peek(NUMBER_SIGN)); } +void +nsCSPParser::percentDecodeStr(const nsAString& aEncStr, nsAString& outDecStr) +{ + outDecStr.Truncate(); + + // helper function that should not be visible outside this methods scope + struct local { + static inline char16_t convertHexDig(char16_t aHexDig) { + if (isNumberToken(aHexDig)) { + return aHexDig - '0'; + } + if (aHexDig >= 'A' && aHexDig <= 'F') { + return aHexDig - 'A' + 10; + } + // must be a lower case character + // (aHexDig >= 'a' && aHexDig <= 'f') + return aHexDig - 'a' + 10; + } + }; + + const char16_t *cur, *end, *hexDig1, *hexDig2; + cur = aEncStr.BeginReading(); + end = aEncStr.EndReading(); + + while (cur != end) { + // if it's not a percent sign then there is + // nothing to do for that character + if (*cur != PERCENT_SIGN) { + outDecStr.Append(*cur); + cur++; + continue; + } + + // get the two hexDigs following the '%'-sign + hexDig1 = cur + 1; + hexDig2 = cur + 2; + + // if there are no hexdigs after the '%' then + // there is nothing to do for us. + if (hexDig1 == end || hexDig2 == end || + !isValidHexDig(*hexDig1) || + !isValidHexDig(*hexDig2)) { + outDecStr.Append(PERCENT_SIGN); + cur++; + continue; + } + + // decode "% hexDig1 hexDig2" into a character. + char16_t decChar = (local::convertHexDig(*hexDig1) << 4) + + local::convertHexDig(*hexDig2); + outDecStr.Append(decChar); + + // increment 'cur' to after the second hexDig + cur = ++hexDig2; + } +} + +// unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" bool -nsCSPParser::atValidPathChar() +nsCSPParser::atValidUnreservedChar() { return (peek(isCharacterToken) || peek(isNumberToken) || peek(DASH) || peek(DOT) || peek(UNDERLINE) || peek(TILDE)); } +// sub-delims = "!" / "$" / "&" / "'" / "(" / ")" +// / "*" / "+" / "," / ";" / "=" +// Please note that even though ',' and ';' appear to be +// valid sub-delims according to the RFC production of paths, +// both can not appear here by itself, they would need to be +// pct-encoded in order to be part of the path. +bool +nsCSPParser::atValidSubDelimChar() +{ + return (peek(EXCLAMATION) || peek(DOLLAR) || peek(AMPERSAND) || + peek(SINGLEQUOTE) || peek(OPENBRACE) || peek(CLOSINGBRACE) || + peek(WILDCARD) || peek(PLUS) || peek(EQUALS)); +} + +// pct-encoded = "%" HEXDIG HEXDIG +bool +nsCSPParser::atValidPctEncodedChar() +{ + const char16_t* pctCurChar = mCurChar; + + if ((pctCurChar + 2) >= mEndChar) { + // string too short, can't be a valid pct-encoded char. + return false; + } + + // Any valid pct-encoding must follow the following format: + // "% HEXDIG HEXDIG" + if (PERCENT_SIGN != *pctCurChar || + !isValidHexDig(*(pctCurChar+1)) || + !isValidHexDig(*(pctCurChar+2))) { + return false; + } + return true; +} + +// pchar = unreserved / pct-encoded / sub-delims / ":" / "@" +// http://tools.ietf.org/html/rfc3986#section-3.3 +bool +nsCSPParser::atValidPathChar() +{ + return (atValidUnreservedChar() || + atValidSubDelimChar() || + atValidPctEncodedChar() || + peek(COLON) || peek(ATSYMBOL)); +} + void nsCSPParser::logWarningErrorToConsole(uint32_t aSeverityFlag, const char* aProperty, const char16_t* aParams[], uint32_t aParamsLength) { CSPPARSERLOG(("nsCSPParser::logWarningErrorToConsole: %s", aProperty)); @@ -248,38 +369,54 @@ nsCSPParser::subPath(nsCSPHostSrc* aCspH CSPPARSERLOG(("nsCSPParser::subPath, mCurToken: %s, mCurValue: %s", NS_ConvertUTF16toUTF8(mCurToken).get(), NS_ConvertUTF16toUTF8(mCurValue).get())); // Emergency exit to avoid endless loops in case a path in a CSP policy // is longer than 512 characters, or also to avoid endless loops // in case we are parsing unrecognized characters in the following loop. uint32_t charCounter = 0; + nsString pctDecodedSubPath; while (!atEndOfPath()) { if (peek(SLASH)) { - aCspHost->appendPath(mCurValue); + // before appendig any additional portion of a subpath we have to pct-decode + // that portion of the subpath. atValidPathChar() already verified a correct + // pct-encoding, now we can safely decode and append the decoded-sub path. + percentDecodeStr(mCurValue, pctDecodedSubPath); + aCspHost->appendPath(pctDecodedSubPath); // Resetting current value since we are appending parts of the path // to aCspHost, e.g; "http://www.example.com/path1/path2" then the // first part is "/path1", second part "/path2" resetCurValue(); } else if (!atValidPathChar()) { const char16_t* params[] = { mCurToken.get() }; logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource", params, ArrayLength(params)); return false; } + // potentially we have encountred a valid pct-encoded character in atValidPathChar(); + // if so, we have to account for "% HEXDIG HEXDIG" and advance the pointer past + // the pct-encoded char. + if (peek(PERCENT_SIGN)) { + advance(); + advance(); + } advance(); if (++charCounter > kSubHostPathCharacterCutoff) { return false; } } - aCspHost->appendPath(mCurValue); + // before appendig any additional portion of a subpath we have to pct-decode + // that portion of the subpath. atValidPathChar() already verified a correct + // pct-encoding, now we can safely decode and append the decoded-sub path. + percentDecodeStr(mCurValue, pctDecodedSubPath); + aCspHost->appendPath(pctDecodedSubPath); resetCurValue(); return true; } bool nsCSPParser::path(nsCSPHostSrc* aCspHost) { CSPPARSERLOG(("nsCSPParser::path, mCurToken: %s, mCurValue: %s", @@ -296,17 +433,19 @@ nsCSPParser::path(nsCSPHostSrc* aCspHost const char16_t* params[] = { mCurToken.get() }; logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource", params, ArrayLength(params)); return false; } if (atEndOfPath()) { // one slash right after host [port] is also considered a path, e.g. // www.example.com/ should result in www.example.com/ - aCspHost->appendPath(mCurValue); + // please note that we do not have to perform any pct-decoding here + // because we are just appending a '/' and not any actual chars. + aCspHost->appendPath(NS_LITERAL_STRING("/")); return true; } // path can begin with "/" but not "//" // see http://tools.ietf.org/html/rfc3986#section-3.3 if (!hostChar()) { const char16_t* params[] = { mCurToken.get() }; logWarningErrorToConsole(nsIScriptError::warningFlag, "couldntParseInvalidSource", params, ArrayLength(params));
--- a/dom/security/nsCSPParser.h +++ b/dom/security/nsCSPParser.h @@ -123,18 +123,23 @@ class nsCSPParser { nsCSPHostSrc* appHost(); // helper function to support app specific hosts nsCSPHostSrc* host(); bool hostChar(); bool schemeChar(); bool port(); bool path(nsCSPHostSrc* aCspHost); bool subHost(); // helper function to parse subDomains + bool atValidUnreservedChar(); // helper function to parse unreserved + bool atValidSubDelimChar(); // helper function to parse sub-delims + bool atValidPctEncodedChar(); // helper function to parse pct-encoded bool subPath(nsCSPHostSrc* aCspHost); // helper function to parse paths void reportURIList(nsTArray<nsCSPBaseSrc*>& outSrcs); // helper function to parse report-uris + void percentDecodeStr(const nsAString& aEncStr, // helper function to percent-decode + nsAString& outDecStr); inline bool atEnd() { return mCurChar >= mEndChar; } inline bool accept(char16_t aSymbol) {
--- a/dom/webidl/InputMethod.webidl +++ b/dom/webidl/InputMethod.webidl @@ -24,16 +24,30 @@ interface MozInputMethod : EventTarget { // allow to mutate. this attribute should be null when there is no // text field currently focused. readonly attribute MozInputContext? inputcontext; [ChromeOnly] // Activate or decactive current input method window. void setActive(boolean isActive); + // Add a dynamically declared input. + // + // The id must not be the same with any statically declared input in the app + // manifest. If an input of the same id is already declared, the info of that + // input will be updated. + Promise<void> addInput(DOMString inputId, object inputManifest); + + // Remove a dynamically declared input. + // + // The id must not be the same with any statically declared input in the app + // manifest. Silently resolves if the input is not previously declared; + // rejects if attempt to remove a statically declared input. + Promise<void> removeInput(DOMString id); + // The following are internal methods for Firefox OS system app only. // Set the value on the currently focused element. This has to be used // for special situations where the value had to be chosen amongst a // list (type=month) or a widget (type=date, time, etc.). // If the value passed in parameter isn't valid (in the term of HTML5 // Forms Validation), the value will simply be ignored by the element. [Throws]
--- a/dom/webidl/PeerConnectionImpl.webidl +++ b/dom/webidl/PeerConnectionImpl.webidl @@ -62,24 +62,24 @@ interface PeerConnectionImpl { /* Puts the SIPCC engine back to 'kIdle', shuts down threads, deletes state */ void close(); /* Notify DOM window if this plugin crash is ours. */ boolean pluginCrash(unsigned long long pluginId, DOMString name, DOMString pluginDumpID); /* Attributes */ + [Constant] readonly attribute DOMString fingerprint; readonly attribute DOMString localDescription; readonly attribute DOMString remoteDescription; readonly attribute PCImplIceConnectionState iceConnectionState; readonly attribute PCImplIceGatheringState iceGatheringState; readonly attribute PCImplSignalingState signalingState; - readonly attribute PCImplSipccState sipccState; attribute DOMString id; attribute DOMString peerIdentity; readonly attribute boolean privacyRequested; /* Data channels */ [Throws] DataChannel createDataChannel(DOMString label, DOMString protocol,
--- a/dom/wifi/moz.build +++ b/dom/wifi/moz.build @@ -33,8 +33,10 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk UNIFIED_SOURCES = [ 'WifiCertService.cpp', 'WifiHotspotUtils.cpp', 'WifiProxyService.cpp', 'WifiUtils.cpp', ] FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/dom/xul/nsIController.idl +++ b/dom/xul/nsIController.idl @@ -2,44 +2,42 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsISupports.idl" [scriptable, uuid(D5B61B82-1DA4-11d3-BF87-00105A1B0627)] interface nsIController : nsISupports { - boolean isCommandEnabled(in string command); - boolean supportsCommand(in string command); + boolean isCommandEnabled(in string command); + boolean supportsCommand(in string command); - void doCommand(in string command); + void doCommand(in string command); - void onEvent(in string eventName); + void onEvent(in string eventName); }; /* Enhanced controller interface that allows for passing of parameters to commands. */ interface nsICommandParams; -[scriptable, uuid(EEC0B435-7F53-44FE-B00A-CF3EED65C01A)] +[scriptable, uuid(EBE55080-C8A9-11D5-A73C-DD620D6E04BC)] interface nsICommandController : nsISupports { void getCommandStateWithParams( in string command, in nsICommandParams aCommandParams); void doCommandWithParams(in string command, in nsICommandParams aCommandParams); - void getSupportedCommands(out unsigned long count, - [array, size_is(count), retval] out string commands); }; /* An API for registering commands in groups, to allow for updating via nsIDOMWindow::UpdateCommands. */ interface nsISimpleEnumerator;
--- a/dom/xul/templates/moz.build +++ b/dom/xul/templates/moz.build @@ -50,8 +50,10 @@ MSVC_ENABLE_PGO = True LOCAL_INCLUDES += [ '/dom/base', '/dom/xul', '/layout/xul/tree/', ] FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/editor/reftests/reftest.list +++ b/editor/reftests/reftest.list @@ -93,22 +93,22 @@ skip-if(Android||B2G) needs-focus == 462 == readonly-editable.html readonly-editable-ref.html == dynamic-overflow-change.html dynamic-overflow-change-ref.html == 694880-1.html 694880-ref.html == 694880-2.html 694880-ref.html == 694880-3.html 694880-ref.html == 388980-1.html 388980-1-ref.html needs-focus == spellcheck-superscript-1.html spellcheck-superscript-1-ref.html skip-if(B2G) fails-if(Android) needs-focus != spellcheck-superscript-2.html spellcheck-superscript-2-ref.html # bug 783658 -needs-focus == 824080-1.html 824080-1-ref.html +needs-focus pref(selectioncaret.enabled,false) == 824080-1.html 824080-1-ref.html needs-focus == 824080-2.html 824080-2-ref.html -needs-focus test-pref(selectioncaret.enabled,false) == 824080-3.html 824080-3-ref.html +needs-focus pref(selectioncaret.enabled,false) == 824080-3.html 824080-3-ref.html needs-focus != 824080-2.html 824080-3.html -needs-focus == 824080-4.html 824080-4-ref.html -needs-focus test-pref(selectioncaret.enabled,false) == 824080-5.html 824080-5-ref.html +needs-focus pref(selectioncaret.enabled,false) == 824080-4.html 824080-4-ref.html +needs-focus pref(selectioncaret.enabled,false) == 824080-5.html 824080-5-ref.html needs-focus != 824080-4.html 824080-5.html needs-focus == 824080-6.html 824080-6-ref.html needs-focus pref(selectioncaret.enabled,false) == 824080-7.html 824080-7-ref.html needs-focus != 824080-6.html 824080-7.html # Bug 674927: copy spellcheck-textarea tests to contenteditable == spellcheck-contenteditable-attr.html spellcheck-contenteditable-nofocus-ref.html fails-if(Android||B2G) needs-focus != spellcheck-contenteditable-attr.html spellcheck-contenteditable-ref.html # B2G no spellcheck underline needs-focus == spellcheck-contenteditable-focused.html spellcheck-contenteditable-ref.html
--- a/embedding/components/commandhandler/nsBaseCommandController.cpp +++ b/embedding/components/commandhandler/nsBaseCommandController.cpp @@ -169,15 +169,8 @@ nsBaseCommandController::GetCommandState } NS_IMETHODIMP nsBaseCommandController::OnEvent(const char * aEventName) { NS_ENSURE_ARG_POINTER(aEventName); return NS_OK; } - -NS_IMETHODIMP -nsBaseCommandController::GetSupportedCommands(uint32_t* aCount, char*** aCommands) -{ - NS_ENSURE_STATE(mCommandTable); - return mCommandTable->GetSupportedCommands(aCount, aCommands); -}
--- a/embedding/components/commandhandler/nsControllerCommandTable.cpp +++ b/embedding/components/commandhandler/nsControllerCommandTable.cpp @@ -183,40 +183,16 @@ nsControllerCommandTable::GetCommandStat #if DEBUG NS_WARNING("Controller command table asked to do a command that it does not handle -- "); #endif return NS_OK; // we don't handle this command } return commandHandler->GetCommandStateParams(aCommandName, aParams, aCommandRefCon); } -static PLDHashOperator -AddCommand(const nsACString& aKey, nsIControllerCommand* aData, void* aArg) -{ - // aArg is a pointer to a array of strings. It gets incremented after - // allocating each one so that it points to the next location for AddCommand - // to assign a string to. - char*** commands = static_cast<char***>(aArg); - (**commands) = ToNewCString(aKey); - (*commands)++; - return PL_DHASH_NEXT; -} - -NS_IMETHODIMP -nsControllerCommandTable::GetSupportedCommands(uint32_t* aCount, - char*** aCommands) -{ - char** commands = - static_cast<char **>(NS_Alloc(sizeof(char *) * mCommandsTable.Count())); - *aCount = mCommandsTable.Count(); - *aCommands = commands; - - mCommandsTable.EnumerateRead(AddCommand, &commands); - return NS_OK; -} nsresult NS_NewControllerCommandTable(nsIControllerCommandTable** aResult) { NS_PRECONDITION(aResult != nullptr, "null ptr"); if (! aResult) return NS_ERROR_NULL_POINTER;
--- a/embedding/components/commandhandler/nsIControllerCommandTable.idl +++ b/embedding/components/commandhandler/nsIControllerCommandTable.idl @@ -13,17 +13,17 @@ * and efficiently dispatch commands to their respective handlers. * * Controllers that use an nsIControllerCommandTable should support * nsIInterfaceRequestor, and be able to return an interface to their * controller command table via getInterface(). * */ -[scriptable, uuid(c847f90e-b8f3-49db-a4df-8867831f2800)] +[scriptable, uuid(d1a47834-6ad4-11d7-bfad-000393636592)] interface nsIControllerCommandTable : nsISupports { /** * Make this command table immutable, so that commands cannot * be registered or unregistered. Some command tables are made * mutable after command registration so that they can be * used as singletons. */ @@ -77,19 +77,16 @@ interface nsIControllerCommandTable : ns * @param aCommandName the name of the command to execute * @param aCommandRefCon the command context data */ void doCommand(in string aCommandName, in nsISupports aCommandRefCon); void doCommandParams(in string aCommandName, in nsICommandParams aParam, in nsISupports aCommandRefCon); void getCommandState(in string aCommandName, in nsICommandParams aParam, in nsISupports aCommandRefCon); - - void getSupportedCommands(out unsigned long count, - [array, size_is(count), retval] out string commands); }; %{C++ // {670ee5da-6ad5-11d7-9950-000393636592} #define NS_CONTROLLERCOMMANDTABLE_CID \ {0x670ee5da, 0x6ad5, 0x11d7, \
--- a/extensions/auth/moz.build +++ b/extensions/auth/moz.build @@ -20,8 +20,10 @@ if CONFIG['OS_ARCH'] == 'WINNT': ] DEFINES['USE_SSPI'] = True else: UNIFIED_SOURCES += [ 'nsAuthSambaNTLM.cpp', ] FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/extensions/cookie/moz.build +++ b/extensions/cookie/moz.build @@ -22,8 +22,10 @@ UNIFIED_SOURCES += [ 'nsPopupWindowManager.cpp', ] MSVC_ENABLE_PGO = True include('/ipc/chromium/chromium-config.mozbuild') FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/extensions/permissions/moz.build +++ b/extensions/permissions/moz.build @@ -5,8 +5,10 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. UNIFIED_SOURCES += [ 'nsContentBlocker.cpp', 'nsModuleFactory.cpp', ] FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/extensions/pref/autoconfig/src/moz.build +++ b/extensions/pref/autoconfig/src/moz.build @@ -7,8 +7,10 @@ UNIFIED_SOURCES += [ 'nsAutoConfig.cpp', 'nsConfigFactory.cpp', 'nsJSConfigTriggers.cpp', 'nsReadConfig.cpp', ] FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/gfx/tests/gtest/moz.build +++ b/gfx/tests/gtest/moz.build @@ -18,17 +18,17 @@ UNIFIED_SOURCES += [ # Hangs on linux in ApplyGdkScreenFontOptions #'gfxFontSelectionTest.cpp', 'TestTextures.cpp', # Test works but it doesn't assert anything #'gfxTextRunPerfTest.cpp', 'TestTiledLayerBuffer.cpp', ] -# Because of gkmedia on windows we wont find these +# Because of gkmedia on windows we won't find these # symbols in xul.dll. if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'windows': UNIFIED_SOURCES += [ '%s/gfx/2d/unittest/%s' % (TOPSRCDIR, p) for p in [ 'TestBase.cpp', 'TestBugs.cpp', 'TestPoint.cpp', 'TestScaling.cpp', ]] @@ -43,8 +43,10 @@ LOCAL_INCLUDES += [ '/gfx/2d', '/gfx/2d/unittest', '/gfx/layers', ] FINAL_LIBRARY = 'xul-gtest' CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS'] + +FAIL_ON_WARNINGS = True
--- a/gfx/ycbcr/moz.build +++ b/gfx/ycbcr/moz.build @@ -65,8 +65,10 @@ if CONFIG['CPU_ARCH'] == 'arm' and CONFI SOURCES += [ 'yuv_row_arm.s', ] SOURCES += [ 'yuv_convert_arm.cpp', ] FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/image/src/DynamicImage.cpp +++ b/image/src/DynamicImage.cpp @@ -211,17 +211,18 @@ NS_IMETHODIMP_(bool) DynamicImage::IsOpaque() { // XXX(seth): For performance reasons it'd be better to return true here, but // I'm not sure how we can guarantee it for an arbitrary gfxDrawable. return false; } NS_IMETHODIMP -DynamicImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval) +DynamicImage::GetImageContainer(LayerManager* aManager, + ImageContainer** _retval) { *_retval = nullptr; return NS_OK; } NS_IMETHODIMP DynamicImage::Draw(gfxContext* aContext, const nsIntSize& aSize, @@ -326,17 +327,19 @@ DynamicImage::GetFirstFrameDelay() return 0; } NS_IMETHODIMP_(void) DynamicImage::SetAnimationStartTime(const mozilla::TimeStamp& aTime) { } nsIntSize -DynamicImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame, GraphicsFilter aFilter, uint32_t aFlags) +DynamicImage::OptimalImageSizeForDest(const gfxSize& aDest, + uint32_t aWhichFrame, + GraphicsFilter aFilter, uint32_t aFlags) { gfxIntSize size(mDrawable->Size()); return nsIntSize(size.width, size.height); } NS_IMETHODIMP_(nsIntRect) DynamicImage::GetImageSpaceInvalidationRect(const nsIntRect& aRect) {
--- a/image/src/DynamicImage.h +++ b/image/src/DynamicImage.h @@ -9,17 +9,16 @@ #include "mozilla/MemoryReporting.h" #include "gfxDrawable.h" #include "Image.h" namespace mozilla { namespace image { /** - * An Image that is dynamically created. The content of the image is provided by * a gfxDrawable. It's anticipated that most uses of DynamicImage will be * ephemeral. */ class DynamicImage : public Image { public: NS_DECL_ISUPPORTS @@ -31,18 +30,18 @@ public: MOZ_ASSERT(aDrawable, "Must have a gfxDrawable to wrap"); } // Inherited methods from Image. virtual nsresult Init(const char* aMimeType, uint32_t aFlags) MOZ_OVERRIDE; virtual already_AddRefed<ProgressTracker> GetProgressTracker() MOZ_OVERRIDE; virtual nsIntRect FrameRect(uint32_t aWhichFrame) MOZ_OVERRIDE; - - virtual size_t SizeOfSourceWithComputedFallback(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE; + virtual size_t SizeOfSourceWithComputedFallback( + MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE; virtual size_t SizeOfDecoded(gfxMemoryLocation aLocation, MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE; virtual void IncrementAnimationConsumers() MOZ_OVERRIDE; virtual void DecrementAnimationConsumers() MOZ_OVERRIDE; #ifdef DEBUG virtual uint32_t GetAnimationConsumers() MOZ_OVERRIDE; #endif
--- a/image/src/FrameBlender.cpp +++ b/image/src/FrameBlender.cpp @@ -61,19 +61,19 @@ FrameBlender::GetNumFrames() const int32_t FrameBlender::GetTimeoutForFrame(uint32_t aFrameNum) { nsRefPtr<imgFrame> frame = RawGetFrame(aFrameNum); const int32_t timeout = frame->GetRawTimeout(); // Ensure a minimal time between updates so we don't throttle the UI thread. - // consider 0 == unspecified and make it fast but not too fast. Unless we have - // a single loop GIF. See bug 890743, bug 125137, bug 139677, and bug 207059. - // The behavior of recent IE and Opera versions seems to be: + // consider 0 == unspecified and make it fast but not too fast. Unless we + // have a single loop GIF. See bug 890743, bug 125137, bug 139677, and bug + // 207059. The behavior of recent IE and Opera versions seems to be: // IE 6/Win: // 10 - 50ms go 100ms // >50ms go correct speed // Opera 7 final/Win: // 10ms goes 100ms // >10ms go correct speed // It seems that there are broken tools out there that set a 0ms or 10ms // timeout when they really want a "default" one. So munge values in that @@ -253,18 +253,20 @@ FrameBlender::DoBlend(nsIntRect* aDirtyR // Optimization: No need to dispose prev.frame when // next frame is full frame and not transparent. doDisposal = false; // No need to blank the composite frame needToBlankComposite = false; } else { if ((prevFrameRect.x >= nextFrameRect.x) && (prevFrameRect.y >= nextFrameRect.y) && - (prevFrameRect.x + prevFrameRect.width <= nextFrameRect.x + nextFrameRect.width) && - (prevFrameRect.y + prevFrameRect.height <= nextFrameRect.y + nextFrameRect.height)) { + (prevFrameRect.x + prevFrameRect.width <= + nextFrameRect.x + nextFrameRect.width) && + (prevFrameRect.y + prevFrameRect.height <= + nextFrameRect.y + nextFrameRect.height)) { // Optimization: No need to dispose prev.frame when // next frame fully overlaps previous frame. doDisposal = false; } } } if (doDisposal) { @@ -294,31 +296,34 @@ FrameBlender::DoBlend(nsIntRect* aDirtyR // compositingFrame. if (mAnim->compositingPrevFrame) { CopyFrameImage(mAnim->compositingPrevFrame->GetRawData(), mAnim->compositingPrevFrame->GetRect(), mAnim->compositingFrame->GetRawData(), mAnim->compositingFrame->GetRect()); // destroy only if we don't need it for this frame's disposal - if (nextFrameDisposalMethod != FrameBlender::kDisposeRestorePrevious) + if (nextFrameDisposalMethod != + FrameBlender::kDisposeRestorePrevious) { mAnim->compositingPrevFrame.reset(); + } } else { ClearFrame(mAnim->compositingFrame->GetRawData(), mAnim->compositingFrame->GetRect()); } break; default: - // Copy previous frame into compositingFrame before we put the new frame on top + // Copy previous frame into compositingFrame before we put the new + // frame on top // Assumes that the previous frame represents a full frame (it could be - // smaller in size than the container, as long as the frame before it erased - // itself) - // Note: Frame 1 never gets into DoBlend(), so (aNextFrameIndex - 1) will - // always be a valid frame number. + // smaller in size than the container, as long as the frame before it + // erased itself) + // Note: Frame 1 never gets into DoBlend(), so (aNextFrameIndex - 1) + // will always be a valid frame number. if (mAnim->lastCompositedFrameIndex != int32_t(aNextFrameIndex - 1)) { if (isFullPrevFrame && !prevFrame->GetIsPaletted()) { // Just copy the bits CopyFrameImage(prevFrame->GetRawData(), prevFrame->GetRect(), mAnim->compositingFrame->GetRawData(), mAnim->compositingFrame->GetRect()); } else { @@ -334,23 +339,23 @@ FrameBlender::DoBlend(nsIntRect* aDirtyR prevFrame->GetHasAlpha(), mAnim->compositingFrame->GetRawData(), mAnim->compositingFrame->GetRect(), FrameBlendMethod(prevFrame->GetBlendMethod())); } } } } else if (needToBlankComposite) { - // If we just created the composite, it could have anything in it's + // If we just created the composite, it could have anything in its // buffers. Clear them ClearFrame(mAnim->compositingFrame->GetRawData(), mAnim->compositingFrame->GetRect()); } - // Check if the frame we are composing wants the previous image restored afer + // Check if the frame we are composing wants the previous image restored after // it is done. Don't store it (again) if last frame wanted its image restored // too if ((nextFrameDisposalMethod == FrameBlender::kDisposeRestorePrevious) && (prevFrameDisposalMethod != FrameBlender::kDisposeRestorePrevious)) { // We are storing the whole image. // It would be better if we just stored the area that nextFrame is going to // overwrite. if (!mAnim->compositingPrevFrame) { @@ -395,65 +400,68 @@ FrameBlender::DoBlend(nsIntRect* aDirtyR return true; } //****************************************************************************** // Fill aFrame with black. Does also clears the mask. void FrameBlender::ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect) { - if (!aFrameData) + if (!aFrameData) { return; + } memset(aFrameData, 0, aFrameRect.width * aFrameRect.height * 4); } //****************************************************************************** void -FrameBlender::ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect, const nsIntRect& aRectToClear) +FrameBlender::ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect, + const nsIntRect& aRectToClear) { if (!aFrameData || aFrameRect.width <= 0 || aFrameRect.height <= 0 || aRectToClear.width <= 0 || aRectToClear.height <= 0) { return; } nsIntRect toClear = aFrameRect.Intersect(aRectToClear); if (toClear.IsEmpty()) { return; } uint32_t bytesPerRow = aFrameRect.width * 4; for (int row = toClear.y; row < toClear.y + toClear.height; ++row) { - memset(aFrameData + toClear.x * 4 + row * bytesPerRow, 0, toClear.width * 4); + memset(aFrameData + toClear.x * 4 + row * bytesPerRow, 0, + toClear.width * 4); } } //****************************************************************************** // Whether we succeed or fail will not cause a crash, and there's not much // we can do about a failure, so there we don't return a nsresult bool -FrameBlender::CopyFrameImage(const uint8_t *aDataSrc, const nsIntRect& aRectSrc, - uint8_t *aDataDest, const nsIntRect& aRectDest) +FrameBlender::CopyFrameImage(const uint8_t* aDataSrc, const nsIntRect& aRectSrc, + uint8_t* aDataDest, const nsIntRect& aRectDest) { uint32_t dataLengthSrc = aRectSrc.width * aRectSrc.height * 4; uint32_t dataLengthDest = aRectDest.width * aRectDest.height * 4; if (!aDataDest || !aDataSrc || dataLengthSrc != dataLengthDest) { return false; } memcpy(aDataDest, aDataSrc, dataLengthDest); return true; } nsresult -FrameBlender::DrawFrameTo(const uint8_t *aSrcData, const nsIntRect& aSrcRect, +FrameBlender::DrawFrameTo(const uint8_t* aSrcData, const nsIntRect& aSrcRect, uint32_t aSrcPaletteLength, bool aSrcHasAlpha, - uint8_t *aDstPixels, const nsIntRect& aDstRect, + uint8_t* aDstPixels, const nsIntRect& aDstRect, FrameBlender::FrameBlendMethod aBlendMethod) { NS_ENSURE_ARG_POINTER(aSrcData); NS_ENSURE_ARG_POINTER(aDstPixels); // According to both AGIF and APNG specs, offsets are unsigned if (aSrcRect.x < 0 || aSrcRect.y < 0) { NS_WARNING("FrameBlender::DrawFrameTo: negative offsets not allowed"); @@ -475,56 +483,61 @@ FrameBlender::DrawFrameTo(const uint8_t (aSrcRect.y + height <= aDstRect.height), "FrameBlender::DrawFrameTo: Invalid aSrcRect"); // clipped image size may be smaller than source, but not larger NS_ASSERTION((width <= aSrcRect.width) && (height <= aSrcRect.height), "FrameBlender::DrawFrameTo: source must be smaller than dest"); // Get pointers to image data - const uint8_t *srcPixels = aSrcData + aSrcPaletteLength; - uint32_t *dstPixels = reinterpret_cast<uint32_t*>(aDstPixels); - const uint32_t *colormap = reinterpret_cast<const uint32_t*>(aSrcData); + const uint8_t* srcPixels = aSrcData + aSrcPaletteLength; + uint32_t* dstPixels = reinterpret_cast<uint32_t*>(aDstPixels); + const uint32_t* colormap = reinterpret_cast<const uint32_t*>(aSrcData); // Skip to the right offset dstPixels += aSrcRect.x + (aSrcRect.y * aDstRect.width); if (!aSrcHasAlpha) { for (int32_t r = height; r > 0; --r) { for (int32_t c = 0; c < width; c++) { dstPixels[c] = colormap[srcPixels[c]]; } // Go to the next row in the source resp. destination image srcPixels += aSrcRect.width; dstPixels += aDstRect.width; } } else { for (int32_t r = height; r > 0; --r) { for (int32_t c = 0; c < width; c++) { const uint32_t color = colormap[srcPixels[c]]; - if (color) + if (color) { dstPixels[c] = color; + } } // Go to the next row in the source resp. destination image srcPixels += aSrcRect.width; dstPixels += aDstRect.width; } } } else { - pixman_image_t* src = pixman_image_create_bits(aSrcHasAlpha ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8, - aSrcRect.width, - aSrcRect.height, - reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(aSrcData)), - aSrcRect.width * 4); - pixman_image_t* dst = pixman_image_create_bits(PIXMAN_a8r8g8b8, - aDstRect.width, - aDstRect.height, - reinterpret_cast<uint32_t*>(aDstPixels), - aDstRect.width * 4); + pixman_image_t* src = + pixman_image_create_bits( + aSrcHasAlpha ? PIXMAN_a8r8g8b8 : PIXMAN_x8r8g8b8, + aSrcRect.width, aSrcRect.height, + reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(aSrcData)), + aSrcRect.width * 4); + pixman_image_t* dst = + pixman_image_create_bits(PIXMAN_a8r8g8b8, + aDstRect.width, + aDstRect.height, + reinterpret_cast<uint32_t*>(aDstPixels), + aDstRect.width * 4); - pixman_image_composite32(aBlendMethod == FrameBlender::kBlendSource ? PIXMAN_OP_SRC : PIXMAN_OP_OVER, + auto op = aBlendMethod == FrameBlender::kBlendSource ? PIXMAN_OP_SRC + : PIXMAN_OP_OVER; + pixman_image_composite32(op, src, nullptr, dst, 0, 0, 0, 0, aSrcRect.x, aSrcRect.y, aSrcRect.width, aSrcRect.height);
--- a/image/src/FrameBlender.h +++ b/image/src/FrameBlender.h @@ -50,19 +50,20 @@ public: void InsertFrame(uint32_t aFrameNum, RawAccessFrameRef&& aRef); void RemoveFrame(uint32_t aFrameNum); void ClearFrames(); /* The total number of frames in this image. */ uint32_t GetNumFrames() const; /* - * Returns the frame's adjusted timeout. If the animation loops and the timeout - * falls in between a certain range then the timeout is adjusted so that - * it's never 0. If the animation does not loop then no adjustments are made. + * Returns the frame's adjusted timeout. If the animation loops and the + * timeout falls in between a certain range then the timeout is adjusted so + * that it's never 0. If the animation does not loop then no adjustments are + * made. */ int32_t GetTimeoutForFrame(uint32_t aFrameNum); /* * Set number of times to loop the image. * @note -1 means loop forever. */ void SetLoopCount(int32_t aLoopCount); @@ -125,55 +126,56 @@ private: /** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS * * The Previous Frame (all frames composited up to the current) needs to be * stored in cases where the image specifies it wants the last frame back * when it's done with the current frame. */ RawAccessFrameRef compositingPrevFrame; - Anim() : - lastCompositedFrameIndex(-1) - {} + Anim() : lastCompositedFrameIndex(-1) { } }; /** Clears an area of <aFrame> with transparent black. * * @param aFrameData Target Frame data * @param aFrameRect The rectangle of the data pointed ot by aFrameData * - * @note Does also clears the transparancy mask + * @note Does also clears the transparency mask */ static void ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect); //! @overload - static void ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect, const nsIntRect &aRectToClear); + static void ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect, + const nsIntRect& aRectToClear); - //! Copy one frames's image and mask into another - static bool CopyFrameImage(const uint8_t *aDataSrc, const nsIntRect& aRectSrc, - uint8_t *aDataDest, const nsIntRect& aRectDest); + //! Copy one frame's image and mask into another + static bool CopyFrameImage(const uint8_t* aDataSrc, const nsIntRect& aRectSrc, + uint8_t* aDataDest, const nsIntRect& aRectDest); /** - * Draws one frames's image to into another, at the position specified by + * Draws one frame's image to into another, at the position specified by * aSrcRect. * * @aSrcData the raw data of the current frame being drawn * @aSrcRect the size of the source frame, and the position of that frame in * the composition frame * @aSrcPaletteLength the length (in bytes) of the palette at the beginning * of the source data (0 if image is not paletted) * @aSrcHasAlpha whether the source data represents an image with alpha * @aDstPixels the raw data of the composition frame where the current frame * is drawn into (32-bit ARGB) * @aDstRect the size of the composition frame - * @aBlendMethod the blend method for how to blend src on the composition frame. + * @aBlendMethod the blend method for how to blend src on the composition + * frame. */ - static nsresult DrawFrameTo(const uint8_t *aSrcData, const nsIntRect& aSrcRect, + static nsresult DrawFrameTo(const uint8_t* aSrcData, + const nsIntRect& aSrcRect, uint32_t aSrcPaletteLength, bool aSrcHasAlpha, - uint8_t *aDstPixels, const nsIntRect& aDstRect, + uint8_t* aDstPixels, const nsIntRect& aDstRect, FrameBlendMethod aBlendMethod); private: // data //! All the frames of the image nsTArray<RawAccessFrameRef> mFrames; nsIntSize mSize; Anim* mAnim; int32_t mLoopCount;
--- a/image/src/ImageFactory.cpp +++ b/image/src/ImageFactory.cpp @@ -24,55 +24,60 @@ #include "ImageFactory.h" #include "gfxPrefs.h" namespace mozilla { namespace image { /*static*/ void ImageFactory::Initialize() -{ -} +{ } static uint32_t ComputeImageFlags(ImageURL* uri, bool isMultiPart) { nsresult rv; // We default to the static globals. bool isDiscardable = gfxPrefs::ImageMemDiscardable(); bool doDecodeOnDraw = gfxPrefs::ImageMemDecodeOnDraw(); - // We want UI to be as snappy as possible and not to flicker. Disable discarding - // and decode-on-draw for chrome URLS. + // We want UI to be as snappy as possible and not to flicker. Disable + // discarding and decode-on-draw for chrome URLS. bool isChrome = false; rv = uri->SchemeIs("chrome", &isChrome); - if (NS_SUCCEEDED(rv) && isChrome) + if (NS_SUCCEEDED(rv) && isChrome) { isDiscardable = doDecodeOnDraw = false; + } // We don't want resources like the "loading" icon to be discardable or // decode-on-draw either. bool isResource = false; rv = uri->SchemeIs("resource", &isResource); - if (NS_SUCCEEDED(rv) && isResource) + if (NS_SUCCEEDED(rv) && isResource) { isDiscardable = doDecodeOnDraw = false; + } // For multipart/x-mixed-replace, we basically want a direct channel to the // decoder. Disable both for this case as well. - if (isMultiPart) + if (isMultiPart) { isDiscardable = doDecodeOnDraw = false; + } // We have all the information we need. uint32_t imageFlags = Image::INIT_FLAG_NONE; - if (isDiscardable) + if (isDiscardable) { imageFlags |= Image::INIT_FLAG_DISCARDABLE; - if (doDecodeOnDraw) + } + if (doDecodeOnDraw) { imageFlags |= Image::INIT_FLAG_DECODE_ON_DRAW; - if (isMultiPart) + } + if (isMultiPart) { imageFlags |= Image::INIT_FLAG_MULTIPART; + } return imageFlags; } /* static */ bool ImageFactory::CanRetargetOnDataAvailable(ImageURL* aURI, bool aIsMultiPart) { // We can't retarget OnDataAvailable safely in cases where we aren't storing @@ -140,20 +145,22 @@ ImageFactory::CreateAnonymousImage(const NS_ENSURE_SUCCESS(rv, BadImage(newImage)); return newImage.forget(); } int32_t SaturateToInt32(int64_t val) { - if (val > INT_MAX) + if (val > INT_MAX) { return INT_MAX; - if (val < INT_MIN) + } + if (val < INT_MIN) { return INT_MIN; + } return static_cast<int32_t>(val); } uint32_t GetContentSize(nsIRequest* aRequest) { nsCOMPtr<nsIChannel> channel(do_QueryInterface(aRequest)); @@ -200,17 +207,18 @@ ImageFactory::CreateRasterImage(nsIReque newImage->SetInnerWindowID(aInnerWindowId); uint32_t len = GetContentSize(aRequest); // Pass anything usable on so that the RasterImage can preallocate // its source buffer. if (len > 0) { - uint32_t sizeHint = std::min<uint32_t>(len, 20000000); // Bound by something reasonable + // Bound by something reasonable + uint32_t sizeHint = std::min<uint32_t>(len, 20000000); rv = newImage->SetSourceSizeHint(sizeHint); if (NS_FAILED(rv)) { // Flush memory, try to get some back, and try again. rv = nsMemory::HeapMinimize(true); nsresult rv2 = newImage->SetSourceSizeHint(sizeHint); // If we've still failed at this point, things are going downhill. if (NS_FAILED(rv) || NS_FAILED(rv2)) { NS_WARNING("About to hit OOM in imagelib!"); @@ -225,18 +233,18 @@ ImageFactory::CreateRasterImage(nsIReque newImage->SetRequestedResolution(parser.GetResolution()); } if (parser.HasSampleSize()) { /* Get our principal */ nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest)); nsCOMPtr<nsIPrincipal> principal; if (chan) { - nsContentUtils::GetSecurityManager()->GetChannelResultPrincipal(chan, - getter_AddRefs(principal)); + nsContentUtils::GetSecurityManager() + ->GetChannelResultPrincipal(chan, getter_AddRefs(principal)); } if ((principal && principal->GetAppStatus() == nsIPrincipal::APP_STATUS_CERTIFIED) || gfxPrefs::ImageMozSampleSizeEnabled()) { newImage->SetRequestedSampleSize(parser.GetSampleSize()); } }
--- a/image/src/ImageFactory.h +++ b/image/src/ImageFactory.h @@ -54,33 +54,36 @@ public: bool aIsMultiPart, uint32_t aInnerWindowId); /** * Creates a new image which isn't associated with a URI or loaded through * the usual image loading mechanism. * * @param aMimeType The mimetype of the image. */ - static already_AddRefed<Image> CreateAnonymousImage(const nsCString& aMimeType); + static already_AddRefed<Image> + CreateAnonymousImage(const nsCString& aMimeType); private: // Factory functions that create specific types of image containers. - static already_AddRefed<Image> CreateRasterImage(nsIRequest* aRequest, - ProgressTracker* aProgressTracker, - const nsCString& aMimeType, - ImageURL* aURI, - uint32_t aImageFlags, - uint32_t aInnerWindowId); + static already_AddRefed<Image> + CreateRasterImage(nsIRequest* aRequest, + ProgressTracker* aProgressTracker, + const nsCString& aMimeType, + ImageURL* aURI, + uint32_t aImageFlags, + uint32_t aInnerWindowId); - static already_AddRefed<Image> CreateVectorImage(nsIRequest* aRequest, - ProgressTracker* aProgressTracker, - const nsCString& aMimeType, - ImageURL* aURI, - uint32_t aImageFlags, - uint32_t aInnerWindowId); + static already_AddRefed<Image> + CreateVectorImage(nsIRequest* aRequest, + ProgressTracker* aProgressTracker, + const nsCString& aMimeType, + ImageURL* aURI, + uint32_t aImageFlags, + uint32_t aInnerWindowId); // This is a static factory class, so disallow instantiation. virtual ~ImageFactory() = 0; }; } // namespace image } // namespace mozilla
--- a/image/src/Orientation.h +++ b/image/src/Orientation.h @@ -26,17 +26,18 @@ MOZ_END_ENUM_CLASS(Flip) /** * A struct that describes an image's orientation as a rotation optionally * followed by a reflection. This may be used to be indicate an image's inherent * orientation or a desired orientation for the image. */ struct Orientation { - explicit Orientation(Angle aRotation = Angle::D0, Flip mFlip = Flip::Unflipped) + explicit Orientation(Angle aRotation = Angle::D0, + Flip mFlip = Flip::Unflipped) : rotation(aRotation) , flip(mFlip) { } bool IsIdentity() const { return (rotation == Angle::D0) && (flip == Flip::Unflipped); }
--- a/image/src/OrientedImage.cpp +++ b/image/src/OrientedImage.cpp @@ -136,22 +136,23 @@ OrientedImage::GetFrame(uint32_t aWhichF new gfxSurfaceDrawable(innerSurface, size); // Draw. nsRefPtr<gfxContext> ctx = new gfxContext(target); ctx->Multiply(OrientationMatrix(size)); gfxUtils::DrawPixelSnapped(ctx, drawable, size, ImageRegion::Create(size), surfaceFormat, GraphicsFilter::FILTER_FAST); - + return target->Snapshot(); } NS_IMETHODIMP -OrientedImage::GetImageContainer(LayerManager* aManager, ImageContainer** _retval) +OrientedImage::GetImageContainer(LayerManager* aManager, + ImageContainer** _retval) { // XXX(seth): We currently don't have a way of orienting the result of // GetImageContainer. We work around this by always returning null, but if it // ever turns out that OrientedImage is widely used on codepaths that can // actually benefit from GetImageContainer, it would be a good idea to fix // that method for performance reasons. if (mOrientation.IsIdentity()) { @@ -163,33 +164,36 @@ OrientedImage::GetImageContainer(LayerMa } struct MatrixBuilder { explicit MatrixBuilder(bool aInvert) : mInvert(aInvert) { } gfxMatrix Build() { return mMatrix; } - void Scale(gfxFloat aX, gfxFloat aY) { + void Scale(gfxFloat aX, gfxFloat aY) + { if (mInvert) { mMatrix *= gfxMatrix::Scaling(1.0 / aX, 1.0 / aY); } else { mMatrix.Scale(aX, aY); } } - void Rotate(gfxFloat aPhi) { + void Rotate(gfxFloat aPhi) + { if (mInvert) { mMatrix *= gfxMatrix::Rotation(-aPhi); } else { mMatrix.Rotate(aPhi); } } - void Translate(gfxPoint aDelta) { + void Translate(gfxPoint aDelta) + { if (mInvert) { mMatrix *= gfxMatrix::Translation(-aDelta); } else { mMatrix.Translate(aDelta); } } private: @@ -305,21 +309,23 @@ OrientedImage::Draw(gfxContext* aContext region.TransformBoundsBy(inverseMatrix); return InnerImage()->Draw(aContext, size, region, aWhichFrame, aFilter, aSVGContext.map(OrientViewport, mOrientation), aFlags); } nsIntSize -OrientedImage::OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame, +OrientedImage::OptimalImageSizeForDest(const gfxSize& aDest, + uint32_t aWhichFrame, GraphicsFilter aFilter, uint32_t aFlags) { if (!mOrientation.SwapsWidthAndHeight()) { - return InnerImage()->OptimalImageSizeForDest(aDest, aWhichFrame, aFilter, aFlags); + return InnerImage()->OptimalImageSizeForDest(aDest, aWhichFrame, aFilter, + aFlags); } // Swap the size for the calculation, then swap it back for the caller. gfxSize destSize(aDest.height, aDest.width); nsIntSize innerImageSize(InnerImage()->OptimalImageSizeForDest(destSize, aWhichFrame, aFilter, aFlags));
--- a/image/src/OrientedImage.h +++ b/image/src/OrientedImage.h @@ -40,22 +40,23 @@ public: layers::ImageContainer** _retval) MOZ_OVERRIDE; NS_IMETHOD Draw(gfxContext* aContext, const nsIntSize& aSize, const ImageRegion& aRegion, uint32_t aWhichFrame, GraphicsFilter aFilter, const Maybe<SVGImageContext>& aSVGContext, uint32_t aFlags) MOZ_OVERRIDE; - NS_IMETHOD_(nsIntRect) GetImageSpaceInvalidationRect(const nsIntRect& aRect) MOZ_OVERRIDE; + NS_IMETHOD_(nsIntRect) GetImageSpaceInvalidationRect( + const nsIntRect& aRect) MOZ_OVERRIDE; nsIntSize OptimalImageSizeForDest(const gfxSize& aDest, uint32_t aWhichFrame, GraphicsFilter aFilter, uint32_t aFlags) MOZ_OVERRIDE; - + protected: OrientedImage(Image* aImage, Orientation aOrientation) : ImageWrapper(aImage) , mOrientation(aOrientation) { } virtual ~OrientedImage() { }
--- a/image/src/ProgressTracker.cpp +++ b/image/src/ProgressTracker.cpp @@ -102,17 +102,18 @@ ProgressTracker::SetImage(Image* aImage) void ProgressTracker::ResetImage() { NS_ABORT_IF_FALSE(mImage, "Resetting image when it's already null!"); mImage = nullptr; } -void ProgressTracker::SetIsMultipart() +void +ProgressTracker::SetIsMultipart() { if (mProgress & FLAG_IS_MULTIPART) { return; } MOZ_ASSERT(!(mProgress & FLAG_ONLOAD_BLOCKED), "Blocked onload before we knew we were multipart?"); @@ -213,19 +214,21 @@ void ProgressTracker::Notify(imgRequestProxy* proxy) { MOZ_ASSERT(NS_IsMainThread(), "imgRequestProxy is not threadsafe"); #ifdef PR_LOGGING if (mImage && mImage->GetURI()) { nsRefPtr<ImageURL> uri(mImage->GetURI()); nsAutoCString spec; uri->GetSpec(spec); - LOG_FUNC_WITH_PARAM(GetImgLog(), "ProgressTracker::Notify async", "uri", spec.get()); + LOG_FUNC_WITH_PARAM(GetImgLog(), + "ProgressTracker::Notify async", "uri", spec.get()); } else { - LOG_FUNC_WITH_PARAM(GetImgLog(), "ProgressTracker::Notify async", "uri", "<unknown>"); + LOG_FUNC_WITH_PARAM(GetImgLog(), + "ProgressTracker::Notify async", "uri", "<unknown>"); } #endif proxy->SetNotificationsDeferred(true); // If we have an existing runnable that we can use, we just append this proxy // to its list of proxies to be notified. This ensures we don't unnecessarily // delay onload. @@ -278,17 +281,18 @@ void ProgressTracker::NotifyCurrentState(imgRequestProxy* proxy) { MOZ_ASSERT(NS_IsMainThread(), "imgRequestProxy is not threadsafe"); #ifdef PR_LOGGING nsRefPtr<ImageURL> uri; proxy->GetURI(getter_AddRefs(uri)); nsAutoCString spec; uri->GetSpec(spec); - LOG_FUNC_WITH_PARAM(GetImgLog(), "ProgressTracker::NotifyCurrentState", "uri", spec.get()); + LOG_FUNC_WITH_PARAM(GetImgLog(), + "ProgressTracker::NotifyCurrentState", "uri", spec.get()); #endif proxy->SetNotificationsDeferred(true); nsCOMPtr<nsIRunnable> ev = new AsyncNotifyCurrentStateRunnable(this, proxy); NS_DispatchToCurrentThread(ev); } @@ -306,41 +310,48 @@ ProgressTracker::NotifyCurrentState(imgR /* static */ void ProgressTracker::SyncNotifyInternal(ProxyArray& aProxies, bool aHasImage, Progress aProgress, const nsIntRect& aDirtyRect) { MOZ_ASSERT(NS_IsMainThread()); - if (aProgress & FLAG_SIZE_AVAILABLE) + if (aProgress & FLAG_SIZE_AVAILABLE) { NOTIFY_IMAGE_OBSERVERS(aProxies, OnSizeAvailable()); + } - if (aProgress & FLAG_DECODE_STARTED) + if (aProgress & FLAG_DECODE_STARTED) { NOTIFY_IMAGE_OBSERVERS(aProxies, OnStartDecode()); + } - if (aProgress & FLAG_ONLOAD_BLOCKED) + if (aProgress & FLAG_ONLOAD_BLOCKED) { NOTIFY_IMAGE_OBSERVERS(aProxies, BlockOnload()); + } if (aHasImage) { // OnFrameUpdate // If there's any content in this frame at all (always true for // vector images, true for raster images that have decoded at // least one frame) then send OnFrameUpdate. - if (!aDirtyRect.IsEmpty()) + if (!aDirtyRect.IsEmpty()) { NOTIFY_IMAGE_OBSERVERS(aProxies, OnFrameUpdate(&aDirtyRect)); + } - if (aProgress & FLAG_FRAME_COMPLETE) + if (aProgress & FLAG_FRAME_COMPLETE) { NOTIFY_IMAGE_OBSERVERS(aProxies, OnFrameComplete()); + } - if (aProgress & FLAG_HAS_TRANSPARENCY) + if (aProgress & FLAG_HAS_TRANSPARENCY) { NOTIFY_IMAGE_OBSERVERS(aProxies, OnImageHasTransparency()); + } - if (aProgress & FLAG_IS_ANIMATED) + if (aProgress & FLAG_IS_ANIMATED) { NOTIFY_IMAGE_OBSERVERS(aProxies, OnImageIsAnimated()); + } } // Send UnblockOnload before OnStopDecode and OnStopRequest. This allows // observers that can fire events when they receive those notifications to do // so then, instead of being forced to wait for UnblockOnload. if (aProgress & FLAG_ONLOAD_UNBLOCKED) { NOTIFY_IMAGE_OBSERVERS(aProxies, UnblockOnload()); } @@ -353,17 +364,18 @@ ProgressTracker::SyncNotifyInternal(Prox if (aProgress & FLAG_LOAD_COMPLETE) { NOTIFY_IMAGE_OBSERVERS(aProxies, OnLoadComplete(aProgress & FLAG_LAST_PART_COMPLETE)); } } void ProgressTracker::SyncNotifyProgress(Progress aProgress, - const nsIntRect& aInvalidRect /* = nsIntRect() */) + const nsIntRect& aInvalidRect + /* = nsIntRect() */) { MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only"); // Don't unblock onload if we're not blocked. Progress progress = Difference(aProgress); if (!((mProgress | progress) & FLAG_ONLOAD_BLOCKED)) { progress &= ~FLAG_ONLOAD_UNBLOCKED; } @@ -385,17 +397,18 @@ void ProgressTracker::SyncNotify(imgRequestProxy* proxy) { MOZ_ASSERT(NS_IsMainThread(), "imgRequestProxy is not threadsafe"); #ifdef PR_LOGGING nsRefPtr<ImageURL> uri; proxy->GetURI(getter_AddRefs(uri)); nsAutoCString spec; uri->GetSpec(spec); - LOG_SCOPE_WITH_PARAM(GetImgLog(), "ProgressTracker::SyncNotify", "uri", spec.get()); + LOG_SCOPE_WITH_PARAM(GetImgLog(), + "ProgressTracker::SyncNotify", "uri", spec.get()); #endif nsIntRect r; if (mImage) { // XXX - Should only send partial rects here, but that needs to // wait until we fix up the observer interface r = mImage->FrameRect(imgIContainer::FRAME_CURRENT); }
--- a/image/src/ProgressTracker.h +++ b/image/src/ProgressTracker.h @@ -98,17 +98,17 @@ public: // not received OnStopRequest from Necko. bool IsLoading() const; // Get the current image status (as in imgIRequest). uint32_t GetImageStatus() const; // Get the current Progress. Progress GetProgress() const { return mProgress; } - + // Schedule an asynchronous "replaying" of all the notifications that would // have to happen to put us in the current state. // We will also take note of any notifications that happen between the time // Notify() is called and when we call SyncNotify on |proxy|, and replay them // as well. // Should be called on the main thread only, since imgRequestProxy and GetURI // are not threadsafe. void Notify(imgRequestProxy* proxy); @@ -159,19 +159,19 @@ public: // with its loading progress. Weak pointers. void AddConsumer(imgRequestProxy* aConsumer); bool RemoveConsumer(imgRequestProxy* aConsumer, nsresult aStatus); size_t ConsumerCount() const { MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only"); return mConsumers.Length(); } - // This is intentionally non-general because its sole purpose is to support an - // some obscure network priority logic in imgRequest. That stuff could probably - // be improved, but it's too scary to mess with at the moment. + // This is intentionally non-general because its sole purpose is to support + // some obscure network priority logic in imgRequest. That stuff could + // probably be improved, but it's too scary to mess with at the moment. bool FirstConsumerIs(imgRequestProxy* aConsumer); void AdoptConsumers(ProgressTracker* aTracker) { MOZ_ASSERT(NS_IsMainThread(), "Use mConsumers on main thread only"); MOZ_ASSERT(aTracker); mConsumers = aTracker->mConsumers; }
--- a/intl/chardet/moz.build +++ b/intl/chardet/moz.build @@ -12,8 +12,10 @@ EXPORTS += [ ] UNIFIED_SOURCES += [ 'nsChardetModule.cpp', 'nsCyrillicDetector.cpp', ] FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/intl/hyphenation/moz.build +++ b/intl/hyphenation/moz.build @@ -25,8 +25,11 @@ MSVC_ENABLE_PGO = True FINAL_LIBRARY = 'xul' # Suppress warnings in third-party code. if CONFIG['GNU_CC']: CFLAGS += [ '-Wno-sign-compare', '-Wno-type-limits', ] + +if CONFIG['GNU_CXX']: + FAIL_ON_WARNINGS = True
--- a/intl/locale/mac/moz.build +++ b/intl/locale/mac/moz.build @@ -12,8 +12,9 @@ UNIFIED_SOURCES += [ FINAL_LIBRARY = 'xul' LOCAL_INCLUDES += [ '..', '../../icu/source/common', '../../icu/source/i18n', ] +FAIL_ON_WARNINGS = True
--- a/intl/locale/moz.build +++ b/intl/locale/moz.build @@ -58,8 +58,10 @@ LOCAL_INCLUDES += [ RESOURCE_FILES += [ 'langGroups.properties', 'language.properties', ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt': CXXFLAGS += CONFIG['MOZ_QT_CFLAGS'] + +FAIL_ON_WARNINGS = True
--- a/intl/lwbrk/moz.build +++ b/intl/lwbrk/moz.build @@ -45,8 +45,10 @@ else: ] MSVC_ENABLE_PGO = True FINAL_LIBRARY = 'xul' if CONFIG['MOZ_WIDGET_GTK']: CXXFLAGS += CONFIG['MOZ_PANGO_CFLAGS'] + +FAIL_ON_WARNINGS = True
--- a/intl/strres/moz.build +++ b/intl/strres/moz.build @@ -16,8 +16,10 @@ XPIDL_MODULE = 'intl' UNIFIED_SOURCES += [ 'nsStringBundle.cpp', 'nsStringBundleTextOverride.cpp', ] MSVC_ENABLE_PGO = True FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/intl/unicharutil/moz.build +++ b/intl/unicharutil/moz.build @@ -26,8 +26,10 @@ UNIFIED_SOURCES += [ 'nsCaseConversionImp2.cpp', 'nsCategoryImp.cpp', 'nsEntityConverter.cpp', 'nsSaveAsCharset.cpp', 'nsUnicodeNormalizer.cpp', ] FINAL_LIBRARY = 'xul' + +FAIL_ON_WARNINGS = True
--- a/intl/unicharutil/util/internal/moz.build +++ b/intl/unicharutil/util/internal/moz.build @@ -8,8 +8,10 @@ include('../objs.mozbuild') UNIFIED_SOURCES += intl_unicharutil_util_cppsrcs FINAL_LIBRARY = 'xul' LOCAL_INCLUDES += [ '..', ] + +FAIL_ON_WARNINGS = True
--- a/intl/unicharutil/util/moz.build +++ b/intl/unicharutil/util/moz.build @@ -32,8 +32,11 @@ USE_STATIC_LIBS = True if CONFIG['_MSC_VER']: DEFINES['_USE_ANSI_CPP'] = True # Don't include directives about which CRT to use CFLAGS += ['-Zl'] CXXFLAGS += ['-Zl'] if CONFIG['ENABLE_INTL_API']: CXXFLAGS += CONFIG['MOZ_ICU_CFLAGS'] + +if CONFIG['GNU_CXX']: + FAIL_ON_WARNINGS = True
new file mode 100644 --- /dev/null +++ b/js/src/jit-test/tests/debug/bug-1103813.js @@ -0,0 +1,6 @@ +// Random chosen test: js/src/jit-test/tests/debug/Source-invisible.js +newGlobal({ + invisibleToDebugger: true +}) +// Random chosen test: js/src/jit-test/tests/debug/Debugger-findObjects-05.js +x = (new Debugger).findObjects()
--- a/js/src/jit/shared/Assembler-x86-shared.cpp +++ b/js/src/jit/shared/Assembler-x86-shared.cpp @@ -133,16 +133,18 @@ AssemblerX86Shared::InvertCondition(Cond return Above; default: MOZ_CRASH("unexpected condition"); } } CPUInfo::SSEVersion CPUInfo::maxSSEVersion = UnknownSSE; CPUInfo::SSEVersion CPUInfo::maxEnabledSSEVersion = UnknownSSE; +bool CPUInfo::avxPresent = false; +bool CPUInfo::avxEnabled = true; void CPUInfo::SetSSEVersion() { int flagsEDX = 0; int flagsECX = 0; #ifdef _MSC_VER @@ -191,9 +193,12 @@ CPUInfo::SetSSEVersion() else if (flagsECX & SSSE3Bit) maxSSEVersion = SSSE3; else if (flagsECX & SSE3Bit) maxSSEVersion = SSE3; else if (flagsEDX & SSE2Bit) maxSSEVersion = SSE2; else if (flagsEDX & SSEBit) maxSSEVersion = SSE; else maxSSEVersion = NoSSE; if (maxEnabledSSEVersion != UnknownSSE) maxSSEVersion = Min(maxSSEVersion, maxEnabledSSEVersion); + + static const int AVXBit = 1 << 28; + avxPresent = (flagsECX & AVXBit) && avxEnabled; }
--- a/js/src/jit/shared/Assembler-x86-shared.h +++ b/js/src/jit/shared/Assembler-x86-shared.h @@ -144,19 +144,29 @@ class CPUInfo if (maxSSEVersion == UnknownSSE) SetSSEVersion(); MOZ_ASSERT(maxSSEVersion != UnknownSSE); MOZ_ASSERT_IF(maxEnabledSSEVersion != UnknownSSE, maxSSEVersion <= maxEnabledSSEVersion); return maxSSEVersion; } + static bool IsAVXPresent() { + if (MOZ_UNLIKELY(maxSSEVersion == UnknownSSE)) + SetSSEVersion(); + + MOZ_ASSERT_IF(!avxEnabled, !avxPresent); + return avxPresent; + } + private: static SSEVersion maxSSEVersion; static SSEVersion maxEnabledSSEVersion; + static bool avxPresent; + static bool avxEnabled; static void SetSSEVersion(); public: static bool IsSSE2Present() { #ifdef JS_CODEGEN_X64 return true; #else @@ -164,20 +174,21 @@ class CPUInfo #endif } static bool IsSSE3Present() { return GetSSEVersion() >= SSE3; } static bool IsSSSE3Present() { return GetSSEVersion() >= SSSE3; } static bool IsSSE41Present() { return GetSSEVersion() >= SSE4_1; } static bool IsSSE42Present() { return GetSSEVersion() >= SSE4_2; } #ifdef JS_CODEGEN_X86 - static void SetFloatingPointDisabled() { maxEnabledSSEVersion = NoSSE; } + static void SetFloatingPointDisabled() { maxEnabledSSEVersion = NoSSE; avxEnabled = false; } #endif - static void SetSSE3Disabled() { maxEnabledSSEVersion = SSE2; } - static void SetSSE4Disabled() { maxEnabledSSEVersion = SSSE3; } + static void SetSSE3Disabled() { maxEnabledSSEVersion = SSE2; avxEnabled = false; } + static void SetSSE4Disabled() { maxEnabledSSEVersion = SSSE3; avxEnabled = false; } + static void SetAVXDisabled() { avxEnabled = false; } }; class AssemblerX86Shared : public AssemblerShared { protected: struct RelativePatch { int32_t offset; void *target; @@ -206,16 +217,22 @@ class AssemblerX86Shared : public Assemb protected: X86Assembler masm; typedef X86Assembler::JmpSrc JmpSrc; typedef X86Assembler::JmpDst JmpDst; public: + AssemblerX86Shared() + { + if (!HasAVX()) + masm.disableVEX(); + } + enum Condition { Equal = X86Assembler::ConditionE, NotEqual = X86Assembler::ConditionNE, Above = X86Assembler::ConditionA, AboveOrEqual = X86Assembler::ConditionAE, Below = X86Assembler::ConditionB, BelowOrEqual = X86Assembler::ConditionBE, GreaterThan = X86Assembler::ConditionG, @@ -953,16 +970,17 @@ class AssemblerX86Shared : public Assemb masm.int3(); } static bool HasSSE2() { return CPUInfo::IsSSE2Present(); } static bool HasSSE3() { return CPUInfo::IsSSE3Present(); } static bool HasSSE41() { return CPUInfo::IsSSE41Present(); } static bool SupportsFloatingPoint() { return CPUInfo::IsSSE2Present(); } static bool SupportsSimd() { return CPUInfo::IsSSE2Present(); } + static bool HasAVX() { return CPUInfo::IsAVXPresent(); } // The below cmpl methods switch the lhs and rhs when it invokes the // macroassembler to conform with intel standard. When calling this // function put the left operand on the left as you would expect. void cmpl(Register lhs, Register rhs) { masm.cmpl_rr(rhs.code(), lhs.code()); } void cmpl(Register lhs, const Operand &rhs) { @@ -1670,46 +1688,46 @@ class AssemblerX86Shared : public Assemb break; case Operand::MEM_ADDRESS32: masm.pcmpgtd_mr(src.address(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void cmpps(uint8_t order, const Operand &src, FloatRegister dest) { + void vcmpps(uint8_t order, const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.cmpps_rr(order, src.fpu(), dest.code()); + masm.vcmpps_rr(order, src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.cmpps_mr(order, src.disp(), src.base(), dest.code()); + masm.vcmpps_mr(order, src1.disp(), src1.base(), src0.code(), dest.code()); break; case Operand::MEM_ADDRESS32: - masm.cmpps_mr(order, src.address(), dest.code()); + masm.vcmpps_mr(order, src1.address(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void cmpeqps(const Operand &src, FloatRegister dest) { - cmpps(X86Assembler::ConditionCmp_EQ, src, dest); + void vcmpeqps(const Operand &src1, FloatRegister src0, FloatRegister dest) { + vcmpps(X86Assembler::ConditionCmp_EQ, src1, src0, dest); } - void cmpltps(const Operand &src, FloatRegister dest) { - cmpps(X86Assembler::ConditionCmp_LT, src, dest); + void vcmpltps(const Operand &src1, FloatRegister src0, FloatRegister dest) { + vcmpps(X86Assembler::ConditionCmp_LT, src1, src0, dest); } - void cmpleps(const Operand &src, FloatRegister dest) { - cmpps(X86Assembler::ConditionCmp_LE, src, dest); + void vcmpleps(const Operand &src1, FloatRegister src0, FloatRegister dest) { + vcmpps(X86Assembler::ConditionCmp_LE, src1, src0, dest); } - void cmpunordps(const Operand &src, FloatRegister dest) { - cmpps(X86Assembler::ConditionCmp_UNORD, src, dest); + void vcmpunordps(const Operand &src1, FloatRegister src0, FloatRegister dest) { + vcmpps(X86Assembler::ConditionCmp_UNORD, src1, src0, dest); } - void cmpneqps(const Operand &src, FloatRegister dest) { - cmpps(X86Assembler::ConditionCmp_NEQ, src, dest); + void vcmpneqps(const Operand &src1, FloatRegister src0, FloatRegister dest) { + vcmpps(X86Assembler::ConditionCmp_NEQ, src1, src0, dest); } void rcpps(const Operand &src, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); switch (src.kind()) { case Operand::FPREG: masm.rcpps_rr(src.fpu(), dest.code()); break; case Operand::MEM_REG_DISP: @@ -1789,107 +1807,107 @@ class AssemblerX86Shared : public Assemb break; case Operand::MEM_ADDRESS32: masm.psubd_mr(src.address(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void addps(const Operand &src, FloatRegister dest) { + void vaddps(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.addps_rr(src.fpu(), dest.code()); + masm.vaddps_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.addps_mr(src.disp(), src.base(), dest.code()); + masm.vaddps_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; case Operand::MEM_ADDRESS32: - masm.addps_mr(src.address(), dest.code()); + masm.vaddps_mr(src1.address(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void subps(const Operand &src, FloatRegister dest) { + void vsubps(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.subps_rr(src.fpu(), dest.code()); + masm.vsubps_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.subps_mr(src.disp(), src.base(), dest.code()); + masm.vsubps_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; case Operand::MEM_ADDRESS32: - masm.subps_mr(src.address(), dest.code()); + masm.vsubps_mr(src1.address(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void mulps(const Operand &src, FloatRegister dest) { + void vmulps(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.mulps_rr(src.fpu(), dest.code()); + masm.vmulps_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.mulps_mr(src.disp(), src.base(), dest.code()); + masm.vmulps_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; case Operand::MEM_ADDRESS32: - masm.mulps_mr(src.address(), dest.code()); + masm.vmulps_mr(src1.address(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void divps(const Operand &src, FloatRegister dest) { + void vdivps(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.divps_rr(src.fpu(), dest.code()); + masm.vdivps_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.divps_mr(src.disp(), src.base(), dest.code()); + masm.vdivps_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; case Operand::MEM_ADDRESS32: - masm.divps_mr(src.address(), dest.code()); + masm.vdivps_mr(src1.address(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void maxps(const Operand &src, FloatRegister dest) { + void vmaxps(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.maxps_rr(src.fpu(), dest.code()); + masm.vmaxps_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.maxps_mr(src.disp(), src.base(), dest.code()); + masm.vmaxps_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; case Operand::MEM_ADDRESS32: - masm.maxps_mr(src.address(), dest.code()); + masm.vmaxps_mr(src1.address(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void minps(const Operand &src, FloatRegister dest) { + void vminps(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.minps_rr(src.fpu(), dest.code()); + masm.vminps_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.minps_mr(src.disp(), src.base(), dest.code()); + masm.vminps_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; case Operand::MEM_ADDRESS32: - masm.minps_mr(src.address(), dest.code()); + masm.vminps_mr(src1.address(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } void andps(const Operand &src, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); switch (src.kind()) { @@ -1994,153 +2012,153 @@ class AssemblerX86Shared : public Assemb break; case Operand::MEM_ADDRESS32: masm.shufps_imr(mask, src.address(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void addsd(FloatRegister src, FloatRegister dest) { + void vaddsd(FloatRegister src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - masm.addsd_rr(src.code(), dest.code()); + masm.vaddsd_rr(src1.code(), src0.code(), dest.code()); } - void addss(FloatRegister src, FloatRegister dest) { + void vaddss(FloatRegister src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - masm.addss_rr(src.code(), dest.code()); + masm.vaddss_rr(src1.code(), src0.code(), dest.code()); } - void addsd(const Operand &src, FloatRegister dest) { + void vaddsd(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.addsd_rr(src.fpu(), dest.code()); + masm.vaddsd_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.addsd_mr(src.disp(), src.base(), dest.code()); + masm.vaddsd_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; case Operand::MEM_ADDRESS32: - masm.addsd_mr(src.address(), dest.code()); + masm.vaddsd_mr(src1.address(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void addss(const Operand &src, FloatRegister dest) { + void vaddss(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.addss_rr(src.fpu(), dest.code()); + masm.vaddss_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.addss_mr(src.disp(), src.base(), dest.code()); + masm.vaddss_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; case Operand::MEM_ADDRESS32: - masm.addss_mr(src.address(), dest.code()); + masm.vaddss_mr(src1.address(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void subsd(FloatRegister src, FloatRegister dest) { + void vsubsd(FloatRegister src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - masm.subsd_rr(src.code(), dest.code()); + masm.vsubsd_rr(src1.code(), src0.code(), dest.code()); } - void subss(FloatRegister src, FloatRegister dest) { + void vsubss(FloatRegister src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - masm.subss_rr(src.code(), dest.code()); + masm.vsubss_rr(src1.code(), src0.code(), dest.code()); } - void subsd(const Operand &src, FloatRegister dest) { + void vsubsd(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.subsd_rr(src.fpu(), dest.code()); + masm.vsubsd_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.subsd_mr(src.disp(), src.base(), dest.code()); + masm.vsubsd_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void subss(const Operand &src, FloatRegister dest) { + void vsubss(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.subss_rr(src.fpu(), dest.code()); + masm.vsubss_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.subss_mr(src.disp(), src.base(), dest.code()); + masm.vsubss_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void mulsd(FloatRegister src, FloatRegister dest) { + void vmulsd(FloatRegister src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - masm.mulsd_rr(src.code(), dest.code()); + masm.vmulsd_rr(src1.code(), src0.code(), dest.code()); } - void mulsd(const Operand &src, FloatRegister dest) { + void vmulsd(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.mulsd_rr(src.fpu(), dest.code()); + masm.vmulsd_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.mulsd_mr(src.disp(), src.base(), dest.code()); + masm.vmulsd_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void mulss(const Operand &src, FloatRegister dest) { + void vmulss(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.mulss_rr(src.fpu(), dest.code()); + masm.vmulss_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.mulss_mr(src.disp(), src.base(), dest.code()); + masm.vmulss_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void mulss(FloatRegister src, FloatRegister dest) { + void vmulss(FloatRegister src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - masm.mulss_rr(src.code(), dest.code()); + masm.vmulss_rr(src1.code(), src0.code(), dest.code()); } - void divsd(FloatRegister src, FloatRegister dest) { + void vdivsd(FloatRegister src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - masm.divsd_rr(src.code(), dest.code()); + masm.vdivsd_rr(src1.code(), src0.code(), dest.code()); } - void divss(FloatRegister src, FloatRegister dest) { + void vdivss(FloatRegister src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - masm.divss_rr(src.code(), dest.code()); + masm.vdivss_rr(src1.code(), src0.code(), dest.code()); } - void divsd(const Operand &src, FloatRegister dest) { + void vdivsd(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.divsd_rr(src.fpu(), dest.code()); + masm.vdivsd_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.divsd_mr(src.disp(), src.base(), dest.code()); + masm.vdivsd_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } - void divss(const Operand &src, FloatRegister dest) { + void vdivss(const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.divss_rr(src.fpu(), dest.code()); + masm.vdivss_rr(src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.divss_mr(src.disp(), src.base(), dest.code()); + masm.vdivss_mr(src1.disp(), src1.base(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } void xorpd(FloatRegister src, FloatRegister dest) { MOZ_ASSERT(HasSSE2()); masm.xorpd_rr(src.code(), dest.code()); @@ -2194,28 +2212,45 @@ class AssemblerX86Shared : public Assemb } void insertps(FloatRegister src, FloatRegister dest, unsigned mask) { MOZ_ASSERT(HasSSE41()); masm.insertps_irr(mask, src.code(), dest.code()); } unsigned blendpsMask(bool x, bool y, bool z, bool w) { return x | (y << 1) | (z << 2) | (w << 3); } - void blendps(FloatRegister src, FloatRegister dest, unsigned mask) { + void vblendps(unsigned mask, FloatRegister src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE41()); - masm.blendps_irr(mask, src.code(), dest.code()); + masm.vblendps_irr(mask, src1.code(), src0.code(), dest.code()); } - void blendps(const Operand &src, FloatRegister dest, unsigned mask) { + void vblendps(unsigned mask, const Operand &src1, FloatRegister src0, FloatRegister dest) { MOZ_ASSERT(HasSSE41()); - switch (src.kind()) { + switch (src1.kind()) { case Operand::FPREG: - masm.blendps_irr(mask, src.fpu(), dest.code()); + masm.vblendps_irr(mask, src1.fpu(), src0.code(), dest.code()); break; case Operand::MEM_REG_DISP: - masm.blendps_imr(mask, src.disp(), src.base(), dest.code()); + masm.vblendps_imr(mask, src1.disp(), src1.base(), src0.code(), dest.code()); + break; + default: + MOZ_CRASH("unexpected operand kind"); + } + } + void vblendvps(FloatRegister mask, FloatRegister src1, FloatRegister src0, FloatRegister dest) { + MOZ_ASSERT(HasSSE41()); + masm.vblendvps_rr(mask.code(), src1.code(), src0.code(), dest.code()); + } + void vblendvps(FloatRegister mask, const Operand &src1, FloatRegister src0, FloatRegister dest) { + MOZ_ASSERT(HasSSE41()); + switch (src1.kind()) { + case Operand::FPREG: + masm.vblendvps_rr(mask.code(), src1.fpu(), src0.code(), dest.code()); + break; + case Operand::MEM_REG_DISP: + masm.vblendvps_mr(mask.code(), src1.disp(), src1.base(), src0.code(), dest.code()); break; default: MOZ_CRASH("unexpected operand kind"); } } void movsldup(FloatRegister src, FloatRegister dest) { MOZ_ASSERT(HasSSE3()); masm.movsldup_rr(src.code(), dest.code());
--- a/js/src/jit/shared/BaseAssembler-x86-shared.h +++ b/js/src/jit/shared/BaseAssembler-x86-shared.h @@ -389,32 +389,43 @@ private: OP2_PSLLD_VdqWdq = 0xF2, OP2_PSUBD_VdqWdq = 0xFA, OP2_PADDD_VdqWdq = 0xFE } TwoByteOpcodeID; typedef enum { OP3_ROUNDSS_VsdWsd = 0x0A, OP3_ROUNDSD_VsdWsd = 0x0B, + OP3_BLENDVPS_VdqWdq = 0x14, OP3_PEXTRD_EdVdqIb = 0x16, OP3_BLENDPS_VpsWpsIb = 0x0C, OP3_PTEST_VdVd = 0x17, OP3_INSERTPS_VpsUps = 0x21, - OP3_PINSRD_VdqEdIb = 0x22 + OP3_PINSRD_VdqEdIb = 0x22, + OP3_VBLENDVPS_VdqWdq = 0x4A } ThreeByteOpcodeID; typedef enum { + ESCAPE_BLENDVPS = 0x38, ESCAPE_PTEST = 0x38, ESCAPE_PINSRD = 0x3A, ESCAPE_PEXTRD = 0x3A, ESCAPE_ROUNDSD = 0x3A, ESCAPE_INSERTPS = 0x3A, - ESCAPE_BLENDPS = 0x3A + ESCAPE_BLENDPS = 0x3A, + ESCAPE_VBLENDVPS = 0x3A } ThreeByteEscape; + typedef enum { + VEX_PS = 0, + VEX_PD = 1, + VEX_SS = 2, + VEX_SD = 3 + } VexOperandType; + TwoByteOpcodeID jccRel32(Condition cond) { return (TwoByteOpcodeID)(OP2_JCC_rel32 + cond); } TwoByteOpcodeID setccOpcode(Condition cond) { return (TwoByteOpcodeID)(OP_SETCC + cond); @@ -452,16 +463,21 @@ private: FPU6_OP_FISTTP = 1, FPU6_OP_FSTP = 3, GROUP11_MOV = 0 } GroupOpcodeID; class X86InstructionFormatter; public: + X86Assembler() + : useVEX_(true) + { } + + void disableVEX() { useVEX_ = false; } class JmpSrc { friend class X86Assembler; friend class X86InstructionFormatter; public: JmpSrc() : m_offset(-1) { @@ -781,116 +797,92 @@ public: } void psubd_mr(const void* address, XMMRegisterID dst) { spew("psubd %p, %s", address, nameFPReg(dst)); m_formatter.prefix(PRE_SSE_66); m_formatter.twoByteOp(OP2_PSUBD_VdqWdq, address, (RegisterID)dst); } - void addps_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("addps %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_ADDPS_VpsWps, (RegisterID)src, (RegisterID)dst); - } - void addps_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("addps %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_ADDPS_VpsWps, offset, base, (RegisterID)dst); - } - void addps_mr(const void* address, XMMRegisterID dst) - { - spew("addps %p, %s", address, nameFPReg(dst)); - m_formatter.twoByteOp(OP2_ADDPS_VpsWps, address, (RegisterID)dst); - } - - void subps_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("subps %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_SUBPS_VpsWps, (RegisterID)src, (RegisterID)dst); - } - void subps_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("subps %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_SUBPS_VpsWps, offset, base, (RegisterID)dst); - } - void subps_mr(const void* address, XMMRegisterID dst) - { - spew("subps %p, %s", address, nameFPReg(dst)); - m_formatter.twoByteOp(OP2_SUBPS_VpsWps, address, (RegisterID)dst); - } - - void mulps_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("mulps %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_MULPS_VpsWps, (RegisterID)src, (RegisterID)dst); - } - void mulps_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("mulps %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_MULPS_VpsWps, offset, base, (RegisterID)dst); - } - void mulps_mr(const void* address, XMMRegisterID dst) - { - spew("mulps %p, %s", address, nameFPReg(dst)); - m_formatter.twoByteOp(OP2_MULPS_VpsWps, address, (RegisterID)dst); - } - - void divps_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("divps %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_DIVPS_VpsWps, (RegisterID)src, (RegisterID)dst); - } - void divps_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("divps %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_DIVPS_VpsWps, offset, base, (RegisterID)dst); - } - void divps_mr(const void* address, XMMRegisterID dst) - { - spew("divps %p, %s", address, nameFPReg(dst)); - m_formatter.twoByteOp(OP2_DIVPS_VpsWps, address, (RegisterID)dst); - } - - void maxps_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("maxps %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_MAXPS_VpsWps, (RegisterID)src, (RegisterID)dst); - } - void maxps_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("maxps %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_MAXPS_VpsWps, offset, base, (RegisterID)dst); - } - void maxps_mr(const void* address, XMMRegisterID dst) - { - spew("maxps %p, %s", address, nameFPReg(dst)); - m_formatter.twoByteOp(OP2_MAXPS_VpsWps, address, (RegisterID)dst); - } - - void minps_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("minps %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_MINPS_VpsWps, (RegisterID)src, (RegisterID)dst); - } - void minps_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("minps %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_MINPS_VpsWps, offset, base, (RegisterID)dst); - } - void minps_mr(const void* address, XMMRegisterID dst) - { - spew("minps %p, %s", address, nameFPReg(dst)); - m_formatter.twoByteOp(OP2_MINPS_VpsWps, address, (RegisterID)dst); + void vaddps_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vaddps", VEX_PS, OP2_ADDPS_VpsWps, src1, src0, dst); + } + void vaddps_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vaddps", VEX_PS, OP2_ADDPS_VpsWps, offset, base, src0, dst); + } + void vaddps_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vaddps", VEX_PS, OP2_ADDPS_VpsWps, address, src0, dst); + } + + void vsubps_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vsubps", VEX_PS, OP2_SUBPS_VpsWps, src1, src0, dst); + } + void vsubps_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vsubps", VEX_PS, OP2_SUBPS_VpsWps, offset, base, src0, dst); + } + void vsubps_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vsubps", VEX_PS, OP2_SUBPS_VpsWps, address, src0, dst); + } + + void vmulps_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vmulps", VEX_PS, OP2_MULPS_VpsWps, src1, src0, dst); + } + void vmulps_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vmulps", VEX_PS, OP2_MULPS_VpsWps, offset, base, src0, dst); + } + void vmulps_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vmulps", VEX_PS, OP2_MULPS_VpsWps, address, src0, dst); + } + + void vdivps_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vdivps", VEX_PS, OP2_DIVPS_VpsWps, src1, src0, dst); + } + void vdivps_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vdivps", VEX_PS, OP2_DIVPS_VpsWps, offset, base, src0, dst); + } + void vdivps_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vdivps", VEX_PS, OP2_DIVPS_VpsWps, address, src0, dst); + } + + void vmaxps_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vmaxps", VEX_PS, OP2_MAXPS_VpsWps, src1, src0, dst); + } + void vmaxps_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vmaxps", VEX_PS, OP2_MAXPS_VpsWps, offset, base, src0, dst); + } + void vmaxps_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vmaxps", VEX_PS, OP2_MAXPS_VpsWps, address, src0, dst); + } + + void vminps_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vminps", VEX_PS, OP2_MINPS_VpsWps, src1, src0, dst); + } + void vminps_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vminps", VEX_PS, OP2_MINPS_VpsWps, offset, base, src0, dst); + } + void vminps_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vminps", VEX_PS, OP2_MINPS_VpsWps, address, src0, dst); } void andl_rr(RegisterID src, RegisterID dst) { spew("andl %s, %s", nameIReg(4,src), nameIReg(4,dst)); m_formatter.oneByteOp(OP_AND_GvEv, src, dst); } @@ -2686,35 +2678,29 @@ public: void pcmpgtd_mr(const void* address, XMMRegisterID dst) { spew("pcmpgtd %p, %s", address, nameFPReg(dst)); m_formatter.prefix(PRE_SSE_66); m_formatter.twoByteOp(OP2_PCMPGTD_VdqWdq, address, (RegisterID)dst); } - void cmpps_rr(uint8_t order, XMMRegisterID src, XMMRegisterID dst) - { - spew("cmpps $%u, %s, %s", order, nameFPReg(src), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_CMPPS_VpsWps, (RegisterID)src, (RegisterID)dst); + void vcmpps_rr(uint8_t order, XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vcmpps", VEX_PS, OP2_CMPPS_VpsWps, src1, src0, dst); m_formatter.immediate8(order); } - - void cmpps_mr(uint8_t order, int offset, RegisterID base, XMMRegisterID dst) - { - spew("cmpps $%u, %s0x%x(%s), %s", - order, PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.twoByteOp(OP2_CMPPS_VpsWps, offset, base, (RegisterID)dst); + void vcmpps_mr(uint8_t order, int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vcmpps", VEX_PS, OP2_CMPPS_VpsWps, offset, base, src0, dst); m_formatter.immediate8(order); } - - void cmpps_mr(uint8_t order, const void* address, XMMRegisterID dst) - { - spew("cmpps $%u, %p, %s", order, address, nameFPReg(dst)); - m_formatter.twoByteOp(OP2_CMPPS_VpsWps, address, (RegisterID)dst); + void vcmpps_mr(uint8_t order, const void* address, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vcmpps", VEX_PS, OP2_CMPPS_VpsWps, address, src0, dst); m_formatter.immediate8(order); } void rcpps_rr(XMMRegisterID src, XMMRegisterID dst){ spew("rcpps %s, %s", nameFPReg(src), nameFPReg(dst)); m_formatter.twoByteOp(OP2_RCPPS_VpsWps, (RegisterID)src, (RegisterID)dst); } void rcpps_mr(int offset, RegisterID base, XMMRegisterID dst){ @@ -2759,50 +2745,43 @@ public: void addsd_rr(XMMRegisterID src, XMMRegisterID dst) { spew("addsd %s, %s", nameFPReg(src), nameFPReg(dst)); m_formatter.prefix(PRE_SSE_F2); m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, (RegisterID)src, (RegisterID)dst); } - void addss_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("addss %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F3); - m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, (RegisterID)src, (RegisterID)dst); - } - - void addsd_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("addsd %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, offset, base, (RegisterID)dst); - } - - void addss_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("addss %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F3); - m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, offset, base, (RegisterID)dst); - } - - void addsd_mr(const void* address, XMMRegisterID dst) - { - spew("addsd %p, %s", address, nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, address, (RegisterID)dst); - } - void addss_mr(const void* address, XMMRegisterID dst) - { - spew("addss %p, %s", address, nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F3); - m_formatter.twoByteOp(OP2_ADDSD_VsdWsd, address, (RegisterID)dst); + void vaddsd_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vaddsd", VEX_SD, OP2_ADDSD_VsdWsd, src1, src0, dst); + } + + void vaddss_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vaddss", VEX_SS, OP2_ADDSD_VsdWsd, src1, src0, dst); + } + + void vaddsd_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vaddsd", VEX_SD, OP2_ADDSD_VsdWsd, offset, base, src0, dst); + } + + void vaddss_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vaddss", VEX_SS, OP2_ADDSD_VsdWsd, offset, base, src0, dst); + } + + void vaddsd_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vaddsd", VEX_SD, OP2_ADDSD_VsdWsd, address, src0, dst); + } + void vaddss_mr(const void* address, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vaddss", VEX_SS, OP2_ADDSD_VsdWsd, address, src0, dst); } void cvtss2sd_rr(XMMRegisterID src, XMMRegisterID dst) { spew("cvtss2sd %s, %s", nameFPReg(src), nameFPReg(dst)); m_formatter.prefix(PRE_SSE_F3); m_formatter.twoByteOp(OP2_CVTSS2SD_VsdEd, (RegisterID)src, (RegisterID)dst); } @@ -3522,82 +3501,62 @@ public: void movdqa_mr(int offset, RegisterID base, RegisterID index, int scale, XMMRegisterID dst) { spew("movdqa %d(%s,%s,%d), %s", offset, nameIReg(base), nameIReg(index), 1<<scale, nameFPReg(dst)); m_formatter.prefix(PRE_SSE_66); m_formatter.twoByteOp(OP2_MOVDQ_VdqWdq, offset, base, index, scale, (RegisterID)dst); } - void mulsd_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("mulsd %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_MULSD_VsdWsd, (RegisterID)src, (RegisterID)dst); - } - - void mulss_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("mulss %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F3); - m_formatter.twoByteOp(OP2_MULSD_VsdWsd, (RegisterID)src, (RegisterID)dst); - } - - void mulsd_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("mulsd %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_MULSD_VsdWsd, offset, base, (RegisterID)dst); - } - - void mulss_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("mulss %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F3); - m_formatter.twoByteOp(OP2_MULSD_VsdWsd, offset, base, (RegisterID)dst); + void vmulsd_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vmulsd", VEX_SD, OP2_MULSD_VsdWsd, src1, src0, dst); + } + + void vmulss_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vmulss", VEX_SS, OP2_MULSD_VsdWsd, src1, src0, dst); + } + + void vmulsd_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vmulsd", VEX_SD, OP2_MULSD_VsdWsd, offset, base, src0, dst); + } + + void vmulss_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vmulss", VEX_SS, OP2_MULSD_VsdWsd, offset, base, src0, dst); } void pextrw_irr(int whichWord, XMMRegisterID src, RegisterID dst) { FIXME_INSN_PRINTING; m_formatter.prefix(PRE_SSE_66); m_formatter.twoByteOp(OP2_PEXTRW_GdUdIb, (RegisterID)src, (RegisterID)dst); m_formatter.immediate8(whichWord); } - void subsd_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("subsd %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_SUBSD_VsdWsd, (RegisterID)src, (RegisterID)dst); - } - - void subss_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("subss %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F3); - m_formatter.twoByteOp(OP2_SUBSD_VsdWsd, (RegisterID)src, (RegisterID)dst); - } - - void subsd_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("subsd %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_SUBSD_VsdWsd, offset, base, (RegisterID)dst); - } - - void subss_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("subss %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F3); - m_formatter.twoByteOp(OP2_SUBSD_VsdWsd, offset, base, (RegisterID)dst); + void vsubsd_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vsubsd", VEX_SD, OP2_SUBSD_VsdWsd, src1, src0, dst); + } + + void vsubss_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vsubss", VEX_SS, OP2_SUBSD_VsdWsd, src1, src0, dst); + } + + void vsubsd_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vsubsd", VEX_SD, OP2_SUBSD_VsdWsd, offset, base, src0, dst); + } + + void vsubss_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vsubss", VEX_SS, OP2_SUBSD_VsdWsd, offset, base, src0, dst); } void ucomiss_rr(XMMRegisterID src, XMMRegisterID dst) { spew("ucomiss %s, %s", nameFPReg(src), nameFPReg(dst)); m_formatter.twoByteOp(OP2_UCOMISD_VsdWsd, (RegisterID)src, (RegisterID)dst); } @@ -3611,44 +3570,34 @@ public: void ucomisd_mr(int offset, RegisterID base, XMMRegisterID dst) { spew("ucomisd %s0x%x(%s), %s", PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); m_formatter.prefix(PRE_SSE_66); m_formatter.twoByteOp(OP2_UCOMISD_VsdWsd, offset, base, (RegisterID)dst); } - void divsd_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("divsd %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_DIVSD_VsdWsd, (RegisterID)src, (RegisterID)dst); - } - - void divss_rr(XMMRegisterID src, XMMRegisterID dst) - { - spew("divss %s, %s", nameFPReg(src), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F3); - m_formatter.twoByteOp(OP2_DIVSD_VsdWsd, (RegisterID)src, (RegisterID)dst); - } - - void divsd_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("divsd %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F2); - m_formatter.twoByteOp(OP2_DIVSD_VsdWsd, offset, base, (RegisterID)dst); - } - - void divss_mr(int offset, RegisterID base, XMMRegisterID dst) - { - spew("divss %s0x%x(%s), %s", - PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_F3); - m_formatter.twoByteOp(OP2_DIVSD_VsdWsd, offset, base, (RegisterID)dst); + void vdivsd_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vdivsd", VEX_SD, OP2_DIVSD_VsdWsd, src1, src0, dst); + } + + void vdivss_rr(XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vdivss", VEX_SS, OP2_DIVSD_VsdWsd, src1, src0, dst); + } + + void vdivsd_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vdivsd", VEX_SD, OP2_DIVSD_VsdWsd, offset, base, src0, dst); + } + + void vdivss_mr(int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + twoByteOpSimd("vdivss", VEX_SS, OP2_DIVSD_VsdWsd, offset, base, src0, dst); } void xorpd_rr(XMMRegisterID src, XMMRegisterID dst) { spew("xorpd %s, %s", nameFPReg(src), nameFPReg(dst)); m_formatter.prefix(PRE_SSE_66); m_formatter.twoByteOp(OP2_XORPD_VpdWpd, (RegisterID)src, (RegisterID)dst); } @@ -3815,33 +3764,37 @@ public: MOZ_ASSERT(lane < 4); spew("pextrd $%x, %s, %s0x%x(%s)", lane, nameFPReg(src), PRETTY_PRINT_OFFSET(offset), nameIReg(base)); m_formatter.prefix(PRE_SSE_66); m_formatter.threeByteOp(OP3_PEXTRD_EdVdqIb, ESCAPE_PEXTRD, offset, base, (RegisterID)src); m_formatter.immediate8(uint8_t(lane)); } - void blendps_irr(unsigned imm, XMMRegisterID src, XMMRegisterID dst) + void vblendps_irr(unsigned imm, XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) + { + MOZ_ASSERT(imm < 16); + // Despite being a "ps" instruction, vblendps is encoded with the "pd" prefix. + threeByteOpSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_BLENDPS, src1, src0, dst); + m_formatter.immediate8(uint8_t(imm)); + } + + void vblendps_imr(unsigned imm, int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) { MOZ_ASSERT(imm < 16); - spew("blendps $%x, %s, %s", imm, nameFPReg(src), nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_66); - m_formatter.threeByteOp(OP3_BLENDPS_VpsWpsIb, ESCAPE_BLENDPS, (RegisterID)src, (RegisterID)dst); + // Despite being a "ps" instruction, vblendps is encoded with the "pd" prefix. + threeByteOpSimd("vblendps", VEX_PD, OP3_BLENDPS_VpsWpsIb, ESCAPE_BLENDPS, offset, base, src0, dst); m_formatter.immediate8(uint8_t(imm)); } - void blendps_imr(unsigned imm, int offset, RegisterID base, XMMRegisterID dst) - { - MOZ_ASSERT(imm < 16); - spew("blendps $%x, %s0x%x(%s), %s", imm, PRETTY_PRINT_OFFSET(offset), nameIReg(base), - nameFPReg(dst)); - m_formatter.prefix(PRE_SSE_66); - m_formatter.threeByteOp(OP3_BLENDPS_VpsWpsIb, ESCAPE_BLENDPS, offset, base, (RegisterID)dst); - m_formatter.immediate8(uint8_t(imm)); + void vblendvps_rr(XMMRegisterID mask, XMMRegisterID src1, XMMRegisterID src0, XMMRegisterID dst) { + vblendvOpSimd(mask, src1, src0, dst); + } + void vblendvps_mr(XMMRegisterID mask, int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) { + vblendvOpSimd(mask, offset, base, src0, dst); } void movsldup_rr(XMMRegisterID src, XMMRegisterID dst) { spew("movsldup %s, %s", nameFPReg(src), nameFPReg(dst)); m_formatter.prefix(PRE_SSE_F3); m_formatter.twoByteOp(OP2_MOVSLDUP_VpsWps, (RegisterID)src, (RegisterID)dst); } @@ -4260,37 +4213,262 @@ public: } static void setInt32(void* where, int32_t value) { reinterpret_cast<int32_t*>(where)[-1] = value; } private: + // Methods for encoding SIMD instructions via either legacy SSE encoding or + // VEX encoding. + + bool useLegacySSEEncoding(XMMRegisterID src0, XMMRegisterID dst) + { + // If we don't have AVX or it's disabled, use the legacy SSE encoding. + if (!useVEX_) { + MOZ_ASSERT(src0 == dst); + return true; + } + + // If src0 is the same as the output register, we might as well use + // the legacy SSE encoding, since it is smaller. However, this is only + // beneficial as long as we're not using ymm registers anywhere. + return src0 == dst; + } + + bool useLegacySSEEncodingForVblendv(XMMRegisterID mask, XMMRegisterID src0, XMMRegisterID dst) + { + // Similar to useLegacySSEEncoding, but for vblendv the Legacy SSE + // encoding also requires the mask to be in xmm0. + + if (!useVEX_) { + MOZ_ASSERT(src0 == dst); + MOZ_ASSERT(mask == X86Registers::xmm0); + return true; + } + + return src0 == dst && mask == X86Registers::xmm0; + } + + const char *legacySSEOpName(const char *name) + { + MOZ_ASSERT(name[0] == 'v'); + return name + 1; + } + +#ifdef JS_CODEGEN_X64 + void twoByteRipOpSimd(const char *name, VexOperandType ty, TwoByteOpcodeID opcode, + int ripOffset, XMMRegisterID src0, XMMRegisterID dst) + { + if (useLegacySSEEncoding(src0, dst)) { + spew("%-11s?%+d(%%rip), %s", legacySSEOpName(name), ripOffset, nameFPReg(src0)); + m_formatter.legacySSEPrefix(ty); + m_formatter.twoByteRipOp(opcode, ripOffset, src0); + return; + } + + spew("%-11s?%+d(%%rip), %s, %s", name, ripOffset, nameFPReg(src0), nameFPReg(dst)); + m_formatter.twoByteRipOpVex(ty, opcode, ripOffset, src0, dst); + } +#endif + + void twoByteOpSimd(const char *name, VexOperandType ty, TwoByteOpcodeID opcode, + XMMRegisterID rm, XMMRegisterID src0, XMMRegisterID dst) + { + if (useLegacySSEEncoding(src0, dst)) { + spew("%-11s%s, %s", legacySSEOpName(name), nameFPReg(rm), nameFPReg(src0)); + m_formatter.legacySSEPrefix(ty); + m_formatter.twoByteOp(opcode, (RegisterID)rm, src0); + return; + } + + spew("%-11s%s, %s, %s", name, nameFPReg(rm), nameFPReg(src0), nameFPReg(dst)); + m_formatter.twoByteOpVex(ty, opcode, (RegisterID)rm, src0, dst); + } + + void twoByteOpSimd(const char *name, VexOperandType ty, TwoByteOpcodeID opcode, + int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + if (useLegacySSEEncoding(src0, dst)) { + spew("%-11s%s0x%x(%s), %s", legacySSEOpName(name), + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(src0)); + m_formatter.legacySSEPrefix(ty); + m_formatter.twoByteOp(opcode, offset, base, src0); + return; + } + + spew("%-11s%s0x%x(%s), %s, %s", name, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(src0), nameFPReg(dst)); + m_formatter.twoByteOpVex(ty, opcode, offset, base, src0, dst); + } + + void twoByteOpSimd_disp32(const char *name, VexOperandType ty, TwoByteOpcodeID opcode, + int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + if (useLegacySSEEncoding(src0, dst)) { + spew("%-11s%s0x%x(%s), %s", legacySSEOpName(name), + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(src0)); + m_formatter.legacySSEPrefix(ty); + m_formatter.twoByteOp_disp32(opcode, offset, base, src0); + return; + } + + spew("%-11s%s0x%x(%s), %s, %s", name, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(src0), nameFPReg(dst)); + m_formatter.twoByteOpVex_disp32(ty, opcode, offset, base, src0, dst); + } + + void twoByteOpSimd(const char *name, VexOperandType ty, TwoByteOpcodeID opcode, + int offset, RegisterID base, RegisterID index, int scale, + XMMRegisterID src0, XMMRegisterID dst) + { + if (useLegacySSEEncoding(src0, dst)) { + spew("%-11s%s0x%x(%s,%s,%d), %s", legacySSEOpName(name), + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameIReg(index), scale, + nameFPReg(src0)); + m_formatter.legacySSEPrefix(ty); + m_formatter.twoByteOp(opcode, offset, base, index, scale, src0); + return; + } + + spew("%-11s%s0x%x(%s,%s,%d), %s, %s", name, PRETTY_PRINT_OFFSET(offset), nameIReg(base), + nameIReg(index), scale, nameFPReg(src0), nameFPReg(dst)); + m_formatter.twoByteOpVex(ty, opcode, offset, base, index, scale, src0, dst); + } + + void twoByteOpSimd(const char *name, VexOperandType ty, TwoByteOpcodeID opcode, + const void* address, XMMRegisterID src0, XMMRegisterID dst) + { + if (useLegacySSEEncoding(src0, dst)) { + spew("%-11s%p, %s", legacySSEOpName(name), address, nameFPReg(src0)); + m_formatter.legacySSEPrefix(ty); + m_formatter.twoByteOp(opcode, address, src0); + return; + } + + spew("%-11s%p, %s, %s", name, address, nameFPReg(src0), nameFPReg(dst)); + m_formatter.twoByteOpVex(ty, opcode, address, src0, dst); + } + + void threeByteOpSimd(const char *name, VexOperandType ty, ThreeByteOpcodeID opcode, + ThreeByteEscape escape, + XMMRegisterID rm, XMMRegisterID src0, XMMRegisterID dst) + { + if (useLegacySSEEncoding(src0, dst)) { + spew("%-11s%s, %s", legacySSEOpName(name), nameFPReg(rm), nameFPReg(src0)); + m_formatter.legacySSEPrefix(ty); + m_formatter.threeByteOp(opcode, escape, (RegisterID)rm, src0); + return; + } + + spew("%-11s%s, %s, %s", name, nameFPReg(rm), nameFPReg(src0), nameFPReg(dst)); + m_formatter.threeByteOpVex(ty, opcode, escape, (RegisterID)rm, src0, dst); + } + + void threeByteOpSimd(const char *name, VexOperandType ty, ThreeByteOpcodeID opcode, + ThreeByteEscape escape, + int offset, RegisterID base, XMMRegisterID src0, XMMRegisterID dst) + { + if (useLegacySSEEncoding(src0, dst)) { + spew("%-11s%s0x%x(%s), %s", legacySSEOpName(name), + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(src0)); + m_formatter.legacySSEPrefix(ty); + m_formatter.threeByteOp(opcode, escape, offset, base, src0); + return; + } + + spew("%-11s%s0x%x(%s), %s, %s", name, + PRETTY_PRINT_OFFSET(offset), nameIReg(base), nameFPReg(src0), nameFPReg(dst)); + m_formatter.threeByteOpVex(ty, opcode, escape, offset, base, src0, dst); + } + + // Blendv is a three-byte op, but the VEX encoding has a different opcode + // than the SSE enc