diff --git a/accessible/public/ia2/Makefile.in b/accessible/public/ia2/Makefile.in index 7454229bcfd7..b6f3d15fa670 100644 --- a/accessible/public/ia2/Makefile.in +++ b/accessible/public/ia2/Makefile.in @@ -20,8 +20,6 @@ GARBAGE += $(MIDL_GENERATED_FILES) FORCE_SHARED_LIB = 1 -SRCS_IN_OBJDIR = 1 - # Please keep this list in sync with the moz.build file until the rest of this # Makefile is ported over. MIDL_INTERFACES = \ diff --git a/accessible/public/msaa/Makefile.in b/accessible/public/msaa/Makefile.in index c03fa5b873cf..9a1d37338bf5 100644 --- a/accessible/public/msaa/Makefile.in +++ b/accessible/public/msaa/Makefile.in @@ -18,8 +18,6 @@ GARBAGE += $(MIDL_GENERATED_FILES) done_gen dlldata.c FORCE_SHARED_LIB = 1 -SRCS_IN_OBJDIR = 1 - CSRCS = \ dlldata.c \ ISimpleDOMNode_p.c \ diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index c01e2cb685ba..e9b7bf2c76ba 100644 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -3612,6 +3612,7 @@ function mimeTypeIsTextBased(aMimeType) aMimeType.endsWith("+xml") || aMimeType == "application/x-javascript" || aMimeType == "application/javascript" || + aMimeType == "application/json" || aMimeType == "application/xml" || aMimeType == "mozilla.application/cached-xul"; } diff --git a/browser/metro/base/content/bindings/autocomplete.xml b/browser/metro/base/content/bindings/autocomplete.xml index e25f8feae126..f9a888b95d13 100644 --- a/browser/metro/base/content/bindings/autocomplete.xml +++ b/browser/metro/base/content/bindings/autocomplete.xml @@ -22,6 +22,7 @@ this.popup._input = this; ]]> + + + + + + + + + + + + diff --git a/browser/metro/base/content/browser-ui.js b/browser/metro/base/content/browser-ui.js index 9c890d452946..1d21706378fe 100644 --- a/browser/metro/base/content/browser-ui.js +++ b/browser/metro/base/content/browser-ui.js @@ -97,7 +97,11 @@ var BrowserUI = { window.addEventListener("MozImprecisePointer", this, true); Services.prefs.addObserver("browser.cache.disk_cache_ssl", this, false); + Services.prefs.addObserver("browser.urlbar.formatting.enabled", this, false); + Services.prefs.addObserver("browser.urlbar.trimURLs", this, false); Services.obs.addObserver(this, "metro_viewstate_changed", false); + + this._edit.inputField.controllers.insertControllerAt(0, this._copyCutURIController); // Init core UI modules ContextUI.init(); @@ -239,11 +243,20 @@ var BrowserUI = { getDisplayURI: function(browser) { let uri = browser.currentURI; + let spec = uri.spec; + try { - uri = gURIFixup.createExposableURI(uri); + spec = gURIFixup.createExposableURI(uri).spec; } catch (ex) {} - return uri.spec; + try { + let charset = browser.characterSet; + let textToSubURI = Cc["@mozilla.org/intl/texttosuburi;1"]. + getService(Ci.nsITextToSubURI); + spec = textToSubURI.unEscapeNonAsciiURI(charset, spec); + } catch (ex) {} + + return spec; }, /** @@ -560,6 +573,12 @@ var BrowserUI = { case "browser.cache.disk_cache_ssl": this._sslDiskCacheEnabled = Services.prefs.getBoolPref(aData); break; + case "browser.urlbar.formatting.enabled": + this._formattingEnabled = Services.prefs.getBookPref(aData); + break; + case "browser.urlbar.trimURLs": + this._mayTrimURLs = Services.prefs.getBoolPref(aData); + break; } break; case "metro_viewstate_changed": @@ -650,11 +669,120 @@ var BrowserUI = { Elements.urlbarState.setAttribute("mode", "view"); }, + _trimURL: function _trimURL(aURL) { + // This function must not modify the given URL such that calling + // nsIURIFixup::createFixupURI with the result will produce a different URI. + return aURL /* remove single trailing slash for http/https/ftp URLs */ + .replace(/^((?:http|https|ftp):\/\/[^/]+)\/$/, "$1") + /* remove http:// unless the host starts with "ftp\d*\." or contains "@" */ + .replace(/^http:\/\/((?!ftp\d*\.)[^\/@]+(?:\/|$))/, "$1"); + }, + + trimURL: function trimURL(aURL) { + return this.mayTrimURLs ? this._trimURL(aURL) : aURL; + }, + _setURI: function _setURI(aURL) { this._edit.value = aURL; this.lastKnownGoodURL = aURL; }, + _getSelectedURIForClipboard: function _getSelectedURIForClipboard() { + // Grab the actual input field's value, not our value, which could include moz-action: + let inputVal = this._edit.inputField.value; + let selectedVal = inputVal.substring(this._edit.selectionStart, this._edit.electionEnd); + + // If the selection doesn't start at the beginning or doesn't span the full domain or + // the URL bar is modified, nothing else to do here. + if (this._edit.selectionStart > 0 || this._edit.valueIsTyped) + return selectedVal; + // The selection doesn't span the full domain if it doesn't contain a slash and is + // followed by some character other than a slash. + if (!selectedVal.contains("/")) { + let remainder = inputVal.replace(selectedVal, ""); + if (remainder != "" && remainder[0] != "/") + return selectedVal; + } + + let uriFixup = Cc["@mozilla.org/docshell/urifixup;1"].getService(Ci.nsIURIFixup); + + let uri; + try { + uri = uriFixup.createFixupURI(inputVal, Ci.nsIURIFixup.FIXUP_FLAG_USE_UTF8); + } catch (e) {} + if (!uri) + return selectedVal; + + // Only copy exposable URIs + try { + uri = uriFixup.createExposableURI(uri); + } catch (ex) {} + + // If the entire URL is selected, just use the actual loaded URI. + if (inputVal == selectedVal) { + // ... but only if isn't a javascript: or data: URI, since those + // are hard to read when encoded + if (!uri.schemeIs("javascript") && !uri.schemeIs("data")) { + // Parentheses are known to confuse third-party applications (bug 458565). + selectedVal = uri.spec.replace(/[()]/g, function (c) escape(c)); + } + + return selectedVal; + } + + // Just the beginning of the URL is selected, check for a trimmed value + let spec = uri.spec; + let trimmedSpec = this.trimURL(spec); + if (spec != trimmedSpec) { + // Prepend the portion that trimURL removed from the beginning. + // This assumes trimURL will only truncate the URL at + // the beginning or end (or both). + let trimmedSegments = spec.split(trimmedSpec); + selectedVal = trimmedSegments[0] + selectedVal; + } + + return selectedVal; + }, + + _copyCutURIController: { + doCommand: function(aCommand) { + let urlbar = BrowserUI._edit; + let val = BrowserUI._getSelectedURIForClipboard(); + if (!val) + return; + + if (aCommand == "cmd_cut" && this.isCommandEnabled(aCommand)) { + let start = urlbar.selectionStart; + let end = urlbar.selectionEnd; + urlbar.inputField.value = urlbar.inputField.value.substring(0, start) + + urlbar.inputField.value.substring(end); + urlbar.selectionStart = urlbar.selectionEnd = start; + } + + Cc["@mozilla.org/widget/clipboardhelper;1"] + .getService(Ci.nsIClipboardHelper) + .copyString(val, document); + }, + + supportsCommand: function(aCommand) { + switch (aCommand) { + case "cmd_copy": + case "cmd_cut": + return true; + } + return false; + }, + + isCommandEnabled: function(aCommand) { + let urlbar = BrowserUI._edit; + return this.supportsCommand(aCommand) && + (aCommand != "cmd_cut" || !urlbar.readOnly) && + urlbar.selectionStart < urlbar.selectionEnd; + }, + + onEvent: function(aEventName) {} + }, + _urlbarClicked: function _urlbarClicked() { // If the urlbar is not already focused, focus it and select the contents. if (Elements.urlbarState.getAttribute("mode") != "edit") @@ -662,6 +790,7 @@ var BrowserUI = { }, _editURI: function _editURI(aShouldDismiss) { + this._clearURIFormatting(); this._edit.focus(); this._edit.select(); @@ -671,11 +800,77 @@ var BrowserUI = { ContextUI.dismissTabs(); }, + formatURI: function formatURI() { + if (!this.formattingEnabled || + Elements.urlbarState.getAttribute("mode") == "edit") + return; + + let controller = this._edit.editor.selectionController; + let selection = controller.getSelection(controller.SELECTION_URLSECONDARY); + selection.removeAllRanges(); + + let textNode = this._edit.editor.rootElement.firstChild; + let value = textNode.textContent; + + let protocol = value.match(/^[a-z\d.+\-]+:(?=[^\d])/); + if (protocol && + ["http:", "https:", "ftp:"].indexOf(protocol[0]) == -1) + return; + let matchedURL = value.match(/^((?:[a-z]+:\/\/)?(?:[^\/]+@)?)(.+?)(?::\d+)?(?:\/|$)/); + if (!matchedURL) + return; + + let [, preDomain, domain] = matchedURL; + let baseDomain = domain; + let subDomain = ""; + // getBaseDomainFromHost doesn't recognize IPv6 literals in brackets as IPs (bug 667159) + if (domain[0] != "[") { + try { + baseDomain = Services.eTLD.getBaseDomainFromHost(domain); + if (!domain.endsWith(baseDomain)) { + // getBaseDomainFromHost converts its resultant to ACE. + let IDNService = Cc["@mozilla.org/network/idn-service;1"] + .getService(Ci.nsIIDNService); + baseDomain = IDNService.convertACEtoUTF8(baseDomain); + } + } catch (e) {} + } + if (baseDomain != domain) { + subDomain = domain.slice(0, -baseDomain.length); + } + + let rangeLength = preDomain.length + subDomain.length; + if (rangeLength) { + let range = document.createRange(); + range.setStart(textNode, 0); + range.setEnd(textNode, rangeLength); + selection.addRange(range); + } + + let startRest = preDomain.length + domain.length; + if (startRest < value.length) { + let range = document.createRange(); + range.setStart(textNode, startRest); + range.setEnd(textNode, value.length); + selection.addRange(range); + } + }, + + _clearURIFormatting: function _clearURIFormatting() { + if (!this.formattingEnabled) + return; + + let controller = this._edit.editor.selectionController; + let selection = controller.getSelection(controller.SELECTION_URLSECONDARY); + selection.removeAllRanges(); + }, + _urlbarBlurred: function _urlbarBlurred() { let state = Elements.urlbarState; if (state.getAttribute("mode") == "edit") state.removeAttribute("mode"); this._updateToolbar(); + this.formatURI(); }, _closeOrQuit: function _closeOrQuit() { @@ -959,6 +1154,24 @@ var BrowserUI = { return this._sslDiskCacheEnabled; }, + _formattingEnabled: null, + + get formattingEnabled() { + if (this._formattingEnabled === null) { + this._formattingEnabled = Services.prefs.getBoolPref("browser.urlbar.formatting.enabled"); + } + return this._formattingEnabled; + }, + + _mayTrimURLs: null, + + get mayTrimURLs() { + if (this._mayTrimURLs === null) { + this._mayTrimURLs = Services.prefs.getBoolPref("browser.urlbar.trimURLs"); + } + return this._mayTrimURLs; + }, + supportsCommand : function(cmd) { var isSupported = false; switch (cmd) { diff --git a/browser/metro/profile/metro.js b/browser/metro/profile/metro.js index b6a523ef8125..821487976a04 100644 --- a/browser/metro/profile/metro.js +++ b/browser/metro/profile/metro.js @@ -261,6 +261,8 @@ pref("places.favicons.optimizeToDimension", 25); // various and sundry awesomebar prefs (should remove/re-evaluate // these once bug 447900 is fixed) +pref("browser.urlbar.trimURLs", true); +pref("browser.urlbar.formatting.enabled", true); pref("browser.urlbar.clickSelectsAll", true); pref("browser.urlbar.doubleClickSelectsAll", true); pref("browser.urlbar.autoFill", false); diff --git a/browser/metro/theme/browser.css b/browser/metro/theme/browser.css index fe61d5cecb62..dea48f0a4763 100644 --- a/browser/metro/theme/browser.css +++ b/browser/metro/theme/browser.css @@ -308,6 +308,12 @@ documenttab[selected] .documenttab-selection { padding: 0 !important; } +#urlbar-edit > hbox > .textbox-input-box > .textbox-input:invalid { + /* Hide error glow around the address bar that shows by default + * when URLs are made invalid by trmming. */ + box-shadow: none !important; +} + /* Combined stop-reload button */ #tool-reload { list-style-image: url("chrome://browser/skin/images/reload.png"); diff --git a/browser/metro/theme/cssthrobber.css b/browser/metro/theme/cssthrobber.css index fb0fd9c63dee..63b699b207aa 100644 --- a/browser/metro/theme/cssthrobber.css +++ b/browser/metro/theme/cssthrobber.css @@ -47,15 +47,15 @@ border-radius: 5px; position: absolute; background: #0095dd; - left:0px; - top:0px; + left: 0; + top: 0; } @keyframes orbit { 0% { opacity: 1; - z-index:99; + z-index: 99; transform: rotate(180deg); animation-timing-function: ease-out; } @@ -64,39 +64,34 @@ opacity: 1; transform: rotate(300deg); animation-timing-function: linear; - origin:0%; } 30% { opacity: 1; - transform:rotate(410deg); + transform: rotate(410deg); animation-timing-function: ease-in-out; - origin:7%; } 39% { opacity: 1; transform: rotate(645deg); animation-timing-function: linear; - origin:30%; } 70% { opacity: 1; transform: rotate(770deg); animation-timing-function: ease-out; - origin:39%; } 75% { opacity: 1; transform: rotate(900deg); animation-timing-function: ease-out; - origin:70%; } 76%, 100% { opacity: 0; - transform:rotate(900deg); + transform: rotate(900deg); } } diff --git a/browser/modules/webrtcUI.jsm b/browser/modules/webrtcUI.jsm index a059dee2b0f9..ad7b01dba469 100644 --- a/browser/modules/webrtcUI.jsm +++ b/browser/modules/webrtcUI.jsm @@ -120,7 +120,7 @@ function prompt(aWindowID, aCallID, aAudioRequested, aVideoRequested, aDevices) } let contentWindow = Services.wm.getOuterWindowWithId(aWindowID); - let host = contentWindow.document.documentURIObject.asciiHost; + let host = contentWindow.document.documentURIObject.host; let browser = getBrowserForWindow(contentWindow); let chromeDoc = browser.ownerDocument; let chromeWin = chromeDoc.defaultView; diff --git a/caps/tests/mochitest/test_app_principal_equality.html b/caps/tests/mochitest/test_app_principal_equality.html index 2dddc55c0999..927bbce62b5d 100644 --- a/caps/tests/mochitest/test_app_principal_equality.html +++ b/caps/tests/mochitest/test_app_principal_equality.html @@ -17,18 +17,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=777467 SpecialPowers.addPermission("browser", true, document); SpecialPowers.addPermission("embed-apps", true, document); - var previousPrefs = { - mozBrowserFramesEnabled: undefined, - oop_by_default: undefined, - }; - try { - previousPrefs.mozBrowserFramesEnabled = SpecialPowers.getBoolPref('dom.mozBrowserFramesEnabled'); - } catch(e) {} - - try { - previousPrefs.oop_by_default = SpecialPowers.getBoolPref('dom.ipc.browser_frames.oop_by_default'); - } catch(e) {} - SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', true); SpecialPowers.setBoolPref("dom.ipc.browser_frames.oop_by_default", false); @@ -66,13 +54,8 @@ addLoadEvent(function() { } // Cleanup. - if (previousPrefs.mozBrowserFramesEnabled !== undefined) { - SpecialPowers.setBoolPref('dom.mozBrowserFramesEnabled', previousPrefs.mozBrowserFramesEnabled); - } - if (previousPrefs.oop_by_default !== undefined) { - SpecialPowers.setBoolPref("dom.ipc.browser_frames.oop_by_default", previousPrefs.oop_by_default); - } - + SpecialPowers.clearUserPref('dom.mozBrowserFramesEnabled'); + SpecialPowers.clearUserPref('dom.ipc.browser_frames.oop_by_default'); SpecialPowers.removePermission("browser", window.document); SpecialPowers.removePermission("embed-apps", window.document); diff --git a/content/base/src/nsFrameMessageManager.cpp b/content/base/src/nsFrameMessageManager.cpp index 2dadfdb345e6..595a58d60477 100644 --- a/content/base/src/nsFrameMessageManager.cpp +++ b/content/base/src/nsFrameMessageManager.cpp @@ -44,19 +44,6 @@ using namespace mozilla; using namespace mozilla::dom; using namespace mozilla::dom::ipc; - -static bool -IsChromeProcess() -{ - nsCOMPtr rt = do_GetService("@mozilla.org/xre/runtime;1"); - if (!rt) - return true; - - uint32_t type; - rt->GetProcessType(&type); - return type == nsIXULRuntime::PROCESS_TYPE_DEFAULT; -} - NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsFrameMessageManager) uint32_t count = tmp->mListeners.Length(); for (uint32_t i = 0; i < count; i++) { @@ -836,7 +823,8 @@ nsFrameMessageManager::Disconnect(bool aRemoveFromParent) nsresult NS_NewGlobalMessageManager(nsIMessageBroadcaster** aResult) { - NS_ENSURE_TRUE(IsChromeProcess(), NS_ERROR_NOT_AVAILABLE); + NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default, + NS_ERROR_NOT_AVAILABLE); nsFrameMessageManager* mm = new nsFrameMessageManager(nullptr, nullptr, nullptr, @@ -1387,7 +1375,8 @@ NS_NewParentProcessMessageManager(nsIMessageBroadcaster** aResult) { NS_ASSERTION(!nsFrameMessageManager::sParentProcessManager, "Re-creating sParentProcessManager"); - NS_ENSURE_TRUE(IsChromeProcess(), NS_ERROR_NOT_AVAILABLE); + NS_ENSURE_TRUE(XRE_GetProcessType() == GeckoProcessType_Default, + NS_ERROR_NOT_AVAILABLE); nsRefPtr mm = new nsFrameMessageManager(nullptr, nullptr, nullptr, @@ -1432,7 +1421,7 @@ NS_NewChildProcessMessageManager(nsISyncMessageSender** aResult) "Re-creating sChildProcessManager"); MessageManagerCallback* cb; - if (IsChromeProcess()) { + if (XRE_GetProcessType() == GeckoProcessType_Default) { cb = new SameChildProcessMessageManagerCallback(); } else { cb = new ChildProcessMessageManagerCallback(); diff --git a/content/base/test/test_bug450160.html b/content/base/test/test_bug450160.html index d5fb7f86929d..dd28623b1ab4 100644 --- a/content/base/test/test_bug450160.html +++ b/content/base/test/test_bug450160.html @@ -32,9 +32,9 @@ function testHTMLDocuments(ids, isXHTML) { is(docType1.ownerDocument, doc1, "docType should have ownerDocument!"); ok(!doc1.documentElement, "Document shouldn't have document element!"); is(doc1.body, null, "Shouldn't have .body!"); - ok(doc1 instanceof SpecialPowers.Ci.nsIDOMHTMLDocument, + ok(doc1 instanceof HTMLDocument, "Document should be an HTML document!"); - ok(!(doc1 instanceof SpecialPowers.Ci.nsIDOMSVGDocument), + ok(!(doc1 instanceof SVGDocument), "Document shouldn't be an SVG document!"); var docType2 = @@ -68,9 +68,9 @@ function testSVGDocument() { var doc1 = document.implementation.createDocument(null, null, docType1); is(docType1.ownerDocument, doc1, "docType should have ownerDocument!"); ok(!doc1.documentElement, "Document shouldn't have document element!"); - ok(!(doc1 instanceof SpecialPowers.Ci.nsIDOMHTMLDocument), + ok(!(doc1 instanceof HTMLDocument), "Document shouldn't be an HTML document!"); - ok(doc1 instanceof SpecialPowers.Ci.nsIDOMSVGDocument, + ok(doc1 instanceof SVGDocument, "Document should be an SVG document!"); // SVG documents have .rootElement. @@ -95,9 +95,9 @@ function testFooBarDocument() { var doc1 = document.implementation.createDocument(null, null, docType1); is(docType1.ownerDocument, doc1, "docType should have ownerDocument!"); ok(!doc1.documentElement, "Document shouldn't have document element!"); - ok(!(doc1 instanceof SpecialPowers.Ci.nsIDOMHTMLDocument), + ok(!(doc1 instanceof HTMLDocument), "Document shouldn't be an HTML document!"); - ok(!(doc1 instanceof SpecialPowers.Ci.nsIDOMSVGDocument), + ok(!(doc1 instanceof SVGDocument), "Document shouldn't be an SVG document!"); var docType2 = @@ -112,9 +112,9 @@ function testFooBarDocument() { function testNullDocTypeDocument() { var doc1 = document.implementation.createDocument(null, null, null); ok(!doc1.documentElement, "Document shouldn't have document element!"); - ok(!(doc1 instanceof SpecialPowers.Ci.nsIDOMHTMLDocument), + ok(!(doc1 instanceof HTMLDocument), "Document shouldn't be an HTML document!"); - ok(!(doc1 instanceof SpecialPowers.Ci.nsIDOMSVGDocument), + ok(!(doc1 instanceof SVGDocument), "Document shouldn't be an SVG document!"); var doc2 = document.implementation.createDocument("FooBarNS", diff --git a/content/base/test/test_websocket.html b/content/base/test/test_websocket.html index d05156107e50..2e15e7c17a8a 100644 --- a/content/base/test/test_websocket.html +++ b/content/base/test/test_websocket.html @@ -777,8 +777,6 @@ function test22() waitTest22 = true; const pref_open = "network.websocket.timeout.open"; - var oldpref_open_value = 20; - oldpref_open_value = SpecialPowers.getIntPref(pref_open); SpecialPowers.setIntPref(pref_open, 5); var ws = CreateTestWS("ws://sub2.test2.example.org/tests/content/base/test/file_websocket", "test-22"); @@ -791,7 +789,7 @@ function test22() maybeFinished(); }; - SpecialPowers.setIntPref(pref_open, oldpref_open_value); + SpecialPowers.clearUserPref(pref_open); doTest(23); } diff --git a/content/html/content/src/HTMLIFrameElement.cpp b/content/html/content/src/HTMLIFrameElement.cpp index 4f679cde433a..346b19a8c2db 100644 --- a/content/html/content/src/HTMLIFrameElement.cpp +++ b/content/html/content/src/HTMLIFrameElement.cpp @@ -7,7 +7,6 @@ #include "mozilla/dom/HTMLIFrameElement.h" #include "mozilla/dom/HTMLIFrameElementBinding.h" -#include "nsIDOMSVGDocument.h" #include "nsMappedAttributes.h" #include "nsAttrValueInlines.h" #include "nsError.h" diff --git a/content/html/content/src/HTMLLabelElement.cpp b/content/html/content/src/HTMLLabelElement.cpp index e3c7ddab6391..d25bfb0bb38f 100644 --- a/content/html/content/src/HTMLLabelElement.cpp +++ b/content/html/content/src/HTMLLabelElement.cpp @@ -28,7 +28,7 @@ HTMLLabelElement::WrapNode(JSContext *aCx, JS::Handle aScope) return HTMLLabelElementBinding::Wrap(aCx, aScope, this); } -// nsISupports +// nsISupports NS_IMPL_ADDREF_INHERITED(HTMLLabelElement, Element) @@ -171,27 +171,26 @@ HTMLLabelElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor) dragDistance.y > CLICK_DISTANCE || dragDistance.y < -CLICK_DISTANCE; } - // Don't click the for-content if we did drag-select text or if we - // have a kbd modifier (which adjusts a selection), or if it's a - // double click (we already forwarded the first click event). - if (dragSelect || event->clickCount > 1 || - event->IsShift() || event->IsControl() || event->IsAlt() || - event->IsMeta()) { + // have a kbd modifier (which adjusts a selection). + if (dragSelect || event->IsShift() || event->IsControl() || + event->IsAlt() || event->IsMeta()) { break; } - - nsIFocusManager* fm = nsFocusManager::GetFocusManager(); - if (fm) { - // Use FLAG_BYMOVEFOCUS here so that the label is scrolled to. - // Also, within HTMLInputElement::PostHandleEvent, inputs will - // be selected only when focused via a key or when the navigation - // flag is used and we want to select the text on label clicks as - // well. - nsCOMPtr elem = do_QueryInterface(content); - fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS); + // Only set focus on the first click of multiple clicks to prevent + // to prevent immediate de-focus. + if (event->clickCount <= 1) { + nsIFocusManager* fm = nsFocusManager::GetFocusManager(); + if (fm) { + // Use FLAG_BYMOVEFOCUS here so that the label is scrolled to. + // Also, within HTMLInputElement::PostHandleEvent, inputs will + // be selected only when focused via a key or when the navigation + // flag is used and we want to select the text on label clicks as + // well. + nsCOMPtr elem = do_QueryInterface(content); + fm->SetFocus(elem, nsIFocusManager::FLAG_BYMOVEFOCUS); + } } - // Dispatch a new click event to |content| // (For compatibility with IE, we do only left click. If // we wanted to interpret the HTML spec very narrowly, we diff --git a/content/html/content/src/HTMLSharedObjectElement.cpp b/content/html/content/src/HTMLSharedObjectElement.cpp index dff85b6298fd..5a2c862f381c 100644 --- a/content/html/content/src/HTMLSharedObjectElement.cpp +++ b/content/html/content/src/HTMLSharedObjectElement.cpp @@ -13,7 +13,6 @@ #include "nsIPluginDocument.h" #include "nsIDOMDocument.h" #include "nsThreadUtils.h" -#include "nsIDOMSVGDocument.h" #include "nsIScriptError.h" #include "nsIWidget.h" #include "nsContentUtils.h" diff --git a/content/media/AudioNodeStream.cpp b/content/media/AudioNodeStream.cpp index f77e692a582e..368707d57fc6 100644 --- a/content/media/AudioNodeStream.cpp +++ b/content/media/AudioNodeStream.cpp @@ -19,6 +19,7 @@ namespace mozilla { * for regular audio contexts, and the rate requested by the web content * for offline audio contexts. * Each chunk in the track is a single block of WEBAUDIO_BLOCK_SIZE samples. + * Note: This must be a different value than MEDIA_STREAM_DEST_TRACK_ID */ static const int AUDIO_NODE_STREAM_TRACK_ID = 1; @@ -235,23 +236,6 @@ AudioNodeStream::SetChannelMixingParametersImpl(uint32_t aNumberOfChannels, mChannelInterpretation = aChannelInterpretation; } -StreamBuffer::Track* -AudioNodeStream::EnsureTrack() -{ - StreamBuffer::Track* track = mBuffer.FindTrack(AUDIO_NODE_STREAM_TRACK_ID); - if (!track) { - nsAutoPtr segment(new AudioSegment()); - for (uint32_t j = 0; j < mListeners.Length(); ++j) { - MediaStreamListener* l = mListeners[j]; - l->NotifyQueuedTrackChanges(Graph(), AUDIO_NODE_STREAM_TRACK_ID, mSampleRate, 0, - MediaStreamListener::TRACK_EVENT_CREATED, - *segment); - } - track = &mBuffer.AddTrack(AUDIO_NODE_STREAM_TRACK_ID, mSampleRate, 0, segment.forget()); - } - return track; -} - bool AudioNodeStream::AllInputsFinished() const { @@ -399,7 +383,7 @@ AudioNodeStream::ProduceOutput(GraphTime aFrom, GraphTime aTo) FinishOutput(); } - StreamBuffer::Track* track = EnsureTrack(); + StreamBuffer::Track* track = EnsureTrack(AUDIO_NODE_STREAM_TRACK_ID, mSampleRate); AudioSegment* segment = track->Get(); @@ -460,7 +444,7 @@ AudioNodeStream::ProduceOutput(GraphTime aFrom, GraphTime aTo) TrackTicks AudioNodeStream::GetCurrentPosition() { - return EnsureTrack()->Get()->GetDuration(); + return EnsureTrack(AUDIO_NODE_STREAM_TRACK_ID, mSampleRate)->Get()->GetDuration(); } void @@ -470,7 +454,7 @@ AudioNodeStream::FinishOutput() return; } - StreamBuffer::Track* track = EnsureTrack(); + StreamBuffer::Track* track = EnsureTrack(AUDIO_NODE_STREAM_TRACK_ID, mSampleRate); track->SetEnded(); FinishOnGraphThread(); diff --git a/content/media/AudioNodeStream.h b/content/media/AudioNodeStream.h index 4beedc7b0e89..5fd5fafc4df5 100644 --- a/content/media/AudioNodeStream.h +++ b/content/media/AudioNodeStream.h @@ -116,7 +116,6 @@ public: protected: void FinishOutput(); - StreamBuffer::Track* EnsureTrack(); void ObtainInputBlock(AudioChunk& aTmpChunk, uint32_t aPortIndex); // The engine that will generate output for this node. diff --git a/content/media/DOMMediaStream.cpp b/content/media/DOMMediaStream.cpp index dff6dd1c96c3..8cd9a8a89e5e 100644 --- a/content/media/DOMMediaStream.cpp +++ b/content/media/DOMMediaStream.cpp @@ -8,6 +8,7 @@ #include "nsContentUtils.h" #include "mozilla/dom/MediaStreamBinding.h" #include "mozilla/dom/LocalMediaStreamBinding.h" +#include "mozilla/dom/AudioNode.h" #include "MediaStreamGraph.h" #include "AudioStreamTrack.h" #include "VideoStreamTrack.h" @@ -39,6 +40,15 @@ NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(DOMMediaStream) NS_IMPL_ISUPPORTS_INHERITED1(DOMLocalMediaStream, DOMMediaStream, nsIDOMLocalMediaStream) +NS_IMPL_CYCLE_COLLECTION_INHERITED_1(DOMAudioNodeMediaStream, DOMMediaStream, + mStreamNode) + +NS_IMPL_ADDREF_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream) +NS_IMPL_RELEASE_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMAudioNodeMediaStream) +NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream) + class DOMMediaStream::StreamListener : public MediaStreamListener { public: StreamListener(DOMMediaStream* aStream) @@ -346,3 +356,18 @@ DOMLocalMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow, stream->InitTrackUnionStream(aWindow, aHintContents); return stream.forget(); } + +DOMAudioNodeMediaStream::DOMAudioNodeMediaStream(AudioNode* aNode) +: mStreamNode(aNode) +{ +} + +already_AddRefed +DOMAudioNodeMediaStream::CreateTrackUnionStream(nsIDOMWindow* aWindow, + AudioNode* aNode, + TrackTypeHints aHintContents) +{ + nsRefPtr stream = new DOMAudioNodeMediaStream(aNode); + stream->InitTrackUnionStream(aWindow, aHintContents); + return stream.forget(); +} diff --git a/content/media/DOMMediaStream.h b/content/media/DOMMediaStream.h index afb06285b756..7a08d0465340 100644 --- a/content/media/DOMMediaStream.h +++ b/content/media/DOMMediaStream.h @@ -33,6 +33,7 @@ namespace mozilla { class MediaStream; namespace dom { +class AudioNode; class MediaStreamTrack; class AudioStreamTrack; class VideoStreamTrack; @@ -206,6 +207,29 @@ public: CreateTrackUnionStream(nsIDOMWindow* aWindow, TrackTypeHints aHintContents = 0); }; +class DOMAudioNodeMediaStream : public DOMMediaStream +{ + typedef dom::AudioNode AudioNode; +public: + DOMAudioNodeMediaStream(AudioNode* aNode); + + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream) + + /** + * Create a DOMAudioNodeMediaStream whose underlying stream is a TrackUnionStream. + */ + static already_AddRefed + CreateTrackUnionStream(nsIDOMWindow* aWindow, + AudioNode* aNode, + TrackTypeHints aHintContents = 0); + +private: + // If this object wraps a stream owned by an AudioNode, we need to ensure that + // the node isn't cycle-collected too early. + nsRefPtr mStreamNode; +}; + } #endif /* NSDOMMEDIASTREAM_H_ */ diff --git a/content/media/MediaStreamGraph.cpp b/content/media/MediaStreamGraph.cpp index a046059aa9d3..7108b690df5a 100644 --- a/content/media/MediaStreamGraph.cpp +++ b/content/media/MediaStreamGraph.cpp @@ -1525,6 +1525,23 @@ MediaStream::FinishOnGraphThread() GraphImpl()->FinishStream(this); } +StreamBuffer::Track* +MediaStream::EnsureTrack(TrackID aTrackId, TrackRate aSampleRate) +{ + StreamBuffer::Track* track = mBuffer.FindTrack(aTrackId); + if (!track) { + nsAutoPtr segment(new AudioSegment()); + for (uint32_t j = 0; j < mListeners.Length(); ++j) { + MediaStreamListener* l = mListeners[j]; + l->NotifyQueuedTrackChanges(Graph(), aTrackId, aSampleRate, 0, + MediaStreamListener::TRACK_EVENT_CREATED, + *segment); + } + track = &mBuffer.AddTrack(aTrackId, aSampleRate, 0, segment.forget()); + } + return track; +} + void MediaStream::RemoveAllListenersImpl() { diff --git a/content/media/MediaStreamGraph.h b/content/media/MediaStreamGraph.h index 345078762b71..d12658067e0b 100644 --- a/content/media/MediaStreamGraph.h +++ b/content/media/MediaStreamGraph.h @@ -277,9 +277,11 @@ public: , mMainThreadDestroyed(false) , mGraph(nullptr) { + MOZ_COUNT_CTOR(MediaStream); } virtual ~MediaStream() { + MOZ_COUNT_DTOR(MediaStream); NS_ASSERTION(mMainThreadDestroyed, "Should have been destroyed already"); NS_ASSERTION(mMainThreadListeners.IsEmpty(), "All main thread listeners should have been removed"); @@ -431,6 +433,8 @@ public: bool HasCurrentData() { return mHasCurrentData; } + StreamBuffer::Track* EnsureTrack(TrackID aTrack, TrackRate aSampleRate); + void ApplyTrackDisabling(TrackID aTrackID, MediaSegment* aSegment); DOMMediaStream* GetWrapper() diff --git a/content/media/TrackUnionStream.h b/content/media/TrackUnionStream.h index 2601c4197d8b..10066e1e28f7 100644 --- a/content/media/TrackUnionStream.h +++ b/content/media/TrackUnionStream.h @@ -26,6 +26,7 @@ class TrackUnionStream : public ProcessedMediaStream { public: TrackUnionStream(DOMMediaStream* aWrapper) : ProcessedMediaStream(aWrapper), + mFilterCallback(nullptr), mMaxTrackID(0) {} virtual void RemoveInput(MediaInputPort* aPort) @@ -75,7 +76,7 @@ public: break; } } - if (!found) { + if (!found && (!mFilterCallback || mFilterCallback(tracks.get()))) { bool trackFinished = false; uint32_t mapIndex = AddTrack(mInputs[i], tracks.get(), aFrom); CopyTrackData(tracks.get(), mapIndex, aFrom, aTo, &trackFinished); @@ -107,7 +108,16 @@ public: } } + // Consumers may specify a filtering callback to apply to every input track. + // Returns true to allow the track to act as an input; false to reject it entirely. + typedef bool (*TrackIDFilterCallback)(StreamBuffer::Track*); + void SetTrackIDFilter(TrackIDFilterCallback aCallback) { + mFilterCallback = aCallback; + } + protected: + TrackIDFilterCallback mFilterCallback; + // Only non-ended tracks are allowed to persist in this map. struct TrackMapEntry { MediaInputPort* mInputPort; diff --git a/content/media/moz.build b/content/media/moz.build index 8bc287a6210a..8e1c32d1f162 100644 --- a/content/media/moz.build +++ b/content/media/moz.build @@ -71,6 +71,7 @@ EXPORTS += [ 'SharedBuffer.h', 'StreamBuffer.h', 'TimeVarying.h', + 'TrackUnionStream.h', 'VideoFrameContainer.h', 'VideoSegment.h', 'VideoUtils.h', diff --git a/content/media/omx/MediaOmxReader.cpp b/content/media/omx/MediaOmxReader.cpp index 0e3c81ea97af..8dc632818a35 100644 --- a/content/media/omx/MediaOmxReader.cpp +++ b/content/media/omx/MediaOmxReader.cpp @@ -17,6 +17,8 @@ #include "MPAPI.h" #define MAX_DROPPED_FRAMES 25 +// Try not to spend more than this much time in a single call to DecodeVideoFrame. +#define MAX_VIDEO_DECODE_SECONDS 3.0 using namespace android; @@ -156,8 +158,10 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip, aTimeThreshold = mVideoSeekTimeUs; } - // Read next frame - while (true) { + TimeStamp start = TimeStamp::Now(); + + // Read next frame. Don't let this loop run for too long. + while ((TimeStamp::Now() - start) < TimeDuration::FromSeconds(MAX_VIDEO_DECODE_SECONDS)) { MPAPI::VideoFrame frame; frame.mGraphicBuffer = nullptr; frame.mShouldSkip = false; @@ -165,22 +169,23 @@ bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip, mVideoQueue.Finish(); return false; } + doSeek = false; // Ignore empty buffer which stagefright media read will sporadically return if (frame.mSize == 0 && !frame.mGraphicBuffer) { - return true; + continue; } parsed++; if (frame.mShouldSkip && mSkipCount < MAX_DROPPED_FRAMES) { mSkipCount++; - return true; + continue; } mSkipCount = 0; mVideoSeekTimeUs = -1; - doSeek = aKeyframeSkip = false; + aKeyframeSkip = false; nsIntRect picture = mPicture; if (frame.Y.mWidth != mInitialFrame.width || diff --git a/content/media/test/Makefile.in b/content/media/test/Makefile.in index eb30daa7aabb..8d1ed24e31ea 100644 --- a/content/media/test/Makefile.in +++ b/content/media/test/Makefile.in @@ -117,7 +117,6 @@ MOCHITEST_FILES = \ test_too_many_elements.html \ test_volume.html \ test_video_to_canvas.html \ - use_large_cache.js \ test_audiowrite.html \ test_mozHasAudio.html \ test_source_media.html \ diff --git a/content/media/test/test_buffered.html b/content/media/test/test_buffered.html index 2c2ee0f1d5da..98ea36c9983f 100644 --- a/content/media/test/test_buffered.html +++ b/content/media/test/test_buffered.html @@ -8,7 +8,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=462957 - Mozilla Bug 462957 @@ -85,8 +84,11 @@ function startTest(test, token) { document.body.appendChild(v); } -manager.runTests(gSeekTests, startTest); - +SimpleTest.waitForExplicitFinish(); +SpecialPowers.pushPrefEnv({"set": [["media.cache_size", 40000]]}, beginTest); +function beginTest() { + manager.runTests(gSeekTests, startTest); +} diff --git a/content/media/test/test_bug493187.html b/content/media/test/test_bug493187.html index 25c27161f074..db9ce8ee8e80 100644 --- a/content/media/test/test_bug493187.html +++ b/content/media/test/test_bug493187.html @@ -8,7 +8,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=493187 Bug 493187 - enter HAVE_FUTURE_DATA when seeking within buffered data even if new data isn't arriving - @@ -62,8 +61,11 @@ function startTest(test, token) { document.body.appendChild(v); } -manager.runTests(gSeekTests, startTest); - +SimpleTest.waitForExplicitFinish(); +SpecialPowers.pushPrefEnv({"set": [["media.cache_size", 40000]]}, beginTest); +function beginTest() { + manager.runTests(gSeekTests, startTest); +} diff --git a/content/media/test/test_can_play_type_mpeg.html b/content/media/test/test_can_play_type_mpeg.html index 1b310013519d..cd113704fc98 100644 --- a/content/media/test/test_can_play_type_mpeg.html +++ b/content/media/test/test_can_play_type_mpeg.html @@ -33,24 +33,17 @@ function IsWindows7() { } function getMediaPref(name) { - // Can't use SpecialPowers.getBoolPref because it throws when pref isn't - // present, and for example on non-Windows systems the WMF prefs won't be - // present. var pref = false; - var prefService = SpecialPowers.wrap(SpecialPowers.Components) - .classes["@mozilla.org/preferences-service;1"] - .getService(SpecialPowers.Ci.nsIPrefService); - var branch = prefService.getBranch("media."); try { - pref = branch.getBoolPref(name); + pref = SpecialPowers.getBoolPref(name); } catch(ex) { } return pref; } -var haveMp4 = (getMediaPref("windows-media-foundation.enabled") && IsWindowsVistaOrLater()) || - getMediaPref("omx.enabled") || - getMediaPref("gstreamer.enabled"); -// TODO: Add "getMediaPref("plugins.enabled")" once MP4 works on Gingerbread. +var haveMp4 = (getMediaPref("media.windows-media-foundation.enabled") && IsWindowsVistaOrLater()) || + getMediaPref("media.omx.enabled") || + getMediaPref("media.gstreamer.enabled"); +// TODO: Add "getMediaPref("media.plugins.enabled")" once MP4 works on Gingerbread. check_mp4(document.getElementById('v'), haveMp4); diff --git a/content/media/test/test_closing_connections.html b/content/media/test/test_closing_connections.html index 89d483ed5e7e..796f7ef6b685 100644 --- a/content/media/test/test_closing_connections.html +++ b/content/media/test/test_closing_connections.html @@ -1,4 +1,4 @@ - +hg diff