From fb60c43315800bcf50013b1db935994d0583f6b5 Mon Sep 17 00:00:00 2001 From: Honza Bambas Date: Thu, 21 Jul 2016 02:00:00 +0800 Subject: [PATCH 001/135] Bug 1288327 - Disable some HTTP cache tests when the old backend is used, r=dragana --HG-- rename : netwerk/test/unit/test_cache2-29e-non-206-response.js => netwerk/test/unit/test_cache2-29e-concurrent_read_half-non-206-response.js --- .../unit/test_cache2-29c-concurrent_read_half-interrupted.js | 5 +++++ ...test_cache2-29e-concurrent_read_half-non-206-response.js} | 5 +++++ netwerk/test/unit/xpcshell.ini | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) rename netwerk/test/unit/{test_cache2-29e-non-206-response.js => test_cache2-29e-concurrent_read_half-non-206-response.js} (95%) diff --git a/netwerk/test/unit/test_cache2-29c-concurrent_read_half-interrupted.js b/netwerk/test/unit/test_cache2-29c-concurrent_read_half-interrupted.js index f82d685e1e18..06be2e9390f4 100644 --- a/netwerk/test/unit/test_cache2-29c-concurrent_read_half-interrupted.js +++ b/netwerk/test/unit/test_cache2-29c-concurrent_read_half-interrupted.js @@ -60,6 +60,11 @@ function contentHandler(metadata, response) function run_test() { + if (!newCacheBackEndUsed()) { + do_check_true(true, "This test doesn't run when the old cache back end is used since the behavior is different"); + return; + } + // Static check do_check_true(responseBody.length > 1024); diff --git a/netwerk/test/unit/test_cache2-29e-non-206-response.js b/netwerk/test/unit/test_cache2-29e-concurrent_read_half-non-206-response.js similarity index 95% rename from netwerk/test/unit/test_cache2-29e-non-206-response.js rename to netwerk/test/unit/test_cache2-29e-concurrent_read_half-non-206-response.js index d0280f33540a..e49f3987cb99 100644 --- a/netwerk/test/unit/test_cache2-29e-non-206-response.js +++ b/netwerk/test/unit/test_cache2-29e-concurrent_read_half-non-206-response.js @@ -55,6 +55,11 @@ function contentHandler(metadata, response) function run_test() { + if (!newCacheBackEndUsed()) { + do_check_true(true, "This test doesn't run when the old cache back end is used since the behavior is different"); + return; + } + // Static check do_check_true(responseBody.length > 1024); diff --git a/netwerk/test/unit/xpcshell.ini b/netwerk/test/unit/xpcshell.ini index 0dbd5111b75e..f0d7f05b7891 100644 --- a/netwerk/test/unit/xpcshell.ini +++ b/netwerk/test/unit/xpcshell.ini @@ -74,7 +74,7 @@ skip-if = true [test_cache2-29b-concurrent_read_non-resumable_entry_size_zero.js] [test_cache2-29c-concurrent_read_half-interrupted.js] [test_cache2-29d-concurrent_read_half-corrupted-206.js] -[test_cache2-29e-non-206-response.js] +[test_cache2-29e-concurrent_read_half-non-206-response.js] [test_cache2-30a-entry-pinning.js] [test_cache2-30b-pinning-storage-clear.js] [test_cache2-30c-pinning-deferred-doom.js] From b3e11b9f98c82f6b6152ea0f898b6f6eb04f6dbb Mon Sep 17 00:00:00 2001 From: Brad Lassey Date: Mon, 3 Aug 2015 19:24:35 -0400 Subject: [PATCH 002/135] Bug 1186948 - remove plugins that are click-to-play from navigator.plugins (restricted to Flash). r=jst,mconley,mrbkap --- browser/modules/PluginContent.jsm | 57 ++++++++++++++++++++++++++++- dom/base/nsPluginArray.cpp | 50 +++++++++++++++++++++++-- dom/base/nsPluginArray.h | 4 ++ dom/bindings/Bindings.conf | 4 ++ dom/plugins/base/nsIPluginHost.idl | 12 ++++++ dom/plugins/base/nsPluginHost.cpp | 14 +++++-- dom/plugins/base/nsPluginTags.cpp | 2 +- dom/plugins/base/nsPluginTags.h | 6 +++ dom/webidl/HiddenPluginEvent.webidl | 12 ++++++ dom/webidl/moz.build | 1 + 10 files changed, 154 insertions(+), 8 deletions(-) create mode 100644 dom/webidl/HiddenPluginEvent.webidl diff --git a/browser/modules/PluginContent.jsm b/browser/modules/PluginContent.jsm index 9c54d8798b38..7258e8612e16 100644 --- a/browser/modules/PluginContent.jsm +++ b/browser/modules/PluginContent.jsm @@ -46,6 +46,7 @@ PluginContent.prototype = { global.addEventListener("pagehide", this, true); global.addEventListener("pageshow", this, true); global.addEventListener("unload", this); + global.addEventListener("HiddenPlugin", this, true); global.addMessageListener("BrowserPlugins:ActivatePlugins", this); global.addMessageListener("BrowserPlugins:NotificationShown", this); @@ -66,6 +67,7 @@ PluginContent.prototype = { global.removeEventListener("pagehide", this, true); global.removeEventListener("pageshow", this, true); global.removeEventListener("unload", this); + global.removeEventListener("HiddenPlugin", this, true); global.removeMessageListener("BrowserPlugins:ActivatePlugins", this); global.removeMessageListener("BrowserPlugins:NotificationShown", this); @@ -194,6 +196,45 @@ PluginContent.prototype = { }; }, + _getPluginInfoForTag: function (pluginTag, tagMimetype) { + let pluginHost = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost); + + let pluginName = gNavigatorBundle.GetStringFromName("pluginInfo.unknownPlugin"); + let permissionString = null; + let blocklistState = null; + + if (pluginTag) { + pluginName = BrowserUtils.makeNicePluginName(pluginTag.name); + + permissionString = pluginHost.getPermissionStringForTag(pluginTag); + blocklistState = pluginTag.blocklistState; + + // Convert this from nsIPluginTag so it can be serialized. + let properties = ["name", "description", "filename", "version", "enabledState", "niceName"]; + let pluginTagCopy = {}; + for (let prop of properties) { + pluginTagCopy[prop] = pluginTag[prop]; + } + pluginTag = pluginTagCopy; + + // Make state-softblocked == state-notblocked for our purposes, + // they have the same UI. STATE_OUTDATED should not exist for plugin + // items, but let's alias it anyway, just in case. + if (blocklistState == Ci.nsIBlocklistService.STATE_SOFTBLOCKED || + blocklistState == Ci.nsIBlocklistService.STATE_OUTDATED) { + blocklistState = Ci.nsIBlocklistService.STATE_NOT_BLOCKED; + } + } + + return { mimetype: tagMimetype, + pluginName: pluginName, + pluginTag: pluginTag, + permissionString: permissionString, + fallbackType: null, + blocklistState: blocklistState, + }; + }, + /** * Update the visibility of the plugin overlay. */ @@ -353,6 +394,14 @@ PluginContent.prototype = { return; } + if (eventType == "HiddenPlugin") { + let pluginTag = event.tag.QueryInterface(Ci.nsIPluginTag); + if (event.target.defaultView.top.document != this.content.document) { + return; + } + this._showClickToPlayNotification(pluginTag, true); + } + let plugin = event.target; let doc = plugin.ownerDocument; @@ -713,7 +762,13 @@ PluginContent.prototype = { let location = this.content.document.location.href; for (let p of plugins) { - let pluginInfo = this._getPluginInfo(p); + let pluginInfo; + if (p instanceof Ci.nsIPluginTag) { + let mimeType = p.getMimeTypes() > 0 ? p.getMimeTypes()[0] : null; + pluginInfo = this._getPluginInfoForTag(p, mimeType); + } else { + pluginInfo = this._getPluginInfo(p); + } if (pluginInfo.permissionString === null) { Cu.reportError("No permission string for active plugin."); continue; diff --git a/dom/base/nsPluginArray.cpp b/dom/base/nsPluginArray.cpp index 9fce18f8e304..820e79cff6fa 100644 --- a/dom/base/nsPluginArray.cpp +++ b/dom/base/nsPluginArray.cpp @@ -8,6 +8,7 @@ #include "mozilla/dom/PluginArrayBinding.h" #include "mozilla/dom/PluginBinding.h" +#include "mozilla/dom/HiddenPluginEvent.h" #include "nsMimeTypeArray.h" #include "Navigator.h" @@ -20,6 +21,8 @@ #include "mozilla/Services.h" #include "nsIInterfaceRequestorUtils.h" #include "nsContentUtils.h" +#include "nsIPermissionManager.h" +#include "nsIDocument.h" using namespace mozilla; using namespace mozilla::dom; @@ -73,7 +76,8 @@ NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(nsPluginArray, mWindow, - mPlugins) + mPlugins, + mCTPPlugins) static void GetPluginMimeTypes(const nsTArray >& aPlugins, @@ -153,6 +157,7 @@ nsPluginArray::Refresh(bool aReloadDocuments) } mPlugins.Clear(); + mCTPPlugins.Clear(); nsCOMPtr navigator = mWindow->GetNavigator(); @@ -228,6 +233,21 @@ nsPluginArray::NamedGetter(const nsAString& aName, bool &aFound) nsPluginElement* plugin = FindPlugin(mPlugins, aName); aFound = (plugin != nullptr); + if (!aFound) { + nsPluginElement* hiddenPlugin = FindPlugin(mCTPPlugins, aName); + if (hiddenPlugin) { + HiddenPluginEventInit init; + init.mTag = hiddenPlugin->PluginTag(); + nsCOMPtr doc = hiddenPlugin->GetParentObject()->GetDoc(); + RefPtr event = + HiddenPluginEvent::Constructor(doc, NS_LITERAL_STRING("HiddenPlugin"), init); + event->SetTarget(doc); + event->SetTrusted(true); + event->WidgetEventPtr()->mFlags.mOnlyChromeDispatch = true; + bool dummy; + doc->DispatchEvent(event, &dummy); + } + } return plugin; } @@ -289,7 +309,7 @@ operator<(const RefPtr& lhs, void nsPluginArray::EnsurePlugins() { - if (!mPlugins.IsEmpty()) { + if (!mPlugins.IsEmpty() || !mCTPPlugins.IsEmpty()) { // We already have an array of plugin elements. return; } @@ -306,7 +326,31 @@ nsPluginArray::EnsurePlugins() // need to wrap each of these with a nsPluginElement, which is // scriptable. for (uint32_t i = 0; i < pluginTags.Length(); ++i) { - mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i])); + nsCOMPtr pluginTag = do_QueryInterface(pluginTags[i]); + if (!pluginTag) { + mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i])); + } else if (pluginTag->IsActive()) { + uint32_t permission = nsIPermissionManager::ALLOW_ACTION; + if (pluginTag->IsClicktoplay()) { + nsCString name; + pluginTag->GetName(name); + if (NS_LITERAL_CSTRING("Shockwave Flash").Equals(name)) { + RefPtr pluginHost = nsPluginHost::GetInst(); + nsCString permString; + nsresult rv = pluginHost->GetPermissionStringForTag(pluginTag, 0, permString); + if (rv == NS_OK) { + nsIPrincipal* principal = mWindow->GetExtantDoc()->NodePrincipal(); + nsCOMPtr permMgr = services::GetPermissionManager(); + permMgr->TestPermissionFromPrincipal(principal, permString.get(), &permission); + } + } + } + if (permission == nsIPermissionManager::ALLOW_ACTION) { + mPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i])); + } else { + mCTPPlugins.AppendElement(new nsPluginElement(mWindow, pluginTags[i])); + } + } } // Alphabetize the enumeration order of non-hidden plugins to reduce diff --git a/dom/base/nsPluginArray.h b/dom/base/nsPluginArray.h index 526bb73b6769..8e02c9a711ac 100644 --- a/dom/base/nsPluginArray.h +++ b/dom/base/nsPluginArray.h @@ -60,6 +60,10 @@ private: nsCOMPtr mWindow; nsTArray > mPlugins; + /* A separate list of click-to-play plugins that we don't tell content + * about but keep track of so we can still prompt the user to click to play. + */ + nsTArray > mCTPPlugins; }; class nsPluginElement final : public nsISupports, diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf index 5fd8bd9437cd..0d67b7a25281 100644 --- a/dom/bindings/Bindings.conf +++ b/dom/bindings/Bindings.conf @@ -845,6 +845,10 @@ DOMInterfaces = { 'nativeType': 'nsPluginArray', }, +'PluginTag': { + 'nativeType': 'nsIPluginTag', +}, + 'PopupBoxObject': { 'resultNotAddRefed': ['triggerNode', 'anchorNode'], }, diff --git a/dom/plugins/base/nsIPluginHost.idl b/dom/plugins/base/nsIPluginHost.idl index ae349bea2a26..d1124aa25959 100644 --- a/dom/plugins/base/nsIPluginHost.idl +++ b/dom/plugins/base/nsIPluginHost.idl @@ -99,6 +99,18 @@ interface nsIPluginHost : nsISupports ACString getPermissionStringForType(in AUTF8String mimeType, [optional] in uint32_t excludeFlags); + /** + * Get the "permission string" for the plugin. This is a string that can be + * passed to the permission manager to see whether the plugin is allowed to + * run, for example. This will typically be based on the plugin's "nice name" + * and its blocklist state. + * + * @tag The tage we're interested in + * @excludeFlags Set of the EXCLUDE_* flags above, defaulting to EXCLUDE_NONE. + */ + ACString getPermissionStringForTag(in nsIPluginTag tag, + [optional] in uint32_t excludeFlags); + /** * Get the nsIPluginTag for this MIME type. This method works with both * enabled and disabled/blocklisted plugins, but an enabled plugin will diff --git a/dom/plugins/base/nsPluginHost.cpp b/dom/plugins/base/nsPluginHost.cpp index fabb8dadc70a..4ea8079cc86f 100644 --- a/dom/plugins/base/nsPluginHost.cpp +++ b/dom/plugins/base/nsPluginHost.cpp @@ -1110,11 +1110,19 @@ nsPluginHost::GetPermissionStringForType(const nsACString &aMimeType, nsresult rv = GetPluginTagForType(aMimeType, aExcludeFlags, getter_AddRefs(tag)); NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(tag, NS_ERROR_FAILURE); + return GetPermissionStringForTag(tag, aExcludeFlags, aPermissionString); +} + +NS_IMETHODIMP +nsPluginHost::GetPermissionStringForTag(nsIPluginTag* aTag, + uint32_t aExcludeFlags, + nsACString &aPermissionString) +{ + NS_ENSURE_TRUE(aTag, NS_ERROR_FAILURE); aPermissionString.Truncate(); uint32_t blocklistState; - rv = tag->GetBlocklistState(&blocklistState); + nsresult rv = aTag->GetBlocklistState(&blocklistState); NS_ENSURE_SUCCESS(rv, rv); if (blocklistState == nsIBlocklistService::STATE_VULNERABLE_UPDATE_AVAILABLE || @@ -1126,7 +1134,7 @@ nsPluginHost::GetPermissionStringForType(const nsACString &aMimeType, } nsCString niceName; - rv = tag->GetNiceName(niceName); + rv = aTag->GetNiceName(niceName); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(!niceName.IsEmpty(), NS_ERROR_FAILURE); diff --git a/dom/plugins/base/nsPluginTags.cpp b/dom/plugins/base/nsPluginTags.cpp index 326b6ddd91e6..1620935ecb3b 100644 --- a/dom/plugins/base/nsPluginTags.cpp +++ b/dom/plugins/base/nsPluginTags.cpp @@ -323,7 +323,7 @@ nsPluginTag::~nsPluginTag() NS_ASSERTION(!mNext, "Risk of exhausting the stack space, bug 486349"); } -NS_IMPL_ISUPPORTS(nsPluginTag, nsIPluginTag, nsIInternalPluginTag) +NS_IMPL_ISUPPORTS(nsPluginTag, nsPluginTag, nsIInternalPluginTag, nsIPluginTag) void nsPluginTag::InitMime(const char* const* aMimeTypes, const char* const* aMimeDescriptions, diff --git a/dom/plugins/base/nsPluginTags.h b/dom/plugins/base/nsPluginTags.h index 9adc628688ff..71b1d7154d9d 100644 --- a/dom/plugins/base/nsPluginTags.h +++ b/dom/plugins/base/nsPluginTags.h @@ -30,6 +30,9 @@ struct FakePluginTagInit; { 0xe8fdd227, 0x27da, 0x46ee, \ { 0xbe, 0xf3, 0x1a, 0xef, 0x5a, 0x8f, 0xc5, 0xb4 } } +#define NS_PLUGINTAG_IID \ + { 0xcce2e8b9, 0x9702, 0x4d4b, \ + { 0xbe, 0xa4, 0x7c, 0x1e, 0x13, 0x1f, 0xaf, 0x78 } } class nsIInternalPluginTag : public nsIPluginTag { public: @@ -90,6 +93,8 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIInternalPluginTag, NS_IINTERNALPLUGINTAG_IID) class nsPluginTag final : public nsIInternalPluginTag { public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_PLUGINTAG_IID) + NS_DECL_ISUPPORTS NS_DECL_NSIPLUGINTAG @@ -192,6 +197,7 @@ private: static uint32_t sNextId; }; +NS_DEFINE_STATIC_IID_ACCESSOR(nsPluginTag, NS_PLUGINTAG_IID) // A class representing "fake" plugin tags; that is plugin tags not // corresponding to actual NPAPI plugins. In practice these are all diff --git a/dom/webidl/HiddenPluginEvent.webidl b/dom/webidl/HiddenPluginEvent.webidl new file mode 100644 index 000000000000..1ba09acb69ef --- /dev/null +++ b/dom/webidl/HiddenPluginEvent.webidl @@ -0,0 +1,12 @@ +interface PluginTag; + +[Constructor(DOMString type, optional HiddenPluginEventInit eventInit), ChromeOnly] +interface HiddenPluginEvent : Event +{ + readonly attribute PluginTag? tag; +}; + +dictionary HiddenPluginEventInit : EventInit +{ + PluginTag? tag = null; +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 0815174a65a7..94be2e805df2 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -790,6 +790,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [ 'ErrorEvent.webidl', 'FontFaceSetLoadEvent.webidl', 'HashChangeEvent.webidl', + 'HiddenPluginEvent.webidl', 'IccChangeEvent.webidl', 'ImageCaptureErrorEvent.webidl', 'MediaStreamEvent.webidl', From 332fcd9fc9ff1fe6c432dffa41c5b18a3396a856 Mon Sep 17 00:00:00 2001 From: Paul Ellenbogen Date: Tue, 19 Jul 2016 13:56:29 -0700 Subject: [PATCH 003/135] Bug 1204099 - RTP payload type validation. r=docfaraday MozReview-Commit-ID: LYNcxKqKwiC --HG-- extra : transplant_source : %16c%B5%CF%0C%20%05Rn%AB4%F4e%B9%EF%E7%0A%09%FDR --- .../signaling/src/jsep/JsepSessionImpl.cpp | 17 +++++++++++++++++ .../signaling/test/jsep_session_unittest.cpp | 15 +++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp index 42926785abce..7e6ff6f50ff5 100644 --- a/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp +++ b/media/webrtc/signaling/src/jsep/JsepSessionImpl.cpp @@ -7,6 +7,7 @@ #include "signaling/src/jsep/JsepSessionImpl.h" #include #include +#include #include #include "nspr.h" @@ -37,6 +38,17 @@ MOZ_MTLOG_MODULE("jsep") MOZ_MTLOG(ML_ERROR, mLastError); \ } while (0); +static std::bitset<128> GetForbiddenSdpPayloadTypes() { + std::bitset<128> forbidden(0); + forbidden[1] = true; + forbidden[2] = true; + forbidden[19] = true; + for (uint16_t i = 64; i < 96; ++i) { + forbidden[i] = true; + } + return forbidden; +} + nsresult JsepSessionImpl::Init() { @@ -1658,6 +1670,7 @@ JsepSessionImpl::ParseSdp(const std::string& sdp, UniquePtr* parsedp) return rv; } + static const std::bitset<128> forbidden = GetForbiddenSdpPayloadTypes(); if (msection.GetMediaType() == SdpMediaSection::kAudio || msection.GetMediaType() == SdpMediaSection::kVideo) { // Sanity-check that payload type can work with RTP @@ -1668,6 +1681,10 @@ JsepSessionImpl::ParseSdp(const std::string& sdp, UniquePtr* parsedp) JSEP_SET_ERROR("audio/video payload type is too large: " << fmt); return NS_ERROR_INVALID_ARG; } + if (forbidden.test(payloadType)) { + JSEP_SET_ERROR("Illegal audio/video payload type: " << fmt); + return NS_ERROR_INVALID_ARG; + } } } } diff --git a/media/webrtc/signaling/test/jsep_session_unittest.cpp b/media/webrtc/signaling/test/jsep_session_unittest.cpp index 26c871b49abb..5c5d710ff8d7 100644 --- a/media/webrtc/signaling/test/jsep_session_unittest.cpp +++ b/media/webrtc/signaling/test/jsep_session_unittest.cpp @@ -2120,6 +2120,21 @@ TEST_P(JsepSessionTest, RenegotiationAnswererDisablesBundleTransport) answererPairs[0].mRtpTransport.get()); } +TEST_P(JsepSessionTest, ParseRejectsBadMediaFormat) +{ + if (GetParam() == "datachannel") { + return; + } + AddTracks(mSessionOff); + std::string offer = CreateOffer(); + UniquePtr munge(Parse(offer)); + SdpMediaSection& mediaSection = munge->GetMediaSection(0); + mediaSection.AddCodec("75", "DummyFormatVal", 8000, 1); + std::string sdpString = munge->ToString(); + nsresult rv = mSessionOff.SetLocalDescription(kJsepSdpOffer, sdpString); + ASSERT_EQ(NS_ERROR_INVALID_ARG, rv); +} + TEST_P(JsepSessionTest, FullCallWithCandidates) { AddTracks(mSessionOff); From 623b56a3f16ada4ad0b3cb80edc78b9ef4893c3f Mon Sep 17 00:00:00 2001 From: Andrew McCreight Date: Tue, 19 Jul 2016 13:13:00 +0800 Subject: [PATCH 004/135] Bug 1287143 - Remove the window argument to SpecialPowers.exactGC(). r=jmaher Cu.forceCC() is the same as DOMWindowUtils.cycleCollect(), but does not require a window. --- dom/base/test/browser_use_counters.js | 2 +- dom/base/test/test_navigator_language.html | 2 +- dom/bindings/test/test_traceProtos.html | 2 +- dom/cache/test/mochitest/test_cache_orphaned_body.html | 2 +- dom/cache/test/mochitest/test_cache_orphaned_cache.html | 2 +- dom/cache/test/mochitest/test_cache_shrink.html | 2 +- dom/indexedDB/test/helpers.js | 2 +- dom/indexedDB/test/unit/xpcshell-head-parent-process.js | 4 ++-- dom/media/test/manifest.js | 2 +- dom/media/test/test_bug1248229.html | 2 +- dom/media/tests/mochitest/head.js | 2 +- dom/media/webaudio/test/browser_bug1181073.js | 2 +- dom/workers/test/serviceworkers/test_bug1151916.html | 2 +- .../test_https_synth_fetch_from_cached_sw.html | 2 +- dom/workers/test/serviceworkers/test_notification_get.html | 2 +- dom/workers/test/serviceworkers/test_sanitize.html | 2 +- dom/workers/test/serviceworkers/test_sanitize_domain.html | 2 +- dom/workers/test/test_multi_sharedWorker_lifetimes.html | 2 +- js/xpconnect/tests/chrome/test_weakref.xul | 2 +- testing/specialpowers/content/specialpowersAPI.js | 5 ++--- 20 files changed, 22 insertions(+), 23 deletions(-) diff --git a/dom/base/test/browser_use_counters.js b/dom/base/test/browser_use_counters.js index 85aa25406eab..3e81bda081e8 100644 --- a/dom/base/test/browser_use_counters.js +++ b/dom/base/test/browser_use_counters.js @@ -87,7 +87,7 @@ add_task(function* () { function waitForDestroyedDocuments() { let deferred = promise.defer(); - SpecialPowers.exactGC(window, deferred.resolve); + SpecialPowers.exactGC(deferred.resolve); return deferred.promise; } diff --git a/dom/base/test/test_navigator_language.html b/dom/base/test/test_navigator_language.html index c0ddc743ff35..7b986aecbd60 100644 --- a/dom/base/test/test_navigator_language.html +++ b/dom/base/test/test_navigator_language.html @@ -195,7 +195,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=889335 document.body.removeChild(frame); frame = null; - SpecialPowers.exactGC(window, function() { + SpecialPowers.exactGC(function() { // This should not crash. SpecialPowers.pushPrefEnv({"set": [['intl.accept_languages', 'en-GB']]}, nextTest); }); diff --git a/dom/bindings/test/test_traceProtos.html b/dom/bindings/test/test_traceProtos.html index 195876744d64..17a5cb96d4b9 100644 --- a/dom/bindings/test/test_traceProtos.html +++ b/dom/bindings/test/test_traceProtos.html @@ -29,7 +29,7 @@ function callback() { } delete window.XMLHttpRequestUpload; -SpecialPowers.exactGC(window, callback); +SpecialPowers.exactGC(callback); diff --git a/dom/cache/test/mochitest/test_cache_orphaned_body.html b/dom/cache/test/mochitest/test_cache_orphaned_body.html index 7a5496eb4358..43e29921f7df 100644 --- a/dom/cache/test/mochitest/test_cache_orphaned_body.html +++ b/dom/cache/test/mochitest/test_cache_orphaned_body.html @@ -54,7 +54,7 @@ function resetStorage() { function gc() { return new Promise(function(resolve, reject) { - SpecialPowers.exactGC(window, resolve); + SpecialPowers.exactGC(resolve); }); } diff --git a/dom/cache/test/mochitest/test_cache_orphaned_cache.html b/dom/cache/test/mochitest/test_cache_orphaned_cache.html index 2cad1a94069c..c797da7b2f75 100644 --- a/dom/cache/test/mochitest/test_cache_orphaned_cache.html +++ b/dom/cache/test/mochitest/test_cache_orphaned_cache.html @@ -54,7 +54,7 @@ function resetStorage() { function gc() { return new Promise(function(resolve, reject) { - SpecialPowers.exactGC(window, resolve); + SpecialPowers.exactGC(resolve); }); } diff --git a/dom/cache/test/mochitest/test_cache_shrink.html b/dom/cache/test/mochitest/test_cache_shrink.html index dfd6d8b6b6ba..e6b362eb2215 100644 --- a/dom/cache/test/mochitest/test_cache_shrink.html +++ b/dom/cache/test/mochitest/test_cache_shrink.html @@ -54,7 +54,7 @@ function resetStorage() { function gc() { return new Promise(function(resolve, reject) { - SpecialPowers.exactGC(window, resolve); + SpecialPowers.exactGC(resolve); }); } diff --git a/dom/indexedDB/test/helpers.js b/dom/indexedDB/test/helpers.js index a62d9ee2fd54..4393fea155fd 100644 --- a/dom/indexedDB/test/helpers.js +++ b/dom/indexedDB/test/helpers.js @@ -345,7 +345,7 @@ function gc() function scheduleGC() { - SpecialPowers.exactGC(window, continueToNextStep); + SpecialPowers.exactGC(continueToNextStep); } function workerScript() { diff --git a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js index 22fb9fcdd57d..a045776b9ac2 100644 --- a/dom/indexedDB/test/unit/xpcshell-head-parent-process.js +++ b/dom/indexedDB/test/unit/xpcshell-head-parent-process.js @@ -217,7 +217,7 @@ function gc() function scheduleGC() { - SpecialPowers.exactGC(null, continueToNextStep); + SpecialPowers.exactGC(continueToNextStep); } function setTimeout(fun, timeout) { @@ -492,7 +492,7 @@ var SpecialPowers = { this._getPrefs().clearUserPref(prefName); }, // Copied (and slightly adjusted) from specialpowersAPI.js - exactGC: function(win, callback) { + exactGC: function(callback) { let count = 0; function doPreciseGCandCC() { diff --git a/dom/media/test/manifest.js b/dom/media/test/manifest.js index 6eb803e482eb..1fdbf46ef6b9 100644 --- a/dom/media/test/manifest.js +++ b/dom/media/test/manifest.js @@ -1665,7 +1665,7 @@ function mediaTestCleanup(callback) { removeNodeAndSource(A[i]); A[i] = null; } - SpecialPowers.exactGC(window, callback); + SpecialPowers.exactGC(callback); } function setMediaTestsPrefs(callback, extraPrefs) { diff --git a/dom/media/test/test_bug1248229.html b/dom/media/test/test_bug1248229.html index 07645ad6770b..4feb265a3a9c 100644 --- a/dom/media/test/test_bug1248229.html +++ b/dom/media/test/test_bug1248229.html @@ -20,7 +20,7 @@ function doTest() { v.onended = function() { info("Got ended."); v.onended = null; - SpecialPowers.exactGC(window, function() { + SpecialPowers.exactGC(function() { info("GC completed."); v.play(); SimpleTest.finish(); diff --git a/dom/media/tests/mochitest/head.js b/dom/media/tests/mochitest/head.js index d9c19526c7f6..0046f7076067 100644 --- a/dom/media/tests/mochitest/head.js +++ b/dom/media/tests/mochitest/head.js @@ -324,7 +324,7 @@ function setupEnvironment() { // We don't care about waiting for this to complete, we just want to ensure // that we don't build up a huge backlog of GC work. - SpecialPowers.exactGC(window); + SpecialPowers.exactGC(); } // This is called by steeplechase; which provides the test configuration options diff --git a/dom/media/webaudio/test/browser_bug1181073.js b/dom/media/webaudio/test/browser_bug1181073.js index 4c06b440f239..f130972589e5 100644 --- a/dom/media/webaudio/test/browser_bug1181073.js +++ b/dom/media/webaudio/test/browser_bug1181073.js @@ -55,7 +55,7 @@ add_task(function*() { ok(time < 1000, "Interval is not throttled with audio playing (" + time + " ms)"); // Destroy the oscillator, but not the audio context - yield new Promise(resolve => SpecialPowers.exactGC(browser.contentWindow, resolve)); + yield new Promise(resolve => SpecialPowers.exactGC(resolve)); yield oscillatorDemisePromise; time = yield ContentTask.spawn(browser, null, function () { diff --git a/dom/workers/test/serviceworkers/test_bug1151916.html b/dom/workers/test/serviceworkers/test_bug1151916.html index 67cada3e69ad..92811775bf95 100644 --- a/dom/workers/test/serviceworkers/test_bug1151916.html +++ b/dom/workers/test/serviceworkers/test_bug1151916.html @@ -59,7 +59,7 @@ function gc() { return new Promise(function(resolve) { - SpecialPowers.exactGC(window, resolve); + SpecialPowers.exactGC(resolve); }); } diff --git a/dom/workers/test/serviceworkers/test_https_synth_fetch_from_cached_sw.html b/dom/workers/test/serviceworkers/test_https_synth_fetch_from_cached_sw.html index a968ac1a8ee3..7bf3b352aef4 100644 --- a/dom/workers/test/serviceworkers/test_https_synth_fetch_from_cached_sw.html +++ b/dom/workers/test/serviceworkers/test_https_synth_fetch_from_cached_sw.html @@ -38,7 +38,7 @@ // properly store and retrieve the security info from the cache. iframe.parentNode.removeChild(iframe); iframe = null; - SpecialPowers.exactGC(window, function() { + SpecialPowers.exactGC(function() { iframe = document.createElement("iframe"); iframe.src = "https://example.com/tests/dom/workers/test/serviceworkers/fetch/https/synth.html"; document.body.appendChild(iframe); diff --git a/dom/workers/test/serviceworkers/test_notification_get.html b/dom/workers/test/serviceworkers/test_notification_get.html index 51a2163d5f3d..dbb312e7b555 100644 --- a/dom/workers/test/serviceworkers/test_notification_get.html +++ b/dom/workers/test/serviceworkers/test_notification_get.html @@ -23,7 +23,7 @@ iframe.src = "about:blank"; document.body.removeChild(iframe); iframe = null; - SpecialPowers.exactGC(window, function() { + SpecialPowers.exactGC(function() { resolve(result); }); }; diff --git a/dom/workers/test/serviceworkers/test_sanitize.html b/dom/workers/test/serviceworkers/test_sanitize.html index 732785faa787..842cb38c331f 100644 --- a/dom/workers/test/serviceworkers/test_sanitize.html +++ b/dom/workers/test/serviceworkers/test_sanitize.html @@ -59,7 +59,7 @@ iframe.src = "about:blank"; document.body.removeChild(iframe); iframe = null; - SpecialPowers.exactGC(window, function() { + SpecialPowers.exactGC(function() { resolve(message.data); }); }; diff --git a/dom/workers/test/serviceworkers/test_sanitize_domain.html b/dom/workers/test/serviceworkers/test_sanitize_domain.html index 70e108b717d1..054b60f37441 100644 --- a/dom/workers/test/serviceworkers/test_sanitize_domain.html +++ b/dom/workers/test/serviceworkers/test_sanitize_domain.html @@ -58,7 +58,7 @@ iframe.src = "about:blank"; document.body.removeChild(iframe); iframe = null; - SpecialPowers.exactGC(window, function() { + SpecialPowers.exactGC(function() { resolve(message.data); }); }; diff --git a/dom/workers/test/test_multi_sharedWorker_lifetimes.html b/dom/workers/test/test_multi_sharedWorker_lifetimes.html index 19cea358aa41..a3f4dc9b5ba5 100644 --- a/dom/workers/test/test_multi_sharedWorker_lifetimes.html +++ b/dom/workers/test/test_multi_sharedWorker_lifetimes.html @@ -113,7 +113,7 @@ for (let i = 0; i < 3; i++) { info("Running GC"); - SpecialPowers.exactGC(window, sendToGenerator); + SpecialPowers.exactGC(sendToGenerator); yield undefined; info("Waiting the event queue to clear"); diff --git a/js/xpconnect/tests/chrome/test_weakref.xul b/js/xpconnect/tests/chrome/test_weakref.xul index caa808de8740..3950a0e357a8 100644 --- a/js/xpconnect/tests/chrome/test_weakref.xul +++ b/js/xpconnect/tests/chrome/test_weakref.xul @@ -29,6 +29,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=484459 SimpleTest.finish(); } - SpecialPowers.exactGC(window, callback); + SpecialPowers.exactGC(callback); ]]> diff --git a/testing/specialpowers/content/specialpowersAPI.js b/testing/specialpowers/content/specialpowersAPI.js index 9c149a9aa089..f15f316f9488 100644 --- a/testing/specialpowers/content/specialpowersAPI.js +++ b/testing/specialpowers/content/specialpowersAPI.js @@ -1489,13 +1489,12 @@ SpecialPowersAPI.prototype = { // needs to run several times and when no other JS is running. // The current number of iterations has been determined according to massive // cross platform testing. - exactGC: function(win, callback) { - var self = this; + exactGC: function(callback) { let count = 0; function genGCCallback(cb) { return function() { - self.getDOMWindowUtils(win).cycleCollect(); + Cu.forceCC(); if (++count < 2) { Cu.schedulePreciseGC(genGCCallback(cb)); } else if (cb) { From ade553c6cf75ec50189e740ca5137dd019eeb53d Mon Sep 17 00:00:00 2001 From: Evan Tseng Date: Wed, 20 Jul 2016 18:17:45 +0800 Subject: [PATCH 005/135] Bug 1282791 - Order the props, r=Honza --- .../client/shared/components/reps/grip.js | 97 +++++++++++-------- 1 file changed, 59 insertions(+), 38 deletions(-) diff --git a/devtools/client/shared/components/reps/grip.js b/devtools/client/shared/components/reps/grip.js index 9e52fe0ed023..858500c52a85 100644 --- a/devtools/client/shared/components/reps/grip.js +++ b/devtools/client/shared/components/reps/grip.js @@ -63,30 +63,24 @@ define(function (require, exports, module) { return ( type == "boolean" || type == "number" || - type == "string" || - type == "object" + (type == "string" && value.length != 0) ); }; - // Object members with non-empty values are preferred since it gives the - // user a better overview of the object. - let props = this.getProps(object, max, isInterestingProp); - - if (props.length <= max) { - // There are not enough props yet (or at least, not enough props to - // be able to know whether we should print "more…" or not). - // Let's display also empty members and functions. - props = props.concat(this.getProps(object, max, (t, value) => { - return !isInterestingProp(t, value); - })); + let ownProperties = object.preview ? object.preview.ownProperties : []; + let indexes = this.getPropIndexes(ownProperties, max, isInterestingProp); + if (indexes.length < max && indexes.length < object.ownPropertyLength) { + // There are not enough props yet. Then add uninteresting props to display them. + indexes = indexes.concat( + this.getPropIndexes(ownProperties, max - indexes.length, (t, value) => { + return !isInterestingProp(t, value); + }) + ); } - // getProps() can return max+1 properties (it can't return more) - // to indicate that there is more props than allowed. Remove the last - // one and append 'more…' postfix in such case. - if (props.length > max) { - props.pop(); - + let props = this.getProps(ownProperties, indexes); + if (props.length < object.ownPropertyLength) { + // There are some undisplayed props. Then display "more...". let objectLink = this.props.objectLink || span; props.push(Caption({ @@ -108,46 +102,73 @@ define(function (require, exports, module) { return props; }, - getProps: function (object, max, filter) { + /** + * Get props ordered by index. + * + * @param {Object} ownProperties Props object. + * @param {Array} indexes Indexes of props. + * @return {Array} Props. + */ + getProps: function (ownProperties, indexes) { let props = []; - max = max || 3; - if (!object) { - return props; - } + // Make indexes ordered by ascending. + indexes.sort(function (a, b) { + return a - b; + }); + + indexes.forEach((i) => { + let name = Object.keys(ownProperties)[i]; + let value = ownProperties[name].value; + props.push(PropRep(Object.assign({}, this.props, { + key: name, + mode: "tiny", + name: name, + object: value, + equal: ": ", + delim: ", ", + }))); + }); + + return props; + }, + + /** + * Get the indexes of props in the object. + * + * @param {Object} ownProperties Props object. + * @param {Number} max The maximum length of indexes array. + * @param {Function} filter Filter the props you want. + * @return {Array} Indexes of interesting props in the object. + */ + getPropIndexes: function (ownProperties, max, filter) { + let indexes = []; try { - let ownProperties = object.preview ? object.preview.ownProperties : []; + let i = 0; for (let name in ownProperties) { - if (props.length > max) { - return props; + if (indexes.length >= max) { + return indexes; } let prop = ownProperties[name]; - let value = prop.value || {}; + let value = prop.value; // Type is specified in grip's "class" field and for primitive // values use typeof. let type = (value.class || typeof value); type = type.toLowerCase(); - // Show only interesting properties. if (filter(type, value)) { - props.push(PropRep(Object.assign({}, this.props, { - key: name, - mode: "tiny", - name: name, - object: value, - equal: ": ", - delim: ", ", - }))); + indexes.push(i); } + i++; } } catch (err) { console.error(err); } - return props; + return indexes; }, render: function () { From 48ef99e762cddb2bbea2a040c97002eaf35dfa4c Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 22 Jul 2016 10:56:13 +0200 Subject: [PATCH 006/135] Bug 1265386: Fix white-space errors in widget/, r=nfroyd MozReview-Commit-ID: ATXI7dYFHmA --- widget/android/nsDeviceContextAndroid.cpp | 10 +-- widget/cocoa/nsCocoaWindow.h | 2 +- widget/cocoa/nsMenuBarX.mm | 56 ++++++++-------- widget/cocoa/nsMenuItemX.mm | 14 ++-- widget/cocoa/nsMenuX.h | 2 +- widget/cocoa/nsMenuX.mm | 26 ++++---- widget/gtk/nsScreenManagerGtk.cpp | 14 ++-- widget/gtk/nsSound.cpp | 4 +- widget/gtk/nsWidgetFactory.cpp | 2 +- widget/gtk/nsWindow.cpp | 80 +++++++++++------------ widget/gtk/nsWindow.h | 10 +-- widget/nsBaseWidget.h | 10 +-- widget/nsIWidget.h | 62 +++++++++--------- widget/nsPrintOptionsImpl.cpp | 12 ++-- widget/nsTransferable.cpp | 52 +++++++-------- widget/windows/AudioSession.cpp | 4 +- widget/windows/JumpListBuilder.cpp | 30 ++++----- widget/windows/JumpListItem.h | 10 +-- widget/windows/TSFTextStore.h | 4 +- widget/windows/TaskbarPreviewButton.h | 2 +- widget/windows/WidgetTraceEvent.cpp | 2 +- widget/windows/WinTaskbar.cpp | 12 ++-- widget/windows/WinUtils.h | 14 ++-- widget/windows/nsDataObjCollection.h | 4 +- widget/windows/nsDeviceContextSpecWin.cpp | 30 ++++----- widget/windows/nsDragService.cpp | 12 ++-- widget/windows/nsFilePicker.h | 14 ++-- widget/windows/nsWindow.h | 4 +- widget/windows/nsWindowBase.cpp | 4 +- 29 files changed, 251 insertions(+), 251 deletions(-) diff --git a/widget/android/nsDeviceContextAndroid.cpp b/widget/android/nsDeviceContextAndroid.cpp index b37914ec03b3..4c952957eae5 100644 --- a/widget/android/nsDeviceContextAndroid.cpp +++ b/widget/android/nsDeviceContextAndroid.cpp @@ -63,22 +63,22 @@ nsDeviceContextSpecAndroid::EndDocument() nsXPIDLString targetPath; nsCOMPtr destFile; mPrintSettings->GetToFileName(getter_Copies(targetPath)); - + nsresult rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(targetPath), false, getter_AddRefs(destFile)); NS_ENSURE_SUCCESS(rv, rv); - + nsAutoString destLeafName; rv = destFile->GetLeafName(destLeafName); NS_ENSURE_SUCCESS(rv, rv); - + nsCOMPtr destDir; rv = destFile->GetParent(getter_AddRefs(destDir)); NS_ENSURE_SUCCESS(rv, rv); - + rv = mTempFile->MoveTo(destDir, destLeafName); NS_ENSURE_SUCCESS(rv, rv); - + destFile->SetPermissions(0666); return NS_OK; } diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h index 1bb3c7d60ca7..497082e6b99a 100644 --- a/widget/cocoa/nsCocoaWindow.h +++ b/widget/cocoa/nsCocoaWindow.h @@ -172,7 +172,7 @@ typedef struct _nsCocoaWindowList { @class ToolbarWindow; -// NSColor subclass that allows us to draw separate colors both in the titlebar +// NSColor subclass that allows us to draw separate colors both in the titlebar // and for background of the window. @interface TitlebarAndBackgroundColor : NSColor { diff --git a/widget/cocoa/nsMenuBarX.mm b/widget/cocoa/nsMenuBarX.mm index d902758fb849..ff25eb81fc8a 100644 --- a/widget/cocoa/nsMenuBarX.mm +++ b/widget/cocoa/nsMenuBarX.mm @@ -127,7 +127,7 @@ nsresult nsMenuBarX::Create(nsIWidget* aParent, nsIContent* aContent) void nsMenuBarX::ConstructNativeMenus() { uint32_t count = mContent->GetChildCount(); - for (uint32_t i = 0; i < count; i++) { + for (uint32_t i = 0; i < count; i++) { nsIContent *menuContent = mContent->GetChildAt(i); if (menuContent && menuContent->IsXULElement(nsGkAtoms::menu)) { @@ -140,7 +140,7 @@ void nsMenuBarX::ConstructNativeMenus() delete newMenu; } } - } + } } void nsMenuBarX::ConstructFallbackNativeMenus() @@ -270,7 +270,7 @@ void nsMenuBarX::ObserveAttributeChanged(nsIDocument* aDocument, } void nsMenuBarX::ObserveContentRemoved(nsIDocument* aDocument, - nsIContent* aChild, + nsIContent* aChild, int32_t aIndexInContainer) { RemoveMenuAtIndex(aIndexInContainer); @@ -478,7 +478,7 @@ void nsMenuBarX::ResetNativeApplicationMenu() void nsMenuBarX::HideItem(nsIDOMDocument* inDoc, const nsAString & inID, nsIContent** outHiddenNode) { nsCOMPtr menuItem; - inDoc->GetElementById(inID, getter_AddRefs(menuItem)); + inDoc->GetElementById(inID, getter_AddRefs(menuItem)); nsCOMPtr menuContent(do_QueryInterface(menuItem)); if (menuContent) { menuContent->SetAttr(kNameSpaceID_None, nsGkAtoms::hidden, NS_LITERAL_STRING("true"), false); @@ -505,7 +505,7 @@ void nsMenuBarX::AquifyMenuBar() HideItem(domDoc, NS_LITERAL_STRING("menu_FileQuitItem"), getter_AddRefs(mQuitItemContent)); if (!sQuitItemContent) sQuitItemContent = mQuitItemContent; - + // remove prefs item and its separator, but save off the pref content node // so we can invoke its command later. HideItem(domDoc, NS_LITERAL_STRING("menu_PrefsSeparator"), nullptr); @@ -586,7 +586,7 @@ NSMenuItem* nsMenuBarX::CreateNativeAppMenuItem(nsMenuX* inMenu, const nsAString // put together the actual NSMenuItem NSMenuItem* newMenuItem = [[NSMenuItem alloc] initWithTitle:labelString action:action keyEquivalent:keyEquiv]; - + [newMenuItem setTag:tag]; [newMenuItem setTarget:target]; [newMenuItem setKeyEquivalentModifierMask:macKeyModifiers]; @@ -609,36 +609,36 @@ nsresult nsMenuBarX::CreateApplicationMenu(nsMenuX* inMenu) // the nib in cocoa widgets. We do not have a way to create an application // menu manually, so we grab the one from the nib and use that. sApplicationMenu = [[[[NSApp mainMenu] itemAtIndex:0] submenu] retain]; - + /* We support the following menu items here: Menu Item DOM Node ID Notes - + ======================== = About This App = <- aboutName ======================== = Preferences... = <- menu_preferences ======================== = Services > = <- menu_mac_services <- (do not define key equivalent) - ======================== + ======================== = Hide App = <- menu_mac_hide_app = Hide Others = <- menu_mac_hide_others = Show All = <- menu_mac_show_all - ======================== + ======================== = Quit = <- menu_FileQuitItem - ======================== - + ======================== + If any of them are ommitted from the application's DOM, we just don't add them. We always add a "Quit" item, but if an app developer does not provide a DOM node with the right ID for the Quit item, we add it in English. App developers need only add each node with a label and a key equivalent (if they want one). Other attributes are optional. Like so: - + - + We need to use this system for localization purposes, until we have a better way to define the Application menu to be used on Mac OS X. */ @@ -681,21 +681,21 @@ nsresult nsMenuBarX::CreateApplicationMenu(nsMenuX* inMenu) 0, nil); if (itemBeingAdded) { [sApplicationMenu addItem:itemBeingAdded]; - + // set this menu item up as the Mac OS X Services menu NSMenu* servicesMenu = [[GeckoServicesNSMenu alloc] initWithTitle:@""]; [itemBeingAdded setSubmenu:servicesMenu]; [NSApp setServicesMenu:servicesMenu]; - + [itemBeingAdded release]; itemBeingAdded = nil; - + // Add separator after Services menu - [sApplicationMenu addItem:[NSMenuItem separatorItem]]; + [sApplicationMenu addItem:[NSMenuItem separatorItem]]; } - + BOOL addHideShowSeparator = FALSE; - + // Add menu item to hide this application itemBeingAdded = CreateNativeAppMenuItem(inMenu, NS_LITERAL_STRING("menu_mac_hide_app"), @selector(menuItemHit:), eCommand_ID_HideApp, nsMenuBarX::sNativeEventTarget); @@ -703,10 +703,10 @@ nsresult nsMenuBarX::CreateApplicationMenu(nsMenuX* inMenu) [sApplicationMenu addItem:itemBeingAdded]; [itemBeingAdded release]; itemBeingAdded = nil; - + addHideShowSeparator = TRUE; } - + // Add menu item to hide other applications itemBeingAdded = CreateNativeAppMenuItem(inMenu, NS_LITERAL_STRING("menu_mac_hide_others"), @selector(menuItemHit:), eCommand_ID_HideOthers, nsMenuBarX::sNativeEventTarget); @@ -714,10 +714,10 @@ nsresult nsMenuBarX::CreateApplicationMenu(nsMenuX* inMenu) [sApplicationMenu addItem:itemBeingAdded]; [itemBeingAdded release]; itemBeingAdded = nil; - + addHideShowSeparator = TRUE; } - + // Add menu item to show all applications itemBeingAdded = CreateNativeAppMenuItem(inMenu, NS_LITERAL_STRING("menu_mac_show_all"), @selector(menuItemHit:), eCommand_ID_ShowAll, nsMenuBarX::sNativeEventTarget); @@ -725,14 +725,14 @@ nsresult nsMenuBarX::CreateApplicationMenu(nsMenuX* inMenu) [sApplicationMenu addItem:itemBeingAdded]; [itemBeingAdded release]; itemBeingAdded = nil; - + addHideShowSeparator = TRUE; } - + // Add a separator after the hide/show menus if at least one exists if (addHideShowSeparator) [sApplicationMenu addItem:[NSMenuItem separatorItem]]; - + // Add quit menu item itemBeingAdded = CreateNativeAppMenuItem(inMenu, NS_LITERAL_STRING("menu_FileQuitItem"), @selector(menuItemHit:), eCommand_ID_Quit, nsMenuBarX::sNativeEventTarget); @@ -751,7 +751,7 @@ nsresult nsMenuBarX::CreateApplicationMenu(nsMenuX* inMenu) [sApplicationMenu addItem:defaultQuitItem]; } } - + return (sApplicationMenu) ? NS_OK : NS_ERROR_FAILURE; NS_OBJC_END_TRY_ABORT_BLOCK_NSRESULT; diff --git a/widget/cocoa/nsMenuItemX.mm b/widget/cocoa/nsMenuItemX.mm index d1ad52c7a1e3..114b69f43010 100644 --- a/widget/cocoa/nsMenuItemX.mm +++ b/widget/cocoa/nsMenuItemX.mm @@ -125,12 +125,12 @@ nsresult nsMenuItemX::SetChecked(bool aIsChecked) NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NSRESULT; mIsChecked = aIsChecked; - + // update the content model. This will also handle unchecking our siblings // if we are a radiomenu - mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, + mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, mIsChecked ? NS_LITERAL_STRING("true") : NS_LITERAL_STRING("false"), true); - + // update native menu item if (mIsChecked) [mNativeMenuItem setState:NSOnState]; @@ -217,14 +217,14 @@ void nsMenuItemX::UncheckRadioSiblings(nsIContent* inCheckedContent) uint32_t count = parent->GetChildCount(); for (uint32_t i = 0; i < count; i++) { nsIContent *sibling = parent->GetChildAt(i); - if (sibling) { + if (sibling) { if (sibling != inCheckedContent) { // skip this node // if the current sibling is in the same group, clear it if (sibling->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, myGroupName, eCaseMatters)) sibling->SetAttr(kNameSpaceID_None, nsGkAtoms::checked, NS_LITERAL_STRING("false"), true); } - } + } } } @@ -289,7 +289,7 @@ nsMenuItemX::ObserveAttributeChanged(nsIDocument *aDocument, nsIContent *aConten if (!aContent) return; - + if (aContent == mContent) { // our own content node changed if (aAttribute == nsGkAtoms::checked) { // if we're a radio menu, uncheck our sibling radio items. No need to @@ -330,7 +330,7 @@ nsMenuItemX::ObserveAttributeChanged(nsIDocument *aDocument, nsIContent *aConten mContent->GetAttr(kNameSpaceID_None, nsGkAtoms::disabled, menuDisabled); if (!commandDisabled.Equals(menuDisabled)) { // The menu's disabled state needs to be updated to match the command. - if (commandDisabled.IsEmpty()) + if (commandDisabled.IsEmpty()) mContent->UnsetAttr(kNameSpaceID_None, nsGkAtoms::disabled, true); else mContent->SetAttr(kNameSpaceID_None, nsGkAtoms::disabled, commandDisabled, true); diff --git a/widget/cocoa/nsMenuX.h b/widget/cocoa/nsMenuX.h index fddc0c6c3593..7b5146a0b84c 100644 --- a/widget/cocoa/nsMenuX.h +++ b/widget/cocoa/nsMenuX.h @@ -75,7 +75,7 @@ protected: bool OnClose(); nsresult AddMenuItem(nsMenuItemX* aMenuItem); nsMenuX* AddMenu(mozilla::UniquePtr aMenu); - void LoadMenuItem(nsIContent* inMenuItemContent); + void LoadMenuItem(nsIContent* inMenuItemContent); void LoadSubMenu(nsIContent* inMenuContent); GeckoNSMenu* CreateMenuWithGeckoString(nsString& menuTitle); diff --git a/widget/cocoa/nsMenuX.mm b/widget/cocoa/nsMenuX.mm index 9d7d69403f3d..dfa1a4a6b6d5 100644 --- a/widget/cocoa/nsMenuX.mm +++ b/widget/cocoa/nsMenuX.mm @@ -119,7 +119,7 @@ nsMenuX::nsMenuX() } mMenuDelegate = [[MenuDelegate alloc] initWithGeckoMenu:this]; - + if (!nsMenuBarX::sNativeEventTarget) nsMenuBarX::sNativeEventTarget = [[NativeMenuItemTarget alloc] init]; @@ -287,7 +287,7 @@ nsresult nsMenuX::GetVisibleItemCount(uint32_t &aCount) // If you need to iterate or search, consider using GetItemAt and doing your own filtering nsMenuObjectX* nsMenuX::GetVisibleItemAt(uint32_t aPos) { - + uint32_t count = mMenuObjectsArray.Length(); if (aPos >= mVisibleItemsCount || aPos >= count) return NULL; @@ -362,7 +362,7 @@ nsEventStatus nsMenuX::MenuOpened() GetMenuPopupContent(getter_AddRefs(popupContent)); nsIContent* dispatchTo = popupContent ? popupContent : mContent; dispatchTo->DispatchDOMEvent(&event, nullptr, nullptr, &status); - + return nsEventStatus_eConsumeNoDefault; } @@ -396,7 +396,7 @@ void nsMenuX::MenuConstruct() { mConstructed = false; gConstructingMenu = true; - + // reset destroy handler flag so that we'll know to fire it next time this menu goes away. mDestroyHandlerCalled = false; @@ -564,10 +564,10 @@ bool nsMenuX::OnOpen() nsEventStatus status = nsEventStatus_eIgnore; WidgetMouseEvent event(true, eXULPopupShowing, nullptr, WidgetMouseEvent::eReal); - + nsCOMPtr popupContent; GetMenuPopupContent(getter_AddRefs(popupContent)); - + nsresult rv = NS_OK; nsIContent* dispatchTo = popupContent ? popupContent : mContent; rv = dispatchTo->DispatchDOMEvent(&event, nullptr, nullptr, &status); @@ -609,12 +609,12 @@ bool nsMenuX::OnClose() nsresult rv = NS_OK; nsIContent* dispatchTo = popupContent ? popupContent : mContent; rv = dispatchTo->DispatchDOMEvent(&event, nullptr, nullptr, &status); - + mDestroyHandlerCalled = true; - + if (NS_FAILED(rv) || status == nsEventStatus_eConsumeNoDefault) return false; - + return true; } @@ -626,7 +626,7 @@ void nsMenuX::GetMenuPopupContent(nsIContent** aResult) if (!aResult) return; *aResult = nullptr; - + // Check to see if we are a "menupopup" node (if we are a native menu). { int32_t dummy; @@ -639,7 +639,7 @@ void nsMenuX::GetMenuPopupContent(nsIContent** aResult) } // Otherwise check our child nodes. - + uint32_t count = mContent->GetChildCount(); for (uint32_t i = 0; i < count; i++) { @@ -704,7 +704,7 @@ void nsMenuX::ObserveAttributeChanged(nsIDocument *aDocument, nsIContent *aConte } else if (parentType == eSubmenuObjectType) { static_cast(mParent)->SetRebuild(true); - } + } else if (parentType == eStandaloneNativeMenuObjectType) { static_cast(mParent)->GetMenuXObject()->SetRebuild(true); } @@ -902,7 +902,7 @@ static NSMutableDictionary *gShadowKeyEquivDB = nil; - (id)initWithItem:(NSMenuItem *)aItem table:(NSMapTable *)aTable { NS_OBJC_BEGIN_TRY_ABORT_BLOCK_NIL; - + if (!gShadowKeyEquivDB) gShadowKeyEquivDB = [[NSMutableDictionary alloc] init]; self = [super init]; diff --git a/widget/gtk/nsScreenManagerGtk.cpp b/widget/gtk/nsScreenManagerGtk.cpp index 1afcc8122057..98166cc924db 100644 --- a/widget/gtk/nsScreenManagerGtk.cpp +++ b/widget/gtk/nsScreenManagerGtk.cpp @@ -145,7 +145,7 @@ nsScreenManagerGtk :: Init() _XnrmQueryScreens_fn _XnrmQueryScreens = (_XnrmQueryScreens_fn) PR_FindFunctionSymbol(mXineramalib, "XineramaQueryScreens"); - + // get the number of screens via xinerama Display *display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); if (_XnrmIsActive && _XnrmQueryScreens && _XnrmIsActive(display)) { @@ -233,7 +233,7 @@ nsScreenManagerGtk :: ScreenForId ( uint32_t aId, nsIScreen **outScreen ) // -// ScreenForRect +// ScreenForRect // // Returns the screen that contains the rectangle. If the rect overlaps // multiple screens, it picks the screen with the greatest area of intersection. @@ -279,7 +279,7 @@ nsScreenManagerGtk::ScreenForRect(int32_t aX, int32_t aY, *aOutScreen = mCachedScreenArray.SafeObjectAt(which); NS_IF_ADDREF(*aOutScreen); return NS_OK; - + } // ScreenForRect @@ -289,8 +289,8 @@ nsScreenManagerGtk::ScreenForRect(int32_t aX, int32_t aY, // The screen with the menubar/taskbar. This shouldn't be needed very // often. // -NS_IMETHODIMP -nsScreenManagerGtk :: GetPrimaryScreen(nsIScreen * *aPrimaryScreen) +NS_IMETHODIMP +nsScreenManagerGtk :: GetPrimaryScreen(nsIScreen * *aPrimaryScreen) { nsresult rv; rv = EnsureInit(); @@ -301,7 +301,7 @@ nsScreenManagerGtk :: GetPrimaryScreen(nsIScreen * *aPrimaryScreen) *aPrimaryScreen = mCachedScreenArray.SafeObjectAt(0); NS_IF_ADDREF(*aPrimaryScreen); return NS_OK; - + } // GetPrimaryScreen @@ -321,7 +321,7 @@ nsScreenManagerGtk :: GetNumberOfScreens(uint32_t *aNumberOfScreens) } *aNumberOfScreens = mCachedScreenArray.Count(); return NS_OK; - + } // GetNumberOfScreens NS_IMETHODIMP diff --git a/widget/gtk/nsSound.cpp b/widget/gtk/nsSound.cpp index 0459c52d3953..61347668e3ed 100644 --- a/widget/gtk/nsSound.cpp +++ b/widget/gtk/nsSound.cpp @@ -184,7 +184,7 @@ nsSound::Init() { // This function is designed so that no library is compulsory, and // one library missing doesn't cause the other(s) to not be used. - if (mInited) + if (mInited) return NS_OK; mInited = true; @@ -429,7 +429,7 @@ NS_IMETHODIMP nsSound::PlaySystemSound(const nsAString &aSoundAlias) // create a nsIFile and then a nsIFileURL from that nsCOMPtr soundFile; - rv = NS_NewLocalFile(aSoundAlias, true, + rv = NS_NewLocalFile(aSoundAlias, true, getter_AddRefs(soundFile)); NS_ENSURE_SUCCESS(rv,rv); diff --git a/widget/gtk/nsWidgetFactory.cpp b/widget/gtk/nsWidgetFactory.cpp index cc4fcc1764ca..9a9974143a53 100644 --- a/widget/gtk/nsWidgetFactory.cpp +++ b/widget/gtk/nsWidgetFactory.cpp @@ -217,7 +217,7 @@ NS_DEFINE_NAMED_CID(NS_PRINTER_ENUMERATOR_CID); NS_DEFINE_NAMED_CID(NS_PRINTSESSION_CID); NS_DEFINE_NAMED_CID(NS_DEVICE_CONTEXT_SPEC_CID); NS_DEFINE_NAMED_CID(NS_PRINTDIALOGSERVICE_CID); -#endif +#endif NS_DEFINE_NAMED_CID(NS_IMAGE_TO_PIXBUF_CID); #if defined(MOZ_X11) NS_DEFINE_NAMED_CID(NS_IDLE_SERVICE_CID); diff --git a/widget/gtk/nsWindow.cpp b/widget/gtk/nsWindow.cpp index 409e8145505e..e09cb8becdf4 100644 --- a/widget/gtk/nsWindow.cpp +++ b/widget/gtk/nsWindow.cpp @@ -591,13 +591,13 @@ nsWindow::OnDestroy(void) return; mOnDestroyCalled = true; - + // Prevent deletion. nsCOMPtr kungFuDeathGrip = this; // release references to children, device context, toolkit + app shell - nsBaseWidget::OnDestroy(); - + nsBaseWidget::OnDestroy(); + // Remove association between this object and its parent and siblings. nsBaseWidget::Destroy(); mParent = nullptr; @@ -719,9 +719,9 @@ nsWindow::Destroy(void) } mLayerManager = nullptr; - // It is safe to call DestroyeCompositor several times (here and + // It is safe to call DestroyeCompositor several times (here and // in the parent class) since it will take effect only once. - // The reason we call it here is because on gtk platforms we need + // The reason we call it here is because on gtk platforms we need // to destroy the compositor before we destroy the gdk window (which // destroys the the gl context attached to it). DestroyCompositor(); @@ -889,7 +889,7 @@ nsWindow::ReparentNativeWidget(nsIWidget* aNewParent) } MOZ_ASSERT(!gdk_window_is_destroyed(mGdkWindow), "destroyed GdkWindow with widget"); - + nsWindow* newParent = static_cast(aNewParent); GdkWindow* newParentWindow = newParent->mGdkWindow; GtkWidget* newContainer = newParent->GetMozContainerWidget(); @@ -975,14 +975,14 @@ nsWindow::RegisterTouchWindow() NS_IMETHODIMP nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY) { - if (!mIsTopLevel || !mShell) + if (!mIsTopLevel || !mShell) return NS_OK; double dpiScale = GetDefaultScale().scale; // we need to use the window size in logical screen pixels int32_t logWidth = std::max(NSToIntRound(mBounds.width / dpiScale), 1); - int32_t logHeight = std::max(NSToIntRound(mBounds.height / dpiScale), 1); + int32_t logHeight = std::max(NSToIntRound(mBounds.height / dpiScale), 1); /* get our playing field. use the current screen, or failing that for any reason, use device caps for the default screen. */ @@ -1018,7 +1018,7 @@ nsWindow::ConstrainPosition(bool aAllowSlop, int32_t *aX, int32_t *aY) *aY = screenRect.y - logHeight + kWindowPositionSlop; else if (*aY >= screenRect.YMost() - kWindowPositionSlop) *aY = screenRect.YMost() - kWindowPositionSlop; - } else { + } else { if (*aX < screenRect.x) *aX = screenRect.x; else if (*aX >= screenRect.XMost() - logWidth) @@ -1398,7 +1398,7 @@ nsWindow::GetLastUserInputTime() if (sLastUserInputTime != GDK_CURRENT_TIME && TimestampIsNewerThan(sLastUserInputTime, timestamp)) { return sLastUserInputTime; - } + } return timestamp; } @@ -1814,7 +1814,7 @@ nsWindow::SetIcon(const nsAString& aIconSpec) return NS_OK; nsAutoCString iconName; - + if (aIconSpec.EqualsLiteral("default")) { nsXPIDLString brandName; GetBrandName(brandName); @@ -1823,7 +1823,7 @@ nsWindow::SetIcon(const nsAString& aIconSpec) } else { AppendUTF16toUTF8(aIconSpec, iconName); } - + nsCOMPtr iconFile; nsAutoCString path; @@ -3224,7 +3224,7 @@ nsWindow::OnScrollEvent(GdkEventScroll *aEvent) // check for duplicate legacy scroll event, see GNOME bug 726878 if (aEvent->direction != GDK_SCROLL_SMOOTH && mLastScrollEventTime == aEvent->time) - return; + return; #endif WidgetWheelEvent wheelEvent(true, eWheel, this); wheelEvent.mDeltaMode = nsIDOMWheelEvent::DOM_DELTA_LINE; @@ -3240,8 +3240,8 @@ nsWindow::OnScrollEvent(GdkEventScroll *aEvent) wheelEvent.mDeltaX = aEvent->delta_x * 3; wheelEvent.mDeltaY = aEvent->delta_y * 3; wheelEvent.mIsNoLineOrPageDelta = true; - // This next step manually unsets smooth scrolling for touch devices - // that trigger GDK_SCROLL_SMOOTH. We use the slave device, which + // This next step manually unsets smooth scrolling for touch devices + // that trigger GDK_SCROLL_SMOOTH. We use the slave device, which // represents the actual input. GdkDevice *device = gdk_event_get_source_device((GdkEvent*)aEvent); GdkInputSource source = gdk_device_get_source(device); @@ -3663,7 +3663,7 @@ nsWindow::Create(nsIWidget* aParent, if (mWindowType == eWindowType_dialog) { SetDefaultIcon(); - gtk_window_set_wmclass(GTK_WINDOW(mShell), "Dialog", + gtk_window_set_wmclass(GTK_WINDOW(mShell), "Dialog", gdk_get_program_class()); gtk_window_set_type_hint(GTK_WINDOW(mShell), GDK_WINDOW_TYPE_HINT_DIALOG); @@ -3719,7 +3719,7 @@ nsWindow::Create(nsIWidget* aParent, // WM_TAKE_FOCUS, focus is requested on the parent window. gtk_widget_realize(mShell); gdk_window_add_filter(gtk_widget_get_window(mShell), - popup_take_focus_filter, nullptr); + popup_take_focus_filter, nullptr); #endif } @@ -3750,7 +3750,7 @@ nsWindow::Create(nsIWidget* aParent, } else { // must be eWindowType_toplevel SetDefaultIcon(); - gtk_window_set_wmclass(GTK_WINDOW(mShell), "Toplevel", + gtk_window_set_wmclass(GTK_WINDOW(mShell), "Toplevel", gdk_get_program_class()); // each toplevel window gets its own window group @@ -4031,7 +4031,7 @@ nsWindow::SetWindowClass(const nsAString &xulWinType) const char *res_class = gdk_get_program_class(); if (!res_class) return NS_ERROR_FAILURE; - + char *res_name = ToNewCString(xulWinType); if (!res_name) return NS_ERROR_OUT_OF_MEMORY; @@ -4578,9 +4578,9 @@ nsWindow::ApplyTransparencyBitmap() g_object_unref(maskBitmap); #else cairo_surface_t *maskBitmap; - maskBitmap = cairo_image_surface_create_for_data((unsigned char*)mTransparencyBitmap, - CAIRO_FORMAT_A1, - mTransparencyBitmapWidth, + maskBitmap = cairo_image_surface_create_for_data((unsigned char*)mTransparencyBitmap, + CAIRO_FORMAT_A1, + mTransparencyBitmapWidth, mTransparencyBitmapHeight, GetBitmapStride(mTransparencyBitmapWidth)); if (!maskBitmap) @@ -4766,7 +4766,7 @@ nsWindow::SetUrgencyHint(GtkWidget *top_window, bool state) { if (!top_window) return; - + gdk_window_set_urgency_hint(gtk_widget_get_window(top_window), state); } @@ -4780,12 +4780,12 @@ nsWindow::SetupPluginPort(void) return nullptr; Window window = gdk_x11_window_get_xid(mGdkWindow); - + // we have to flush the X queue here so that any plugins that // might be running on separate X connections will be able to use // this window in case it was just created #ifdef MOZ_X11 - XWindowAttributes xattrs; + XWindowAttributes xattrs; Display *display = GDK_DISPLAY_XDISPLAY(gdk_display_get_default()); XGetWindowAttributes(display, window, &xattrs); XSelectInput (display, window, @@ -4796,7 +4796,7 @@ nsWindow::SetupPluginPort(void) XSync(display, False); #endif /* MOZ_X11 */ - + return (void *)window; } @@ -4829,7 +4829,7 @@ nsWindow::SetNonXEmbedPluginFocus() Window curFocusWindow; int focusState; - + GdkDisplay *gdkDisplay = gdk_window_get_display(mGdkWindow); XGetInputFocus(gdk_x11_display_get_xdisplay(gdkDisplay), &curFocusWindow, @@ -5313,7 +5313,7 @@ get_gtk_cursor(nsCursor aCursor) if ((gdkcursor = gCursorCache[aCursor])) { return gdkcursor; } - + GdkDisplay *defaultDisplay = gdk_display_get_default(); // The strategy here is to use standard GDK cursors, and, if not available, @@ -5487,15 +5487,15 @@ get_gtk_cursor(nsCursor aCursor) GdkPixbuf * cursor_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, 32, 32); if (!cursor_pixbuf) return nullptr; - + guchar *data = gdk_pixbuf_get_pixels(cursor_pixbuf); - + // Read data from GtkCursors and compose RGBA surface from 1bit bitmap and mask // GtkCursors bits and mask are 32x32 monochrome bitmaps (1 bit for each pixel) // so it's 128 byte array (4 bytes for are one bitmap row and there are 32 rows here). const unsigned char *bits = GtkCursors[newType].bits; const unsigned char *mask_bits = GtkCursors[newType].mask_bits; - + for (int i = 0; i < 128; i++) { char bit = *bits++; char mask = *mask_bits++; @@ -5507,11 +5507,11 @@ get_gtk_cursor(nsCursor aCursor) *data++ = (((mask >> j) & 0x01) * 0xff); } } - + gdkcursor = gdk_cursor_new_from_pixbuf(gdk_display_get_default(), cursor_pixbuf, GtkCursors[newType].hot_x, GtkCursors[newType].hot_y); - + g_object_unref(cursor_pixbuf); } @@ -5542,16 +5542,16 @@ draw_window_of_widget(GtkWidget *widget, GdkWindow *aWindow, cairo_t *cr) if (!window) { NS_WARNING("Cannot get nsWindow from GtkWidget"); } - else { - cairo_save(cr); - gtk_cairo_transform_to_window(cr, widget, aWindow); + else { + cairo_save(cr); + gtk_cairo_transform_to_window(cr, widget, aWindow); // TODO - window->OnExposeEvent() can destroy this or other windows, // do we need to handle it somehow? window->OnExposeEvent(cr); cairo_restore(cr); } } - + GList *children = gdk_window_get_children(aWindow); GList *child = children; while (child) { @@ -5562,7 +5562,7 @@ draw_window_of_widget(GtkWidget *widget, GdkWindow *aWindow, cairo_t *cr) draw_window_of_widget(widget, window, cr); } child = g_list_next(child); - } + } g_list_free(children); } @@ -5846,7 +5846,7 @@ plugin_window_filter_func(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) #else plugin_window = gdk_x11_window_lookup_for_display( gdk_x11_lookup_xdisplay(xevent->xcreatewindow.display), xeventWindow); -#endif +#endif if (plugin_window) { GtkWidget *widget = get_gtk_widget_for_gdk_window(plugin_window); @@ -5857,7 +5857,7 @@ plugin_window_filter_func(GdkXEvent *gdk_xevent, GdkEvent *event, gpointer data) nswindow->SetPluginType(nsWindow::PluginType_NONXEMBED); break; } - else + else #endif if(GTK_IS_SOCKET(widget)) { if (!g_object_get_data(G_OBJECT(widget), "enable-xt-focus")) { diff --git a/widget/gtk/nsWindow.h b/widget/gtk/nsWindow.h index 71e2577ab526..4188e9d462bf 100644 --- a/widget/gtk/nsWindow.h +++ b/widget/gtk/nsWindow.h @@ -79,12 +79,12 @@ public: static void ReleaseGlobals(); NS_DECL_ISUPPORTS_INHERITED - + void CommonCreate(nsIWidget *aParent, bool aListenForResizes); - + virtual nsresult DispatchEvent(mozilla::WidgetGUIEvent* aEvent, nsEventStatus& aStatus) override; - + // called when we are destroyed virtual void OnDestroy(void) override; @@ -100,7 +100,7 @@ public: NS_IMETHOD Destroy(void) override; virtual nsIWidget *GetParent() override; virtual float GetDPI() override; - virtual double GetDefaultScaleInternal() override; + virtual double GetDefaultScaleInternal() override; // Under Gtk, we manage windows using device pixels so no scaling is needed: mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale() final { @@ -529,7 +529,7 @@ private: // full translucency at this time; each pixel is either fully opaque // or fully transparent. gchar* mTransparencyBitmap; - + // all of our DND stuff void InitDragEvent(mozilla::WidgetDragEvent& aEvent); diff --git a/widget/nsBaseWidget.h b/widget/nsBaseWidget.h index 8efbe0e25dfc..9ccaad682383 100644 --- a/widget/nsBaseWidget.h +++ b/widget/nsBaseWidget.h @@ -98,9 +98,9 @@ public: /** * Common widget implementation used as base class for native - * or crossplatform implementations of Widgets. - * All cross-platform behavior that all widgets need to implement - * should be placed in this class. + * or crossplatform implementations of Widgets. + * All cross-platform behavior that all widgets need to implement + * should be placed in this class. * (Note: widget implementations are not required to use this * class, but it gives them a head start.) */ @@ -326,7 +326,7 @@ public: // return true if this is a popup widget with a native titlebar bool IsPopupWithTitleBar() const { - return (mWindowType == eWindowType_popup && + return (mWindowType == eWindowType_popup && mBorderStyle != eBorderStyle_default && mBorderStyle & eBorderStyle_title); } @@ -590,7 +590,7 @@ protected: /** * Starts the OMTC compositor destruction sequence. * - * When this function returns, the compositor should not be + * When this function returns, the compositor should not be * able to access the opengl context anymore. * It is safe to call it several times if platform implementations * require the compositor to be destroyed before ~nsBaseWidget is diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h index 65b5eb970c46..60b31cf85202 100644 --- a/widget/nsIWidget.h +++ b/widget/nsIWidget.h @@ -170,13 +170,13 @@ enum nsTransparencyMode { */ enum nsCursor { ///(normal cursor, usually rendered as an arrow) - eCursor_standard, + eCursor_standard, ///(system is busy, usually rendered as a hourglass or watch) - eCursor_wait, + eCursor_wait, ///(Selecting something, usually rendered as an IBeam) - eCursor_select, + eCursor_select, ///(can hyper-link, usually rendered as a human hand) - eCursor_hyperlink, + eCursor_hyperlink, ///(north/south/west/east edge sizing) eCursor_n_resize, eCursor_s_resize, @@ -212,7 +212,7 @@ enum nsCursor { ///(normal cursor, usually rendered as an arrow) eCursor_none, // This one better be the last one in this list. eCursorCount - }; + }; enum nsTopLevelWidgetZPlacement { // for PlaceBehind() eZPlacementBottom = 0, // bottom of the window stack @@ -389,9 +389,9 @@ class nsIWidget : public nsISupports ClearNativeTouchSequence(nullptr); } - + /** - * Create and initialize a widget. + * Create and initialize a widget. * * All the arguments can be null in which case a top level window * with size 0 is created. The event callback function has to be @@ -400,10 +400,10 @@ class nsIWidget : public nsISupports * hook called synchronously. The return value determines whether * the event goes to the default window procedure or it is hidden * to the os. The assumption is that if the event handler returns - * false the widget does not see the event. The widget should not - * automatically clear the window to the background color. The - * calling code must handle paint messages and clear the background - * itself. + * false the widget does not see the event. The widget should not + * automatically clear the window to the background color. The + * calling code must handle paint messages and clear the background + * itself. * * In practice at least one of aParent and aNativeParent will be null. If * both are null the widget isn't parented (e.g. context menus or @@ -466,7 +466,7 @@ class nsIWidget : public nsISupports bool aForceUseIWidgetParent = false) = 0; /** - * Attach to a top level widget. + * Attach to a top level widget. * * In cases where a top level chrome widget is being used as a content * container, attach a secondary listener and update the device @@ -500,7 +500,7 @@ class nsIWidget : public nsISupports //@} /** - * Close and destroy the internal native window. + * Close and destroy the internal native window. * This method does not delete the widget. */ @@ -518,12 +518,12 @@ class nsIWidget : public nsISupports * * Change the widget's parent. Null parents are allowed. * - * @param aNewParent new parent + * @param aNewParent new parent */ NS_IMETHOD SetParent(nsIWidget* aNewParent) = 0; /** - * Return the parent Widget of this Widget or nullptr if this is a + * Return the parent Widget of this Widget or nullptr if this is a * top level window * * @return the parent widget or nullptr if it does not have a parent @@ -590,7 +590,7 @@ class nsIWidget : public nsISupports nsIWidget* GetFirstChild() const { return mFirstChild; } - + /** * Return the last child of this widget. Will return null if * there are no children. @@ -605,14 +605,14 @@ class nsIWidget : public nsISupports nsIWidget* GetNextSibling() const { return mNextSibling; } - + /** * Set the next sibling of this widget */ void SetNextSibling(nsIWidget* aSibling) { mNextSibling = aSibling; } - + /** * Return the previous sibling of this widget */ @@ -800,7 +800,7 @@ class nsIWidget : public nsISupports virtual void SetZIndex(int32_t aZIndex) = 0; /** - * Gets the widget's z-index. + * Gets the widget's z-index. */ int32_t GetZIndex() { @@ -982,7 +982,7 @@ class nsIWidget : public nsISupports NS_IMETHOD SetCursor(imgIContainer* aCursor, uint32_t aHotspotX, uint32_t aHotspotY) = 0; - /** + /** * Get the window type of this widget. */ nsWindowType WindowType() { return mWindowType; } @@ -1157,7 +1157,7 @@ class nsIWidget : public nsISupports */ virtual void SetUseBrightTitlebarForeground(bool aBrightForeground) {} - /** + /** * Hide window chrome (borders, buttons) for this widget. * */ @@ -1378,10 +1378,10 @@ class nsIWidget : public nsISupports * */ NS_IMETHOD EnableDragDrop(bool aEnable) = 0; - + /** * Enables/Disables system mouse capture. - * @param aCapture true enables mouse capture, false disables mouse capture + * @param aCapture true enables mouse capture, false disables mouse capture * */ NS_IMETHOD CaptureMouse(bool aCapture) = 0; @@ -1395,7 +1395,7 @@ class nsIWidget : public nsISupports * Enables/Disables system capture of any and all events that would cause a * popup to be rolled up. aListener should be set to a non-null value for * any popups that are not managed by the popup manager. - * @param aDoCapture true enables capture, false disables capture + * @param aDoCapture true enables capture, false disables capture * */ NS_IMETHOD CaptureRollupEvents(nsIRollupListener* aListener, bool aDoCapture) = 0; @@ -1407,8 +1407,8 @@ class nsIWidget : public nsISupports * the Mac. The notification should be suppressed if the window is already * in the foreground and should be dismissed when the user brings this window * to the foreground. - * @param aCycleCount Maximum number of times to animate the window per system - * conventions. If set to -1, cycles indefinitely until + * @param aCycleCount Maximum number of times to animate the window per system + * conventions. If set to -1, cycles indefinitely until * window is brought into the foreground. */ NS_IMETHOD GetAttention(int32_t aCycleCount) = 0; @@ -1427,9 +1427,9 @@ class nsIWidget : public nsISupports * Ignored on any platform that does not support it. Ignored by widgets that * do not represent windows. * - * @param aColor The color to set the title bar background to. Alpha values - * other than fully transparent (0) are respected if possible - * on the platform. An alpha of 0 will cause the window to + * @param aColor The color to set the title bar background to. Alpha values + * other than fully transparent (0) are respected if possible + * on the platform. An alpha of 0 will cause the window to * draw with the default style for the platform. * * @param aActive Whether the color should be applied to active or inactive @@ -1705,7 +1705,7 @@ public: * This is used for native menu system testing. * * Updates a native menu at the position specified by the index string. - * The index string is a string of positive integers separated by the "|" + * The index string is a string of positive integers separated by the "|" * (pipe) character. * * Example: 1|0|4 @@ -1752,7 +1752,7 @@ public: /* * Tell the plugin has focus. It is unnecessary to use IPC */ - bool PluginHasFocus() + bool PluginHasFocus() { return GetInputContext().mIMEState.mEnabled == IMEState::PLUGIN; } diff --git a/widget/nsPrintOptionsImpl.cpp b/widget/nsPrintOptionsImpl.cpp index 6127bb1b2c00..ca6d1f5f4501 100644 --- a/widget/nsPrintOptionsImpl.cpp +++ b/widget/nsPrintOptionsImpl.cpp @@ -435,7 +435,7 @@ GetPrefName((_a2), aPrefName), (_a3)); * or read the prefs in using the printer name to qualify. * It is either "print.attr_name" or "print.printer_HPLasr5.attr_name" */ -nsresult +nsresult nsPrintOptions::ReadPrefs(nsIPrintSettings* aPS, const nsAString& aPrinterName, uint32_t aFlags) { @@ -731,7 +731,7 @@ nsPrintOptions::ReadPrefs(nsIPrintSettings* aPS, const nsAString& aPrinterName, * See documentation in nsPrintOptionsImpl.h * @update 1/12/01 rods */ -nsresult +nsresult nsPrintOptions::WritePrefs(nsIPrintSettings *aPS, const nsAString& aPrinterName, uint32_t aFlags) { @@ -796,7 +796,7 @@ nsPrintOptions::WritePrefs(nsIPrintSettings *aPS, const nsAString& aPrinterName, int16_t sizeUnit; double width, height; char16_t *name; - + if ( NS_SUCCEEDED(aPS->GetPaperSizeUnit(&sizeUnit)) && NS_SUCCEEDED(aPS->GetPaperWidth(&width)) && @@ -1103,7 +1103,7 @@ nsPrintOptions::InitPrintSettingsFromPrinter(const char16_t *aPrinterName, /** --------------------------------------------------- * Helper function - Returns either the name or sets the length to zero */ -static nsresult +static nsresult GetAdjustedPrinterName(nsIPrintSettings* aPS, bool aUsePNP, nsAString& aPrinterName) { @@ -1113,7 +1113,7 @@ GetAdjustedPrinterName(nsIPrintSettings* aPS, bool aUsePNP, if (!aUsePNP) return NS_OK; - // Get the Printer Name from the PrintSettings + // Get the Printer Name from the PrintSettings // to use as a prefix for Pref Names char16_t* prtName = nullptr; @@ -1141,7 +1141,7 @@ GetAdjustedPrinterName(nsIPrintSettings* aPS, bool aUsePNP, } #endif -NS_IMETHODIMP +NS_IMETHODIMP nsPrintOptions::InitPrintSettingsFromPrefs(nsIPrintSettings* aPS, bool aUsePNP, uint32_t aFlags) { diff --git a/widget/nsTransferable.cpp b/widget/nsTransferable.cpp index 543ff912afbe..c5049f399c20 100644 --- a/widget/nsTransferable.cpp +++ b/widget/nsTransferable.cpp @@ -12,7 +12,7 @@ Notes to self: */ - + #include "nsTransferable.h" #include "nsString.h" #include "nsReadableUtils.h" @@ -28,7 +28,7 @@ Notes to self: #include "nsXPIDLString.h" #include "nsDirectoryServiceDefs.h" #include "nsDirectoryService.h" -#include "nsCRT.h" +#include "nsCRT.h" #include "nsNetUtil.h" #include "nsIDOMNode.h" #include "nsIOutputStream.h" @@ -52,9 +52,9 @@ size_t GetDataForFlavor (const nsTArray& aArray, } //------------------------------------------------------------------------- -DataStruct::~DataStruct() -{ - if (mCacheFileName) free(mCacheFileName); +DataStruct::~DataStruct() +{ + if (mCacheFileName) free(mCacheFileName); } //------------------------------------------------------------------------- @@ -68,11 +68,11 @@ DataStruct::SetData ( nsISupports* aData, uint32_t aDataLen, bool aIsPrivateData if ( NS_SUCCEEDED(WriteCache(aData, aDataLen)) ) return; else - NS_WARNING("Oh no, couldn't write data to the cache file"); - } + NS_WARNING("Oh no, couldn't write data to the cache file"); + } mData = aData; - mDataLen = aDataLen; + mDataLen = aDataLen; } @@ -94,10 +94,10 @@ DataStruct::GetData ( nsISupports** aData, uint32_t *aDataLen ) return; } } - + *aData = mData; if ( mData ) - NS_ADDREF(*aData); + NS_ADDREF(*aData); *aDataLen = mDataLen; } @@ -108,7 +108,7 @@ DataStruct::GetFileSpec(const char* aFileName) { nsCOMPtr cacheFile; NS_GetSpecialDirectory(NS_OS_TEMP_DIR, getter_AddRefs(cacheFile)); - + if (!cacheFile) return nullptr; @@ -121,7 +121,7 @@ DataStruct::GetFileSpec(const char* aFileName) } else { cacheFile->AppendNative(nsDependentCString(aFileName)); } - + return cacheFile.forget(); } @@ -187,12 +187,12 @@ DataStruct::ReadCache(nsISupports** aData, uint32_t* aDataLen) auto data = mozilla::MakeUnique(size); if ( !data ) return NS_ERROR_OUT_OF_MEMORY; - + // now read it all in nsCOMPtr inStr; NS_NewLocalFileInputStream( getter_AddRefs(inStr), cacheFile); - + if (!cacheFile) return NS_ERROR_FAILURE; nsresult rv = inStr->Read(data.get(), fileSize, aDataLen); @@ -254,7 +254,7 @@ nsTransferable::Init(nsILoadContext* aContext) // // GetTransferDataFlavors // -// Returns a copy of the internal list of flavors. This does NOT take into +// Returns a copy of the internal list of flavors. This does NOT take into // account any converter that may be registered. This list consists of // nsISupportsCString objects so that the flavor list can be accessed from JS. // @@ -296,7 +296,7 @@ nsTransferable::GetTransferData(const char *aFlavor, nsISupports **aData, uint32 nsresult rv = NS_OK; nsCOMPtr savedData; - + // first look and see if the data is present in one of the intrinsic flavors for (size_t i = 0; i < mDataArray.Length(); ++i) { DataStruct& data = mDataArray.ElementAt(i); @@ -368,7 +368,7 @@ nsTransferable::GetTransferData(const char *aFlavor, nsISupports **aData, uint32 // // Returns the data of the first flavor found. Caller is responsible for deleting the // flavor string. -// +// NS_IMETHODIMP nsTransferable::GetAnyTransferData(char **aFlavor, nsISupports **aData, uint32_t *aDataLen) { @@ -393,7 +393,7 @@ nsTransferable::GetAnyTransferData(char **aFlavor, nsISupports **aData, uint32_t // SetTransferData // // -// +// NS_IMETHODIMP nsTransferable::SetTransferData(const char *aFlavor, nsISupports *aData, uint32_t aDataLen) { @@ -431,7 +431,7 @@ nsTransferable::SetTransferData(const char *aFlavor, nsISupports *aData, uint32_ nsresult result = NS_ERROR_FAILURE; if ( NS_SUCCEEDED(AddDataFlavor(aFlavor)) ) result = SetTransferData (aFlavor, aData, aDataLen); - + return result; } @@ -440,7 +440,7 @@ nsTransferable::SetTransferData(const char *aFlavor, nsISupports *aData, uint32_ // AddDataFlavor // // Adds a data flavor to our list with no data. Error if it already exists. -// +// NS_IMETHODIMP nsTransferable::AddDataFlavor(const char *aDataFlavor) { @@ -477,7 +477,7 @@ nsTransferable::RemoveDataFlavor(const char *aDataFlavor) /** - * + * * */ NS_IMETHODIMP @@ -492,7 +492,7 @@ nsTransferable::IsLargeDataSet(bool *_retval) /** - * + * * */ NS_IMETHODIMP nsTransferable::SetConverter(nsIFormatConverter * aConverter) @@ -505,7 +505,7 @@ NS_IMETHODIMP nsTransferable::SetConverter(nsIFormatConverter * aConverter) /** - * + * * */ NS_IMETHODIMP nsTransferable::GetConverter(nsIFormatConverter * *aConverter) @@ -531,7 +531,7 @@ nsTransferable::FlavorsTransferableCanImport(nsISupportsArray **_retval) MOZ_ASSERT(mInitialized); NS_ENSURE_ARG_POINTER(_retval); - + // Get the flavor list, and on to the end of it, append the list of flavors we // can also get to through a converter. This is so that we can just walk the list // in one go, looking for the desired flavor. @@ -561,7 +561,7 @@ nsTransferable::FlavorsTransferableCanImport(nsISupportsArray **_retval) } } // if a converter exists - return NS_OK; + return NS_OK; } // FlavorsTransferableCanImport @@ -577,7 +577,7 @@ nsTransferable::FlavorsTransferableCanExport(nsISupportsArray **_retval) MOZ_ASSERT(mInitialized); NS_ENSURE_ARG_POINTER(_retval); - + // Get the flavor list, and on to the end of it, append the list of flavors we // can also get to through a converter. This is so that we can just walk the list // in one go, looking for the desired flavor. diff --git a/widget/windows/AudioSession.cpp b/widget/windows/AudioSession.cpp index 6b09f1d29792..5a5db2f02fc5 100644 --- a/widget/windows/AudioSession.cpp +++ b/widget/windows/AudioSession.cpp @@ -26,7 +26,7 @@ namespace mozilla { namespace widget { -/* +/* * To take advantage of what Vista+ have to offer with respect to audio, * we need to maintain an audio session. This class wraps IAudioSessionControl * and implements IAudioSessionEvents (for callbacks from Windows) @@ -201,7 +201,7 @@ AudioSession::Start() MOZ_ASSERT(XRE_IsParentProcess(), "Should only get here in a chrome process!"); - nsCOMPtr bundleService = + nsCOMPtr bundleService = do_GetService(NS_STRINGBUNDLE_CONTRACTID); NS_ENSURE_TRUE(bundleService, NS_ERROR_FAILURE); nsCOMPtr bundle; diff --git a/widget/windows/JumpListBuilder.cpp b/widget/windows/JumpListBuilder.cpp index 2f488247ae01..566c41d4ab65 100644 --- a/widget/windows/JumpListBuilder.cpp +++ b/widget/windows/JumpListBuilder.cpp @@ -48,7 +48,7 @@ JumpListBuilder::JumpListBuilder() : mHasCommit(false) { ::CoInitialize(nullptr); - + CoCreateInstance(CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER, IID_ICustomDestinationList, getter_AddRefs(mJumpListMgr)); @@ -148,12 +148,12 @@ NS_IMETHODIMP JumpListBuilder::InitListBuild(nsIMutableArray *removedItems, bool return NS_OK; } -// Ensures that we don't have old ICO files that aren't in our jump lists +// Ensures that we don't have old ICO files that aren't in our jump lists // anymore left over in the cache. -nsresult JumpListBuilder::RemoveIconCacheForItems(nsIMutableArray *items) +nsresult JumpListBuilder::RemoveIconCacheForItems(nsIMutableArray *items) { NS_ENSURE_ARG_POINTER(items); - + nsresult rv; uint32_t length; items->GetLength(&length); @@ -176,14 +176,14 @@ nsresult JumpListBuilder::RemoveIconCacheForItems(nsIMutableArray *items) nsCOMPtr uri; rv = shortcut->GetFaviconPageUri(getter_AddRefs(uri)); if (NS_SUCCEEDED(rv) && uri) { - + // The local file path is stored inside the nsIURI // Get the nsIURI spec which stores the local path for the icon to remove nsAutoCString spec; nsresult rv = uri->GetSpec(spec); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr event + nsCOMPtr event = new mozilla::widget::AsyncDeleteIconFromDisk(NS_ConvertUTF8toUTF16(spec)); mIOThread->Dispatch(event, NS_DISPATCH_NORMAL); @@ -202,11 +202,11 @@ nsresult JumpListBuilder::RemoveIconCacheForItems(nsIMutableArray *items) } // Ensures that we have no old ICO files left in the jump list cache -nsresult JumpListBuilder::RemoveIconCacheForAllItems() +nsresult JumpListBuilder::RemoveIconCacheForAllItems() { // Construct the path of our jump list cache nsCOMPtr jumpListCacheDir; - nsresult rv = NS_GetSpecialDirectory("ProfLDS", + nsresult rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(jumpListCacheDir)); NS_ENSURE_SUCCESS(rv, rv); rv = jumpListCacheDir->AppendNative(nsDependentCString( @@ -215,7 +215,7 @@ nsresult JumpListBuilder::RemoveIconCacheForAllItems() nsCOMPtr entries; rv = jumpListCacheDir->GetDirectoryEntries(getter_AddRefs(entries)); NS_ENSURE_SUCCESS(rv, rv); - + // Loop through each directory entry and remove all ICO files found do { bool hasMore = false; @@ -274,7 +274,7 @@ NS_IMETHODIMP JumpListBuilder::AddListToBuild(int16_t aCatType, nsIArray *items, nsCOMPtr item = do_QueryElementAt(items, i); if (!item) continue; - // Check for separators + // Check for separators if (IsSeparator(item)) { RefPtr link; rv = JumpListSeparator::GetSeparator(link); @@ -454,7 +454,7 @@ bool JumpListBuilder::IsSeparator(nsCOMPtr& item) item->GetType(&type); if (NS_FAILED(item->GetType(&type))) return false; - + if (type == nsIJumpListItem::JUMPLIST_ITEM_SEPARATOR) return true; return false; @@ -479,7 +479,7 @@ nsresult JumpListBuilder::TransferIObjectArrayToIMutableArray(IObjectArray *objA IShellItem * pItem = nullptr; if (SUCCEEDED(objArray->GetAt(idx, IID_IShellLinkW, (LPVOID*)&pLink))) { - nsCOMPtr shortcut = + nsCOMPtr shortcut = do_CreateInstance(kJumpListShortcutCID, &rv); if (NS_FAILED(rv)) return NS_ERROR_UNEXPECTED; @@ -487,7 +487,7 @@ nsresult JumpListBuilder::TransferIObjectArrayToIMutableArray(IObjectArray *objA item = do_QueryInterface(shortcut); } else if (SUCCEEDED(objArray->GetAt(idx, IID_IShellItem, (LPVOID*)&pItem))) { - nsCOMPtr link = + nsCOMPtr link = do_CreateInstance(kJumpListLinkCID, &rv); if (NS_FAILED(rv)) return NS_ERROR_UNEXPECTED; @@ -523,8 +523,8 @@ NS_IMETHODIMP JumpListBuilder::Observe(nsISupports* aSubject, nsDependentString(aData).EqualsASCII(kPrefTaskbarEnabled)) { bool enabled = Preferences::GetBool(kPrefTaskbarEnabled, true); if (!enabled) { - - nsCOMPtr event = + + nsCOMPtr event = new mozilla::widget::AsyncDeleteAllFaviconsFromDisk(); mIOThread->Dispatch(event, NS_DISPATCH_NORMAL); } diff --git a/widget/windows/JumpListItem.h b/widget/windows/JumpListItem.h index 77eaed991229..1e3152ae09b6 100644 --- a/widget/windows/JumpListItem.h +++ b/widget/windows/JumpListItem.h @@ -105,11 +105,11 @@ public: NS_IMETHOD Equals(nsIJumpListItem *item, bool *_retval) override; NS_DECL_NSIJUMPLISTSHORTCUT - static nsresult GetShellLink(nsCOMPtr& item, - RefPtr& aShellLink, + static nsresult GetShellLink(nsCOMPtr& item, + RefPtr& aShellLink, nsCOMPtr &aIOThread); static nsresult GetJumpListShortcut(IShellLinkW *pLink, nsCOMPtr& aShortcut); - static nsresult GetOutputIconPath(nsCOMPtr aFaviconPageURI, + static nsresult GetOutputIconPath(nsCOMPtr aFaviconPageURI, nsCOMPtr &aICOFile); protected: @@ -118,10 +118,10 @@ protected: nsCOMPtr mHandlerApp; bool ExecutableExists(nsCOMPtr& handlerApp); - static nsresult ObtainCachedIconFile(nsCOMPtr aFaviconPageURI, + static nsresult ObtainCachedIconFile(nsCOMPtr aFaviconPageURI, nsString &aICOFilePath, nsCOMPtr &aIOThread); - static nsresult CacheIconFileFromFaviconURIAsync(nsCOMPtr aFaviconPageURI, + static nsresult CacheIconFileFromFaviconURIAsync(nsCOMPtr aFaviconPageURI, nsCOMPtr aICOFile, nsCOMPtr &aIOThread); }; diff --git a/widget/windows/TSFTextStore.h b/widget/windows/TSFTextStore.h index 6f40748f6317..c64663925032 100644 --- a/widget/windows/TSFTextStore.h +++ b/widget/windows/TSFTextStore.h @@ -675,7 +675,7 @@ protected: // When On*Composition() is called without document lock, we need to flush // the recorded actions at quitting the method. - // AutoPendingActionAndContentFlusher class is usedful for it. + // AutoPendingActionAndContentFlusher class is usedful for it. class MOZ_STACK_CLASS AutoPendingActionAndContentFlusher final { public: @@ -866,7 +866,7 @@ protected: DWORD Cookie() const { return mCookie; } bool OnMouseButtonEvent(ULONG aEdge, ULONG aQuadrant, DWORD aButtonStatus); LONG RangeStart() const { return mStart; } - + private: RefPtr mSink; LONG mStart; diff --git a/widget/windows/TaskbarPreviewButton.h b/widget/windows/TaskbarPreviewButton.h index 585bf548aca1..2b4342d1574c 100644 --- a/widget/windows/TaskbarPreviewButton.h +++ b/widget/windows/TaskbarPreviewButton.h @@ -25,7 +25,7 @@ class TaskbarPreviewButton : public nsITaskbarPreviewButton, public nsSupportsWe { virtual ~TaskbarPreviewButton(); -public: +public: TaskbarPreviewButton(TaskbarWindowPreview* preview, uint32_t index); NS_DECL_ISUPPORTS diff --git a/widget/windows/WidgetTraceEvent.cpp b/widget/windows/WidgetTraceEvent.cpp index 8c6b6eb2ce47..2be93568163b 100644 --- a/widget/windows/WidgetTraceEvent.cpp +++ b/widget/windows/WidgetTraceEvent.cpp @@ -60,7 +60,7 @@ public: } nsCOMPtr baseWindow(do_QueryInterface(docShell)); - + if (!baseWindow) return NS_ERROR_FAILURE; diff --git a/widget/windows/WinTaskbar.cpp b/widget/windows/WinTaskbar.cpp index 72f309c7c876..698b7ec0e5c9 100644 --- a/widget/windows/WinTaskbar.cpp +++ b/widget/windows/WinTaskbar.cpp @@ -57,7 +57,7 @@ HWND GetHWNDFromDOMWindow(mozIDOMWindow *dw) { nsCOMPtr widget; - if (!dw) + if (!dw) return nullptr; nsCOMPtr window = nsPIDOMWindowInner::From(dw); @@ -125,7 +125,7 @@ class DefaultController final : public nsITaskbarPreviewController ~DefaultController() {} HWND mWnd; public: - DefaultController(HWND hWnd) + DefaultController(HWND hWnd) : mWnd(hWnd) { } @@ -241,7 +241,7 @@ WinTaskbar::Initialize() { return true; } -WinTaskbar::WinTaskbar() +WinTaskbar::WinTaskbar() : mTaskbar(nullptr) { } @@ -456,7 +456,7 @@ WinTaskbar::CreateJumpListBuilder(nsIJumpListBuilder * *aJumpListBuilder) { if (JumpListBuilder::sBuildingList) return NS_ERROR_ALREADY_INITIALIZED; - nsCOMPtr builder = + nsCOMPtr builder = do_CreateInstance(kJumpListBuilderCID, &rv); if (NS_FAILED(rv)) return NS_ERROR_UNEXPECTED; @@ -479,7 +479,7 @@ WinTaskbar::PrepareFullScreen(mozIDOMWindow *aWindow, bool aFullScreen) { HWND toplevelHWND = ::GetAncestor(GetHWNDFromDOMWindow(aWindow), GA_ROOT); if (!toplevelHWND) return NS_ERROR_INVALID_ARG; - + return PrepareFullScreenHWND(toplevelHWND, aFullScreen); } @@ -490,7 +490,7 @@ WinTaskbar::PrepareFullScreenHWND(void *aHWND, bool aFullScreen) { NS_ENSURE_ARG_POINTER(aHWND); - if (!::IsWindow((HWND)aHWND)) + if (!::IsWindow((HWND)aHWND)) return NS_ERROR_INVALID_ARG; HRESULT hr = mTaskbar->MarkFullscreenWindow((HWND)aHWND, aFullScreen); diff --git a/widget/windows/WinUtils.h b/widget/windows/WinUtils.h index 1a255510547b..163fc58a4c42 100644 --- a/widget/windows/WinUtils.h +++ b/widget/windows/WinUtils.h @@ -292,8 +292,8 @@ public: * | | | window like dialog | | * +-----------------+-------+-----------------------+-----------------------+ */ - static HWND GetTopLevelHWND(HWND aWnd, - bool aStopIfNotChild = false, + static HWND GetTopLevelHWND(HWND aWnd, + bool aStopIfNotChild = false, bool aStopIfNotPopup = true); /** @@ -534,9 +534,9 @@ class AsyncFaviconDataReady final : public nsIFaviconDataCallback public: NS_DECL_ISUPPORTS NS_DECL_NSIFAVICONDATACALLBACK - - AsyncFaviconDataReady(nsIURI *aNewURI, - nsCOMPtr &aIOThread, + + AsyncFaviconDataReady(nsIURI *aNewURI, + nsCOMPtr &aIOThread, const bool aURLShortcut); nsresult OnFaviconDataNotAvailable(void); private: @@ -614,7 +614,7 @@ public: nsCOMPtr &aIOThread, bool aURLShortcut); - static nsresult HashURI(nsCOMPtr &aCryptoHash, + static nsresult HashURI(nsCOMPtr &aCryptoHash, nsIURI *aUri, nsACString& aUriHash); @@ -622,7 +622,7 @@ public: nsCOMPtr &aICOFile, bool aURLShortcut); - static nsresult + static nsresult CacheIconFileFromFaviconURIAsync(nsCOMPtr aFaviconPageURI, nsCOMPtr aICOFile, nsCOMPtr &aIOThread, diff --git a/widget/windows/nsDataObjCollection.h b/widget/windows/nsDataObjCollection.h index 429afab1e371..06bd36a7d06b 100644 --- a/widget/windows/nsDataObjCollection.h +++ b/widget/windows/nsDataObjCollection.h @@ -22,7 +22,7 @@ EXTERN_C const IID IID_IDataObjCollection; // this way we can filter out collection objects that aren't ours class nsIDataObjCollection : public IUnknown { public: - + }; /* @@ -30,7 +30,7 @@ public: * can be adapted by an object derived from CfDragDrop. The CfDragDrop is * associated with instances via SetDragDrop(). */ - + class nsDataObjCollection final : public nsIDataObjCollection, public nsDataObj { public: diff --git a/widget/windows/nsDeviceContextSpecWin.cpp b/widget/windows/nsDeviceContextSpecWin.cpp index 8bcb4c191de0..8b725fa5d319 100644 --- a/widget/windows/nsDeviceContextSpecWin.cpp +++ b/widget/windows/nsDeviceContextSpecWin.cpp @@ -198,7 +198,7 @@ NS_IMETHODIMP nsDeviceContextSpecWin::Init(nsIWidget* aWidget, NS_ASSERTION(printerName, "We have to have a printer name"); if (!printerName || !*printerName) return rv; - + return GetDataFromPrinter(printerName, mPrintSettings); } @@ -318,13 +318,13 @@ void nsDeviceContextSpecWin::SetDevMode(LPDEVMODEW aDevMode) } //------------------------------------------------------------------ -void +void nsDeviceContextSpecWin::GetDevMode(LPDEVMODEW &aDevMode) { aDevMode = mDevMode; } -#define DISPLAY_LAST_ERROR +#define DISPLAY_LAST_ERROR //---------------------------------------------------------------------------------- // Setup the object's data member with the selected printer's data @@ -344,7 +344,7 @@ nsDeviceContextSpecWin::GetDataFromPrinter(char16ptr_t aName, nsIPrintSettings* HANDLE hPrinter = nullptr; wchar_t *name = (wchar_t*)aName; // Windows APIs use non-const name argument - + BOOL status = ::OpenPrinterW(name, &hPrinter, nullptr); if (status) { @@ -426,7 +426,7 @@ NS_IMPL_ISUPPORTS(nsPrinterEnumeratorWin, nsIPrinterEnumerator) //---------------------------------------------------------------------------------- // Return the Default Printer name -NS_IMETHODIMP +NS_IMETHODIMP nsPrinterEnumeratorWin::GetDefaultPrinterName(char16_t * *aDefaultPrinterName) { NS_ENSURE_ARG_POINTER(aDefaultPrinterName); @@ -436,7 +436,7 @@ nsPrinterEnumeratorWin::GetDefaultPrinterName(char16_t * *aDefaultPrinterName) return NS_OK; } -NS_IMETHODIMP +NS_IMETHODIMP nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const char16_t *aPrinterName, nsIPrintSettings *aPrintSettings) { NS_ENSURE_ARG_POINTER(aPrinterName); @@ -498,7 +498,7 @@ nsPrinterEnumeratorWin::InitPrintSettingsFromPrinter(const char16_t *aPrinterNam //---------------------------------------------------------------------------------- // Enumerate all the Printers from the global array and pass their // names back (usually to script) -NS_IMETHODIMP +NS_IMETHODIMP nsPrinterEnumeratorWin::GetPrinterNameList(nsIStringEnumerator **aPrinterNameList) { NS_ENSURE_ARG_POINTER(aPrinterNameList); @@ -530,7 +530,7 @@ nsPrinterEnumeratorWin::GetPrinterNameList(nsIStringEnumerator **aPrinterNameLis //---------------------------------------------------------------------------------- // THe array hold the name and port for each printer -void +void GlobalPrinters::ReallocatePrinters() { if (PrintersAreAllocated()) { @@ -541,7 +541,7 @@ GlobalPrinters::ReallocatePrinters() } //---------------------------------------------------------------------------------- -void +void GlobalPrinters::FreeGlobalPrinters() { if (mPrinters != nullptr) { @@ -554,14 +554,14 @@ GlobalPrinters::FreeGlobalPrinters() } //---------------------------------------------------------------------------------- -nsresult +nsresult GlobalPrinters::EnumerateNativePrinters() { nsresult rv = NS_ERROR_GFX_PRINTER_NO_PRINTER_AVAILABLE; PR_PL(("-----------------------\n")); PR_PL(("EnumerateNativePrinters\n")); - WCHAR szDefaultPrinterName[1024]; + WCHAR szDefaultPrinterName[1024]; DWORD status = GetProfileStringW(L"devices", 0, L",", szDefaultPrinterName, ArrayLength(szDefaultPrinterName)); @@ -588,18 +588,18 @@ GlobalPrinters::EnumerateNativePrinters() //------------------------------------------------------------------ // Uses the GetProfileString to get the default printer from the registry -void +void GlobalPrinters::GetDefaultPrinterName(nsString& aDefaultPrinterName) { aDefaultPrinterName.Truncate(); - WCHAR szDefaultPrinterName[1024]; + WCHAR szDefaultPrinterName[1024]; DWORD status = GetProfileStringW(L"windows", L"device", 0, szDefaultPrinterName, ArrayLength(szDefaultPrinterName)); if (status > 0) { WCHAR comma = ','; LPWSTR sPtr = szDefaultPrinterName; - while (*sPtr != comma && *sPtr != 0) + while (*sPtr != comma && *sPtr != 0) sPtr++; if (*sPtr == comma) { *sPtr = 0; @@ -615,7 +615,7 @@ GlobalPrinters::GetDefaultPrinterName(nsString& aDefaultPrinterName) //---------------------------------------------------------------------------------- // This goes and gets the list of available printers and puts // the default printer at the beginning of the list -nsresult +nsresult GlobalPrinters::EnumeratePrinterList() { // reallocate and get a new list each time it is asked for diff --git a/widget/windows/nsDragService.cpp b/widget/windows/nsDragService.cpp index 849dd3847353..d8ae717571f9 100644 --- a/widget/windows/nsDragService.cpp +++ b/widget/windows/nsDragService.cpp @@ -73,7 +73,7 @@ nsDragService::CreateDragImage(nsIDOMNode *aDOMNode, return false; memset(psdi, 0, sizeof(SHDRAGIMAGE)); - if (!aDOMNode) + if (!aDOMNode) return false; // Prepare the drag image @@ -137,7 +137,7 @@ nsDragService::CreateDragImage(nsIDOMNode *aDOMNode, HDC hdcSrc = CreateCompatibleDC(nullptr); void *lpBits = nullptr; if (hdcSrc) { - psdi->hbmpDragImage = + psdi->hbmpDragImage = ::CreateDIBSection(hdcSrc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, (void**)&lpBits, nullptr, 0); if (psdi->hbmpDragImage && lpBits) { @@ -297,7 +297,7 @@ nsDragService::StartInvokingDragSession(IDataObject * aDataObj, HRESULT res = ::DoDragDrop(aDataObj, nativeDragSrc, effects, &winDropRes); // In cases where the drop operation completed outside the application, update - // the source node's nsIDOMDataTransfer dropEffect value so it is up to date. + // the source node's nsIDOMDataTransfer dropEffect value so it is up to date. if (!mSentLocalDropEvent) { uint32_t dropResult; // Order is important, since multiple flags can be returned. @@ -309,9 +309,9 @@ nsDragService::StartInvokingDragSession(IDataObject * aDataObj, dropResult = DRAGDROP_ACTION_MOVE; else dropResult = DRAGDROP_ACTION_NONE; - + if (mDataTransfer) { - if (res == DRAGDROP_S_DROP) // Success + if (res == DRAGDROP_S_DROP) // Success mDataTransfer->SetDropEffectInt(dropResult); else mDataTransfer->SetDropEffectInt(DRAGDROP_ACTION_NONE); @@ -373,7 +373,7 @@ nsDragService::GetNumDropItems(uint32_t * aNumItems) } else { // If the count cannot be determined just return 0. - // This can happen if we have collection data of type + // This can happen if we have collection data of type // MULTI_MIME ("Mozilla/IDataObjectCollectionFormat") on the clipboard // from another process but we can't obtain an IID_IDataObjCollection // from this process. diff --git a/widget/windows/nsFilePicker.h b/widget/windows/nsFilePicker.h index a56add91d5b9..90d8c15bc1f7 100644 --- a/widget/windows/nsFilePicker.h +++ b/widget/windows/nsFilePicker.h @@ -58,12 +58,12 @@ class nsFilePicker : { virtual ~nsFilePicker(); public: - nsFilePicker(); + nsFilePicker(); NS_IMETHOD Init(mozIDOMWindowProxy *aParent, const nsAString& aTitle, int16_t aMode); - + NS_DECL_ISUPPORTS - + // IUnknown's QueryInterface STDMETHODIMP QueryInterface(REFIID refiid, void** ppvResult); @@ -73,8 +73,8 @@ public: NS_IMETHOD GetFile(nsIFile * *aFile); NS_IMETHOD GetFileURL(nsIURI * *aFileURL); NS_IMETHOD GetFiles(nsISimpleEnumerator **aFiles); - NS_IMETHOD Show(int16_t *aReturnVal); - NS_IMETHOD ShowW(int16_t *aReturnVal); + NS_IMETHOD Show(int16_t *aReturnVal); + NS_IMETHOD ShowW(int16_t *aReturnVal); NS_IMETHOD AppendFilter(const nsAString& aTitle, const nsAString& aFilter); // IFileDialogEvents @@ -131,7 +131,7 @@ protected: public: ComDlgFilterSpec() {} ~ComDlgFilterSpec() {} - + const uint32_t Length() { return mSpecList.Length(); } @@ -143,7 +143,7 @@ protected: const COMDLG_FILTERSPEC* get() { return mSpecList.Elements(); } - + void Append(const nsAString& aTitle, const nsAString& aFilter); private: AutoTArray mSpecList; diff --git a/widget/windows/nsWindow.h b/widget/windows/nsWindow.h index e55bfb5d7ab5..08f53aa13417 100644 --- a/widget/windows/nsWindow.h +++ b/widget/windows/nsWindow.h @@ -481,7 +481,7 @@ protected: static bool IsTopLevelMouseExit(HWND aWnd); virtual nsresult SetWindowClipRegion(const nsTArray& aRects, bool aIntersectWithExisting) override; - nsIntRegion GetRegionToPaint(bool aForceFullRepaint, + nsIntRegion GetRegionToPaint(bool aForceFullRepaint, PAINTSTRUCT ps, HDC aDC); static void ActivateOtherWindowHelper(HWND aWnd); void ClearCachedResources(); @@ -567,7 +567,7 @@ protected: // Indicates custom frames are enabled bool mCustomNonClient; - // Cached copy of L&F's resize border + // Cached copy of L&F's resize border int32_t mHorResizeMargin; int32_t mVertResizeMargin; // Height of the caption plus border diff --git a/widget/windows/nsWindowBase.cpp b/widget/windows/nsWindowBase.cpp index 9035ce9f4dcb..b76780a43a8e 100644 --- a/widget/windows/nsWindowBase.cpp +++ b/widget/windows/nsWindowBase.cpp @@ -87,7 +87,7 @@ nsWindowBase::InjectTouchPoint(uint32_t aId, LayoutDeviceIntPoint& aPoint, info.touchMask = TOUCH_MASK_CONTACTAREA|TOUCH_MASK_ORIENTATION|TOUCH_MASK_PRESSURE; info.pressure = aPressure; info.orientation = aOrientation; - + info.pointerInfo.pointerFlags = aFlags; info.pointerInfo.pointerType = PT_TOUCH; info.pointerInfo.pointerId = aId; @@ -98,7 +98,7 @@ nsWindowBase::InjectTouchPoint(uint32_t aId, LayoutDeviceIntPoint& aPoint, info.rcContact.bottom = info.pointerInfo.ptPixelLocation.y + 2; info.rcContact.left = info.pointerInfo.ptPixelLocation.x - 2; info.rcContact.right = info.pointerInfo.ptPixelLocation.x + 2; - + if (!sInjectTouchFuncPtr(1, &info)) { WinUtils::Log("InjectTouchInput failure. GetLastError=%d", GetLastError()); return false; From 9bf55886245b197dffcf031d7540bc21b2d66ee8 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 22 Jul 2016 10:56:13 +0200 Subject: [PATCH 007/135] Bug 1265386: Convert code in widget/ to |UniquePtr|, r=nfroyd This patch replaces all references to |nsAutoPtr| in widget/ by references to |UniquePtr|. |nsAutoPtr| is deprecated and will go away soon. MozReview-Commit-ID: 8xAS79wTkPC --- widget/android/nsAppShell.cpp | 1 - widget/cocoa/nsChildView.h | 3 +-- widget/cocoa/nsChildView.mm | 22 +++++++++++----------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/widget/android/nsAppShell.cpp b/widget/android/nsAppShell.cpp index 5ffc32f1631c..12fb4559b00f 100644 --- a/widget/android/nsAppShell.cpp +++ b/widget/android/nsAppShell.cpp @@ -74,7 +74,6 @@ using namespace mozilla; typedef mozilla::dom::GamepadPlatformService GamepadPlatformService; nsIGeolocationUpdate *gLocationCallback = nullptr; -nsAutoPtr gLastSizeChange; nsAppShell* nsAppShell::sAppShell; StaticAutoPtr nsAppShell::sAppShellLock; diff --git a/widget/cocoa/nsChildView.h b/widget/cocoa/nsChildView.h index 63afd44bf752..2e62f4251a33 100644 --- a/widget/cocoa/nsChildView.h +++ b/widget/cocoa/nsChildView.h @@ -13,7 +13,6 @@ #include "mozAccessibleProtocol.h" #endif -#include "nsAutoPtr.h" #include "nsISupports.h" #include "nsBaseWidget.h" #include "nsWeakPtr.h" @@ -627,7 +626,7 @@ protected: // Used in OMTC BasicLayers mode. Presents the BasicCompositor result // surface to the screen using an OpenGL context. - nsAutoPtr mGLPresenter; + mozilla::UniquePtr mGLPresenter; mozilla::UniquePtr mVibrancyManager; RefPtr mSwipeTracker; diff --git a/widget/cocoa/nsChildView.mm b/widget/cocoa/nsChildView.mm index b994d632643b..6e171da24a73 100644 --- a/widget/cocoa/nsChildView.mm +++ b/widget/cocoa/nsChildView.mm @@ -275,12 +275,12 @@ namespace { class GLPresenter : public GLManager { public: - static GLPresenter* CreateForWindow(nsIWidget* aWindow) + static mozilla::UniquePtr CreateForWindow(nsIWidget* aWindow) { // Contrary to CompositorOGL, we allow unaccelerated OpenGL contexts to be // used. BasicCompositor only requires very basic GL functionality. RefPtr context = gl::GLContextProvider::CreateForWindow(aWindow, false); - return context ? new GLPresenter(context) : nullptr; + return context ? MakeUnique(context) : nullptr; } explicit GLPresenter(GLContext* aContext); @@ -291,7 +291,7 @@ public: { MOZ_ASSERT(aTarget == LOCAL_GL_TEXTURE_RECTANGLE_ARB); MOZ_ASSERT(aFormat == gfx::SurfaceFormat::R8G8B8A8); - return mRGBARectProgram; + return mRGBARectProgram.get(); } virtual const gfx::Matrix4x4& GetProjMatrix() const override { @@ -315,7 +315,7 @@ public: protected: RefPtr mGLContext; - nsAutoPtr mRGBARectProgram; + mozilla::UniquePtr mRGBARectProgram; gfx::Matrix4x4 mProjMatrix; GLuint mQuadVBO; }; @@ -1988,7 +1988,7 @@ nsChildView::CleanupWindowEffects() bool nsChildView::PreRender(LayerManagerComposite* aManager) { - nsAutoPtr manager(GLManager::CreateGLManager(aManager)); + UniquePtr manager(GLManager::CreateGLManager(aManager)); if (!manager) { return true; } @@ -2010,7 +2010,7 @@ nsChildView::PreRender(LayerManagerComposite* aManager) void nsChildView::PostRender(LayerManagerComposite* aManager) { - nsAutoPtr manager(GLManager::CreateGLManager(aManager)); + UniquePtr manager(GLManager::CreateGLManager(aManager)); if (!manager) { return; } @@ -2023,9 +2023,9 @@ void nsChildView::DrawWindowOverlay(LayerManagerComposite* aManager, LayoutDeviceIntRect aRect) { - nsAutoPtr manager(GLManager::CreateGLManager(aManager)); + mozilla::UniquePtr manager(GLManager::CreateGLManager(aManager)); if (manager) { - DrawWindowOverlay(manager, aRect); + DrawWindowOverlay(manager.get(), aRect); } } @@ -2718,11 +2718,11 @@ nsChildView::DoRemoteComposition(const LayoutDeviceIntRect& aRenderRect) mGLPresenter->BeginFrame(aRenderRect.Size()); // Draw the result from the basic compositor. - mBasicCompositorImage->Draw(mGLPresenter, LayoutDeviceIntPoint(0, 0)); + mBasicCompositorImage->Draw(mGLPresenter.get(), LayoutDeviceIntPoint(0, 0)); // DrawWindowOverlay doesn't do anything for non-GL, so it didn't paint // anything during the basic compositor transaction. Draw the overlay now. - DrawWindowOverlay(mGLPresenter, aRenderRect); + DrawWindowOverlay(mGLPresenter.get(), aRenderRect); mGLPresenter->EndFrame(); @@ -3008,7 +3008,7 @@ GLPresenter::GLPresenter(GLContext* aContext) mGLContext->MakeCurrent(); ShaderConfigOGL config; config.SetTextureTarget(LOCAL_GL_TEXTURE_RECTANGLE_ARB); - mRGBARectProgram = new ShaderProgramOGL(mGLContext, + mRGBARectProgram = MakeUnique(mGLContext, ProgramProfileOGL::GetProfileFor(config)); // Create mQuadVBO. From fce35d00ac92b402d67f3b82d44fc61f4c9e6c53 Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Fri, 22 Jul 2016 12:43:15 +0900 Subject: [PATCH 008/135] Bug 1288595 - Guard DPI_AWARENESS_CONTEXT defines against Windows SDK beta (10.0.14383.0). r=jfkthame MozReview-Commit-ID: 6CMZ3mVhWd5 --HG-- extra : rebase_source : 4aac1b1b9d8b06414022ce350c28e72bf3a2fdeb --- widget/windows/WinUtils.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/widget/windows/WinUtils.h b/widget/windows/WinUtils.h index 163fc58a4c42..3842c54cef95 100644 --- a/widget/windows/WinUtils.h +++ b/widget/windows/WinUtils.h @@ -78,7 +78,7 @@ class nsWindow; class nsWindowBase; struct KeyPair; -#ifndef DPI_AWARENESS_CONTEXT_DECLARED +#if !defined(DPI_AWARENESS_CONTEXT_DECLARED) && !defined(DPI_AWARENESS_CONTEXT_UNAWARE) DECLARE_HANDLE(DPI_AWARENESS_CONTEXT); From 8bd3135b4daefb5a8973aa885d73cdfe925c73a6 Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Fri, 22 Jul 2016 02:42:22 -0700 Subject: [PATCH 009/135] Bug 1288569 - Add more mCanSend checks r=nical --- gfx/layers/ipc/CompositorBridgeChild.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/gfx/layers/ipc/CompositorBridgeChild.cpp b/gfx/layers/ipc/CompositorBridgeChild.cpp index 36c97ea19e43..216f31bc1bd3 100644 --- a/gfx/layers/ipc/CompositorBridgeChild.cpp +++ b/gfx/layers/ipc/CompositorBridgeChild.cpp @@ -291,6 +291,9 @@ CompositorBridgeChild::RecvCompositorUpdated(const uint64_t& aLayersId, if (dom::TabChild* child = dom::TabChild::GetFrom(aLayersId)) { child->CompositorUpdated(aNewIdentifier); } + if (!mCanSend) { + return true; + } SendAcknowledgeCompositorUpdate(aLayersId); } return true; @@ -416,6 +419,9 @@ CompositorBridgeChild::RecvUpdatePluginConfigurations(const LayoutDeviceIntPoint // Any plugins we didn't update need to be hidden, as they are // not associated with visible content. nsIWidget::UpdateRegisteredPluginWindowVisibility((uintptr_t)parent, visiblePluginIds); + if (!mCanSend) { + return true; + } SendRemotePluginsReady(); return true; #endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) @@ -461,6 +467,9 @@ CompositorBridgeChild::RecvHideAllPlugins(const uintptr_t& aParentWidget) MOZ_ASSERT(NS_IsMainThread()); nsTArray list; nsIWidget::UpdateRegisteredPluginWindowVisibility(aParentWidget, list); + if (!mCanSend) { + return true; + } SendRemotePluginsReady(); return true; #endif // !defined(XP_WIN) && !defined(MOZ_WIDGET_GTK) @@ -653,6 +662,9 @@ CompositorBridgeChild::RequestNotifyAfterRemotePaint(TabChild* aTabChild) { MOZ_ASSERT(aTabChild, "NULL TabChild not allowed in CompositorBridgeChild::RequestNotifyAfterRemotePaint"); mWeakTabChild = do_GetWeakReference( static_cast(aTabChild) ); + if (!mCanSend) { + return; + } Unused << SendRequestNotifyAfterRemotePaint(); } From c0d13a09b6670816294de5aaec6d1c904a0323cb Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 22 Jul 2016 11:52:09 +0200 Subject: [PATCH 010/135] Bug 1250922: Add gpsd geolocation provider on Linux, r=jdm,glandium Gpsd is the GPS daemon on Linux. It implements support for a wide range of GPS receivers. This patch adds support for gpsd to the Geolocation module. The build system can now test for libgps, which provides the public interface to gpsd's functionality. If found, |GpsdLocationProvider| is added to the build. MozReview-Commit-ID: 1kBgFdEZePI --- config/system-headers | 1 + dom/system/linux/GpsdLocationProvider.cpp | 375 ++++++++++++++++++++++ dom/system/linux/GpsdLocationProvider.h | 48 +++ dom/system/linux/moz.build | 20 ++ dom/system/moz.build | 2 + toolkit/moz.configure | 13 + 6 files changed, 459 insertions(+) create mode 100644 dom/system/linux/GpsdLocationProvider.cpp create mode 100644 dom/system/linux/GpsdLocationProvider.h create mode 100644 dom/system/linux/moz.build diff --git a/config/system-headers b/config/system-headers index 3b8e4b204cfb..8f7136549b34 100644 --- a/config/system-headers +++ b/config/system-headers @@ -498,6 +498,7 @@ glib-object.h gmodule.h gnome.h gnu/libc-version.h +gps.h grp.h gssapi_generic.h gssapi/gssapi_generic.h diff --git a/dom/system/linux/GpsdLocationProvider.cpp b/dom/system/linux/GpsdLocationProvider.cpp new file mode 100644 index 000000000000..4a7010297f34 --- /dev/null +++ b/dom/system/linux/GpsdLocationProvider.cpp @@ -0,0 +1,375 @@ +/* -*- 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 "GpsdLocationProvider.h" +#include +#include +#include "mozilla/Atomics.h" +#include "mozilla/FloatingPoint.h" +#include "mozilla/LazyIdleThread.h" +#include "nsGeoPosition.h" +#include "nsIDOMGeoPositionError.h" +#include "nsProxyRelease.h" +#include "nsThreadUtils.h" + +namespace mozilla { +namespace dom { + +// +// UpdateRunnable +// + +class GpsdLocationProvider::UpdateRunnable final : public Runnable +{ +public: + UpdateRunnable( + const nsMainThreadPtrHandle& aLocationProvider, + nsIDOMGeoPosition* aPosition) + : mLocationProvider(aLocationProvider) + , mPosition(aPosition) + { + MOZ_ASSERT(mLocationProvider); + MOZ_ASSERT(mPosition); + } + + // nsIRunnable + // + + NS_IMETHOD Run() override + { + mLocationProvider->Update(mPosition); + return NS_OK; + } + +private: + nsMainThreadPtrHandle mLocationProvider; + RefPtr mPosition; +}; + +// +// NotifyErrorRunnable +// + +class GpsdLocationProvider::NotifyErrorRunnable final : public Runnable +{ +public: + NotifyErrorRunnable( + const nsMainThreadPtrHandle& aLocationProvider, + int aError) + : mLocationProvider(aLocationProvider) + , mError(aError) + { + MOZ_ASSERT(mLocationProvider); + } + + // nsIRunnable + // + + NS_IMETHOD Run() override + { + mLocationProvider->NotifyError(mError); + return NS_OK; + } + +private: + nsMainThreadPtrHandle mLocationProvider; + int mError; +}; + +// +// PollRunnable +// + +/** + * |PollRunnable| does the main work of processing GPS data received + * from gpsd. libgps blocks while polling, so this runnable has to be + * executed on it's own thread. To cancel the poll runnable, invoke + * |StopRunning| and |PollRunnable| will stop within a reasonable time + * frame. + */ +class GpsdLocationProvider::PollRunnable final : public Runnable +{ +public: + PollRunnable( + const nsMainThreadPtrHandle& aLocationProvider) + : mLocationProvider(aLocationProvider) + , mRunning(true) + { + MOZ_ASSERT(mLocationProvider); + } + + bool IsRunning() const + { + return mRunning; + } + + void StopRunning() + { + mRunning = false; + } + + // nsIRunnable + // + + NS_IMETHOD Run() override + { + int err; + + switch (GPSD_API_MAJOR_VERSION) { + case 5: + err = PollLoop5(); + break; + default: + err = nsIDOMGeoPositionError::POSITION_UNAVAILABLE; + break; + } + + if (err) { + NS_DispatchToMainThread( + MakeAndAddRef(mLocationProvider, err)); + } + + mLocationProvider = nullptr; + + return NS_OK; + } + +protected: + int PollLoop5() + { +#if GPSD_API_MAJOR_VERSION == 5 + static const int GPSD_WAIT_TIMEOUT_US = 1000000; /* us to wait for GPS data */ + + struct gps_data_t gpsData; + + auto res = gps_open(nullptr, nullptr, &gpsData); + + if (res < 0) { + return ErrnoToError(errno); + } + + gps_stream(&gpsData, WATCH_ENABLE | WATCH_JSON, NULL); + + int err = 0; + + double lat = -1; + double lon = -1; + double alt = -1; + double hError = -1; + double vError = -1; + double heading = -1; + double speed = -1; + long long timestamp = 0; + + while (IsRunning()) { + + errno = 0; + auto hasGpsData = gps_waiting(&gpsData, GPSD_WAIT_TIMEOUT_US); + + if (errno) { + err = ErrnoToError(errno); + break; + } + if (!hasGpsData) { + continue; /* woke up from timeout */ + } + + res = gps_read(&gpsData); + + if (res < 0) { + err = ErrnoToError(errno); + break; + } else if (!res) { + continue; /* no data available */ + } + + if (gpsData.status == STATUS_NO_FIX) { + continue; + } + + switch (gpsData.fix.mode) { + case MODE_3D: + if (!IsNaN(gpsData.fix.altitude)) { + alt = gpsData.fix.altitude; + } + MOZ_FALLTHROUGH; + case MODE_2D: + if (!IsNaN(gpsData.fix.latitude)) { + lat = gpsData.fix.latitude; + } + if (!IsNaN(gpsData.fix.longitude)) { + lon = gpsData.fix.longitude; + } + if (!IsNaN(gpsData.fix.epx) && !IsNaN(gpsData.fix.epy)) { + hError = std::max(gpsData.fix.epx, gpsData.fix.epy); + } else if (!IsNaN(gpsData.fix.epx)) { + hError = gpsData.fix.epx; + } else if (!IsNaN(gpsData.fix.epy)) { + hError = gpsData.fix.epy; + } + if (!IsNaN(gpsData.fix.altitude)) { + alt = gpsData.fix.altitude; + } + if (!IsNaN(gpsData.fix.epv)) { + vError = gpsData.fix.epv; + } + if (!IsNaN(gpsData.fix.track)) { + heading = gpsData.fix.track; + } + if (!IsNaN(gpsData.fix.speed)) { + speed = gpsData.fix.speed; + } + break; + default: + continue; // There's no useful data in this fix; continue. + } + + timestamp = PR_Now() / PR_USEC_PER_MSEC; // convert to milliseconds + + NS_DispatchToMainThread( + MakeAndAddRef(mLocationProvider, + new nsGeoPosition(lat, lon, alt, + hError, vError, + heading, speed, + timestamp))); + } + + gps_stream(&gpsData, WATCH_DISABLE, NULL); + gps_close(&gpsData); + + return err; +#else + return nsIDOMGeoPositionError::POSITION_UNAVAILABLE; +#endif // GPSD_MAJOR_API_VERSION + } + + static int ErrnoToError(int aErrno) + { + switch (aErrno) { + case EACCES: + MOZ_FALLTHROUGH; + case EPERM: + MOZ_FALLTHROUGH; + case EROFS: + return nsIDOMGeoPositionError::PERMISSION_DENIED; + case ETIME: + MOZ_FALLTHROUGH; + case ETIMEDOUT: + return nsIDOMGeoPositionError::TIMEOUT; + default: + return nsIDOMGeoPositionError::POSITION_UNAVAILABLE; + } + } + +private: + nsMainThreadPtrHandle mLocationProvider; + Atomic mRunning; +}; + +// +// GpsdLocationProvider +// + +const uint32_t GpsdLocationProvider::GPSD_POLL_THREAD_TIMEOUT_MS = 5000; + +GpsdLocationProvider::GpsdLocationProvider() +{ } + +GpsdLocationProvider::~GpsdLocationProvider() +{ } + +void +GpsdLocationProvider::Update(nsIDOMGeoPosition* aPosition) +{ + if (!mCallback || !mPollRunnable) { + return; // not initialized or already shut down + } + + mCallback->Update(aPosition); +} + +void +GpsdLocationProvider::NotifyError(int aError) +{ + if (!mCallback) { + return; // not initialized or already shut down + } + + mCallback->NotifyError(aError); +} + +// nsISupports +// + +NS_IMPL_ISUPPORTS(GpsdLocationProvider, nsIGeolocationProvider) + +// nsIGeolocationProvider +// + +NS_IMETHODIMP +GpsdLocationProvider::Startup() +{ + if (mPollRunnable) { + return NS_OK; // already running + } + + RefPtr pollRunnable = + MakeAndAddRef( + nsMainThreadPtrHandle( + new nsMainThreadPtrHolder(this))); + + // Use existing poll thread... + RefPtr pollThread = mPollThread; + + // ... or create a new one. + if (!pollThread) { + pollThread = MakeAndAddRef( + GPSD_POLL_THREAD_TIMEOUT_MS, + NS_LITERAL_CSTRING("Gpsd poll thread"), + LazyIdleThread::ManualShutdown); + } + + auto rv = pollThread->Dispatch(pollRunnable, NS_DISPATCH_NORMAL); + + if (NS_FAILED(rv)) { + return rv; + } + + mPollRunnable = pollRunnable.forget(); + mPollThread = pollThread.forget(); + + return NS_OK; +} + +NS_IMETHODIMP +GpsdLocationProvider::Watch(nsIGeolocationUpdate* aCallback) +{ + mCallback = aCallback; + + return NS_OK; +} + +NS_IMETHODIMP +GpsdLocationProvider::Shutdown() +{ + if (!mPollRunnable) { + return NS_OK; // not running + } + + mPollRunnable->StopRunning(); + mPollRunnable = nullptr; + + return NS_OK; +} + +NS_IMETHODIMP +GpsdLocationProvider::SetHighAccuracy(bool aHigh) +{ + return NS_OK; +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/system/linux/GpsdLocationProvider.h b/dom/system/linux/GpsdLocationProvider.h new file mode 100644 index 000000000000..d409d81d7918 --- /dev/null +++ b/dom/system/linux/GpsdLocationProvider.h @@ -0,0 +1,48 @@ +/* -*- 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/. */ + +#ifndef GpsdLocationProvider_h +#define GpsdLocationProvider_h + +#include "nsCOMPtr.h" +#include "nsGeolocation.h" +#include "nsIGeolocationProvider.h" + +namespace mozilla { + +class LazyIdleThread; + +namespace dom { + +class GpsdLocationProvider final : public nsIGeolocationProvider +{ + class NotifyErrorRunnable; + class PollRunnable; + class UpdateRunnable; + +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIGEOLOCATIONPROVIDER + + GpsdLocationProvider(); + +private: + ~GpsdLocationProvider(); + + void Update(nsIDOMGeoPosition* aPosition); + void NotifyError(int aError); + + static const uint32_t GPSD_POLL_THREAD_TIMEOUT_MS; + + nsCOMPtr mCallback; + RefPtr mPollThread; + RefPtr mPollRunnable; +}; + +} // namespace dom +} // namespace mozilla + +#endif /* GpsLocationProvider_h */ diff --git a/dom/system/linux/moz.build b/dom/system/linux/moz.build new file mode 100644 index 000000000000..d9e50cb311ca --- /dev/null +++ b/dom/system/linux/moz.build @@ -0,0 +1,20 @@ +# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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 CONFIG['MOZ_GPSD']: + SOURCES += [ + 'GpsdLocationProvider.cpp' + ] + + CXXFLAGS += CONFIG['MOZ_GPSD_CFLAGS'] + + OS_LIBS += CONFIG['MOZ_GPSD_LIBS'] + + LOCAL_INCLUDES += [ + '/dom/geolocation' + ] + +FINAL_LIBRARY = 'xul' diff --git a/dom/system/moz.build b/dom/system/moz.build index b5929bc09490..4e28008fac39 100644 --- a/dom/system/moz.build +++ b/dom/system/moz.build @@ -14,6 +14,8 @@ elif toolkit == 'android': DIRS += ['android'] elif toolkit == 'gonk': DIRS += ['gonk'] +elif toolkit in ('gtk2', 'gtk3'): + DIRS += ['linux'] XPIDL_SOURCES += [ 'nsIOSFileConstantsService.idl', diff --git a/toolkit/moz.configure b/toolkit/moz.configure index 155512562571..be8a677d3cdd 100644 --- a/toolkit/moz.configure +++ b/toolkit/moz.configure @@ -435,6 +435,19 @@ def check_places_and_android_history(places, android_history): if places and android_history: die('Cannot use MOZ_ANDROID_HISTORY alongside MOZ_PLACES.') +# gpsd support +# ============================================================== +option('--enable-gpsd', env='MOZ_GPSD', + help='Enable gpsd support') + +@depends('--enable-gpsd') +def gpsd(value): + return bool(value) + +system_gpsd = pkg_check_modules('MOZ_GPSD', 'libgps >= 3.11', gpsd) + +set_config('MOZ_GPSD', system_gpsd) + # Miscellaneous programs # ============================================================== From 6c1b3c2bc23925c3852d800ae536be7c4aca6a97 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 22 Jul 2016 11:52:09 +0200 Subject: [PATCH 011/135] Bug 1250922: Use gpsd for Geolocation, r=jdm,glandium This patch adds the gpsd location provider to |nsGeolocationService|. On release builds, the new provider is *not* used by default, as GPS is slow to start and unreliable indoors. To enable gpsd, users with a supported GPS receiver must set the preference 'geo.location.use_gpsd' to 'true'. On non-release builds, the gpsd location provider is enabled by default to give it some testing. MozReview-Commit-ID: I0tj1GmmFNP --- browser/app/moz.build | 3 +++ browser/app/profile/firefox.js | 10 ++++++++++ dom/geolocation/moz.build | 6 ++++++ dom/geolocation/nsGeolocation.cpp | 12 ++++++++++++ 4 files changed, 31 insertions(+) diff --git a/browser/app/moz.build b/browser/app/moz.build index bc1f24325b22..a008ef58d680 100644 --- a/browser/app/moz.build +++ b/browser/app/moz.build @@ -80,6 +80,9 @@ if CONFIG['MOZ_LINKER']: if CONFIG['HAVE_CLOCK_MONOTONIC']: OS_LIBS += CONFIG['REALTIME_LIBS'] +if CONFIG['MOZ_GPSD']: + DEFINES['MOZ_GPSD'] = True + for icon in ('firefox', 'document', 'newwindow', 'newtab', 'pbmode'): DEFINES[icon.upper() + '_ICO'] = '"%s/dist/branding/%s.ico"' % ( TOPOBJDIR, icon) diff --git a/browser/app/profile/firefox.js b/browser/app/profile/firefox.js index 9527129e9b8e..0e9c1ff40624 100644 --- a/browser/app/profile/firefox.js +++ b/browser/app/profile/firefox.js @@ -1240,6 +1240,16 @@ pref("geo.provider.use_corelocation", true); pref("geo.provider.ms-windows-location", false); #endif +#ifdef MOZ_WIDGET_GTK +#ifdef MOZ_GPSD +#ifdef RELEASE_BUILD +pref("geo.provider.use_gpsd", false); +#else +pref("geo.provider.use_gpsd", true); +#endif +#endif +#endif + // Necko IPC security checks only needed for app isolation for cookies/cache/etc: // currently irrelevant for desktop e10s pref("network.disable.ipc.security", true); diff --git a/dom/geolocation/moz.build b/dom/geolocation/moz.build index 2937511bc189..06270b4377cb 100644 --- a/dom/geolocation/moz.build +++ b/dom/geolocation/moz.build @@ -42,3 +42,9 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows': LOCAL_INCLUDES += [ '/dom/system/windows', ] +elif CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3'): + if CONFIG['MOZ_GPSD']: + LOCAL_INCLUDES += [ + '/dom/system/linux', + ] + DEFINES['MOZ_GPSD'] = True diff --git a/dom/geolocation/nsGeolocation.cpp b/dom/geolocation/nsGeolocation.cpp index 880f1de3b393..209ad9c3e790 100644 --- a/dom/geolocation/nsGeolocation.cpp +++ b/dom/geolocation/nsGeolocation.cpp @@ -45,6 +45,10 @@ class nsIPrincipal; #include "GonkGPSGeolocationProvider.h" #endif +#ifdef MOZ_GPSD +#include "GpsdLocationProvider.h" +#endif + #ifdef MOZ_WIDGET_COCOA #include "CoreLocationLocationProvider.h" #endif @@ -766,6 +770,14 @@ nsresult nsGeolocationService::Init() mProvider = do_GetService(GONK_GPS_GEOLOCATION_PROVIDER_CONTRACTID); #endif +#ifdef MOZ_WIDGET_GTK +#ifdef MOZ_GPSD + if (Preferences::GetBool("geo.provider.use_gpsd", false)) { + mProvider = new GpsdLocationProvider(); + } +#endif +#endif + #ifdef MOZ_WIDGET_COCOA if (Preferences::GetBool("geo.provider.use_corelocation", true)) { mProvider = new CoreLocationLocationProvider(); From e653da5240720c778002da17381f7948b2c39291 Mon Sep 17 00:00:00 2001 From: Thomas Zimmermann Date: Fri, 22 Jul 2016 11:52:09 +0200 Subject: [PATCH 012/135] Bug 1250922: Add MLS as fallback for gpsd, r=jdm The Mozilla Location Service is the fallback for gpsd. If no location information is received from GSP within a few seconds, MLS provides a position. It will be updated once GPS is ready. If GPS fails, MLS will take over again until GPS has been restored. --- dom/system/linux/GpsdLocationProvider.cpp | 93 +++++++++++++++++++++++ dom/system/linux/GpsdLocationProvider.h | 4 + 2 files changed, 97 insertions(+) diff --git a/dom/system/linux/GpsdLocationProvider.cpp b/dom/system/linux/GpsdLocationProvider.cpp index 4a7010297f34..b652763e3289 100644 --- a/dom/system/linux/GpsdLocationProvider.cpp +++ b/dom/system/linux/GpsdLocationProvider.cpp @@ -7,6 +7,7 @@ #include "GpsdLocationProvider.h" #include #include +#include "MLSFallback.h" #include "mozilla/Atomics.h" #include "mozilla/FloatingPoint.h" #include "mozilla/LazyIdleThread.h" @@ -18,6 +19,62 @@ namespace mozilla { namespace dom { +// +// MLSGeolocationUpdate +// + +/** + * |MLSGeolocationUpdate| provides a fallback if gpsd is not supported. + */ +class GpsdLocationProvider::MLSGeolocationUpdate final + : public nsIGeolocationUpdate +{ +public: + NS_DECL_ISUPPORTS + NS_DECL_NSIGEOLOCATIONUPDATE + + explicit MLSGeolocationUpdate(nsIGeolocationUpdate* aCallback); + +protected: + ~MLSGeolocationUpdate() = default; + +private: + nsCOMPtr mCallback; +}; + +GpsdLocationProvider::MLSGeolocationUpdate::MLSGeolocationUpdate( + nsIGeolocationUpdate* aCallback) + : mCallback(aCallback) +{ + MOZ_ASSERT(mCallback); +} + +// nsISupports +// + +NS_IMPL_ISUPPORTS(GpsdLocationProvider::MLSGeolocationUpdate, nsIGeolocationUpdate); + +// nsIGeolocationUpdate +// + +NS_IMETHODIMP +GpsdLocationProvider::MLSGeolocationUpdate::Update(nsIDOMGeoPosition* aPosition) +{ + nsCOMPtr coords; + aPosition->GetCoords(getter_AddRefs(coords)); + if (!coords) { + return NS_ERROR_FAILURE; + } + + return mCallback->Update(aPosition); +} + +NS_IMETHODIMP +GpsdLocationProvider::MLSGeolocationUpdate::NotifyError(uint16_t aError) +{ + return mCallback->NotifyError(aError); +} + // // UpdateRunnable // @@ -101,6 +158,11 @@ public: MOZ_ASSERT(mLocationProvider); } + static bool IsSupported() + { + return GPSD_API_MAJOR_VERSION == 5; + } + bool IsRunning() const { return mRunning; @@ -288,6 +350,12 @@ GpsdLocationProvider::Update(nsIDOMGeoPosition* aPosition) return; // not initialized or already shut down } + if (mMLSProvider) { + /* We got a location from gpsd, so let's cancel our MLS fallback. */ + mMLSProvider->Shutdown(); + mMLSProvider = nullptr; + } + mCallback->Update(aPosition); } @@ -298,6 +366,14 @@ GpsdLocationProvider::NotifyError(int aError) return; // not initialized or already shut down } + if (!mMLSProvider) { + /* With gpsd failed, we restart MLS. It will be canceled once we + * get another location from gpsd. + */ + mMLSProvider = MakeAndAddRef(); + mMLSProvider->Startup(new MLSGeolocationUpdate(mCallback)); + } + mCallback->NotifyError(aError); } @@ -312,6 +388,10 @@ NS_IMPL_ISUPPORTS(GpsdLocationProvider, nsIGeolocationProvider) NS_IMETHODIMP GpsdLocationProvider::Startup() { + if (!PollRunnable::IsSupported()) { + return NS_OK; // We'll fall back to MLS. + } + if (mPollRunnable) { return NS_OK; // already running } @@ -349,12 +429,25 @@ GpsdLocationProvider::Watch(nsIGeolocationUpdate* aCallback) { mCallback = aCallback; + /* The MLS fallback will kick in after a few seconds if gpsd + * doesn't provide location information within time. Once we + * see the first message from gpsd, the fallback will be + * disabled in |Update|. + */ + mMLSProvider = MakeAndAddRef(); + mMLSProvider->Startup(new MLSGeolocationUpdate(aCallback)); + return NS_OK; } NS_IMETHODIMP GpsdLocationProvider::Shutdown() { + if (mMLSProvider) { + mMLSProvider->Shutdown(); + mMLSProvider = nullptr; + } + if (!mPollRunnable) { return NS_OK; // not running } diff --git a/dom/system/linux/GpsdLocationProvider.h b/dom/system/linux/GpsdLocationProvider.h index d409d81d7918..c49bad9f43ef 100644 --- a/dom/system/linux/GpsdLocationProvider.h +++ b/dom/system/linux/GpsdLocationProvider.h @@ -11,6 +11,8 @@ #include "nsGeolocation.h" #include "nsIGeolocationProvider.h" +class MLSFallback; + namespace mozilla { class LazyIdleThread; @@ -19,6 +21,7 @@ namespace dom { class GpsdLocationProvider final : public nsIGeolocationProvider { + class MLSGeolocationUpdate; class NotifyErrorRunnable; class PollRunnable; class UpdateRunnable; @@ -40,6 +43,7 @@ private: nsCOMPtr mCallback; RefPtr mPollThread; RefPtr mPollRunnable; + RefPtr mMLSProvider; }; } // namespace dom From 3e647537b4dcf634955c82c3dfa65428e12a44b8 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 22 Jul 2016 13:01:41 +0200 Subject: [PATCH 013/135] Bug 1288694 - Wrong use of ErrorResult in dom/ipc/FilePickerParent, r=smaug --- dom/ipc/FilePickerParent.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dom/ipc/FilePickerParent.cpp b/dom/ipc/FilePickerParent.cpp index 94c84709f11f..c7e149121908 100644 --- a/dom/ipc/FilePickerParent.cpp +++ b/dom/ipc/FilePickerParent.cpp @@ -110,11 +110,13 @@ FilePickerParent::IORunnable::Run() ErrorResult error; blobImpl->GetSize(error); if (NS_WARN_IF(error.Failed())) { + error.SuppressException(); continue; } blobImpl->GetLastModified(error); if (NS_WARN_IF(error.Failed())) { + error.SuppressException(); continue; } From 3a9a5e2c83b15bb908b765f59d4edcfd1ce751fd Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Fri, 22 Jul 2016 11:32:41 +0200 Subject: [PATCH 014/135] Bug 1285003 - CSP: Insecure http port :80 should also allow secure https port :443. r=dveditz --- dom/security/nsCSPUtils.cpp | 131 +++++++++++++++++++++++++----------- 1 file changed, 91 insertions(+), 40 deletions(-) diff --git a/dom/security/nsCSPUtils.cpp b/dom/security/nsCSPUtils.cpp index 0311a76a5636..c0ed8be65ee5 100644 --- a/dom/security/nsCSPUtils.cpp +++ b/dom/security/nsCSPUtils.cpp @@ -18,6 +18,8 @@ #include "nsReadableUtils.h" #include "nsSandboxFlags.h" +#define DEFAULT_PORT -1 + static mozilla::LogModule* GetCspUtilsLog() { @@ -437,6 +439,89 @@ nsCSPHostSrc::~nsCSPHostSrc() { } +/* + * Checks whether the current directive permits a specific port. + * @param aEnforcementScheme + * The scheme that this directive allows + * (used to query the default port for that scheme) + * @param aEnforcementPort + * The port that this directive allows + * @param aResourceURI + * The uri of the subresource load + */ +bool +permitsPort(const nsAString& aEnforcementScheme, + const nsAString& aEnforcementPort, + nsIURI* aResourceURI) +{ + // If enforcement port is the wildcard, don't block the load. + if (aEnforcementPort.EqualsASCII("*")) { + return true; + } + + int32_t resourcePort; + nsresult rv = aResourceURI->GetPort(&resourcePort); + NS_ENSURE_SUCCESS(rv, false); + + // Avoid unnecessary string creation/manipulation and don't block the + // load if the resource to be loaded uses the default port for that + // scheme and there is no port to be enforced. + // Note, this optimization relies on scheme checks within permitsScheme(). + if (resourcePort == DEFAULT_PORT && aEnforcementPort.IsEmpty()) { + return true; + } + + // By now we know at that either the resourcePort does not use the default + // port or there is a port restriction to be enforced. A port value of -1 + // corresponds to the protocol's default port (eg. -1 implies port 80 for + // http URIs), in such a case we have to query the default port of the + // resource to be loaded. + if (resourcePort == DEFAULT_PORT) { + nsAutoCString resourceScheme; + rv = aResourceURI->GetScheme(resourceScheme); + NS_ENSURE_SUCCESS(rv, false); + resourcePort = NS_GetDefaultPort(resourceScheme.get()); + } + + // If there is a port to be enforced and the ports match, then + // don't block the load. + nsString resourcePortStr; + resourcePortStr.AppendInt(resourcePort); + if (aEnforcementPort.Equals(resourcePortStr)) { + return true; + } + + // If there is no port to be enforced, query the default port for the load. + nsString enforcementPort(aEnforcementPort); + if (enforcementPort.IsEmpty()) { + // For scheme less sources, our parser always generates a scheme + // which is the scheme of the protected resource. + MOZ_ASSERT(!aEnforcementScheme.IsEmpty(), + "need a scheme to query default port"); + int32_t defaultEnforcementPort = + NS_GetDefaultPort(NS_ConvertUTF16toUTF8(aEnforcementScheme).get()); + enforcementPort.Truncate(); + enforcementPort.AppendInt(defaultEnforcementPort); + } + + // If default ports match, don't block the load + if (enforcementPort.Equals(resourcePortStr)) { + return true; + } + + // Additional port matching where the regular URL matching algorithm + // treats insecure ports as matching their secure variants. + // default port for http is :80 + // default port for https is :443 + if (enforcementPort.EqualsLiteral("80") && + resourcePortStr.EqualsLiteral("443")) { + return true; + } + + // ports do not match, block the load. + return false; +} + bool nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected, bool aReportOnly, bool aUpgradeInsecure) const @@ -502,6 +587,11 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected return false; } + // Port matching: Check if the ports match. + if (!permitsPort(mScheme, mPort, aUri)) { + return false; + } + // 4.9) Path matching: If there is a path, we have to enforce // path-level matching, unless the channel got redirected, see: // http://www.w3.org/TR/CSP11/#source-list-paths-and-redirects @@ -534,46 +624,7 @@ nsCSPHostSrc::permits(nsIURI* aUri, const nsAString& aNonce, bool aWasRedirected } } - // 4.8) Port matching: If port uses wildcard, allow the load. - if (mPort.EqualsASCII("*")) { - return true; - } - - // Before we can check if the port matches, we have to - // query the port from aUri. - int32_t uriPort; - rv = aUri->GetPort(&uriPort); - NS_ENSURE_SUCCESS(rv, false); - - nsAutoCString scheme; - rv = aUri->GetScheme(scheme); - NS_ENSURE_SUCCESS(rv, false); - - uriPort = (uriPort > 0) ? uriPort : NS_GetDefaultPort(scheme.get()); - - // 4.7) Default port matching: If mPort is empty, we have to compare default ports. - if (mPort.IsEmpty()) { - int32_t port = NS_GetDefaultPort(NS_ConvertUTF16toUTF8(mScheme).get()); - if (port != uriPort) { - // We should not return false for scheme-less sources where the protected resource - // is http and the load is https, see: http://www.w3.org/TR/CSP2/#match-source-expression - // BUT, we only allow scheme-less sources to be upgraded from http to https if CSP - // does not explicitly define a port. - if (!(uriPort == NS_GetDefaultPort("https"))) { - return false; - } - } - } - // 4.7) Port matching: Compare the ports. - else { - nsString portStr; - portStr.AppendInt(uriPort); - if (!mPort.Equals(portStr)) { - return false; - } - } - - // At the end: scheme, host, path, and port match -> allow the load. + // At the end: scheme, host, port and path match -> allow the load. return true; } From 022d9af2b329c4f9af904a4c0be7be0168b0cf9e Mon Sep 17 00:00:00 2001 From: Christoph Kerschbaumer Date: Fri, 22 Jul 2016 11:32:21 +0200 Subject: [PATCH 015/135] Bug 1285003 - Test insecure http port :80 allows secure https port :443. r=dveditz --- dom/security/test/csp/test_allow_https_schemes.html | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dom/security/test/csp/test_allow_https_schemes.html b/dom/security/test/csp/test_allow_https_schemes.html index 454687bc9bc2..713464200369 100644 --- a/dom/security/test/csp/test_allow_https_schemes.html +++ b/dom/security/test/csp/test_allow_https_schemes.html @@ -28,7 +28,12 @@ SimpleTest.waitForExplicitFinish(); var policies = [ ["allowed", "example.com"], ["allowed", "example.com:443"], - ["blocked", "example.com:80"] + ["allowed", "example.com:80"], + ["allowed", "http://*:80"], + ["allowed", "https://*:443"], + // our testing framework only supports :80 and :443, but + // using :8000 in a policy does the trick for the test. + ["blocked", "example.com:8000"], ] var counter = 0; From 5ce5a2cc20b3c28ff4e20aff53445509ec2e77b2 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Wed, 20 Jul 2016 15:02:23 +0200 Subject: [PATCH 016/135] Bug 1283020 - Update cubeb consumers to pass in latency in frames and not in ms. r=achronop MozReview-Commit-ID: D7HjHNPRIre --- dom/media/AudioStream.cpp | 4 +++- dom/media/GraphDriver.cpp | 6 +++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/dom/media/AudioStream.cpp b/dom/media/AudioStream.cpp index 3f2ae52734fe..6da230c0929a 100644 --- a/dom/media/AudioStream.cpp +++ b/dom/media/AudioStream.cpp @@ -362,9 +362,11 @@ AudioStream::OpenCubeb(cubeb_stream_params& aParams, } cubeb_stream* stream = nullptr; + /* Convert from milliseconds to frames. */ + uint32_t latency_frames = CubebUtils::GetCubebLatency() * aParams.rate / 1000; if (cubeb_stream_init(cubebContext, &stream, "AudioStream", nullptr, nullptr, nullptr, &aParams, - CubebUtils::GetCubebLatency(), + latency_frames, DataCallback_S, StateCallback_S, this) == CUBEB_OK) { mCubebStream.reset(stream); CubebUtils::ReportCubebBackendUsed(); diff --git a/dom/media/GraphDriver.cpp b/dom/media/GraphDriver.cpp index 17821199dbd9..7f7fcddd544e 100644 --- a/dom/media/GraphDriver.cpp +++ b/dom/media/GraphDriver.cpp @@ -559,7 +559,7 @@ AudioCallbackDriver::Init() { cubeb_stream_params output; cubeb_stream_params input; - uint32_t latency; + uint32_t latency_frames; bool firstStream = CubebUtils::GetFirstStream(); MOZ_ASSERT(!NS_IsMainThread(), @@ -588,7 +588,7 @@ AudioCallbackDriver::Init() output.format = CUBEB_SAMPLE_FLOAT32NE; } - if (cubeb_get_min_latency(CubebUtils::GetCubebContext(), output, &latency) != CUBEB_OK) { + if (cubeb_get_min_latency(CubebUtils::GetCubebContext(), output, &latency_frames) != CUBEB_OK) { NS_WARNING("Could not get minimal latency from cubeb."); return; } @@ -624,7 +624,7 @@ AudioCallbackDriver::Init() input_id, mGraphImpl->mInputWanted ? &input : nullptr, output_id, - mGraphImpl->mOutputWanted ? &output : nullptr, latency, + mGraphImpl->mOutputWanted ? &output : nullptr, latency_frames, DataCallback_s, StateCallback_s, this) == CUBEB_OK) { mAudioStream.own(stream); DebugOnly rv = cubeb_stream_set_volume(mAudioStream, CubebUtils::GetVolumeScale()); From 6100b0f94e781f5cc109bbab2f0e173c4facdd64 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Wed, 20 Jul 2016 15:02:23 +0200 Subject: [PATCH 017/135] Bug 1285541 - Update moz.build and update.sh for the new version of cubeb. r=achronop MozReview-Commit-ID: 27b5L7ilGEg --- media/libcubeb/src/moz.build | 2 +- media/libcubeb/update.sh | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/media/libcubeb/src/moz.build b/media/libcubeb/src/moz.build index bf09f95ca84d..78121462065c 100644 --- a/media/libcubeb/src/moz.build +++ b/media/libcubeb/src/moz.build @@ -49,7 +49,7 @@ if CONFIG['OS_ARCH'] == 'OpenBSD': if CONFIG['OS_TARGET'] == 'Darwin': SOURCES += [ - 'cubeb_audiounit.c', + 'cubeb_audiounit.cpp', 'cubeb_resampler.cpp' ] if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa': diff --git a/media/libcubeb/update.sh b/media/libcubeb/update.sh index 726d806fc515..6f950b571c3e 100755 --- a/media/libcubeb/update.sh +++ b/media/libcubeb/update.sh @@ -12,7 +12,8 @@ cp $1/src/cubeb-speex-resampler.h src cp $1/src/cubeb.c src cp $1/src/cubeb_alsa.c src cp $1/src/cubeb_audiotrack.c src -cp $1/src/cubeb_audiounit.c src +cp $1/src/cubeb_audiounit.cpp src +cp $1/src/cubeb_osx_run_loop.h src cp $1/src/cubeb_jack.cpp src cp $1/src/cubeb_opensl.c src cp $1/src/cubeb_panner.cpp src From 6c724564256c6a0248a01d197eee298a1a0714b5 Mon Sep 17 00:00:00 2001 From: Paul Adenot Date: Wed, 20 Jul 2016 15:02:29 +0200 Subject: [PATCH 018/135] Bug 1285541 - Update cubeb to revision 2a5fd74b. r=padenot,achronop Patches by padenot and achronop. MozReview-Commit-ID: G00OFgHdKne --HG-- rename : media/libcubeb/src/cubeb_audiounit.c => media/libcubeb/src/cubeb_audiounit.cpp --- CLOBBER | 2 +- media/libcubeb/README_MOZILLA | 2 +- media/libcubeb/include/cubeb.h | 23 +- media/libcubeb/src/cubeb.c | 2 +- media/libcubeb/src/cubeb_alsa.c | 17 +- media/libcubeb/src/cubeb_audiotrack.c | 3 - ...{cubeb_audiounit.c => cubeb_audiounit.cpp} | 483 ++++++++++++------ media/libcubeb/src/cubeb_jack.cpp | 22 +- media/libcubeb/src/cubeb_opensl.c | 21 +- media/libcubeb/src/cubeb_osx_run_loop.h | 8 + media/libcubeb/src/cubeb_pulse.c | 22 +- media/libcubeb/src/cubeb_resampler_internal.h | 4 +- media/libcubeb/src/cubeb_ring_array.h | 22 +- media/libcubeb/src/cubeb_sndio.c | 6 +- media/libcubeb/src/cubeb_wasapi.cpp | 90 ++-- media/libcubeb/src/cubeb_winmm.c | 32 +- media/libcubeb/tests/test_audio.cpp | 5 +- media/libcubeb/tests/test_duplex.cpp | 6 +- media/libcubeb/tests/test_latency.cpp | 6 +- media/libcubeb/tests/test_record.cpp | 2 +- media/libcubeb/tests/test_sanity.cpp | 2 +- media/libcubeb/tests/test_tone.cpp | 2 +- 22 files changed, 483 insertions(+), 299 deletions(-) rename media/libcubeb/src/{cubeb_audiounit.c => cubeb_audiounit.cpp} (83%) diff --git a/CLOBBER b/CLOBBER index de1a51366053..1bd73ede65f5 100644 --- a/CLOBBER +++ b/CLOBBER @@ -22,4 +22,4 @@ # changes to stick? As of bug 928195, this shouldn't be necessary! Please # don't change CLOBBER for WebIDL changes any more. -Bug 1287946 - clobber due to generated SDK headers changing (bug 1182840) +Bug 1285541 - Clobber needed because this patch renames a file. diff --git a/media/libcubeb/README_MOZILLA b/media/libcubeb/README_MOZILLA index 16290971ffc2..51ce10c0cbba 100644 --- a/media/libcubeb/README_MOZILLA +++ b/media/libcubeb/README_MOZILLA @@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system. The cubeb git repository is: git://github.com/kinetiknz/cubeb.git -The git commit ID used was b8aebef33a096640d6cbd7a6fa568bccef1b339c. +The git commit ID used was 2a5fd74b1122ff4e4c445c1e092932be1273646e. diff --git a/media/libcubeb/include/cubeb.h b/media/libcubeb/include/cubeb.h index 9bc06fb9b1cb..95118dc9113b 100644 --- a/media/libcubeb/include/cubeb.h +++ b/media/libcubeb/include/cubeb.h @@ -32,10 +32,10 @@ extern "C" { cubeb_init(&app_ctx, "Example Application"); int rv; int rate; - int latency_ms; + int latency_frames; uint64_t ts; - rv = cubeb_get_min_latency(app_ctx, output_params, &latency_ms); + rv = cubeb_get_min_latency(app_ctx, output_params, &latency_frames); if (rv != CUBEB_OK) { fprintf(stderr, "Could not get minimum latency"); return rv; @@ -61,7 +61,7 @@ extern "C" { rv = cubeb_stream_init(app_ctx, &stm, "Example Stream 1", NULL, input_params, NULL, output_params, - latency_ms, + latency_frames, data_cb, state_cb, NULL); if (rv != CUBEB_OK) { @@ -284,8 +284,8 @@ typedef struct { unsigned int max_rate; /**< Maximum sample rate supported. */ unsigned int min_rate; /**< Minimum sample rate supported. */ - unsigned int latency_lo_ms; /**< Lowest possible latency in milliseconds. */ - unsigned int latency_hi_ms; /**< Higest possible latency in milliseconds. */ + unsigned int latency_lo; /**< Lowest possible latency in frames. */ + unsigned int latency_hi; /**< Higest possible latency in frames. */ } cubeb_device_info; /** Device collection. */ @@ -363,19 +363,20 @@ char const * cubeb_get_backend_id(cubeb * context); @retval CUBEB_ERROR */ int cubeb_get_max_channel_count(cubeb * context, uint32_t * max_channels); -/** Get the minimal latency value, in milliseconds, that is guaranteed to work +/** Get the minimal latency value, in frames, that is guaranteed to work when creating a stream for the specified sample rate. This is platform, hardware and backend dependant. @param context A pointer to the cubeb context. @param params On some backends, the minimum achievable latency depends on the characteristics of the stream. - @param latency_ms The latency value, in ms, to pass to cubeb_stream_init. + @param latency_frames The latency value, in frames, to pass to + cubeb_stream_init. @retval CUBEB_OK @retval CUBEB_ERROR_INVALID_PARAMETER @retval CUBEB_ERROR_NOT_SUPPORTED */ int cubeb_get_min_latency(cubeb * context, cubeb_stream_params params, - uint32_t * latency_ms); + uint32_t * latency_frames); /** Get the preferred sample rate for this backend: this is hardware and platform dependant, and can avoid resampling, and/or trigger fastpaths. @@ -404,8 +405,8 @@ void cubeb_destroy(cubeb * context); default output device is used. @param output_stream_params Parameters for the output side of the stream, or NULL if this stream is input only. - @param latency Approximate stream latency in milliseconds. Valid range - is [1, 2000]. + @param latency Stream latency in frames. Valid range + is [1, 96000]. @param data_callback Will be called to preroll data before playback is started by cubeb_stream_start. @param state_callback A pointer to a state callback. @@ -422,7 +423,7 @@ int cubeb_stream_init(cubeb * context, cubeb_stream_params * input_stream_params, cubeb_devid output_device, cubeb_stream_params * output_stream_params, - unsigned int latency, + unsigned int latency_frames, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr); diff --git a/media/libcubeb/src/cubeb.c b/media/libcubeb/src/cubeb.c index 2fc3860d7c5d..f89a8f6a5afe 100644 --- a/media/libcubeb/src/cubeb.c +++ b/media/libcubeb/src/cubeb.c @@ -107,7 +107,7 @@ validate_stream_params(cubeb_stream_params * input_stream_params, int validate_latency(int latency) { - if (latency < 1 || latency > 2000) { + if (latency < 1 || latency > 96000) { return CUBEB_ERROR_INVALID_PARAMETER; } return CUBEB_OK; diff --git a/media/libcubeb/src/cubeb_alsa.c b/media/libcubeb/src/cubeb_alsa.c index d9794e0a1108..26ae393131b8 100644 --- a/media/libcubeb/src/cubeb_alsa.c +++ b/media/libcubeb/src/cubeb_alsa.c @@ -774,7 +774,7 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name, cubeb_stream_params * input_stream_params, cubeb_devid output_device, cubeb_stream_params * output_stream_params, - unsigned int latency, + unsigned int latency_frames, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr) { @@ -782,6 +782,8 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name, int r; snd_pcm_format_t format; snd_pcm_uframes_t period_size; + int latency_us = 0; + assert(ctx && stream); @@ -845,16 +847,19 @@ alsa_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name, r = snd_pcm_nonblock(stm->pcm, 1); assert(r == 0); + latency_us = latency_frames * 1e6 / stm->params.rate; + /* Ugly hack: the PA ALSA plugin allows buffer configurations that can't possibly work. See https://bugzilla.mozilla.org/show_bug.cgi?id=761274. Only resort to this hack if the handle_underrun workaround failed. */ if (!ctx->local_config && ctx->is_pa) { - latency = latency < 500 ? 500 : latency; + const int min_latency = 5e5; + latency_us = latency_us < min_latency ? min_latency: latency_us; } r = snd_pcm_set_params(stm->pcm, format, SND_PCM_ACCESS_RW_INTERLEAVED, stm->params.channels, stm->params.rate, 1, - latency * 1000); + latency_us); if (r < 0) { alsa_stream_destroy(stm); return CUBEB_ERROR_INVALID_FORMAT; @@ -999,11 +1004,11 @@ alsa_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) { } static int -alsa_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms) +alsa_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames) { - /* This is found to be an acceptable minimum, even on a super low-end + /* 40ms is found to be an acceptable minimum, even on a super low-end * machine. */ - *latency_ms = 40; + *latency_frames = 40 * params.rate / 1000; return CUBEB_OK; } diff --git a/media/libcubeb/src/cubeb_audiotrack.c b/media/libcubeb/src/cubeb_audiotrack.c index 59e3be2a2402..fe2603405edf 100644 --- a/media/libcubeb/src/cubeb_audiotrack.c +++ b/media/libcubeb/src/cubeb_audiotrack.c @@ -250,9 +250,6 @@ audiotrack_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * l return CUBEB_ERROR; } - /* Convert to milliseconds. */ - *latency_ms = *latency_ms * 1000 / params.rate; - return CUBEB_OK; } diff --git a/media/libcubeb/src/cubeb_audiounit.c b/media/libcubeb/src/cubeb_audiounit.cpp similarity index 83% rename from media/libcubeb/src/cubeb_audiounit.c rename to media/libcubeb/src/cubeb_audiounit.cpp index e2a934129e50..22a42ca6163f 100644 --- a/media/libcubeb/src/cubeb_audiounit.c +++ b/media/libcubeb/src/cubeb_audiounit.cpp @@ -27,6 +27,8 @@ #endif #include "cubeb_resampler.h" #include "cubeb_ring_array.h" +#include "cubeb_utils.h" +#include #if !defined(kCFCoreFoundationVersionNumber10_7) /* From CoreFoundation CFBase.h */ @@ -65,10 +67,16 @@ typedef UInt32 AudioFormatFlags; #define LOG(...) #endif -static struct cubeb_ops const audiounit_ops; + +/* Testing empirically, some headsets report a minimal latency that is very + * low, but this does not work in practice. Lie and say the minimum is 256 + * frames. */ +const uint32_t SAFE_MIN_LATENCY_FRAMES = 256; + +extern cubeb_ops const audiounit_ops; struct cubeb { - struct cubeb_ops const * ops; + cubeb_ops const * ops; pthread_mutex_t mutex; int active_streams; int limit_streams; @@ -80,6 +88,65 @@ struct cubeb { AudioObjectID * devtype_device_array; }; +class auto_array_wrapper +{ +public: + explicit auto_array_wrapper(auto_array * ar) + : float_ar(ar) + , short_ar(nullptr) + {assert((float_ar && !short_ar) || (!float_ar && short_ar));} + + explicit auto_array_wrapper(auto_array * ar) + : float_ar(nullptr) + , short_ar(ar) + {assert((float_ar && !short_ar) || (!float_ar && short_ar));} + + ~auto_array_wrapper() { + assert((float_ar && !short_ar) || (!float_ar && short_ar)); + delete float_ar; + delete short_ar; + } + + void push(void * elements, size_t length){ + assert((float_ar && !short_ar) || (!float_ar && short_ar)); + if (float_ar) + return float_ar->push(static_cast(elements), length); + return short_ar->push(static_cast(elements), length); + } + + size_t length() const { + assert((float_ar && !short_ar) || (!float_ar && short_ar)); + if (float_ar) + return float_ar->length(); + return short_ar->length(); + } + + void push_silence(size_t length) { + assert((float_ar && !short_ar) || (!float_ar && short_ar)); + if (float_ar) + return float_ar->push_silence(length); + return short_ar->push_silence(length); + } + + bool pop(void * elements, size_t length) { + assert((float_ar && !short_ar) || (!float_ar && short_ar)); + if (float_ar) + return float_ar->pop(static_cast(elements), length); + return short_ar->pop(static_cast(elements), length); + } + + void * data() const { + assert((float_ar && !short_ar) || (!float_ar && short_ar)); + if (float_ar) + return float_ar->data(); + return short_ar->data(); + } + +private: + auto_array * float_ar; + auto_array * short_ar; +}; + struct cubeb_stream { cubeb * context; cubeb_data_callback data_callback; @@ -98,7 +165,7 @@ struct cubeb_stream { pthread_mutex_t mutex; /* Hold the input samples in every * input callback iteration */ - ring_array input_buffer_array; + auto_array_wrapper * input_linear_buffer; /* Frames on input buffer */ uint32_t input_buffer_frames; /* Frame counters */ @@ -158,38 +225,18 @@ audiounit_make_silent(AudioBuffer * ioData) } static OSStatus -audiounit_input_callback(void * user_ptr, - AudioUnitRenderActionFlags * flags, - AudioTimeStamp const * tstamp, - UInt32 bus, - UInt32 input_frames, - AudioBufferList * bufs) +audiounit_render_input(cubeb_stream * stm, + AudioUnitRenderActionFlags * flags, + AudioTimeStamp const * tstamp, + UInt32 bus, + UInt32 input_frames) { - cubeb_stream * stm = user_ptr; - long outframes, frames; - - pthread_mutex_lock(&stm->mutex); - - assert(stm->input_unit != NULL); - assert(AU_IN_BUS == bus); - - if (stm->shutdown) { - pthread_mutex_unlock(&stm->mutex); - return noErr; - } - - /* Get next store buffer from ring array */ - AudioBuffer * input_buffer = ring_array_get_free_buffer(&stm->input_buffer_array); - if (input_buffer == NULL) { - LOG("input: Ring array is full drop one buffer\n"); - ring_array_get_data_buffer(&stm->input_buffer_array); - - input_buffer = ring_array_get_free_buffer(&stm->input_buffer_array); - assert(input_buffer); - } - + /* Create the AudioBufferList to store input. */ AudioBufferList input_buffer_list; - input_buffer_list.mBuffers[0] = *input_buffer; + input_buffer_list.mBuffers[0].mDataByteSize = + stm->input_desc.mBytesPerFrame * stm->input_buffer_frames; + input_buffer_list.mBuffers[0].mData = nullptr; + input_buffer_list.mBuffers[0].mNumberChannels = stm->input_desc.mChannelsPerFrame; input_buffer_list.mNumberBuffers = 1; /* Render input samples */ @@ -199,21 +246,57 @@ audiounit_input_callback(void * user_ptr, bus, input_frames, &input_buffer_list); + if (r != noErr) { - LOG("Input AudioUnitRender failed with error=%d", r); - audiounit_make_silent(input_buffer); + LOG("Input AudioUnitRender failed with error=%d\n", r); + audiounit_make_silent(&input_buffer_list.mBuffers[0]); return r; } + /* Copy input data in linear buffer. */ + stm->input_linear_buffer->push(input_buffer_list.mBuffers[0].mData, + input_frames * stm->input_desc.mChannelsPerFrame); + LOG("- input: buffers %d, size %d, channels %d, frames %d\n", input_buffer_list.mNumberBuffers, input_buffer_list.mBuffers[0].mDataByteSize, input_buffer_list.mBuffers[0].mNumberChannels, input_frames); + /* Advance input frame counter. */ assert(input_frames > 0); stm->frames_read += input_frames; + return noErr; +} + +static OSStatus +audiounit_input_callback(void * user_ptr, + AudioUnitRenderActionFlags * flags, + AudioTimeStamp const * tstamp, + UInt32 bus, + UInt32 input_frames, + AudioBufferList * bufs) +{ + cubeb_stream * stm = static_cast(user_ptr); + long outframes, frames; + + pthread_mutex_lock(&stm->mutex); + + assert(stm->input_unit != NULL); + assert(AU_IN_BUS == bus); + + if (stm->shutdown) { + LOG("- input shutdown\n"); + pthread_mutex_unlock(&stm->mutex); + return noErr; + } + + OSStatus r = audiounit_render_input(stm, flags, tstamp, bus, input_frames); + if (r != noErr) { + return r; + } + // Full Duplex. We'll call data_callback in the AudioUnit output callback. if (stm->output_unit != NULL) { // User callback will be called by output callback @@ -224,13 +307,14 @@ audiounit_input_callback(void * user_ptr, /* Input only. Call the user callback through resampler. Resampler will deliver input buffer in the correct rate. */ frames = input_frames; - input_buffer = ring_array_get_data_buffer(&stm->input_buffer_array); - assert(input_buffer && "fetch buffer is null in the input"); + assert(input_frames <= stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame); outframes = cubeb_resampler_fill(stm->resampler, - input_buffer->mData, + stm->input_linear_buffer->data(), &frames, NULL, 0); + // Reset input buffer + stm->input_linear_buffer->pop(nullptr, frames * stm->input_desc.mChannelsPerFrame); if (outframes < 0 || outframes != input_frames) { stm->shutdown = 1; @@ -253,7 +337,7 @@ audiounit_output_callback(void * user_ptr, assert(AU_OUT_BUS == bus); assert(outBufferList->mNumberBuffers == 1); - cubeb_stream * stm = user_ptr; + cubeb_stream * stm = static_cast(user_ptr); LOG("- output(%p): buffers %d, size %d, channels %d, frames %d\n", stm, outBufferList->mNumberBuffers, outBufferList->mBuffers[0].mDataByteSize, @@ -265,6 +349,7 @@ audiounit_output_callback(void * user_ptr, pthread_mutex_lock(&stm->mutex); if (stm->shutdown) { + LOG("- output shutdown\n"); audiounit_make_silent(&outBufferList->mBuffers[0]); pthread_mutex_unlock(&stm->mutex); return noErr; @@ -286,33 +371,22 @@ audiounit_output_callback(void * user_ptr, /* Get output buffer. */ output_buffer = outBufferList->mBuffers[0].mData; /* If Full duplex get also input buffer */ - AudioBuffer * input_aud_buf = NULL; if (stm->input_unit != NULL) { /* Output callback came first */ if (stm->frames_read == 0) { LOG("Output callback came first send silent.\n"); - audiounit_make_silent(&outBufferList->mBuffers[0]); - pthread_mutex_unlock(&stm->mutex); - return noErr; + stm->input_linear_buffer->push_silence(stm->input_buffer_frames * + stm->input_desc.mChannelsPerFrame); } /* Input samples stored previously in input callback. */ - input_aud_buf = ring_array_get_data_buffer(&stm->input_buffer_array); - if (input_aud_buf == NULL) { - LOG("Requested more output than input. " - "This is either a hole or we are after a stream stop and input thread stopped before output\n"); - /* Provide silent input. Other than that we could provide silent output and exit without - * calling user callback. I do not prefer it because the user loose the control of - * the output. Also resampler loose frame counting and produce less frame than - * expected at some point in the future breaking an assert. */ - - /* Avoid here to allocate new memory since we are inside callback. Use the existing - * allocated buffers since the ring array is empty and the buffer is not used. */ - input_aud_buf = ring_array_get_dummy_buffer(&stm->input_buffer_array); - audiounit_make_silent(input_aud_buf); + if (stm->input_linear_buffer->length() == 0) { + /* Do nothing, there should be enough pre-buffered data to consume. */ + LOG("Input hole. Requested more input than ouput.\n"); } - input_buffer = input_aud_buf->mData; - input_frames = stm->input_buffer_frames; - assert(stm->frames_read > 0); + // The input buffer + input_buffer = stm->input_linear_buffer->data(); + // Number of input frames in the buffer + input_frames = stm->input_linear_buffer->length() / stm->input_desc.mChannelsPerFrame; } /* Call user callback through resampler. */ @@ -322,9 +396,8 @@ audiounit_output_callback(void * user_ptr, output_buffer, output_frames); - /* Cleanup the input buffer to make sure that we have fresh data. */ if (input_buffer) { - audiounit_make_silent(input_aud_buf); + stm->input_linear_buffer->pop(nullptr, input_frames * stm->input_desc.mChannelsPerFrame); } if (outframes < 0) { @@ -358,7 +431,8 @@ audiounit_output_callback(void * user_ptr, return noErr; } -/*static*/ int +extern "C" { +int audiounit_init(cubeb ** context, char const * context_name) { cubeb * ctx; @@ -366,8 +440,9 @@ audiounit_init(cubeb ** context, char const * context_name) *context = NULL; - ctx = calloc(1, sizeof(*ctx)); + ctx = new cubeb; assert(ctx); + PodZero(ctx, 1); ctx->ops = &audiounit_ops; @@ -385,6 +460,7 @@ audiounit_init(cubeb ** context, char const * context_name) return CUBEB_OK; } +} static char const * audiounit_get_backend_id(cubeb * ctx) @@ -700,7 +776,7 @@ audiounit_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) } static int -audiounit_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms) +audiounit_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames) { #if TARGET_OS_IPHONE //TODO: [[AVAudioSession sharedInstance] inputLatency] @@ -711,7 +787,8 @@ audiounit_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * la return CUBEB_ERROR; } - *latency_ms = (latency_range.mMinimum * 1000 + params.rate - 1) / params.rate; + *latency_frames = std::max(latency_range.mMinimum, + SAFE_MIN_LATENCY_FRAMES); #endif return CUBEB_OK; @@ -750,7 +827,7 @@ audiounit_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) return CUBEB_ERROR; } - *rate = (uint32_t)fsamplerate; + *rate = static_cast(fsamplerate); #endif return CUBEB_OK; } @@ -773,7 +850,7 @@ audiounit_destroy(cubeb * ctx) int r = pthread_mutex_destroy(&ctx->mutex); assert(r == 0); - free(ctx); + delete ctx; } static void audiounit_stream_destroy(cubeb_stream * stm); @@ -862,7 +939,7 @@ audiounit_create_unit(AudioUnit * unit, devid = audiounit_get_default_device_id(is_input ? CUBEB_DEVICE_TYPE_INPUT : CUBEB_DEVICE_TYPE_OUTPUT); } else { - devid = (AudioDeviceID)device; + devid = reinterpret_cast(device); } int err = AudioUnitSetProperty(*unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, @@ -876,21 +953,42 @@ audiounit_create_unit(AudioUnit * unit, } static int -audiounit_init_input_buffer_array(cubeb_stream * stream, uint32_t capacity) +audiounit_init_input_linear_buffer(cubeb_stream * stream, uint32_t capacity) { - int r = ring_array_init(&stream->input_buffer_array, - capacity, - stream->input_desc.mBytesPerFrame, - stream->input_desc.mChannelsPerFrame, - stream->input_buffer_frames); + if (stream->input_desc.mFormatFlags == kAudioFormatFlagIsSignedInteger) { + stream->input_linear_buffer = new auto_array_wrapper( + new auto_array(capacity * + stream->input_buffer_frames * + stream->input_desc.mChannelsPerFrame) ); + } else { + stream->input_linear_buffer = new auto_array_wrapper( + new auto_array(capacity * + stream->input_buffer_frames * + stream->input_desc.mChannelsPerFrame) ); + } - return r; + if (!stream->input_linear_buffer) { + return CUBEB_ERROR; + } + + assert(stream->input_linear_buffer->length() == 0); + + // Pre-buffer silence if needed + if (capacity != 1) { + size_t silence_size = stream->input_buffer_frames * + stream->input_desc.mChannelsPerFrame; + stream->input_linear_buffer->push_silence(silence_size); + + assert(stream->input_linear_buffer->length() == silence_size); + } + + return CUBEB_OK; } static void -audiounit_destroy_input_buffer_array(cubeb_stream * stream) +audiounit_destroy_input_linear_buffer(cubeb_stream * stream) { - ring_array_destroy(&stream->input_buffer_array); + delete stream->input_linear_buffer; } static int @@ -901,7 +999,7 @@ audiounit_stream_init(cubeb * context, cubeb_stream_params * input_stream_params, cubeb_devid output_device, cubeb_stream_params * output_stream_params, - unsigned int latency, + unsigned int latency_frames, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr) @@ -945,8 +1043,9 @@ audiounit_stream_init(cubeb * context, } } - stm = calloc(1, sizeof(cubeb_stream)); + stm = new cubeb_stream; assert(stm); + PodZero(stm, 1); /* These could be different in the future if we have both * full-duplex stream and different devices for input vs output. */ @@ -968,29 +1067,36 @@ audiounit_stream_init(cubeb * context, /* Init data members where necessary */ stm->hw_latency_frames = UINT64_MAX; + /* Silently clamp the latency down to the platform default, because we + * synthetize the clock from the callbacks, and we want the clock to update + * often. */ + + UInt32 default_frame_count; + size = sizeof(default_frame_count); + if (stm->output_unit) { + if (AudioUnitGetProperty(stm->output_unit, kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Output, 0, &default_frame_count, &size) != 0) { + audiounit_stream_destroy(stm); + return CUBEB_ERROR; + } + } else { + if (AudioUnitGetProperty(stm->input_unit, kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Input, 0, &default_frame_count, &size) != 0) { + audiounit_stream_destroy(stm); + return CUBEB_ERROR; + } + } + + LOG("Default buffer size: %u frames\n", default_frame_count); + + latency_frames = std::max(std::min(latency_frames, + default_frame_count), + SAFE_MIN_LATENCY_FRAMES); + + LOG("Clamped buffer size: %u frames\n", latency_frames); + /* Setup Input Stream! */ if (input_stream_params != NULL) { - size = sizeof(UInt32); - if (AudioUnitGetProperty(stm->input_unit, - kAudioDevicePropertyBufferFrameSize, - kAudioUnitScope_Input, - AU_IN_BUS, - &stm->input_buffer_frames, - &size) != 0) { - audiounit_stream_destroy(stm); - return CUBEB_ERROR; - } - - if (AudioUnitSetProperty(stm->input_unit, - kAudioDevicePropertyBufferFrameSize, - kAudioUnitScope_Output, - AU_IN_BUS, - &stm->input_buffer_frames, - size) != 0) { - audiounit_stream_destroy(stm); - return CUBEB_ERROR; - } - /* Get input device sample rate. */ AudioStreamBasicDescription input_hw_desc; size = sizeof(AudioStreamBasicDescription); @@ -1012,6 +1118,23 @@ audiounit_stream_init(cubeb * context, return r; } + // Use latency to calculate buffer size + if (stm->input_hw_rate == input_stream_params->rate) { + stm->input_buffer_frames = latency_frames; + } else { + stm->input_buffer_frames = (latency_frames * stm->input_hw_rate) / input_stream_params->rate; + } + LOG("Calculated input number of frames %u for latency %u\n", stm->input_buffer_frames, latency_frames); + if (AudioUnitSetProperty(stm->input_unit, + kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Output, + AU_IN_BUS, + &stm->input_buffer_frames, + sizeof(UInt32)) != 0) { + audiounit_stream_destroy(stm); + return CUBEB_ERROR; + } + AudioStreamBasicDescription src_desc = stm->input_desc; /* Input AudioUnit must be configured with device's sample rate. we will resample inside input callback. */ @@ -1044,7 +1167,7 @@ audiounit_stream_init(cubeb * context, // Full-duplex increase capacity array_capacity = 8; } - if (audiounit_init_input_buffer_array(stm, array_capacity) != CUBEB_OK) { + if (audiounit_init_input_linear_buffer(stm, array_capacity) != CUBEB_OK) { audiounit_stream_destroy(stm); return CUBEB_ERROR; } @@ -1072,6 +1195,20 @@ audiounit_stream_init(cubeb * context, return r; } + /* Get output device sample rate. */ + AudioStreamBasicDescription output_hw_desc; + size = sizeof(AudioStreamBasicDescription); + memset(&output_hw_desc, 0, size); + if (AudioUnitGetProperty(stm->output_unit, + kAudioUnitProperty_StreamFormat, + kAudioUnitScope_Output, + AU_OUT_BUS, + &output_hw_desc, + &size) != 0) { + audiounit_stream_destroy(stm); + return CUBEB_ERROR; + } + if (AudioUnitSetProperty(stm->output_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, @@ -1082,6 +1219,27 @@ audiounit_stream_init(cubeb * context, return CUBEB_ERROR; } + // Use latency to set number of frames in out buffer. Use the + // device sampling rate, internal resampler of audiounit will + // calculate the expected number of frames. + // Use latency to calculate buffer size + uint32_t output_buffer_frames = 0; + if (output_hw_desc.mSampleRate == output_stream_params->rate) { + output_buffer_frames = latency_frames; + } else { + output_buffer_frames = (latency_frames * output_hw_desc.mSampleRate) / output_stream_params->rate; + } + LOG("Calculated output number of frames %u for latency %u\n", output_buffer_frames, latency_frames); + if (AudioUnitSetProperty(stm->output_unit, + kAudioDevicePropertyBufferFrameSize, + kAudioUnitScope_Input, + AU_OUT_BUS, + &output_buffer_frames, + sizeof(output_buffer_frames)) != 0) { + audiounit_stream_destroy(stm); + return CUBEB_ERROR; + } + assert(stm->output_unit != NULL); aurcbs_out.inputProc = audiounit_output_callback; aurcbs_out.inputProcRefCon = stm; @@ -1100,7 +1258,7 @@ audiounit_stream_init(cubeb * context, // Setting the latency doesn't work well for USB headsets (eg. plantronics). // Keep the default latency for now. #if 0 - buffer_size = latency / 1000.0 * ss.mSampleRate; + buffer_size = latency; /* Get the range of latency this particular device can work with, and clamp * the requested latency to this acceptable range. */ @@ -1203,7 +1361,7 @@ audiounit_stream_destroy(cubeb_stream * stm) AudioComponentInstanceDispose(stm->input_unit); } - audiounit_destroy_input_buffer_array(stm); + audiounit_destroy_input_linear_buffer(stm); if (stm->output_unit != NULL) { AudioOutputUnitStop(stm->output_unit); @@ -1225,7 +1383,7 @@ audiounit_stream_destroy(cubeb_stream * stm) stm->context->active_streams -= 1; pthread_mutex_unlock(&stm->context->mutex); - free(stm); + delete stm; } static int @@ -1347,7 +1505,7 @@ audiounit_stream_get_latency(cubeb_stream * stm, uint32_t * latency) /* This part is fixed and depend on the stream parameter and the hardware. */ stm->hw_latency_frames = - (uint32_t)(unit_latency_sec * stm->output_desc.mSampleRate) + static_cast(unit_latency_sec * stm->output_desc.mSampleRate) + device_latency_frames + device_safety_offset; } @@ -1419,10 +1577,11 @@ int audiounit_stream_get_current_device(cubeb_stream * stm, return CUBEB_ERROR; } - *device = malloc(sizeof(cubeb_device)); + *device = new cubeb_device; if (!*device) { return CUBEB_ERROR; } + PodZero(*device, 1); size = sizeof(UInt32); /* This fails with some USB headset, so simply return an empty string. */ @@ -1434,12 +1593,7 @@ int audiounit_stream_get_current_device(cubeb_stream * stm, data = 0; } - (*device)->output_name = malloc(size + 1); - if (!(*device)->output_name) { - return CUBEB_ERROR; - } - - (*device)->output_name = malloc(size + 1); + (*device)->output_name = new char[size + 1]; if (!(*device)->output_name) { return CUBEB_ERROR; } @@ -1465,7 +1619,7 @@ int audiounit_stream_get_current_device(cubeb_stream * stm, data = 0; } - (*device)->input_name = malloc(size + 1); + (*device)->input_name = new char[size + 1]; if (!(*device)->input_name) { return CUBEB_ERROR; } @@ -1486,9 +1640,9 @@ int audiounit_stream_get_current_device(cubeb_stream * stm, int audiounit_stream_device_destroy(cubeb_stream * stream, cubeb_device * device) { - free(device->output_name); - free(device->input_name); - free(device); + delete [] device->output_name; + delete [] device->input_name; + delete device; return CUBEB_OK; } @@ -1528,17 +1682,17 @@ audiounit_get_devices(AudioObjectID ** devices, uint32_t * count) return ret; } - *count = (uint32_t)(size / sizeof(AudioObjectID)); + *count = static_cast(size / sizeof(AudioObjectID)); if (size >= sizeof(AudioObjectID)) { if (*devices != NULL) { - free(*devices); + delete [] (*devices); } - *devices = malloc(size); - memset(*devices, 0, size); + *devices = new AudioObjectID[*count]; + PodZero(*devices, *count); ret = AudioObjectGetPropertyData(kAudioObjectSystemObject, &adr, 0, NULL, &size, (void *)*devices); if (ret != noErr) { - free(*devices); + delete [] (*devices); *devices = NULL; } } else { @@ -1560,10 +1714,10 @@ audiounit_strref_to_cstr_utf8(CFStringRef strref) len = CFStringGetLength(strref); size = CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8); - ret = malloc(size); + ret = new char[size]; if (!CFStringGetCString(strref, ret, size, kCFStringEncodingUTF8)) { - free(ret); + delete [] ret; ret = NULL; } @@ -1580,7 +1734,7 @@ audiounit_get_channel_count(AudioObjectID devid, AudioObjectPropertyScope scope) adr.mSelector = kAudioDevicePropertyStreamConfiguration; if (AudioObjectGetPropertyDataSize(devid, &adr, 0, NULL, &size) == noErr && size > 0) { - AudioBufferList * list = alloca(size); + AudioBufferList * list = static_cast(alloca(size)); if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, list) == noErr) { for (i = 0; i < list->mNumberBuffers; i++) ret += list->mBuffers[i].mNumberChannels; @@ -1611,7 +1765,7 @@ audiounit_get_available_samplerate(AudioObjectID devid, AudioObjectPropertyScope if (AudioObjectHasProperty(devid, &adr) && AudioObjectGetPropertyDataSize(devid, &adr, 0, NULL, &size) == noErr) { uint32_t i, count = size / sizeof(AudioValueRange); - AudioValueRange * ranges = malloc(size); + AudioValueRange * ranges = new AudioValueRange[count]; range.mMinimum = 9999999999.0; range.mMaximum = 0.0; if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, ranges) == noErr) { @@ -1622,9 +1776,9 @@ audiounit_get_available_samplerate(AudioObjectID devid, AudioObjectPropertyScope range.mMinimum = ranges[i].mMinimum; } } - free(ranges); - *max = (uint32_t)range.mMaximum; - *min = (uint32_t)range.mMinimum; + delete [] ranges; + *max = static_cast(range.mMaximum); + *min = static_cast(range.mMinimum); } else { *min = *max = 0; } @@ -1683,7 +1837,8 @@ audiounit_create_device_from_hwdev(AudioObjectID devid, cubeb_device_type type) return NULL; } - ret = calloc(1, sizeof(cubeb_device_info)); + ret = new cubeb_device_info; + PodZero(ret, 1); size = sizeof(CFStringRef); adr.mSelector = kAudioDevicePropertyDeviceUID; @@ -1733,7 +1888,7 @@ audiounit_create_device_from_hwdev(AudioObjectID devid, cubeb_device_type type) CUBEB_DEVICE_PREF_ALL : CUBEB_DEVICE_PREF_NONE; ret->max_channels = ch; - ret->format = CUBEB_DEVICE_FMT_ALL; /* CoreAudio supports All! */ + ret->format = (cubeb_device_fmt)CUBEB_DEVICE_FMT_ALL; /* CoreAudio supports All! */ /* kAudioFormatFlagsAudioUnitCanonical is deprecated, prefer floating point */ ret->default_format = CUBEB_DEVICE_FMT_F32NE; audiounit_get_available_samplerate(devid, adr.mScope, @@ -1744,11 +1899,11 @@ audiounit_create_device_from_hwdev(AudioObjectID devid, cubeb_device_type type) adr.mSelector = kAudioDevicePropertyBufferFrameSizeRange; size = sizeof(AudioValueRange); if (AudioObjectGetPropertyData(devid, &adr, 0, NULL, &size, &range) == noErr) { - ret->latency_lo_ms = ((latency + range.mMinimum) * 1000) / ret->default_rate; - ret->latency_hi_ms = ((latency + range.mMaximum) * 1000) / ret->default_rate; + ret->latency_lo = latency + range.mMinimum; + ret->latency_hi = latency + range.mMaximum; } else { - ret->latency_lo_ms = 10; /* Default to 10ms */ - ret->latency_hi_ms = 100; /* Default to 100ms */ + ret->latency_lo = 10 * ret->default_rate / 1000; /* Default to 10ms */ + ret->latency_hi = 100 * ret->default_rate / 1000; /* Default to 100ms */ } return ret; @@ -1766,8 +1921,8 @@ audiounit_enumerate_devices(cubeb * context, cubeb_device_type type, return CUBEB_ERROR; } - *collection = malloc(sizeof(cubeb_device_collection) + - sizeof(cubeb_device_info*) * (hwdevcount > 0 ? hwdevcount - 1 : 0)); + *collection = static_cast(malloc(sizeof(cubeb_device_collection) + + sizeof(cubeb_device_info*) * (hwdevcount > 0 ? hwdevcount - 1 : 0))); (*collection)->count = 0; if (hwdevcount > 0) { @@ -1788,7 +1943,7 @@ audiounit_enumerate_devices(cubeb * context, cubeb_device_type type, } } - free(hwdevs); + delete [] hwdevs; return CUBEB_OK; } @@ -1825,7 +1980,7 @@ audiounit_get_devices_of_type(cubeb_device_type devtype, AudioObjectID ** devid_ if (devtype == (CUBEB_DEVICE_TYPE_INPUT | CUBEB_DEVICE_TYPE_OUTPUT)) { if (devid_array) { - *devid_array = calloc(count, sizeof(AudioObjectID)); + *devid_array = new AudioObjectID[count]; assert(*devid_array); memcpy(*devid_array, &devices, count * sizeof(AudioObjectID)); } @@ -1847,7 +2002,7 @@ audiounit_get_devices_of_type(cubeb_device_type devtype, AudioObjectID ** devid_ } if (devid_array && dev_count > 0) { - *devid_array = calloc(dev_count, sizeof(AudioObjectID)); + *devid_array = static_cast(calloc(dev_count, sizeof(AudioObjectID))); assert(*devid_array); memcpy(*devid_array, &devices_in_scope, dev_count * sizeof(AudioObjectID)); } @@ -1872,7 +2027,7 @@ audiounit_collection_changed_callback(AudioObjectID inObjectID, const AudioObjectPropertyAddress * inAddresses, void * inClientData) { - cubeb * context = inClientData; + cubeb * context = static_cast(inClientData); pthread_mutex_lock(&context->mutex); if (context->collection_changed_callback == NULL) { /* Listener removed while waiting in mutex, abort. */ @@ -1889,14 +2044,14 @@ audiounit_collection_changed_callback(AudioObjectID inObjectID, if (context->devtype_device_count == new_number_of_devices && audiounit_equal_arrays(devices, context->devtype_device_array, new_number_of_devices)) { /* Device changed for the other scope, ignore. */ - free(devices); + delete [] devices; pthread_mutex_unlock(&context->mutex); return noErr; } /* Device on desired scope changed, reset counter and array. */ context->devtype_device_count = new_number_of_devices; /* Free the old array before replace. */ - free(context->devtype_device_array); + delete [] context->devtype_device_array; context->devtype_device_array = devices; } @@ -1957,12 +2112,12 @@ audiounit_remove_device_listener(cubeb * context) context); if (ret == noErr) { /* Reset all values. */ - context->collection_changed_devtype = 0; + context->collection_changed_devtype = CUBEB_DEVICE_TYPE_UNKNOWN; context->collection_changed_callback = NULL; context->collection_changed_user_ptr = NULL; context->devtype_device_count = 0; if (context->devtype_device_array) { - free(context->devtype_device_array); + delete [] context->devtype_device_array; context->devtype_device_array = NULL; } } @@ -1987,24 +2142,24 @@ int audiounit_register_device_collection_changed(cubeb * context, return (ret == noErr) ? CUBEB_OK : CUBEB_ERROR; } -static struct cubeb_ops const audiounit_ops = { - .init = audiounit_init, - .get_backend_id = audiounit_get_backend_id, - .get_max_channel_count = audiounit_get_max_channel_count, - .get_min_latency = audiounit_get_min_latency, - .get_preferred_sample_rate = audiounit_get_preferred_sample_rate, - .enumerate_devices = audiounit_enumerate_devices, - .destroy = audiounit_destroy, - .stream_init = audiounit_stream_init, - .stream_destroy = audiounit_stream_destroy, - .stream_start = audiounit_stream_start, - .stream_stop = audiounit_stream_stop, - .stream_get_position = audiounit_stream_get_position, - .stream_get_latency = audiounit_stream_get_latency, - .stream_set_volume = audiounit_stream_set_volume, - .stream_set_panning = audiounit_stream_set_panning, - .stream_get_current_device = audiounit_stream_get_current_device, - .stream_device_destroy = audiounit_stream_device_destroy, - .stream_register_device_changed_callback = audiounit_stream_register_device_changed_callback, - .register_device_collection_changed = audiounit_register_device_collection_changed +cubeb_ops const audiounit_ops = { + /*.init =*/ audiounit_init, + /*.get_backend_id =*/ audiounit_get_backend_id, + /*.get_max_channel_count =*/ audiounit_get_max_channel_count, + /*.get_min_latency =*/ audiounit_get_min_latency, + /*.get_preferred_sample_rate =*/ audiounit_get_preferred_sample_rate, + /*.enumerate_devices =*/ audiounit_enumerate_devices, + /*.destroy =*/ audiounit_destroy, + /*.stream_init =*/ audiounit_stream_init, + /*.stream_destroy =*/ audiounit_stream_destroy, + /*.stream_start =*/ audiounit_stream_start, + /*.stream_stop =*/ audiounit_stream_stop, + /*.stream_get_position =*/ audiounit_stream_get_position, + /*.stream_get_latency =*/ audiounit_stream_get_latency, + /*.stream_set_volume =*/ audiounit_stream_set_volume, + /*.stream_set_panning =*/ audiounit_stream_set_panning, + /*.stream_get_current_device =*/ audiounit_stream_get_current_device, + /*.stream_device_destroy =*/ audiounit_stream_device_destroy, + /*.stream_register_device_changed_callback =*/ audiounit_stream_register_device_changed_callback, + /*.register_device_collection_changed =*/ audiounit_register_device_collection_changed }; diff --git a/media/libcubeb/src/cubeb_jack.cpp b/media/libcubeb/src/cubeb_jack.cpp index 265dc79f5c6e..8f32f3dfe2a1 100644 --- a/media/libcubeb/src/cubeb_jack.cpp +++ b/media/libcubeb/src/cubeb_jack.cpp @@ -85,8 +85,8 @@ extern "C" } static char const * cbjack_get_backend_id(cubeb * context); static int cbjack_get_max_channel_count(cubeb * ctx, uint32_t * max_channels); -static int cbjack_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms); -static int cbjack_get_latency(cubeb_stream * stm, unsigned int * latency_ms); +static int cbjack_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames); +static int cbjack_get_latency(cubeb_stream * stm, unsigned int * latency_frames); static int cbjack_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate); static void cbjack_destroy(cubeb * context); static void cbjack_interleave_capture(cubeb_stream * stream, float **in, jack_nframes_t nframes, bool format_mismatch); @@ -102,7 +102,7 @@ static int cbjack_stream_init(cubeb * context, cubeb_stream ** stream, char cons cubeb_stream_params * input_stream_params, cubeb_devid output_device, cubeb_stream_params * output_stream_params, - unsigned int latency, + unsigned int latency_frames, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr); @@ -307,10 +307,8 @@ cbjack_graph_order_callback(void * arg) max_latency = 128; } - if (cbjack_get_preferred_sample_rate(ctx, &rate) == CUBEB_ERROR) - ctx->jack_latency = (max_latency * 1000) / 48000; - else - ctx->jack_latency = (max_latency * 1000) / rate; + ctx->jack_latency = max_latency; + return 0; } @@ -705,7 +703,7 @@ cbjack_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_ cubeb_stream_params * input_stream_params, cubeb_devid output_device, cubeb_stream_params * output_stream_params, - unsigned int latency, + unsigned int latency_frames, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr) @@ -999,8 +997,8 @@ cbjack_enumerate_devices(cubeb * context, cubeb_device_type type, context->devinfo[i]->min_rate = rate; context->devinfo[i]->max_rate = rate; context->devinfo[i]->default_rate = rate; - context->devinfo[i]->latency_lo_ms = 1; - context->devinfo[i]->latency_hi_ms = 10; + context->devinfo[i]->latency_lo = 0; + context->devinfo[i]->latency_hi = 0; i++; } @@ -1020,8 +1018,8 @@ cbjack_enumerate_devices(cubeb * context, cubeb_device_type type, context->devinfo[i]->min_rate = rate; context->devinfo[i]->max_rate = rate; context->devinfo[i]->default_rate = rate; - context->devinfo[i]->latency_lo_ms = 1; - context->devinfo[i]->latency_hi_ms = 10; + context->devinfo[i]->latency_lo = 0; + context->devinfo[i]->latency_hi = 0; i++; } diff --git a/media/libcubeb/src/cubeb_opensl.c b/media/libcubeb/src/cubeb_opensl.c index ec0639cfabf3..d44a56bd7ae8 100644 --- a/media/libcubeb/src/cubeb_opensl.c +++ b/media/libcubeb/src/cubeb_opensl.c @@ -425,7 +425,7 @@ opensl_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) } static int -opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms) +opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames) { /* https://android.googlesource.com/platform/ndk.git/+/master/docs/opensles/index.html * We don't want to deal with JNI here (and we don't have Java on b2g anyways), @@ -475,7 +475,7 @@ opensl_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten /* To get a fast track in Android's mixer, we need to be at the native * samplerate, which is device dependant. Some devices might be able to * resample when playing a fast track, but it's pretty rare. */ - *latency_ms = NBUFS * primary_buffer_size / (primary_sampling_rate / 1000); + *latency_frames = NBUFS * primary_buffer_size; dlclose(libmedia); @@ -502,7 +502,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name cubeb_stream_params * input_stream_params, cubeb_devid output_device, cubeb_stream_params * output_stream_params, - unsigned int latency, + unsigned int latency_frames, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr) { @@ -517,11 +517,6 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name *stream = NULL; - if (output_stream_params->channels < 1 || output_stream_params->channels > 32 || - latency < 1 || latency > 2000) { - return CUBEB_ERROR_INVALID_FORMAT; - } - SLDataFormat_PCM format; format.formatType = SL_DATAFORMAT_PCM; @@ -554,7 +549,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name stm->user_ptr = user_ptr; stm->inputrate = output_stream_params->rate; - stm->latency = latency; + stm->latency = latency_frames; stm->stream_type = output_stream_params->stream_type; stm->framesize = output_stream_params->channels * sizeof(int16_t); stm->lastPosition = -1; @@ -594,11 +589,11 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name if (get_android_version() >= ANDROID_VERSION_MARSHMALLOW) { // Reset preferred samping rate to trigger fallback to native sampling rate. preferred_sampling_rate = 0; - if (opensl_get_min_latency(ctx, *output_stream_params, &latency) != CUBEB_OK) { + if (opensl_get_min_latency(ctx, *output_stream_params, &latency_frames) != CUBEB_OK) { // Default to AudioFlinger's advertised fast track latency of 10ms. - latency = 10; + latency_frames = 440; } - stm->latency = latency; + stm->latency = latency_frames; } #endif @@ -627,7 +622,7 @@ opensl_stream_init(cubeb * ctx, cubeb_stream ** stream, char const * stream_name stm->outputrate = preferred_sampling_rate; stm->bytespersec = stm->outputrate * stm->framesize; - stm->queuebuf_len = (stm->bytespersec * latency) / (1000 * NBUFS); + stm->queuebuf_len = stm->framesize * latency_frames / NBUFS; // round up to the next multiple of stm->framesize, if needed. if (stm->queuebuf_len % stm->framesize) { stm->queuebuf_len += stm->framesize - (stm->queuebuf_len % stm->framesize); diff --git a/media/libcubeb/src/cubeb_osx_run_loop.h b/media/libcubeb/src/cubeb_osx_run_loop.h index cb034b5d734b..78cd68d09b78 100644 --- a/media/libcubeb/src/cubeb_osx_run_loop.h +++ b/media/libcubeb/src/cubeb_osx_run_loop.h @@ -11,4 +11,12 @@ * * This has to be called only once per process, so it is in a separate header * for easy integration in other code bases. */ +#if defined(__cplusplus) +extern "C" { +#endif + void cubeb_set_coreaudio_notification_runloop(); + +#if defined(__cplusplus) +} +#endif diff --git a/media/libcubeb/src/cubeb_pulse.c b/media/libcubeb/src/cubeb_pulse.c index 6abf05ca735a..a6658f3cb45f 100644 --- a/media/libcubeb/src/cubeb_pulse.c +++ b/media/libcubeb/src/cubeb_pulse.c @@ -582,10 +582,10 @@ pulse_get_preferred_sample_rate(cubeb * ctx, uint32_t * rate) } static int -pulse_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms) +pulse_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames) { // According to PulseAudio developers, this is a safe minimum. - *latency_ms = 25; + *latency_frames = 25 * params.rate / 1000; return CUBEB_OK; } @@ -670,12 +670,12 @@ create_pa_stream(cubeb_stream * stm, } static pa_buffer_attr -set_buffering_attribute(unsigned int latency, pa_sample_spec * sample_spec) +set_buffering_attribute(unsigned int latency_frames, pa_sample_spec * sample_spec) { pa_buffer_attr battr; battr.maxlength = -1; battr.prebuf = -1; - battr.tlength = WRAP(pa_usec_to_bytes)(latency * PA_USEC_PER_MSEC, sample_spec); + battr.tlength = latency_frames * WRAP(pa_frame_size)(sample_spec); battr.minreq = battr.tlength / 4; battr.fragsize = battr.minreq; @@ -693,7 +693,7 @@ pulse_stream_init(cubeb * context, cubeb_stream_params * input_stream_params, cubeb_devid output_device, cubeb_stream_params * output_stream_params, - unsigned int latency, + unsigned int latency_frames, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr) @@ -734,7 +734,7 @@ pulse_stream_init(cubeb * context, WRAP(pa_stream_set_state_callback)(stm->output_stream, stream_state_callback, stm); WRAP(pa_stream_set_write_callback)(stm->output_stream, stream_write_callback, stm); - battr = set_buffering_attribute(latency, &stm->output_sample_spec); + battr = set_buffering_attribute(latency_frames, &stm->output_sample_spec); WRAP(pa_stream_connect_playback)(stm->output_stream, output_device, &battr, @@ -757,7 +757,7 @@ pulse_stream_init(cubeb * context, WRAP(pa_stream_set_state_callback)(stm->input_stream, stream_state_callback, stm); WRAP(pa_stream_set_read_callback)(stm->input_stream, stream_read_callback, stm); - battr = set_buffering_attribute(latency, &stm->input_sample_spec); + battr = set_buffering_attribute(latency_frames, &stm->input_sample_spec); WRAP(pa_stream_connect_record)(stm->input_stream, input_device, &battr, @@ -1056,8 +1056,8 @@ pulse_sink_info_cb(pa_context * context, const pa_sink_info * info, devinfo->max_rate = PA_RATE_MAX; devinfo->default_rate = info->sample_spec.rate; - devinfo->latency_lo_ms = 25; - devinfo->latency_hi_ms = 400; + devinfo->latency_lo = 0; + devinfo->latency_hi = 0; pulse_ensure_dev_list_data_list_size (list_data); list_data->devinfo[list_data->count++] = devinfo; @@ -1116,8 +1116,8 @@ pulse_source_info_cb(pa_context * context, const pa_source_info * info, devinfo->max_rate = PA_RATE_MAX; devinfo->default_rate = info->sample_spec.rate; - devinfo->latency_lo_ms = 1; - devinfo->latency_hi_ms = 10; + devinfo->latency_lo = 0; + devinfo->latency_hi = 0; pulse_ensure_dev_list_data_list_size (list_data); list_data->devinfo[list_data->count++] = devinfo; diff --git a/media/libcubeb/src/cubeb_resampler_internal.h b/media/libcubeb/src/cubeb_resampler_internal.h index 265bddf9970e..c547991db5b3 100644 --- a/media/libcubeb/src/cubeb_resampler_internal.h +++ b/media/libcubeb/src/cubeb_resampler_internal.h @@ -263,7 +263,7 @@ public: * number of output frames will be exactly equal. */ uint32_t input_needed_for_output(uint32_t output_frame_count) { - return (uint32_t)ceilf((output_frame_count - samples_to_frames(resampling_in_buffer.length())) + return (uint32_t)ceilf((output_frame_count - samples_to_frames(resampling_out_buffer.length())) * resampling_ratio); } @@ -332,7 +332,7 @@ private: /** Additional latency inserted into the pipeline for synchronisation. */ uint32_t additional_latency; /** When `input_buffer` is called, this allows tracking the number of samples - that where in the buffer. */ + that were in the buffer. */ uint32_t leftover_samples; }; diff --git a/media/libcubeb/src/cubeb_ring_array.h b/media/libcubeb/src/cubeb_ring_array.h index 047c158f0876..51b3b321a369 100644 --- a/media/libcubeb/src/cubeb_ring_array.h +++ b/media/libcubeb/src/cubeb_ring_array.h @@ -8,9 +8,7 @@ #ifndef CUBEB_RING_ARRAY_H #define CUBEB_RING_ARRAY_H -#if defined(__cplusplus) -extern "C" { -#endif +#include "cubeb_utils.h" /** Ring array of pointers is used to hold buffers. In case that asynchronous producer/consumer callbacks do not arrive in a @@ -34,10 +32,11 @@ single_audiobuffer_init(AudioBuffer * buffer, assert(bytesPerFrame > 0 && channelsPerFrame && frames > 0); size_t size = bytesPerFrame * frames; - buffer->mData = calloc(1, size); + buffer->mData = operator new(size); if (buffer->mData == NULL) { return CUBEB_ERROR; } + PodZero(static_cast(buffer->mData), size); buffer->mNumberChannels = channelsPerFrame; buffer->mDataByteSize = size; @@ -64,7 +63,8 @@ ring_array_init(ring_array * ra, ra->tail = 0; ra->count = 0; - ra->buffer_array = calloc(ra->capacity, sizeof(AudioBuffer)); + ra->buffer_array = new AudioBuffer[ra->capacity]; + PodZero(ra->buffer_array, ra->capacity); if (ra->buffer_array == NULL) { return CUBEB_ERROR; } @@ -92,10 +92,10 @@ ring_array_destroy(ring_array * ra) } for (unsigned int i = 0; i < ra->capacity; ++i) { if (ra->buffer_array[i].mData) { - free(ra->buffer_array[i].mData); + operator delete(ra->buffer_array[i].mData); } } - free(ra->buffer_array); + delete [] ra->buffer_array; } /** Get the allocated buffer to be stored with fresh data. @@ -111,7 +111,7 @@ ring_array_get_free_buffer(ring_array * ra) } assert(ra->count == 0 || (ra->tail + ra->count) % ra->capacity != ra->tail); - void * ret = &ra->buffer_array[(ra->tail + ra->count) % ra->capacity]; + AudioBuffer * ret = &ra->buffer_array[(ra->tail + ra->count) % ra->capacity]; ++ra->count; assert(ra->count <= ra->capacity); @@ -131,7 +131,7 @@ ring_array_get_data_buffer(ring_array * ra) if (ra->count == 0) { return NULL; } - void * ret = &ra->buffer_array[ra->tail]; + AudioBuffer * ret = &ra->buffer_array[ra->tail]; ra->tail = (ra->tail + 1) % ra->capacity; assert(ra->tail < ra->capacity); @@ -156,8 +156,4 @@ ring_array_get_dummy_buffer(ring_array * ra) return &ra->buffer_array[0]; } -#if defined(__cplusplus) -} -#endif - #endif //CUBEB_RING_ARRAY_H diff --git a/media/libcubeb/src/cubeb_sndio.c b/media/libcubeb/src/cubeb_sndio.c index 2b3242b8df83..f3defeced5bc 100644 --- a/media/libcubeb/src/cubeb_sndio.c +++ b/media/libcubeb/src/cubeb_sndio.c @@ -177,7 +177,7 @@ sndio_stream_init(cubeb * context, cubeb_stream_params * input_stream_params, cubeb_devid output_device, cubeb_stream_params * output_stream_params, - unsigned int latency, + unsigned int latency_frames, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void *user_ptr) @@ -222,7 +222,7 @@ sndio_stream_init(cubeb * context, } wpar.rate = output_stream_params->rate; wpar.pchan = output_stream_params->channels; - wpar.appbufsz = latency * wpar.rate / 1000; + wpar.appbufsz = latency_frames; if (!sio_setpar(s->hdl, &wpar) || !sio_getpar(s->hdl, &rpar)) { sio_close(s->hdl); free(s); @@ -290,7 +290,7 @@ static int sndio_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms) { // XXX Not yet implemented. - *latency_ms = 40; + *latency = 2048; return CUBEB_OK; } diff --git a/media/libcubeb/src/cubeb_wasapi.cpp b/media/libcubeb/src/cubeb_wasapi.cpp index 044b5fe8e928..b0ec043765ad 100644 --- a/media/libcubeb/src/cubeb_wasapi.cpp +++ b/media/libcubeb/src/cubeb_wasapi.cpp @@ -62,23 +62,6 @@ DEFINE_PROPERTYKEY(PKEY_Device_InstanceId, 0x78c34fc8, 0x104a, 0x4aca, 0x9e (sizeof(array_) / sizeof(array_[0])) namespace { -uint32_t -ms_to_hns(uint32_t ms) -{ - return ms * 10000; -} - -uint32_t -hns_to_ms(REFERENCE_TIME hns) -{ - return static_cast(hns / 10000); -} - -double -hns_to_s(REFERENCE_TIME hns) -{ - return static_cast(hns) / 10000000; -} void SafeRelease(HANDLE handle) @@ -240,7 +223,7 @@ struct cubeb_stream /* The input and output device, or NULL for default. */ cubeb_devid input_device; cubeb_devid output_device; - /* The latency initially requested for this stream. */ + /* The latency initially requested for this stream, in frames. */ unsigned latency; cubeb_state_callback state_callback; cubeb_data_callback data_callback; @@ -438,6 +421,50 @@ double stream_to_mix_samplerate_ratio(cubeb_stream_params & stream, cubeb_stream return double(stream.rate) / mixer.rate; } + +uint32_t +get_rate(cubeb_stream * stm) +{ + return has_input(stm) ? stm->input_stream_params.rate + : stm->output_stream_params.rate; +} + +uint32_t +ms_to_hns(uint32_t ms) +{ + return ms * 10000; +} + +uint32_t +hns_to_ms(REFERENCE_TIME hns) +{ + return static_cast(hns / 10000); +} + +double +hns_to_s(REFERENCE_TIME hns) +{ + return static_cast(hns) / 10000000; +} + +uint32_t +hns_to_frames(cubeb_stream * stm, REFERENCE_TIME hns) +{ + return hns_to_ms(hns * get_rate(stm)) / 1000; +} + +uint32_t +hns_to_frames(uint32_t rate, REFERENCE_TIME hns) +{ + return hns_to_ms(hns * rate) / 1000; +} + +REFERENCE_TIME +frames_to_hns(cubeb_stream * stm, uint32_t frames) +{ + return frames * 1000 / get_rate(stm); +} + /* Upmix function, copies a mono channel into L and R */ template void @@ -1244,7 +1271,7 @@ wasapi_get_max_channel_count(cubeb * ctx, uint32_t * max_channels) } int -wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_ms) +wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency_frames) { HRESULT hr; IAudioClient * client; @@ -1287,7 +1314,8 @@ wasapi_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * laten /* According to the docs, the best latency we can achieve is by synchronizing the stream and the engine. http://msdn.microsoft.com/en-us/library/windows/desktop/dd370871%28v=vs.85%29.aspx */ - *latency_ms = hns_to_ms(default_period); + + *latency_frames = hns_to_frames(params.rate, default_period); SafeRelease(client); @@ -1476,7 +1504,7 @@ int setup_wasapi_stream_one_side(cubeb_stream * stm, hr = (*audio_client)->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_NOPERSIST, - ms_to_hns(stm->latency), + frames_to_hns(stm, stm->latency), 0, mix_format, NULL); @@ -1642,7 +1670,7 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream, cubeb_stream_params * input_stream_params, cubeb_devid output_device, cubeb_stream_params * output_stream_params, - unsigned int latency, cubeb_data_callback data_callback, + unsigned int latency_frames, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr) { HRESULT hr; @@ -1652,7 +1680,7 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream, return CUBEB_ERROR; } - XASSERT(context && stream); + XASSERT(context && stream && (input_stream_params || output_stream_params)); if (output_stream_params && output_stream_params->format != CUBEB_SAMPLE_FLOAT32NE || input_stream_params && input_stream_params->format != CUBEB_SAMPLE_FLOAT32NE) { @@ -1676,7 +1704,8 @@ wasapi_stream_init(cubeb * context, cubeb_stream ** stream, stm->output_stream_params = *output_stream_params; stm->output_device = output_device; } - stm->latency = latency; + + stm->latency = latency_frames; stm->volume = 1.0; stm->stream_reset_lock = new owned_critical_section(); @@ -1734,8 +1763,6 @@ void close_wasapi_stream(cubeb_stream * stm) stm->stream_reset_lock->assert_current_thread_owns(); - XASSERT(stm->output_client || stm->input_client); - SafeRelease(stm->output_client); stm->output_client = NULL; SafeRelease(stm->input_client); @@ -1947,8 +1974,7 @@ int wasapi_stream_get_latency(cubeb_stream * stm, uint32_t * latency) if (FAILED(hr)) { return CUBEB_ERROR; } - double latency_s = hns_to_s(latency_hns); - *latency = static_cast(latency_s * stm->output_stream_params.rate); + *latency = hns_to_frames(stm, latency_hns); return CUBEB_OK; } @@ -2141,11 +2167,11 @@ wasapi_create_device(IMMDeviceEnumerator * enumerator, IMMDevice * dev) if (SUCCEEDED(dev->Activate(__uuidof(IAudioClient), CLSCTX_INPROC_SERVER, NULL, (void**)&client)) && SUCCEEDED(client->GetDevicePeriod(&def_period, &min_period))) { - ret->latency_lo_ms = hns_to_ms(min_period); - ret->latency_hi_ms = hns_to_ms(def_period); + ret->latency_lo = hns_to_frames(ret->default_rate, min_period); + ret->latency_hi = hns_to_frames(ret->default_rate, def_period); } else { - ret->latency_lo_ms = 0; - ret->latency_hi_ms = 0; + ret->latency_lo = 0; + ret->latency_hi = 0; } SafeRelease(client); diff --git a/media/libcubeb/src/cubeb_winmm.c b/media/libcubeb/src/cubeb_winmm.c index 746909ba8fa8..65bb1ed8df58 100644 --- a/media/libcubeb/src/cubeb_winmm.c +++ b/media/libcubeb/src/cubeb_winmm.c @@ -89,7 +89,7 @@ struct cubeb { PSLIST_HEADER work; CRITICAL_SECTION lock; unsigned int active_streams; - unsigned int minimum_latency; + unsigned int minimum_latency_ms; }; struct cubeb_stream { @@ -336,7 +336,7 @@ winmm_init(cubeb ** context, char const * context_name) InitializeCriticalSection(&ctx->lock); ctx->active_streams = 0; - ctx->minimum_latency = calculate_minimum_latency(); + ctx->minimum_latency_ms = calculate_minimum_latency(); *context = ctx; @@ -384,7 +384,7 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n cubeb_stream_params * input_stream_params, cubeb_devid output_device, cubeb_stream_params * output_stream_params, - unsigned int latency, + unsigned int latency_frames, cubeb_data_callback data_callback, cubeb_state_callback state_callback, void * user_ptr) @@ -467,11 +467,13 @@ winmm_stream_init(cubeb * context, cubeb_stream ** stream, char const * stream_n stm->user_ptr = user_ptr; stm->written = 0; - if (latency < context->minimum_latency) { - latency = context->minimum_latency; + uint32_t latency_ms = latency_frames * 1000 / output_stream_params->rate; + + if (latency_ms < context->minimum_latency_ms) { + latency_ms = context->minimum_latency_ms; } - bufsz = (size_t) (stm->params.rate / 1000.0 * latency * bytes_per_frame(stm->params) / NBUFS); + bufsz = (size_t) (stm->params.rate / 1000.0 * latency_ms * bytes_per_frame(stm->params) / NBUFS); if (bufsz % bytes_per_frame(stm->params) != 0) { bufsz += bytes_per_frame(stm->params) - (bufsz % bytes_per_frame(stm->params)); } @@ -600,7 +602,7 @@ static int winmm_get_min_latency(cubeb * ctx, cubeb_stream_params params, uint32_t * latency) { // 100ms minimum, if we are not in a bizarre configuration. - *latency = ctx->minimum_latency; + *latency = ctx->minimum_latency_ms * params.rate / 1000; return CUBEB_OK; } @@ -854,8 +856,8 @@ winmm_create_device_from_outcaps2(LPWAVEOUTCAPS2A caps, UINT devid) &ret->format, &ret->default_format); /* Hardcoed latency estimates... */ - ret->latency_lo_ms = 100; - ret->latency_hi_ms = 200; + ret->latency_lo = 100 * ret->default_rate / 1000; + ret->latency_hi = 200 * ret->default_rate / 1000; return ret; } @@ -885,8 +887,8 @@ winmm_create_device_from_outcaps(LPWAVEOUTCAPSA caps, UINT devid) &ret->format, &ret->default_format); /* Hardcoed latency estimates... */ - ret->latency_lo_ms = 100; - ret->latency_hi_ms = 200; + ret->latency_lo = 100 * ret->default_rate / 1000; + ret->latency_hi = 200 * ret->default_rate / 1000; return ret; } @@ -935,8 +937,8 @@ winmm_create_device_from_incaps2(LPWAVEINCAPS2A caps, UINT devid) &ret->format, &ret->default_format); /* Hardcoed latency estimates... */ - ret->latency_lo_ms = 100; - ret->latency_hi_ms = 200; + ret->latency_lo = 100 * ret->default_rate / 1000; + ret->latency_hi = 200 * ret->default_rate / 1000; return ret; } @@ -966,8 +968,8 @@ winmm_create_device_from_incaps(LPWAVEINCAPSA caps, UINT devid) &ret->format, &ret->default_format); /* Hardcoed latency estimates... */ - ret->latency_lo_ms = 100; - ret->latency_hi_ms = 200; + ret->latency_lo = 100 * ret->default_rate / 1000; + ret->latency_hi = 200 * ret->default_rate / 1000; return ret; } diff --git a/media/libcubeb/tests/test_audio.cpp b/media/libcubeb/tests/test_audio.cpp index 7a8adf66f611..1bd18b378c7e 100644 --- a/media/libcubeb/tests/test_audio.cpp +++ b/media/libcubeb/tests/test_audio.cpp @@ -161,7 +161,7 @@ int run_test(int num_channels, int sampling_rate, int is_float) } r = cubeb_stream_init(ctx, &stream, "test tone", NULL, NULL, NULL, ¶ms, - 100, is_float ? data_cb_float : data_cb_short, state_cb, synth); + 4096, is_float ? data_cb_float : data_cb_short, state_cb, synth); if (r != CUBEB_OK) { fprintf(stderr, "Error initializing cubeb stream: %d\n", r); goto cleanup; @@ -213,7 +213,8 @@ int run_panning_volume_test(int is_float) } r = cubeb_stream_init(ctx, &stream, "test tone", NULL, NULL, NULL, ¶ms, - 100, is_float ? data_cb_float : data_cb_short, state_cb, synth); + 4096, is_float ? data_cb_float : data_cb_short, + state_cb, synth); if (r != CUBEB_OK) { fprintf(stderr, "Error initializing cubeb stream: %d\n", r); goto cleanup; diff --git a/media/libcubeb/tests/test_duplex.cpp b/media/libcubeb/tests/test_duplex.cpp index bc80366c29c4..85fbd3d70a2b 100644 --- a/media/libcubeb/tests/test_duplex.cpp +++ b/media/libcubeb/tests/test_duplex.cpp @@ -101,7 +101,7 @@ int main(int argc, char *argv[]) cubeb_stream_params output_params; int r; user_state stream_state = { false }; - uint32_t latency_ms = 0; + uint32_t latency_frames = 0; r = cubeb_init(&ctx, "Cubeb duplex example"); if (r != CUBEB_OK) { @@ -123,7 +123,7 @@ int main(int argc, char *argv[]) output_params.rate = 48000; output_params.channels = 2; - r = cubeb_get_min_latency(ctx, output_params, &latency_ms); + r = cubeb_get_min_latency(ctx, output_params, &latency_frames); if (r != CUBEB_OK) { fprintf(stderr, "Could not get minimal latency\n"); @@ -132,7 +132,7 @@ int main(int argc, char *argv[]) r = cubeb_stream_init(ctx, &stream, "Cubeb duplex", NULL, &input_params, NULL, &output_params, - latency_ms, data_cb, state_cb, &stream_state); + latency_frames, data_cb, state_cb, &stream_state); if (r != CUBEB_OK) { fprintf(stderr, "Error initializing cubeb stream\n"); return r; diff --git a/media/libcubeb/tests/test_latency.cpp b/media/libcubeb/tests/test_latency.cpp index 5e58f87292b7..558ef9515176 100644 --- a/media/libcubeb/tests/test_latency.cpp +++ b/media/libcubeb/tests/test_latency.cpp @@ -21,7 +21,7 @@ int main(int argc, char * argv[]) int r; uint32_t max_channels; uint32_t preferred_rate; - uint32_t latency_ms; + uint32_t latency_frames; LOG("latency_test start"); r = cubeb_init(&ctx, "Cubeb audio test"); @@ -47,10 +47,10 @@ int main(int argc, char * argv[]) preferred_rate, max_channels }; - r = cubeb_get_min_latency(ctx, params, &latency_ms); + r = cubeb_get_min_latency(ctx, params, &latency_frames); assert(r == CUBEB_OK || r == CUBEB_ERROR_NOT_SUPPORTED); if (r == CUBEB_OK) { - assert(latency_ms > 0 && "Invalid minimal latency."); + assert(latency_frames > 0 && "Invalid minimal latency."); LOG("cubeb_get_min_latency ok"); } diff --git a/media/libcubeb/tests/test_record.cpp b/media/libcubeb/tests/test_record.cpp index 1d27eef25650..5dbfb61a59e7 100644 --- a/media/libcubeb/tests/test_record.cpp +++ b/media/libcubeb/tests/test_record.cpp @@ -106,7 +106,7 @@ int main(int argc, char *argv[]) params.channels = 1; r = cubeb_stream_init(ctx, &stream, "Cubeb record (mono)", NULL, ¶ms, NULL, nullptr, - 250, data_cb, state_cb, &stream_state); + 4096, data_cb, state_cb, &stream_state); if (r != CUBEB_OK) { fprintf(stderr, "Error initializing cubeb stream\n"); return r; diff --git a/media/libcubeb/tests/test_sanity.cpp b/media/libcubeb/tests/test_sanity.cpp index c6bd9de79589..30c2d65dde3a 100644 --- a/media/libcubeb/tests/test_sanity.cpp +++ b/media/libcubeb/tests/test_sanity.cpp @@ -26,8 +26,8 @@ #define BEGIN_TEST fprintf(stderr, "START %s\n", __func__) #define END_TEST fprintf(stderr, "END %s\n", __func__) -#define STREAM_LATENCY 100 #define STREAM_RATE 44100 +#define STREAM_LATENCY 100 * STREAM_RATE / 1000 #define STREAM_CHANNELS 1 #if (defined(_WIN32) || defined(__WIN32__)) #define STREAM_FORMAT CUBEB_SAMPLE_FLOAT32LE diff --git a/media/libcubeb/tests/test_tone.cpp b/media/libcubeb/tests/test_tone.cpp index 82bcb80b9cec..ae5ac8041f39 100644 --- a/media/libcubeb/tests/test_tone.cpp +++ b/media/libcubeb/tests/test_tone.cpp @@ -128,7 +128,7 @@ int main(int argc, char *argv[]) user_data->position = 0; r = cubeb_stream_init(ctx, &stream, "Cubeb tone (mono)", NULL, NULL, NULL, ¶ms, - 250, data_cb, state_cb, user_data); + 4096, data_cb, state_cb, user_data); if (r != CUBEB_OK) { fprintf(stderr, "Error initializing cubeb stream\n"); return r; From 960b8954870198430f6cc9a4392b9e2ce1cebd0d Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Fri, 22 Jul 2016 13:57:10 +0100 Subject: [PATCH 019/135] Bug 1285305 - Add comments explaining compacting GC update phases r=sfink --- js/src/jsgc.cpp | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index cb0ff3da59ba..59a59fa5f647 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2441,11 +2441,31 @@ GCRuntime::updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, s } } -// Pointer updates run in three phases because of depdendencies between the -// different types of GC thing. The most important consideration is the -// dependency: +// After cells have been relocated any pointers to a cell's old locations must +// be updated to point to the new location. This happens by iterating through +// all cells in heap and tracing their children (non-recursively) to update +// them. // -// object ---> shape ---> base shape +// This is complicated by the fact that updating a GC thing sometimes depends on +// making use of other GC things. After a moving GC these things may not be in +// a valid state since they may contain pointers which have not been updated +// yet. +// +// The main dependencies are: +// +// - Updating a shape makes use of its base shape +// - Updating a JSObject makes use of its shape +// - Updating a typed object makes use of its type descriptor object +// +// This means we require at least four phases for update: +// +// 1) base shapes +// 2) shapes +// 3) typed object type descriptor objects +// 4) all other objects +// +// Since we want to minimize the number of phases, we put everything else into +// the second phase and label it the 'misc' phase. static const AllocKinds UpdatePhaseBaseShapes { AllocKind::BASE_SHAPE From 09944b17dd66ebbb23353bf959e5a00ffead25ac Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Fri, 22 Jul 2016 13:57:10 +0100 Subject: [PATCH 020/135] Bug 1288427 - Remove the base shapes update phase of compacting GC r=terrence --- js/src/jsgc.cpp | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 59a59fa5f647..d40d0716e799 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -2453,27 +2453,22 @@ GCRuntime::updateCellPointers(MovingTracer* trc, Zone* zone, AllocKinds kinds, s // // The main dependencies are: // -// - Updating a shape makes use of its base shape // - Updating a JSObject makes use of its shape // - Updating a typed object makes use of its type descriptor object // -// This means we require at least four phases for update: +// This means we require at least three phases for update: // -// 1) base shapes -// 2) shapes -// 3) typed object type descriptor objects -// 4) all other objects +// 1) shapes +// 2) typed object type descriptor objects +// 3) all other objects // // Since we want to minimize the number of phases, we put everything else into -// the second phase and label it the 'misc' phase. - -static const AllocKinds UpdatePhaseBaseShapes { - AllocKind::BASE_SHAPE -}; +// the first phase and label it the 'misc' phase. static const AllocKinds UpdatePhaseMisc { AllocKind::SCRIPT, AllocKind::LAZY_SCRIPT, + AllocKind::BASE_SHAPE, AllocKind::SHAPE, AllocKind::ACCESSOR_SHAPE, AllocKind::OBJECT_GROUP, @@ -2505,8 +2500,6 @@ GCRuntime::updateAllCellPointers(MovingTracer* trc, Zone* zone) size_t bgTaskCount = CellUpdateBackgroundTaskCount(); - updateCellPointers(trc, zone, UpdatePhaseBaseShapes, bgTaskCount); - updateCellPointers(trc, zone, UpdatePhaseMisc, bgTaskCount); // Update TypeDescrs before all other objects as typed objects access these From d8659edc522ea7916873287dae38efb238a363d9 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Fri, 22 Jul 2016 13:57:10 +0100 Subject: [PATCH 021/135] Bug 1275448 - Don't crash on shutdown due to non-empty type descriptors set if we leak r=sfink --- js/src/gc/Zone.cpp | 2 -- js/src/jsgc.cpp | 8 ++++++-- js/src/jsgc.h | 12 ++++++++---- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/js/src/gc/Zone.cpp b/js/src/gc/Zone.cpp index 19d80af1551d..11f652b457c2 100644 --- a/js/src/gc/Zone.cpp +++ b/js/src/gc/Zone.cpp @@ -58,8 +58,6 @@ JS::Zone::Zone(JSRuntime* rt) Zone::~Zone() { - MOZ_ASSERT_IF(typeDescrObjects.initialized(), typeDescrObjects.empty()); - JSRuntime* rt = runtimeFromMainThread(); if (this == rt->gc.systemZone) rt->gc.systemZone = nullptr; diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index d40d0716e799..72e8315a4a32 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3553,13 +3553,14 @@ GCRuntime::sweepZones(FreeOp* fop, bool destroyingRuntime) // We are about to delete the Zone; this will leave the Zone* // in the arena header dangling if there are any arenas // remaining at this point. - zone->arenas.checkEmptyArenaLists(); + mozilla::DebugOnly arenasEmpty = zone->arenas.checkEmptyArenaLists(); if (callback) callback(zone); zone->sweepCompartments(fop, false, destroyingRuntime); MOZ_ASSERT(zone->compartments.empty()); + MOZ_ASSERT_IF(arenasEmpty, zone->typeDescrObjects.empty()); fop->delete_(zone); stats.sweptZone(); continue; @@ -3587,9 +3588,10 @@ FOR_EACH_ALLOCKIND(MAKE_CASE) } #endif // DEBUG -void +bool ArenaLists::checkEmptyArenaList(AllocKind kind) { + bool empty = true; #ifdef DEBUG if (!arenaLists[kind].isEmpty()) { for (Arena* current = arenaLists[kind].head(); current; current = current->next) { @@ -3598,10 +3600,12 @@ ArenaLists::checkEmptyArenaList(AllocKind kind) MOZ_ASSERT(t->asTenured().isMarked(), "unmarked cells should have been finalized"); fprintf(stderr, "ERROR: GC found live Cell %p of kind %s at shutdown\n", t, AllocKindToAscii(kind)); + empty = false; } } } #endif // DEBUG + return empty; } void diff --git a/js/src/jsgc.h b/js/src/jsgc.h index 4b59b4c3c8ae..c9c73fcce514 100644 --- a/js/src/jsgc.h +++ b/js/src/jsgc.h @@ -741,18 +741,22 @@ class ArenaLists #endif } - void checkEmptyArenaLists() { + bool checkEmptyArenaLists() { + bool empty = true; #ifdef DEBUG - for (auto i : AllAllocKinds()) - checkEmptyArenaList(i); + for (auto i : AllAllocKinds()) { + if (!checkEmptyArenaList(i)) + empty = false; + } #endif + return empty; } void checkEmptyFreeList(AllocKind kind) { MOZ_ASSERT(freeLists[kind]->isEmpty()); } - void checkEmptyArenaList(AllocKind kind); + bool checkEmptyArenaList(AllocKind kind); bool relocateArenas(Zone* zone, Arena*& relocatedListOut, JS::gcreason::Reason reason, SliceBudget& sliceBudget, gcstats::Statistics& stats); From 45cd7b63bf9bd7361a83fcb16722b946f8ab18b9 Mon Sep 17 00:00:00 2001 From: Jon Coppeard Date: Fri, 22 Jul 2016 13:57:20 +0100 Subject: [PATCH 022/135] Bug 1288716 - Fix jit-test handling of --tbpl argument r=bbouvier --- js/src/jit-test/jit_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jit-test/jit_test.py b/js/src/jit-test/jit_test.py index 4bf7fa0b191d..bb580fb24442 100755 --- a/js/src/jit-test/jit_test.py +++ b/js/src/jit-test/jit_test.py @@ -121,7 +121,7 @@ def main(argv): op.add_option('--ion', dest='jitflags', action='store_const', const='ion', help='Run tests once with --ion-eager and once with' ' --baseline-eager (equivalent to --jitflags=ion)') - op.add_option('--tbpl', dest='jit_flags', action='store_const', const='all', + op.add_option('--tbpl', dest='jitflags', action='store_const', const='all', help='Run tests with all IonMonkey option combinations' ' (equivalent to --jitflags=all)') op.add_option('-j', '--worker-count', dest='max_jobs', type=int, From b0f1ee13875669ea52a2d296d56c02ff04a7e94c Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Fri, 22 Jul 2016 06:26:48 -0700 Subject: [PATCH 023/135] Bug 1288440 P1 Avoid leaking existing windows in sdk/tab/events. r=gabor --- addon-sdk/source/lib/sdk/tab/events.js | 40 ++++++++++++++------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/addon-sdk/source/lib/sdk/tab/events.js b/addon-sdk/source/lib/sdk/tab/events.js index 7e4036fc60ac..e431cc9d21c5 100644 --- a/addon-sdk/source/lib/sdk/tab/events.js +++ b/addon-sdk/source/lib/sdk/tab/events.js @@ -39,29 +39,33 @@ function tabEventsFor(window) { return merge(channels); } -// Filter DOMContentLoaded events from all the browser events. -var readyEvents = filter(events, e => e.type === "DOMContentLoaded"); -// Map DOMContentLoaded events to it's target browser windows. -var futureWindows = map(readyEvents, e => e.target); -// Expand all browsers that will become interactive to supported tab events -// on these windows. Result will be a tab events from all tabs of all windows -// that will become interactive. -var eventsFromFuture = expand(futureWindows, tabEventsFor); +// Create our event channels. We do this in a separate function to +// minimize the chance of leaking intermediate objects on the global. +function makeEvents() { + // Filter DOMContentLoaded events from all the browser events. + var readyEvents = filter(events, e => e.type === "DOMContentLoaded"); + // Map DOMContentLoaded events to it's target browser windows. + var futureWindows = map(readyEvents, e => e.target); + // Expand all browsers that will become interactive to supported tab events + // on these windows. Result will be a tab events from all tabs of all windows + // that will become interactive. + var eventsFromFuture = expand(futureWindows, tabEventsFor); -// Above covers only windows that will become interactive in a future, but some -// windows may already be interactive so we pick those and expand to supported -// tab events for them too. -var interactiveWindows = windows("navigator:browser", { includePrivate: true }). - filter(isInteractive); -var eventsFromInteractive = merge(interactiveWindows.map(tabEventsFor)); + // Above covers only windows that will become interactive in a future, but some + // windows may already be interactive so we pick those and expand to supported + // tab events for them too. + var interactiveWindows = windows("navigator:browser", { includePrivate: true }). + filter(isInteractive); + var eventsFromInteractive = merge(interactiveWindows.map(tabEventsFor)); -// Finally merge stream of tab events from future windows and current windows -// to cover all tab events on all windows that will open. -var allEvents = merge([eventsFromInteractive, eventsFromFuture]); + // Finally merge stream of tab events from future windows and current windows + // to cover all tab events on all windows that will open. + return merge([eventsFromInteractive, eventsFromFuture]); +} // Map events to Fennec format if necessary -exports.events = map(allEvents, function (event) { +exports.events = map(makeEvents(), function (event) { return !isFennec ? event : { type: event.type, target: event.target.ownerDocument.defaultView.BrowserApp From 6669a84ee0097858d5b7c13cb3abf4f1550756cf Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Fri, 22 Jul 2016 06:26:49 -0700 Subject: [PATCH 024/135] Bug 1288440 P2 Don't leak existing windows in sdk/window/events. r=gabor --- addon-sdk/source/lib/sdk/window/events.js | 36 +++++++++++++---------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/addon-sdk/source/lib/sdk/window/events.js b/addon-sdk/source/lib/sdk/window/events.js index e122bbd9e15c..b1d3a1f3e537 100644 --- a/addon-sdk/source/lib/sdk/window/events.js +++ b/addon-sdk/source/lib/sdk/window/events.js @@ -43,22 +43,26 @@ function eventsFor(window) { return map(changes, toEventWithDefaultViewTarget); } -// In addition to observing windows that are open we also observe windows -// that are already already opened in case they're in process of loading. -var opened = windows(null, { includePrivate: true }); -var currentEvents = merge(opened.map(eventsFor)); +// Create our event channels. We do this in a separate function to +// minimize the chance of leaking intermediate objects on the global. +function makeEvents() { + // In addition to observing windows that are open we also observe windows + // that are already already opened in case they're in process of loading. + var opened = windows(null, { includePrivate: true }); + var currentEvents = merge(opened.map(eventsFor)); -// Register system event listeners for top level window open / close. -function rename({type, target, data}) { - return { type: rename[type], target: target, data: data } + // Register system event listeners for top level window open / close. + function rename({type, target, data}) { + return { type: rename[type], target: target, data: data } + } + rename.domwindowopened = "open"; + rename.domwindowclosed = "close"; + + var openEvents = map(observe("domwindowopened"), rename); + var closeEvents = map(observe("domwindowclosed"), rename); + var futureEvents = expand(openEvents, ({target}) => eventsFor(target)); + + return merge([currentEvents, futureEvents, openEvents, closeEvents]); } -rename.domwindowopened = "open"; -rename.domwindowclosed = "close"; -var openEvents = map(observe("domwindowopened"), rename); -var closeEvents = map(observe("domwindowclosed"), rename); -var futureEvents = expand(openEvents, ({target}) => eventsFor(target)); - -var channel = merge([currentEvents, futureEvents, - openEvents, closeEvents]); -exports.events = channel; +exports.events = makeEvents(); From 9027cc8e21ef3a6c037f95b8207e61144dbac75d Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Fri, 22 Jul 2016 06:26:49 -0700 Subject: [PATCH 025/135] Bug 1288440 P3 Test that sdk/tab/events does not leak. r=gabor --- .../source/test/leak/jetpack-package.ini | 1 + .../source/test/leak/test-leak-tab-events.js | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 addon-sdk/source/test/leak/test-leak-tab-events.js diff --git a/addon-sdk/source/test/leak/jetpack-package.ini b/addon-sdk/source/test/leak/jetpack-package.ini index 01531a79f589..3796c21ee464 100644 --- a/addon-sdk/source/test/leak/jetpack-package.ini +++ b/addon-sdk/source/test/leak/jetpack-package.ini @@ -4,4 +4,5 @@ support-files = [test-leak-window-events.js] [test-leak-event-dom-closed-window.js] +[test-leak-tab-events.js] [test-leak-event-chrome.js] diff --git a/addon-sdk/source/test/leak/test-leak-tab-events.js b/addon-sdk/source/test/leak/test-leak-tab-events.js new file mode 100644 index 000000000000..4266c04fc079 --- /dev/null +++ b/addon-sdk/source/test/leak/test-leak-tab-events.js @@ -0,0 +1,46 @@ +/* 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/. */ +'use strict'; + +const { asyncWindowLeakTest } = require("./leak-utils"); +const { Loader } = require('sdk/test/loader'); +const openWindow = require("sdk/window/utils").open; + +exports["test sdk/tab/events does not leak new window"] = function*(assert) { + yield asyncWindowLeakTest(assert, _ => { + return new Promise(resolve => { + let loader = Loader(module); + let { events } = loader.require('sdk/tab/events'); + let w = openWindow(); + w.addEventListener("load", function windowLoaded(evt) { + w.removeEventListener("load", windowLoaded); + w.addEventListener("DOMWindowClose", function windowClosed(evt) { + w.removeEventListener("DOMWindowClose", windowClosed); + resolve(loader); + }); + w.close(); + }); + }); + }); +} + +exports["test sdk/tab/events does not leak when attached to existing window"] = function*(assert) { + yield asyncWindowLeakTest(assert, _ => { + return new Promise(resolve => { + let loader = Loader(module); + let w = openWindow(); + w.addEventListener("load", function windowLoaded(evt) { + w.removeEventListener("load", windowLoaded); + let { events } = loader.require('sdk/tab/events'); + w.addEventListener("DOMWindowClose", function windowClosed(evt) { + w.removeEventListener("DOMWindowClose", windowClosed); + resolve(loader); + }); + w.close(); + }); + }); + }); +} + +require("sdk/test").run(exports); From 921a58dfb28948fe30000b0b3c8dbfa0a9359341 Mon Sep 17 00:00:00 2001 From: Ben Kelly Date: Fri, 22 Jul 2016 06:26:49 -0700 Subject: [PATCH 026/135] Bug 1288440 P4 Test that sdk/window/events does not leak existing windows. r=gabor --- .../test/leak/test-leak-window-events.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/addon-sdk/source/test/leak/test-leak-window-events.js b/addon-sdk/source/test/leak/test-leak-window-events.js index 6fd0cc792372..ceb20f47556b 100644 --- a/addon-sdk/source/test/leak/test-leak-window-events.js +++ b/addon-sdk/source/test/leak/test-leak-window-events.js @@ -44,4 +44,22 @@ exports["test window/events for leaks"] = function*(assert) { }); }; +exports["test window/events for leaks with existing window"] = function*(assert) { + yield asyncWindowLeakTest(assert, _ => { + return new Promise((resolve, reject) => { + let loader = Loader(module); + let w = open(); + w.addEventListener("load", function windowLoaded(evt) { + w.removeEventListener("load", windowLoaded); + let { events } = loader.require("sdk/window/events"); + w.addEventListener("DOMWindowClose", function windowClosed(evt) { + w.removeEventListener("DOMWindowClose", windowClosed); + resolve(loader); + }); + w.close(); + }); + }); + }); +}; + require("sdk/test").run(exports); From e85a5267b71c3ba1a892cbd96710e00d4305cc05 Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Fri, 22 Jul 2016 08:18:49 -0600 Subject: [PATCH 027/135] Bug 1288450 - Add min sdk version to mozinfo.json; r=ahal --- python/mozbuild/mozbuild/mozinfo.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/mozbuild/mozbuild/mozinfo.py b/python/mozbuild/mozbuild/mozinfo.py index c6bb9b2de872..f96a2ae08e6e 100755 --- a/python/mozbuild/mozbuild/mozinfo.py +++ b/python/mozbuild/mozbuild/mozinfo.py @@ -140,6 +140,9 @@ def build_dict(config, env=os.environ): d['platform_guess'] = guess_platform() d['buildtype_guess'] = guess_buildtype() + if d['buildapp'] == 'mobile/android' and 'MOZ_ANDROID_MIN_SDK_VERSION' in substs: + d['android_min_sdk'] = substs['MOZ_ANDROID_MIN_SDK_VERSION'] + return d From 35dde125dd0ce8f1cad732b73f30063478617bce Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Fri, 22 Jul 2016 08:18:50 -0600 Subject: [PATCH 028/135] Bug 1266562 - Remove robocop testAwesomebar; r=snorp --- .../android/tests/browser/robocop/robocop.ini | 1 - .../mozilla/gecko/tests/testAwesomebar.java | 30 ------------------- 2 files changed, 31 deletions(-) delete mode 100644 mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAwesomebar.java diff --git a/mobile/android/tests/browser/robocop/robocop.ini b/mobile/android/tests/browser/robocop/robocop.ini index 7a64cdc69ca6..547c53aab8fa 100644 --- a/mobile/android/tests/browser/robocop/robocop.ini +++ b/mobile/android/tests/browser/robocop/robocop.ini @@ -13,7 +13,6 @@ skip-if = android_version == "18" # disabled on 4.3, bug 1146420 skip-if = android_version == "18" [src/org/mozilla/gecko/tests/testANRReporter.java] -[src/org/mozilla/gecko/tests/testAwesomebar.java] [src/org/mozilla/gecko/tests/testAxisLocking.java] # [src/org/mozilla/gecko/tests/testBookmark.java] # see bug 915350 [src/org/mozilla/gecko/tests/testBookmarksPanel.java] diff --git a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAwesomebar.java b/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAwesomebar.java deleted file mode 100644 index d2df704c3dde..000000000000 --- a/mobile/android/tests/browser/robocop/src/org/mozilla/gecko/tests/testAwesomebar.java +++ /dev/null @@ -1,30 +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/. */ - -package org.mozilla.gecko.tests; - -public class testAwesomebar extends BaseTest { - public void testAwesomebar() { - blockForGeckoReady(); - - String url = getAbsoluteUrl(mStringHelper.ROBOCOP_BLANK_PAGE_01_URL); - inputAndLoadUrl(url); - - mDriver.setupScrollHandling(); - // Calculate where we should be dragging. - int midX = mDriver.getGeckoLeft() + mDriver.getGeckoWidth()/2; - int midY = mDriver.getGeckoTop() + mDriver.getGeckoHeight()/2; - int endY = mDriver.getGeckoTop() + mDriver.getGeckoHeight()/10; - for (int i = 0; i < 10; i++) { - mActions.drag(midX, midX, midY, endY); - try { - Thread.sleep(200); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - - verifyUrl(url); - } -} From 099aae1f90f8444874896fd75b4c4cd64ad2c2a8 Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Fri, 22 Jul 2016 08:18:51 -0600 Subject: [PATCH 029/135] Bug 1285269 - Add TC Linux 64 asan reftests; r=dustin --- taskcluster/ci/desktop-test/test-sets.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/taskcluster/ci/desktop-test/test-sets.yml b/taskcluster/ci/desktop-test/test-sets.yml index 35d690fd79b5..6d377817793c 100644 --- a/taskcluster/ci/desktop-test/test-sets.yml +++ b/taskcluster/ci/desktop-test/test-sets.yml @@ -51,4 +51,6 @@ asan-tests: - mochitest-jetpack - mochitest-media - mochitest-webgl + - reftest + - reftest-no-accel - xpcshell From 496107445fa7a5806c2316dae224f164beafe476 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 22 Jul 2016 16:14:24 +0200 Subject: [PATCH 030/135] Bug 1287091 - part 1 - ContextualIdentityService should use a storage for the containers, r=Gijs --- browser/base/content/browser.js | 3 +- browser/base/content/nsContextMenu.js | 3 +- browser/base/content/utilityOverlay.js | 4 +- .../customizableui/CustomizableWidgets.jsm | 3 +- .../ContextualIdentityService.jsm | 118 +++++++++++++++++- 5 files changed, 119 insertions(+), 12 deletions(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 511178b5e7de..fc58acb41e35 100755 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -8,6 +8,7 @@ var Cu = Components.utils; var Cc = Components.classes; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/ContextualIdentityService.jsm"); Cu.import("resource://gre/modules/NotificationDB.jsm"); Cu.import("resource:///modules/RecentWindow.jsm"); @@ -56,8 +57,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils", "@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils"); XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager", "resource://gre/modules/LightweightThemeManager.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", - "resource://gre/modules/ContextualIdentityService.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "gAboutNewTabService", "@mozilla.org/browser/aboutnewtab-service;1", "nsIAboutNewTabService"); diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 124847b00beb..263b13737dcb 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -4,6 +4,7 @@ # 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/. +Components.utils.import("resource://gre/modules/ContextualIdentityService.jsm"); Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm"); Components.utils.import("resource://gre/modules/LoginManagerContextMenu.jsm"); @@ -11,8 +12,6 @@ Components.utils.import("resource://gre/modules/BrowserUtils.jsm"); Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", - "resource://gre/modules/ContextualIdentityService.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper", "resource://gre/modules/LoginHelper.jsm"); diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index dbddd6de62a3..458a3563ed3b 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -5,6 +5,7 @@ // Services = object with smart getters for common XPCOM services Components.utils.import("resource://gre/modules/AppConstants.jsm"); +Components.utils.import("resource://gre/modules/ContextualIdentityService.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); @@ -13,9 +14,6 @@ Components.utils.import("resource:///modules/RecentWindow.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ShellService", "resource:///modules/ShellService.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", - "resource://gre/modules/ContextualIdentityService.jsm"); - XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService", "@mozilla.org/browser/aboutnewtab-service;1", "nsIAboutNewTabService"); diff --git a/browser/components/customizableui/CustomizableWidgets.jsm b/browser/components/customizableui/CustomizableWidgets.jsm index 307309ee7115..8ee76afe86e4 100644 --- a/browser/components/customizableui/CustomizableWidgets.jsm +++ b/browser/components/customizableui/CustomizableWidgets.jsm @@ -11,6 +11,7 @@ Cu.import("resource:///modules/CustomizableUI.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/AppConstants.jsm"); +Cu.import("resource://gre/modules/ContextualIdentityService.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry", "resource:///modules/BrowserUITelemetry.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", @@ -27,8 +28,6 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "SyncedTabs", "resource://services-sync/SyncedTabs.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", - "resource://gre/modules/ContextualIdentityService.jsm"); XPCOMUtils.defineLazyGetter(this, "CharsetBundle", function() { const kCharsetBundle = "chrome://global/locale/charsetMenu.properties"; diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm index 31a4aabea8c5..59b8c5acd414 100644 --- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm +++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm @@ -7,16 +7,34 @@ this.EXPORTED_SYMBOLS = ["ContextualIdentityService"]; const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm") +Cu.import("resource://gre/modules/Services.jsm"); -const DEFAULT_TAB_COLOR = "#909090" +const DEFAULT_TAB_COLOR = "#909090"; +const SAVE_DELAY_MS = 1500; XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() { return Services.strings.createBundle("chrome://browser/locale/browser.properties"); }); +XPCOMUtils.defineLazyGetter(this, "gTextDecoder", function () { + return new TextDecoder(); +}); + +XPCOMUtils.defineLazyGetter(this, "gTextEncoder", function () { + return new TextEncoder(); +}); + +XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown", + "resource://gre/modules/AsyncShutdown.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "OS", + "resource://gre/modules/osfile.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask", + "resource://gre/modules/DeferredTask.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", + "resource://gre/modules/FileUtils.jsm"); + this.ContextualIdentityService = { - _identities: [ + _defaultIdentities: [ { userContextId: 1, public: true, icon: "chrome://browser/skin/usercontext/personal.svg", @@ -62,15 +80,107 @@ this.ContextualIdentityService = { alreadyOpened: false }, ], + _identities: null, + + _path: null, + _dataReady: false, + + _saver: null, + + init() { + this._path = OS.Path.join(OS.Constants.Path.profileDir, "containers.json"); + + this._saver = new DeferredTask(() => this.save(), SAVE_DELAY_MS); + AsyncShutdown.profileBeforeChange.addBlocker("ContextualIdentityService: writing data", + () => this._saver.finalize()); + + this.load(); + }, + + load() { + OS.File.read(this._path).then(bytes => { + // If synchronous loading happened in the meantime, exit now. + if (this._dataReady) { + return; + } + + try { + this._identities = JSON.parse(gTextDecoder.decode(bytes)); + this._dataReady = true; + } catch(error) { + this.loadError(error); + } + }, (error) => { + this.loadError(error); + }); + }, + + loadError(error) { + if (!(error instanceof OS.File.Error && error.becauseNoSuchFile) && + !(error instanceof Components.Exception && + error.result == Cr.NS_ERROR_FILE_NOT_FOUND)) { + // Let's report the error. + Cu.reportError(error); + } + + // If synchronous loading happened in the meantime, exit now. + if (this._dataReady) { + return; + } + + this._identities = this._defaultIdentities; + this._dataReady = true; + + this.saveSoon(); + }, + + saveSoon() { + this._saver.arm(); + }, + + save() { + let bytes = gTextEncoder.encode(JSON.stringify(this._identities)); + return OS.File.writeAtomic(this._path, bytes, + { tmpPath: this._path + ".tmp" }); + }, + + ensureDataReady() { + if (this._dataReady) { + return; + } + + try { + // This reads the file and automatically detects the UTF-8 encoding. + let inputStream = Cc["@mozilla.org/network/file-input-stream;1"] + .createInstance(Ci.nsIFileInputStream); + inputStream.init(new FileUtils.File(this._path), + FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0); + try { + let json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON); + this._identities = json.decodeFromStream(inputStream, + inputStream.available()); + this._dataReady = true; + } finally { + inputStream.close(); + } + } catch (error) { + this.loadError(error); + return; + } + }, + getIdentities() { + this.ensureDataReady(); return this._identities.filter(info => info.public); }, getPrivateIdentity(label) { + this.ensureDataReady(); return this._identities.find(info => !info.public && info.label == label); }, getIdentityFromId(userContextId) { + this.ensureDataReady(); return this._identities.find(info => info.userContextId == userContextId); }, @@ -122,3 +232,5 @@ this.ContextualIdentityService = { } }, } + +ContextualIdentityService.init(); From 89e03b112fa3524d800328277b72df23319ae993 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 22 Jul 2016 16:19:46 +0200 Subject: [PATCH 031/135] Bug 1287091 - part 2 - ContextualIdentityService must store telemetry data in a separate array, r=Gijs --- .../contextualidentity/ContextualIdentityService.jsm | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm index 59b8c5acd414..8a2c1871d538 100644 --- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm +++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm @@ -41,7 +41,6 @@ this.ContextualIdentityService = { color: "#00a7e0", label: "userContextPersonal.label", accessKey: "userContextPersonal.accesskey", - alreadyOpened: false, telemetryId: 1, }, { userContextId: 2, @@ -50,7 +49,6 @@ this.ContextualIdentityService = { color: "#f89c24", label: "userContextWork.label", accessKey: "userContextWork.accesskey", - alreadyOpened: false, telemetryId: 2, }, { userContextId: 3, @@ -59,7 +57,6 @@ this.ContextualIdentityService = { color: "#7dc14c", label: "userContextBanking.label", accessKey: "userContextBanking.accesskey", - alreadyOpened: false, telemetryId: 3, }, { userContextId: 4, @@ -68,7 +65,6 @@ this.ContextualIdentityService = { color: "#ee5195", label: "userContextShopping.label", accessKey: "userContextShopping.accesskey", - alreadyOpened: false, telemetryId: 4, }, { userContextId: Math.pow(2, 31) - 1, @@ -76,11 +72,11 @@ this.ContextualIdentityService = { icon: "", color: "", label: "userContextIdInternal.thumbnail", - accessKey: "", - alreadyOpened: false }, + accessKey: "" }, ], _identities: null, + _openedIdentities: new Set(), _path: null, _dataReady: false, @@ -219,8 +215,8 @@ this.ContextualIdentityService = { return; } - if (!identity.alreadyOpened) { - identity.alreadyOpened = true; + if (this._openedIdentities.has(userContextId)) { + this._openedIdentities.add(userContextId); Services.telemetry.getHistogramById("UNIQUE_CONTAINERS_OPENED").add(1); } From 0d52ef50ca9fb363090bf32fbf095a859191ee4b Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 22 Jul 2016 16:19:50 +0200 Subject: [PATCH 032/135] Bug 1287091 - part 3 - ContextualIdentityService JSON file should have versions, r=Gijs --- .../ContextualIdentityService.jsm | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm index 8a2c1871d538..009f05db494b 100644 --- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm +++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm @@ -67,7 +67,7 @@ this.ContextualIdentityService = { accessKey: "userContextShopping.accesskey", telemetryId: 4, }, - { userContextId: Math.pow(2, 31) - 1, + { userContextId: 5, public: false, icon: "", color: "", @@ -77,6 +77,7 @@ this.ContextualIdentityService = { _identities: null, _openedIdentities: new Set(), + _lastUserContextId: 0, _path: null, _dataReady: false, @@ -101,7 +102,16 @@ this.ContextualIdentityService = { } try { - this._identities = JSON.parse(gTextDecoder.decode(bytes)); + let data = JSON.parse(gTextDecoder.decode(bytes)); + if (data.version != 1) { + dump("ERROR - ContextualIdentityService - Unknown version found in " + this._path + "\n"); + this.loadError(null); + return; + } + + this._identities = data.identities; + this._lastUserContextId = data.lastUserContextId; + this._dataReady = true; } catch(error) { this.loadError(error); @@ -112,7 +122,8 @@ this.ContextualIdentityService = { }, loadError(error) { - if (!(error instanceof OS.File.Error && error.becauseNoSuchFile) && + if (error != null && + !(error instanceof OS.File.Error && error.becauseNoSuchFile) && !(error instanceof Components.Exception && error.result == Cr.NS_ERROR_FILE_NOT_FOUND)) { // Let's report the error. @@ -125,6 +136,8 @@ this.ContextualIdentityService = { } this._identities = this._defaultIdentities; + this._lastUserContextId = this._defaultIdentities.length; + this._dataReady = true; this.saveSoon(); @@ -135,7 +148,13 @@ this.ContextualIdentityService = { }, save() { - let bytes = gTextEncoder.encode(JSON.stringify(this._identities)); + let object = { + version: 1, + lastUserContextId: this._lastUserContextId, + identities: this._identities + }; + + let bytes = gTextEncoder.encode(JSON.stringify(object)); return OS.File.writeAtomic(this._path, bytes, { tmpPath: this._path + ".tmp" }); }, From 2809a4efe7694762fee948d600e4d5005324b482 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 22 Jul 2016 16:19:50 +0200 Subject: [PATCH 033/135] Bug 1287091 - part 4 - ContextualIdentityService create/remove/update, r=Gijs --- browser/base/content/utilityOverlay.js | 8 +- .../customizableui/CustomizableWidgets.jsm | 2 +- .../ContextualIdentityService.jsm | 90 +++++++++++++++---- .../components/contextualidentity/moz.build | 2 + .../tests/unit/test_basic.js | 67 ++++++++++++++ .../tests/unit/xpcshell.ini | 3 + 6 files changed, 153 insertions(+), 19 deletions(-) create mode 100644 toolkit/components/contextualidentity/tests/unit/test_basic.js create mode 100644 toolkit/components/contextualidentity/tests/unit/xpcshell.ini diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index 458a3563ed3b..e59fa56cb89d 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -445,8 +445,12 @@ function createUserContextMenu(event, addCommandAttribute = true, excludeUserCon let menuitem = document.createElement("menuitem"); menuitem.setAttribute("usercontextid", identity.userContextId); - menuitem.setAttribute("label", bundle.getString(identity.label)); - menuitem.setAttribute("accesskey", bundle.getString(identity.accessKey)); + menuitem.setAttribute("label", ContextualIdentityService.getUserContextLabel(identity.userContextId)); + + if (identity.accessKey) { + menuitem.setAttribute("accesskey", bundle.getString(identity.accessKey)); + } + menuitem.classList.add("menuitem-iconic"); if (addCommandAttribute) { diff --git a/browser/components/customizableui/CustomizableWidgets.jsm b/browser/components/customizableui/CustomizableWidgets.jsm index 8ee76afe86e4..b26aa9c8336e 100644 --- a/browser/components/customizableui/CustomizableWidgets.jsm +++ b/browser/components/customizableui/CustomizableWidgets.jsm @@ -1134,7 +1134,7 @@ const CustomizableWidgets = [ ContextualIdentityService.getIdentities().forEach(identity => { let bundle = doc.getElementById("bundle_browser"); - let label = bundle.getString(identity.label); + let label = ContextualIdentityService.getUserContextLabel(identity.userContextId); let item = doc.createElementNS(kNSXUL, "toolbarbutton"); item.setAttribute("label", label); diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm index 009f05db494b..3d614581a793 100644 --- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm +++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm @@ -33,13 +33,17 @@ XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask", XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm"); -this.ContextualIdentityService = { +function _ContextualIdentityService(path) { + this.init(path); +} + +_ContextualIdentityService.prototype = { _defaultIdentities: [ { userContextId: 1, public: true, icon: "chrome://browser/skin/usercontext/personal.svg", color: "#00a7e0", - label: "userContextPersonal.label", + l10nID: "userContextPersonal.label", accessKey: "userContextPersonal.accesskey", telemetryId: 1, }, @@ -47,7 +51,7 @@ this.ContextualIdentityService = { public: true, icon: "chrome://browser/skin/usercontext/work.svg", color: "#f89c24", - label: "userContextWork.label", + l10nID: "userContextWork.label", accessKey: "userContextWork.accesskey", telemetryId: 2, }, @@ -55,7 +59,7 @@ this.ContextualIdentityService = { public: true, icon: "chrome://browser/skin/usercontext/banking.svg", color: "#7dc14c", - label: "userContextBanking.label", + l10nID: "userContextBanking.label", accessKey: "userContextBanking.accesskey", telemetryId: 3, }, @@ -63,7 +67,7 @@ this.ContextualIdentityService = { public: true, icon: "chrome://browser/skin/usercontext/shopping.svg", color: "#ee5195", - label: "userContextShopping.label", + l10nID: "userContextShopping.label", accessKey: "userContextShopping.accesskey", telemetryId: 4, }, @@ -71,7 +75,7 @@ this.ContextualIdentityService = { public: false, icon: "", color: "", - label: "userContextIdInternal.thumbnail", + name: "userContextIdInternal.thumbnail", accessKey: "" }, ], @@ -84,9 +88,8 @@ this.ContextualIdentityService = { _saver: null, - init() { - this._path = OS.Path.join(OS.Constants.Path.profileDir, "containers.json"); - + init(path) { + this._path = path; this._saver = new DeferredTask(() => this.save(), SAVE_DELAY_MS); AsyncShutdown.profileBeforeChange.addBlocker("ContextualIdentityService: writing data", () => this._saver.finalize()); @@ -159,6 +162,49 @@ this.ContextualIdentityService = { { tmpPath: this._path + ".tmp" }); }, + create(name, icon, color) { + let identity = { + userContextId: ++this._lastUserContextId, + public: true, + icon, + color, + name + }; + + this._identities.push(identity); + this.saveSoon(); + + return Cu.cloneInto(identity, {}); + }, + + update(userContextId, name, icon, color) { + let identity = this._identities.find(identity => identity.userContextId == userContextId && + identity.public); + if (identity) { + identity.name = name; + identity.color = color; + identity.icon = icon; + delete identity.l10nID; + delete identity.accessKey; + this.saveSoon(); + } + + return !!identity; + }, + + remove(userContextId) { + let index = this._identities.findIndex(i => i.userContextId == userContextId && i.public); + if (index == -1) { + return false; + } + + this._identities.splice(index, 1); + this._openedIdentities.delete(userContextId); + this.saveSoon(); + + return true; + }, + ensureDataReady() { if (this._dataReady) { return; @@ -186,17 +232,18 @@ this.ContextualIdentityService = { getIdentities() { this.ensureDataReady(); - return this._identities.filter(info => info.public); + return Cu.cloneInto(this._identities.filter(info => info.public), {}); }, - getPrivateIdentity(label) { + getPrivateIdentity(name) { this.ensureDataReady(); - return this._identities.find(info => !info.public && info.label == label); + return Cu.cloneInto(this._identities.find(info => !info.public && info.name == name), {}); }, getIdentityFromId(userContextId) { this.ensureDataReady(); - return this._identities.find(info => info.userContextId == userContextId); + return Cu.cloneInto(this._identities.find(info => info.userContextId == userContextId && + info.public), {}); }, getUserContextLabel(userContextId) { @@ -204,7 +251,13 @@ this.ContextualIdentityService = { if (!identity.public) { return ""; } - return gBrowserBundle.GetStringFromName(identity.label); + + // We cannot localize the user-created identity names. + if (identity.name) { + return identity.name; + } + + return gBrowserBundle.GetStringFromName(identity.l10nID); }, setTabStyle(tab) { @@ -246,6 +299,11 @@ this.ContextualIdentityService = { .add(identity.telemetryId); } }, -} -ContextualIdentityService.init(); + createNewInstanceForTesting(path) { + return new _ContextualIdentityService(path); + }, +}; + +let path = OS.Path.join(OS.Constants.Path.profileDir, "containers.json"); +this.ContextualIdentityService = new _ContextualIdentityService(path); diff --git a/toolkit/components/contextualidentity/moz.build b/toolkit/components/contextualidentity/moz.build index 680c7bd0ea44..9188421f9ec1 100644 --- a/toolkit/components/contextualidentity/moz.build +++ b/toolkit/components/contextualidentity/moz.build @@ -7,3 +7,5 @@ EXTRA_JS_MODULES += [ 'ContextualIdentityService.jsm', ] + +XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] diff --git a/toolkit/components/contextualidentity/tests/unit/test_basic.js b/toolkit/components/contextualidentity/tests/unit/test_basic.js new file mode 100644 index 000000000000..4d17b9a267cc --- /dev/null +++ b/toolkit/components/contextualidentity/tests/unit/test_basic.js @@ -0,0 +1,67 @@ +"use strict"; + +do_get_profile(); + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Cu.import("resource://gre/modules/ContextualIdentityService.jsm"); + +const TEST_STORE_FILE_NAME = "test-containers.json"; + +let cis; + +// Basic tests +add_task(function() { + ok(!!ContextualIdentityService, "ContextualIdentityService exists"); + + cis = ContextualIdentityService.createNewInstanceForTesting(TEST_STORE_FILE_NAME); + ok(!!cis, "We have our instance of ContextualIdentityService"); + + equal(cis.getIdentities().length, 4, "By default, 4 containers."); + equal(cis.getIdentityFromId(0), null, "No identity with id 0"); + + ok(!!cis.getIdentityFromId(1), "Identity 1 exists"); + ok(!!cis.getIdentityFromId(2), "Identity 2 exists"); + ok(!!cis.getIdentityFromId(3), "Identity 3 exists"); + ok(!!cis.getIdentityFromId(4), "Identity 4 exists"); +}); + +// Create a new identity +add_task(function() { + equal(cis.getIdentities().length, 4, "By default, 4 containers."); + + let identity = cis.create("New Container", "Icon", "Color"); + ok(!!identity, "New container created"); + equal(identity.name, "New Container", "Name matches"); + equal(identity.icon, "Icon", "Icon matches"); + equal(identity.color, "Color", "Color matches"); + + equal(cis.getIdentities().length, 5, "Expected 5 containers."); + + ok(!!cis.getIdentityFromId(identity.userContextId), "Identity exists"); + equal(cis.getIdentityFromId(identity.userContextId).name, "New Container", "Identity name is OK"); + equal(cis.getIdentityFromId(identity.userContextId).icon, "Icon", "Identity icon is OK"); + equal(cis.getIdentityFromId(identity.userContextId).color, "Color", "Identity color is OK"); + equal(cis.getUserContextLabel(identity.userContextId), "New Container", "Identity label is OK"); + + // Remove an identity + equal(cis.remove(-1), false, "cis.remove() returns false if identity doesn't exist."); + equal(cis.remove(1), true, "cis.remove() returns true if identity exists."); + + equal(cis.getIdentities().length, 4, "Expected 4 containers."); +}); + +// Update an identity +add_task(function() { + ok(!!cis.getIdentityFromId(2), "Identity 2 exists"); + + equal(cis.update(-1, "Container", "Icon", "Color"), false, "Update returns false if the identity doesn't exist"); + + equal(cis.update(2, "Container", "Icon", "Color"), true, "Update returns true if everything is OK"); + + ok(!!cis.getIdentityFromId(2), "Identity exists"); + equal(cis.getIdentityFromId(2).name, "Container", "Identity name is OK"); + equal(cis.getIdentityFromId(2).icon, "Icon", "Identity icon is OK"); + equal(cis.getIdentityFromId(2).color, "Color", "Identity color is OK"); + equal(cis.getUserContextLabel(2), "Container", "Identity label is OK"); +}); diff --git a/toolkit/components/contextualidentity/tests/unit/xpcshell.ini b/toolkit/components/contextualidentity/tests/unit/xpcshell.ini new file mode 100644 index 000000000000..b45ff2c30f29 --- /dev/null +++ b/toolkit/components/contextualidentity/tests/unit/xpcshell.ini @@ -0,0 +1,3 @@ +[DEFAULT] + +[test_basic.js] From 0925e452df95dceb1a25638536f5db9929d6aa2c Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 22 Jul 2016 16:19:50 +0200 Subject: [PATCH 034/135] Bug 1287091 - part 5 - ContextualIdentityService should dispatch 'clear-origin-data' when a container is deleted, r=Gijs --- .../contextualidentity/ContextualIdentityService.jsm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm index 3d614581a793..5a60ef413b40 100644 --- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm +++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm @@ -198,6 +198,9 @@ _ContextualIdentityService.prototype = { return false; } + Services.obs.notifyObservers(null, "clear-origin-data", + JSON.stringify({ userContextId })); + this._identities.splice(index, 1); this._openedIdentities.delete(userContextId); this.saveSoon(); From e20e678f4831c5f8ac5291b202dc5ae03e259807 Mon Sep 17 00:00:00 2001 From: Sotaro Ikeda Date: Fri, 22 Jul 2016 07:26:20 -0700 Subject: [PATCH 035/135] Bug 1288648 - Disable some WebVTT tests r=jgraham --- .../cues-with-video/processing-model/align_start.html.ini | 1 + .../processing-model/align_start_wrapped.html.ini | 1 + .../bold_object/bold_transition_with_timestamp.html.ini | 1 + 3 files changed, 3 insertions(+) diff --git a/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/align_start.html.ini b/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/align_start.html.ini index 53f992870f10..fa6af3ea320b 100644 --- a/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/align_start.html.ini +++ b/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/align_start.html.ini @@ -1,3 +1,4 @@ [align_start.html] type: reftest expected: FAIL + disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1288648 diff --git a/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/align_start_wrapped.html.ini b/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/align_start_wrapped.html.ini index 31ad38633705..90660c27fb72 100644 --- a/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/align_start_wrapped.html.ini +++ b/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/align_start_wrapped.html.ini @@ -1,3 +1,4 @@ [align_start_wrapped.html] type: reftest expected: FAIL + disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1288648 diff --git a/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_transition_with_timestamp.html.ini b/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_transition_with_timestamp.html.ini index 6317bcf2a986..7f8b322a5713 100644 --- a/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_transition_with_timestamp.html.ini +++ b/testing/web-platform/meta/webvtt/rendering/cues-with-video/processing-model/selectors/cue_function/bold_object/bold_transition_with_timestamp.html.ini @@ -1,3 +1,4 @@ [bold_transition_with_timestamp.html] type: reftest expected: FAIL + disabled: https://bugzilla.mozilla.org/show_bug.cgi?id=1288648 From 50904b3baba10a92e20bee132c2c6293ccf8ab47 Mon Sep 17 00:00:00 2001 From: Trevor Saunders Date: Tue, 28 Jun 2016 10:28:33 -0400 Subject: [PATCH 036/135] bug 1272498 - rewrite NS_InvokeByIndex in assembly r=froydnj --- xpcom/reflect/xptcall/md/unix/moz.build | 2 + .../md/unix/xptcinvoke_asm_x86_64_unix.s | 92 +++++++++++++ .../md/unix/xptcinvoke_x86_64_unix.cpp | 129 ++---------------- 3 files changed, 102 insertions(+), 121 deletions(-) create mode 100644 xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_x86_64_unix.s diff --git a/xpcom/reflect/xptcall/md/unix/moz.build b/xpcom/reflect/xptcall/md/unix/moz.build index c8576dfa93d3..f8f06799934d 100644 --- a/xpcom/reflect/xptcall/md/unix/moz.build +++ b/xpcom/reflect/xptcall/md/unix/moz.build @@ -28,6 +28,7 @@ if CONFIG['OS_ARCH'] in ('Linux', 'Bitrig', 'DragonFly', 'FreeBSD', 'NetBSD', 'O CONFIG['OS_ARCH'].startswith('GNU_'): if CONFIG['OS_TEST'] == 'x86_64': SOURCES += [ + 'xptcinvoke_asm_x86_64_unix.s', 'xptcinvoke_x86_64_unix.cpp', 'xptcstubs_x86_64_linux.cpp', ] @@ -53,6 +54,7 @@ if CONFIG['OS_ARCH'] == 'SunOS' and '86' in CONFIG['OS_TEST']: if CONFIG['OS_TEST'] == 'x86_64': if CONFIG['GNU_CC']: SOURCES += [ + 'xptcinvoke_asm_x86_64_unix.s', 'xptcinvoke_x86_64_unix.cpp', 'xptcstubs_x86_64_linux.cpp' ] diff --git a/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_x86_64_unix.s b/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_x86_64_unix.s new file mode 100644 index 000000000000..5045b0e6cb3b --- /dev/null +++ b/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_x86_64_unix.s @@ -0,0 +1,92 @@ +# 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/. + +.intel_syntax noprefix + +# nsresult NS_InvokeByIndex(nsISupports* this, uint32_t aVtableIndex, +# uint32_t argc, nsXPTCVariant* argv); +.text +.global NS_InvokeByIndex +.type NS_InvokeByIndex, @function +.align 4 +NS_InvokeByIndex: + push rbp + mov rbp, rsp + +# save r12 and r13 because we use them and they are callee saved. + push r12 + push r13 + +# save this and the vtable index because we need them after setting up the +# stack. + mov r12, rdi + mov r13, rsi + +# allocate space for stack arguments, in theory we only need 8 * (argc - 5) +# bytes because at least 5 arguments will go in registers, but for now it is +# just simpler to allocate 8 * (argc - 1) bytes. Note that we treat the this +# pointer specially. + lea eax, [edx * 8] + sub rsp, rax + +# if there is an odd number of args the stack can be misaligned so realign it. + and rsp, 0xffffffffffffff00 + +# pass the stack slot area to InvokeCopyToStack. + mov r8, rsp + +# setup space for the register slots: there are 5 integer ones and 8 floating +# point ones. So we need 104 bytes of space, but we allocate 112 to keep rsp +# aligned to 16 bytes. + sub rsp, 112 + +# the first argument to InvokeCopyToStack is the integer register area, and the +# second is the floating point area. + mov rdi, rsp + lea rsi, [rsp + 40] + +# The 3rd and 4th arguments to InvokeCopyToStack are already in the right +# registers because they are our 3rd and 4th arguments. So now we can just +# call InvokeCopyToStack. + call InvokeCopyToStack + +# setup this + mov rdi, r12 + +# copy the integer arguments into place. + mov rsi, [rsp] + mov rdx, [rsp + 8] + mov rcx, [rsp + 16] + mov r8, [rsp + 24] + mov r9, [rsp + 32] + +# copy the float arguments into place + movsd xmm0, [rsp + 40] + movsd xmm1, [rsp + 48] + movsd xmm2, [rsp + 56] + movsd xmm3, [rsp + 64] + movsd xmm4, [rsp + 72] + movsd xmm5, [rsp + 80] + movsd xmm6, [rsp + 88] + movsd xmm7, [rsp + 96] + +# get rid of the scratch space for registers + add rsp, 112 + +# load the function pointer and call + lea eax, [r13d * 8] + add rax, [rdi] + call [rax] + +# r12 and r13 were pushed relative to the old stack pointer which is now the +# frame pointer. + mov r12, [rbp - 0x8] + mov r13, [rbp - 0x10] + + mov rsp, rbp + pop rbp + ret + +// Magic indicating no need for an executable stack +.section .note.GNU-stack, "", @progbits ; .previous diff --git a/xpcom/reflect/xptcall/md/unix/xptcinvoke_x86_64_unix.cpp b/xpcom/reflect/xptcall/md/unix/xptcinvoke_x86_64_unix.cpp index 08e51988971c..a9db2a693a58 100644 --- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_x86_64_unix.cpp +++ b/xpcom/reflect/xptcall/md/unix/xptcinvoke_x86_64_unix.cpp @@ -8,46 +8,19 @@ #include "xptcprivate.h" -// 6 integral parameters are passed in registers -const uint32_t GPR_COUNT = 6; +// 6 integral parameters are passed in registers, but 1 is |this| which isn't +// considered here. +const uint32_t GPR_COUNT = 5; // 8 floating point parameters are passed in SSE registers const uint32_t FPR_COUNT = 8; -// Remember that these 'words' are 64-bit long -static inline void -invoke_count_words(uint32_t paramCount, nsXPTCVariant * s, - uint32_t & nr_stack) +extern "C" void +InvokeCopyToStack(uint64_t * gpregs, double * fpregs, + uint32_t paramCount, nsXPTCVariant * s, + uint64_t* d) { - uint32_t nr_gpr; - uint32_t nr_fpr; - nr_gpr = 1; // skip one GP register for 'that' - nr_fpr = 0; - nr_stack = 0; - - /* Compute number of eightbytes of class MEMORY. */ - for (uint32_t i = 0; i < paramCount; i++, s++) { - if (!s->IsPtrData() - && (s->type == nsXPTType::T_FLOAT || s->type == nsXPTType::T_DOUBLE)) { - if (nr_fpr < FPR_COUNT) - nr_fpr++; - else - nr_stack++; - } - else { - if (nr_gpr < GPR_COUNT) - nr_gpr++; - else - nr_stack++; - } - } -} - -static void -invoke_copy_to_stack(uint64_t * d, uint32_t paramCount, nsXPTCVariant * s, - uint64_t * gpregs, double * fpregs) -{ - uint32_t nr_gpr = 1u; // skip one GP register for 'that' + uint32_t nr_gpr = 0u; // skip one GP register for 'that' uint32_t nr_fpr = 0u; uint64_t value = 0u; @@ -100,89 +73,3 @@ invoke_copy_to_stack(uint64_t * d, uint32_t paramCount, nsXPTCVariant * s, } } } - -// Disable avx for the next function to allow compilation with -// -march=native on new machines, or similar hardcoded -march options. -// Having avx enabled appears to change the alignment behavior of alloca -// (apparently adding an extra 16 bytes) of padding/alignment (and using -// 32-byte alignment instead of 16-byte). This seems to be the best -// available workaround, given that this code, which should perhaps -// better be written in assembly, is written in C++. -#ifndef __clang__ -#pragma GCC push_options -#pragma GCC target ("no-avx") -#endif - -// Avoid AddressSanitizer instrumentation for the next function because it -// depends on __builtin_alloca behavior and alignment that cannot be relied on -// once the function is compiled with a version of ASan that has dynamic-alloca -// instrumentation enabled. - -MOZ_ASAN_BLACKLIST -EXPORT_XPCOM_API(nsresult) -NS_InvokeByIndex(nsISupports * that, uint32_t methodIndex, - uint32_t paramCount, nsXPTCVariant * params) -{ - uint32_t nr_stack; - invoke_count_words(paramCount, params, nr_stack); - - // Stack, if used, must be 16-bytes aligned - if (nr_stack) - nr_stack = (nr_stack + 1) & ~1; - - // Load parameters to stack, if necessary - uint64_t *stack = (uint64_t *) __builtin_alloca(nr_stack * 8); - uint64_t gpregs[GPR_COUNT]; - double fpregs[FPR_COUNT]; - invoke_copy_to_stack(stack, paramCount, params, gpregs, fpregs); - - // We used to have switches to make sure we would only load the registers - // that are needed for this call. That produced larger code that was - // not faster in practice. It also caused compiler warnings about the - // variables being used uninitialized. - // We now just load every every register. There could still be a warning - // from a memory analysis tools that we are loading uninitialized stack - // positions. - - // FIXME: this function depends on the above __builtin_alloca placing - // the array in the correct spot for the ABI. - - // Load FPR registers from fpregs[] - double d0, d1, d2, d3, d4, d5, d6, d7; - - d7 = fpregs[7]; - d6 = fpregs[6]; - d5 = fpregs[5]; - d4 = fpregs[4]; - d3 = fpregs[3]; - d2 = fpregs[2]; - d1 = fpregs[1]; - d0 = fpregs[0]; - - // Load GPR registers from gpregs[] - uint64_t a0, a1, a2, a3, a4, a5; - - a5 = gpregs[5]; - a4 = gpregs[4]; - a3 = gpregs[3]; - a2 = gpregs[2]; - a1 = gpregs[1]; - a0 = (uint64_t) that; - - // Get pointer to method - uint64_t methodAddress = *((uint64_t *)that); - methodAddress += 8 * methodIndex; - methodAddress = *((uint64_t *)methodAddress); - - typedef nsresult (*Method)(uint64_t, uint64_t, uint64_t, uint64_t, - uint64_t, uint64_t, double, double, double, - double, double, double, double, double); - nsresult result = ((Method)methodAddress)(a0, a1, a2, a3, a4, a5, - d0, d1, d2, d3, d4, d5, - d6, d7); - return result; -} - -#ifndef __clang__ -#pragma GCC pop_options -#endif From 60ab8339e0de27c757307ab1e5da762397ec3e15 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Fri, 22 Jul 2016 16:50:10 +0200 Subject: [PATCH 037/135] Bug 1288736 - Add some missing rv.SuppressException(), r=smaug --- dom/base/BodyUtil.cpp | 1 + dom/base/File.cpp | 4 +++- dom/base/nsContentUtils.cpp | 7 +++++-- dom/base/nsFrameMessageManager.cpp | 1 + dom/broadcastchannel/BroadcastChannelChild.cpp | 5 +++-- dom/canvas/ImageBitmap.cpp | 2 ++ dom/devicestorage/nsDeviceStorage.cpp | 2 ++ dom/events/BeforeAfterKeyboardEvent.cpp | 4 +++- dom/events/DataTransfer.cpp | 4 +++- dom/filehandle/ActorsParent.cpp | 1 + dom/filesystem/FileSystemBase.cpp | 2 ++ dom/filesystem/FileSystemRequestParent.cpp | 1 + dom/filesystem/FileSystemTaskBase.cpp | 1 + dom/html/HTMLInputElement.cpp | 4 +++- dom/ipc/Blob.cpp | 2 ++ dom/ipc/ContentParent.cpp | 1 + dom/ipc/TabChild.cpp | 1 + dom/media/webaudio/AudioDestinationNode.cpp | 1 + dom/media/webaudio/ScriptProcessorNode.cpp | 1 + dom/network/TCPSocketParent.cpp | 10 ++++++++-- dom/performance/PerformanceObserver.cpp | 4 +++- dom/telephony/MMICall.cpp | 1 + dom/tv/TVTuner.cpp | 5 +++++ dom/workers/ScriptLoader.cpp | 1 + dom/workers/WorkerPrivate.cpp | 2 ++ dom/xul/templates/nsXULTemplateQueryProcessorXML.cpp | 8 +++++++- .../windowwatcher/nsAutoWindowStateHelper.cpp | 1 + layout/forms/nsFileControlFrame.cpp | 1 + 28 files changed, 66 insertions(+), 12 deletions(-) diff --git a/dom/base/BodyUtil.cpp b/dom/base/BodyUtil.cpp index b5870338776d..397e5f8328cd 100644 --- a/dom/base/BodyUtil.cpp +++ b/dom/base/BodyUtil.cpp @@ -324,6 +324,7 @@ private: ErrorResult rv; mFormData->Append(name, *file, dummy, rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return false; } } diff --git a/dom/base/File.cpp b/dom/base/File.cpp index cc7f73fea18b..fdfb34ac49cd 100644 --- a/dom/base/File.cpp +++ b/dom/base/File.cpp @@ -924,7 +924,9 @@ BlobImplFile::GetType(nsAString& aType) ErrorResult rv; runnable->Dispatch(rv); - NS_WARN_IF(rv.Failed()); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + } return; } diff --git a/dom/base/nsContentUtils.cpp b/dom/base/nsContentUtils.cpp index aaef9669f3f8..cc3f4871f270 100644 --- a/dom/base/nsContentUtils.cpp +++ b/dom/base/nsContentUtils.cpp @@ -1803,9 +1803,12 @@ nsContentUtils::IsControlledByServiceWorker(nsIDocument* aDocument) ErrorResult rv; bool controlled = swm->IsControlled(aDocument, rv); - NS_WARN_IF(rv.Failed()); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + return false; + } - return !rv.Failed() && controlled; + return controlled; } /* static */ diff --git a/dom/base/nsFrameMessageManager.cpp b/dom/base/nsFrameMessageManager.cpp index 4a03067bb9e1..57d396f79816 100644 --- a/dom/base/nsFrameMessageManager.cpp +++ b/dom/base/nsFrameMessageManager.cpp @@ -792,6 +792,7 @@ nsFrameMessageManager::SendMessage(const nsAString& aMessageName, retval[i].Read(aCx, &ret, rv); if (rv.Failed()) { MOZ_ASSERT(false, "Unable to read structured clone in SendMessage"); + rv.SuppressException(); return NS_ERROR_UNEXPECTED; } diff --git a/dom/broadcastchannel/BroadcastChannelChild.cpp b/dom/broadcastchannel/BroadcastChannelChild.cpp index 1e7294cbbcc1..bcb7628f0400 100644 --- a/dom/broadcastchannel/BroadcastChannelChild.cpp +++ b/dom/broadcastchannel/BroadcastChannelChild.cpp @@ -99,6 +99,7 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData) ErrorResult rv; cloneData.Read(cx, &value, rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return true; } } @@ -112,8 +113,8 @@ BroadcastChannelChild::RecvNotify(const ClonedMessageData& aData) ErrorResult rv; RefPtr event = MessageEvent::Constructor(mBC, NS_LITERAL_STRING("message"), init, rv); - if (rv.Failed()) { - NS_WARNING("Failed to create a MessageEvent object."); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return true; } diff --git a/dom/canvas/ImageBitmap.cpp b/dom/canvas/ImageBitmap.cpp index 0846ce8d5150..d87bc89733a4 100644 --- a/dom/canvas/ImageBitmap.cpp +++ b/dom/canvas/ImageBitmap.cpp @@ -91,6 +91,7 @@ CropAndCopyDataSourceSurface(DataSourceSurface* aSurface, const IntRect& aCropRe ErrorResult error; const IntRect positiveCropRect = FixUpNegativeDimension(aCropRect, error); if (NS_WARN_IF(error.Failed())) { + error.SuppressException(); return nullptr; } @@ -1106,6 +1107,7 @@ DecodeBlob(Blob& aBlob) ErrorResult error; aBlob.Impl()->GetInternalStream(getter_AddRefs(stream), error); if (NS_WARN_IF(error.Failed())) { + error.SuppressException(); return nullptr; } diff --git a/dom/devicestorage/nsDeviceStorage.cpp b/dom/devicestorage/nsDeviceStorage.cpp index ac34ab238cac..8604648db644 100644 --- a/dom/devicestorage/nsDeviceStorage.cpp +++ b/dom/devicestorage/nsDeviceStorage.cpp @@ -1958,6 +1958,7 @@ public: nsCOMPtr stream; mBlob->GetInternalStream(getter_AddRefs(stream), rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return Reject(POST_ERROR_EVENT_UNKNOWN); } @@ -2070,6 +2071,7 @@ public: nsCOMPtr stream; mBlob->GetInternalStream(getter_AddRefs(stream), rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return Reject(POST_ERROR_EVENT_UNKNOWN); } diff --git a/dom/events/BeforeAfterKeyboardEvent.cpp b/dom/events/BeforeAfterKeyboardEvent.cpp index 1fc40170952b..c94227755b9f 100644 --- a/dom/events/BeforeAfterKeyboardEvent.cpp +++ b/dom/events/BeforeAfterKeyboardEvent.cpp @@ -41,7 +41,9 @@ BeforeAfterKeyboardEvent::Constructor( new BeforeAfterKeyboardEvent(aOwner, nullptr, nullptr); ErrorResult rv; event->InitWithKeyboardEventInit(aOwner, aType, aParam, rv); - NS_WARN_IF(rv.Failed()); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + } event->mEvent->AsBeforeAfterKeyboardEvent()->mEmbeddedCancelled = aParam.mEmbeddedCancelled; diff --git a/dom/events/DataTransfer.cpp b/dom/events/DataTransfer.cpp index 4dad80261e87..88893a494991 100644 --- a/dom/events/DataTransfer.cpp +++ b/dom/events/DataTransfer.cpp @@ -1286,7 +1286,9 @@ DataTransfer::SetDataWithPrincipalFromOtherProcess(const nsAString& aFormat, RefPtr item = mItems->SetDataWithPrincipal(format, aData, aIndex, aPrincipal, /* aInsertOnly = */ false, aHidden, rv); - NS_WARN_IF(rv.Failed()); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + } } } diff --git a/dom/filehandle/ActorsParent.cpp b/dom/filehandle/ActorsParent.cpp index 0926a3489a90..13755c2a2b95 100644 --- a/dom/filehandle/ActorsParent.cpp +++ b/dom/filehandle/ActorsParent.cpp @@ -2536,6 +2536,7 @@ WriteOp::Init(FileHandle* aFileHandle) ErrorResult rv; blobImpl->GetInternalStream(getter_AddRefs(inputStream), rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return false; } diff --git a/dom/filesystem/FileSystemBase.cpp b/dom/filesystem/FileSystemBase.cpp index f0792efe295d..0127d8b8b2c3 100644 --- a/dom/filesystem/FileSystemBase.cpp +++ b/dom/filesystem/FileSystemBase.cpp @@ -84,12 +84,14 @@ FileSystemBase::GetRealPath(BlobImpl* aFile, nsIFile** aPath) const ErrorResult rv; aFile->GetMozFullPathInternal(filePath, rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return false; } rv = NS_NewNativeLocalFile(NS_ConvertUTF16toUTF8(filePath), true, aPath); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return false; } diff --git a/dom/filesystem/FileSystemRequestParent.cpp b/dom/filesystem/FileSystemRequestParent.cpp index b417bf697391..36d3735c5c14 100644 --- a/dom/filesystem/FileSystemRequestParent.cpp +++ b/dom/filesystem/FileSystemRequestParent.cpp @@ -35,6 +35,7 @@ FileSystemRequestParent::~FileSystemRequestParent() MOZ_ASSERT(mFileSystem); \ mTask = name##TaskParent::Create(mFileSystem, p, this, rv); \ if (NS_WARN_IF(rv.Failed())) { \ + rv.SuppressException(); \ return false; \ } \ break; \ diff --git a/dom/filesystem/FileSystemTaskBase.cpp b/dom/filesystem/FileSystemTaskBase.cpp index 4d6f6ecf4784..1ebec7edcc0a 100644 --- a/dom/filesystem/FileSystemTaskBase.cpp +++ b/dom/filesystem/FileSystemTaskBase.cpp @@ -150,6 +150,7 @@ FileSystemTaskChildBase::Start() ErrorResult rv; FileSystemParams params = GetRequestParams(serialization, rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return; } diff --git a/dom/html/HTMLInputElement.cpp b/dom/html/HTMLInputElement.cpp index a582c316dbfe..aebee3060aae 100644 --- a/dom/html/HTMLInputElement.cpp +++ b/dom/html/HTMLInputElement.cpp @@ -508,7 +508,9 @@ GetDOMFileOrDirectoryName(const OwningFileOrDirectory& aData, MOZ_ASSERT(aData.IsDirectory()); ErrorResult rv; aData.GetAsDirectory()->GetName(aName, rv); - NS_WARN_IF(rv.Failed()); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + } } } diff --git a/dom/ipc/Blob.cpp b/dom/ipc/Blob.cpp index d95172baba15..e36e634a1e90 100644 --- a/dom/ipc/Blob.cpp +++ b/dom/ipc/Blob.cpp @@ -859,6 +859,7 @@ CreateBlobImpl(const nsTArray& aBlobDatas, } if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return nullptr; } @@ -4394,6 +4395,7 @@ BlobParent::RecvGetFilePath(nsString* aFilePath) ErrorResult rv; mBlobImpl->GetMozFullPathInternal(filePath, rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return false; } diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 59e36b29e077..93ea2a76560d 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -3335,6 +3335,7 @@ ContentParent::RecvGetXPCOMProcessAttributes(bool* aIsOffline, ErrorResult rv; aInitialData->Write(jsapi.cx(), init, rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return false; } } diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 01407b477a83..e82355bd7304 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -220,6 +220,7 @@ TabChildBase::DispatchMessageManagerMessage(const nsAString& aMessageName, ErrorResult rv; data.Write(cx, json, rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return; } } diff --git a/dom/media/webaudio/AudioDestinationNode.cpp b/dom/media/webaudio/AudioDestinationNode.cpp index 137fb7b9ce3e..cfe960fb3677 100644 --- a/dom/media/webaudio/AudioDestinationNode.cpp +++ b/dom/media/webaudio/AudioDestinationNode.cpp @@ -157,6 +157,7 @@ public: AudioBuffer::Create(context, mNumberOfChannels, mLength, mSampleRate, mBuffer.forget(), rv); if (rv.Failed()) { + rv.SuppressException(); return; } diff --git a/dom/media/webaudio/ScriptProcessorNode.cpp b/dom/media/webaudio/ScriptProcessorNode.cpp index 92f6fb8d1297..09210d65de84 100644 --- a/dom/media/webaudio/ScriptProcessorNode.cpp +++ b/dom/media/webaudio/ScriptProcessorNode.cpp @@ -432,6 +432,7 @@ private: aNode->BufferSize(), context->SampleRate(), mInputBuffer.forget(), rv); if (rv.Failed()) { + rv.SuppressException(); return nullptr; } } diff --git a/dom/network/TCPSocketParent.cpp b/dom/network/TCPSocketParent.cpp index 4420f7ce365a..76c6df7f38e8 100644 --- a/dom/network/TCPSocketParent.cpp +++ b/dom/network/TCPSocketParent.cpp @@ -274,7 +274,10 @@ TCPSocketParent::RecvStartTLS() NS_ENSURE_TRUE(mSocket, true); ErrorResult rv; mSocket->UpgradeToSecure(rv); - NS_ENSURE_FALSE(rv.Failed(), true); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + } + return true; } @@ -292,7 +295,10 @@ TCPSocketParent::RecvResume() NS_ENSURE_TRUE(mSocket, true); ErrorResult rv; mSocket->Resume(rv); - NS_ENSURE_FALSE(rv.Failed(), true); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + } + return true; } diff --git a/dom/performance/PerformanceObserver.cpp b/dom/performance/PerformanceObserver.cpp index e7c4312a3663..11dd30ac233e 100644 --- a/dom/performance/PerformanceObserver.cpp +++ b/dom/performance/PerformanceObserver.cpp @@ -116,7 +116,9 @@ PerformanceObserver::Notify() ErrorResult rv; mCallback->Call(this, *list, *this, rv); - NS_WARN_IF(rv.Failed()); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + } mQueuedEntries.Clear(); } diff --git a/dom/telephony/MMICall.cpp b/dom/telephony/MMICall.cpp index 3cb2d3921c9d..24c5bdfadcac 100644 --- a/dom/telephony/MMICall.cpp +++ b/dom/telephony/MMICall.cpp @@ -31,6 +31,7 @@ MMICall::MMICall(nsPIDOMWindowInner* aWindow, const nsAString& aServiceCode) ErrorResult rv; RefPtr promise = Promise::Create(global, rv); if (rv.Failed()) { + rv.SuppressException(); return; } diff --git a/dom/tv/TVTuner.cpp b/dom/tv/TVTuner.cpp index 9bc0f17fc596..c9e429694f26 100644 --- a/dom/tv/TVTuner.cpp +++ b/dom/tv/TVTuner.cpp @@ -238,6 +238,7 @@ TVTuner::CreateSimulatedMediaStream() ElementCreationOptions options; RefPtr element = doc->CreateElement(VIDEO_TAG, options, error); if (NS_WARN_IF(error.Failed())) { + error.SuppressException(); return nullptr; } @@ -253,11 +254,13 @@ TVTuner::CreateSimulatedMediaStream() mediaElement->SetAutoplay(true, error); if (NS_WARN_IF(error.Failed())) { + error.SuppressException(); return nullptr; } mediaElement->SetLoop(true, error); if (NS_WARN_IF(error.Failed())) { + error.SuppressException(); return nullptr; } @@ -293,6 +296,7 @@ TVTuner::CreateSimulatedMediaStream() mediaElement->SetSrc(currentVideoBlobUrl, error); if (NS_WARN_IF(error.Failed())) { + error.SuppressException(); return nullptr; } @@ -300,6 +304,7 @@ TVTuner::CreateSimulatedMediaStream() // http://www.w3.org/TR/mediacapture-fromelement/ RefPtr stream = mediaElement->MozCaptureStream(error); if (NS_WARN_IF(error.Failed())) { + error.SuppressException(); return nullptr; } diff --git a/dom/workers/ScriptLoader.cpp b/dom/workers/ScriptLoader.cpp index c0cc492d117d..5d8287c5ffd5 100644 --- a/dom/workers/ScriptLoader.cpp +++ b/dom/workers/ScriptLoader.cpp @@ -1565,6 +1565,7 @@ CacheCreator::DeleteCache() // running. RefPtr promise = mCacheStorage->Delete(mCacheName, rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return; } diff --git a/dom/workers/WorkerPrivate.cpp b/dom/workers/WorkerPrivate.cpp index 9a2dee3a84ad..4814022225ca 100644 --- a/dom/workers/WorkerPrivate.cpp +++ b/dom/workers/WorkerPrivate.cpp @@ -760,6 +760,7 @@ public: RefPtr event = ExtendableMessageEvent::Constructor( aTarget, NS_LITERAL_STRING("message"), init, rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return false; } event->SetSource(client); @@ -6571,6 +6572,7 @@ WorkerPrivate::ConnectMessagePort(JSContext* aCx, ErrorResult rv; RefPtr port = MessagePort::Create(globalScope, aIdentifier, rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return false; } diff --git a/dom/xul/templates/nsXULTemplateQueryProcessorXML.cpp b/dom/xul/templates/nsXULTemplateQueryProcessorXML.cpp index feb59406d9e2..1c6fed25240c 100644 --- a/dom/xul/templates/nsXULTemplateQueryProcessorXML.cpp +++ b/dom/xul/templates/nsXULTemplateQueryProcessorXML.cpp @@ -45,7 +45,13 @@ nsXULTemplateResultSetXML::HasMoreElements(bool *aResult) // nodes, so just return false in this case. ErrorResult rv; uint32_t length = mResults->GetSnapshotLength(rv); - *aResult = !rv.Failed() && mPosition < length; + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + *aResult = false; + return NS_OK; + } + + *aResult = mPosition < length; return NS_OK; } diff --git a/embedding/components/windowwatcher/nsAutoWindowStateHelper.cpp b/embedding/components/windowwatcher/nsAutoWindowStateHelper.cpp index 427cea55e110..068f2a6dc418 100644 --- a/embedding/components/windowwatcher/nsAutoWindowStateHelper.cpp +++ b/embedding/components/windowwatcher/nsAutoWindowStateHelper.cpp @@ -59,6 +59,7 @@ nsAutoWindowStateHelper::DispatchEventToChrome(const char* aEventName) ErrorResult rv; RefPtr event = doc->CreateEvent(NS_LITERAL_STRING("Events"), rv); if (rv.Failed()) { + rv.SuppressException(); return false; } event->InitEvent(NS_ConvertASCIItoUTF16(aEventName), true, true); diff --git a/layout/forms/nsFileControlFrame.cpp b/layout/forms/nsFileControlFrame.cpp index 5603f944ecaa..e79589d4cac3 100644 --- a/layout/forms/nsFileControlFrame.cpp +++ b/layout/forms/nsFileControlFrame.cpp @@ -267,6 +267,7 @@ nsFileControlFrame::DnDListener::IsValidDropData(nsIDOMDataTransfer* aDOMDataTra ErrorResult rv; RefPtr types = dataTransfer->GetTypes(rv); if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); return false; } From 813df3ea0e6a2f57622f928dcb24a573469f887f Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Fri, 22 Jul 2016 09:31:09 -0600 Subject: [PATCH 038/135] backout 69094e855e27 for mozinfo test failures --- python/mozbuild/mozbuild/mozinfo.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/python/mozbuild/mozbuild/mozinfo.py b/python/mozbuild/mozbuild/mozinfo.py index f96a2ae08e6e..c6bb9b2de872 100755 --- a/python/mozbuild/mozbuild/mozinfo.py +++ b/python/mozbuild/mozbuild/mozinfo.py @@ -140,9 +140,6 @@ def build_dict(config, env=os.environ): d['platform_guess'] = guess_platform() d['buildtype_guess'] = guess_buildtype() - if d['buildapp'] == 'mobile/android' and 'MOZ_ANDROID_MIN_SDK_VERSION' in substs: - d['android_min_sdk'] = substs['MOZ_ANDROID_MIN_SDK_VERSION'] - return d From 01040de30f277380010c3fed5faf0e545e85dbfd Mon Sep 17 00:00:00 2001 From: George Wright Date: Thu, 21 Jul 2016 13:01:49 -0400 Subject: [PATCH 039/135] Bug 1288474 - Don't accept TextureClient returns if the pool has been destroyed r=nical --- gfx/layers/client/TextureClientPool.cpp | 6 ++++-- gfx/layers/client/TextureClientPool.h | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/gfx/layers/client/TextureClientPool.cpp b/gfx/layers/client/TextureClientPool.cpp index dd3d8e0c7f5d..6e4b588c09ca 100644 --- a/gfx/layers/client/TextureClientPool.cpp +++ b/gfx/layers/client/TextureClientPool.cpp @@ -35,6 +35,7 @@ TextureClientPool::TextureClientPool(LayersBackend aLayersBackend, , mPoolIncrementSize(aPoolIncrementSize) , mOutstandingClients(0) , mSurfaceAllocator(aAllocator) + , mDestroyed(false) { TCP_LOG("TexturePool %p created with maximum unused texture clients %u\n", this, mInitialPoolSize); @@ -149,7 +150,7 @@ TextureClientPool::AllocateTextureClients(size_t aSize) void TextureClientPool::ReturnTextureClient(TextureClient *aClient) { - if (!aClient) { + if (!aClient || mDestroyed) { return; } #ifdef GFX_DEBUG_TRACK_CLIENTS_IN_POOL @@ -170,7 +171,7 @@ TextureClientPool::ReturnTextureClient(TextureClient *aClient) void TextureClientPool::ReturnTextureClientDeferred(TextureClient* aClient) { - if (!aClient) { + if (!aClient || mDestroyed) { return; } MOZ_ASSERT(aClient->GetReadLock()); @@ -285,6 +286,7 @@ TextureClientPool::Clear() void TextureClientPool::Destroy() { Clear(); + mDestroyed = true; mInitialPoolSize = 0; mPoolIncrementSize = 0; } diff --git a/gfx/layers/client/TextureClientPool.h b/gfx/layers/client/TextureClientPool.h index 131661c92735..16e016f2f122 100644 --- a/gfx/layers/client/TextureClientPool.h +++ b/gfx/layers/client/TextureClientPool.h @@ -151,6 +151,11 @@ private: RefPtr mTimer; // This mSurfaceAllocator owns us, so no need to hold a ref to it TextureForwarder* mSurfaceAllocator; + + // Keep track of whether this pool has been destroyed or not. If it has, + // we won't accept returns of TextureClients anymore, and the refcounting + // should take care of their destruction. + bool mDestroyed; }; } // namespace layers From 12c2a5366201738da59919a16ec2ec369dbb3187 Mon Sep 17 00:00:00 2001 From: Robert Longson Date: Fri, 22 Jul 2016 18:17:05 +0100 Subject: [PATCH 040/135] Bug 1283539 - Make SVGLength.convertToSpecifiedUnits work for percentage units on outer svg elements. r=dholbert --- dom/svg/nsSVGLength2.cpp | 4 ++++ dom/svg/test/mochitest.ini | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/dom/svg/nsSVGLength2.cpp b/dom/svg/nsSVGLength2.cpp index 41d67c6a426d..1deec1006b08 100644 --- a/dom/svg/nsSVGLength2.cpp +++ b/dom/svg/nsSVGLength2.cpp @@ -162,6 +162,10 @@ SVGElementMetrics::EnsureCtx() const { if (!mCtx && mSVGElement) { mCtx = mSVGElement->GetCtx(); + if (!mCtx && mSVGElement->IsSVGElement(nsGkAtoms::svg)) { + // mSVGElement must be the outer svg element + mCtx = static_cast(mSVGElement); + } } return mCtx != nullptr; } diff --git a/dom/svg/test/mochitest.ini b/dom/svg/test/mochitest.ini index f0315baa5a34..8b184b6aa559 100644 --- a/dom/svg/test/mochitest.ini +++ b/dom/svg/test/mochitest.ini @@ -47,7 +47,6 @@ support-files = [test_lang.xhtml] skip-if = true # disabled-for-intermittent-failures--bug-701060 [test_length.xhtml] -skip-if = true [test_lengthParsing.html] [test_markerOrient.xhtml] [test_nonAnimStrings.xhtml] From 739f9d9915ddf0fede8b6e8ef9e431757f5294ef Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Thu, 21 Jul 2016 18:01:28 -0400 Subject: [PATCH 041/135] Bug 1249511 - Add cargo nightly to tooltool. r=mshal Repacks of upstream builds cargo 0.13.0-nightly (664125b 2016-07-19) for each host platform. Unpacks into cargo/bin/cargo. This version supports `cargo build --frozen` to disallow network access during the build. MozReview-Commit-ID: IihpDlqxPx6 --- browser/config/tooltool-manifests/linux32/releng.manifest | 8 ++++++++ browser/config/tooltool-manifests/linux64/releng.manifest | 8 ++++++++ .../tooltool-manifests/macosx64/cross-releng.manifest | 8 ++++++++ .../config/tooltool-manifests/macosx64/releng.manifest | 8 ++++++++ browser/config/tooltool-manifests/win32/releng.manifest | 8 ++++++++ browser/config/tooltool-manifests/win64/releng.manifest | 8 ++++++++ 6 files changed, 48 insertions(+) diff --git a/browser/config/tooltool-manifests/linux32/releng.manifest b/browser/config/tooltool-manifests/linux32/releng.manifest index b18e65fd3f28..2b617d988e81 100644 --- a/browser/config/tooltool-manifests/linux32/releng.manifest +++ b/browser/config/tooltool-manifests/linux32/releng.manifest @@ -24,6 +24,14 @@ "unpack": true }, { +"version": "cargo 0.13.0-nightly (664125b 2016-07-19)", +"size": 3123796, +"digest": "4b9d2bcb8488b6649ba6c748e19d33bfceb25c7566e882fc7e00322392e424a5a9c5878c11c61d57cdaecf67bcc110842c6eff95e49736e8f3c83d9ce1677122", +"algorithm": "sha512", +"filename": "cargo.tar.xz", +"unpack": true +}, +{ "size": 167175, "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831", "algorithm": "sha512", diff --git a/browser/config/tooltool-manifests/linux64/releng.manifest b/browser/config/tooltool-manifests/linux64/releng.manifest index 4dd82f636358..c904160e53ed 100644 --- a/browser/config/tooltool-manifests/linux64/releng.manifest +++ b/browser/config/tooltool-manifests/linux64/releng.manifest @@ -24,6 +24,14 @@ "unpack": true }, { +"version": "cargo 0.13.0-nightly (664125b 2016-07-19)", +"size": 3123796, +"digest": "4b9d2bcb8488b6649ba6c748e19d33bfceb25c7566e882fc7e00322392e424a5a9c5878c11c61d57cdaecf67bcc110842c6eff95e49736e8f3c83d9ce1677122", +"algorithm": "sha512", +"filename": "cargo.tar.xz", +"unpack": true +}, +{ "size": 167175, "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831", "algorithm": "sha512", diff --git a/browser/config/tooltool-manifests/macosx64/cross-releng.manifest b/browser/config/tooltool-manifests/macosx64/cross-releng.manifest index 19893e20cbb8..e8c81576daa0 100644 --- a/browser/config/tooltool-manifests/macosx64/cross-releng.manifest +++ b/browser/config/tooltool-manifests/macosx64/cross-releng.manifest @@ -24,6 +24,14 @@ "filename": "MacOSX10.7.sdk.tar.bz2" }, { +"version": "cargo 0.13.0-nightly (664125b 2016-07-19)", +"size": 2571167, +"digest": "b2616459fbf15c75b54628a6bfe8cf89c0841ea08431f5096e72be4fac4c685785dfc7a2f18a03a5f7bd377e78d3c108e5029b12616842cbbd0497ff7363fdaf", +"algorithm": "sha512", +"filename": "cargo.tar.bz2", +"unpack": true +}, +{ "size": 167175, "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831", "algorithm": "sha512", diff --git a/browser/config/tooltool-manifests/macosx64/releng.manifest b/browser/config/tooltool-manifests/macosx64/releng.manifest index e54650edce11..980f30b4567d 100644 --- a/browser/config/tooltool-manifests/macosx64/releng.manifest +++ b/browser/config/tooltool-manifests/macosx64/releng.manifest @@ -15,6 +15,14 @@ "unpack": true }, { +"version": "cargo 0.13.0-nightly (664125b 2016-07-19)", +"size": 2571167, +"digest": "b2616459fbf15c75b54628a6bfe8cf89c0841ea08431f5096e72be4fac4c685785dfc7a2f18a03a5f7bd377e78d3c108e5029b12616842cbbd0497ff7363fdaf", +"algorithm": "sha512", +"filename": "cargo.tar.bz2", +"unpack": true +}, +{ "size": 167175, "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831", "algorithm": "sha512", diff --git a/browser/config/tooltool-manifests/win32/releng.manifest b/browser/config/tooltool-manifests/win32/releng.manifest index a5960ccf6be9..7260577f8e1d 100644 --- a/browser/config/tooltool-manifests/win32/releng.manifest +++ b/browser/config/tooltool-manifests/win32/releng.manifest @@ -14,6 +14,14 @@ "unpack": true }, { +"version": "cargo 0.13.0-nightly (664125b 2016-07-19)", +"size": 2298848, +"digest": "d3d1f7b6d195248550f98eb8ce87aa314d36a8a667c110ff2058777fe5a97b7007a41dc1c8a4605c4230e9105972768918222352d5e0fdebbc49639671de38ca", +"algorithm": "sha512", +"filename": "cargo.tar.bz2", +"unpack": true +}, +{ "size": 167175, "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831", "algorithm": "sha512", diff --git a/browser/config/tooltool-manifests/win64/releng.manifest b/browser/config/tooltool-manifests/win64/releng.manifest index a2571652553c..d6042d6f7e5f 100644 --- a/browser/config/tooltool-manifests/win64/releng.manifest +++ b/browser/config/tooltool-manifests/win64/releng.manifest @@ -15,6 +15,14 @@ "unpack": true }, { +"version": "cargo 0.13.0-nightly (664125b 2016-07-19)", +"size": 2561498, +"digest": "d300fd06b16efe49bdb1a238d516c8797d2de0edca7efadd55249401e1dd1d775fb84649630e273f95d9e8b956d87d1f75726c0a68294d25fafe078c3b2b9ba9", +"algorithm": "sha512", +"filename": "cargo.tar.bz2", +"unpack": true +}, +{ "size": 167175, "digest": "0b71a936edf5bd70cf274aaa5d7abc8f77fe8e7b5593a208f805cc9436fac646b9c4f0b43c2b10de63ff3da671497d35536077ecbc72dba7f8159a38b580f831", "algorithm": "sha512", From c87ae9e0a01a5353dcea29e3dc3ba261486216f4 Mon Sep 17 00:00:00 2001 From: Ralph Giles Date: Thu, 21 Jul 2016 18:15:44 -0400 Subject: [PATCH 042/135] Bug 1249511 - Make tooltool cargo available in the environment. r=mshal MozReview-Commit-ID: 37l7NzHMzoa --- build/mozconfig.rust | 1 + 1 file changed, 1 insertion(+) diff --git a/build/mozconfig.rust b/build/mozconfig.rust index c9cfbe23db03..65177a6bd8e2 100644 --- a/build/mozconfig.rust +++ b/build/mozconfig.rust @@ -4,6 +4,7 @@ # Assume this is compiled with --enable-rpath so we don't # have to set LD_LIBRARY_PATH. RUSTC="$topsrcdir/rustc/bin/rustc" +CARGO="$topsrcdir/cargo/bin/cargo" # Enable rust in the build. ac_add_options --enable-rust From f58ed6912f3bb7201fb09bdfc50b3c13757d546d Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 21 Jul 2016 19:26:42 -0500 Subject: [PATCH 043/135] Bug 1288564 - Baldr: change HeapPtr to ReadBarriered in WeakCache (r=terrence) MozReview-Commit-ID: 722L1GFAo6c --HG-- extra : rebase_source : 867c492d7114bad15414c6b671888f0ad263e478 --- js/src/jscompartment.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/src/jscompartment.h b/js/src/jscompartment.h index d6b2033fa043..92844c5f4dc9 100644 --- a/js/src/jscompartment.h +++ b/js/src/jscompartment.h @@ -517,8 +517,8 @@ struct JSCompartment mozilla::LinkedList unboxedLayouts; // All wasm live instances in the compartment. - using WasmInstanceObjectSet = js::GCHashSet, - js::MovableCellHasher>, + using WasmInstanceObjectSet = js::GCHashSet, + js::MovableCellHasher>, js::SystemAllocPolicy>; JS::WeakCache wasmInstances; From fc7d4e3d39da5ac6033ce72b89614f8f182bfdaa Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Wed, 20 Jul 2016 12:56:53 -0500 Subject: [PATCH 044/135] Bug 1288222 - Baldr: factor out common global access code (r=bbouvier) MozReview-Commit-ID: 5NOGyihk8s --HG-- extra : rebase_source : 622fa7961d494a252ef2a7c5c04959904965ce96 --- js/src/asmjs/WasmBaselineCompile.cpp | 31 ++----------------- js/src/jit/CodeGenerator.cpp | 23 ++++++++++++++ js/src/jit/CodeGenerator.h | 2 ++ js/src/jit/MacroAssembler.h | 3 ++ js/src/jit/arm/CodeGenerator-arm.cpp | 26 ---------------- js/src/jit/arm/CodeGenerator-arm.h | 2 -- js/src/jit/arm/MacroAssembler-arm.h | 7 +++-- js/src/jit/arm64/CodeGenerator-arm64.cpp | 12 ------- js/src/jit/arm64/CodeGenerator-arm64.h | 2 -- js/src/jit/arm64/MacroAssembler-arm64.h | 8 ++--- .../mips-shared/CodeGenerator-mips-shared.cpp | 26 ---------------- .../mips-shared/CodeGenerator-mips-shared.h | 2 -- js/src/jit/mips32/MacroAssembler-mips32.h | 6 ++-- js/src/jit/mips64/MacroAssembler-mips64.h | 6 ++-- js/src/jit/none/MacroAssembler-none.h | 1 + js/src/jit/x64/Assembler-x64.h | 7 ++--- js/src/jit/x64/CodeGenerator-x64.cpp | 28 ----------------- js/src/jit/x64/CodeGenerator-x64.h | 2 -- js/src/jit/x86/Assembler-x86.h | 4 +-- js/src/jit/x86/CodeGenerator-x86.cpp | 29 ----------------- js/src/jit/x86/CodeGenerator-x86.h | 2 -- 21 files changed, 51 insertions(+), 178 deletions(-) diff --git a/js/src/asmjs/WasmBaselineCompile.cpp b/js/src/asmjs/WasmBaselineCompile.cpp index 16fd52f886e7..6c87e698ad8e 100644 --- a/js/src/asmjs/WasmBaselineCompile.cpp +++ b/js/src/asmjs/WasmBaselineCompile.cpp @@ -2057,25 +2057,11 @@ class BaseCompiler masm.move32(Imm32(sigIndex), WasmTableCallSigReg); } -#if defined(JS_CODEGEN_X64) - // CodeGeneratorX64::visitAsmJSLoadFuncPtr() { ScratchI32 scratch(*this); - CodeOffset label = masm.loadRipRelativeInt64(scratch); - masm.append(GlobalAccess(label, globalDataOffset)); - masm.loadPtr(Operand(scratch, ptrReg, ScalePointer, 0), ptrReg); + masm.loadWasmGlobalPtr(globalDataOffset, scratch); + masm.loadPtr(BaseIndex(scratch, ptrReg, ScalePointer, 0), ptrReg); } -#elif defined(JS_CODEGEN_X86) - // CodeGeneratorX86::visitAsmJSLoadFuncPtr() - { - ScratchI32 scratch(*this); - CodeOffset label = masm.movlWithPatch(PatchedAbsoluteAddress(), scratch); - masm.append(GlobalAccess(label, globalDataOffset)); - masm.loadPtr(Operand(scratch, ptrReg, ScalePointer), ptrReg); - } -#else - MOZ_CRASH("BaseCompiler platform hook: funcPtrCall"); -#endif callDynamic(ptrReg, call); } @@ -2085,18 +2071,7 @@ class BaseCompiler void ffiCall(unsigned globalDataOffset, const FunctionCall& call) { Register ptrReg = WasmTableCallPtrReg; - -#if defined(JS_CODEGEN_X64) - // CodeGeneratorX64::visitAsmJSLoadFFIFunc() - CodeOffset label = masm.loadRipRelativeInt64(ptrReg); - masm.append(GlobalAccess(label, globalDataOffset)); -#elif defined(JS_CODEGEN_X86) - // CodeGeneratorX86::visitAsmJSLoadFFIFunc() - CodeOffset label = masm.movlWithPatch(PatchedAbsoluteAddress(), ptrReg); - masm.append(GlobalAccess(label, globalDataOffset)); -#else - MOZ_CRASH("BaseCompiler platform hook: ffiCall"); -#endif + masm.loadWasmGlobalPtr(globalDataOffset, ptrReg); callDynamic(ptrReg, call); } diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 39a9940ce9d9..7cb3afdac862 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -11228,6 +11228,29 @@ CodeGenerator::visitAsmJSVoidReturn(LAsmJSVoidReturn* lir) masm.jump(&returnLabel_); } +void +CodeGenerator::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins) +{ + const MAsmJSLoadFuncPtr* mir = ins->mir(); + + Register index = ToRegister(ins->index()); + Register out = ToRegister(ins->output()); + + if (mir->hasLimit()) { + masm.branch32(Assembler::Condition::AboveOrEqual, index, Imm32(mir->limit()), + wasm::JumpTarget::OutOfBounds); + } + + masm.loadWasmGlobalPtr(mir->globalDataOffset(), out); + masm.loadPtr(BaseIndex(out, index, ScalePointer), out); +} + +void +CodeGenerator::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins) +{ + masm.loadWasmGlobalPtr(ins->mir()->globalDataOffset(), ToRegister(ins->output())); +} + void CodeGenerator::emitAssertRangeI(const Range* r, Register input) { diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index 61fce95cf2da..f76832986449 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -363,6 +363,8 @@ class CodeGenerator final : public CodeGeneratorSpecific void visitAsmJSParameter(LAsmJSParameter* lir); void visitAsmJSReturn(LAsmJSReturn* ret); void visitAsmJSVoidReturn(LAsmJSVoidReturn* ret); + void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins); + void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins); void visitLexicalCheck(LLexicalCheck* ins); void visitThrowRuntimeLexicalError(LThrowRuntimeLexicalError* ins); void visitGlobalNameConflictsCheck(LGlobalNameConflictsCheck* ins); diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index f87231045c72..e7d7b6d89cde 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -1266,6 +1266,9 @@ class MacroAssembler : public MacroAssemblerSpecific void loadJitActivation(Register dest) { loadPtr(AbsoluteAddress(GetJitContext()->runtime->addressOfActivation()), dest); } + void loadWasmActivation(Register dest) { + loadWasmGlobalPtr(wasm::ActivationGlobalDataOffset, dest); + } template void loadTypedOrValue(const T& src, TypedOrValueRegister dest) { diff --git a/js/src/jit/arm/CodeGenerator-arm.cpp b/js/src/jit/arm/CodeGenerator-arm.cpp index ebbf0912ba99..db94ef879d57 100644 --- a/js/src/jit/arm/CodeGenerator-arm.cpp +++ b/js/src/jit/arm/CodeGenerator-arm.cpp @@ -2752,32 +2752,6 @@ CodeGeneratorARM::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins) } } -void -CodeGeneratorARM::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins) -{ - const MAsmJSLoadFuncPtr* mir = ins->mir(); - - Register index = ToRegister(ins->index()); - Register out = ToRegister(ins->output()); - - if (mir->hasLimit()) { - masm.branch32(Assembler::Condition::AboveOrEqual, index, Imm32(mir->limit()), - wasm::JumpTarget::OutOfBounds); - } - - masm.ma_ldr(Address(GlobalReg, mir->globalDataOffset() - AsmJSGlobalRegBias), out); - masm.ma_ldr(DTRAddr(out, DtrRegImmShift(index, LSL, 2)), out); -} - -void -CodeGeneratorARM::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins) -{ - const MAsmJSLoadFFIFunc* mir = ins->mir(); - - masm.ma_ldr(Address(GlobalReg, mir->globalDataOffset() - AsmJSGlobalRegBias), - ToRegister(ins->output())); -} - void CodeGeneratorARM::visitNegI(LNegI* ins) { diff --git a/js/src/jit/arm/CodeGenerator-arm.h b/js/src/jit/arm/CodeGenerator-arm.h index 7369bc55605d..3dcd1a3618a0 100644 --- a/js/src/jit/arm/CodeGenerator-arm.h +++ b/js/src/jit/arm/CodeGenerator-arm.h @@ -217,8 +217,6 @@ class CodeGeneratorARM : public CodeGeneratorShared void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins); void visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins); void visitAsmJSAtomicBinopCallout(LAsmJSAtomicBinopCallout* ins); - void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins); - void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins); void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins); void visitWasmTruncateToInt32(LWasmTruncateToInt32* ins); void visitOutOfLineWasmTruncateCheck(OutOfLineWasmTruncateCheck* ool); diff --git a/js/src/jit/arm/MacroAssembler-arm.h b/js/src/jit/arm/MacroAssembler-arm.h index b11b0c96a92b..650e83c030e4 100644 --- a/js/src/jit/arm/MacroAssembler-arm.h +++ b/js/src/jit/arm/MacroAssembler-arm.h @@ -1438,12 +1438,13 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM as_vmov(VFPRegister(dest).singleOverlay(), VFPRegister(src).singleOverlay(), cc); } - void loadWasmActivation(Register dest) { - loadPtr(Address(GlobalReg, wasm::ActivationGlobalDataOffset - AsmJSGlobalRegBias), dest); + void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) { + loadPtr(Address(GlobalReg, globalDataOffset - AsmJSGlobalRegBias), dest); } void loadAsmJSHeapRegisterFromGlobalData() { - loadPtr(Address(GlobalReg, wasm::HeapGlobalDataOffset - AsmJSGlobalRegBias), HeapReg); + loadWasmGlobalPtr(wasm::HeapGlobalDataOffset, HeapReg); } + // Instrumentation for entering and leaving the profiler. void profilerEnterFrame(Register framePtr, Register scratch); void profilerExitFrame(); diff --git a/js/src/jit/arm64/CodeGenerator-arm64.cpp b/js/src/jit/arm64/CodeGenerator-arm64.cpp index db8358fce8ae..d14e14bb6a37 100644 --- a/js/src/jit/arm64/CodeGenerator-arm64.cpp +++ b/js/src/jit/arm64/CodeGenerator-arm64.cpp @@ -703,18 +703,6 @@ CodeGeneratorARM64::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins) MOZ_CRASH("visitWasmStoreGlobalVar"); } -void -CodeGeneratorARM64::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins) -{ - MOZ_CRASH("visitAsmJSLoadFuncPtr"); -} - -void -CodeGeneratorARM64::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins) -{ - MOZ_CRASH("visitAsmJSLoadFFIFunc"); -} - void CodeGeneratorARM64::visitNegI(LNegI* ins) { diff --git a/js/src/jit/arm64/CodeGenerator-arm64.h b/js/src/jit/arm64/CodeGenerator-arm64.h index 2e0101ee1c9d..d1e9295c04ca 100644 --- a/js/src/jit/arm64/CodeGenerator-arm64.h +++ b/js/src/jit/arm64/CodeGenerator-arm64.h @@ -203,8 +203,6 @@ class CodeGeneratorARM64 : public CodeGeneratorShared void visitAsmJSStoreHeap(LAsmJSStoreHeap* ins); void visitAsmJSCompareExchangeHeap(LAsmJSCompareExchangeHeap* ins); void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins); - void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins); - void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins); void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins); void visitWasmLoadGlobalVar(LWasmLoadGlobalVar* ins); diff --git a/js/src/jit/arm64/MacroAssembler-arm64.h b/js/src/jit/arm64/MacroAssembler-arm64.h index 6a87aa0128f8..014a2fcfedbd 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64.h +++ b/js/src/jit/arm64/MacroAssembler-arm64.h @@ -2305,12 +2305,12 @@ class MacroAssemblerCompat : public vixl::MacroAssembler #endif } - void loadWasmActivation(Register dest) { - loadPtr(Address(GlobalReg, wasm::ActivationGlobalDataOffset - AsmJSGlobalRegBias), dest); + void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) { + loadPtr(Address(GlobalReg, globalDataOffset - AsmJSGlobalRegBias), dest); } void loadAsmJSHeapRegisterFromGlobalData() { - loadPtr(Address(GlobalReg, wasm::HeapGlobalDataOffset - AsmJSGlobalRegBias), HeapReg); - loadPtr(Address(GlobalReg, wasm::HeapGlobalDataOffset - AsmJSGlobalRegBias + 8), HeapLenReg); + loadWasmGlobalPtr(wasm::HeapGlobalDataOffset, HeapReg); + loadWasmGlobalPtr(wasm::HeapGlobalDataOffset + 8, HeapLenReg); } // Overwrites the payload bits of a dest register containing a Value. diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp index 8a8fa746057e..0315cad9bd98 100644 --- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.cpp @@ -2262,32 +2262,6 @@ CodeGeneratorMIPSShared::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins) masm.storeDouble(ToFloatRegister(ins->value()), Address(GlobalReg, addr)); } -void -CodeGeneratorMIPSShared::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins) -{ - const MAsmJSLoadFuncPtr* mir = ins->mir(); - - Register index = ToRegister(ins->index()); - Register out = ToRegister(ins->output()); - unsigned addr = mir->globalDataOffset() - AsmJSGlobalRegBias; - - if (mir->hasLimit()) { - masm.branch32(Assembler::Condition::AboveOrEqual, index, Imm32(mir->limit()), - wasm::JumpTarget::OutOfBounds); - } - - BaseIndex source(GlobalReg, index, ScalePointer, addr); - masm.loadPtr(source, out); -} - -void -CodeGeneratorMIPSShared::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins) -{ - const MAsmJSLoadFFIFunc* mir = ins->mir(); - masm.loadPtr(Address(GlobalReg, mir->globalDataOffset() - AsmJSGlobalRegBias), - ToRegister(ins->output())); -} - void CodeGeneratorMIPSShared::visitNegI(LNegI* ins) { diff --git a/js/src/jit/mips-shared/CodeGenerator-mips-shared.h b/js/src/jit/mips-shared/CodeGenerator-mips-shared.h index 67c880b54154..3d9eb25951ae 100644 --- a/js/src/jit/mips-shared/CodeGenerator-mips-shared.h +++ b/js/src/jit/mips-shared/CodeGenerator-mips-shared.h @@ -204,8 +204,6 @@ class CodeGeneratorMIPSShared : public CodeGeneratorShared void visitAsmJSAtomicExchangeHeap(LAsmJSAtomicExchangeHeap* ins); void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins); void visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins); - void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins); - void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins); void visitAsmJSPassStackArg(LAsmJSPassStackArg* ins); void visitAsmSelect(LAsmSelect* ins); diff --git a/js/src/jit/mips32/MacroAssembler-mips32.h b/js/src/jit/mips32/MacroAssembler-mips32.h index c77cba685e56..3b19b85a9e40 100644 --- a/js/src/jit/mips32/MacroAssembler-mips32.h +++ b/js/src/jit/mips32/MacroAssembler-mips32.h @@ -998,12 +998,12 @@ class MacroAssemblerMIPSCompat : public MacroAssemblerMIPS as_movs(dest, src); } - void loadWasmActivation(Register dest) { - loadPtr(Address(GlobalReg, wasm::ActivationGlobalDataOffset - AsmJSGlobalRegBias), dest); + void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) { + loadPtr(Address(GlobalReg, globalDataOffset - AsmJSGlobalRegBias), dest); } void loadAsmJSHeapRegisterFromGlobalData() { MOZ_ASSERT(Imm16::IsInSignedRange(wasm::HeapGlobalDataOffset - AsmJSGlobalRegBias)); - loadPtr(Address(GlobalReg, wasm::HeapGlobalDataOffset - AsmJSGlobalRegBias), HeapReg); + loadWasmGlobalPtr(wasm::HeapGlobalDataOffset, HeapReg); } // Instrumentation for entering and leaving the profiler. diff --git a/js/src/jit/mips64/MacroAssembler-mips64.h b/js/src/jit/mips64/MacroAssembler-mips64.h index 883cae7f0e11..1ee57e11291b 100644 --- a/js/src/jit/mips64/MacroAssembler-mips64.h +++ b/js/src/jit/mips64/MacroAssembler-mips64.h @@ -1000,12 +1000,12 @@ class MacroAssemblerMIPS64Compat : public MacroAssemblerMIPS64 as_movs(dest, src); } - void loadWasmActivation(Register dest) { - loadPtr(Address(GlobalReg, wasm::ActivationGlobalDataOffset - AsmJSGlobalRegBias), dest); + void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) { + loadPtr(Address(GlobalReg, globalDataOffset - AsmJSGlobalRegBias), dest); } void loadAsmJSHeapRegisterFromGlobalData() { MOZ_ASSERT(Imm16::IsInSignedRange(wasm::HeapGlobalDataOffset - AsmJSGlobalRegBias)); - loadPtr(Address(GlobalReg, wasm::HeapGlobalDataOffset - AsmJSGlobalRegBias), HeapReg); + loadWasmGlobalPtr(wasm::HeapGlobalDataOffset, dest); } // Instrumentation for entering and leaving the profiler. diff --git a/js/src/jit/none/MacroAssembler-none.h b/js/src/jit/none/MacroAssembler-none.h index c03ed333a76a..b5ebacab5956 100644 --- a/js/src/jit/none/MacroAssembler-none.h +++ b/js/src/jit/none/MacroAssembler-none.h @@ -405,6 +405,7 @@ class MacroAssemblerNone : public Assembler void buildFakeExitFrame(Register, uint32_t*) { MOZ_CRASH(); } bool buildOOLFakeExitFrame(void*) { MOZ_CRASH(); } + void loadWasmGlobalPtr(uint32_t, Register) { MOZ_CRASH(); } void loadWasmActivation(Register) { MOZ_CRASH(); } void loadAsmJSHeapRegisterFromGlobalData() { MOZ_CRASH(); } diff --git a/js/src/jit/x64/Assembler-x64.h b/js/src/jit/x64/Assembler-x64.h index cf4e760ac83c..8b21e86b502c 100644 --- a/js/src/jit/x64/Assembler-x64.h +++ b/js/src/jit/x64/Assembler-x64.h @@ -825,13 +825,12 @@ class Assembler : public AssemblerX86Shared return CodeOffset(masm.leaq_rip(dest.encoding()).offset()); } - void loadWasmActivation(Register dest) { + void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) { CodeOffset label = loadRipRelativeInt64(dest); - append(wasm::GlobalAccess(label, wasm::ActivationGlobalDataOffset)); + append(wasm::GlobalAccess(label, globalDataOffset)); } void loadAsmJSHeapRegisterFromGlobalData() { - CodeOffset label = loadRipRelativeInt64(HeapReg); - append(wasm::GlobalAccess(label, wasm::HeapGlobalDataOffset)); + loadWasmGlobalPtr(wasm::HeapGlobalDataOffset, HeapReg); } void cmpq(Register rhs, Register lhs) { diff --git a/js/src/jit/x64/CodeGenerator-x64.cpp b/js/src/jit/x64/CodeGenerator-x64.cpp index 077bb17a0f6d..4db8ca69973d 100644 --- a/js/src/jit/x64/CodeGenerator-x64.cpp +++ b/js/src/jit/x64/CodeGenerator-x64.cpp @@ -1246,34 +1246,6 @@ CodeGeneratorX64::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins) masm.append(wasm::GlobalAccess(label, mir->globalDataOffset())); } -void -CodeGeneratorX64::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins) -{ - const MAsmJSLoadFuncPtr* mir = ins->mir(); - - Register index = ToRegister(ins->index()); - Register out = ToRegister(ins->output()); - - if (mir->hasLimit()) { - masm.branch32(Assembler::Condition::AboveOrEqual, index, Imm32(mir->limit()), - wasm::JumpTarget::OutOfBounds); - } - - CodeOffset label = masm.loadRipRelativeInt64(out); - masm.append(wasm::GlobalAccess(label, mir->globalDataOffset())); - - masm.loadPtr(Operand(out, index, ScalePointer, 0), out); -} - -void -CodeGeneratorX64::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins) -{ - MAsmJSLoadFFIFunc* mir = ins->mir(); - - CodeOffset label = masm.loadRipRelativeInt64(ToRegister(ins->output())); - masm.append(wasm::GlobalAccess(label, mir->globalDataOffset())); -} - void CodeGeneratorX64::visitTruncateDToInt32(LTruncateDToInt32* ins) { diff --git a/js/src/jit/x64/CodeGenerator-x64.h b/js/src/jit/x64/CodeGenerator-x64.h index fd7f18cae319..f4f8b7adc038 100644 --- a/js/src/jit/x64/CodeGenerator-x64.h +++ b/js/src/jit/x64/CodeGenerator-x64.h @@ -85,8 +85,6 @@ class CodeGeneratorX64 : public CodeGeneratorX86Shared void visitAsmJSAtomicExchangeHeap(LAsmJSAtomicExchangeHeap* ins); void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins); void visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins); - void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins); - void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins); void visitAsmJSUInt32ToDouble(LAsmJSUInt32ToDouble* lir); void visitAsmJSUInt32ToFloat32(LAsmJSUInt32ToFloat32* lir); void visitAsmReinterpretFromI64(LAsmReinterpretFromI64* lir); diff --git a/js/src/jit/x86/Assembler-x86.h b/js/src/jit/x86/Assembler-x86.h index 536e97b442b5..f8cf59a442a0 100644 --- a/js/src/jit/x86/Assembler-x86.h +++ b/js/src/jit/x86/Assembler-x86.h @@ -920,9 +920,9 @@ class Assembler : public AssemblerX86Shared return CodeOffset(masm.currentOffset()); } - void loadWasmActivation(Register dest) { + void loadWasmGlobalPtr(uint32_t globalDataOffset, Register dest) { CodeOffset label = movlWithPatch(PatchedAbsoluteAddress(), dest); - append(wasm::GlobalAccess(label, wasm::ActivationGlobalDataOffset)); + append(wasm::GlobalAccess(label, globalDataOffset)); } void loadAsmJSHeapRegisterFromGlobalData() { // x86 doesn't have a pinned heap register. diff --git a/js/src/jit/x86/CodeGenerator-x86.cpp b/js/src/jit/x86/CodeGenerator-x86.cpp index a035289bd559..06869c37712e 100644 --- a/js/src/jit/x86/CodeGenerator-x86.cpp +++ b/js/src/jit/x86/CodeGenerator-x86.cpp @@ -901,35 +901,6 @@ CodeGeneratorX86::visitWasmStoreGlobalVar(LWasmStoreGlobalVar* ins) masm.append(wasm::GlobalAccess(label, mir->globalDataOffset())); } -void -CodeGeneratorX86::visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins) -{ - const MAsmJSLoadFuncPtr* mir = ins->mir(); - - Register index = ToRegister(ins->index()); - Register out = ToRegister(ins->output()); - - if (mir->hasLimit()) { - masm.branch32(Assembler::Condition::AboveOrEqual, index, Imm32(mir->limit()), - wasm::JumpTarget::OutOfBounds); - } - - CodeOffset label = masm.movlWithPatch(PatchedAbsoluteAddress(), out); - masm.append(wasm::GlobalAccess(label, mir->globalDataOffset())); - - masm.loadPtr(Operand(out, index, ScalePointer), out); -} - -void -CodeGeneratorX86::visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins) -{ - MAsmJSLoadFFIFunc* mir = ins->mir(); - - Register out = ToRegister(ins->output()); - CodeOffset label = masm.movlWithPatch(PatchedAbsoluteAddress(), out); - masm.append(wasm::GlobalAccess(label, mir->globalDataOffset())); -} - namespace js { namespace jit { diff --git a/js/src/jit/x86/CodeGenerator-x86.h b/js/src/jit/x86/CodeGenerator-x86.h index 6b9482bb9f38..6e271c11003d 100644 --- a/js/src/jit/x86/CodeGenerator-x86.h +++ b/js/src/jit/x86/CodeGenerator-x86.h @@ -68,8 +68,6 @@ class CodeGeneratorX86 : public CodeGeneratorX86Shared void visitAsmJSAtomicExchangeHeap(LAsmJSAtomicExchangeHeap* ins); void visitAsmJSAtomicBinopHeap(LAsmJSAtomicBinopHeap* ins); void visitAsmJSAtomicBinopHeapForEffect(LAsmJSAtomicBinopHeapForEffect* ins); - void visitAsmJSLoadFuncPtr(LAsmJSLoadFuncPtr* ins); - void visitAsmJSLoadFFIFunc(LAsmJSLoadFFIFunc* ins); void visitWasmTruncateToInt32(LWasmTruncateToInt32* ins); void visitOutOfLineTruncate(OutOfLineTruncate* ool); From 04fe291d25560854d240a70e22a600acf0a3e606 Mon Sep 17 00:00:00 2001 From: Luke Wagner Date: Thu, 21 Jul 2016 21:19:49 -0500 Subject: [PATCH 045/135] Bug 1288222 - Baldr: match signature types structurally (r=bbouvier) MozReview-Commit-ID: 7Noq2TBkKmB --HG-- extra : rebase_source : 89201ad63cdd369437b7c2c251d6c9e65e9c2ece --- js/src/asmjs/AsmJS.cpp | 6 +- js/src/asmjs/WasmBaselineCompile.cpp | 20 ++- js/src/asmjs/WasmCode.cpp | 56 ++----- js/src/asmjs/WasmCode.h | 1 + js/src/asmjs/WasmCompile.cpp | 10 +- js/src/asmjs/WasmFrameIterator.cpp | 19 ++- js/src/asmjs/WasmFrameIterator.h | 3 +- js/src/asmjs/WasmGenerator.cpp | 30 +++- js/src/asmjs/WasmGenerator.h | 16 +- js/src/asmjs/WasmInstance.cpp | 90 ++++++++++ js/src/asmjs/WasmInstance.h | 2 + js/src/asmjs/WasmIonCompile.cpp | 7 +- js/src/asmjs/WasmIonCompile.h | 14 +- js/src/asmjs/WasmModule.cpp | 9 +- js/src/asmjs/WasmModule.h | 4 +- js/src/asmjs/WasmTypes.cpp | 148 +++++++++++++++++ js/src/asmjs/WasmTypes.h | 73 +++++++-- .../jit-test/tests/wasm/spec/func_ptrs.wast | 14 +- js/src/jit-test/tests/wasm/table-gc.js | 154 +++++++++++++++++ js/src/jit-test/tests/wasm/tables.js | 155 ++---------------- js/src/jit/CodeGenerator.cpp | 4 +- js/src/jit/CodeGenerator.h | 2 +- js/src/jit/MIR.h | 20 +-- js/src/jit/MacroAssembler.h | 3 +- js/src/jit/arm/MacroAssembler-arm-inl.h | 3 +- js/src/jit/arm64/MacroAssembler-arm64-inl.h | 3 +- .../MacroAssembler-mips-shared-inl.h | 3 +- js/src/jit/shared/CodeGenerator-shared.cpp | 19 ++- .../MacroAssembler-x86-shared-inl.h | 3 +- js/src/vm/Runtime.h | 4 - 30 files changed, 615 insertions(+), 280 deletions(-) create mode 100644 js/src/jit-test/tests/wasm/table-gc.js diff --git a/js/src/asmjs/AsmJS.cpp b/js/src/asmjs/AsmJS.cpp index 9445777f609d..34e62bad8633 100644 --- a/js/src/asmjs/AsmJS.cpp +++ b/js/src/asmjs/AsmJS.cpp @@ -1543,10 +1543,10 @@ class MOZ_STACK_CLASS ModuleValidator class NamedSig { PropertyName* name_; - const DeclaredSig* sig_; + const SigWithId* sig_; public: - NamedSig(PropertyName* name, const DeclaredSig& sig) + NamedSig(PropertyName* name, const SigWithId& sig) : name_(name), sig_(&sig) {} PropertyName* name() const { @@ -1570,7 +1570,7 @@ class MOZ_STACK_CLASS ModuleValidator } }; typedef HashMap ImportMap; - typedef HashMap SigMap; + typedef HashMap SigMap; typedef HashMap GlobalMap; typedef HashMap MathNameMap; typedef HashMap AtomicsNameMap; diff --git a/js/src/asmjs/WasmBaselineCompile.cpp b/js/src/asmjs/WasmBaselineCompile.cpp index 6c87e698ad8e..23b774e70b17 100644 --- a/js/src/asmjs/WasmBaselineCompile.cpp +++ b/js/src/asmjs/WasmBaselineCompile.cpp @@ -1737,7 +1737,7 @@ class BaseCompiler void beginFunction() { JitSpew(JitSpew_Codegen, "# Emitting wasm baseline code"); - wasm::GenerateFunctionPrologue(masm, localSize_, mg_.funcSigIndex(func_.index()), + wasm::GenerateFunctionPrologue(masm, localSize_, mg_.funcSigs[func_.index()]->id, &compileResults_.offsets()); MOZ_ASSERT(masm.framePushed() == uint32_t(localSize_)); @@ -2041,7 +2041,7 @@ class BaseCompiler // Precondition: sync() - void funcPtrCall(const Sig& sig, uint32_t sigIndex, uint32_t length, uint32_t globalDataOffset, + void funcPtrCall(const SigWithId& sig, uint32_t length, uint32_t globalDataOffset, Stk& indexVal, const FunctionCall& call) { Register ptrReg = WasmTableCallPtrReg; @@ -2054,7 +2054,17 @@ class BaseCompiler } else { masm.branch32(Assembler::Condition::AboveOrEqual, ptrReg, Imm32(length), wasm::JumpTarget::OutOfBounds); - masm.move32(Imm32(sigIndex), WasmTableCallSigReg); + } + + switch (sig.id.kind()) { + case SigIdDesc::Kind::Global: + masm.loadWasmGlobalPtr(sig.id.globalDataOffset(), WasmTableCallSigReg); + break; + case SigIdDesc::Kind::Immediate: + masm.move32(Imm32(sig.id.immediate()), WasmTableCallSigReg); + break; + case SigIdDesc::Kind::None: + break; } { @@ -5143,7 +5153,7 @@ BaseCompiler::emitCallIndirect(uint32_t callOffset) Nothing callee_; - const Sig& sig = mg_.sigs[sigIndex]; + const SigWithId& sig = mg_.sigs[sigIndex]; if (deadCode_) { return skipCall(sig.args()) && iter_.readCallIndirectCallee(&callee_) && @@ -5175,7 +5185,7 @@ BaseCompiler::emitCallIndirect(uint32_t callOffset) ? mg_.tables[mg_.asmJSSigToTableIndex[sigIndex]] : mg_.tables[0]; - funcPtrCall(sig, sigIndex, table.initial, table.globalDataOffset, callee, baselineCall); + funcPtrCall(sig, table.initial, table.globalDataOffset, callee, baselineCall); endCall(baselineCall); diff --git a/js/src/asmjs/WasmCode.cpp b/js/src/asmjs/WasmCode.cpp index 93b309ec490b..2ce9d3ef85a8 100644 --- a/js/src/asmjs/WasmCode.cpp +++ b/js/src/asmjs/WasmCode.cpp @@ -249,53 +249,17 @@ CodeSegment::~CodeSegment() DeallocateExecutableMemory(bytes_, totalLength(), gc::SystemPageSize()); } -static size_t -SerializedSigSize(const Sig& sig) -{ - return sizeof(ExprType) + - SerializedPodVectorSize(sig.args()); -} - -static uint8_t* -SerializeSig(uint8_t* cursor, const Sig& sig) -{ - cursor = WriteScalar(cursor, sig.ret()); - cursor = SerializePodVector(cursor, sig.args()); - return cursor; -} - -static const uint8_t* -DeserializeSig(const uint8_t* cursor, Sig* sig) -{ - ExprType ret; - cursor = ReadScalar(cursor, &ret); - - ValTypeVector args; - cursor = DeserializePodVector(cursor, &args); - if (!cursor) - return nullptr; - - *sig = Sig(Move(args), ret); - return cursor; -} - -static size_t -SizeOfSigExcludingThis(const Sig& sig, MallocSizeOf mallocSizeOf) -{ - return sig.args().sizeOfExcludingThis(mallocSizeOf); -} - size_t FuncExport::serializedSize() const { - return SerializedSigSize(sig_) + + return sig_.serializedSize() + sizeof(pod); } uint8_t* FuncExport::serialize(uint8_t* cursor) const { - cursor = SerializeSig(cursor, sig_); + cursor = sig_.serialize(cursor); cursor = WriteBytes(cursor, &pod, sizeof(pod)); return cursor; } @@ -303,7 +267,7 @@ FuncExport::serialize(uint8_t* cursor) const const uint8_t* FuncExport::deserialize(const uint8_t* cursor) { - (cursor = DeserializeSig(cursor, &sig_)) && + (cursor = sig_.deserialize(cursor)) && (cursor = ReadBytes(cursor, &pod, sizeof(pod))); return cursor; } @@ -311,20 +275,20 @@ FuncExport::deserialize(const uint8_t* cursor) size_t FuncExport::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { - return SizeOfSigExcludingThis(sig_, mallocSizeOf); + return sig_.sizeOfExcludingThis(mallocSizeOf); } size_t FuncImport::serializedSize() const { - return SerializedSigSize(sig_) + + return sig_.serializedSize() + sizeof(pod); } uint8_t* FuncImport::serialize(uint8_t* cursor) const { - cursor = SerializeSig(cursor, sig_); + cursor = sig_.serialize(cursor); cursor = WriteBytes(cursor, &pod, sizeof(pod)); return cursor; } @@ -332,7 +296,7 @@ FuncImport::serialize(uint8_t* cursor) const const uint8_t* FuncImport::deserialize(const uint8_t* cursor) { - (cursor = DeserializeSig(cursor, &sig_)) && + (cursor = sig_.deserialize(cursor)) && (cursor = ReadBytes(cursor, &pod, sizeof(pod))); return cursor; } @@ -340,7 +304,7 @@ FuncImport::deserialize(const uint8_t* cursor) size_t FuncImport::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { - return SizeOfSigExcludingThis(sig_, mallocSizeOf); + return sig_.sizeOfExcludingThis(mallocSizeOf); } CodeRange::CodeRange(Kind kind, Offsets offsets) @@ -452,6 +416,7 @@ Metadata::serializedSize() const return sizeof(pod()) + SerializedVectorSize(funcImports) + SerializedVectorSize(funcExports) + + SerializedVectorSize(sigIds) + SerializedPodVectorSize(tables) + SerializedPodVectorSize(memoryAccesses) + SerializedPodVectorSize(boundsChecks) + @@ -469,6 +434,7 @@ Metadata::serialize(uint8_t* cursor) const cursor = WriteBytes(cursor, &pod(), sizeof(pod())); cursor = SerializeVector(cursor, funcImports); cursor = SerializeVector(cursor, funcExports); + cursor = SerializeVector(cursor, sigIds); cursor = SerializePodVector(cursor, tables); cursor = SerializePodVector(cursor, memoryAccesses); cursor = SerializePodVector(cursor, boundsChecks); @@ -487,6 +453,7 @@ Metadata::deserialize(const uint8_t* cursor) (cursor = ReadBytes(cursor, &pod(), sizeof(pod()))) && (cursor = DeserializeVector(cursor, &funcImports)) && (cursor = DeserializeVector(cursor, &funcExports)) && + (cursor = DeserializeVector(cursor, &sigIds)) && (cursor = DeserializePodVector(cursor, &tables)) && (cursor = DeserializePodVector(cursor, &memoryAccesses)) && (cursor = DeserializePodVector(cursor, &boundsChecks)) && @@ -504,6 +471,7 @@ Metadata::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const { return SizeOfVectorExcludingThis(funcImports, mallocSizeOf) + SizeOfVectorExcludingThis(funcExports, mallocSizeOf) + + SizeOfVectorExcludingThis(sigIds, mallocSizeOf) + tables.sizeOfExcludingThis(mallocSizeOf) + memoryAccesses.sizeOfExcludingThis(mallocSizeOf) + boundsChecks.sizeOfExcludingThis(mallocSizeOf) + diff --git a/js/src/asmjs/WasmCode.h b/js/src/asmjs/WasmCode.h index 046b6bc20f7c..3ea17ff0cf5c 100644 --- a/js/src/asmjs/WasmCode.h +++ b/js/src/asmjs/WasmCode.h @@ -466,6 +466,7 @@ struct Metadata : ShareableBase, MetadataCacheablePod FuncImportVector funcImports; FuncExportVector funcExports; + SigWithIdVector sigIds; TableDescVector tables; MemoryAccessVector memoryAccesses; BoundsCheckVector boundsChecks; diff --git a/js/src/asmjs/WasmCompile.cpp b/js/src/asmjs/WasmCompile.cpp index 3395d6de7ccd..bf37e80b6498 100644 --- a/js/src/asmjs/WasmCompile.cpp +++ b/js/src/asmjs/WasmCompile.cpp @@ -550,7 +550,7 @@ DecodeTypeSection(Decoder& d, ModuleGeneratorData* init) } static bool -DecodeSignatureIndex(Decoder& d, const ModuleGeneratorData& init, const DeclaredSig** sig) +DecodeSignatureIndex(Decoder& d, const ModuleGeneratorData& init, const SigWithId** sig) { uint32_t sigIndex; if (!d.readVarU32(&sigIndex)) @@ -723,7 +723,7 @@ static bool DecodeImport(Decoder& d, bool newFormat, ModuleGeneratorData* init, ImportVector* imports) { if (!newFormat) { - const DeclaredSig* sig = nullptr; + const SigWithId* sig = nullptr; if (!DecodeSignatureIndex(d, *init, &sig)) return false; @@ -764,7 +764,7 @@ DecodeImport(Decoder& d, bool newFormat, ModuleGeneratorData* init, ImportVector switch (DefinitionKind(importKind)) { case DefinitionKind::Function: { - const DeclaredSig* sig = nullptr; + const SigWithId* sig = nullptr; if (!DecodeSignatureIndex(d, *init, &sig)) return false; if (!CheckTypeForJS(d, *sig)) @@ -1067,7 +1067,7 @@ DecodeFunctionBody(Decoder& d, ModuleGenerator& mg, uint32_t funcIndex) return false; ValTypeVector locals; - const DeclaredSig& sig = mg.funcSig(funcIndex); + const Sig& sig = mg.funcSig(funcIndex); if (!locals.appendAll(sig.args())) return false; @@ -1120,7 +1120,7 @@ DecodeStartSection(Decoder& d, ModuleGenerator& mg) if (startFuncIndex >= mg.numFuncSigs()) return Fail(d, "unknown start function"); - const DeclaredSig& sig = mg.funcSig(startFuncIndex); + const Sig& sig = mg.funcSig(startFuncIndex); if (sig.ret() != ExprType::Void) return Fail(d, "start function must not return anything"); diff --git a/js/src/asmjs/WasmFrameIterator.cpp b/js/src/asmjs/WasmFrameIterator.cpp index ea92b8e42122..f4a3f58fa7c1 100644 --- a/js/src/asmjs/WasmFrameIterator.cpp +++ b/js/src/asmjs/WasmFrameIterator.cpp @@ -331,7 +331,7 @@ GenerateProfilingEpilogue(MacroAssembler& masm, unsigned framePushed, ExitReason // Specifically, ToggleProfiling patches all callsites to either call the // profiling or non-profiling entry point. void -wasm::GenerateFunctionPrologue(MacroAssembler& masm, unsigned framePushed, uint32_t sigIndex, +wasm::GenerateFunctionPrologue(MacroAssembler& masm, unsigned framePushed, const SigIdDesc& sigId, FuncOffsets* offsets) { #if defined(JS_CODEGEN_ARM) @@ -349,8 +349,21 @@ wasm::GenerateFunctionPrologue(MacroAssembler& masm, unsigned framePushed, uint3 // Generate table entry thunk: masm.haltingAlign(CodeAlignment); offsets->tableEntry = masm.currentOffset(); - masm.branch32(Assembler::Condition::NotEqual, WasmTableCallSigReg, Imm32(sigIndex), - JumpTarget::BadIndirectCall); + switch (sigId.kind()) { + case SigIdDesc::Kind::Global: { + Register scratch = WasmTableCallPtrReg; // clobbered by the indirect call + masm.loadWasmGlobalPtr(sigId.globalDataOffset(), scratch); + masm.branch32(Assembler::Condition::NotEqual, WasmTableCallSigReg, scratch, + JumpTarget::BadIndirectCall); + break; + } + case SigIdDesc::Kind::Immediate: + masm.branch32(Assembler::Condition::NotEqual, WasmTableCallSigReg, Imm32(sigId.immediate()), + JumpTarget::BadIndirectCall); + break; + case SigIdDesc::Kind::None: + break; + } offsets->tableProfilingJump = masm.nopPatchableToNearJump().offset(); // Generate normal prologue: diff --git a/js/src/asmjs/WasmFrameIterator.h b/js/src/asmjs/WasmFrameIterator.h index b26ae6f068bb..d77553e9fdff 100644 --- a/js/src/asmjs/WasmFrameIterator.h +++ b/js/src/asmjs/WasmFrameIterator.h @@ -33,6 +33,7 @@ namespace wasm { class CallSite; class CodeRange; class Instance; +class SigIdDesc; struct CallThunk; struct FuncOffsets; struct Metadata; @@ -111,7 +112,7 @@ void GenerateExitEpilogue(jit::MacroAssembler& masm, unsigned framePushed, ExitReason reason, ProfilingOffsets* offsets); void -GenerateFunctionPrologue(jit::MacroAssembler& masm, unsigned framePushed, uint32_t sigIndex, +GenerateFunctionPrologue(jit::MacroAssembler& masm, unsigned framePushed, const SigIdDesc& sigId, FuncOffsets* offsets); void GenerateFunctionEpilogue(jit::MacroAssembler& masm, unsigned framePushed, FuncOffsets* offsets); diff --git a/js/src/asmjs/WasmGenerator.cpp b/js/src/asmjs/WasmGenerator.cpp index 64ee846f2784..82f4b0ec2925 100644 --- a/js/src/asmjs/WasmGenerator.cpp +++ b/js/src/asmjs/WasmGenerator.cpp @@ -152,6 +152,26 @@ ModuleGenerator::init(UniqueModuleGeneratorData shared, CompileArgs&& args, if (!allocateGlobalBytes(sizeof(void*), sizeof(void*), &table.globalDataOffset)) return false; } + + for (uint32_t i = 0; i < numSigs_; i++) { + SigWithId& sig = shared_->sigs[i]; + if (SigIdDesc::isGlobal(sig)) { + uint32_t globalDataOffset; + if (!allocateGlobalBytes(sizeof(void*), sizeof(void*), &globalDataOffset)) + return false; + + sig.id = SigIdDesc::global(sig, globalDataOffset); + + Sig copy; + if (!copy.clone(sig)) + return false; + + if (!metadata_->sigIds.emplaceBack(Move(copy), sig.id)) + return false; + } else { + sig.id = SigIdDesc::immediate(sig); + } + } } else { MOZ_ASSERT(shared_->sigs.length() == MaxSigs); MOZ_ASSERT(shared_->tables.length() == MaxTables); @@ -341,9 +361,6 @@ ModuleGenerator::finishTask(IonCompileTask* task) return true; } -typedef Vector OffsetVector; -typedef Vector ProfilingOffsetVector; - bool ModuleGenerator::finishFuncExports() { @@ -376,6 +393,9 @@ ModuleGenerator::finishFuncExports() return true; } +typedef Vector OffsetVector; +typedef Vector ProfilingOffsetVector; + bool ModuleGenerator::finishCodegen() { @@ -616,7 +636,7 @@ ModuleGenerator::initSig(uint32_t sigIndex, Sig&& sig) shared_->sigs[sigIndex] = Move(sig); } -const DeclaredSig& +const SigWithId& ModuleGenerator::sig(uint32_t index) const { MOZ_ASSERT(index < numSigs_); @@ -650,7 +670,7 @@ ModuleGenerator::bumpMinMemoryLength(uint32_t newMinMemoryLength) shared_->minMemoryLength = newMinMemoryLength; } -const DeclaredSig& +const SigWithId& ModuleGenerator::funcSig(uint32_t funcIndex) const { MOZ_ASSERT(shared_->funcSigs[funcIndex]); diff --git a/js/src/asmjs/WasmGenerator.h b/js/src/asmjs/WasmGenerator.h index c29f9ea71d2f..16cd52b328db 100644 --- a/js/src/asmjs/WasmGenerator.h +++ b/js/src/asmjs/WasmGenerator.h @@ -38,11 +38,11 @@ class FunctionGenerator; struct FuncImportGenDesc { - const DeclaredSig* sig; + const SigWithId* sig; uint32_t globalDataOffset; FuncImportGenDesc() : sig(nullptr), globalDataOffset(0) {} - explicit FuncImportGenDesc(const DeclaredSig* sig) : sig(sig), globalDataOffset(0) {} + explicit FuncImportGenDesc(const SigWithId* sig) : sig(sig), globalDataOffset(0) {} }; typedef Vector FuncImportGenDescVector; @@ -55,17 +55,13 @@ struct ModuleGeneratorData mozilla::Atomic minMemoryLength; uint32_t maxMemoryLength; - DeclaredSigVector sigs; - DeclaredSigPtrVector funcSigs; + SigWithIdVector sigs; + SigWithIdPtrVector funcSigs; FuncImportGenDescVector funcImports; GlobalDescVector globals; TableDescVector tables; Uint32Vector asmJSSigToTableIndex; - uint32_t funcSigIndex(uint32_t funcIndex) const { - return funcSigs[funcIndex] - sigs.begin(); - } - explicit ModuleGeneratorData(SignalUsage usesSignal, ModuleKind kind = ModuleKind::Wasm) : kind(kind), usesSignal(usesSignal), @@ -161,11 +157,11 @@ class MOZ_STACK_CLASS ModuleGenerator // Signatures: uint32_t numSigs() const { return numSigs_; } - const DeclaredSig& sig(uint32_t sigIndex) const; + const SigWithId& sig(uint32_t sigIndex) const; // Function declarations: uint32_t numFuncSigs() const { return shared_->funcSigs.length(); } - const DeclaredSig& funcSig(uint32_t funcIndex) const; + const SigWithId& funcSig(uint32_t funcIndex) const; // Globals: MOZ_MUST_USE bool allocateGlobal(ValType type, bool isConst, uint32_t* index); diff --git a/js/src/asmjs/WasmInstance.cpp b/js/src/asmjs/WasmInstance.cpp index 3e48fcd1f016..6612a26a806f 100644 --- a/js/src/asmjs/WasmInstance.cpp +++ b/js/src/asmjs/WasmInstance.cpp @@ -41,6 +41,59 @@ using namespace js::wasm; using mozilla::BinarySearch; using mozilla::Swap; +class SigIdSet +{ + typedef HashMap Map; + Map map_; + + public: + ~SigIdSet() { + MOZ_ASSERT_IF(!JSRuntime::hasLiveRuntimes(), !map_.initialized() || map_.empty()); + } + + bool ensureInitialized(JSContext* cx) { + if (!map_.initialized() && !map_.init()) { + ReportOutOfMemory(cx); + return false; + } + + return true; + } + + bool allocateSigId(JSContext* cx, const Sig& sig, const void** sigId) { + Map::AddPtr p = map_.lookupForAdd(sig); + if (p) { + MOZ_ASSERT(p->value() > 0); + p->value()++; + *sigId = p->key(); + return true; + } + + UniquePtr clone = MakeUnique(); + if (!clone || !clone->clone(sig) || !map_.add(p, clone.get(), 1)) { + ReportOutOfMemory(cx); + return false; + } + + *sigId = clone.release(); + MOZ_ASSERT(!(uintptr_t(*sigId) & SigIdDesc::ImmediateBit)); + return true; + } + + void deallocateSigId(const Sig& sig, const void* sigId) { + Map::Ptr p = map_.lookup(sig); + MOZ_RELEASE_ASSERT(p && p->key() == sigId && p->value() > 0); + + p->value()--; + if (!p->value()) { + js_delete(p->key()); + map_.remove(p); + } + } +}; + +ExclusiveData sigIdSet; + uint8_t** Instance::addressOfMemoryBase() const { @@ -54,6 +107,13 @@ Instance::addressOfTableBase(size_t tableIndex) const return (void**)(codeSegment_->globalData() + metadata_->tables[tableIndex].globalDataOffset); } +const void** +Instance::addressOfSigId(const SigIdDesc& sigId) const +{ + MOZ_ASSERT(sigId.globalDataOffset() >= InitialGlobalDataBytes); + return (const void**)(codeSegment_->globalData() + sigId.globalDataOffset()); +} + FuncImportExit& Instance::funcImportToExit(const FuncImport& fi) { @@ -388,6 +448,27 @@ Instance::Instance(UniqueCodeSegment codeSegment, *addressOfTableBase(i) = tables_[i]->array(); } +bool +Instance::init(JSContext* cx) +{ + if (!metadata_->sigIds.empty()) { + ExclusiveData::Guard lockedSigIdSet = sigIdSet.lock(); + + if (!lockedSigIdSet->ensureInitialized(cx)) + return false; + + for (const SigWithId& sig : metadata_->sigIds) { + const void* sigId; + if (!lockedSigIdSet->allocateSigId(cx, sig, &sigId)) + return false; + + *addressOfSigId(sig.id) = sigId; + } + } + + return true; +} + Instance::~Instance() { for (unsigned i = 0; i < metadata_->funcImports.length(); i++) { @@ -395,6 +476,15 @@ Instance::~Instance() if (exit.baselineScript) exit.baselineScript->removeDependentWasmImport(*this, i); } + + if (!metadata_->sigIds.empty()) { + ExclusiveData::Guard lockedSigIdSet = sigIdSet.lock(); + + for (const SigWithId& sig : metadata_->sigIds) { + if (const void* sigId = *addressOfSigId(sig.id)) + lockedSigIdSet->deallocateSigId(sig, sigId); + } + } } void diff --git a/js/src/asmjs/WasmInstance.h b/js/src/asmjs/WasmInstance.h index 7692fa29f905..f20a5828353f 100644 --- a/js/src/asmjs/WasmInstance.h +++ b/js/src/asmjs/WasmInstance.h @@ -55,6 +55,7 @@ class Instance // Internal helpers: uint8_t** addressOfMemoryBase() const; void** addressOfTableBase(size_t tableIndex) const; + const void** addressOfSigId(const SigIdDesc& sigId) const; FuncImportExit& funcImportToExit(const FuncImport& fi); MOZ_MUST_USE bool toggleProfiling(JSContext* cx); @@ -80,6 +81,7 @@ class Instance SharedTableVector&& tables, Handle funcImports); ~Instance(); + bool init(JSContext* cx); void trace(JSTracer* trc); const CodeSegment& codeSegment() const { return *codeSegment_; } diff --git a/js/src/asmjs/WasmIonCompile.cpp b/js/src/asmjs/WasmIonCompile.cpp index 27bac1359147..3651fce5dad5 100644 --- a/js/src/asmjs/WasmIonCompile.cpp +++ b/js/src/asmjs/WasmIonCompile.cpp @@ -901,10 +901,11 @@ class FunctionCompiler MInstruction* ptrFun = MAsmJSLoadFuncPtr::New(alloc(), maskedIndex, globalDataOffset); curBlock_->add(ptrFun); callee = MAsmJSCall::Callee(ptrFun); + MOZ_ASSERT(mg_.sigs[sigIndex].id.kind() == SigIdDesc::Kind::None); } else { MInstruction* ptrFun = MAsmJSLoadFuncPtr::New(alloc(), index, length, globalDataOffset); curBlock_->add(ptrFun); - callee = MAsmJSCall::Callee(ptrFun, sigIndex); + callee = MAsmJSCall::Callee(ptrFun, mg_.sigs[sigIndex].id); } return callPrivate(callee, args, mg_.sigs[sigIndex].ret(), def); @@ -3384,10 +3385,10 @@ wasm::IonCompileFunction(IonCompileTask* task) if (!lir) return false; - uint32_t sigIndex = task->mg().funcSigIndex(func.index()); + SigIdDesc sigId = task->mg().funcSigs[func.index()]->id; CodeGenerator codegen(&mir, lir, &results.masm()); - if (!codegen.generateWasm(sigIndex, &results.offsets())) + if (!codegen.generateWasm(sigId, &results.offsets())) return false; } diff --git a/js/src/asmjs/WasmIonCompile.h b/js/src/asmjs/WasmIonCompile.h index 8f11286a92d3..557125adbb0f 100644 --- a/js/src/asmjs/WasmIonCompile.h +++ b/js/src/asmjs/WasmIonCompile.h @@ -37,16 +37,16 @@ typedef jit::ABIArgIter ABIArgValTypeIter; class FuncBytes { - Bytes bytes_; - uint32_t index_; - const DeclaredSig& sig_; - uint32_t lineOrBytecode_; - Uint32Vector callSiteLineNums_; + Bytes bytes_; + uint32_t index_; + const SigWithId& sig_; + uint32_t lineOrBytecode_; + Uint32Vector callSiteLineNums_; public: FuncBytes(Bytes&& bytes, uint32_t index, - const DeclaredSig& sig, + const SigWithId& sig, uint32_t lineOrBytecode, Uint32Vector&& callSiteLineNums) : bytes_(Move(bytes)), @@ -59,7 +59,7 @@ class FuncBytes Bytes& bytes() { return bytes_; } const Bytes& bytes() const { return bytes_; } uint32_t index() const { return index_; } - const DeclaredSig& sig() const { return sig_; } + const SigWithId& sig() const { return sig_; } uint32_t lineOrBytecode() const { return lineOrBytecode_; } const Uint32Vector& callSiteLineNums() const { return callSiteLineNums_; } }; diff --git a/js/src/asmjs/WasmModule.cpp b/js/src/asmjs/WasmModule.cpp index 4466cc50d9f8..6d1ec98d98ee 100644 --- a/js/src/asmjs/WasmModule.cpp +++ b/js/src/asmjs/WasmModule.cpp @@ -442,8 +442,8 @@ Module::instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) c } bool -Module::instantiateTable(JSContext* cx, const CodeSegment& codeSegment, - HandleWasmTableObject tableImport, SharedTableVector* tables) const +Module::instantiateTable(JSContext* cx, HandleWasmTableObject tableImport, + SharedTableVector* tables) const { for (const TableDesc& tableDesc : metadata_->tables) { SharedTable table; @@ -551,7 +551,7 @@ Module::instantiate(JSContext* cx, return false; SharedTableVector tables; - if (!instantiateTable(cx, *codeSegment, tableImport, &tables)) + if (!instantiateTable(cx, tableImport, &tables)) return false; // To support viewing the source of an instance (Instance::createText), the @@ -586,6 +586,9 @@ Module::instantiate(JSContext* cx, instanceObj->init(Move(instance)); } + if (!instanceObj->instance().init(cx)) + return false; + // Create the export object. RootedObject exportObj(cx); diff --git a/js/src/asmjs/WasmModule.h b/js/src/asmjs/WasmModule.h index 4816a951e79c..8ca9e8f22858 100644 --- a/js/src/asmjs/WasmModule.h +++ b/js/src/asmjs/WasmModule.h @@ -186,8 +186,8 @@ class Module : public RefCounted const SharedBytes bytecode_; bool instantiateMemory(JSContext* cx, MutableHandleWasmMemoryObject memory) const; - bool instantiateTable(JSContext* cx, const CodeSegment& codeSegment, - HandleWasmTableObject tableImport, SharedTableVector* tables) const; + bool instantiateTable(JSContext* cx, HandleWasmTableObject tableImport, + SharedTableVector* tables) const; bool initElems(JSContext* cx, HandleWasmInstanceObject instanceObj, HandleWasmTableObject tableObj) const; diff --git a/js/src/asmjs/WasmTypes.cpp b/js/src/asmjs/WasmTypes.cpp index cec0b43599b0..870362d67555 100644 --- a/js/src/asmjs/WasmTypes.cpp +++ b/js/src/asmjs/WasmTypes.cpp @@ -330,6 +330,154 @@ GetCPUID() #endif } +typedef uint32_t ImmediateType; // for 32/64 consistency +static const unsigned sImmediateBits = sizeof(ImmediateType) * 8 - 1; // -1 for ImmediateBit +static const unsigned sReturnBit = 1; +static const unsigned sLengthBits = 4; +static const unsigned sTypeBits = 2; +static const unsigned sMaxTypes = (sImmediateBits - sReturnBit - sLengthBits) / sTypeBits; + +static bool +IsImmediateType(ValType vt) +{ + MOZ_ASSERT(uint32_t(vt) > 0); + return (uint32_t(vt) - 1) < (1 << sTypeBits); +} + +static bool +IsImmediateType(ExprType et) +{ + return et == ExprType::Void || IsImmediateType(NonVoidToValType(et)); +} + +/* static */ bool +SigIdDesc::isGlobal(const Sig& sig) +{ + unsigned numTypes = (sig.ret() == ExprType::Void ? 0 : 1) + + (sig.args().length()); + if (numTypes > sMaxTypes) + return true; + + if (!IsImmediateType(sig.ret())) + return true; + + for (ValType v : sig.args()) { + if (!IsImmediateType(v)) + return true; + } + + return false; +} + +/* static */ SigIdDesc +SigIdDesc::global(const Sig& sig, uint32_t globalDataOffset) +{ + MOZ_ASSERT(isGlobal(sig)); + return SigIdDesc(Kind::Global, globalDataOffset); +} + +static ImmediateType +LengthToBits(uint32_t length) +{ + static_assert(sMaxTypes <= ((1 << sLengthBits) - 1), "fits"); + MOZ_ASSERT(length <= sMaxTypes); + return length; +} + +static ImmediateType +TypeToBits(ValType type) +{ + static_assert(3 <= ((1 << sTypeBits) - 1), "fits"); + MOZ_ASSERT(uint32_t(type) >= 1 && uint32_t(type) <= 4); + return uint32_t(type) - 1; +} + +size_t +Sig::serializedSize() const +{ + return sizeof(ret_) + + SerializedPodVectorSize(args_); +} + +uint8_t* +Sig::serialize(uint8_t* cursor) const +{ + cursor = WriteScalar(cursor, ret_); + cursor = SerializePodVector(cursor, args_); + return cursor; +} + +const uint8_t* +Sig::deserialize(const uint8_t* cursor) +{ + (cursor = ReadScalar(cursor, &ret_)) && + (cursor = DeserializePodVector(cursor, &args_)); + return cursor; +} + +size_t +Sig::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const +{ + return args_.sizeOfExcludingThis(mallocSizeOf); +} + +/* static */ SigIdDesc +SigIdDesc::immediate(const Sig& sig) +{ + ImmediateType immediate = ImmediateBit; + uint32_t shift = 1; + + if (sig.ret() != ExprType::Void) { + immediate |= (1 << shift); + shift += sReturnBit; + + immediate |= TypeToBits(NonVoidToValType(sig.ret())) << shift; + shift += sTypeBits; + } else { + shift += sReturnBit; + } + + immediate |= LengthToBits(sig.args().length()) << shift; + shift += sLengthBits; + + for (ValType argType : sig.args()) { + immediate |= TypeToBits(argType) << shift; + shift += sTypeBits; + } + + MOZ_ASSERT(shift <= sImmediateBits); + return SigIdDesc(Kind::Immediate, immediate); +} + +size_t +SigWithId::serializedSize() const +{ + return Sig::serializedSize() + + sizeof(id); +} + +uint8_t* +SigWithId::serialize(uint8_t* cursor) const +{ + cursor = Sig::serialize(cursor); + cursor = WriteBytes(cursor, &id, sizeof(id)); + return cursor; +} + +const uint8_t* +SigWithId::deserialize(const uint8_t* cursor) +{ + (cursor = Sig::deserialize(cursor)) && + (cursor = ReadBytes(cursor, &id, sizeof(id))); + return cursor; +} + +size_t +SigWithId::sizeOfExcludingThis(MallocSizeOf mallocSizeOf) const +{ + return Sig::sizeOfExcludingThis(mallocSizeOf); +} + Assumptions::Assumptions(JS::BuildIdCharVector&& buildId) : usesSignal(), cpuId(GetCPUID()), diff --git a/js/src/asmjs/WasmTypes.h b/js/src/asmjs/WasmTypes.h index a256522c2e5c..47071631bb5a 100644 --- a/js/src/asmjs/WasmTypes.h +++ b/js/src/asmjs/WasmTypes.h @@ -402,6 +402,8 @@ class Sig bool operator!=(const Sig& rhs) const { return !(*this == rhs); } + + WASM_DECLARE_SERIALIZABLE(Sig) }; struct SigHashPolicy @@ -411,6 +413,61 @@ struct SigHashPolicy static bool match(const Sig* lhs, Lookup rhs) { return *lhs == rhs; } }; +// SigIdDesc describes a signature id that can be used by call_indirect and +// table-entry prologues to structurally compare whether the caller and callee's +// signatures *structurally* match. To handle the general case, a Sig is +// allocated and stored in a process-wide hash table, so that pointer equality +// implies structural equality. As an optimization for the 99% case where the +// Sig has a small number of parameters, the Sig is bit-packed into a uint32 +// immediate value so that integer equality implies structural equality. Both +// cases can be handled with a single comparison by always setting the LSB for +// the immediates (the LSB is necessarily 0 for allocated Sig pointers due to +// alignment). + +class SigIdDesc +{ + public: + enum class Kind { None, Immediate, Global }; + static const uintptr_t ImmediateBit = 0x1; + + private: + Kind kind_; + size_t bits_; + + SigIdDesc(Kind kind, size_t bits) : kind_(kind), bits_(bits) {} + + public: + Kind kind() const { return kind_; } + static bool isGlobal(const Sig& sig); + + SigIdDesc() : kind_(Kind::None), bits_(0) {} + static SigIdDesc global(const Sig& sig, uint32_t globalDataOffset); + static SigIdDesc immediate(const Sig& sig); + + bool isGlobal() const { return kind_ == Kind::Global; } + + size_t immediate() const { MOZ_ASSERT(kind_ == Kind::Immediate); return bits_; } + uint32_t globalDataOffset() const { MOZ_ASSERT(kind_ == Kind::Global); return bits_; } +}; + +// SigWithId pairs a Sig with SigIdDesc, describing either how to compile code +// that compares this signature's id or, at instantiation what signature ids to +// allocate in the global hash and where to put them. + +struct SigWithId : Sig +{ + SigIdDesc id; + + SigWithId() = default; + explicit SigWithId(Sig&& sig, SigIdDesc id) : Sig(Move(sig)), id(id) {} + void operator=(Sig&& rhs) { Sig::operator=(Move(rhs)); } + + WASM_DECLARE_SERIALIZABLE(SigWithId) +}; + +typedef Vector SigWithIdVector; +typedef Vector SigWithIdPtrVector; + // A GlobalDesc describes a single global variable. Currently, globals are only // exposed through asm.js. @@ -426,22 +483,6 @@ struct GlobalDesc typedef Vector GlobalDescVector; -// A "declared" signature is a Sig object that is created and owned by the -// ModuleGenerator. These signature objects are read-only and have the same -// lifetime as the ModuleGenerator. This type is useful since some uses of Sig -// need this extended lifetime and want to statically distinguish from the -// common stack-allocated Sig objects that get passed around. - -struct DeclaredSig : Sig -{ - DeclaredSig() = default; - explicit DeclaredSig(Sig&& sig) : Sig(Move(sig)) {} - void operator=(Sig&& rhs) { Sig::operator=(Move(rhs)); } -}; - -typedef Vector DeclaredSigVector; -typedef Vector DeclaredSigPtrVector; - // The (,Profiling,Func)Offsets classes are used to record the offsets of // different key points in a CodeRange during compilation. diff --git a/js/src/jit-test/tests/wasm/spec/func_ptrs.wast b/js/src/jit-test/tests/wasm/spec/func_ptrs.wast index 8b89ec7d76d9..c63d78e24b65 100644 --- a/js/src/jit-test/tests/wasm/spec/func_ptrs.wast +++ b/js/src/jit-test/tests/wasm/spec/func_ptrs.wast @@ -58,21 +58,21 @@ (assert_return (invoke "callt" (i32.const 0)) (i32.const 1)) (assert_return (invoke "callt" (i32.const 1)) (i32.const 2)) (assert_return (invoke "callt" (i32.const 2)) (i32.const 3)) -(assert_trap (invoke "callt" (i32.const 3)) "indirect call signature mismatch") -(assert_trap (invoke "callt" (i32.const 4)) "indirect call signature mismatch") +(assert_return (invoke "callt" (i32.const 3)) (i32.const 4)) +(assert_return (invoke "callt" (i32.const 4)) (i32.const 5)) (assert_return (invoke "callt" (i32.const 5)) (i32.const 1)) (assert_return (invoke "callt" (i32.const 6)) (i32.const 3)) (assert_trap (invoke "callt" (i32.const 7)) "undefined table index 7") (assert_trap (invoke "callt" (i32.const 100)) "undefined table index 100") (assert_trap (invoke "callt" (i32.const -1)) "undefined table index -1") -(assert_trap (invoke "callu" (i32.const 0)) "indirect call signature mismatch") -(assert_trap (invoke "callu" (i32.const 1)) "indirect call signature mismatch") -(assert_trap (invoke "callu" (i32.const 2)) "indirect call signature mismatch") +(assert_return (invoke "callu" (i32.const 0)) (i32.const 1)) +(assert_return (invoke "callu" (i32.const 1)) (i32.const 2)) +(assert_return (invoke "callu" (i32.const 2)) (i32.const 3)) (assert_return (invoke "callu" (i32.const 3)) (i32.const 4)) (assert_return (invoke "callu" (i32.const 4)) (i32.const 5)) -(assert_trap (invoke "callu" (i32.const 5)) "indirect call signature mismatch") -(assert_trap (invoke "callu" (i32.const 6)) "indirect call signature mismatch") +(assert_return (invoke "callu" (i32.const 5)) (i32.const 1)) +(assert_return (invoke "callu" (i32.const 6)) (i32.const 3)) (assert_trap (invoke "callu" (i32.const 7)) "undefined table index 7") (assert_trap (invoke "callu" (i32.const -1)) "undefined table index -1") diff --git a/js/src/jit-test/tests/wasm/table-gc.js b/js/src/jit-test/tests/wasm/table-gc.js new file mode 100644 index 000000000000..4ce46c12bfe1 --- /dev/null +++ b/js/src/jit-test/tests/wasm/table-gc.js @@ -0,0 +1,154 @@ +// |jit-test| --no-baseline +// Turn off baseline and since it messes up the GC finalization assertions by +// adding spurious edges to the GC graph. + +load(libdir + 'wasm.js'); +load(libdir + 'asserts.js'); + +const Module = WebAssembly.Module; +const Instance = WebAssembly.Instance; +const Table = WebAssembly.Table; + +// Explicitly opt into the new binary format for imports and exports until it +// is used by default everywhere. +const textToBinary = str => wasmTextToBinary(str, 'new-format'); +const evalText = (str, imports) => new Instance(new Module(textToBinary(str)), imports); + +var caller = `(type $v2i (func (result i32))) (func $call (param $i i32) (result i32) (call_indirect $v2i (get_local $i))) (export "call" $call)` +var callee = i => `(func $f${i} (type $v2i) (result i32) (i32.const ${i}))`; + +// A table should not hold exported functions alive and exported functions +// should not hold their originating table alive. Live exported functions should +// hold instances alive. Nothing should hold the export object alive. +resetFinalizeCount(); +var i = evalText(`(module (table (resizable 2)) (export "tbl" table) (elem 0 $f0) ${callee(0)} ${caller})`); +var e = i.exports; +var t = e.tbl; +var f = t.get(0); +assertEq(f(), e.call(0)); +assertErrorMessage(() => e.call(1), Error, /bad wasm indirect call/); +assertErrorMessage(() => e.call(2), Error, /out-of-range/); +assertEq(finalizeCount(), 0); +i.edge = makeFinalizeObserver(); +e.edge = makeFinalizeObserver(); +t.edge = makeFinalizeObserver(); +f.edge = makeFinalizeObserver(); +gc(); +assertEq(finalizeCount(), 0); +f = null; +gc(); +assertEq(finalizeCount(), 1); +f = t.get(0); +f.edge = makeFinalizeObserver(); +gc(); +assertEq(finalizeCount(), 1); +i.exports = null; +e = null; +gc(); +assertEq(finalizeCount(), 2); +t = null; +gc(); +assertEq(finalizeCount(), 3); +i = null; +gc(); +assertEq(finalizeCount(), 3); +assertEq(f(), 0); +f = null; +gc(); +assertEq(finalizeCount(), 5); + +// A table should hold the instance of any of its elements alive. +resetFinalizeCount(); +var i = evalText(`(module (table (resizable 1)) (export "tbl" table) (elem 0 $f0) ${callee(0)} ${caller})`); +var e = i.exports; +var t = e.tbl; +var f = t.get(0); +i.edge = makeFinalizeObserver(); +e.edge = makeFinalizeObserver(); +t.edge = makeFinalizeObserver(); +f.edge = makeFinalizeObserver(); +gc(); +assertEq(finalizeCount(), 0); +i.exports = null; +e = null; +gc(); +assertEq(finalizeCount(), 1); +f = null; +gc(); +assertEq(finalizeCount(), 2); +i = null; +gc(); +assertEq(finalizeCount(), 2); +t = null; +gc(); +assertEq(finalizeCount(), 4); + +// The bad-indirect-call stub should (currently, could be changed later) keep +// the instance containing that stub alive. +resetFinalizeCount(); +var i = evalText(`(module (table (resizable 2)) (export "tbl" table) ${caller})`); +var e = i.exports; +var t = e.tbl; +i.edge = makeFinalizeObserver(); +e.edge = makeFinalizeObserver(); +t.edge = makeFinalizeObserver(); +gc(); +assertEq(finalizeCount(), 0); +i.exports = null; +e = null; +gc(); +assertEq(finalizeCount(), 1); +i = null; +gc(); +assertEq(finalizeCount(), 1); +t = null; +gc(); +assertEq(finalizeCount(), 3); + +// Before initialization, a table is not bound to any instance. +resetFinalizeCount(); +var i = evalText(`(module (func $f0 (result i32) (i32.const 0)) (export "f0" $f0))`); +var t = new Table({initial:4}); +i.edge = makeFinalizeObserver(); +t.edge = makeFinalizeObserver(); +gc(); +assertEq(finalizeCount(), 0); +i = null; +gc(); +assertEq(finalizeCount(), 1); +t = null; +gc(); +assertEq(finalizeCount(), 2); + +// When a Table is created (uninitialized) and then first assigned, it keeps the +// first element's Instance alive (as above). +resetFinalizeCount(); +var i = evalText(`(module (func $f (result i32) (i32.const 42)) (export "f" $f))`); +var f = i.exports.f; +var t = new Table({initial:1}); +i.edge = makeFinalizeObserver(); +f.edge = makeFinalizeObserver(); +t.edge = makeFinalizeObserver(); +t.set(0, f); +assertEq(t.get(0), f); +assertEq(t.get(0)(), 42); +gc(); +assertEq(finalizeCount(), 0); +f = null; +i.exports = null; +gc(); +assertEq(finalizeCount(), 1); +assertEq(t.get(0)(), 42); +t.get(0).edge = makeFinalizeObserver(); +gc(); +assertEq(finalizeCount(), 2); +i = null; +gc(); +assertEq(finalizeCount(), 2); +t.set(0, null); +assertEq(t.get(0), null); +gc(); +assertEq(finalizeCount(), 2); +t = null; +gc(); +assertEq(finalizeCount(), 4); diff --git a/js/src/jit-test/tests/wasm/tables.js b/js/src/jit-test/tests/wasm/tables.js index 92cdcba58bbc..879008fe84f8 100644 --- a/js/src/jit-test/tests/wasm/tables.js +++ b/js/src/jit-test/tests/wasm/tables.js @@ -1,8 +1,4 @@ -// |jit-test| --no-baseline - -// Turn off baseline and since it messes up the GC finalization assertions by -// adding spurious edges to the GC graph. - +// |jit-test| test-also-wasm-baseline load(libdir + 'wasm.js'); load(libdir + 'asserts.js'); @@ -60,138 +56,19 @@ assertEq(call(1), 1); assertEq(tbl.get(0)(), 0); assertEq(tbl.get(1)(), 1); -// A table should not hold exported functions alive and exported functions -// should not hold their originating table alive. Live exported functions should -// hold instances alive. Nothing should hold the export object alive. -resetFinalizeCount(); -var i = evalText(`(module (table (resizable 2)) (export "tbl" table) (elem 0 $f0) ${callee(0)} ${caller})`); -var e = i.exports; -var t = e.tbl; -var f = t.get(0); -assertEq(f(), e.call(0)); -assertErrorMessage(() => e.call(1), Error, /bad wasm indirect call/); -assertErrorMessage(() => e.call(2), Error, /out-of-range/); -assertEq(finalizeCount(), 0); -i.edge = makeFinalizeObserver(); -e.edge = makeFinalizeObserver(); -t.edge = makeFinalizeObserver(); -f.edge = makeFinalizeObserver(); -gc(); -assertEq(finalizeCount(), 0); -f = null; -gc(); -assertEq(finalizeCount(), 1); -f = t.get(0); -f.edge = makeFinalizeObserver(); -gc(); -assertEq(finalizeCount(), 1); -i.exports = null; -e = null; -gc(); -assertEq(finalizeCount(), 2); -t = null; -gc(); -assertEq(finalizeCount(), 3); -i = null; -gc(); -assertEq(finalizeCount(), 3); -assertEq(f(), 0); -f = null; -gc(); -assertEq(finalizeCount(), 5); +// Call signatures are matched structurally: -// A table should hold the instance of any of its elements alive. -resetFinalizeCount(); -var i = evalText(`(module (table (resizable 1)) (export "tbl" table) (elem 0 $f0) ${callee(0)} ${caller})`); -var e = i.exports; -var t = e.tbl; -var f = t.get(0); -i.edge = makeFinalizeObserver(); -e.edge = makeFinalizeObserver(); -t.edge = makeFinalizeObserver(); -f.edge = makeFinalizeObserver(); -gc(); -assertEq(finalizeCount(), 0); -i.exports = null; -e = null; -gc(); -assertEq(finalizeCount(), 1); -f = null; -gc(); -assertEq(finalizeCount(), 2); -i = null; -gc(); -assertEq(finalizeCount(), 2); -t = null; -gc(); -assertEq(finalizeCount(), 4); - -// The bad-indirect-call stub should (currently, could be changed later) keep -// the instance containing that stub alive. -resetFinalizeCount(); -var i = evalText(`(module (table (resizable 2)) (export "tbl" table) ${caller})`); -var e = i.exports; -var t = e.tbl; -i.edge = makeFinalizeObserver(); -e.edge = makeFinalizeObserver(); -t.edge = makeFinalizeObserver(); -gc(); -assertEq(finalizeCount(), 0); -i.exports = null; -e = null; -gc(); -assertEq(finalizeCount(), 1); -i = null; -gc(); -assertEq(finalizeCount(), 1); -t = null; -gc(); -assertEq(finalizeCount(), 3); - -// Before initialization, a table is not bound to any instance. -resetFinalizeCount(); -var i = evalText(`(module (func $f0 (result i32) (i32.const 0)) (export "f0" $f0))`); -var t = new Table({initial:4}); -i.edge = makeFinalizeObserver(); -t.edge = makeFinalizeObserver(); -gc(); -assertEq(finalizeCount(), 0); -i = null; -gc(); -assertEq(finalizeCount(), 1); -t = null; -gc(); -assertEq(finalizeCount(), 2); - -// When a Table is created (uninitialized) and then first assigned, it keeps the -// first element's Instance alive (as above). -resetFinalizeCount(); -var i = evalText(`(module (func $f (result i32) (i32.const 42)) (export "f" $f))`); -var f = i.exports.f; -var t = new Table({initial:1}); -i.edge = makeFinalizeObserver(); -f.edge = makeFinalizeObserver(); -t.edge = makeFinalizeObserver(); -t.set(0, f); -assertEq(t.get(0), f); -assertEq(t.get(0)(), 42); -gc(); -assertEq(finalizeCount(), 0); -f = null; -i.exports = null; -gc(); -assertEq(finalizeCount(), 1); -assertEq(t.get(0)(), 42); -t.get(0).edge = makeFinalizeObserver(); -gc(); -assertEq(finalizeCount(), 2); -i = null; -gc(); -assertEq(finalizeCount(), 2); -t.set(0, null); -assertEq(t.get(0), null); -gc(); -assertEq(finalizeCount(), 2); -t = null; -gc(); -assertEq(finalizeCount(), 4); +var call = evalText(`(module + (type $v2i1 (func (result i32))) + (type $v2i2 (func (result i32))) + (type $i2v (func (param i32))) + (table $a $b $c) + (func $a (type $v2i1) (result i32) (i32.const 0)) + (func $b (type $v2i2) (result i32) (i32.const 1)) + (func $c (type $i2v) (param i32)) + (func $call (param i32) (result i32) (call_indirect $v2i1 (get_local 0))) + (export "call" $call) +)`).exports.call; +assertEq(call(0), 0); +assertEq(call(1), 1); +assertErrorMessage(() => call(2), Error, /bad wasm indirect call/); diff --git a/js/src/jit/CodeGenerator.cpp b/js/src/jit/CodeGenerator.cpp index 7cb3afdac862..88c6173fdc66 100644 --- a/js/src/jit/CodeGenerator.cpp +++ b/js/src/jit/CodeGenerator.cpp @@ -8972,11 +8972,11 @@ CodeGenerator::visitRest(LRest* lir) } bool -CodeGenerator::generateWasm(uint32_t sigIndex, wasm::FuncOffsets* offsets) +CodeGenerator::generateWasm(wasm::SigIdDesc sigId, wasm::FuncOffsets* offsets) { JitSpew(JitSpew_Codegen, "# Emitting asm.js code"); - wasm::GenerateFunctionPrologue(masm, frameSize(), sigIndex, offsets); + wasm::GenerateFunctionPrologue(masm, frameSize(), sigId, offsets); // Overflow checks are omitted by CodeGenerator in some cases (leaf // functions with small framePushed). Perform overflow-checking after diff --git a/js/src/jit/CodeGenerator.h b/js/src/jit/CodeGenerator.h index f76832986449..9898c6c8ae61 100644 --- a/js/src/jit/CodeGenerator.h +++ b/js/src/jit/CodeGenerator.h @@ -66,7 +66,7 @@ class CodeGenerator final : public CodeGeneratorSpecific public: MOZ_MUST_USE bool generate(); - MOZ_MUST_USE bool generateWasm(uint32_t sigIndex, wasm::FuncOffsets *offsets); + MOZ_MUST_USE bool generateWasm(wasm::SigIdDesc sigId, wasm::FuncOffsets *offsets); MOZ_MUST_USE bool link(JSContext* cx, CompilerConstraintList* constraints); MOZ_MUST_USE bool linkSharedStubs(JSContext* cx); diff --git a/js/src/jit/MIR.h b/js/src/jit/MIR.h index ea7a5b62d0f3..4f390b251c82 100644 --- a/js/src/jit/MIR.h +++ b/js/src/jit/MIR.h @@ -13475,14 +13475,14 @@ class MAsmJSCall final class Callee { public: enum Which { Internal, Dynamic, Builtin }; - static const uint32_t NoSigIndex = UINT32_MAX; private: Which which_; - union { + union U { + U() {} uint32_t internal_; struct { MDefinition* callee_; - uint32_t sigIndex_; + wasm::SigIdDesc sigId_; } dynamic; wasm::SymbolicAddress builtin_; } u; @@ -13491,9 +13491,11 @@ class MAsmJSCall final explicit Callee(uint32_t callee) : which_(Internal) { u.internal_ = callee; } - explicit Callee(MDefinition* callee, uint32_t sigIndex = NoSigIndex) : which_(Dynamic) { + explicit Callee(MDefinition* callee, wasm::SigIdDesc sigId = wasm::SigIdDesc()) + : which_(Dynamic) + { u.dynamic.callee_ = callee; - u.dynamic.sigIndex_ = sigIndex; + u.dynamic.sigId_ = sigId; } explicit Callee(wasm::SymbolicAddress callee) : which_(Builtin) { u.builtin_ = callee; @@ -13509,13 +13511,9 @@ class MAsmJSCall final MOZ_ASSERT(which_ == Dynamic); return u.dynamic.callee_; } - bool dynamicHasSigIndex() const { + wasm::SigIdDesc dynamicSigId() const { MOZ_ASSERT(which_ == Dynamic); - return u.dynamic.sigIndex_ != NoSigIndex; - } - uint32_t dynamicSigIndex() const { - MOZ_ASSERT(dynamicHasSigIndex()); - return u.dynamic.sigIndex_; + return u.dynamic.sigId_; } wasm::SymbolicAddress builtin() const { MOZ_ASSERT(which_ == Builtin); diff --git a/js/src/jit/MacroAssembler.h b/js/src/jit/MacroAssembler.h index e7d7b6d89cde..97d55266f34c 100644 --- a/js/src/jit/MacroAssembler.h +++ b/js/src/jit/MacroAssembler.h @@ -883,7 +883,8 @@ class MacroAssembler : public MacroAssemblerSpecific // =============================================================== // Branch functions - inline void branch32(Condition cond, Register lhs, Register rhs, Label* label) PER_SHARED_ARCH; + template + inline void branch32(Condition cond, Register lhs, Register rhs, L label) PER_SHARED_ARCH; template inline void branch32(Condition cond, Register lhs, Imm32 rhs, L label) PER_SHARED_ARCH; inline void branch32(Condition cond, Register length, const RegisterOrInt32Constant& key, diff --git a/js/src/jit/arm/MacroAssembler-arm-inl.h b/js/src/jit/arm/MacroAssembler-arm-inl.h index 62b2a7e62b18..116b90bc1f7e 100644 --- a/js/src/jit/arm/MacroAssembler-arm-inl.h +++ b/js/src/jit/arm/MacroAssembler-arm-inl.h @@ -652,8 +652,9 @@ MacroAssembler::popcnt32(Register input, Register output, Register tmp) // =============================================================== // Branch functions +template void -MacroAssembler::branch32(Condition cond, Register lhs, Register rhs, Label* label) +MacroAssembler::branch32(Condition cond, Register lhs, Register rhs, L label) { ma_cmp(lhs, rhs); ma_b(label, cond); diff --git a/js/src/jit/arm64/MacroAssembler-arm64-inl.h b/js/src/jit/arm64/MacroAssembler-arm64-inl.h index 8eae4d8657e6..e7e89f3de78b 100644 --- a/js/src/jit/arm64/MacroAssembler-arm64-inl.h +++ b/js/src/jit/arm64/MacroAssembler-arm64-inl.h @@ -651,8 +651,9 @@ MacroAssembler::ctz32(Register src, Register dest, bool knownNotZero) // =============================================================== // Branch functions +template void -MacroAssembler::branch32(Condition cond, Register lhs, Register rhs, Label* label) +MacroAssembler::branch32(Condition cond, Register lhs, Register rhs, L label) { cmp32(lhs, rhs); B(label, cond); diff --git a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h index 3a207ac34632..84dbaa8c8d36 100644 --- a/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h +++ b/js/src/jit/mips-shared/MacroAssembler-mips-shared-inl.h @@ -400,8 +400,9 @@ MacroAssembler::ctz32(Register src, Register dest, bool knownNotZero) // =============================================================== // Branch functions +template void -MacroAssembler::branch32(Condition cond, Register lhs, Register rhs, Label* label) +MacroAssembler::branch32(Condition cond, Register lhs, Register rhs, L label) { ma_b(lhs, rhs, label, cond); } diff --git a/js/src/jit/shared/CodeGenerator-shared.cpp b/js/src/jit/shared/CodeGenerator-shared.cpp index 42b13ec56281..12ef0fe84fbd 100644 --- a/js/src/jit/shared/CodeGenerator-shared.cpp +++ b/js/src/jit/shared/CodeGenerator-shared.cpp @@ -1510,19 +1510,30 @@ CodeGeneratorShared::emitAsmJSCall(LAsmJSCall* ins) MAsmJSCall::Callee callee = mir->callee(); switch (callee.which()) { - case MAsmJSCall::Callee::Internal: + case MAsmJSCall::Callee::Internal: { masm.call(mir->desc(), callee.internal()); break; + } case MAsmJSCall::Callee::Dynamic: { - if (callee.dynamicHasSigIndex()) - masm.move32(Imm32(callee.dynamicSigIndex()), WasmTableCallSigReg); + wasm::SigIdDesc sigId = callee.dynamicSigId(); + switch (sigId.kind()) { + case wasm::SigIdDesc::Kind::Global: + masm.loadWasmGlobalPtr(sigId.globalDataOffset(), WasmTableCallSigReg); + break; + case wasm::SigIdDesc::Kind::Immediate: + masm.move32(Imm32(sigId.immediate()), WasmTableCallSigReg); + break; + case wasm::SigIdDesc::Kind::None: + break; + } MOZ_ASSERT(WasmTableCallPtrReg == ToRegister(ins->getOperand(mir->dynamicCalleeOperandIndex()))); masm.call(mir->desc(), WasmTableCallPtrReg); break; } - case MAsmJSCall::Callee::Builtin: + case MAsmJSCall::Callee::Builtin: { masm.call(callee.builtin()); break; + } } if (mir->spIncrement()) diff --git a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h index 4140c96df171..ba2bba63a9f3 100644 --- a/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h +++ b/js/src/jit/x86-shared/MacroAssembler-x86-shared-inl.h @@ -442,8 +442,9 @@ MacroAssembler::rshift32Arithmetic(Imm32 shift, Register srcDest) // =============================================================== // Branch instructions +template void -MacroAssembler::branch32(Condition cond, Register lhs, Register rhs, Label* label) +MacroAssembler::branch32(Condition cond, Register lhs, Register rhs, L label) { cmp32(lhs, rhs); j(cond, label); diff --git a/js/src/vm/Runtime.h b/js/src/vm/Runtime.h index caf17c96cd1a..fe17fd488ffc 100644 --- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -106,10 +106,6 @@ class Simulator; #endif } // namespace jit -namespace wasm { -class Module; -} // namespace wasm - /* * A FreeOp can do one thing: free memory. For convenience, it has delete_ * convenience methods that also call destructors. From 66620d784744b11321d19a450f1209cc523f12cb Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Fri, 22 Jul 2016 10:32:05 -0700 Subject: [PATCH 046/135] Bug 1288566 - Include all possible states in StateName; r=jonco --HG-- extra : rebase_source : 3e10b55fef34b5d9641c431f1818d08278e34554 --- js/src/jsgc.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 72e8315a4a32..c8eed2f9fcdc 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -7602,7 +7602,8 @@ StateName(State state) "Mark", "Sweep", "Finalize", - "Compact" + "Compact", + "Decommit" }; MOZ_ASSERT(ArrayLength(names) == NUM_STATES); MOZ_ASSERT(state < NUM_STATES); From f3ec60ef5fafeeb2e4ecae864ef2ec7dbb2c3784 Mon Sep 17 00:00:00 2001 From: David Keeler Date: Fri, 22 Jul 2016 10:31:34 -0700 Subject: [PATCH 047/135] backout changeset 1a1d7ef3cb0e (bug 1279479) for causing WebRTC compatibility issues The WebRTC implementation inherits cipher suite preferences from PSM and then enables a few mandatory ones and disables a number of undesirable ones. If PSM makes a change to a cipher suite preference that isn't in WebRTC's whitelist or blacklist, compatibility issues can arise. See bug 1288246 for an example. --HG-- rename : security/manager/ssl/tests/unit/test_fallback_cipher.js => security/manager/ssl/tests/unit/test_weak_crypto.js --- dom/flyweb/HttpServer.cpp | 3 +- security/manager/ssl/LocalCertService.cpp | 72 +++----- security/manager/ssl/nsILocalCertService.idl | 8 +- security/manager/ssl/nsNSSComponent.cpp | 44 ++--- security/manager/ssl/nsNSSComponent.h | 4 +- security/manager/ssl/nsNSSIOLayer.cpp | 25 ++- ...fallback_cipher.js => test_weak_crypto.js} | 158 ++++++++++-------- security/manager/ssl/tests/unit/xpcshell.ini | 2 - toolkit/components/telemetry/Histograms.json | 7 + .../telemetry/histogram-whitelists.json | 2 + 10 files changed, 169 insertions(+), 156 deletions(-) rename security/manager/ssl/tests/unit/{test_fallback_cipher.js => test_weak_crypto.js} (55%) diff --git a/dom/flyweb/HttpServer.cpp b/dom/flyweb/HttpServer.cpp index 03d2f7b04a7a..726ad2192a5d 100644 --- a/dom/flyweb/HttpServer.cpp +++ b/dom/flyweb/HttpServer.cpp @@ -54,8 +54,7 @@ HttpServer::Init(int32_t aPort, bool aHttps, HttpServerListener* aListener) if (mHttps) { nsCOMPtr lcs = do_CreateInstance("@mozilla.org/security/local-cert-service;1"); - nsresult rv = lcs->GetOrCreateCert(NS_LITERAL_CSTRING("flyweb"), this, - nsILocalCertService::KEY_TYPE_EC); + nsresult rv = lcs->GetOrCreateCert(NS_LITERAL_CSTRING("flyweb"), this); if (NS_FAILED(rv)) { NotifyStarted(rv); } diff --git a/security/manager/ssl/LocalCertService.cpp b/security/manager/ssl/LocalCertService.cpp index 346383910f4a..7ea0b47890eb 100644 --- a/security/manager/ssl/LocalCertService.cpp +++ b/security/manager/ssl/LocalCertService.cpp @@ -71,12 +71,10 @@ class LocalCertGetTask final : public LocalCertTask { public: LocalCertGetTask(const nsACString& aNickname, - nsILocalCertGetCallback* aCallback, - uint32_t aKeyType) + nsILocalCertGetCallback* aCallback) : LocalCertTask(aNickname) , mCallback(new nsMainThreadPtrHolder(aCallback)) , mCert(nullptr) - , mKeyType(aKeyType) { } @@ -131,43 +129,24 @@ private: return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } - UniqueSECKEYPrivateKey privateKey; - - SECOidTag algTag; - SECKEYPublicKey* tempPublicKey; - if (mKeyType == nsILocalCertService::KEY_TYPE_RSA) { - // Use RSA key params - PK11RSAGenParams rsaParams; - rsaParams.keySizeInBits = 2048; - rsaParams.pe = 65537; - algTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; - - // Generate cert key pair - privateKey.reset( - PK11_GenerateKeyPair(slot.get(), CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams, - &tempPublicKey, true /* token */, - true /* sensitive */, nullptr)); - } else { - // Use the well-known NIST P-256 curve - SECOidData* curveOidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); - if (!curveOidData) { - return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); - } - - // Get key params from the curve - ScopedAutoSECItem keyParams(2 + curveOidData->oid.len); - keyParams.data[0] = SEC_ASN1_OBJECT_ID; - keyParams.data[1] = curveOidData->oid.len; - memcpy(keyParams.data + 2, curveOidData->oid.data, curveOidData->oid.len); - algTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; - - // Generate cert key pair - privateKey.reset( - PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &keyParams, - &tempPublicKey, true /* token */, - true /* sensitive */, nullptr)); + // Use the well-known NIST P-256 curve + SECOidData* curveOidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); + if (!curveOidData) { + return mozilla::psm::GetXPCOMFromNSSError(PR_GetError()); } + // Get key params from the curve + ScopedAutoSECItem keyParams(2 + curveOidData->oid.len); + keyParams.data[0] = SEC_ASN1_OBJECT_ID; + keyParams.data[1] = curveOidData->oid.len; + memcpy(keyParams.data + 2, curveOidData->oid.data, curveOidData->oid.len); + + // Generate cert key pair + SECKEYPublicKey* tempPublicKey; + UniqueSECKEYPrivateKey privateKey( + PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &keyParams, + &tempPublicKey, true /* token */, + true /* sensitive */, nullptr)); UniqueSECKEYPublicKey publicKey(tempPublicKey); tempPublicKey = nullptr; if (!privateKey || !publicKey) { @@ -231,7 +210,8 @@ private: return NS_ERROR_INVALID_POINTER; } rv = MapSECStatus( - SECOID_SetAlgorithmID(arena, &cert->signature, algTag, 0)); + SECOID_SetAlgorithmID(arena, &cert->signature, + SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, 0)); if (NS_FAILED(rv)) { return rv; } @@ -245,7 +225,8 @@ private: } rv = MapSECStatus( SEC_DerSignData(arena, &cert->derCert, certDER->data, certDER->len, - privateKey.get(), algTag)); + privateKey.get(), + SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE)); if (NS_FAILED(rv)) { return rv; } @@ -345,7 +326,6 @@ private: nsMainThreadPtrHandle mCallback; nsCOMPtr mCert; // out - uint32_t mKeyType; }; class LocalCertRemoveTask final : public LocalCertTask @@ -425,8 +405,7 @@ LocalCertService::LoginToKeySlot() NS_IMETHODIMP LocalCertService::GetOrCreateCert(const nsACString& aNickname, - nsILocalCertGetCallback* aCallback, - uint32_t aKeyType) + nsILocalCertGetCallback* aCallback) { if (NS_WARN_IF(aNickname.IsEmpty())) { return NS_ERROR_INVALID_ARG; @@ -434,10 +413,6 @@ LocalCertService::GetOrCreateCert(const nsACString& aNickname, if (NS_WARN_IF(!aCallback)) { return NS_ERROR_INVALID_POINTER; } - if (aKeyType != nsILocalCertService::KEY_TYPE_EC && - aKeyType != nsILocalCertService::KEY_TYPE_RSA) { - return NS_ERROR_INVALID_ARG; - } // Before sending off the task, login to key slot if needed nsresult rv = LoginToKeySlot(); @@ -446,8 +421,7 @@ LocalCertService::GetOrCreateCert(const nsACString& aNickname, return NS_OK; } - RefPtr task(new LocalCertGetTask(aNickname, aCallback, - aKeyType)); + RefPtr task(new LocalCertGetTask(aNickname, aCallback)); return task->Dispatch("LocalCertGet"); } diff --git a/security/manager/ssl/nsILocalCertService.idl b/security/manager/ssl/nsILocalCertService.idl index e8031553f2ef..a452683d97f8 100644 --- a/security/manager/ssl/nsILocalCertService.idl +++ b/security/manager/ssl/nsILocalCertService.idl @@ -11,9 +11,6 @@ interface nsILocalCertCallback; [scriptable, uuid(9702fdd4-4c2c-439c-ba2e-19cda018eb99)] interface nsILocalCertService : nsISupports { - const unsigned long KEY_TYPE_EC = 0; - const unsigned long KEY_TYPE_RSA = 1; - /** * Get or create a new self-signed X.509 cert to represent this device over a * secure transport, like TLS. @@ -24,11 +21,8 @@ interface nsILocalCertService : nsISupports * * @param nickname Nickname that identifies the cert * @param cb Callback to be notified with the result - * @param keyType A KEY_TYPE_* constant that specifies the key type. - * KEY_TYPE_EC if absent. */ - void getOrCreateCert(in ACString nickname, in nsILocalCertGetCallback cb, - [optional] in unsigned long keyType); + void getOrCreateCert(in ACString nickname, in nsILocalCertGetCallback cb); /** * Remove a X.509 cert with the given nickname. diff --git a/security/manager/ssl/nsNSSComponent.cpp b/security/manager/ssl/nsNSSComponent.cpp index d6e437736454..f4193e62638f 100644 --- a/security/manager/ssl/nsNSSComponent.cpp +++ b/security/manager/ssl/nsNSSComponent.cpp @@ -1249,7 +1249,7 @@ typedef struct { const char* pref; long id; bool enabledByDefault; - bool fallback; + bool weak; } CipherPref; // Update the switch statement in AccumulateCipherSuite in nsNSSCallbacks.cpp @@ -1281,10 +1281,10 @@ static const CipherPref sCipherPrefs[] = { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, true }, { "security.ssl3.dhe_rsa_aes_128_sha", - TLS_DHE_RSA_WITH_AES_128_CBC_SHA, true, true }, + TLS_DHE_RSA_WITH_AES_128_CBC_SHA, true }, { "security.ssl3.dhe_rsa_aes_256_sha", - TLS_DHE_RSA_WITH_AES_256_CBC_SHA, true, true }, + TLS_DHE_RSA_WITH_AES_256_CBC_SHA, true }, { "security.ssl3.ecdhe_psk_aes_128_gcm_sha256", TLS_ECDHE_PSK_WITH_AES_128_GCM_SHA256, true }, @@ -1305,26 +1305,26 @@ static const CipherPref sCipherPrefs[] = { { nullptr, 0 } // end marker }; -// Bit flags indicating what fallback ciphers are enabled. +// Bit flags indicating what weak ciphers are enabled. // The bit index will correspond to the index in sCipherPrefs. // Wrtten by the main thread, read from any threads. -static Atomic sEnabledFallbackCiphers; +static Atomic sEnabledWeakCiphers; static_assert(MOZ_ARRAY_LENGTH(sCipherPrefs) - 1 <= sizeof(uint32_t) * CHAR_BIT, "too many cipher suites"); /*static*/ bool -nsNSSComponent::AreAnyFallbackCiphersEnabled() +nsNSSComponent::AreAnyWeakCiphersEnabled() { - return !!sEnabledFallbackCiphers; + return !!sEnabledWeakCiphers; } /*static*/ void -nsNSSComponent::UseFallbackCiphersOnSocket(PRFileDesc* fd) +nsNSSComponent::UseWeakCiphersOnSocket(PRFileDesc* fd) { - const uint32_t enabledFallbackCiphers = sEnabledFallbackCiphers; + const uint32_t enabledWeakCiphers = sEnabledWeakCiphers; const CipherPref* const cp = sCipherPrefs; for (size_t i = 0; cp[i].pref; ++i) { - if (enabledFallbackCiphers & ((uint32_t)1 << i)) { + if (enabledWeakCiphers & ((uint32_t)1 << i)) { SSL_CipherPrefSet(fd, cp[i].id, true); } } @@ -1437,18 +1437,18 @@ CipherSuiteChangeObserver::Observe(nsISupports* aSubject, if (prefName.Equals(cp[i].pref)) { bool cipherEnabled = Preferences::GetBool(cp[i].pref, cp[i].enabledByDefault); - if (cp[i].fallback) { - // Fallback ciphers will not be used by default even if they + if (cp[i].weak) { + // Weak ciphers will not be used by default even if they // are enabled in prefs. They are only used on specific // sockets as a part of a fallback mechanism. - // Only the main thread will change sEnabledFallbackCiphers. - uint32_t enabledFallbackCiphers = sEnabledFallbackCiphers; + // Only the main thread will change sEnabledWeakCiphers. + uint32_t enabledWeakCiphers = sEnabledWeakCiphers; if (cipherEnabled) { - enabledFallbackCiphers |= ((uint32_t)1 << i); + enabledWeakCiphers |= ((uint32_t)1 << i); } else { - enabledFallbackCiphers &= ~((uint32_t)1 << i); + enabledWeakCiphers &= ~((uint32_t)1 << i); } - sEnabledFallbackCiphers = enabledFallbackCiphers; + sEnabledWeakCiphers = enabledWeakCiphers; } else { SSL_CipherPrefSetDefault(cp[i].id, cipherEnabled); SSL_ClearSessionCache(); @@ -2292,22 +2292,22 @@ InitializeCipherSuite() } // Now only set SSL/TLS ciphers we knew about at compile time - uint32_t enabledFallbackCiphers = 0; + uint32_t enabledWeakCiphers = 0; const CipherPref* const cp = sCipherPrefs; for (size_t i = 0; cp[i].pref; ++i) { bool cipherEnabled = Preferences::GetBool(cp[i].pref, cp[i].enabledByDefault); - if (cp[i].fallback) { - // Fallback ciphers are not used by default. See the comment + if (cp[i].weak) { + // Weak ciphers are not used by default. See the comment // in CipherSuiteChangeObserver::Observe for details. if (cipherEnabled) { - enabledFallbackCiphers |= ((uint32_t)1 << i); + enabledWeakCiphers |= ((uint32_t)1 << i); } } else { SSL_CipherPrefSetDefault(cp[i].id, cipherEnabled); } } - sEnabledFallbackCiphers = enabledFallbackCiphers; + sEnabledWeakCiphers = enabledWeakCiphers; // Enable ciphers for PKCS#12 SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1); diff --git a/security/manager/ssl/nsNSSComponent.h b/security/manager/ssl/nsNSSComponent.h index a267211ac579..b9977bc33600 100644 --- a/security/manager/ssl/nsNSSComponent.h +++ b/security/manager/ssl/nsNSSComponent.h @@ -159,8 +159,8 @@ public: GetDefaultCertVerifier() override; // The following two methods are thread-safe. - static bool AreAnyFallbackCiphersEnabled(); - static void UseFallbackCiphersOnSocket(PRFileDesc* fd); + static bool AreAnyWeakCiphersEnabled(); + static void UseWeakCiphersOnSocket(PRFileDesc* fd); static void FillTLSVersionRange(SSLVersionRange& rangeOut, uint32_t minFromPrefs, diff --git a/security/manager/ssl/nsNSSIOLayer.cpp b/security/manager/ssl/nsNSSIOLayer.cpp index e1da9571b418..b936ec13b735 100644 --- a/security/manager/ssl/nsNSSIOLayer.cpp +++ b/security/manager/ssl/nsNSSIOLayer.cpp @@ -1051,12 +1051,25 @@ retryDueToTLSIntolerance(PRErrorCode err, nsNSSSocketInfo* socketInfo) return false; } + // Disallow PR_CONNECT_RESET_ERROR if fallback limit reached. + bool fallbackLimitReached = + helpers.fallbackLimitReached(socketInfo->GetHostName(), range.max); + if (err == PR_CONNECT_RESET_ERROR && fallbackLimitReached) { + return false; + } + if ((err == SSL_ERROR_NO_CYPHER_OVERLAP || err == PR_END_OF_FILE_ERROR || err == PR_CONNECT_RESET_ERROR) && - nsNSSComponent::AreAnyFallbackCiphersEnabled()) { - if (helpers.rememberStrongCiphersFailed(socketInfo->GetHostName(), - socketInfo->GetPort(), err)) { - return true; + nsNSSComponent::AreAnyWeakCiphersEnabled()) { + if (helpers.isInsecureFallbackSite(socketInfo->GetHostName()) || + helpers.mUnrestrictedRC4Fallback) { + if (helpers.rememberStrongCiphersFailed(socketInfo->GetHostName(), + socketInfo->GetPort(), err)) { + Telemetry::Accumulate(Telemetry::SSL_WEAK_CIPHERS_FALLBACK, + tlsIntoleranceTelemetryBucket(err)); + return true; + } + Telemetry::Accumulate(Telemetry::SSL_WEAK_CIPHERS_FALLBACK, 0); } } @@ -2400,7 +2413,7 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS, ("[%p] nsSSLIOLayerSetOptions: using TLS version range (0x%04x,0x%04x)%s\n", fd, static_cast(range.min), static_cast(range.max), - strongCiphersStatus == StrongCiphersFailed ? " with fallback ciphers" : "")); + strongCiphersStatus == StrongCiphersFailed ? " with weak ciphers" : "")); if (SSL_VersionRangeSet(fd, &range) != SECSuccess) { return NS_ERROR_FAILURE; @@ -2408,7 +2421,7 @@ nsSSLIOLayerSetOptions(PRFileDesc* fd, bool forSTARTTLS, infoObject->SetTLSVersionRange(range); if (strongCiphersStatus == StrongCiphersFailed) { - nsNSSComponent::UseFallbackCiphersOnSocket(fd); + nsNSSComponent::UseWeakCiphersOnSocket(fd); } // when adjustForTLSIntolerance tweaks the maximum version downward, diff --git a/security/manager/ssl/tests/unit/test_fallback_cipher.js b/security/manager/ssl/tests/unit/test_weak_crypto.js similarity index 55% rename from security/manager/ssl/tests/unit/test_fallback_cipher.js rename to security/manager/ssl/tests/unit/test_weak_crypto.js index f9c164e7f427..c1160ec3b0ab 100644 --- a/security/manager/ssl/tests/unit/test_fallback_cipher.js +++ b/security/manager/ssl/tests/unit/test_weak_crypto.js @@ -5,13 +5,10 @@ // Tests the weak crypto override -const TLS_DHE_RSA_WITH_AES_128_CBC_SHA = 0x0033; -const TLS_DHE_RSA_WITH_AES_256_CBC_SHA = 0x0039; - -const fallback_cipher_prefs = [ - "security.ssl3.dhe_rsa_aes_128_sha", - "security.ssl3.dhe_rsa_aes_256_sha" -]; +const TLS_RSA_WITH_RC4_128_MD5 = 0x0004; +const TLS_RSA_WITH_RC4_128_SHA = 0x0005; +const TLS_ECDHE_ECDSA_WITH_RC4_128_SHA = 0xC007; +const TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xC011; // Need profile dir to store the key / cert do_get_profile(); @@ -28,13 +25,9 @@ const socketTransportService = Cc["@mozilla.org/network/socket-transport-service;1"] .getService(Ci.nsISocketTransportService); -function getCert(keyType = Ci.nsILocalCertService.KEY_TYPE_EC) { +function getCert() { let deferred = Promise.defer(); - let nickname = "tls-test"; - if (keyType == Ci.nsILocalCertService.KEY_TYPE_RSA) { - nickname = "tls-test-rsa"; - } - certService.getOrCreateCert(nickname, { + certService.getOrCreateCert("tls-test", { handleCert: function(c, rv) { if (rv) { deferred.reject(rv); @@ -42,11 +35,11 @@ function getCert(keyType = Ci.nsILocalCertService.KEY_TYPE_EC) { } deferred.resolve(c); } - }, keyType); + }); return deferred.promise; } -function startServer(cert, fallbackOnly) { +function startServer(cert, rc4only) { let tlsServer = Cc["@mozilla.org/network/tls-server-socket;1"] .createInstance(Ci.nsITLSServerSocket); tlsServer.init(-1, true, -1); @@ -68,12 +61,12 @@ function startServer(cert, fallbackOnly) { equal(status.tlsVersionUsed, Ci.nsITLSClientStatus.TLS_VERSION_1_2, "Using TLS 1.2"); - let expectedCipher = fallbackOnly ? "TLS_DHE_RSA_WITH_AES_128_CBC_SHA" - : "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"; + let expectedCipher = rc4only ? "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA" + : "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"; equal(status.cipherName, expectedCipher, "Using expected cipher"); equal(status.keyLength, 128, "Using 128-bit key"); - equal(status.macLength, fallbackOnly ? 160 : 128, "Using MAC of expected length"); + equal(status.macLength, rc4only ? 160 : 128, "Using MAC of expected length"); input.asyncWait({ onInputStreamReady: function(input) { @@ -87,10 +80,12 @@ function startServer(cert, fallbackOnly) { tlsServer.setSessionCache(false); tlsServer.setSessionTickets(false); tlsServer.setRequestClientCertificate(Ci.nsITLSServerSocket.REQUEST_NEVER); - if (fallbackOnly) { + if (rc4only) { let cipherSuites = [ - TLS_DHE_RSA_WITH_AES_128_CBC_SHA, - TLS_DHE_RSA_WITH_AES_256_CBC_SHA + TLS_ECDHE_RSA_WITH_RC4_128_SHA, + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + TLS_RSA_WITH_RC4_128_SHA, + TLS_RSA_WITH_RC4_128_MD5 ]; tlsServer.setCipherSuites(cipherSuites, cipherSuites.length); } @@ -107,7 +102,7 @@ function storeCertOverride(port, cert) { overrideBits, true); } -function startClient(name, port, expectedResult, options = {}) { +function startClient(port, expectedResult, options = {}) { let transport = socketTransportService.createTransport(["ssl"], 1, "127.0.0.1", port, null); if (options.isPrivate) { @@ -129,8 +124,8 @@ function startClient(name, port, expectedResult, options = {}) { onInputStreamReady: function(input) { try { let data = NetUtil.readInputStreamToString(input, input.available()); - equal(Cr.NS_OK, expectedResult, name + ": Connection should succeed"); - equal(data, "HELLO", name + ": Echoed data received"); + equal(Cr.NS_OK, expectedResult, "Connection should succeed"); + equal(data, "HELLO", "Echoed data received"); } catch (e) { if (!((e.result == Cr.NS_ERROR_NET_RESET) && options.allowReset) && (e.result != expectedResult)) { @@ -154,14 +149,13 @@ function startClient(name, port, expectedResult, options = {}) { if (e.result != Cr.NS_OK) { ok((e.result === expectedResult) || (options.allowReset && (e.result === Cr.NS_ERROR_NET_RESET)), - name + ": Actual and expected connection result should match:" + - e.result + " === " + expectedResult); + "Actual and expected connection result should match"); output.close(); deferred.resolve(); return; } } - do_print(name + ": Output to server written"); + do_print("Output to server written"); input = transport.openInputStream(0, 0, 0); input.asyncWait(handler, 0, 0, Services.tm.currentThread); } catch (e) { @@ -189,57 +183,89 @@ add_task(function* () { ok(!!cert, "Got self-signed cert"); let port = startServer(cert, false); storeCertOverride(port, cert); - yield startClient("sanity check, public", port, Cr.NS_OK); - yield startClient("sanity check, private", port, Cr.NS_OK, {isPrivate: true}); + yield startClient(port, Cr.NS_OK); + yield startClient(port, Cr.NS_OK, {isPrivate: true}); }); add_task(function* () { - let cert = yield getCert(Ci.nsILocalCertService.KEY_TYPE_RSA); + let cert = yield getCert(); ok(!!cert, "Got self-signed cert"); let port = startServer(cert, true); storeCertOverride(port, cert); - - // disable fallback cipher suites - for (let pref of fallback_cipher_prefs) { - Services.prefs.setBoolPref(pref, false); - } - - yield startClient("server: fallback only, client: fallback disabled, public", - port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP)); - yield startClient("server: fallback only, client: fallback disabled, private", - port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP)); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), {isPrivate: true}); - // enable fallback cipher suites - for (let pref of fallback_cipher_prefs) { - Services.prefs.setBoolPref(pref, true); - } - + weakCryptoOverride.addWeakCryptoOverride("127.0.0.1", true); + // private browsing should not affect the permanent storage. + equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"), + ""); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP)); // The auto-retry on connection reset is implemented in our HTTP layer. // So we will see the crafted NS_ERROR_NET_RESET when we use // nsISocketTransport directly. - yield startClient("server: fallback only, client: fallback enabled, public", - port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), - {allowReset: true}); - // retry manually to simulate the HTTP layer - yield startClient("server: fallback only, client: fallback enabled retry, public", - port, Cr.NS_OK); - // make sure that we remember the TLS intolerance - yield startClient("server: fallback only, client: second try after fallback success, public", - port, Cr.NS_OK); - yield startClient("server: fallback only, client: fallback enabled, private", - port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), {isPrivate: true, allowReset: true}); - yield startClient("server: fallback only, client: fallback enabled retry, private", - port, Cr.NS_OK, {isPrivate: true}); - // make sure that we remember the TLS intolerance - yield startClient("server: fallback only, client: second try after fallback success, private", - port, Cr.NS_OK, {isPrivate: true}); + // retry manually to simulate the HTTP layer + yield startClient(port, Cr.NS_OK, {isPrivate: true}); + + weakCryptoOverride.removeWeakCryptoOverride("127.0.0.1", port, true); + equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"), + ""); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP)); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), + {isPrivate: true}); + + weakCryptoOverride.addWeakCryptoOverride("127.0.0.1", false, true); + // temporary override should not change the pref. + equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"), + ""); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), + {allowReset: true}); + yield startClient(port, Cr.NS_OK); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), + {isPrivate: true}); + + weakCryptoOverride.removeWeakCryptoOverride("127.0.0.1", port, false); + equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"), + ""); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP)); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), + {isPrivate: true}); + + weakCryptoOverride.addWeakCryptoOverride("127.0.0.1", false); + // permanent override should change the pref. + equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"), + "127.0.0.1"); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), + {allowReset: true}); + yield startClient(port, Cr.NS_OK); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), + {isPrivate: true}); + + weakCryptoOverride.removeWeakCryptoOverride("127.0.0.1", port, false); + equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"), + ""); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP)); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), + {isPrivate: true}); + + // add a host to the pref to prepare the next test + weakCryptoOverride.addWeakCryptoOverride("127.0.0.1", false); + yield startClient(port, getXPCOMStatusFromNSS(SSL_ERROR_NO_CYPHER_OVERLAP), + {allowReset: true}); + yield startClient(port, Cr.NS_OK); + equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"), + "127.0.0.1"); }); -do_register_cleanup(function() { - do_print("reset modified prefs"); - for (let pref of fallback_cipher_prefs) { - Services.prefs.clearUserPref(pref); - } +add_task(function* () { + let cert = yield getCert(); + ok(!!cert, "Got self-signed cert"); + let port = startServer(cert, false); + storeCertOverride(port, cert); + yield startClient(port, Cr.NS_OK); + // Successful strong cipher will remove the host from the pref. + equal(Services.prefs.getCharPref("security.tls.insecure_fallback_hosts"), + ""); }); diff --git a/security/manager/ssl/tests/unit/xpcshell.ini b/security/manager/ssl/tests/unit/xpcshell.ini index d0d5531b82ec..cb4b8d35946b 100644 --- a/security/manager/ssl/tests/unit/xpcshell.ini +++ b/security/manager/ssl/tests/unit/xpcshell.ini @@ -61,8 +61,6 @@ skip-if = toolkit == 'android' || buildapp == 'b2g' skip-if = os != 'win' # tests a Windows-specific feature [test_ev_certs.js] run-sequentially = hardcoded ports -[test_fallback_cipher.js] -firefox-appdir = browser [test_getchain.js] [test_hash_algorithms.js] [test_hash_algorithms_wrap.js] diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 4ae17d1723fb..34f06cb85e17 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -7538,6 +7538,13 @@ "n_values": 64, "description": "TLS/SSL version intolerance was falsely detected, server rejected handshake (see tlsIntoleranceTelemetryBucket() in nsNSSIOLayer.cpp)." }, + "SSL_WEAK_CIPHERS_FALLBACK": { + "alert_emails": ["seceng-telemetry@mozilla.com"], + "expires_in_version": "never", + "kind": "enumerated", + "n_values": 64, + "description": "Fallback attempted when server did not support any strong cipher suites" + }, "SSL_CIPHER_SUITE_FULL": { "alert_emails": ["seceng-telemetry@mozilla.com"], "expires_in_version": "never", diff --git a/toolkit/components/telemetry/histogram-whitelists.json b/toolkit/components/telemetry/histogram-whitelists.json index 8df1f6c42a43..4e922dfa0de3 100644 --- a/toolkit/components/telemetry/histogram-whitelists.json +++ b/toolkit/components/telemetry/histogram-whitelists.json @@ -898,6 +898,7 @@ "SSL_TLS12_INTOLERANCE_REASON_POST", "SSL_TLS12_INTOLERANCE_REASON_PRE", "SSL_VERSION_FALLBACK_INAPPROPRIATE", + "SSL_WEAK_CIPHERS_FALLBACK", "STARTUP_CACHE_AGE_HOURS", "STARTUP_CRASH_DETECTED", "STARTUP_MEASUREMENT_ERRORS", @@ -2081,6 +2082,7 @@ "SSL_TLS12_INTOLERANCE_REASON_POST", "SSL_TLS12_INTOLERANCE_REASON_PRE", "SSL_VERSION_FALLBACK_INAPPROPRIATE", + "SSL_WEAK_CIPHERS_FALLBACK", "STARTUP_CACHE_AGE_HOURS", "STARTUP_CACHE_INVALID", "STARTUP_CRASH_DETECTED", From c3a5940060c743197756f7add3d8de175b1d77a7 Mon Sep 17 00:00:00 2001 From: Terrence Cole Date: Fri, 22 Jul 2016 10:50:26 -0700 Subject: [PATCH 048/135] No Bug - Fix up some function names that appear in comments; r=meow --HG-- extra : rebase_source : c71365b5b3aeb504318ad4720e76b3d0b75b50b9 --- js/public/Class.h | 4 ++-- js/src/jsapi.h | 2 +- js/src/jspubtd.h | 4 ++-- js/src/tests/js1_7/extensions/regress-387955-01.js | 2 +- js/src/tests/js1_7/extensions/regress-387955-02.js | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/js/public/Class.h b/js/public/Class.h index 66b69d947cfe..38a98194afdf 100644 --- a/js/public/Class.h +++ b/js/public/Class.h @@ -381,8 +381,8 @@ typedef bool /** * Function type for trace operation of the class called to enumerate all * traceable things reachable from obj's private data structure. For each such - * thing, a trace implementation must call one of the JS_Call*Tracer variants - * on the thing. + * thing, a trace implementation must call JS::TraceEdge on the thing's + * location. * * JSTraceOp implementation can assume that no other threads mutates object * state. It must not change state of the object or corresponding native diff --git a/js/src/jsapi.h b/js/src/jsapi.h index 6f39b0727fb9..71eef7591fcc 100644 --- a/js/src/jsapi.h +++ b/js/src/jsapi.h @@ -1592,7 +1592,7 @@ JS_strdup(JSRuntime* rt, const char* s); * Register externally maintained GC roots. * * traceOp: the trace operation. For each root the implementation should call - * JS_CallTracer whenever the root contains a traceable thing. + * JS::TraceEdge whenever the root contains a traceable thing. * data: the data argument to pass to each invocation of traceOp. */ extern JS_PUBLIC_API(bool) diff --git a/js/src/jspubtd.h b/js/src/jspubtd.h index 30594592843a..e01307b62cd3 100644 --- a/js/src/jspubtd.h +++ b/js/src/jspubtd.h @@ -118,8 +118,8 @@ typedef JSConstScalarSpec JSConstDoubleSpec; typedef JSConstScalarSpec JSConstIntegerSpec; /* - * Generic trace operation that calls JS_CallTracer on each traceable thing - * stored in data. + * Generic trace operation that calls JS::TraceEdge on each traceable thing's + * location reachable from data. */ typedef void (* JSTraceDataOp)(JSTracer* trc, void* data); diff --git a/js/src/tests/js1_7/extensions/regress-387955-01.js b/js/src/tests/js1_7/extensions/regress-387955-01.js index a93243f47ea7..e3af18401a60 100644 --- a/js/src/tests/js1_7/extensions/regress-387955-01.js +++ b/js/src/tests/js1_7/extensions/regress-387955-01.js @@ -6,7 +6,7 @@ //----------------------------------------------------------------------------- var BUGNUMBER = 387955; -var summary = 'Do not Crash [@ JS_CallTracer]'; +var summary = 'Do not Crash [@ TraceEdge]'; var actual = 'No Crash'; var expect = 'No Crash'; diff --git a/js/src/tests/js1_7/extensions/regress-387955-02.js b/js/src/tests/js1_7/extensions/regress-387955-02.js index 19508c8b43f7..dc3b795b687e 100644 --- a/js/src/tests/js1_7/extensions/regress-387955-02.js +++ b/js/src/tests/js1_7/extensions/regress-387955-02.js @@ -6,7 +6,7 @@ //----------------------------------------------------------------------------- var BUGNUMBER = 387955; -var summary = 'Do not Crash [@ JS_CallTracer]'; +var summary = 'Do not Crash [@ TraceEdge]'; var actual = 'No Crash'; var expect = 'No Crash'; From 9c4601840197c2719a7cbf196dd667ca482657a0 Mon Sep 17 00:00:00 2001 From: Wes Kocher Date: Fri, 22 Jul 2016 11:14:13 -0700 Subject: [PATCH 049/135] Backed out 5 changesets (bug 1287091) for build bustage after assertions in SharedIC.h CLOSED TREE Backed out changeset c57fd3af416e (bug 1287091) Backed out changeset edad0174cb12 (bug 1287091) Backed out changeset 7ed07b35bad6 (bug 1287091) Backed out changeset 939d5064ab91 (bug 1287091) Backed out changeset acbca9af0a3b (bug 1287091) --- browser/base/content/browser.js | 3 +- browser/base/content/nsContextMenu.js | 3 +- browser/base/content/utilityOverlay.js | 12 +- .../customizableui/CustomizableWidgets.jsm | 5 +- .../ContextualIdentityService.jsm | 236 ++---------------- .../components/contextualidentity/moz.build | 2 - .../tests/unit/test_basic.js | 67 ----- .../tests/unit/xpcshell.ini | 3 - 8 files changed, 36 insertions(+), 295 deletions(-) delete mode 100644 toolkit/components/contextualidentity/tests/unit/test_basic.js delete mode 100644 toolkit/components/contextualidentity/tests/unit/xpcshell.ini diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index fc58acb41e35..511178b5e7de 100755 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -8,7 +8,6 @@ var Cu = Components.utils; var Cc = Components.classes; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/ContextualIdentityService.jsm"); Cu.import("resource://gre/modules/NotificationDB.jsm"); Cu.import("resource:///modules/RecentWindow.jsm"); @@ -57,6 +56,8 @@ XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils", "@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils"); XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager", "resource://gre/modules/LightweightThemeManager.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", + "resource://gre/modules/ContextualIdentityService.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "gAboutNewTabService", "@mozilla.org/browser/aboutnewtab-service;1", "nsIAboutNewTabService"); diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 263b13737dcb..124847b00beb 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -4,7 +4,6 @@ # 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/. -Components.utils.import("resource://gre/modules/ContextualIdentityService.jsm"); Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm"); Components.utils.import("resource://gre/modules/LoginManagerContextMenu.jsm"); @@ -12,6 +11,8 @@ Components.utils.import("resource://gre/modules/BrowserUtils.jsm"); Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", + "resource://gre/modules/ContextualIdentityService.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper", "resource://gre/modules/LoginHelper.jsm"); diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index e59fa56cb89d..dbddd6de62a3 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -5,7 +5,6 @@ // Services = object with smart getters for common XPCOM services Components.utils.import("resource://gre/modules/AppConstants.jsm"); -Components.utils.import("resource://gre/modules/ContextualIdentityService.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); @@ -14,6 +13,9 @@ Components.utils.import("resource:///modules/RecentWindow.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ShellService", "resource:///modules/ShellService.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", + "resource://gre/modules/ContextualIdentityService.jsm"); + XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService", "@mozilla.org/browser/aboutnewtab-service;1", "nsIAboutNewTabService"); @@ -445,12 +447,8 @@ function createUserContextMenu(event, addCommandAttribute = true, excludeUserCon let menuitem = document.createElement("menuitem"); menuitem.setAttribute("usercontextid", identity.userContextId); - menuitem.setAttribute("label", ContextualIdentityService.getUserContextLabel(identity.userContextId)); - - if (identity.accessKey) { - menuitem.setAttribute("accesskey", bundle.getString(identity.accessKey)); - } - + menuitem.setAttribute("label", bundle.getString(identity.label)); + menuitem.setAttribute("accesskey", bundle.getString(identity.accessKey)); menuitem.classList.add("menuitem-iconic"); if (addCommandAttribute) { diff --git a/browser/components/customizableui/CustomizableWidgets.jsm b/browser/components/customizableui/CustomizableWidgets.jsm index b26aa9c8336e..307309ee7115 100644 --- a/browser/components/customizableui/CustomizableWidgets.jsm +++ b/browser/components/customizableui/CustomizableWidgets.jsm @@ -11,7 +11,6 @@ Cu.import("resource:///modules/CustomizableUI.jsm"); Cu.import("resource://gre/modules/Services.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); Cu.import("resource://gre/modules/AppConstants.jsm"); -Cu.import("resource://gre/modules/ContextualIdentityService.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "BrowserUITelemetry", "resource:///modules/BrowserUITelemetry.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils", @@ -28,6 +27,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "PrivateBrowsingUtils", "resource://gre/modules/PrivateBrowsingUtils.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "SyncedTabs", "resource://services-sync/SyncedTabs.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", + "resource://gre/modules/ContextualIdentityService.jsm"); XPCOMUtils.defineLazyGetter(this, "CharsetBundle", function() { const kCharsetBundle = "chrome://global/locale/charsetMenu.properties"; @@ -1134,7 +1135,7 @@ const CustomizableWidgets = [ ContextualIdentityService.getIdentities().forEach(identity => { let bundle = doc.getElementById("bundle_browser"); - let label = ContextualIdentityService.getUserContextLabel(identity.userContextId); + let label = bundle.getString(identity.label); let item = doc.createElementNS(kNSXUL, "toolbarbutton"); item.setAttribute("label", label); diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm index 5a60ef413b40..31a4aabea8c5 100644 --- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm +++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm @@ -7,246 +7,71 @@ this.EXPORTED_SYMBOLS = ["ContextualIdentityService"]; const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm"); +Cu.import("resource://gre/modules/Services.jsm") -const DEFAULT_TAB_COLOR = "#909090"; -const SAVE_DELAY_MS = 1500; +const DEFAULT_TAB_COLOR = "#909090" XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() { return Services.strings.createBundle("chrome://browser/locale/browser.properties"); }); -XPCOMUtils.defineLazyGetter(this, "gTextDecoder", function () { - return new TextDecoder(); -}); - -XPCOMUtils.defineLazyGetter(this, "gTextEncoder", function () { - return new TextEncoder(); -}); - -XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown", - "resource://gre/modules/AsyncShutdown.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "OS", - "resource://gre/modules/osfile.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask", - "resource://gre/modules/DeferredTask.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", - "resource://gre/modules/FileUtils.jsm"); - -function _ContextualIdentityService(path) { - this.init(path); -} - -_ContextualIdentityService.prototype = { - _defaultIdentities: [ +this.ContextualIdentityService = { + _identities: [ { userContextId: 1, public: true, icon: "chrome://browser/skin/usercontext/personal.svg", color: "#00a7e0", - l10nID: "userContextPersonal.label", + label: "userContextPersonal.label", accessKey: "userContextPersonal.accesskey", + alreadyOpened: false, telemetryId: 1, }, { userContextId: 2, public: true, icon: "chrome://browser/skin/usercontext/work.svg", color: "#f89c24", - l10nID: "userContextWork.label", + label: "userContextWork.label", accessKey: "userContextWork.accesskey", + alreadyOpened: false, telemetryId: 2, }, { userContextId: 3, public: true, icon: "chrome://browser/skin/usercontext/banking.svg", color: "#7dc14c", - l10nID: "userContextBanking.label", + label: "userContextBanking.label", accessKey: "userContextBanking.accesskey", + alreadyOpened: false, telemetryId: 3, }, { userContextId: 4, public: true, icon: "chrome://browser/skin/usercontext/shopping.svg", color: "#ee5195", - l10nID: "userContextShopping.label", + label: "userContextShopping.label", accessKey: "userContextShopping.accesskey", + alreadyOpened: false, telemetryId: 4, }, - { userContextId: 5, + { userContextId: Math.pow(2, 31) - 1, public: false, icon: "", color: "", - name: "userContextIdInternal.thumbnail", - accessKey: "" }, + label: "userContextIdInternal.thumbnail", + accessKey: "", + alreadyOpened: false }, ], - _identities: null, - _openedIdentities: new Set(), - _lastUserContextId: 0, - - _path: null, - _dataReady: false, - - _saver: null, - - init(path) { - this._path = path; - this._saver = new DeferredTask(() => this.save(), SAVE_DELAY_MS); - AsyncShutdown.profileBeforeChange.addBlocker("ContextualIdentityService: writing data", - () => this._saver.finalize()); - - this.load(); - }, - - load() { - OS.File.read(this._path).then(bytes => { - // If synchronous loading happened in the meantime, exit now. - if (this._dataReady) { - return; - } - - try { - let data = JSON.parse(gTextDecoder.decode(bytes)); - if (data.version != 1) { - dump("ERROR - ContextualIdentityService - Unknown version found in " + this._path + "\n"); - this.loadError(null); - return; - } - - this._identities = data.identities; - this._lastUserContextId = data.lastUserContextId; - - this._dataReady = true; - } catch(error) { - this.loadError(error); - } - }, (error) => { - this.loadError(error); - }); - }, - - loadError(error) { - if (error != null && - !(error instanceof OS.File.Error && error.becauseNoSuchFile) && - !(error instanceof Components.Exception && - error.result == Cr.NS_ERROR_FILE_NOT_FOUND)) { - // Let's report the error. - Cu.reportError(error); - } - - // If synchronous loading happened in the meantime, exit now. - if (this._dataReady) { - return; - } - - this._identities = this._defaultIdentities; - this._lastUserContextId = this._defaultIdentities.length; - - this._dataReady = true; - - this.saveSoon(); - }, - - saveSoon() { - this._saver.arm(); - }, - - save() { - let object = { - version: 1, - lastUserContextId: this._lastUserContextId, - identities: this._identities - }; - - let bytes = gTextEncoder.encode(JSON.stringify(object)); - return OS.File.writeAtomic(this._path, bytes, - { tmpPath: this._path + ".tmp" }); - }, - - create(name, icon, color) { - let identity = { - userContextId: ++this._lastUserContextId, - public: true, - icon, - color, - name - }; - - this._identities.push(identity); - this.saveSoon(); - - return Cu.cloneInto(identity, {}); - }, - - update(userContextId, name, icon, color) { - let identity = this._identities.find(identity => identity.userContextId == userContextId && - identity.public); - if (identity) { - identity.name = name; - identity.color = color; - identity.icon = icon; - delete identity.l10nID; - delete identity.accessKey; - this.saveSoon(); - } - - return !!identity; - }, - - remove(userContextId) { - let index = this._identities.findIndex(i => i.userContextId == userContextId && i.public); - if (index == -1) { - return false; - } - - Services.obs.notifyObservers(null, "clear-origin-data", - JSON.stringify({ userContextId })); - - this._identities.splice(index, 1); - this._openedIdentities.delete(userContextId); - this.saveSoon(); - - return true; - }, - - ensureDataReady() { - if (this._dataReady) { - return; - } - - try { - // This reads the file and automatically detects the UTF-8 encoding. - let inputStream = Cc["@mozilla.org/network/file-input-stream;1"] - .createInstance(Ci.nsIFileInputStream); - inputStream.init(new FileUtils.File(this._path), - FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0); - try { - let json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON); - this._identities = json.decodeFromStream(inputStream, - inputStream.available()); - this._dataReady = true; - } finally { - inputStream.close(); - } - } catch (error) { - this.loadError(error); - return; - } - }, - getIdentities() { - this.ensureDataReady(); - return Cu.cloneInto(this._identities.filter(info => info.public), {}); + return this._identities.filter(info => info.public); }, - getPrivateIdentity(name) { - this.ensureDataReady(); - return Cu.cloneInto(this._identities.find(info => !info.public && info.name == name), {}); + getPrivateIdentity(label) { + return this._identities.find(info => !info.public && info.label == label); }, getIdentityFromId(userContextId) { - this.ensureDataReady(); - return Cu.cloneInto(this._identities.find(info => info.userContextId == userContextId && - info.public), {}); + return this._identities.find(info => info.userContextId == userContextId); }, getUserContextLabel(userContextId) { @@ -254,13 +79,7 @@ _ContextualIdentityService.prototype = { if (!identity.public) { return ""; } - - // We cannot localize the user-created identity names. - if (identity.name) { - return identity.name; - } - - return gBrowserBundle.GetStringFromName(identity.l10nID); + return gBrowserBundle.GetStringFromName(identity.label); }, setTabStyle(tab) { @@ -290,8 +109,8 @@ _ContextualIdentityService.prototype = { return; } - if (this._openedIdentities.has(userContextId)) { - this._openedIdentities.add(userContextId); + if (!identity.alreadyOpened) { + identity.alreadyOpened = true; Services.telemetry.getHistogramById("UNIQUE_CONTAINERS_OPENED").add(1); } @@ -302,11 +121,4 @@ _ContextualIdentityService.prototype = { .add(identity.telemetryId); } }, - - createNewInstanceForTesting(path) { - return new _ContextualIdentityService(path); - }, -}; - -let path = OS.Path.join(OS.Constants.Path.profileDir, "containers.json"); -this.ContextualIdentityService = new _ContextualIdentityService(path); +} diff --git a/toolkit/components/contextualidentity/moz.build b/toolkit/components/contextualidentity/moz.build index 9188421f9ec1..680c7bd0ea44 100644 --- a/toolkit/components/contextualidentity/moz.build +++ b/toolkit/components/contextualidentity/moz.build @@ -7,5 +7,3 @@ EXTRA_JS_MODULES += [ 'ContextualIdentityService.jsm', ] - -XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] diff --git a/toolkit/components/contextualidentity/tests/unit/test_basic.js b/toolkit/components/contextualidentity/tests/unit/test_basic.js deleted file mode 100644 index 4d17b9a267cc..000000000000 --- a/toolkit/components/contextualidentity/tests/unit/test_basic.js +++ /dev/null @@ -1,67 +0,0 @@ -"use strict"; - -do_get_profile(); - -const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; - -Cu.import("resource://gre/modules/ContextualIdentityService.jsm"); - -const TEST_STORE_FILE_NAME = "test-containers.json"; - -let cis; - -// Basic tests -add_task(function() { - ok(!!ContextualIdentityService, "ContextualIdentityService exists"); - - cis = ContextualIdentityService.createNewInstanceForTesting(TEST_STORE_FILE_NAME); - ok(!!cis, "We have our instance of ContextualIdentityService"); - - equal(cis.getIdentities().length, 4, "By default, 4 containers."); - equal(cis.getIdentityFromId(0), null, "No identity with id 0"); - - ok(!!cis.getIdentityFromId(1), "Identity 1 exists"); - ok(!!cis.getIdentityFromId(2), "Identity 2 exists"); - ok(!!cis.getIdentityFromId(3), "Identity 3 exists"); - ok(!!cis.getIdentityFromId(4), "Identity 4 exists"); -}); - -// Create a new identity -add_task(function() { - equal(cis.getIdentities().length, 4, "By default, 4 containers."); - - let identity = cis.create("New Container", "Icon", "Color"); - ok(!!identity, "New container created"); - equal(identity.name, "New Container", "Name matches"); - equal(identity.icon, "Icon", "Icon matches"); - equal(identity.color, "Color", "Color matches"); - - equal(cis.getIdentities().length, 5, "Expected 5 containers."); - - ok(!!cis.getIdentityFromId(identity.userContextId), "Identity exists"); - equal(cis.getIdentityFromId(identity.userContextId).name, "New Container", "Identity name is OK"); - equal(cis.getIdentityFromId(identity.userContextId).icon, "Icon", "Identity icon is OK"); - equal(cis.getIdentityFromId(identity.userContextId).color, "Color", "Identity color is OK"); - equal(cis.getUserContextLabel(identity.userContextId), "New Container", "Identity label is OK"); - - // Remove an identity - equal(cis.remove(-1), false, "cis.remove() returns false if identity doesn't exist."); - equal(cis.remove(1), true, "cis.remove() returns true if identity exists."); - - equal(cis.getIdentities().length, 4, "Expected 4 containers."); -}); - -// Update an identity -add_task(function() { - ok(!!cis.getIdentityFromId(2), "Identity 2 exists"); - - equal(cis.update(-1, "Container", "Icon", "Color"), false, "Update returns false if the identity doesn't exist"); - - equal(cis.update(2, "Container", "Icon", "Color"), true, "Update returns true if everything is OK"); - - ok(!!cis.getIdentityFromId(2), "Identity exists"); - equal(cis.getIdentityFromId(2).name, "Container", "Identity name is OK"); - equal(cis.getIdentityFromId(2).icon, "Icon", "Identity icon is OK"); - equal(cis.getIdentityFromId(2).color, "Color", "Identity color is OK"); - equal(cis.getUserContextLabel(2), "Container", "Identity label is OK"); -}); diff --git a/toolkit/components/contextualidentity/tests/unit/xpcshell.ini b/toolkit/components/contextualidentity/tests/unit/xpcshell.ini deleted file mode 100644 index b45ff2c30f29..000000000000 --- a/toolkit/components/contextualidentity/tests/unit/xpcshell.ini +++ /dev/null @@ -1,3 +0,0 @@ -[DEFAULT] - -[test_basic.js] From be23815df35bdf4faeda5afe61dadc743c8ecadd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Thau=C3=A3=20Silveira?= Date: Thu, 21 Jul 2016 13:57:00 -0400 Subject: [PATCH 050/135] Bug 1287587 - Add Telemetry probes for user printing activities. r=mconley, data-review=liuche --- .../components/printing/content/printUtils.js | 6 ++++-- toolkit/components/telemetry/Histograms.json | 17 +++++++++++++++++ toolkit/content/browser-content.js | 11 +++++++++++ 3 files changed, 32 insertions(+), 2 deletions(-) diff --git a/toolkit/components/printing/content/printUtils.js b/toolkit/components/printing/content/printUtils.js index d9635244ca9e..74e020845e19 100644 --- a/toolkit/components/printing/content/printUtils.js +++ b/toolkit/components/printing/content/printUtils.js @@ -588,10 +588,12 @@ var PrintUtils = { printPreviewTB.initialize(ppBrowser); // Enable simplify page checkbox when the page is an article - if (this._sourceBrowser.isArticle) + if (this._sourceBrowser.isArticle) { printPreviewTB.enableSimplifyPage(); - else + } else { + this.logTelemetry("PRINT_PREVIEW_SIMPLIFY_PAGE_UNAVAILABLE_COUNT"); printPreviewTB.disableSimplifyPage(); + } // copy the window close handler if (document.documentElement.hasAttribute("onclose")) diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 34f06cb85e17..59b0c454341d 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -5683,6 +5683,23 @@ "releaseChannelCollection": "opt-out", "description": "A counter incremented every time the browser enters simplified mode on print preview." }, + "PRINT_PREVIEW_SIMPLIFY_PAGE_UNAVAILABLE_COUNT": { + "alert_emails": ["carnold@mozilla.org"], + "bug_numbers": [1287587], + "expires_in_version": "56", + "kind": "count", + "releaseChannelCollection": "opt-out", + "description": "A counter incremented every time the simplified mode is unavailable on print preview." + }, + "PRINT_COUNT": { + "alert_emails": ["carnold@mozilla.org"], + "bug_numbers": [1287587], + "expires_in_version": "56", + "kind": "count", + "keyed": true, + "releaseChannelCollection": "opt-out", + "description": "A counter incremented every time the user prints a document." + }, "DEVTOOLS_DEBUGGER_DISPLAY_SOURCE_LOCAL_MS": { "expires_in_version": "never", "kind": "exponential", diff --git a/toolkit/content/browser-content.js b/toolkit/content/browser-content.js index 55cbd67efa52..eedb2ccd94f9 100644 --- a/toolkit/content/browser-content.js +++ b/toolkit/content/browser-content.js @@ -646,6 +646,17 @@ var Printing = { let print = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor) .getInterface(Ci.nsIWebBrowserPrint); print.print(printSettings, null); + + let histogram = Services.telemetry.getKeyedHistogramById("PRINT_COUNT"); + if (print.doingPrintPreview) { + if (simplifiedMode) { + histogram.add("SIMPLIFIED"); + } else { + histogram.add("WITH_PREVIEW"); + } + } else { + histogram.add("WITHOUT_PREVIEW"); + } } catch(e) { // Pressing cancel is expressed as an NS_ERROR_ABORT return value, // causing an exception to be thrown which we catch here. From 2ce5c03b9b0ec98b142753a49f2db1983c493141 Mon Sep 17 00:00:00 2001 From: dimi Date: Thu, 21 Jul 2016 15:35:36 +0800 Subject: [PATCH 051/135] Bug 1272239 - Part 1: Support completion for test database. r=francois MozReview-Commit-ID: 85BALQHKSal --- toolkit/components/url-classifier/SafeBrowsing.jsm | 3 --- toolkit/components/url-classifier/nsUrlClassifierDBService.cpp | 3 --- 2 files changed, 6 deletions(-) diff --git a/toolkit/components/url-classifier/SafeBrowsing.jsm b/toolkit/components/url-classifier/SafeBrowsing.jsm index 0bfa122301fa..4384335ccab5 100644 --- a/toolkit/components/url-classifier/SafeBrowsing.jsm +++ b/toolkit/components/url-classifier/SafeBrowsing.jsm @@ -27,8 +27,6 @@ function log(...stuff) { dump(Services.urlFormatter.trimSensitiveURLs(msg) + "\n"); } -// Skip all the ones containining "test", because we never need to ask for -// updates for them. function getLists(prefName) { log("getLists: " + prefName); let pref = null; @@ -42,7 +40,6 @@ function getLists(prefName) { return []; } return pref.split(",") - .filter(function(value) { return value.indexOf("test-") == -1; }) .map(function(value) { return value.trim(); }); } diff --git a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp index 285929b3150d..270f81e32267 100644 --- a/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp +++ b/toolkit/components/url-classifier/nsUrlClassifierDBService.cpp @@ -1601,9 +1601,6 @@ nsUrlClassifierDBService::GetCompleter(const nsACString &tableName, return false; } - MOZ_ASSERT(!StringBeginsWith(tableName, NS_LITERAL_CSTRING("test-")), - "We should never fetch hash completions for test tables"); - // Otherwise, call gethash to find the hash completions. return NS_SUCCEEDED(CallGetService(NS_URLCLASSIFIERHASHCOMPLETER_CONTRACTID, completer)); From 4135954a00e772634c99c4dca6bcf5a8898aab17 Mon Sep 17 00:00:00 2001 From: dimi Date: Thu, 21 Jul 2016 15:37:00 +0800 Subject: [PATCH 052/135] Bug 1272239 - Part 2: Testcase, only tables with provider could register gethash url in listmanager. r=francois MozReview-Commit-ID: FcnXswQyerb --- .../url-classifier/tests/mochitest/chrome.ini | 1 + .../test_safebrowsing_bug1272239.html | 87 +++++++++++++++++++ 2 files changed, 88 insertions(+) create mode 100644 toolkit/components/url-classifier/tests/mochitest/test_safebrowsing_bug1272239.html diff --git a/toolkit/components/url-classifier/tests/mochitest/chrome.ini b/toolkit/components/url-classifier/tests/mochitest/chrome.ini index 0b01d1766f0e..0e5bbb7bf06c 100644 --- a/toolkit/components/url-classifier/tests/mochitest/chrome.ini +++ b/toolkit/components/url-classifier/tests/mochitest/chrome.ini @@ -18,5 +18,6 @@ tags = trackingprotection tags = trackingprotection [test_trackingprotection_whitelist.html] tags = trackingprotection +[test_safebrowsing_bug1272239.html] [test_donottrack.html] [test_classifier_changetablepref.html] diff --git a/toolkit/components/url-classifier/tests/mochitest/test_safebrowsing_bug1272239.html b/toolkit/components/url-classifier/tests/mochitest/test_safebrowsing_bug1272239.html new file mode 100644 index 000000000000..8066c2a37214 --- /dev/null +++ b/toolkit/components/url-classifier/tests/mochitest/test_safebrowsing_bug1272239.html @@ -0,0 +1,87 @@ + + + + Bug 1272239 - Only tables with provider could register gethash url in listmanager. + + + + + +

+ +
+
+
+
+ + From 4f45ea248fc484e02d7ab9d6627bcc879fce49bd Mon Sep 17 00:00:00 2001 From: dimi Date: Thu, 21 Jul 2016 15:40:03 +0800 Subject: [PATCH 053/135] Bug 1272239 - Part 3: Testcase, test gethash. r=francois MozReview-Commit-ID: 3IkrdJgZNP1 --- .../url-classifier/tests/mochitest/bad.css | 1 + .../tests/mochitest/classifierFrame.html | 11 +- .../tests/mochitest/classifierHelper.js | 34 ++++ .../tests/mochitest/gethash.sjs | 119 ++++++++++++++ .../tests/mochitest/gethashFrame.html | 62 ++++++++ .../url-classifier/tests/mochitest/import.css | 6 +- .../tests/mochitest/mochitest.ini | 4 + .../tests/mochitest/test_gethash.html | 150 ++++++++++++++++++ 8 files changed, 383 insertions(+), 4 deletions(-) create mode 100644 toolkit/components/url-classifier/tests/mochitest/bad.css create mode 100644 toolkit/components/url-classifier/tests/mochitest/gethash.sjs create mode 100644 toolkit/components/url-classifier/tests/mochitest/gethashFrame.html create mode 100644 toolkit/components/url-classifier/tests/mochitest/test_gethash.html diff --git a/toolkit/components/url-classifier/tests/mochitest/bad.css b/toolkit/components/url-classifier/tests/mochitest/bad.css new file mode 100644 index 000000000000..f57b36a77845 --- /dev/null +++ b/toolkit/components/url-classifier/tests/mochitest/bad.css @@ -0,0 +1 @@ +#styleBad { visibility: hidden; } diff --git a/toolkit/components/url-classifier/tests/mochitest/classifierFrame.html b/toolkit/components/url-classifier/tests/mochitest/classifierFrame.html index 1cd520284779..c7923f448411 100644 --- a/toolkit/components/url-classifier/tests/mochitest/classifierFrame.html +++ b/toolkit/components/url-classifier/tests/mochitest/classifierFrame.html @@ -15,6 +15,14 @@ function checkLoads() { var style = document.defaultView.getComputedStyle(elt, ""); window.parent.isnot(style.visibility, "hidden", "Should not load bad css"); + elt = document.getElementById("styleBad"); + style = document.defaultView.getComputedStyle(elt, ""); + window.parent.isnot(style.visibility, "hidden", "Should not load bad css"); + + elt = document.getElementById("styleImport"); + style = document.defaultView.getComputedStyle(elt, ""); + window.parent.isnot(style.visibility, "visible", "Should import clean css"); + // Call parent.loadTestFrame again to test classification metadata in HTTP // cache entries. if (window.parent.firstLoad) { @@ -36,7 +44,6 @@ function checkLoads() { - @@ -44,5 +51,7 @@ function checkLoads() { The following should not be hidden:
STYLE TEST
+
STYLE BAD
+
STYLE IMPORT
diff --git a/toolkit/components/url-classifier/tests/mochitest/classifierHelper.js b/toolkit/components/url-classifier/tests/mochitest/classifierHelper.js index fe025fb4114b..b70539838802 100644 --- a/toolkit/components/url-classifier/tests/mochitest/classifierHelper.js +++ b/toolkit/components/url-classifier/tests/mochitest/classifierHelper.js @@ -9,6 +9,12 @@ const ADD_CHUNKNUM = 524; const SUB_CHUNKNUM = 523; const HASHLEN = 32; +const PREFS = { + PROVIDER_LISTS : "browser.safebrowsing.provider.mozilla.lists", + DISALLOW_COMPLETIONS : "urlclassifier.disallow_completions", + PROVIDER_GETHASHURL : "browser.safebrowsing.provider.mozilla.gethashURL" +}; + // addUrlToDB & removeUrlFromDB are asynchronous, queue the task to ensure // the callback follow correct order. classifierHelper._updates = []; @@ -17,6 +23,27 @@ classifierHelper._updates = []; // removed after test complete. classifierHelper._updatesToCleanup = []; +// This function is used to allow completion for specific "list", +// some lists like "test-malware-simple" is default disabled to ask for complete. +// "list" is the db we would like to allow it +// "url" is the completion server +classifierHelper.allowCompletion = function(lists, url) { + for (var list of lists) { + // Add test db to provider + var pref = SpecialPowers.getCharPref(PREFS.PROVIDER_LISTS); + pref += "," + list; + SpecialPowers.setCharPref(PREFS.PROVIDER_LISTS, pref); + + // Rename test db so we will not disallow it from completions + pref = SpecialPowers.getCharPref(PREFS.DISALLOW_COMPLETIONS); + pref = pref.replace(list, list + "-backup"); + SpecialPowers.setCharPref(PREFS.DISALLOW_COMPLETIONS, pref); + } + + // Set get hash url + SpecialPowers.setCharPref(PREFS.PROVIDER_GETHASHURL, url); +} + // Pass { url: ..., db: ... } to add url to database, // onsuccess/onerror will be called when update complete. classifierHelper.addUrlToDB = function(updateData) { @@ -26,6 +53,7 @@ classifierHelper.addUrlToDB = function(updateData) { var LISTNAME = update.db; var CHUNKDATA = update.url; var CHUNKLEN = CHUNKDATA.length; + var HASHLEN = update.len ? update.len : 32; classifierHelper._updatesToCleanup.push(update); testUpdate += @@ -49,6 +77,7 @@ classifierHelper.removeUrlFromDB = function(updateData) { var LISTNAME = update.db; var CHUNKDATA = ADD_CHUNKNUM + ":" + update.url; var CHUNKLEN = CHUNKDATA.length; + var HASHLEN = update.len ? update.len : 32; testUpdate += "n:1000\n" + @@ -127,6 +156,11 @@ classifierHelper._setup = function() { }; classifierHelper._cleanup = function() { + // clean all the preferences may touch by helper + for (var pref in PREFS) { + SpecialPowers.clearUserPref(pref); + } + if (!classifierHelper._updatesToCleanup) { return Promise.resolve(); } diff --git a/toolkit/components/url-classifier/tests/mochitest/gethash.sjs b/toolkit/components/url-classifier/tests/mochitest/gethash.sjs new file mode 100644 index 000000000000..47f409bd5b8e --- /dev/null +++ b/toolkit/components/url-classifier/tests/mochitest/gethash.sjs @@ -0,0 +1,119 @@ +const CC = Components.Constructor; +const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1", + "nsIBinaryInputStream", + "setInputStream"); + +function handleRequest(request, response) +{ + var query = {}; + request.queryString.split('&').forEach(function (val) { + var idx = val.indexOf('='); + query[val.slice(0, idx)] = unescape(val.slice(idx + 1)); + }); + + // Store fullhash in the server side. + if ("list" in query && "fullhash" in query) { + // In the server side we will store: + // 1. All the full hashes for a given list + // 2. All the lists we have right now + // data is separate by '\n' + let list = query["list"]; + let hashes = getState(list); + + let hash = base64ToString(query["fullhash"]); + hashes += hash + "\n"; + setState(list, hashes); + + let lists = getState("lists"); + if (lists.indexOf(list) == -1) { + lists += list + "\n"; + setState("lists", lists); + } + + return; + } + + var body = new BinaryInputStream(request.bodyInputStream); + var avail; + var bytes = []; + + while ((avail = body.available()) > 0) { + Array.prototype.push.apply(bytes, body.readByteArray(avail)); + } + + var responseBody = parseV2Request(bytes); + + response.setHeader("Content-Type", "text/plain", false); + response.write(responseBody); + +} + +function parseV2Request(bytes) { + var request = String.fromCharCode.apply(this, bytes); + var [HEADER, PREFIXES] = request.split("\n"); + var [PREFIXSIZE, LENGTH] = HEADER.split(":").map(val => { + return parseInt(val); + }); + + var ret = ""; + for(var start = 0; start < LENGTH; start += PREFIXSIZE) { + getState("lists").split("\n").forEach(function(list) { + var completions = getState(list).split("\n"); + + for (var completion of completions) { + if (completion.indexOf(PREFIXES.substr(start, PREFIXSIZE)) == 0) { + ret += list + ":" + "1" + ":" + "32" + "\n"; + ret += completion; + } + } + }); + } + + return ret; +} + +/* Convert Base64 data to a string */ +const toBinaryTable = [ + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, + -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, + 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1, + -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, + 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, + -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, + 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 +]; +const base64Pad = '='; + +function base64ToString(data) { + var result = ''; + var leftbits = 0; // number of bits decoded, but yet to be appended + var leftdata = 0; // bits decoded, but yet to be appended + + // Convert one by one. + for (var i = 0; i < data.length; i++) { + var c = toBinaryTable[data.charCodeAt(i) & 0x7f]; + var padding = (data[i] == base64Pad); + // Skip illegal characters and whitespace + if (c == -1) continue; + + // Collect data into leftdata, update bitcount + leftdata = (leftdata << 6) | c; + leftbits += 6; + + // If we have 8 or more bits, append 8 bits to the result + if (leftbits >= 8) { + leftbits -= 8; + // Append if not padding. + if (!padding) + result += String.fromCharCode((leftdata >> leftbits) & 0xff); + leftdata &= (1 << leftbits) - 1; + } + } + + // If there are any bits left, the base64 string was corrupted + if (leftbits) + throw Components.Exception('Corrupted base64 string'); + + return result; +} diff --git a/toolkit/components/url-classifier/tests/mochitest/gethashFrame.html b/toolkit/components/url-classifier/tests/mochitest/gethashFrame.html new file mode 100644 index 000000000000..560ddcde6ea2 --- /dev/null +++ b/toolkit/components/url-classifier/tests/mochitest/gethashFrame.html @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + +
+
STYLE EVIL
+
STYLE BAD
+
STYLE IMPORT
+ + diff --git a/toolkit/components/url-classifier/tests/mochitest/import.css b/toolkit/components/url-classifier/tests/mochitest/import.css index 4b5803a0a385..9b86c8216907 100644 --- a/toolkit/components/url-classifier/tests/mochitest/import.css +++ b/toolkit/components/url-classifier/tests/mochitest/import.css @@ -1,3 +1,3 @@ -/* malware.example.com is in the malware database. - classifierBad.css does not actually exist. */ -@import url("http://malware.example.com/tests/docshell/test/classifierBad.css"); +/* malware.example.com is in the malware database. */ +@import url("http://malware.example.com/tests/toolkit/components/url-classifier/tests/mochitest/bad.css"); +#styleImport { visibility: hidden; } diff --git a/toolkit/components/url-classifier/tests/mochitest/mochitest.ini b/toolkit/components/url-classifier/tests/mochitest/mochitest.ini index 6eaca54bf9c4..b9c4005911a4 100644 --- a/toolkit/components/url-classifier/tests/mochitest/mochitest.ini +++ b/toolkit/components/url-classifier/tests/mochitest/mochitest.ini @@ -23,9 +23,13 @@ support-files = dnt.html dnt.sjs update.sjs + bad.css + gethash.sjs + gethashFrame.html [test_classifier.html] skip-if = (os == 'linux' && debug) #Bug 1199778 [test_classifier_worker.html] [test_classify_ping.html] [test_classify_track.html] +[test_gethash.html] diff --git a/toolkit/components/url-classifier/tests/mochitest/test_gethash.html b/toolkit/components/url-classifier/tests/mochitest/test_gethash.html new file mode 100644 index 000000000000..93e7d40a470a --- /dev/null +++ b/toolkit/components/url-classifier/tests/mochitest/test_gethash.html @@ -0,0 +1,150 @@ + + + + Bug 1272239 - Test gethash. + + + + + + +

+ +
+
+
+
+
+
+ + From 0931d35c4c6f2438d3cc64064a330d12491f9759 Mon Sep 17 00:00:00 2001 From: Ethan Lin Date: Thu, 21 Jul 2016 07:31:00 -0400 Subject: [PATCH 054/135] Bug 1285086 - Turn on WebGLSampler. r=jgilbert --HG-- extra : histedit_source : 9a788a293cbf8fc373c9bf7dbce7596f845e460d --- dom/canvas/WebGL2ContextSamplers.cpp | 9 --------- 1 file changed, 9 deletions(-) diff --git a/dom/canvas/WebGL2ContextSamplers.cpp b/dom/canvas/WebGL2ContextSamplers.cpp index a042e4e154eb..e44eab256abe 100644 --- a/dom/canvas/WebGL2ContextSamplers.cpp +++ b/dom/canvas/WebGL2ContextSamplers.cpp @@ -12,24 +12,15 @@ namespace mozilla { already_AddRefed WebGL2Context::CreateSampler() { - const char funcName[] = "createSampler"; - if (IsContextLost()) return nullptr; - /* GLuint sampler; MakeContextCurrent(); gl->fGenSamplers(1, &sampler); RefPtr globj = new WebGLSampler(this, sampler); return globj.forget(); - */ - - ErrorInvalidOperation("%s: Sampler objects are still under development, and are" - " currently disabled.", - funcName); - return nullptr; } void From cef86a68d7e0992b17482cb246ad342f646296e2 Mon Sep 17 00:00:00 2001 From: Ethan Lin Date: Thu, 21 Jul 2016 07:32:00 -0400 Subject: [PATCH 055/135] Bug 1285086 - Enable related webgl conformance test. r=jgilbert --HG-- extra : histedit_source : 2923e5c992879ae732843982e03b18bb676bcbef --- dom/canvas/test/webgl-conf/generated-mochitest.ini | 4 ---- dom/canvas/test/webgl-conf/mochitest-errata.ini | 8 -------- 2 files changed, 12 deletions(-) diff --git a/dom/canvas/test/webgl-conf/generated-mochitest.ini b/dom/canvas/test/webgl-conf/generated-mochitest.ini index 8a79c66f5f61..78c3e7d91ab9 100644 --- a/dom/canvas/test/webgl-conf/generated-mochitest.ini +++ b/dom/canvas/test/webgl-conf/generated-mochitest.ini @@ -4546,10 +4546,8 @@ skip-if = (os == 'win' && debug) || (os == 'android' || os == 'linux' || (os == [generated/test_2_conformance2__glsl3__vector-dynamic-indexing.html] skip-if = (os == 'win') || (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2')) [generated/test_2_conformance2__misc__expando-loss-2.html] -fail-if = (os == 'mac') || (os == 'win') skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2')) [generated/test_2_conformance2__misc__instanceof-test.html] -fail-if = (os == 'mac') || (os == 'win') skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2')) [generated/test_2_conformance2__misc__uninitialized-test-2.html] skip-if = (os == 'mac') || (os == 'win') || (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2')) @@ -4586,10 +4584,8 @@ skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5. [generated/test_2_conformance2__rendering__instanced-arrays.html] skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2')) [generated/test_2_conformance2__samplers__sampler-drawing-test.html] -fail-if = (os == 'mac') || (os == 'win') skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2')) [generated/test_2_conformance2__samplers__samplers.html] -fail-if = (os == 'mac') || (os == 'win') skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2')) [generated/test_2_conformance2__state__gl-enum-tests.html] skip-if = (os == 'android' || os == 'linux' || (os == 'win' && os_version == '5.1') || (os == 'win' && os_version == '6.2')) diff --git a/dom/canvas/test/webgl-conf/mochitest-errata.ini b/dom/canvas/test/webgl-conf/mochitest-errata.ini index bfa2b4bdfc1d..fcfdcd08ac24 100644 --- a/dom/canvas/test/webgl-conf/mochitest-errata.ini +++ b/dom/canvas/test/webgl-conf/mochitest-errata.ini @@ -133,18 +133,12 @@ fail-if = (os == 'mac') skip-if = (os == 'win') [generated/test_2_conformance__extensions__webgl-compressed-texture-s3tc.html] fail-if = (os == 'mac') || (os == 'win') -[generated/test_2_conformance2__misc__instanceof-test.html] -fail-if = (os == 'mac') || (os == 'win') [generated/test_2_conformance__textures__misc__tex-image-with-invalid-data.html] fail-if = (os == 'mac') || (os == 'win') -[generated/test_2_conformance2__samplers__sampler-drawing-test.html] -fail-if = (os == 'mac') || (os == 'win') [generated/test_2_conformance2__buffers__buffer-type-restrictions.html] fail-if = (os == 'mac') || (os == 'win') [generated/test_2_conformance2__rendering__draw-buffers.html] fail-if = (os == 'mac') || (os == 'win') -[generated/test_2_conformance2__samplers__samplers.html] -fail-if = (os == 'mac') || (os == 'win') [generated/test_2_conformance__textures__misc__tex-image-with-format-and-type.html] fail-if = (os == 'mac') [generated/test_2_conformance__attribs__gl-vertexattribpointer.html] @@ -169,8 +163,6 @@ fail-if = (os == 'mac') || (os == 'win') fail-if = (os == 'mac') || (os == 'win') || (os == 'android') || (os == 'linux') [generated/test_2_conformance__textures__misc__tex-sub-image-2d-bad-args.html] fail-if = (os == 'mac') || (os == 'win') -[generated/test_2_conformance2__misc__expando-loss-2.html] -fail-if = (os == 'mac') || (os == 'win') [generated/test_conformance__ogles__GL__biuDepthRange__biuDepthRange_001_to_002.html] fail-if = (os == 'android') || (os == 'linux') [generated/test_conformance__ogles__GL__gl_FragCoord__gl_FragCoord_001_to_003.html] From 885cdcfe3a3676297fe68a511510c66498318c14 Mon Sep 17 00:00:00 2001 From: Wei-Cheng Pan Date: Fri, 27 May 2016 15:58:51 +0800 Subject: [PATCH 056/135] Bug 1264566 - Part 1: Refactor FileDescriptor to fix leaks in content processes. r=valentin, r=baku Now FileDescriptor takes the ownership of the platform handle, in both parent and content processes. Copying will duplicate the underlying handle. It also comes with a move constructor to avoid duplicating if possible. The getter will duplicate a new handle, so a UniquePtr is needed to hold the duplicated handle. MozReview-Commit-ID: DgvjmTI4tpf --HG-- extra : transplant_source : %8A%CA%96l%40iZ%08%D1J%F3%8C%F2%D0%8B6%E5%9EH%13 extra : histedit_source : ee9856a5a1b650663d65380847712691ac8e84bf --- ipc/glue/FileDescriptor.cpp | 198 +++++++++++++++++++++++++++--------- ipc/glue/FileDescriptor.h | 136 ++++++++++--------------- 2 files changed, 200 insertions(+), 134 deletions(-) diff --git a/ipc/glue/FileDescriptor.cpp b/ipc/glue/FileDescriptor.cpp index 26b6ef989a2e..de5f90714047 100644 --- a/ipc/glue/FileDescriptor.cpp +++ b/ipc/glue/FileDescriptor.cpp @@ -7,6 +7,7 @@ #include "FileDescriptor.h" #include "mozilla/Assertions.h" +#include "mozilla/Move.h" #include "nsDebug.h" #ifdef XP_WIN @@ -31,67 +32,83 @@ using mozilla::ipc::FileDescriptor; FileDescriptor::FileDescriptor() - : mHandle(INVALID_HANDLE), mHandleCreatedByOtherProcess(false) -#ifdef DEBUG - , mHandleCreatedByOtherProcessWasUsed(false) -#endif -{ } + : mHandle(INVALID_HANDLE) +{ +} + +FileDescriptor::FileDescriptor(const FileDescriptor& aOther) + : mHandle(INVALID_HANDLE) +{ + Assign(aOther); +} + +FileDescriptor::FileDescriptor(FileDescriptor&& aOther) + : mHandle(INVALID_HANDLE) +{ + *this = mozilla::Move(aOther); +} FileDescriptor::FileDescriptor(PlatformHandleType aHandle) - : mHandle(INVALID_HANDLE), mHandleCreatedByOtherProcess(false) -#ifdef DEBUG - , mHandleCreatedByOtherProcessWasUsed(false) -#endif + : mHandle(INVALID_HANDLE) { - DuplicateInCurrentProcess(aHandle); + mHandle = Clone(aHandle); +} + +FileDescriptor::FileDescriptor(const IPDLPrivate&, const PickleType& aPickle) + : mHandle(INVALID_HANDLE) +{ +#ifdef XP_WIN + mHandle = aPickle; +#else + mHandle = aPickle.fd; +#endif +} + +FileDescriptor::~FileDescriptor() +{ + Close(); +} + +FileDescriptor& +FileDescriptor::operator=(const FileDescriptor& aOther) +{ + if (this != &aOther) { + Assign(aOther); + } + return *this; +} + +FileDescriptor& +FileDescriptor::operator=(FileDescriptor&& aOther) +{ + if (this != &aOther) { + Close(); + mHandle = aOther.mHandle; + aOther.mHandle = INVALID_HANDLE; + } + return *this; +} + +bool +FileDescriptor::IsValid() const +{ + return IsValid(mHandle); } void -FileDescriptor::DuplicateInCurrentProcess(PlatformHandleType aHandle) +FileDescriptor::Assign(const FileDescriptor& aOther) { - MOZ_ASSERT_IF(mHandleCreatedByOtherProcess && IsValid(), - mHandleCreatedByOtherProcessWasUsed); - - if (IsValid(aHandle)) { - PlatformHandleType newHandle; -#ifdef XP_WIN - if (::DuplicateHandle(GetCurrentProcess(), aHandle, GetCurrentProcess(), - &newHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { -#else // XP_WIN - if ((newHandle = dup(aHandle)) != INVALID_HANDLE) { -#endif - mHandle = newHandle; - return; - } - NS_WARNING("Failed to duplicate file handle for current process!"); - } + Close(); + mHandle = Clone(aOther.mHandle); +} +void +FileDescriptor::Close() +{ + Close(mHandle); mHandle = INVALID_HANDLE; } -void -FileDescriptor::CloseCurrentProcessHandle() -{ - MOZ_ASSERT_IF(mHandleCreatedByOtherProcess && IsValid(), - mHandleCreatedByOtherProcessWasUsed); - - // Don't actually close handles created by another process. - if (mHandleCreatedByOtherProcess) { - return; - } - - if (IsValid()) { -#ifdef XP_WIN - if (!CloseHandle(mHandle)) { - NS_WARNING("Failed to close file handle for current process!"); - } -#else // XP_WIN - HANDLE_EINTR(close(mHandle)); -#endif - mHandle = INVALID_HANDLE; - } -} - FileDescriptor::PickleType FileDescriptor::ShareTo(const FileDescriptor::IPDLPrivate&, FileDescriptor::ProcessId aTargetPid) const @@ -120,9 +137,90 @@ FileDescriptor::ShareTo(const FileDescriptor::IPDLPrivate&, MOZ_CRASH("Must not get here!"); } +FileDescriptor::UniquePlatformHandle +FileDescriptor::ClonePlatformHandle() const +{ + return UniquePlatformHandle(Clone(mHandle)); +} + +bool +FileDescriptor::operator==(const FileDescriptor& aOther) const +{ + return mHandle == aOther.mHandle; +} + // static bool FileDescriptor::IsValid(PlatformHandleType aHandle) { return aHandle != INVALID_HANDLE; } + +// static +FileDescriptor::PlatformHandleType +FileDescriptor::Clone(PlatformHandleType aHandle) +{ + if (!IsValid(aHandle)) { + return INVALID_HANDLE; + } + FileDescriptor::PlatformHandleType newHandle; +#ifdef XP_WIN + if (::DuplicateHandle(GetCurrentProcess(), aHandle, GetCurrentProcess(), + &newHandle, 0, FALSE, DUPLICATE_SAME_ACCESS)) { +#else // XP_WIN + if ((newHandle = dup(aHandle)) != INVALID_HANDLE) { +#endif + return newHandle; + } + NS_WARNING("Failed to duplicate file handle for current process!"); + return INVALID_HANDLE; +} + +// static +void +FileDescriptor::Close(PlatformHandleType aHandle) +{ + if (IsValid(aHandle)) { +#ifdef XP_WIN + if (!CloseHandle(aHandle)) { + NS_WARNING("Failed to close file handle for current process!"); + } +#else // XP_WIN + HANDLE_EINTR(close(aHandle)); +#endif + } +} + +FileDescriptor::PlatformHandleHelper::PlatformHandleHelper(FileDescriptor::PlatformHandleType aHandle) + :mHandle(aHandle) +{ +} + +FileDescriptor::PlatformHandleHelper::PlatformHandleHelper(std::nullptr_t) + :mHandle(INVALID_HANDLE) +{ +} + +bool +FileDescriptor::PlatformHandleHelper::operator!=(std::nullptr_t) const +{ + return mHandle != INVALID_HANDLE; +} + +FileDescriptor::PlatformHandleHelper::operator PlatformHandleType () const +{ + return mHandle; +} + +#ifdef XP_WIN +FileDescriptor::PlatformHandleHelper::operator std::intptr_t () const +{ + return reinterpret_cast(mHandle); +} +#endif + +void +FileDescriptor::PlatformHandleDeleter::operator()(FileDescriptor::PlatformHandleHelper aHelper) +{ + FileDescriptor::Close(aHelper); +} diff --git a/ipc/glue/FileDescriptor.h b/ipc/glue/FileDescriptor.h index efcc09f97e47..b30c5db1a705 100644 --- a/ipc/glue/FileDescriptor.h +++ b/ipc/glue/FileDescriptor.h @@ -9,8 +9,7 @@ #include "base/basictypes.h" #include "base/process.h" -#include "mozilla/DebugOnly.h" -#include "nscore.h" +#include "mozilla/UniquePtr.h" #ifdef XP_WIN // Need the HANDLE typedef. @@ -47,49 +46,52 @@ public: typedef base::FileDescriptor PickleType; #endif + struct PlatformHandleHelper + { + MOZ_IMPLICIT PlatformHandleHelper(PlatformHandleType aHandle); + MOZ_IMPLICIT PlatformHandleHelper(std::nullptr_t); + bool operator != (std::nullptr_t) const; + operator PlatformHandleType () const; +#ifdef XP_WIN + operator std::intptr_t () const; +#endif + private: + PlatformHandleType mHandle; + }; + struct PlatformHandleDeleter + { + typedef PlatformHandleHelper pointer; + void operator () (PlatformHandleHelper aHelper); + }; + typedef UniquePtr UniquePlatformHandle; + // This should only ever be created by IPDL. struct IPDLPrivate {}; + // Represents an invalid handle. FileDescriptor(); - FileDescriptor(const FileDescriptor& aOther) - : mHandleCreatedByOtherProcess(false) -#ifdef DEBUG - , mHandleCreatedByOtherProcessWasUsed(false) -#endif - { - // Don't use operator= here because that will call - // CloseCurrentProcessHandle() on this (uninitialized) object. - Assign(aOther); - } + // Copy constructor will duplicate a new handle. + FileDescriptor(const FileDescriptor& aOther); + FileDescriptor(FileDescriptor&& aOther); + + // This constructor will duplicate a new handle. + // The caller still have to close aHandle. explicit FileDescriptor(PlatformHandleType aHandle); - FileDescriptor(const IPDLPrivate&, const PickleType& aPickle) -#ifdef XP_WIN - : mHandle(aPickle) -#else - : mHandle(aPickle.fd) -#endif - , mHandleCreatedByOtherProcess(true) -#ifdef DEBUG - , mHandleCreatedByOtherProcessWasUsed(false) -#endif - { } + // This constructor WILL NOT duplicate the handle. + // FileDescriptor takes the ownership from IPC message. + FileDescriptor(const IPDLPrivate&, const PickleType& aPickle); - ~FileDescriptor() - { - CloseCurrentProcessHandle(); - } + ~FileDescriptor(); FileDescriptor& - operator=(const FileDescriptor& aOther) - { - CloseCurrentProcessHandle(); - Assign(aOther); - return *this; - } + operator=(const FileDescriptor& aOther); + + FileDescriptor& + operator=(FileDescriptor&& aOther); // Performs platform-specific actions to duplicate mHandle in the other // process (e.g. dup() on POSIX, DuplicateHandle() on Windows). Returns a @@ -100,70 +102,36 @@ public: // Tests mHandle against a well-known invalid platform-specific file handle // (e.g. -1 on POSIX, INVALID_HANDLE_VALUE on Windows). bool - IsValid() const - { - return IsValid(mHandle); - } + IsValid() const; - PlatformHandleType - PlatformHandle() const - { -#ifdef DEBUG - if (mHandleCreatedByOtherProcess) { - mHandleCreatedByOtherProcessWasUsed = true; - } -#endif - return mHandle; - } + // Returns a duplicated handle, it is caller's responsibility to close the + // handle. + UniquePlatformHandle + ClonePlatformHandle() const; + // Only used in nsTArray. bool - operator==(const FileDescriptor& aOther) const - { - return mHandle == aOther.mHandle; - } + operator==(const FileDescriptor& aOther) const; private: + friend struct PlatformHandleTrait; + void - Assign(const FileDescriptor& aOther) - { - if (aOther.mHandleCreatedByOtherProcess) { - mHandleCreatedByOtherProcess = true; -#ifdef DEBUG - mHandleCreatedByOtherProcessWasUsed = - aOther.mHandleCreatedByOtherProcessWasUsed; -#endif - mHandle = aOther.PlatformHandle(); - } else { - DuplicateInCurrentProcess(aOther.PlatformHandle()); - mHandleCreatedByOtherProcess = false; -#ifdef DEBUG - mHandleCreatedByOtherProcessWasUsed = false; -#endif - } - } + Assign(const FileDescriptor& aOther); + + void + Close(); static bool IsValid(PlatformHandleType aHandle); - void - DuplicateInCurrentProcess(PlatformHandleType aHandle); + static PlatformHandleType + Clone(PlatformHandleType aHandle); - void - CloseCurrentProcessHandle(); + static void + Close(PlatformHandleType aHandle); PlatformHandleType mHandle; - - // If this is true then this instance is created by IPDL to ferry a handle to - // its eventual consumer and we never close the handle. If this is false then - // we are a RAII wrapper around the handle and we close the handle on - // destruction. - bool mHandleCreatedByOtherProcess; - -#ifdef DEBUG - // This is to ensure that we don't leak the handle (which is only possible - // when we're in the receiving process). - mutable bool mHandleCreatedByOtherProcessWasUsed; -#endif }; } // namespace ipc From fd87664d8e4195913bc0a67f6c98db2d37076a5d Mon Sep 17 00:00:00 2001 From: Wei-Cheng Pan Date: Fri, 27 May 2016 16:12:51 +0800 Subject: [PATCH 057/135] Bug 1264566 - Part 2: Refactor all usage of FileDescriptor. r=valentin Callers should use a UniquePtr to hold the platform handle. MozReview-Commit-ID: 6BWnyAf4b3a --HG-- extra : transplant_source : %26%CA%0D%28%08%9BT%97Z%A1%3Dq%CD%21%A1_%EFE%83%0E extra : histedit_source : 77f8ed3d0fdec6cce0c95469130ade0fb547bb91 --- .../FileDescriptorOutputStream.cpp | 3 ++- dom/asmjscache/AsmJSCache.cpp | 3 ++- dom/camera/GonkCameraControl.cpp | 6 ++--- dom/ipc/ContentChild.cpp | 3 ++- dom/ipc/ContentParent.cpp | 4 ++-- dom/plugins/ipc/PluginModuleParent.cpp | 4 ++-- ipc/glue/FileDescriptorUtils.cpp | 22 ++++--------------- ipc/glue/FileDescriptorUtils.h | 4 ++-- ipc/glue/Transport_posix.cpp | 3 ++- netwerk/base/nsFileStreams.cpp | 3 ++- netwerk/ipc/RemoteOpenFileChild.cpp | 3 ++- security/sandbox/linux/gtest/TestBroker.cpp | 3 ++- xpcom/io/nsAnonymousTemporaryFile.cpp | 4 ++-- 13 files changed, 29 insertions(+), 36 deletions(-) diff --git a/devtools/shared/heapsnapshot/FileDescriptorOutputStream.cpp b/devtools/shared/heapsnapshot/FileDescriptorOutputStream.cpp index 51cfd3ad77a6..72a289558f06 100644 --- a/devtools/shared/heapsnapshot/FileDescriptorOutputStream.cpp +++ b/devtools/shared/heapsnapshot/FileDescriptorOutputStream.cpp @@ -15,7 +15,8 @@ FileDescriptorOutputStream::Create(const ipc::FileDescriptor& fileDescriptor) if (NS_WARN_IF(!fileDescriptor.IsValid())) return nullptr; - PRFileDesc* prfd = PR_ImportFile(PROsfd(fileDescriptor.PlatformHandle())); + auto rawFD = fileDescriptor.ClonePlatformHandle(); + PRFileDesc* prfd = PR_ImportFile(PROsfd(rawFD.release())); if (NS_WARN_IF(!prfd)) return nullptr; diff --git a/dom/asmjscache/AsmJSCache.cpp b/dom/asmjscache/AsmJSCache.cpp index b21515972d6e..b7aa1f870279 100644 --- a/dom/asmjscache/AsmJSCache.cpp +++ b/dom/asmjscache/AsmJSCache.cpp @@ -1310,7 +1310,8 @@ private: mFileSize = aFileSize; - mFileDesc = PR_ImportFile(PROsfd(aFileDesc.PlatformHandle())); + auto rawFD = aFileDesc.ClonePlatformHandle(); + mFileDesc = PR_ImportFile(PROsfd(rawFD.release())); if (!mFileDesc) { return false; } diff --git a/dom/camera/GonkCameraControl.cpp b/dom/camera/GonkCameraControl.cpp index 10fc1ae43a83..8f1285af3894 100644 --- a/dom/camera/GonkCameraControl.cpp +++ b/dom/camera/GonkCameraControl.cpp @@ -1252,15 +1252,15 @@ nsGonkCameraControl::StartRecordingImpl(DeviceStorageFileDescriptor* aFileDescri closer = new CloseFileRunnable(aFileDescriptor->mFileDescriptor); } nsresult rv; - int fd = aFileDescriptor->mFileDescriptor.PlatformHandle(); + auto rawFD = aFileDescriptor->mFileDescriptor.ClonePlatformHandle(); if (aOptions) { - rv = SetupRecording(fd, aOptions->rotation, aOptions->maxFileSizeBytes, + rv = SetupRecording(rawFD.get(), aOptions->rotation, aOptions->maxFileSizeBytes, aOptions->maxVideoLengthMs); if (NS_SUCCEEDED(rv)) { rv = SetupRecordingFlash(aOptions->autoEnableLowLightTorch); } } else { - rv = SetupRecording(fd, 0, 0, 0); + rv = SetupRecording(rawFD.get(), 0, 0, 0); } if (NS_WARN_IF(NS_FAILED(rv))) { return rv; diff --git a/dom/ipc/ContentChild.cpp b/dom/ipc/ContentChild.cpp index fed395439313..b902d08fb153 100644 --- a/dom/ipc/ContentChild.cpp +++ b/dom/ipc/ContentChild.cpp @@ -1422,7 +1422,8 @@ ContentChild::RecvSetProcessSandbox(const MaybeFileDesc& aBroker) #endif int brokerFd = -1; if (aBroker.type() == MaybeFileDesc::TFileDescriptor) { - brokerFd = aBroker.get_FileDescriptor().PlatformHandle(); + auto fd = aBroker.get_FileDescriptor().ClonePlatformHandle(); + brokerFd = fd.release(); // brokerFd < 0 means to allow direct filesystem access, so // make absolutely sure that doesn't happen if the parent // didn't intend it. diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp index 93ea2a76560d..d2903415bbd9 100644 --- a/dom/ipc/ContentParent.cpp +++ b/dom/ipc/ContentParent.cpp @@ -4922,9 +4922,9 @@ ContentParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd) #else MOZ_ASSERT(0 > mChildXSocketFdDup.get(), "Already backed up X resources??"); - mChildXSocketFdDup.forget(); if (aXSocketFd.IsValid()) { - mChildXSocketFdDup.reset(aXSocketFd.PlatformHandle()); + auto rawFD = aXSocketFd.ClonePlatformHandle(); + mChildXSocketFdDup.reset(rawFD.release()); } #endif return true; diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 44ab0e9e7909..71bcda3a10de 100755 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -1914,9 +1914,9 @@ PluginModuleParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd) #else MOZ_ASSERT(0 > mPluginXSocketFdDup.get(), "Already backed up X resources??"); - mPluginXSocketFdDup.forget(); if (aXSocketFd.IsValid()) { - mPluginXSocketFdDup.reset(aXSocketFd.PlatformHandle()); + auto rawFD = aXSocketFd.ClonePlatformHandle(); + mPluginXSocketFdDup.reset(rawFD.release()); } #endif return true; diff --git a/ipc/glue/FileDescriptorUtils.cpp b/ipc/glue/FileDescriptorUtils.cpp index 05ab02d1a604..e30bc97d8cc8 100644 --- a/ipc/glue/FileDescriptorUtils.cpp +++ b/ipc/glue/FileDescriptorUtils.cpp @@ -62,19 +62,7 @@ CloseFileRunnable::CloseFile() { // It's possible for this to happen on the main thread if the dispatch to the // stream service fails so we can't assert the thread on which we're running. - - MOZ_ASSERT(mFileDescriptor.IsValid()); - - PRFileDesc* fd = - PR_ImportFile(PROsfd(mFileDescriptor.PlatformHandle())); - NS_WARN_IF_FALSE(fd, "Failed to import file handle!"); - mFileDescriptor = FileDescriptor(); - - if (fd) { - PR_Close(fd); - fd = nullptr; - } } NS_IMETHODIMP @@ -93,21 +81,19 @@ FILE* FileDescriptorToFILE(const FileDescriptor& aDesc, const char* aOpenMode) { - // Debug builds check whether the handle was "used", even if it's - // invalid, so that needs to happen first. - FileDescriptor::PlatformHandleType handle = aDesc.PlatformHandle(); if (!aDesc.IsValid()) { errno = EBADF; return nullptr; } + auto handle = aDesc.ClonePlatformHandle(); #ifdef XP_WIN - int fd = _open_osfhandle(reinterpret_cast(handle), 0); + int fd = _open_osfhandle(static_cast(handle.get()), 0); if (fd == -1) { - CloseHandle(handle); return nullptr; } + Unused << handle.release(); #else - int fd = handle; + int fd = handle.release(); #endif FILE* file = fdopen(fd, aOpenMode); if (!file) { diff --git a/ipc/glue/FileDescriptorUtils.h b/ipc/glue/FileDescriptorUtils.h index 2dbeadc9702f..34562c3619cd 100644 --- a/ipc/glue/FileDescriptorUtils.h +++ b/ipc/glue/FileDescriptorUtils.h @@ -44,8 +44,8 @@ private: void CloseFile(); }; -// On failure, FileDescriptorToFILE closes the given descriptor; on -// success, fclose()ing the returned FILE* will close the handle. +// On failure, FileDescriptorToFILE returns nullptr; on success, +// returns duplicated FILE*. // This is meant for use with FileDescriptors received over IPC. FILE* FileDescriptorToFILE(const FileDescriptor& aDesc, const char* aOpenMode); diff --git a/ipc/glue/Transport_posix.cpp b/ipc/glue/Transport_posix.cpp index 0f6a5cda7b49..14414f631b92 100644 --- a/ipc/glue/Transport_posix.cpp +++ b/ipc/glue/Transport_posix.cpp @@ -60,7 +60,8 @@ OpenDescriptor(const TransportDescriptor& aTd, Transport::Mode aMode) UniquePtr OpenDescriptor(const FileDescriptor& aFd, Transport::Mode aMode) { - return MakeUnique(aFd.PlatformHandle(), aMode, nullptr); + auto rawFD = aFd.ClonePlatformHandle(); + return MakeUnique(rawFD.release(), aMode, nullptr); } TransportDescriptor diff --git a/netwerk/base/nsFileStreams.cpp b/netwerk/base/nsFileStreams.cpp index c918fcf7aa9e..14e8eb0d561d 100644 --- a/netwerk/base/nsFileStreams.cpp +++ b/netwerk/base/nsFileStreams.cpp @@ -635,7 +635,8 @@ nsFileInputStream::Deserialize(const InputStreamParams& aParams, } if (fd.IsValid()) { - PRFileDesc* fileDesc = PR_ImportFile(PROsfd(fd.PlatformHandle())); + auto rawFD = fd.ClonePlatformHandle(); + PRFileDesc* fileDesc = PR_ImportFile(PROsfd(rawFD.release())); if (!fileDesc) { NS_WARNING("Failed to import file handle!"); return false; diff --git a/netwerk/ipc/RemoteOpenFileChild.cpp b/netwerk/ipc/RemoteOpenFileChild.cpp index e74da98b5777..53e89e822f49 100644 --- a/netwerk/ipc/RemoteOpenFileChild.cpp +++ b/netwerk/ipc/RemoteOpenFileChild.cpp @@ -294,7 +294,8 @@ RemoteOpenFileChild::HandleFileDescriptorAndNotifyListener( } if (aFD.IsValid()) { - mNSPRFileDesc = PR_ImportFile(aFD.PlatformHandle()); + auto rawFD = aFD.ClonePlatformHandle(); + mNSPRFileDesc = PR_ImportFile(rawFD.release()); if (!mNSPRFileDesc) { NS_WARNING("Failed to import file handle!"); } diff --git a/security/sandbox/linux/gtest/TestBroker.cpp b/security/sandbox/linux/gtest/TestBroker.cpp index 0fbe8fb4d1da..eeceedd23a3d 100644 --- a/security/sandbox/linux/gtest/TestBroker.cpp +++ b/security/sandbox/linux/gtest/TestBroker.cpp @@ -67,7 +67,8 @@ protected: mServer = SandboxBroker::Create(GetPolicy(), getpid(), fd); ASSERT_NE(mServer, nullptr); ASSERT_TRUE(fd.IsValid()); - mClient.reset(new SandboxBrokerClient(dup(fd.PlatformHandle()))); + auto rawFD = fd.ClonePlatformHandle(); + mClient.reset(new SandboxBrokerClient(rawFD.release())); } template diff --git a/xpcom/io/nsAnonymousTemporaryFile.cpp b/xpcom/io/nsAnonymousTemporaryFile.cpp index 2ef219fe3160..932f8a87db9a 100644 --- a/xpcom/io/nsAnonymousTemporaryFile.cpp +++ b/xpcom/io/nsAnonymousTemporaryFile.cpp @@ -126,8 +126,8 @@ NS_OpenAnonymousTemporaryFile(PRFileDesc** aOutFileDesc) MOZ_ASSERT(NS_FAILED(rv)); return rv; } - *aOutFileDesc = - PR_ImportFile(PROsfd(fd.get_FileDescriptor().PlatformHandle())); + auto rawFD = fd.get_FileDescriptor().ClonePlatformHandle(); + *aOutFileDesc = PR_ImportFile(PROsfd(rawFD.release())); return NS_OK; } From eab2098c9926f4e39dfce3f55aa85cd7c553b090 Mon Sep 17 00:00:00 2001 From: Wei-Cheng Pan Date: Fri, 24 Jun 2016 18:12:32 +0800 Subject: [PATCH 058/135] Bug 1264566 - Part 3: Release upload stream after request complete. r=valentin MozReview-Commit-ID: 5r1fEkOy9vU --HG-- extra : transplant_source : %1Dc6%99%3F%5C%81%F6%FDu%FD%C0l%B8-%CD%AF%BBx%01 extra : histedit_source : b407a427fa4cd3fedfd71f7d7f56958fce1099ca --- netwerk/protocol/http/HttpChannelChild.cpp | 2 ++ netwerk/protocol/http/nsHttpChannel.cpp | 2 ++ 2 files changed, 4 insertions(+) diff --git a/netwerk/protocol/http/HttpChannelChild.cpp b/netwerk/protocol/http/HttpChannelChild.cpp index caddba404dcd..ac182f893137 100644 --- a/netwerk/protocol/http/HttpChannelChild.cpp +++ b/netwerk/protocol/http/HttpChannelChild.cpp @@ -864,6 +864,8 @@ HttpChannelChild::OnStopRequest(const nsresult& channelStatus, LOG(("HttpChannelChild::OnStopRequest [this=%p status=%x]\n", this, channelStatus)); + mUploadStream = nullptr; + if (mDivertingToParent) { MOZ_RELEASE_ASSERT(!mFlushedForDiversion, "Should not be processing any more callbacks from parent!"); diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index f82b475192ae..9c653ed3d3b6 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -6341,6 +6341,8 @@ nsHttpChannel::OnStopRequest(nsIRequest *request, nsISupports *ctxt, nsresult st MOZ_ASSERT(NS_IsMainThread(), "OnStopRequest should only be called from the main thread"); + mUploadStream = nullptr; + if (NS_FAILED(status)) { ProcessSecurityReport(status); } From 4c0049442526c6741e816b54eaccfd65288d67ff Mon Sep 17 00:00:00 2001 From: Jamie Nicol Date: Fri, 22 Jul 2016 14:16:22 +0100 Subject: [PATCH 059/135] Bug 1164027 - Use MAP_ANONYMOUS instead of opening /dev/zero. r=jrmuizel MozReview-Commit-ID: 5GeNG5Tm1GS --HG-- extra : histedit_source : 31e30d68fce2f97015c6e84da953e1b6f04fca50 --- gfx/gl/GLContext.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/gfx/gl/GLContext.cpp b/gfx/gl/GLContext.cpp index 5f8fe5133857..4a8cbc3f9496 100644 --- a/gfx/gl/GLContext.cpp +++ b/gfx/gl/GLContext.cpp @@ -12,7 +12,6 @@ #include #include #ifdef MOZ_WIDGET_ANDROID -#include #include #endif @@ -2886,16 +2885,12 @@ WillTextureMapSucceed(GLsizei width, GLsizei height, GLenum format, GLenum type) // there to be double the actual size of the texture available. size_t size = width * height * GetBytesPerTexel(format, type) * 2; - int fd = open("/dev/zero", O_RDONLY); - - void *p = mmap(nullptr, size, PROT_NONE, MAP_SHARED, fd, 0); + void *p = mmap(nullptr, size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); if (p != MAP_FAILED) { willSucceed = true; munmap(p, size); } - close(fd); - return willSucceed; } #endif // MOZ_WIDGET_ANDROID From 8836484e88b825ffe998d1ccdc9a0f2d2fc807e1 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 22 Jul 2016 14:56:46 -0400 Subject: [PATCH 060/135] Backed out changeset 2e8cfd225f04 (bug 1272498) for OSX bustage on a CLOSED TREE. --HG-- extra : histedit_source : c6f409f477c5d66ae52adae84188eef6ff67356c --- xpcom/reflect/xptcall/md/unix/moz.build | 2 - .../md/unix/xptcinvoke_asm_x86_64_unix.s | 92 ------------- .../md/unix/xptcinvoke_x86_64_unix.cpp | 129 ++++++++++++++++-- 3 files changed, 121 insertions(+), 102 deletions(-) delete mode 100644 xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_x86_64_unix.s diff --git a/xpcom/reflect/xptcall/md/unix/moz.build b/xpcom/reflect/xptcall/md/unix/moz.build index f8f06799934d..c8576dfa93d3 100644 --- a/xpcom/reflect/xptcall/md/unix/moz.build +++ b/xpcom/reflect/xptcall/md/unix/moz.build @@ -28,7 +28,6 @@ if CONFIG['OS_ARCH'] in ('Linux', 'Bitrig', 'DragonFly', 'FreeBSD', 'NetBSD', 'O CONFIG['OS_ARCH'].startswith('GNU_'): if CONFIG['OS_TEST'] == 'x86_64': SOURCES += [ - 'xptcinvoke_asm_x86_64_unix.s', 'xptcinvoke_x86_64_unix.cpp', 'xptcstubs_x86_64_linux.cpp', ] @@ -54,7 +53,6 @@ if CONFIG['OS_ARCH'] == 'SunOS' and '86' in CONFIG['OS_TEST']: if CONFIG['OS_TEST'] == 'x86_64': if CONFIG['GNU_CC']: SOURCES += [ - 'xptcinvoke_asm_x86_64_unix.s', 'xptcinvoke_x86_64_unix.cpp', 'xptcstubs_x86_64_linux.cpp' ] diff --git a/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_x86_64_unix.s b/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_x86_64_unix.s deleted file mode 100644 index 5045b0e6cb3b..000000000000 --- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_asm_x86_64_unix.s +++ /dev/null @@ -1,92 +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/. - -.intel_syntax noprefix - -# nsresult NS_InvokeByIndex(nsISupports* this, uint32_t aVtableIndex, -# uint32_t argc, nsXPTCVariant* argv); -.text -.global NS_InvokeByIndex -.type NS_InvokeByIndex, @function -.align 4 -NS_InvokeByIndex: - push rbp - mov rbp, rsp - -# save r12 and r13 because we use them and they are callee saved. - push r12 - push r13 - -# save this and the vtable index because we need them after setting up the -# stack. - mov r12, rdi - mov r13, rsi - -# allocate space for stack arguments, in theory we only need 8 * (argc - 5) -# bytes because at least 5 arguments will go in registers, but for now it is -# just simpler to allocate 8 * (argc - 1) bytes. Note that we treat the this -# pointer specially. - lea eax, [edx * 8] - sub rsp, rax - -# if there is an odd number of args the stack can be misaligned so realign it. - and rsp, 0xffffffffffffff00 - -# pass the stack slot area to InvokeCopyToStack. - mov r8, rsp - -# setup space for the register slots: there are 5 integer ones and 8 floating -# point ones. So we need 104 bytes of space, but we allocate 112 to keep rsp -# aligned to 16 bytes. - sub rsp, 112 - -# the first argument to InvokeCopyToStack is the integer register area, and the -# second is the floating point area. - mov rdi, rsp - lea rsi, [rsp + 40] - -# The 3rd and 4th arguments to InvokeCopyToStack are already in the right -# registers because they are our 3rd and 4th arguments. So now we can just -# call InvokeCopyToStack. - call InvokeCopyToStack - -# setup this - mov rdi, r12 - -# copy the integer arguments into place. - mov rsi, [rsp] - mov rdx, [rsp + 8] - mov rcx, [rsp + 16] - mov r8, [rsp + 24] - mov r9, [rsp + 32] - -# copy the float arguments into place - movsd xmm0, [rsp + 40] - movsd xmm1, [rsp + 48] - movsd xmm2, [rsp + 56] - movsd xmm3, [rsp + 64] - movsd xmm4, [rsp + 72] - movsd xmm5, [rsp + 80] - movsd xmm6, [rsp + 88] - movsd xmm7, [rsp + 96] - -# get rid of the scratch space for registers - add rsp, 112 - -# load the function pointer and call - lea eax, [r13d * 8] - add rax, [rdi] - call [rax] - -# r12 and r13 were pushed relative to the old stack pointer which is now the -# frame pointer. - mov r12, [rbp - 0x8] - mov r13, [rbp - 0x10] - - mov rsp, rbp - pop rbp - ret - -// Magic indicating no need for an executable stack -.section .note.GNU-stack, "", @progbits ; .previous diff --git a/xpcom/reflect/xptcall/md/unix/xptcinvoke_x86_64_unix.cpp b/xpcom/reflect/xptcall/md/unix/xptcinvoke_x86_64_unix.cpp index a9db2a693a58..08e51988971c 100644 --- a/xpcom/reflect/xptcall/md/unix/xptcinvoke_x86_64_unix.cpp +++ b/xpcom/reflect/xptcall/md/unix/xptcinvoke_x86_64_unix.cpp @@ -8,19 +8,46 @@ #include "xptcprivate.h" -// 6 integral parameters are passed in registers, but 1 is |this| which isn't -// considered here. -const uint32_t GPR_COUNT = 5; +// 6 integral parameters are passed in registers +const uint32_t GPR_COUNT = 6; // 8 floating point parameters are passed in SSE registers const uint32_t FPR_COUNT = 8; -extern "C" void -InvokeCopyToStack(uint64_t * gpregs, double * fpregs, - uint32_t paramCount, nsXPTCVariant * s, - uint64_t* d) +// Remember that these 'words' are 64-bit long +static inline void +invoke_count_words(uint32_t paramCount, nsXPTCVariant * s, + uint32_t & nr_stack) { - uint32_t nr_gpr = 0u; // skip one GP register for 'that' + uint32_t nr_gpr; + uint32_t nr_fpr; + nr_gpr = 1; // skip one GP register for 'that' + nr_fpr = 0; + nr_stack = 0; + + /* Compute number of eightbytes of class MEMORY. */ + for (uint32_t i = 0; i < paramCount; i++, s++) { + if (!s->IsPtrData() + && (s->type == nsXPTType::T_FLOAT || s->type == nsXPTType::T_DOUBLE)) { + if (nr_fpr < FPR_COUNT) + nr_fpr++; + else + nr_stack++; + } + else { + if (nr_gpr < GPR_COUNT) + nr_gpr++; + else + nr_stack++; + } + } +} + +static void +invoke_copy_to_stack(uint64_t * d, uint32_t paramCount, nsXPTCVariant * s, + uint64_t * gpregs, double * fpregs) +{ + uint32_t nr_gpr = 1u; // skip one GP register for 'that' uint32_t nr_fpr = 0u; uint64_t value = 0u; @@ -73,3 +100,89 @@ InvokeCopyToStack(uint64_t * gpregs, double * fpregs, } } } + +// Disable avx for the next function to allow compilation with +// -march=native on new machines, or similar hardcoded -march options. +// Having avx enabled appears to change the alignment behavior of alloca +// (apparently adding an extra 16 bytes) of padding/alignment (and using +// 32-byte alignment instead of 16-byte). This seems to be the best +// available workaround, given that this code, which should perhaps +// better be written in assembly, is written in C++. +#ifndef __clang__ +#pragma GCC push_options +#pragma GCC target ("no-avx") +#endif + +// Avoid AddressSanitizer instrumentation for the next function because it +// depends on __builtin_alloca behavior and alignment that cannot be relied on +// once the function is compiled with a version of ASan that has dynamic-alloca +// instrumentation enabled. + +MOZ_ASAN_BLACKLIST +EXPORT_XPCOM_API(nsresult) +NS_InvokeByIndex(nsISupports * that, uint32_t methodIndex, + uint32_t paramCount, nsXPTCVariant * params) +{ + uint32_t nr_stack; + invoke_count_words(paramCount, params, nr_stack); + + // Stack, if used, must be 16-bytes aligned + if (nr_stack) + nr_stack = (nr_stack + 1) & ~1; + + // Load parameters to stack, if necessary + uint64_t *stack = (uint64_t *) __builtin_alloca(nr_stack * 8); + uint64_t gpregs[GPR_COUNT]; + double fpregs[FPR_COUNT]; + invoke_copy_to_stack(stack, paramCount, params, gpregs, fpregs); + + // We used to have switches to make sure we would only load the registers + // that are needed for this call. That produced larger code that was + // not faster in practice. It also caused compiler warnings about the + // variables being used uninitialized. + // We now just load every every register. There could still be a warning + // from a memory analysis tools that we are loading uninitialized stack + // positions. + + // FIXME: this function depends on the above __builtin_alloca placing + // the array in the correct spot for the ABI. + + // Load FPR registers from fpregs[] + double d0, d1, d2, d3, d4, d5, d6, d7; + + d7 = fpregs[7]; + d6 = fpregs[6]; + d5 = fpregs[5]; + d4 = fpregs[4]; + d3 = fpregs[3]; + d2 = fpregs[2]; + d1 = fpregs[1]; + d0 = fpregs[0]; + + // Load GPR registers from gpregs[] + uint64_t a0, a1, a2, a3, a4, a5; + + a5 = gpregs[5]; + a4 = gpregs[4]; + a3 = gpregs[3]; + a2 = gpregs[2]; + a1 = gpregs[1]; + a0 = (uint64_t) that; + + // Get pointer to method + uint64_t methodAddress = *((uint64_t *)that); + methodAddress += 8 * methodIndex; + methodAddress = *((uint64_t *)methodAddress); + + typedef nsresult (*Method)(uint64_t, uint64_t, uint64_t, uint64_t, + uint64_t, uint64_t, double, double, double, + double, double, double, double, double); + nsresult result = ((Method)methodAddress)(a0, a1, a2, a3, a4, a5, + d0, d1, d2, d3, d4, d5, + d6, d7); + return result; +} + +#ifndef __clang__ +#pragma GCC pop_options +#endif From 8d3499e3d5a88d4f980bdf25aa023bbd77704a55 Mon Sep 17 00:00:00 2001 From: Michael Li Date: Thu, 21 Jul 2016 12:57:00 -0400 Subject: [PATCH 061/135] Bug 1288508 - Make nsIAccessible* interfaces builtinclass so they can be static_cast'ed to xpcAccessibleGeneric. r=yzen --- accessible/interfaces/nsIAccessible.idl | 2 +- accessible/interfaces/nsIAccessibleApplication.idl | 2 +- accessible/interfaces/nsIAccessibleDocument.idl | 2 +- accessible/interfaces/nsIAccessibleEditableText.idl | 2 +- accessible/interfaces/nsIAccessibleHyperLink.idl | 2 +- accessible/interfaces/nsIAccessibleHyperText.idl | 2 +- accessible/interfaces/nsIAccessibleImage.idl | 2 +- accessible/interfaces/nsIAccessiblePivot.idl | 6 +++--- accessible/interfaces/nsIAccessibleRelation.idl | 2 +- accessible/interfaces/nsIAccessibleRetrieval.idl | 2 +- accessible/interfaces/nsIAccessibleRole.idl | 2 +- accessible/interfaces/nsIAccessibleSelectable.idl | 2 +- accessible/interfaces/nsIAccessibleStates.idl | 2 +- accessible/interfaces/nsIAccessibleTable.idl | 4 ++-- accessible/interfaces/nsIAccessibleText.idl | 2 +- accessible/interfaces/nsIAccessibleTextRange.idl | 2 +- accessible/interfaces/nsIAccessibleTypes.idl | 4 ++-- accessible/interfaces/nsIAccessibleValue.idl | 2 +- accessible/interfaces/nsIXBLAccessible.idl | 2 +- 19 files changed, 23 insertions(+), 23 deletions(-) diff --git a/accessible/interfaces/nsIAccessible.idl b/accessible/interfaces/nsIAccessible.idl index f707780723b3..9048e7644130 100644 --- a/accessible/interfaces/nsIAccessible.idl +++ b/accessible/interfaces/nsIAccessible.idl @@ -30,7 +30,7 @@ class Accessible; * Mozilla creates the implementations of nsIAccessible on demand. * See http://www.mozilla.org/projects/ui/accessibility for more information. */ -[scriptable, uuid(de2869d9-563c-4943-996b-31a4daa4d097)] +[scriptable, builtinclass, uuid(de2869d9-563c-4943-996b-31a4daa4d097)] interface nsIAccessible : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleApplication.idl b/accessible/interfaces/nsIAccessibleApplication.idl index 037e833595fd..f3e472fed862 100644 --- a/accessible/interfaces/nsIAccessibleApplication.idl +++ b/accessible/interfaces/nsIAccessibleApplication.idl @@ -9,7 +9,7 @@ * This interface is implemented by top level accessible object in hierarchy and * provides information about application. */ -[scriptable, uuid(79251626-387c-4531-89f3-680d31d6cf05)] +[scriptable, builtinclass, uuid(79251626-387c-4531-89f3-680d31d6cf05)] interface nsIAccessibleApplication : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleDocument.idl b/accessible/interfaces/nsIAccessibleDocument.idl index 7e10bef8f3c0..071847dd2957 100644 --- a/accessible/interfaces/nsIAccessibleDocument.idl +++ b/accessible/interfaces/nsIAccessibleDocument.idl @@ -19,7 +19,7 @@ interface mozIDOMWindowProxy; * the root node of a document or you can get one from * nsIAccessible::GetDocument(). */ -[scriptable, uuid(5cad5f91-fcce-40e7-913e-4671701d19b4)] +[scriptable, builtinclass, uuid(5cad5f91-fcce-40e7-913e-4671701d19b4)] interface nsIAccessibleDocument : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleEditableText.idl b/accessible/interfaces/nsIAccessibleEditableText.idl index e8144d5d71ba..ac5d9743791f 100644 --- a/accessible/interfaces/nsIAccessibleEditableText.idl +++ b/accessible/interfaces/nsIAccessibleEditableText.idl @@ -6,7 +6,7 @@ #include "nsISupports.idl" -[scriptable, uuid(28915cca-3366-4034-ba1d-b7afb9b37639)] +[scriptable, builtinclass, uuid(28915cca-3366-4034-ba1d-b7afb9b37639)] interface nsIAccessibleEditableText : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleHyperLink.idl b/accessible/interfaces/nsIAccessibleHyperLink.idl index e4477baa3443..e2926d4f0f51 100644 --- a/accessible/interfaces/nsIAccessibleHyperLink.idl +++ b/accessible/interfaces/nsIAccessibleHyperLink.idl @@ -13,7 +13,7 @@ interface nsIAccessible; * A cross-platform interface that supports hyperlink-specific properties and * methods. Anchors, image maps, xul:labels with class="text-link" implement this interface. */ -[scriptable, uuid(883643d4-93a5-4f32-922c-6f06e01363c1)] +[scriptable, builtinclass, uuid(883643d4-93a5-4f32-922c-6f06e01363c1)] interface nsIAccessibleHyperLink : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleHyperText.idl b/accessible/interfaces/nsIAccessibleHyperText.idl index 5b9c23261502..6e34f2a90961 100644 --- a/accessible/interfaces/nsIAccessibleHyperText.idl +++ b/accessible/interfaces/nsIAccessibleHyperText.idl @@ -15,7 +15,7 @@ * Current implementation assumes every embedded object is a link. */ -[scriptable, uuid(b33684e2-090c-4e1d-a3d9-f4b46f4237b9)] +[scriptable, builtinclass, uuid(b33684e2-090c-4e1d-a3d9-f4b46f4237b9)] interface nsIAccessibleHyperText : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleImage.idl b/accessible/interfaces/nsIAccessibleImage.idl index f0a544ed8457..d9980c0cc4cb 100644 --- a/accessible/interfaces/nsIAccessibleImage.idl +++ b/accessible/interfaces/nsIAccessibleImage.idl @@ -5,7 +5,7 @@ #include "nsISupports.idl" -[scriptable, uuid(09086623-0f09-4310-ac56-c2cda7c29648)] +[scriptable, builtinclass, uuid(09086623-0f09-4310-ac56-c2cda7c29648)] interface nsIAccessibleImage : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessiblePivot.idl b/accessible/interfaces/nsIAccessiblePivot.idl index 76d2bfd753d4..c9e21230ed8a 100644 --- a/accessible/interfaces/nsIAccessiblePivot.idl +++ b/accessible/interfaces/nsIAccessiblePivot.idl @@ -20,7 +20,7 @@ interface nsIAccessiblePivotObserver; * provides traversal methods to move the pivot to next/prev state that complies * to a given rule. */ -[scriptable, uuid(81fe5144-059b-42db-bd3a-f6ce3158d5e9)] +[scriptable, builtinclass, uuid(81fe5144-059b-42db-bd3a-f6ce3158d5e9)] interface nsIAccessiblePivot : nsISupports { const TextBoundaryType CHAR_BOUNDARY = 0; @@ -191,7 +191,7 @@ interface nsIAccessiblePivot : nsISupports /** * An observer interface for pivot changes. */ -[scriptable, uuid(6006e502-3861-49bd-aba1-fa6d2e74e237)] +[scriptable, builtinclass, uuid(6006e502-3861-49bd-aba1-fa6d2e74e237)] interface nsIAccessiblePivotObserver : nsISupports { /** @@ -213,7 +213,7 @@ interface nsIAccessiblePivotObserver : nsISupports in boolean aIsFromUserInput); }; -[scriptable, uuid(e197460d-1eff-4247-b4bb-a43be1840dae)] +[scriptable, builtinclass, uuid(e197460d-1eff-4247-b4bb-a43be1840dae)] interface nsIAccessibleTraversalRule : nsISupports { /* Ignore this accessible object */ diff --git a/accessible/interfaces/nsIAccessibleRelation.idl b/accessible/interfaces/nsIAccessibleRelation.idl index e2ab38981911..dde05672c7e4 100644 --- a/accessible/interfaces/nsIAccessibleRelation.idl +++ b/accessible/interfaces/nsIAccessibleRelation.idl @@ -11,7 +11,7 @@ interface nsIAccessible; /** * This interface gives access to an accessible's set of relations. */ -[scriptable, uuid(55b308c4-2ae4-46bc-b4cd-4d4370e0a660)] +[scriptable, builtinclass, uuid(55b308c4-2ae4-46bc-b4cd-4d4370e0a660)] interface nsIAccessibleRelation : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleRetrieval.idl b/accessible/interfaces/nsIAccessibleRetrieval.idl index 168d4a5095d2..15a44769f381 100644 --- a/accessible/interfaces/nsIAccessibleRetrieval.idl +++ b/accessible/interfaces/nsIAccessibleRetrieval.idl @@ -16,7 +16,7 @@ interface nsIAccessiblePivot; * nsIAccessible for a given DOM node. More documentation at: * http://www.mozilla.org/projects/ui/accessibility */ -[scriptable, uuid(17f86615-1a3d-4021-b227-3a2ef5cbffd8)] +[scriptable, builtinclass, uuid(17f86615-1a3d-4021-b227-3a2ef5cbffd8)] interface nsIAccessibleRetrieval : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleRole.idl b/accessible/interfaces/nsIAccessibleRole.idl index f04af90ae724..16b379d604b7 100644 --- a/accessible/interfaces/nsIAccessibleRole.idl +++ b/accessible/interfaces/nsIAccessibleRole.idl @@ -8,7 +8,7 @@ /** * Defines cross platform (Gecko) roles. */ -[scriptable, uuid(05a9f33f-dcfd-4e7b-b825-138ba784c1f5)] +[scriptable, builtinclass, uuid(05a9f33f-dcfd-4e7b-b825-138ba784c1f5)] interface nsIAccessibleRole : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleSelectable.idl b/accessible/interfaces/nsIAccessibleSelectable.idl index 8f75092227dd..dff2677e20d8 100644 --- a/accessible/interfaces/nsIAccessibleSelectable.idl +++ b/accessible/interfaces/nsIAccessibleSelectable.idl @@ -11,7 +11,7 @@ interface nsIArray; /** * An accessibility interface for selectable widgets. */ -[scriptable, uuid(8efb03d4-1354-4875-94cf-261336057626)] +[scriptable, builtinclass, uuid(8efb03d4-1354-4875-94cf-261336057626)] interface nsIAccessibleSelectable : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleStates.idl b/accessible/interfaces/nsIAccessibleStates.idl index ea9361e4201f..77a395468329 100644 --- a/accessible/interfaces/nsIAccessibleStates.idl +++ b/accessible/interfaces/nsIAccessibleStates.idl @@ -5,7 +5,7 @@ #include "nsISupports.idl" -[scriptable, uuid(f1e0fbb7-fde4-4519-9383-2bcbee428513)] +[scriptable, builtinclass, uuid(f1e0fbb7-fde4-4519-9383-2bcbee428513)] interface nsIAccessibleStates : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleTable.idl b/accessible/interfaces/nsIAccessibleTable.idl index 539428bae38c..8d1469d6371e 100644 --- a/accessible/interfaces/nsIAccessibleTable.idl +++ b/accessible/interfaces/nsIAccessibleTable.idl @@ -9,7 +9,7 @@ interface nsIAccessible; interface nsIArray; -[scriptable, uuid(cb0bf7b9-117e-40e2-9e46-189c3d43ce4a)] +[scriptable, builtinclass, uuid(cb0bf7b9-117e-40e2-9e46-189c3d43ce4a)] interface nsIAccessibleTable : nsISupports { /** @@ -221,7 +221,7 @@ interface nsIAccessibleTable : nsISupports }; -[scriptable, uuid(654e296d-fae6-452b-987d-746b20b9514b)] +[scriptable, builtinclass, uuid(654e296d-fae6-452b-987d-746b20b9514b)] interface nsIAccessibleTableCell : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleText.idl b/accessible/interfaces/nsIAccessibleText.idl index b2d8631ab920..7612fbfe2398 100644 --- a/accessible/interfaces/nsIAccessibleText.idl +++ b/accessible/interfaces/nsIAccessibleText.idl @@ -13,7 +13,7 @@ interface nsIArray; interface nsIPersistentProperties; interface nsIAccessibleTextRange; -[scriptable, uuid(93ad2ca1-f12b-4ab9-a793-95d9fa9d1774)] +[scriptable, builtinclass, uuid(93ad2ca1-f12b-4ab9-a793-95d9fa9d1774)] interface nsIAccessibleText : nsISupports { // In parameters for character offsets: diff --git a/accessible/interfaces/nsIAccessibleTextRange.idl b/accessible/interfaces/nsIAccessibleTextRange.idl index 4ce7eb1f7b96..1c351c734c91 100644 --- a/accessible/interfaces/nsIAccessibleTextRange.idl +++ b/accessible/interfaces/nsIAccessibleTextRange.idl @@ -13,7 +13,7 @@ interface nsIVariant; /** * A range representing a piece of text in the document. */ -[scriptable, uuid(c4515623-55f9-4543-a3d5-c1e9afa588f4)] +[scriptable, builtinclass, uuid(c4515623-55f9-4543-a3d5-c1e9afa588f4)] interface nsIAccessibleTextRange : nsISupports { readonly attribute nsIAccessibleText startContainer; diff --git a/accessible/interfaces/nsIAccessibleTypes.idl b/accessible/interfaces/nsIAccessibleTypes.idl index bcb353e68c21..5f0ac42749c1 100644 --- a/accessible/interfaces/nsIAccessibleTypes.idl +++ b/accessible/interfaces/nsIAccessibleTypes.idl @@ -9,7 +9,7 @@ * These constants control the scrolling of an object or substring into a * window. Note, keep them synchronized with IA2ScrollType. */ -[scriptable, uuid(05cd38b1-94b3-4cdf-8371-3935a9611405)] +[scriptable, builtinclass, uuid(05cd38b1-94b3-4cdf-8371-3935a9611405)] interface nsIAccessibleScrollType : nsISupports { /** @@ -59,7 +59,7 @@ interface nsIAccessibleScrollType : nsISupports /** * These constants define which coordinate system a point is located in. */ -[scriptable, uuid(c9fbdf10-619e-436f-bf4b-8566686f1577)] +[scriptable, builtinclass, uuid(c9fbdf10-619e-436f-bf4b-8566686f1577)] interface nsIAccessibleCoordinateType : nsISupports { /** diff --git a/accessible/interfaces/nsIAccessibleValue.idl b/accessible/interfaces/nsIAccessibleValue.idl index e034b817bc6f..886fcb8fed8e 100644 --- a/accessible/interfaces/nsIAccessibleValue.idl +++ b/accessible/interfaces/nsIAccessibleValue.idl @@ -6,7 +6,7 @@ #include "nsISupports.idl" -[scriptable, uuid(42a1e1dc-58cf-419d-bff0-ed3314c70016)] +[scriptable, builtinclass, uuid(42a1e1dc-58cf-419d-bff0-ed3314c70016)] interface nsIAccessibleValue : nsISupports { readonly attribute double maximumValue; diff --git a/accessible/interfaces/nsIXBLAccessible.idl b/accessible/interfaces/nsIXBLAccessible.idl index a065da22b07e..054ee62bd70b 100644 --- a/accessible/interfaces/nsIXBLAccessible.idl +++ b/accessible/interfaces/nsIXBLAccessible.idl @@ -10,7 +10,7 @@ * XBL controls can implement this interface to provide own implementation of * accessible properties. */ -[scriptable, uuid(3716eb86-166b-445b-a94a-9b522fee96e6)] +[scriptable, builtinclass, uuid(3716eb86-166b-445b-a94a-9b522fee96e6)] interface nsIXBLAccessible : nsISupports { /** From 7712664858f24d895cfa8e424a21afbf15492af3 Mon Sep 17 00:00:00 2001 From: JerryShih Date: Fri, 22 Jul 2016 07:42:00 -0400 Subject: [PATCH 062/135] Bug 1288598 - Handle gl.getFramebufferAttachmentParameter() call for default framebuffer. r=jgilbert --- dom/canvas/WebGLContextGL.cpp | 73 ++++++++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 9 deletions(-) diff --git a/dom/canvas/WebGLContextGL.cpp b/dom/canvas/WebGLContextGL.cpp index 8b7ac37d519b..a33b0b0d367f 100644 --- a/dom/canvas/WebGLContextGL.cpp +++ b/dom/canvas/WebGLContextGL.cpp @@ -776,6 +776,25 @@ WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx, switch (pname) { case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE: + switch (attachment) { + case LOCAL_GL_BACK: + break; + case LOCAL_GL_DEPTH: + if (!mOptions.depth) { + return JS::Int32Value(LOCAL_GL_NONE); + } + break; + case LOCAL_GL_STENCIL: + if (!mOptions.stencil) { + return JS::Int32Value(LOCAL_GL_NONE); + } + break; + default: + ErrorInvalidEnum("%s: With the default framebuffer, can only query COLOR, DEPTH," + " or STENCIL for GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE", + funcName); + return JS::NullValue(); + } return JS::Int32Value(LOCAL_GL_FRAMEBUFFER_DEFAULT); case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME: @@ -791,27 +810,63 @@ WebGLContext::GetFramebufferAttachmentParameter(JSContext* cx, return JS::NumberValue(0); case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE: - if (attachment == LOCAL_GL_BACK) - return JS::NumberValue(mOptions.alpha ? 8 : 0); + if (attachment == LOCAL_GL_BACK) { + if (mOptions.alpha) { + return JS::NumberValue(8); + } + ErrorInvalidOperation("The default framebuffer doesn't contain an alpha buffer"); + return JS::NullValue(); + } return JS::NumberValue(0); case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE: - if (attachment == LOCAL_GL_DEPTH) - return JS::NumberValue(mOptions.depth ? 24 : 0); + if (attachment == LOCAL_GL_DEPTH) { + if (mOptions.depth) { + return JS::NumberValue(24); + } + ErrorInvalidOperation("The default framebuffer doesn't contain an depth buffer"); + return JS::NullValue(); + } return JS::NumberValue(0); case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE: - if (attachment == LOCAL_GL_STENCIL) - return JS::NumberValue(mOptions.stencil ? 8 : 0); + if (attachment == LOCAL_GL_STENCIL) { + if (mOptions.stencil) { + return JS::NumberValue(8); + } + ErrorInvalidOperation("The default framebuffer doesn't contain an stencil buffer"); + return JS::NullValue(); + } return JS::NumberValue(0); case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: - if (attachment == LOCAL_GL_STENCIL) - return JS::NumberValue(LOCAL_GL_UNSIGNED_INT); - else + if (attachment == LOCAL_GL_STENCIL) { + if (mOptions.stencil) { + return JS::NumberValue(LOCAL_GL_UNSIGNED_INT); + } + ErrorInvalidOperation("The default framebuffer doesn't contain an stencil buffer"); + } else if (attachment == LOCAL_GL_DEPTH) { + if (mOptions.depth) { + return JS::NumberValue(LOCAL_GL_UNSIGNED_NORMALIZED); + } + ErrorInvalidOperation("The default framebuffer doesn't contain an depth buffer"); + } else { // LOCAL_GL_BACK return JS::NumberValue(LOCAL_GL_UNSIGNED_NORMALIZED); + } + return JS::NullValue(); case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING: + if (attachment == LOCAL_GL_STENCIL) { + if (!mOptions.stencil) { + ErrorInvalidOperation("The default framebuffer doesn't contain an stencil buffer"); + return JS::NullValue(); + } + } else if (attachment == LOCAL_GL_DEPTH) { + if (!mOptions.depth) { + ErrorInvalidOperation("The default framebuffer doesn't contain an depth buffer"); + return JS::NullValue(); + } + } return JS::NumberValue(LOCAL_GL_LINEAR); } From a9bb41be6301f072ded5e93cd36b886e52040180 Mon Sep 17 00:00:00 2001 From: JerryShih Date: Thu, 21 Jul 2016 18:37:00 -0400 Subject: [PATCH 063/135] Bug 1288351 - Handle gl.getFramebufferAttachmentParameter() FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE query for DS format. r=jgilbert --- dom/canvas/WebGLFramebuffer.cpp | 39 +++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/dom/canvas/WebGLFramebuffer.cpp b/dom/canvas/WebGLFramebuffer.cpp index ea0b5f9e0cf7..b133e6caf712 100644 --- a/dom/canvas/WebGLFramebuffer.cpp +++ b/dom/canvas/WebGLFramebuffer.cpp @@ -528,7 +528,7 @@ WebGLFBAttachPoint::GetParameter(const char* funcName, WebGLContext* webgl, JSCo if (!usage) return JS::NullValue(); - const auto format = usage->format; + auto format = usage->format; GLint ret = 0; switch (pname) { @@ -559,10 +559,38 @@ WebGLFBAttachPoint::GetParameter(const char* funcName, WebGLContext* webgl, JSCo case LOCAL_GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE: MOZ_ASSERT(attachment != LOCAL_GL_DEPTH_STENCIL_ATTACHMENT); + if (format->componentType == webgl::ComponentType::Special) { + // Special format is used for DS mixed format(e.g. D24S8 and D32FS8). + MOZ_ASSERT(format->unsizedFormat == webgl::UnsizedFormat::DS); + MOZ_ASSERT(attachment == LOCAL_GL_DEPTH_ATTACHMENT || + attachment == LOCAL_GL_STENCIL_ATTACHMENT); + + if (attachment == LOCAL_GL_DEPTH_ATTACHMENT) { + switch (format->effectiveFormat) { + case webgl::EffectiveFormat::DEPTH24_STENCIL8: + format = webgl::GetFormat(webgl::EffectiveFormat::DEPTH_COMPONENT24); + break; + case webgl::EffectiveFormat::DEPTH32F_STENCIL8: + format = webgl::GetFormat(webgl::EffectiveFormat::DEPTH_COMPONENT32F); + break; + default: + MOZ_ASSERT(false, "no matched DS format"); + break; + } + } else if (attachment == LOCAL_GL_STENCIL_ATTACHMENT) { + switch (format->effectiveFormat) { + case webgl::EffectiveFormat::DEPTH24_STENCIL8: + case webgl::EffectiveFormat::DEPTH32F_STENCIL8: + format = webgl::GetFormat(webgl::EffectiveFormat::STENCIL_INDEX8); + break; + default: + MOZ_ASSERT(false, "no matched DS format"); + break; + } + } + } + switch (format->componentType) { - case webgl::ComponentType::Special: - MOZ_ASSERT(false, "Should never happen."); - break; case webgl::ComponentType::None: ret = LOCAL_GL_NONE; break; @@ -581,6 +609,9 @@ WebGLFBAttachPoint::GetParameter(const char* funcName, WebGLContext* webgl, JSCo case webgl::ComponentType::Float: ret = LOCAL_GL_FLOAT; break; + default: + MOZ_ASSERT(false, "No matched component type"); + break; } break; From 1c9ae94a7e6e814df1f5fb412c4f870a5d95538b Mon Sep 17 00:00:00 2001 From: Oriol Date: Fri, 22 Jul 2016 10:39:00 -0400 Subject: [PATCH 064/135] Bug 1288515 - Rename GetScriptedProxyHandlerObject to ScriptedProxyHandler::handlerObject and make it public. r=jimb --- js/src/proxy/ScriptedProxyHandler.cpp | 30 +++++++++++++-------------- js/src/proxy/ScriptedProxyHandler.h | 2 ++ 2 files changed, 17 insertions(+), 15 deletions(-) diff --git a/js/src/proxy/ScriptedProxyHandler.cpp b/js/src/proxy/ScriptedProxyHandler.cpp index d4051c6a6351..7cab520c2166 100644 --- a/js/src/proxy/ScriptedProxyHandler.cpp +++ b/js/src/proxy/ScriptedProxyHandler.cpp @@ -126,8 +126,8 @@ IsCompatiblePropertyDescriptor(JSContext* cx, bool extensible, Handleas().handler() == &ScriptedProxyHandler::singleton); return proxy->as().extra(ScriptedProxyHandler::HANDLER_EXTRA).toObjectOrNull(); @@ -171,7 +171,7 @@ ScriptedProxyHandler::getPrototype(JSContext* cx, HandleObject proxy, MutableHandleObject protop) const { // Steps 1-3. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; @@ -242,7 +242,7 @@ ScriptedProxyHandler::setPrototype(JSContext* cx, HandleObject proxy, HandleObje ObjectOpResult& result) const { // Steps 1-4. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; @@ -333,7 +333,7 @@ ScriptedProxyHandler::preventExtensions(JSContext* cx, HandleObject proxy, ObjectOpResult& result) const { // Steps 1-3. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; @@ -389,7 +389,7 @@ bool ScriptedProxyHandler::isExtensible(JSContext* cx, HandleObject proxy, bool* extensible) const { // Steps 1-3. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; @@ -441,7 +441,7 @@ ScriptedProxyHandler::getOwnPropertyDescriptor(JSContext* cx, HandleObject proxy MutableHandle desc) const { // Steps 2-4. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; @@ -560,7 +560,7 @@ ScriptedProxyHandler::defineProperty(JSContext* cx, HandleObject proxy, HandleId Handle desc, ObjectOpResult& result) const { // Steps 2-4. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; @@ -699,7 +699,7 @@ bool ScriptedProxyHandler::ownPropertyKeys(JSContext* cx, HandleObject proxy, AutoIdVector& props) const { // Steps 1-3. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; @@ -838,7 +838,7 @@ ScriptedProxyHandler::delete_(JSContext* cx, HandleObject proxy, HandleId id, ObjectOpResult& result) const { // Steps 2-4. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; @@ -897,7 +897,7 @@ bool ScriptedProxyHandler::has(JSContext* cx, HandleObject proxy, HandleId id, bool* bp) const { // Steps 2-4. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; @@ -967,7 +967,7 @@ ScriptedProxyHandler::get(JSContext* cx, HandleObject proxy, HandleValue receive MutableHandleValue vp) const { // Steps 2-4. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; @@ -1042,7 +1042,7 @@ ScriptedProxyHandler::set(JSContext* cx, HandleObject proxy, HandleId id, Handle HandleValue receiver, ObjectOpResult& result) const { // Steps 2-4. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; @@ -1118,7 +1118,7 @@ bool ScriptedProxyHandler::call(JSContext* cx, HandleObject proxy, const CallArgs& args) const { // Steps 1-3. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; @@ -1165,7 +1165,7 @@ bool ScriptedProxyHandler::construct(JSContext* cx, HandleObject proxy, const CallArgs& args) const { // Steps 1-3. - RootedObject handler(cx, GetScriptedProxyHandlerObject(proxy)); + RootedObject handler(cx, ScriptedProxyHandler::handlerObject(proxy)); if (!handler) { JS_ReportErrorNumber(cx, GetErrorMessage, nullptr, JSMSG_PROXY_REVOKED); return false; diff --git a/js/src/proxy/ScriptedProxyHandler.h b/js/src/proxy/ScriptedProxyHandler.h index 7a45d5711590..5e4c316c23d1 100644 --- a/js/src/proxy/ScriptedProxyHandler.h +++ b/js/src/proxy/ScriptedProxyHandler.h @@ -92,6 +92,8 @@ class ScriptedProxyHandler : public BaseProxyHandler // The "function extended" slot index in which the revocation object is stored. Per spec, this // is to be cleared during the first revocation. static const int REVOKE_SLOT = 0; + + static JSObject* handlerObject(const JSObject* proxy); }; bool From 3f8f83a0a17eba6308166ebef61f7d3c060d8f1c Mon Sep 17 00:00:00 2001 From: Oriol Date: Fri, 22 Jul 2016 10:50:00 -0400 Subject: [PATCH 065/135] Bug 1282257 - Create accessor properties in Debugger.Object.prototype to expose the target and the handler of a proxy object. r=jimb --- js/src/doc/Debugger/Debugger.Object.md | 31 ++++----- js/src/jit-test/tests/debug/Object-proxy.js | 32 +++++++++ js/src/vm/Debugger.cpp | 77 +++++++++++++++++++++ js/src/vm/Debugger.h | 8 +++ 4 files changed, 129 insertions(+), 19 deletions(-) create mode 100644 js/src/jit-test/tests/debug/Object-proxy.js diff --git a/js/src/doc/Debugger/Debugger.Object.md b/js/src/doc/Debugger/Debugger.Object.md index e269cc67f8fd..e603b45947aa 100644 --- a/js/src/doc/Debugger/Debugger.Object.md +++ b/js/src/doc/Debugger/Debugger.Object.md @@ -188,26 +188,19 @@ from its prototype: function, not a debuggee function, or not a function at all, this is `undefined`. +`isProxy` +: If the referent is a (scripted) proxy, return `true`. If the referent is not + a (scripted) proxy, return `false`. + +`proxyTarget` +: If the referent is a (scripted) proxy, return a `Debugger.Object` instance + referring to the ECMAScript `[[ProxyTarget]]` of the referent. If the referent + is not a (scripted) proxy, return `undefined`. + `proxyHandler` -: If the referent is a proxy whose handler object was allocated by - debuggee code, this is its handler object—the object whose methods are - invoked to implement accesses of the proxy's properties. If the referent - is not a proxy whose handler object was allocated by debuggee code, this - is `null`. - -`proxyCallTrap` -: If the referent is a function proxy whose handler object was allocated - by debuggee code, this is its call trap function—the function called - when the function proxy is called. If the referent is not a function - proxy whose handler object was allocated by debuggee code, this is - `null`. - -`proxyConstructTrap` -: If the referent is a function proxy whose handler object was allocated - by debuggee code, its construction trap function—the function called - when the function proxy is called via a `new` expression. If the - referent is not a function proxy whose handler object was allocated by - debuggee code, this is `null`. +: If the referent is a (scripted) proxy, return a `Debugger.Object` instance + referring to the ECMAScript `[[ProxyHandler]]` of the referent. If the referent + is not a (scripted) proxy, return `undefined`. `promiseState` : If the referent is a [`Promise`][promise], this is an object describing diff --git a/js/src/jit-test/tests/debug/Object-proxy.js b/js/src/jit-test/tests/debug/Object-proxy.js new file mode 100644 index 000000000000..89bae27e14ce --- /dev/null +++ b/js/src/jit-test/tests/debug/Object-proxy.js @@ -0,0 +1,32 @@ +// Debugger.Object.prototype.isProxy recognizes (scripted) proxies. +// Debugger.Object.prototype.proxyTarget exposes the [[Proxytarget]] of a proxy. +// Debugger.Object.prototype.proxyHandler exposes the [[ProxyHandler]] of a proxy. + +var g = newGlobal(); +var dbg = new Debugger; +var gDO = dbg.addDebuggee(g); + +g.eval('var target = [1,2,3];'); +g.eval('var handler = {has: ()=>false};'); +g.eval('var proxy = new Proxy(target, handler);'); +g.eval('var proxyProxy = new Proxy(proxy, proxy);'); + +var target = gDO.getOwnPropertyDescriptor('target').value; +var handler = gDO.getOwnPropertyDescriptor('handler').value; +var proxy = gDO.getOwnPropertyDescriptor('proxy').value; +var proxyProxy = gDO.getOwnPropertyDescriptor('proxyProxy').value; + +assertEq(target.isProxy, false); +assertEq(handler.isProxy, false); +assertEq(proxy.isProxy, true); +assertEq(proxyProxy.isProxy, true); + +assertEq(target.proxyTarget, undefined); +assertEq(handler.proxyTarget, undefined); +assertEq(proxy.proxyTarget, target); +assertEq(proxyProxy.proxyTarget, proxy); + +assertEq(target.proxyHandler, undefined); +assertEq(handler.proxyHandler, undefined); +assertEq(proxy.proxyHandler, handler); +assertEq(proxyProxy.proxyTarget, proxy); diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index bc49f669ceef..75cec31cbef0 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -45,6 +45,8 @@ #include "vm/NativeObject-inl.h" #include "vm/Stack-inl.h" +#include "proxy/ScriptedProxyHandler.h" + using namespace js; using JS::dbg::AutoEntryMonitor; @@ -8475,6 +8477,50 @@ DebuggerObject::errorMessageNameGetter(JSContext *cx, unsigned argc, Value* vp) return true; } +/* static */ bool +DebuggerObject::isProxyGetter(JSContext* cx, unsigned argc, Value* vp) +{ + THIS_DEBUGOBJECT(cx, argc, vp, "get isProxy", args, object) + + args.rval().setBoolean(object->isScriptedProxy()); + return true; +} + +/* static */ bool +DebuggerObject::proxyTargetGetter(JSContext* cx, unsigned argc, Value* vp) +{ + THIS_DEBUGOBJECT(cx, argc, vp, "get proxyTarget", args, object) + + if (!object->isScriptedProxy()) { + args.rval().setUndefined(); + return true; + } + + Rooted result(cx); + if (!DebuggerObject::scriptedProxyTarget(cx, object, &result)) + return false; + + args.rval().setObject(*result); + return true; +} + +/* static */ bool +DebuggerObject::proxyHandlerGetter(JSContext* cx, unsigned argc, Value* vp) +{ + THIS_DEBUGOBJECT(cx, argc, vp, "get proxyHandler", args, object) + + if (!object->isScriptedProxy()) { + args.rval().setUndefined(); + return true; + } + Rooted result(cx); + if (!DebuggerObject::scriptedProxyHandler(cx, object, &result)) + return false; + + args.rval().setObject(*result); + return true; +} + #ifdef SPIDERMONKEY_PROMISE /* static */ bool DebuggerObject::isPromiseGetter(JSContext* cx, unsigned argc, Value* vp) @@ -9045,6 +9091,9 @@ const JSPropertySpec DebuggerObject::properties_[] = { JS_PSG("global", DebuggerObject::globalGetter, 0), JS_PSG("allocationSite", DebuggerObject::allocationSiteGetter, 0), JS_PSG("errorMessageName", DebuggerObject::errorMessageNameGetter, 0), + JS_PSG("isProxy", DebuggerObject::isProxyGetter, 0), + JS_PSG("proxyTarget", DebuggerObject::proxyTargetGetter, 0), + JS_PSG("proxyHandler", DebuggerObject::proxyHandlerGetter, 0), JS_PS_END }; @@ -9164,6 +9213,12 @@ DebuggerObject::isGlobal() const return referent()->is(); } +bool +DebuggerObject::isScriptedProxy() const +{ + return js::IsScriptedProxy(referent()); +} + /* static */ bool DebuggerObject::isPromise(JSContext* cx, Handle object, bool& result) @@ -9839,6 +9894,28 @@ DebuggerObject::requireGlobal(JSContext* cx, Handle object) return true; } +/* static */ bool +DebuggerObject::scriptedProxyTarget(JSContext* cx, Handle object, + MutableHandle result) +{ + MOZ_ASSERT(object->isScriptedProxy()); + RootedObject referent(cx, object->referent()); + Debugger* dbg = object->owner(); + RootedObject unwrapped(cx, js::GetProxyTargetObject(referent)); + return dbg->wrapDebuggeeObject(cx, unwrapped, result); +} + +/* static */ bool +DebuggerObject::scriptedProxyHandler(JSContext* cx, Handle object, + MutableHandle result) +{ + MOZ_ASSERT(object->isScriptedProxy()); + RootedObject referent(cx, object->referent()); + Debugger* dbg = object->owner(); + RootedObject unwrapped(cx, ScriptedProxyHandler::handlerObject(referent)); + return dbg->wrapDebuggeeObject(cx, unwrapped, result); +} + /*** Debugger.Environment ************************************************************************/ diff --git a/js/src/vm/Debugger.h b/js/src/vm/Debugger.h index 3914d379f9a5..524a3635f480 100644 --- a/js/src/vm/Debugger.h +++ b/js/src/vm/Debugger.h @@ -1238,6 +1238,10 @@ class DebuggerObject : public NativeObject MutableHandleObject result); static MOZ_MUST_USE bool getErrorMessageName(JSContext* cx, Handle object, MutableHandleString result); + static MOZ_MUST_USE bool scriptedProxyTarget(JSContext* cx, Handle object, + MutableHandle result); + static MOZ_MUST_USE bool scriptedProxyHandler(JSContext* cx, Handle object, + MutableHandle result); // Methods static MOZ_MUST_USE bool isExtensible(JSContext* cx, Handle object, @@ -1288,6 +1292,7 @@ class DebuggerObject : public NativeObject bool isBoundFunction() const; bool isArrowFunction() const; bool isGlobal() const; + bool isScriptedProxy() const; JSAtom* name() const; JSAtom* displayName() const; @@ -1336,6 +1341,9 @@ class DebuggerObject : public NativeObject static MOZ_MUST_USE bool globalGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool allocationSiteGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool errorMessageNameGetter(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool isProxyGetter(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool proxyTargetGetter(JSContext* cx, unsigned argc, Value* vp); + static MOZ_MUST_USE bool proxyHandlerGetter(JSContext* cx, unsigned argc, Value* vp); #ifdef SPIDERMONKEY_PROMISE static MOZ_MUST_USE bool isPromiseGetter(JSContext* cx, unsigned argc, Value* vp); static MOZ_MUST_USE bool promiseStateGetter(JSContext* cx, unsigned argc, Value* vp); From a713ce246bdbdef89061dda676de088e6c11b82f Mon Sep 17 00:00:00 2001 From: Jed Davis Date: Fri, 22 Jul 2016 08:50:00 -0400 Subject: [PATCH 066/135] Bug 1287971 - Disable sandboxing in Linux ASan builds. r=jhector ASan itself can be accomodated under sandboxing, but LSan can't. Also fixes bug 1287437. --- old-configure.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/old-configure.in b/old-configure.in index 868f4324b2a6..bb246a1fb6bb 100644 --- a/old-configure.in +++ b/old-configure.in @@ -4515,8 +4515,9 @@ AC_SUBST(MOZ_NO_EV_CERTS) dnl ======================================================== dnl = Sandboxing support dnl ======================================================== -if test -n "$MOZ_TSAN"; then +if test -n "$MOZ_TSAN" -o -n "$MOZ_ASAN"; then # Bug 1182565: TSan conflicts with sandboxing on Linux. + # Bug 1287971: LSan also conflicts with sandboxing on Linux. case $OS_TARGET in Linux|Android) MOZ_SANDBOX= From 3822028a8abb53c7b1a218c349208fccec77a340 Mon Sep 17 00:00:00 2001 From: Jinank Jain Date: Thu, 21 Jul 2016 18:12:49 -0400 Subject: [PATCH 067/135] Bug 1284441 - Remove unnecessary cast from ExpressionDecompiler::decompilePC. r=arai --- js/src/jsopcode.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/src/jsopcode.cpp b/js/src/jsopcode.cpp index 9ae2975b8590..a62748e37348 100644 --- a/js/src/jsopcode.cpp +++ b/js/src/jsopcode.cpp @@ -1213,7 +1213,7 @@ ExpressionDecompiler::decompilePC(jsbytecode* pc) return decompilePCForStackOperand(pc, -int32_t(GET_ARGC(pc) + 2)) && write("(...)"); case JSOP_SPREADCALL: - return decompilePCForStackOperand(pc, -int32_t(3)) && + return decompilePCForStackOperand(pc, -3) && write("(...)"); case JSOP_NEWARRAY: return write("[]"); From 53ccdb52688742faf31cc053b004551c046d5f4f Mon Sep 17 00:00:00 2001 From: Lee Salzman Date: Fri, 22 Jul 2016 14:11:59 -0400 Subject: [PATCH 068/135] Bug 1288762 - Fix gfxFontconfigFontBase constructor. r=me --- gfx/thebes/gfxFontconfigUtils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/gfx/thebes/gfxFontconfigUtils.cpp b/gfx/thebes/gfxFontconfigUtils.cpp index 27c2237f27b9..5bf606c13e25 100644 --- a/gfx/thebes/gfxFontconfigUtils.cpp +++ b/gfx/thebes/gfxFontconfigUtils.cpp @@ -1087,6 +1087,8 @@ gfxFontconfigUtils::ActivateBundledFonts() } } +#endif + gfxFontconfigFontBase::gfxFontconfigFontBase(cairo_scaled_font_t *aScaledFont, FcPattern *aPattern, gfxFontEntry *aFontEntry, @@ -1096,4 +1098,3 @@ gfxFontconfigFontBase::gfxFontconfigFontBase(cairo_scaled_font_t *aScaledFont, { } -#endif From 25504e4a0d37d80b312db0c315e7344934e6a8f1 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 22 Jul 2016 16:19:52 -0400 Subject: [PATCH 069/135] Bug 1288581 part 1. Start tracing the expando object, if any, inside the ExpandoAndGeneration of a shadowing DOM proxy from that proxy's trace hook. r=smaug --- dom/bindings/Codegen.py | 7 ++++++- dom/bindings/DOMJSProxyHandler.cpp | 22 ++++++++++++++++++++++ dom/bindings/DOMJSProxyHandler.h | 11 ++++++++++- 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/dom/bindings/Codegen.py b/dom/bindings/Codegen.py index b18fdf80881a..95c028f5b090 100644 --- a/dom/bindings/Codegen.py +++ b/dom/bindings/Codegen.py @@ -11723,8 +11723,13 @@ class CGDOMJSProxyHandler(CGClass): methods.append(CGDOMJSProxyHandler_call()) methods.append(CGDOMJSProxyHandler_isCallable()) + if descriptor.interface.getExtendedAttribute('OverrideBuiltins'): + parentClass = 'ShadowingDOMProxyHandler' + else: + parentClass = 'mozilla::dom::DOMProxyHandler' + CGClass.__init__(self, 'DOMProxyHandler', - bases=[ClassBase('mozilla::dom::DOMProxyHandler')], + bases=[ClassBase(parentClass)], constructors=constructors, methods=methods) diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index 4a63d4555616..01ea13d5ab24 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -297,5 +297,27 @@ DOMProxyHandler::GetExpandoObject(JSObject *obj) return v.isUndefined() ? nullptr : &v.toObject(); } +// static +void +ShadowingDOMProxyHandler::trace(JSTracer* trc, JSObject* proxy) const +{ + DOMProxyHandler::trace(trc, proxy); + + MOZ_ASSERT(IsDOMProxy(proxy), "expected a DOM proxy object"); + JS::Value v = js::GetProxyExtra(proxy, JSPROXYSLOT_EXPANDO); + MOZ_ASSERT(!v.isObject(), "Should not have expando object directly!"); + + if (v.isUndefined()) { + // This can happen if we GC while creating our object, before we get a + // chance to set up its JSPROXYSLOT_EXPANDO slot. + return; + } + + js::ExpandoAndGeneration* expandoAndGeneration = + static_cast(v.toPrivate()); + JS::TraceEdge(trc, &expandoAndGeneration->expando, + "Shadowing DOM proxy expando"); +} + } // namespace dom } // namespace mozilla diff --git a/dom/bindings/DOMJSProxyHandler.h b/dom/bindings/DOMJSProxyHandler.h index 407730d4c7ee..b99d3f2b9cc4 100644 --- a/dom/bindings/DOMJSProxyHandler.h +++ b/dom/bindings/DOMJSProxyHandler.h @@ -32,7 +32,9 @@ enum { * * If it is, the proxy is initialized with a PrivateValue, which contains a * pointer to a js::ExpandoAndGeneration object; this contains a pointer to - * the actual expando object as well as the "generation" of the object. + * the actual expando object as well as the "generation" of the object. The + * proxy handler will trace the expando object stored in the + * js::ExpandoAndGeneration while the proxy itself is alive. * * If it is not, the proxy is initialized with an UndefinedValue. In * EnsureExpandoObject, it is set to an ObjectValue that points to the @@ -140,6 +142,13 @@ public: static const char family; }; +// Class used by shadowing handlers (the ones that have [OverrideBuiltins]. +// This handles tracing the expando in ExpandoAndGeneration. +class ShadowingDOMProxyHandler : public DOMProxyHandler +{ + virtual void trace(JSTracer* trc, JSObject* proxy) const override; +}; + inline bool IsDOMProxy(JSObject *obj) { const js::Class* clasp = js::GetObjectClass(obj); From ab510337321b952ada9fe18ebc79aa44a2503b8c Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 22 Jul 2016 16:19:52 -0400 Subject: [PATCH 070/135] Bug 1288581 part 2. Stop messing with the ExpandoAndGeneration's expando in CC code, since it's now traced by the reflector proxy. r=smaug --- dom/base/nsDocument.cpp | 14 ++------------ dom/html/HTMLFormElement.cpp | 9 +-------- dom/html/HTMLFormElement.h | 4 ++-- dom/html/nsDOMStringMap.cpp | 9 ++------- js/src/jsfriendapi.h | 3 +-- 5 files changed, 8 insertions(+), 31 deletions(-) diff --git a/dom/base/nsDocument.cpp b/dom/base/nsDocument.cpp index 62ba206943fe..f42e98d7599d 100644 --- a/dom/base/nsDocument.cpp +++ b/dom/base/nsDocument.cpp @@ -1742,10 +1742,6 @@ NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsDocument) if (elm) { elm->MarkForCC(); } - if (tmp->mExpandoAndGeneration.expando.isObject()) { - JS::ExposeObjectToActiveJS( - &(tmp->mExpandoAndGeneration.expando.toObject())); - } return true; } NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_END @@ -1931,13 +1927,7 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_CLASS(nsDocument) -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDocument) - if (tmp->PreservingWrapper()) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mExpandoAndGeneration.expando) - } - NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER -NS_IMPL_CYCLE_COLLECTION_TRACE_END - +NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument) tmp->mInUnlinkOrDeletion = true; @@ -2010,7 +2000,7 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDocument) // else, and not unlink an awful lot here. tmp->mIdentifierMap.Clear(); - tmp->mExpandoAndGeneration.Unlink(); + tmp->mExpandoAndGeneration.OwnerUnlinked(); if (tmp->mAnimationController) { tmp->mAnimationController->Unlink(); diff --git a/dom/html/HTMLFormElement.cpp b/dom/html/HTMLFormElement.cpp index 59db417556c8..7768d55df586 100644 --- a/dom/html/HTMLFormElement.cpp +++ b/dom/html/HTMLFormElement.cpp @@ -145,16 +145,9 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLFormElement, nsGenericHTMLElement) tmp->Clear(); - tmp->mExpandoAndGeneration.Unlink(); + tmp->mExpandoAndGeneration.OwnerUnlinked(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(HTMLFormElement, - nsGenericHTMLElement) - if (tmp->PreservingWrapper()) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mExpandoAndGeneration.expando) - } -NS_IMPL_CYCLE_COLLECTION_TRACE_END - NS_IMPL_ADDREF_INHERITED(HTMLFormElement, Element) NS_IMPL_RELEASE_INHERITED(HTMLFormElement, Element) diff --git a/dom/html/HTMLFormElement.h b/dom/html/HTMLFormElement.h index 11f2d6265a51..ff4d83409821 100644 --- a/dom/html/HTMLFormElement.h +++ b/dom/html/HTMLFormElement.h @@ -120,8 +120,8 @@ public: virtual nsresult Clone(mozilla::dom::NodeInfo *aNodeInfo, nsINode **aResult) const override; - NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(HTMLFormElement, - nsGenericHTMLElement) + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(HTMLFormElement, + nsGenericHTMLElement) /** * Remove an element from this form's list of elements diff --git a/dom/html/nsDOMStringMap.cpp b/dom/html/nsDOMStringMap.cpp index e9cac5e38cb3..0efa6712c1d4 100644 --- a/dom/html/nsDOMStringMap.cpp +++ b/dom/html/nsDOMStringMap.cpp @@ -32,15 +32,10 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsDOMStringMap) tmp->mElement->RemoveMutationObserver(tmp); tmp->mElement = nullptr; } - tmp->mExpandoAndGeneration.Unlink(); + tmp->mExpandoAndGeneration.OwnerUnlinked(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END -NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(nsDOMStringMap) - NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER - if (tmp->PreservingWrapper()) { - NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mExpandoAndGeneration.expando) - } -NS_IMPL_CYCLE_COLLECTION_TRACE_END +NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsDOMStringMap) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsDOMStringMap) NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY diff --git a/js/src/jsfriendapi.h b/js/src/jsfriendapi.h index 5609310bd582..b5906bca57a8 100644 --- a/js/src/jsfriendapi.h +++ b/js/src/jsfriendapi.h @@ -1243,10 +1243,9 @@ struct ExpandoAndGeneration { generation(0) {} - void Unlink() + void OwnerUnlinked() { ++generation; - expando.setUndefined(); } static size_t offsetOfExpando() From c0fdb1ba695548e864d9bbb7f704848637856898 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 22 Jul 2016 16:19:52 -0400 Subject: [PATCH 071/135] Bug 1157127. When reusing the global of an initial about:blank for a new document, clear out its XBL scope when we change the global's principal. r=bholley --- dom/base/nsGlobalWindow.cpp | 12 ++++++++++-- js/xpconnect/src/XPCWrappedNativeScope.cpp | 6 ++++++ js/xpconnect/src/xpcprivate.h | 1 + js/xpconnect/src/xpcpublic.h | 5 +++++ layout/reftests/bugs/1157127-1-ref.html | 15 +++++++++++++++ layout/reftests/bugs/1157127-1.html | 16 ++++++++++++++++ layout/reftests/bugs/1157127-subframe.xml | 1 + layout/reftests/bugs/reftest.list | 1 + 8 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 layout/reftests/bugs/1157127-1-ref.html create mode 100644 layout/reftests/bugs/1157127-1.html create mode 100644 layout/reftests/bugs/1157127-subframe.xml diff --git a/dom/base/nsGlobalWindow.cpp b/dom/base/nsGlobalWindow.cpp index f1baedcc32ee..8f3f33f700c5 100644 --- a/dom/base/nsGlobalWindow.cpp +++ b/dom/base/nsGlobalWindow.cpp @@ -2745,8 +2745,16 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument, aDocument->NodePrincipal()->Equals(existing, &sameOrigin); MOZ_ASSERT(sameOrigin); #endif - JS_SetCompartmentPrincipals(compartment, - nsJSPrincipals::get(aDocument->NodePrincipal())); + MOZ_ASSERT_IF(aDocument == oldDoc, + xpc::GetCompartmentPrincipal(compartment) == + aDocument->NodePrincipal()); + if (aDocument != oldDoc) { + JS_SetCompartmentPrincipals(compartment, + nsJSPrincipals::get(aDocument->NodePrincipal())); + // Make sure we clear out the old content XBL scope, so the new one will + // get created with a principal that subsumes our new principal. + xpc::ClearContentXBLScope(newInnerGlobal); + } } else { if (aState) { newInnerWindow = wsh->GetInnerWindow(); diff --git a/js/xpconnect/src/XPCWrappedNativeScope.cpp b/js/xpconnect/src/XPCWrappedNativeScope.cpp index f346b0485424..025df071fcbf 100644 --- a/js/xpconnect/src/XPCWrappedNativeScope.cpp +++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp @@ -375,6 +375,12 @@ UseContentXBLScope(JSCompartment* c) return scope && scope->UseContentXBLScope(); } +void +ClearContentXBLScope(JSObject* global) +{ + CompartmentPrivate::Get(global)->scope->ClearContentXBLScope(); +} + } /* namespace xpc */ JSObject* diff --git a/js/xpconnect/src/xpcprivate.h b/js/xpconnect/src/xpcprivate.h index 3a98cbad2e49..03a073a01d16 100644 --- a/js/xpconnect/src/xpcprivate.h +++ b/js/xpconnect/src/xpcprivate.h @@ -1015,6 +1015,7 @@ public: bool IsContentXBLScope() { return mIsContentXBLScope; } bool AllowContentXBLScope(); bool UseContentXBLScope() { return mUseContentXBLScope; } + void ClearContentXBLScope() { mContentXBLScope = nullptr; } bool IsAddonScope() { return mIsAddonScope; } diff --git a/js/xpconnect/src/xpcpublic.h b/js/xpconnect/src/xpcpublic.h index 44da22b4884d..3efe86160c45 100644 --- a/js/xpconnect/src/xpcpublic.h +++ b/js/xpconnect/src/xpcpublic.h @@ -123,6 +123,11 @@ AllowContentXBLScope(JSCompartment* c); bool UseContentXBLScope(JSCompartment* c); +// Clear out the content XBL scope (if any) on the given global. This will +// force creation of a new one if one is needed again. +void +ClearContentXBLScope(JSObject* global); + bool IsInAddonScope(JSObject* obj); diff --git a/layout/reftests/bugs/1157127-1-ref.html b/layout/reftests/bugs/1157127-1-ref.html new file mode 100644 index 000000000000..9b03f139b7df --- /dev/null +++ b/layout/reftests/bugs/1157127-1-ref.html @@ -0,0 +1,15 @@ + + + + diff --git a/layout/reftests/bugs/1157127-1.html b/layout/reftests/bugs/1157127-1.html new file mode 100644 index 000000000000..b1104c74ee25 --- /dev/null +++ b/layout/reftests/bugs/1157127-1.html @@ -0,0 +1,16 @@ + + + + diff --git a/layout/reftests/bugs/1157127-subframe.xml b/layout/reftests/bugs/1157127-subframe.xml new file mode 100644 index 000000000000..f3f286eafc9c --- /dev/null +++ b/layout/reftests/bugs/1157127-subframe.xml @@ -0,0 +1 @@ + diff --git a/layout/reftests/bugs/reftest.list b/layout/reftests/bugs/reftest.list index 1a6fadb1bf48..7f6fa5fc30fe 100644 --- a/layout/reftests/bugs/reftest.list +++ b/layout/reftests/bugs/reftest.list @@ -1929,6 +1929,7 @@ skip-if(B2G||Mulet) == 1150021-1.xul 1150021-1-ref.xul == 1153845-1.html 1153845-1-ref.html == 1155828-1.html 1155828-1-ref.html == 1156129-1.html 1156129-1-ref.html +pref(dom.use_xbl_scopes_for_remote_xul,true) HTTP(..) == 1157127-1.html 1157127-1-ref.html == 1169331-1.html 1169331-1-ref.html fuzzy(1,74) fuzzy-if(gtkWidget,6,79) == 1174332-1.html 1174332-1-ref.html == 1179078-1.html 1179078-1-ref.html From 2f3c416bde6310394fcdeda30f95147a3868905b Mon Sep 17 00:00:00 2001 From: Yura Zenevich Date: Fri, 22 Jul 2016 15:00:34 -0400 Subject: [PATCH 072/135] Bug 1226877 - make collapsed details pane hidden using visibility: hidden to be inaccessible by both keyboard and a11y tools. r=bgrins MozReview-Commit-ID: 4DxnGDpRLHf --- devtools/client/netmonitor/netmonitor.css | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/devtools/client/netmonitor/netmonitor.css b/devtools/client/netmonitor/netmonitor.css index ba00b422df21..3ee8ea1da509 100644 --- a/devtools/client/netmonitor/netmonitor.css +++ b/devtools/client/netmonitor/netmonitor.css @@ -7,6 +7,14 @@ overflow: hidden; } +/** + * Collapsed details pane needs to be truly hidden to prevent both accessibility + * tools and keyboard from accessing its contents. + */ +#details-pane.pane-collapsed { + visibility: hidden; +} + #details-pane-toggle[disabled] { display: none; } @@ -36,7 +44,6 @@ @media (max-width: 700px) { #toolbar-spacer, #details-pane-toggle, - #details-pane.pane-collapsed, .requests-menu-waterfall, #requests-menu-network-summary-button > .toolbarbutton-text { display: none; From 7ebb9d306eb69687628140f2dbf4981c2dd4084c Mon Sep 17 00:00:00 2001 From: Yura Zenevich Date: Fri, 22 Jul 2016 15:00:57 -0400 Subject: [PATCH 073/135] Bug 1226877 - make toolbox panels inaccessible with keyboard when they are hidden or collapsed. r=bgrins MozReview-Commit-ID: IEj81E2Y5wv --- devtools/client/themes/toolbox.css | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/devtools/client/themes/toolbox.css b/devtools/client/themes/toolbox.css index f0c49a3334d1..5163609f71e0 100644 --- a/devtools/client/themes/toolbox.css +++ b/devtools/client/themes/toolbox.css @@ -382,4 +382,23 @@ .toolbox-panel[selected] { visibility: visible; -} \ No newline at end of file +} + +/** + * When panels are collapsed or hidden, making sure that they are also + * inaccessible by keyboard. This is not the case by default because the are + * predominantly hidden using visibility: collapse; style or collapsed + * attribute. + */ +.toolbox-panel *, +#toolbox-panel-webconsole[collapsed] * { + -moz-user-focus: ignore; +} + +/** + * Enrure that selected toolbox panel's contents are keyboard accessible as they + * are explicitly made not to be when hidden (default). + */ +.toolbox-panel[selected] * { + -moz-user-focus: normal; +} From 1a1438ccb5cc7776dd5bb0ef2a8a576cf101ff00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Thu, 21 Jul 2016 18:47:02 -0700 Subject: [PATCH 074/135] Bug 1288578: Make public nsClassHashTable::IsEmpty. r=froydnj MozReview-Commit-ID: JSjT17kWYcQ --- xpcom/glue/nsClassHashtable.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/xpcom/glue/nsClassHashtable.h b/xpcom/glue/nsClassHashtable.h index 30567735ec7e..4a7c0aed2901 100644 --- a/xpcom/glue/nsClassHashtable.h +++ b/xpcom/glue/nsClassHashtable.h @@ -29,6 +29,8 @@ public: typedef T* UserDataType; typedef nsBaseHashtable, T*> base_type; + using base_type::IsEmpty; + nsClassHashtable() {} explicit nsClassHashtable(uint32_t aInitLength) : nsBaseHashtable, T*>(aInitLength) From e51037a1346553d0d0ce44be340b27400b5b92d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Fri, 22 Jul 2016 11:26:15 -0700 Subject: [PATCH 075/135] Bug 1287951: followup: use nsClassHashTable's IsEmpty instead of Count. r=me MozReview-Commit-ID: 7flRcbykG4c --- layout/base/ServoRestyleManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/base/ServoRestyleManager.h b/layout/base/ServoRestyleManager.h index c5ca0f571537..858a5f689694 100644 --- a/layout/base/ServoRestyleManager.h +++ b/layout/base/ServoRestyleManager.h @@ -67,7 +67,7 @@ public: const nsAttrValue* aOldValue); nsresult ReparentStyleContext(nsIFrame* aFrame); - bool HasPendingRestyles() { return mModifiedElements.Count() != 0; } + bool HasPendingRestyles() { return !mModifiedElements.IsEmpty(); } protected: ~ServoRestyleManager() {} From ed6e02e2dffc0bca576a41560b69da6538fa4ff7 Mon Sep 17 00:00:00 2001 From: Nathan Froyd Date: Sat, 23 Jul 2016 00:28:05 -0400 Subject: [PATCH 076/135] Bug 1288795 - remove dead assignments in test_emitter.py; r=chmanchester Prevailing style in the file for when read_topsrcdir is being tested for exception-throwingness is to omit the assignment, so let's make everything consistent. --- .../mozbuild/test/frontend/test_emitter.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/python/mozbuild/mozbuild/test/frontend/test_emitter.py b/python/mozbuild/mozbuild/test/frontend/test_emitter.py index 0b4552a14ceb..cdc05f6cc013 100644 --- a/python/mozbuild/mozbuild/test/frontend/test_emitter.py +++ b/python/mozbuild/mozbuild/test/frontend/test_emitter.py @@ -204,7 +204,7 @@ class TestEmitterBasic(unittest.TestCase): reader = self.reader('use-yasm') with self.assertRaisesRegexp(SandboxValidationError, 'yasm is not available'): - objs = self.read_topsrcdir(reader) + self.read_topsrcdir(reader) # When yasm is available, this should work. reader = self.reader('use-yasm', @@ -273,19 +273,19 @@ class TestEmitterBasic(unittest.TestCase): reader = self.reader('generated-files-no-script') with self.assertRaisesRegexp(SandboxValidationError, 'Script for generating bar.c does not exist'): - objs = self.read_topsrcdir(reader) + self.read_topsrcdir(reader) def test_generated_files_no_inputs(self): reader = self.reader('generated-files-no-inputs') with self.assertRaisesRegexp(SandboxValidationError, 'Input for generating foo.c does not exist'): - objs = self.read_topsrcdir(reader) + self.read_topsrcdir(reader) def test_generated_files_no_python_script(self): reader = self.reader('generated-files-no-python-script') with self.assertRaisesRegexp(SandboxValidationError, 'Script for generating bar.c does not end in .py'): - objs = self.read_topsrcdir(reader) + self.read_topsrcdir(reader) def test_exports(self): reader = self.reader('exports') @@ -314,7 +314,7 @@ class TestEmitterBasic(unittest.TestCase): reader = self.reader('exports-missing') with self.assertRaisesRegexp(SandboxValidationError, 'File listed in EXPORTS does not exist:'): - objs = self.read_topsrcdir(reader) + self.read_topsrcdir(reader) def test_exports_missing_generated(self): ''' @@ -323,7 +323,7 @@ class TestEmitterBasic(unittest.TestCase): reader = self.reader('exports-missing-generated') with self.assertRaisesRegexp(SandboxValidationError, 'Objdir file listed in EXPORTS not in GENERATED_FILES:'): - objs = self.read_topsrcdir(reader) + self.read_topsrcdir(reader) def test_exports_generated(self): reader = self.reader('exports-generated') @@ -360,7 +360,7 @@ class TestEmitterBasic(unittest.TestCase): reader = self.reader('test-harness-files-root') with self.assertRaisesRegexp(SandboxValidationError, 'Cannot install files to the root of TEST_HARNESS_FILES'): - objs = self.read_topsrcdir(reader) + self.read_topsrcdir(reader) def test_branding_files(self): reader = self.reader('branding-files') @@ -540,7 +540,7 @@ class TestEmitterBasic(unittest.TestCase): reader = self.reader('test-python-unit-test-missing') with self.assertRaisesRegexp(SandboxValidationError, 'Path specified in PYTHON_UNIT_TESTS does not exist:'): - objs = self.read_topsrcdir(reader) + self.read_topsrcdir(reader) def test_test_manifest_keys_extracted(self): """Ensure all metadata from test manifests is extracted.""" @@ -990,7 +990,7 @@ class TestEmitterBasic(unittest.TestCase): reader = self.reader('final-target-pp-files-non-srcdir') with self.assertRaisesRegexp(SandboxValidationError, 'Only source directory paths allowed in FINAL_TARGET_PP_FILES:'): - objs = self.read_topsrcdir(reader) + self.read_topsrcdir(reader) def test_android_res_dirs(self): """Test that ANDROID_RES_DIRS works properly.""" From 0d1fe4cb0361367bbb642f3023a6abe8519baf88 Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Fri, 22 Jul 2016 14:31:36 -0600 Subject: [PATCH 077/135] Bug 1288450 - Add min sdk version to mozinfo.json; r=ahal --- python/mozbuild/mozbuild/mozinfo.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/python/mozbuild/mozbuild/mozinfo.py b/python/mozbuild/mozbuild/mozinfo.py index c6bb9b2de872..7065a1ad27d6 100755 --- a/python/mozbuild/mozbuild/mozinfo.py +++ b/python/mozbuild/mozbuild/mozinfo.py @@ -140,6 +140,9 @@ def build_dict(config, env=os.environ): d['platform_guess'] = guess_platform() d['buildtype_guess'] = guess_buildtype() + if 'buildapp' in d and d['buildapp'] == 'mobile/android' and 'MOZ_ANDROID_MIN_SDK_VERSION' in substs: + d['android_min_sdk'] = substs['MOZ_ANDROID_MIN_SDK_VERSION'] + return d From fd78e8fcc7fbbd315debfd0bab87e6c8e14561bf Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Fri, 22 Jul 2016 14:31:37 -0600 Subject: [PATCH 078/135] Bug 1288501 - Accept total-chunk, this-chunk options in android_emulator_unittest.py; r=kmoir --- .../configs/android/androidarm_4_3.py | 613 +----------------- .../mozharness/mozilla/testing/errors.py | 1 + .../scripts/android_emulator_unittest.py | 72 +- 3 files changed, 71 insertions(+), 615 deletions(-) diff --git a/testing/mozharness/configs/android/androidarm_4_3.py b/testing/mozharness/configs/android/androidarm_4_3.py index 0b0e686e2f9b..844bbc910047 100644 --- a/testing/mozharness/configs/android/androidarm_4_3.py +++ b/testing/mozharness/configs/android/androidarm_4_3.py @@ -80,6 +80,7 @@ config = { "--extra-profile-file=fonts", "--extra-profile-file=hyphenation", "--screenshot-on-fail", + "--total-chunks=20", ], }, "mochitest-gl": { @@ -103,6 +104,28 @@ config = { "--subsuite=webgl", ], }, + "mochitest-chrome": { + "run_filename": "runtestsremote.py", + "testsdir": "mochitest", + "options": [ + "--dm_trans=adb", + "--app=%(app)s", + "--remote-webserver=%(remote_webserver)s", + "--xre-path=%(xre_path)s", + "--utility-path=%(utility_path)s", + "--http-port=%(http_port)s", + "--ssl-port=%(ssl_port)s", + "--certificate-path=%(certs_path)s", + "--symbols-path=%(symbols_path)s", + "--quiet", + "--log-raw=%(raw_log_file)s", + "--log-errorsummary=%(error_summary_file)s", + "--extra-profile-file=fonts", + "--extra-profile-file=hyphenation", + "--screenshot-on-fail", + "--chrome", + ], + }, "mochitest-plain-gpu": { "run_filename": "runtestsremote.py", "testsdir": "mochitest", @@ -332,596 +355,6 @@ config = { }, }, # end suite_definitions - "test_suite_definitions": { - "jsreftest-1": { - "category": "jsreftest", - "extra_args": ["--this-chunk=1"], - }, - "jsreftest-2": { - "category": "jsreftest", - "extra_args": ["--this-chunk=2"], - }, - "jsreftest-3": { - "category": "jsreftest", - "extra_args": ["--this-chunk=3"], - }, - "jsreftest-4": { - "category": "jsreftest", - "extra_args": ["--this-chunk=4"], - }, - "jsreftest-5": { - "category": "jsreftest", - "extra_args": ["--this-chunk=5"], - }, - "jsreftest-6": { - "category": "jsreftest", - "extra_args": ["--this-chunk=6"], - }, - "jsreftest-debug-1": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=1"], - }, - "jsreftest-debug-2": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=2"], - }, - "jsreftest-debug-3": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=3"], - }, - "jsreftest-debug-4": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=4"], - }, - "jsreftest-debug-5": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=5"], - }, - "jsreftest-debug-6": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=6"], - }, - "jsreftest-debug-7": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=7"], - }, - "jsreftest-debug-8": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=8"], - }, - "jsreftest-debug-9": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=9"], - }, - "jsreftest-debug-10": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=10"], - }, - "jsreftest-debug-11": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=11"], - }, - "jsreftest-debug-12": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=12"], - }, - "jsreftest-debug-13": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=13"], - }, - "jsreftest-debug-14": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=14"], - }, - "jsreftest-debug-15": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=15"], - }, - "jsreftest-debug-16": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=16"], - }, - "jsreftest-debug-17": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=17"], - }, - "jsreftest-debug-18": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=18"], - }, - "jsreftest-debug-19": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=19"], - }, - "jsreftest-debug-20": { - "category": "jsreftest-debug", - "extra_args": ["--this-chunk=20"], - }, - "mochitest-1": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=1"], - }, - "mochitest-2": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=2"], - }, - "mochitest-3": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=3"], - }, - "mochitest-4": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=4"], - }, - "mochitest-5": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=5"], - }, - "mochitest-6": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=6"], - }, - "mochitest-7": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=7"], - }, - "mochitest-8": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=8"], - }, - "mochitest-9": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=9"], - }, - "mochitest-10": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=10"], - }, - "mochitest-11": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=11"], - }, - "mochitest-12": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=12"], - }, - "mochitest-13": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=13"], - }, - "mochitest-14": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=14"], - }, - "mochitest-15": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=15"], - }, - "mochitest-16": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=16"], - }, - "mochitest-17": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=17"], - }, - "mochitest-18": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=18"], - }, - "mochitest-19": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=19"], - }, - "mochitest-20": { - "category": "mochitest", - "extra_args": ["--total-chunks=20", "--this-chunk=20"], - }, - "mochitest-chrome": { - "category": "mochitest", - "extra_args": ["--chrome"], - }, - "mochitest-media-1": { - "category": "mochitest-media", - "extra_args": ["--this-chunk=1"], - }, - "mochitest-media-2": { - "category": "mochitest-media", - "extra_args": ["--this-chunk=2"], - }, - "mochitest-plain-gpu": { - "category": "mochitest-plain-gpu", - "extra_args": [], - }, - "mochitest-plain-clipboard": { - "category": "mochitest-plain-clipboard", - "extra_args": [], - }, - "mochitest-gl-1": { - "category": "mochitest-gl", - "extra_args": ["--this-chunk=1"], - }, - "mochitest-gl-2": { - "category": "mochitest-gl", - "extra_args": ["--this-chunk=2"], - }, - "mochitest-gl-3": { - "category": "mochitest-gl", - "extra_args": ["--this-chunk=3"], - }, - "mochitest-gl-4": { - "category": "mochitest-gl", - "extra_args": ["--this-chunk=4"], - }, - "mochitest-gl-5": { - "category": "mochitest-gl", - "extra_args": ["--this-chunk=5"], - }, - "mochitest-gl-6": { - "category": "mochitest-gl", - "extra_args": ["--this-chunk=6"], - }, - "mochitest-gl-7": { - "category": "mochitest-gl", - "extra_args": ["--this-chunk=7"], - }, - "mochitest-gl-8": { - "category": "mochitest-gl", - "extra_args": ["--this-chunk=8"], - }, - "mochitest-gl-9": { - "category": "mochitest-gl", - "extra_args": ["--this-chunk=9"], - }, - "mochitest-gl-10": { - "category": "mochitest-gl", - "extra_args": ["--this-chunk=10"], - }, - "reftest-1": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=1"], - }, - "reftest-2": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=2"], - }, - "reftest-3": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=3"], - }, - "reftest-4": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=4"], - }, - "reftest-5": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=5"], - }, - "reftest-6": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=6"], - }, - "reftest-7": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=7"], - }, - "reftest-8": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=8"], - }, - "reftest-9": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=9"], - }, - "reftest-10": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=10"], - }, - "reftest-11": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=11"], - }, - "reftest-12": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=12"], - }, - "reftest-13": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=13"], - }, - "reftest-14": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=14"], - }, - "reftest-15": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=15"], - }, - "reftest-16": { - "category": "reftest", - "extra_args": ["--total-chunks=16", "--this-chunk=16"], - }, - "reftest-debug-1": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=1"], - }, - "reftest-debug-2": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=2"], - }, - "reftest-debug-3": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=3"], - }, - "reftest-debug-4": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=4"], - }, - "reftest-debug-5": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=5"], - }, - "reftest-debug-6": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=6"], - }, - "reftest-debug-7": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=7"], - }, - "reftest-debug-8": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=8"], - }, - "reftest-debug-9": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=9"], - }, - "reftest-debug-10": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=10"], - }, - "reftest-debug-11": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=11"], - }, - "reftest-debug-12": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=12"], - }, - "reftest-debug-13": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=13"], - }, - "reftest-debug-14": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=14"], - }, - "reftest-debug-15": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=15"], - }, - "reftest-debug-16": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=16"], - }, - "reftest-debug-17": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=17"], - }, - "reftest-debug-18": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=18"], - }, - "reftest-debug-19": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=19"], - }, - "reftest-debug-20": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=20"], - }, - "reftest-debug-21": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=21"], - }, - "reftest-debug-22": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=22"], - }, - "reftest-debug-23": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=23"], - }, - "reftest-debug-24": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=24"], - }, - "reftest-debug-25": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=25"], - }, - "reftest-debug-26": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=26"], - }, - "reftest-debug-27": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=27"], - }, - "reftest-debug-28": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=28"], - }, - "reftest-debug-29": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=29"], - }, - "reftest-debug-30": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=30"], - }, - "reftest-debug-31": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=31"], - }, - "reftest-debug-32": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=32"], - }, - "reftest-debug-33": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=33"], - }, - "reftest-debug-34": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=34"], - }, - "reftest-debug-35": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=35"], - }, - "reftest-debug-36": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=36"], - }, - "reftest-debug-37": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=37"], - }, - "reftest-debug-38": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=38"], - }, - "reftest-debug-39": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=39"], - }, - "reftest-debug-40": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=40"], - }, - "reftest-debug-41": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=41"], - }, - "reftest-debug-42": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=42"], - }, - "reftest-debug-43": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=43"], - }, - "reftest-debug-44": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=44"], - }, - "reftest-debug-45": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=45"], - }, - "reftest-debug-46": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=46"], - }, - "reftest-debug-47": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=47"], - }, - "reftest-debug-48": { - "category": "reftest-debug", - "extra_args": ["--total-chunks=48", "--this-chunk=48"], - }, - "crashtest-1": { - "category": "crashtest", - "extra_args": ["--this-chunk=1"], - }, - "crashtest-2": { - "category": "crashtest", - "extra_args": ["--this-chunk=2"], - }, - "crashtest-3": { - "category": "crashtest", - "extra_args": ["--this-chunk=3"], - }, - "crashtest-4": { - "category": "crashtest", - "extra_args": ["--this-chunk=4"], - }, - "crashtest-debug-1": { - "category": "crashtest-debug", - "extra_args": ["--this-chunk=1"], - }, - "crashtest-debug-2": { - "category": "crashtest-debug", - "extra_args": ["--this-chunk=2"], - }, - "crashtest-debug-3": { - "category": "crashtest-debug", - "extra_args": ["--this-chunk=3"], - }, - "crashtest-debug-4": { - "category": "crashtest-debug", - "extra_args": ["--this-chunk=4"], - }, - "crashtest-debug-5": { - "category": "crashtest-debug", - "extra_args": ["--this-chunk=5"], - }, - "crashtest-debug-6": { - "category": "crashtest-debug", - "extra_args": ["--this-chunk=6"], - }, - "crashtest-debug-7": { - "category": "crashtest-debug", - "extra_args": ["--this-chunk=7"], - }, - "crashtest-debug-8": { - "category": "crashtest-debug", - "extra_args": ["--this-chunk=8"], - }, - "crashtest-debug-9": { - "category": "crashtest-debug", - "extra_args": ["--this-chunk=9"], - }, - "crashtest-debug-10": { - "category": "crashtest-debug", - "extra_args": ["--this-chunk=10"], - }, - "xpcshell-1": { - "category": "xpcshell", - "extra_args": ["--total-chunks=3", "--this-chunk=1"], - }, - "xpcshell-2": { - "category": "xpcshell", - "extra_args": ["--total-chunks=3", "--this-chunk=2"], - }, - "xpcshell-3": { - "category": "xpcshell", - "extra_args": ["--total-chunks=3", "--this-chunk=3"], - }, - "robocop-1": { - "category": "robocop", - "extra_args": ["--this-chunk=1"], - }, - "robocop-2": { - "category": "robocop", - "extra_args": ["--this-chunk=2"], - }, - "robocop-3": { - "category": "robocop", - "extra_args": ["--this-chunk=3"], - }, - "robocop-4": { - "category": "robocop", - "extra_args": ["--this-chunk=4"], - }, - "cppunittest": { - "category": "cppunittest", - "extra_args": [], - }, - }, # end of "test_definitions" "download_minidump_stackwalk": True, "default_blob_upload_servers": [ "https://blobupload.elasticbeanstalk.com", diff --git a/testing/mozharness/mozharness/mozilla/testing/errors.py b/testing/mozharness/mozharness/mozilla/testing/errors.py index 7eee5c8cf546..62f4d72e1467 100644 --- a/testing/mozharness/mozharness/mozilla/testing/errors.py +++ b/testing/mozharness/mozharness/mozilla/testing/errors.py @@ -27,6 +27,7 @@ _mochitest_summary = { TinderBoxPrintRe = { "mochitest_summary": _mochitest_summary, + "mochitest-chrome_summary": _mochitest_summary, "mochitest-gl_summary": _mochitest_summary, "mochitest-media_summary": _mochitest_summary, "mochitest-plain-clipboard_summary": _mochitest_summary, diff --git a/testing/mozharness/scripts/android_emulator_unittest.py b/testing/mozharness/scripts/android_emulator_unittest.py index 4d9f399b6e88..6451f56d4f22 100644 --- a/testing/mozharness/scripts/android_emulator_unittest.py +++ b/testing/mozharness/scripts/android_emulator_unittest.py @@ -9,6 +9,7 @@ import copy import datetime import glob import os +import re import sys import signal import socket @@ -36,14 +37,28 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin ["--test-suite"], {"action": "store", "dest": "test_suite", - } + } ], [ ["--adb-path"], {"action": "store", "dest": "adb_path", "default": None, "help": "Path to adb", - } + } + ], [ + ["--total-chunk"], + {"action": "store", + "dest": "total_chunks", + "default": None, + "help": "Number of total chunks", + } + ], [ + ["--this-chunk"], + {"action": "store", + "dest": "this_chunk", + "default": None, + "help": "Number of this chunk", + } ]] + copy.deepcopy(testing_config_options) + \ copy.deepcopy(blobupload_config_options) @@ -101,19 +116,25 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin self.robocop_path = os.path.join(abs_dirs['abs_work_dir'], "robocop.apk") self.minidump_stackwalk_path = c.get("minidump_stackwalk_path") self.emulator = c.get('emulator') - self.test_suite_definitions = c['test_suite_definitions'] self.test_suite = c.get('test_suite') + self.this_chunk = c.get('this_chunk') + self.total_chunks = c.get('total_chunks') + if self.test_suite not in self.config["suite_definitions"]: + # accept old-style test suite name like "mochitest-3" + m = re.match("(.*)-(\d*)", self.test_suite) + if m: + self.test_suite = m.group(1) + if self.this_chunk is None: + self.this_chunk = m.group(2) self.sdk_level = None self.xre_path = None - assert self.test_suite in self.test_suite_definitions def _query_tests_dir(self): dirs = self.query_abs_dirs() - suite_category = self.test_suite_definitions[self.test_suite]["category"] try: - test_dir = self.config["suite_definitions"][suite_category]["testsdir"] + test_dir = self.config["suite_definitions"][self.test_suite]["testsdir"] except: - test_dir = suite_category + test_dir = self.test_suite return os.path.join(dirs['abs_test_install_dir'], test_dir) def query_abs_dirs(self): @@ -435,17 +456,16 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin def _build_command(self): c = self.config dirs = self.query_abs_dirs() - suite_category = self.test_suite_definitions[self.test_suite]["category"] - if suite_category not in self.config["suite_definitions"]: - self.fatal("Key '%s' not defined in the config!" % suite_category) + if self.test_suite not in self.config["suite_definitions"]: + self.fatal("Key '%s' not defined in the config!" % self.test_suite) cmd = [ self.query_python_path('python'), '-u', os.path.join( self._query_tests_dir(), - self.config["suite_definitions"][suite_category]["run_filename"] + self.config["suite_definitions"][self.test_suite]["run_filename"] ), ] @@ -476,21 +496,25 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin 'device_ip': c['device_ip'], 'device_port': str(self.emulator['sut_port1']), }) - for option in self.config["suite_definitions"][suite_category]["options"]: + for option in self.config["suite_definitions"][self.test_suite]["options"]: + opt = option.split('=')[0] + # override configured chunk options with script args, if specified + if opt == '--this-chunk' and self.this_chunk is not None: + continue + if opt == '--total-chunks' and self.total_chunks is not None: + continue cmd.extend([option % str_format_values]) - for arg in self.test_suite_definitions[self.test_suite]["extra_args"]: - argname = arg.split('=')[0] - # only add the extra arg if it wasn't already defined by in-tree configs - if any(a.split('=')[0] == argname for a in cmd): - continue - cmd.append(arg) + if self.this_chunk is not None: + cmd.extend(['--this-chunk', self.this_chunk]) + if self.total_chunks is not None: + cmd.extend(['--total-chunks', self.total_chunks]) - try_options, try_tests = self.try_args(suite_category) + try_options, try_tests = self.try_args(self.test_suite) cmd.extend(try_options) cmd.extend(self.query_tests_args( - self.config["suite_definitions"][suite_category].get("tests"), - self.test_suite_definitions[self.test_suite].get("tests"), + self.config["suite_definitions"][self.test_suite].get("tests"), + None, try_tests)) return cmd @@ -621,8 +645,7 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin """ Download and extract fennec APK, tests.zip, host utils, and robocop (if required). """ - suite_category = self.test_suite_definitions[self.test_suite]['category'] - super(AndroidEmulatorTest, self).download_and_extract(suite_categories=[suite_category]) + super(AndroidEmulatorTest, self).download_and_extract(suite_categories=[self.test_suite]) dirs = self.query_abs_dirs() if self.test_suite.startswith('robocop'): robocop_url = self.installer_url[:self.installer_url.rfind('/')] + '/robocop.apk' @@ -690,8 +713,7 @@ class AndroidEmulatorTest(BlobUploadMixin, TestingMixin, EmulatorMixin, VCSMixin 'jsreftest-debug': 'jsreftest', 'crashtest-debug': 'crashtest', } - suite_category = self.test_suite_definitions[self.test_suite]["category"] - suite_category = aliases.get(suite_category, suite_category) + suite_category = aliases.get(self.test_suite, self.test_suite) parser = self.get_test_output_parser( suite_category, config=self.config, From 3b625b3b98430cd7c782d7e6fb9421a14057d1a8 Mon Sep 17 00:00:00 2001 From: Ryan VanderMeulen Date: Fri, 22 Jul 2016 17:08:29 -0400 Subject: [PATCH 079/135] Bug 1282257 - Fix include ordering to make the style checker happy. r=bustage --- js/src/vm/Debugger.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/js/src/vm/Debugger.cpp b/js/src/vm/Debugger.cpp index 75cec31cbef0..9164e70f997c 100644 --- a/js/src/vm/Debugger.cpp +++ b/js/src/vm/Debugger.cpp @@ -31,6 +31,7 @@ #include "js/GCAPI.h" #include "js/UbiNodeBreadthFirst.h" #include "js/Vector.h" +#include "proxy/ScriptedProxyHandler.h" #include "vm/ArgumentsObject.h" #include "vm/DebuggerMemory.h" #include "vm/SPSProfiler.h" @@ -45,8 +46,6 @@ #include "vm/NativeObject-inl.h" #include "vm/Stack-inl.h" -#include "proxy/ScriptedProxyHandler.h" - using namespace js; using JS::dbg::AutoEntryMonitor; From a42390b5060c941bf754923f193cbd3f04799e3a Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 22 Jul 2016 17:20:49 -0400 Subject: [PATCH 080/135] Bug 1288581 followup. Remove a bogus comment. DONTBUILD. --- dom/bindings/DOMJSProxyHandler.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/dom/bindings/DOMJSProxyHandler.cpp b/dom/bindings/DOMJSProxyHandler.cpp index 01ea13d5ab24..5fc63a71e026 100644 --- a/dom/bindings/DOMJSProxyHandler.cpp +++ b/dom/bindings/DOMJSProxyHandler.cpp @@ -297,7 +297,6 @@ DOMProxyHandler::GetExpandoObject(JSObject *obj) return v.isUndefined() ? nullptr : &v.toObject(); } -// static void ShadowingDOMProxyHandler::trace(JSTracer* trc, JSObject* proxy) const { From 93e60feb01deeff47c79dd07765bad6502a8dbc1 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Fri, 22 Jul 2016 14:30:22 +1200 Subject: [PATCH 081/135] Bug 1288582 - Hide Adobe Primetime plugin on Windows < Vista. r=spohl We're not going to get a supported Adobe GMP on WinXP, so we shouldn't download it or show it in our add-on manager. MozReview-Commit-ID: I3cNsStmzsV --HG-- extra : rebase_source : b67c7cbec013f83bcf7d24cac99755faf1b5e07e --- toolkit/modules/GMPUtils.jsm | 3 ++- toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/toolkit/modules/GMPUtils.jsm b/toolkit/modules/GMPUtils.jsm index b1d2b8e8d0a3..d1b9c0c1d0a5 100644 --- a/toolkit/modules/GMPUtils.jsm +++ b/toolkit/modules/GMPUtils.jsm @@ -79,8 +79,9 @@ this.GMPUtils = { this.maybeReportTelemetry(aPlugin.id, "VIDEO_EME_ADOBE_UNSUPPORTED_REASON", GMPPluginUnsupportedReason.NOT_WINDOWS); - return false; } + // Windows Vista and later only supported by Adobe EME. + return AppConstants.isPlatformAndVersionAtLeast("win", "6"); } else if (aPlugin.id == WIDEVINE_ID) { // The Widevine plugin is available for Windows versions Vista and later // and Mac OSX 10.7 and later. diff --git a/toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js b/toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js index 9b071f24f49f..a1eba5676e7a 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js +++ b/toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js @@ -381,7 +381,7 @@ add_task(function* testEmeSupport() { let doc = gManagerWindow.document; let item = get_addon_element(gManagerWindow, addon.id); if (addon.id == GMPScope.EME_ADOBE_ID) { - if (Services.appinfo.OS == "WINNT") { + if (AppConstants.isPlatformAndVersionAtLeast("win", "6")) { Assert.ok(item, "Adobe EME supported, found add-on element."); } else { Assert.ok(!item, From 888002acb976cddcbe50bd10e01eb99b8ffd96ab Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Fri, 22 Jul 2016 14:21:19 +1200 Subject: [PATCH 082/135] Bug 1288580 - Mark Widevine as supported on Linux and remove Mac OSX version check. r=spohl This means if Widevine is preffed visible on Linux it will show up in the plugin list. We only support Mac OSX 10.9 and later, so we don't need the >= 10.7 check any more. MozReview-Commit-ID: BjgMKeIIrrI --HG-- extra : rebase_source : 46740a9d40f8ae700b6a47eb488a2435e48c1e99 --- toolkit/modules/GMPUtils.jsm | 12 +++++------- .../extensions/test/browser/browser_gmpProvider.js | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/toolkit/modules/GMPUtils.jsm b/toolkit/modules/GMPUtils.jsm index d1b9c0c1d0a5..4b8070120ef3 100644 --- a/toolkit/modules/GMPUtils.jsm +++ b/toolkit/modules/GMPUtils.jsm @@ -83,13 +83,11 @@ this.GMPUtils = { // Windows Vista and later only supported by Adobe EME. return AppConstants.isPlatformAndVersionAtLeast("win", "6"); } else if (aPlugin.id == WIDEVINE_ID) { - // The Widevine plugin is available for Windows versions Vista and later - // and Mac OSX 10.7 and later. - if (AppConstants.isPlatformAndVersionAtLeast("win", "6") || - AppConstants.isPlatformAndVersionAtLeast("macosx", "10.7")) { - return true; - } - return false; + // The Widevine plugin is available for Windows versions Vista and later, + // Mac OSX, and Linux. + return AppConstants.isPlatformAndVersionAtLeast("win", "6") || + AppConstants.platform == "macosx" || + AppConstants.platform == "linux"; } return true; diff --git a/toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js b/toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js index a1eba5676e7a..b5ecaf60c124 100644 --- a/toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js +++ b/toolkit/mozapps/extensions/test/browser/browser_gmpProvider.js @@ -389,7 +389,8 @@ add_task(function* testEmeSupport() { } } else if (addon.id == GMPScope.WIDEVINE_ID) { if (AppConstants.isPlatformAndVersionAtLeast("win", "6") || - AppConstants.isPlatformAndVersionAtLeast("macosx", "10.7")) { + AppConstants.platform == "macosx" || + AppConstants.platform == "linux") { Assert.ok(item, "Widevine supported, found add-on element."); } else { Assert.ok(!item, From e091dd26b182e6f8beaa854f98ed98f3dd9955d1 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Fri, 1 Jul 2016 11:28:58 +1200 Subject: [PATCH 083/135] Bug 1278198 - Update MediaKeySystemConfiguration and MediaKeys to match draft EME spec. r=smaug The only thing we're now not up to date on (in terms of WebIDL) is the "persistent-usage-record" MediaKeySessionType. MozReview-Commit-ID: 4CKK35HAxKK --HG-- extra : rebase_source : 2015a2d0c61e09e329f5f9cc699f5d946e97862b --- dom/webidl/MediaKeySystemAccess.webidl | 19 +++++++++++++------ dom/webidl/MediaKeys.webidl | 10 ++++++++-- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/dom/webidl/MediaKeySystemAccess.webidl b/dom/webidl/MediaKeySystemAccess.webidl index 9af198a205e9..01552e449004 100644 --- a/dom/webidl/MediaKeySystemAccess.webidl +++ b/dom/webidl/MediaKeySystemAccess.webidl @@ -10,18 +10,25 @@ * W3C liability, trademark and document use rules apply. */ +enum MediaKeysRequirement { + "required", + "optional", + "not-allowed" +}; + dictionary MediaKeySystemMediaCapability { DOMString contentType = ""; - // TODO: robustness + DOMString robustness = ""; }; dictionary MediaKeySystemConfiguration { DOMString label = ""; - sequence initDataTypes; - sequence audioCapabilities; - sequence videoCapabilities; - - // TODO: distinctiveIdentifier, persistentState, sessionTypes + sequence initDataTypes = []; + sequence audioCapabilities = []; + sequence videoCapabilities = []; + MediaKeysRequirement distinctiveIdentifier = "optional"; + MediaKeysRequirement persistentState = "optional"; + sequence sessionTypes; }; [Pref="media.eme.apiVisible"] diff --git a/dom/webidl/MediaKeys.webidl b/dom/webidl/MediaKeys.webidl index 6c60f46b450b..cb84cdab6d64 100644 --- a/dom/webidl/MediaKeys.webidl +++ b/dom/webidl/MediaKeys.webidl @@ -10,14 +10,20 @@ * W3C liability, trademark and document use rules apply. */ -enum SessionType { "temporary", "persistent" }; +// Note: "persistent-usage-record" session type is unsupported yet, as +// it's marked as "at risk" in the spec, and Chrome doesn't support it. +enum MediaKeySessionType { + "temporary", + "persistent-license", + // persistent-usage-record, +}; [Pref="media.eme.apiVisible"] interface MediaKeys { readonly attribute DOMString keySystem; [NewObject, Throws] - MediaKeySession createSession(optional SessionType sessionType = "temporary"); + MediaKeySession createSession(optional MediaKeySessionType sessionType = "temporary"); [NewObject] Promise setServerCertificate((ArrayBufferView or ArrayBuffer) serverCertificate); From 1ea9b742f56d0345a9c0e1150f719f05ea0922e9 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Mon, 4 Jul 2016 14:14:01 +1200 Subject: [PATCH 084/135] Bug 1278198 - Update EME code to reflect new WebIDL name changes. r=gerald MozReview-Commit-ID: EssCsJxBBwt --HG-- extra : rebase_source : 154746eca911e2250f3fa94a6a2d4b2624910e50 --- dom/media/eme/CDMProxy.h | 4 ++-- dom/media/eme/MediaKeySession.cpp | 4 ++-- dom/media/eme/MediaKeySession.h | 4 ++-- dom/media/eme/MediaKeys.cpp | 2 +- dom/media/eme/MediaKeys.h | 2 +- dom/media/gmp/GMPCDMProxy.cpp | 8 ++++---- dom/media/gmp/GMPCDMProxy.h | 4 ++-- media/gmp-clearkey/0.1/ClearKeyUtils.cpp | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/dom/media/eme/CDMProxy.h b/dom/media/eme/CDMProxy.h index 863312bd92c1..06143e70dd35 100644 --- a/dom/media/eme/CDMProxy.h +++ b/dom/media/eme/CDMProxy.h @@ -41,7 +41,7 @@ struct DecryptResult { class CDMProxy { protected: typedef dom::PromiseId PromiseId; - typedef dom::SessionType SessionType; + typedef dom::MediaKeySessionType MediaKeySessionType; public: NS_IMETHOD_(MozExternalRefCountType) AddRef(void) = 0; @@ -68,7 +68,7 @@ public: // Calls MediaKeys::OnSessionActivated() when session is created. // Assumes ownership of (Move()s) aInitData's contents. virtual void CreateSession(uint32_t aCreateSessionToken, - dom::SessionType aSessionType, + MediaKeySessionType aSessionType, PromiseId aPromiseId, const nsAString& aInitDataType, nsTArray& aInitData) = 0; diff --git a/dom/media/eme/MediaKeySession.cpp b/dom/media/eme/MediaKeySession.cpp index 7dc7296b9843..1bf8bb5559c8 100644 --- a/dom/media/eme/MediaKeySession.cpp +++ b/dom/media/eme/MediaKeySession.cpp @@ -44,7 +44,7 @@ MediaKeySession::MediaKeySession(JSContext* aCx, MediaKeys* aKeys, const nsAString& aKeySystem, const nsAString& aCDMVersion, - SessionType aSessionType, + MediaKeySessionType aSessionType, ErrorResult& aRv) : DOMEventTargetHelper(aParent) , mKeys(aKeys) @@ -386,7 +386,7 @@ MediaKeySession::Remove(ErrorResult& aRv) NS_LITERAL_CSTRING("MediaKeySession.Remove() called before sessionId set by CDM")); return promise.forget(); } - if (mSessionType != SessionType::Persistent) { + if (mSessionType != MediaKeySessionType::Persistent_license) { promise->MaybeReject(NS_ERROR_DOM_INVALID_ACCESS_ERR, NS_LITERAL_CSTRING("Calling MediaKeySession.remove() on non-persistent session")); // "The operation is not supported on session type sessions." diff --git a/dom/media/eme/MediaKeySession.h b/dom/media/eme/MediaKeySession.h index 78e2176726f2..6d4bf8fe9d00 100644 --- a/dom/media/eme/MediaKeySession.h +++ b/dom/media/eme/MediaKeySession.h @@ -42,7 +42,7 @@ public: MediaKeys* aKeys, const nsAString& aKeySystem, const nsAString& aCDMVersion, - SessionType aSessionType, + MediaKeySessionType aSessionType, ErrorResult& aRv); void SetSessionId(const nsAString& aSessionId); @@ -119,7 +119,7 @@ private: const nsString mKeySystem; const nsString mCDMVersion; nsString mSessionId; - const SessionType mSessionType; + const MediaKeySessionType mSessionType; const uint32_t mToken; bool mIsClosed; bool mUninitialized; diff --git a/dom/media/eme/MediaKeys.cpp b/dom/media/eme/MediaKeys.cpp index 2deef3152a6e..d28ba05af26e 100644 --- a/dom/media/eme/MediaKeys.cpp +++ b/dom/media/eme/MediaKeys.cpp @@ -414,7 +414,7 @@ MediaKeys::OnCDMCreated(PromiseId aId, const nsACString& aNodeId, const uint32_t already_AddRefed MediaKeys::CreateSession(JSContext* aCx, - SessionType aSessionType, + MediaKeySessionType aSessionType, ErrorResult& aRv) { if (!mProxy) { diff --git a/dom/media/eme/MediaKeys.h b/dom/media/eme/MediaKeys.h index 2ba348f100be..4f8a12b08008 100644 --- a/dom/media/eme/MediaKeys.h +++ b/dom/media/eme/MediaKeys.h @@ -66,7 +66,7 @@ public: // JavaScript: MediaKeys.createSession() already_AddRefed CreateSession(JSContext* aCx, - SessionType aSessionType, + MediaKeySessionType aSessionType, ErrorResult& aRv); // JavaScript: MediaKeys.SetServerCertificate() diff --git a/dom/media/gmp/GMPCDMProxy.cpp b/dom/media/gmp/GMPCDMProxy.cpp index 03612167e364..78a0358a4f9f 100644 --- a/dom/media/gmp/GMPCDMProxy.cpp +++ b/dom/media/gmp/GMPCDMProxy.cpp @@ -263,7 +263,7 @@ GMPCDMProxy::OnCDMCreated(uint32_t aPromiseId) void GMPCDMProxy::CreateSession(uint32_t aCreateSessionToken, - dom::SessionType aSessionType, + dom::MediaKeySessionType aSessionType, PromiseId aPromiseId, const nsAString& aInitDataType, nsTArray& aInitData) @@ -284,10 +284,10 @@ GMPCDMProxy::CreateSession(uint32_t aCreateSessionToken, } GMPSessionType -ToGMPSessionType(dom::SessionType aSessionType) { +ToGMPSessionType(dom::MediaKeySessionType aSessionType) { switch (aSessionType) { - case dom::SessionType::Temporary: return kGMPTemporySession; - case dom::SessionType::Persistent: return kGMPPersistentSession; + case dom::MediaKeySessionType::Temporary: return kGMPTemporySession; + case dom::MediaKeySessionType::Persistent_license: return kGMPPersistentSession; default: return kGMPTemporySession; }; }; diff --git a/dom/media/gmp/GMPCDMProxy.h b/dom/media/gmp/GMPCDMProxy.h index 2c2e3fc482db..16072db0b923 100644 --- a/dom/media/gmp/GMPCDMProxy.h +++ b/dom/media/gmp/GMPCDMProxy.h @@ -33,7 +33,7 @@ public: bool aInPrivateBrowsing) override; void CreateSession(uint32_t aCreateSessionToken, - dom::SessionType aSessionType, + dom::MediaKeySessionType aSessionType, PromiseId aPromiseId, const nsAString& aInitDataType, nsTArray& aInitData) override; @@ -134,7 +134,7 @@ private: void OnCDMCreated(uint32_t aPromiseId); struct CreateSessionData { - dom::SessionType mSessionType; + dom::MediaKeySessionType mSessionType; uint32_t mCreateSessionToken; PromiseId mPromiseId; nsCString mInitDataType; diff --git a/media/gmp-clearkey/0.1/ClearKeyUtils.cpp b/media/gmp-clearkey/0.1/ClearKeyUtils.cpp index e6aeea4b6029..4bafdbcb9719 100644 --- a/media/gmp-clearkey/0.1/ClearKeyUtils.cpp +++ b/media/gmp-clearkey/0.1/ClearKeyUtils.cpp @@ -521,7 +521,7 @@ ClearKeyUtils::SessionTypeToString(GMPSessionType aSessionType) { switch (aSessionType) { case kGMPTemporySession: return "temporary"; - case kGMPPersistentSession: return "persistent"; + case kGMPPersistentSession: return "persistent-license"; default: { assert(false); // Should not reach here. return "invalid"; From e7b5f0ede075f26146ee7df3d6a15de0ad35f535 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Fri, 8 Jul 2016 09:36:27 +1200 Subject: [PATCH 085/135] Bug 1278198 - Update navigator.requestMediaKeySystemAccess() MOZ_LOG to log new EME WebIDL attributes. r=gerald MozReview-Commit-ID: 8V5YbJP0lFA --HG-- extra : rebase_source : 34e6fd16d904bfc0f04894c7999c412968b89907 --- dom/base/Navigator.cpp | 81 ++++++++++++++++++++++++++++-------------- 1 file changed, 55 insertions(+), 26 deletions(-) diff --git a/dom/base/Navigator.cpp b/dom/base/Navigator.cpp index bf626e549545..46efbee6fedf 100644 --- a/dom/base/Navigator.cpp +++ b/dom/base/Navigator.cpp @@ -2586,18 +2586,30 @@ Navigator::GetUserAgent(nsPIDOMWindowInner* aWindow, nsIURI* aURI, static nsCString ToCString(const nsString& aString) { - return NS_ConvertUTF16toUTF8(aString); + nsCString str("'"); + str.Append(NS_ConvertUTF16toUTF8(aString)); + str.AppendLiteral("'"); + return str; +} + +static nsCString +ToCString(const MediaKeysRequirement aValue) +{ + nsCString str("'"); + str.Append(nsDependentCString(MediaKeysRequirementValues::strings[static_cast(aValue)].value)); + str.AppendLiteral("'"); + return str; } static nsCString ToCString(const MediaKeySystemMediaCapability& aValue) { nsCString str; - str.AppendLiteral("{contentType='"); - if (!aValue.mContentType.IsEmpty()) { - str.Append(ToCString(aValue.mContentType)); - } - str.AppendLiteral("'}"); + str.AppendLiteral("{contentType="); + str.Append(ToCString(aValue.mContentType)); + str.AppendLiteral(", robustness="); + str.Append(ToCString(aValue.mRobustness)); + str.AppendLiteral("}"); return str; } @@ -2605,38 +2617,55 @@ template static nsCString ToCString(const Sequence& aSequence) { - nsCString s; - s.AppendLiteral("["); + nsCString str; + str.AppendLiteral("["); for (size_t i = 0; i < aSequence.Length(); i++) { if (i != 0) { - s.AppendLiteral(","); + str.AppendLiteral(","); } - s.Append(ToCString(aSequence[i])); + str.Append(ToCString(aSequence[i])); } - s.AppendLiteral("]"); - return s; + str.AppendLiteral("]"); + return str; +} + +template +static nsCString +ToCString(const Optional>& aOptional) +{ + nsCString str; + if (aOptional.WasPassed()) { + str.Append(ToCString(aOptional.Value())); + } else { + str.AppendLiteral("[]"); + } + return str; } static nsCString ToCString(const MediaKeySystemConfiguration& aConfig) { nsCString str; - str.AppendLiteral("{"); - str.AppendPrintf("label='%s'", NS_ConvertUTF16toUTF8(aConfig.mLabel).get()); + str.AppendLiteral("{label="); + str.Append(ToCString(aConfig.mLabel)); - if (aConfig.mInitDataTypes.WasPassed()) { - str.AppendLiteral(", initDataTypes="); - str.Append(ToCString(aConfig.mInitDataTypes.Value())); - } + str.AppendLiteral(", initDataTypes="); + str.Append(ToCString(aConfig.mInitDataTypes)); - if (aConfig.mAudioCapabilities.WasPassed()) { - str.AppendLiteral(", audioCapabilities="); - str.Append(ToCString(aConfig.mAudioCapabilities.Value())); - } - if (aConfig.mVideoCapabilities.WasPassed()) { - str.AppendLiteral(", videoCapabilities="); - str.Append(ToCString(aConfig.mVideoCapabilities.Value())); - } + str.AppendLiteral(", audioCapabilities="); + str.Append(ToCString(aConfig.mAudioCapabilities)); + + str.AppendLiteral(", videoCapabilities="); + str.Append(ToCString(aConfig.mVideoCapabilities)); + + str.AppendLiteral(", distinctiveIdentifier="); + str.Append(ToCString(aConfig.mDistinctiveIdentifier)); + + str.AppendLiteral(", persistentState="); + str.Append(ToCString(aConfig.mPersistentState)); + + str.AppendLiteral(", sessionTypes="); + str.Append(ToCString(aConfig.mSessionTypes)); str.AppendLiteral("}"); From 1ec646af14973d1b254841c3d93d02344d4a4508 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Fri, 1 Jul 2016 13:36:57 +1200 Subject: [PATCH 086/135] Bug 1278198 - Implement "Get Supported Configuration" algorithm in MediaKeySystemAccess. r=gerald MozReview-Commit-ID: KiJMOm5HgHe --HG-- extra : rebase_source : 0c60b76ad38cb9c5513e6618c8d8f4bc6f43b168 --- dom/media/VideoUtils.cpp | 103 +- dom/media/VideoUtils.h | 25 +- dom/media/eme/MediaKeySystemAccess.cpp | 950 ++++++++++++++---- dom/media/eme/MediaKeySystemAccessManager.cpp | 15 + dom/media/mediasource/MediaSource.cpp | 13 +- dom/media/mediasource/MediaSource.h | 1 + 6 files changed, 810 insertions(+), 297 deletions(-) diff --git a/dom/media/VideoUtils.cpp b/dom/media/VideoUtils.cpp index b12dc32b9c3e..ef7cdda857cf 100644 --- a/dom/media/VideoUtils.cpp +++ b/dom/media/VideoUtils.cpp @@ -406,16 +406,6 @@ LogToBrowserConsole(const nsAString& aMsg) console->LogStringMessage(msg.get()); } -bool -IsAACCodecString(const nsAString& aCodec) -{ - return - aCodec.EqualsLiteral("mp4a.40.2") || // MPEG4 AAC-LC - aCodec.EqualsLiteral("mp4a.40.5") || // MPEG4 HE-AAC - aCodec.EqualsLiteral("mp4a.67") || // MPEG2 AAC-LC - aCodec.EqualsLiteral("mp4a.40.29"); // MPEG4 HE-AACv2 -} - bool ParseCodecsString(const nsAString& aCodecs, nsTArray& aOutCodecs) { @@ -434,97 +424,52 @@ ParseCodecsString(const nsAString& aCodecs, nsTArray& aOutCodecs) return true; } -static bool -CheckContentType(const nsAString& aContentType, - mozilla::function aSubtypeFilter, - mozilla::function aCodecFilter) +bool +ParseMIMETypeString(const nsAString& aMIMEType, + nsString& aOutContainerType, + nsTArray& aOutCodecs) { - nsContentTypeParser parser(aContentType); - nsAutoString mimeType; - nsresult rv = parser.GetType(mimeType); - if (NS_FAILED(rv) || !aSubtypeFilter(mimeType)) { + nsContentTypeParser parser(aMIMEType); + nsresult rv = parser.GetType(aOutContainerType); + if (NS_FAILED(rv)) { return false; } nsString codecsStr; parser.GetParameter("codecs", codecsStr); - nsTArray codecs; - if (!ParseCodecsString(codecsStr, codecs)) { - return false; - } - for (const nsString& codec : codecs) { - if (!aCodecFilter(codec)) { - return false; - } - } - return true; + return ParseCodecsString(codecsStr, aOutCodecs); } bool -IsH264ContentType(const nsAString& aContentType) +IsH264CodecString(const nsAString& aCodec) { - return CheckContentType(aContentType, - [](const nsAString& type) { - return type.EqualsLiteral("video/mp4"); - }, - [](const nsAString& codec) { - int16_t profile = 0; - int16_t level = 0; - return ExtractH264CodecDetails(codec, profile, level); - } - ); + int16_t profile = 0; + int16_t level = 0; + return ExtractH264CodecDetails(aCodec, profile, level); } bool -IsAACContentType(const nsAString& aContentType) +IsAACCodecString(const nsAString& aCodec) { - return CheckContentType(aContentType, - [](const nsAString& type) { - return type.EqualsLiteral("audio/mp4") || - type.EqualsLiteral("audio/x-m4a"); - }, - [](const nsAString& codec) { - return codec.EqualsLiteral("mp4a.40.2") || // MPEG4 AAC-LC - codec.EqualsLiteral("mp4a.40.5") || // MPEG4 HE-AAC - codec.EqualsLiteral("mp4a.67"); // MPEG2 AAC-LC - }); + return + aCodec.EqualsLiteral("mp4a.40.2") || // MPEG4 AAC-LC + aCodec.EqualsLiteral("mp4a.40.5") || // MPEG4 HE-AAC + aCodec.EqualsLiteral("mp4a.67") || // MPEG2 AAC-LC + aCodec.EqualsLiteral("mp4a.40.29"); // MPEG4 HE-AACv2 } bool -IsVorbisContentType(const nsAString& aContentType) +IsVP8CodecString(const nsAString& aCodec) { - return CheckContentType(aContentType, - [](const nsAString& type) { - return type.EqualsLiteral("audio/webm") || - type.EqualsLiteral("audio/ogg"); - }, - [](const nsAString& codec) { - return codec.EqualsLiteral("vorbis"); - }); + return aCodec.EqualsLiteral("vp8") || + aCodec.EqualsLiteral("vp8.0"); } bool -IsVP8ContentType(const nsAString& aContentType) +IsVP9CodecString(const nsAString& aCodec) { - return CheckContentType(aContentType, - [](const nsAString& type) { - return type.EqualsLiteral("video/webm"); - }, - [](const nsAString& codec) { - return codec.EqualsLiteral("vp8"); - }); -} - -bool -IsVP9ContentType(const nsAString& aContentType) -{ - return CheckContentType(aContentType, - [](const nsAString& type) { - return type.EqualsLiteral("video/webm"); - }, - [](const nsAString& codec) { - return codec.EqualsLiteral("vp9"); - }); + return aCodec.EqualsLiteral("vp9") || + aCodec.EqualsLiteral("vp9.0"); } } // end namespace mozilla diff --git a/dom/media/VideoUtils.h b/dom/media/VideoUtils.h index e6b2e1e1c0f1..dc3653ca61fa 100644 --- a/dom/media/VideoUtils.h +++ b/dom/media/VideoUtils.h @@ -322,18 +322,26 @@ private: void LogToBrowserConsole(const nsAString& aMsg); +bool +ParseMIMETypeString(const nsAString& aMIMEType, + nsString& aOutContainerType, + nsTArray& aOutCodecs); + bool ParseCodecsString(const nsAString& aCodecs, nsTArray& aOutCodecs); bool -IsH264ContentType(const nsAString& aContentType); - -bool -IsAACContentType(const nsAString& aContentType); +IsH264CodecString(const nsAString& aCodec); bool IsAACCodecString(const nsAString& aCodec); +bool +IsVP8CodecString(const nsAString& aCodec); + +bool +IsVP9CodecString(const nsAString& aCodec); + template class StringListRange { @@ -447,15 +455,6 @@ StringListContains(const ListString& aList, const ItemString& aItem) return false; } -bool -IsVorbisContentType(const nsAString& aContentType); - -bool -IsVP8ContentType(const nsAString& aContentType); - -bool -IsVP9ContentType(const nsAString& aContentType); - } // end namespace mozilla #endif diff --git a/dom/media/eme/MediaKeySystemAccess.cpp b/dom/media/eme/MediaKeySystemAccess.cpp index f7d382b1ce95..f36fb759a530 100644 --- a/dom/media/eme/MediaKeySystemAccess.cpp +++ b/dom/media/eme/MediaKeySystemAccess.cpp @@ -33,6 +33,10 @@ #include "gmp-video-decode.h" #include "DecoderDoctorDiagnostics.h" #include "WebMDecoder.h" +#include "mozilla/StaticPtr.h" +#include "mozilla/ClearOnShutdown.h" +#include "nsUnicharUtils.h" +#include "mozilla/dom/MediaSource.h" namespace mozilla { namespace dom { @@ -313,252 +317,797 @@ MediaKeySystemAccess::GetKeySystemStatus(const nsAString& aKeySystem, return MediaKeySystemStatus::Cdm_not_supported; } +typedef nsCString GMPCodecString; + +#define GMP_CODEC_AAC NS_LITERAL_CSTRING("aac") +#define GMP_CODEC_OPUS NS_LITERAL_CSTRING("opus") +#define GMP_CODEC_VORBIS NS_LITERAL_CSTRING("vorbis") +#define GMP_CODEC_H264 NS_LITERAL_CSTRING("h264") +#define GMP_CODEC_VP8 NS_LITERAL_CSTRING("vp8") +#define GMP_CODEC_VP9 NS_LITERAL_CSTRING("vp9") + +GMPCodecString +ToGMPAPICodecString(const nsString& aCodec) +{ + if (IsAACCodecString(aCodec)) { + return GMP_CODEC_AAC; + } + if (aCodec.EqualsLiteral("opus")) { + return GMP_CODEC_OPUS; + } + if (aCodec.EqualsLiteral("vorbis")) { + return GMP_CODEC_VORBIS; + } + if (IsH264CodecString(aCodec)) { + return GMP_CODEC_H264; + } + if (IsVP8CodecString(aCodec)) { + return GMP_CODEC_VP8; + } + if (IsVP9CodecString(aCodec)) { + return GMP_CODEC_VP9; + } + return EmptyCString(); +} + +// A codec can be decrypted-and-decoded by the CDM, or only decrypted +// by the CDM and decoded by Gecko. Not both. +struct KeySystemContainerSupport +{ + bool IsSupported() const + { + return !mCodecsDecoded.IsEmpty() || !mCodecsDecrypted.IsEmpty(); + } + + // CDM decrypts and decodes using a DRM robust decoder, and passes decoded + // samples back to Gecko for rendering. + bool DecryptsAndDecodes(GMPCodecString aCodec) const + { + return mCodecsDecoded.Contains(aCodec); + } + + // CDM decrypts and passes the decrypted samples back to Gecko for decoding. + bool Decrypts(GMPCodecString aCodec) const + { + return mCodecsDecrypted.Contains(aCodec); + } + + void SetCanDecryptAndDecode(GMPCodecString aCodec) + { + // Can't both decrypt and decrypt-and-decode a codec. + MOZ_ASSERT(!Decrypts(aCodec)); + // Prevent duplicates. + MOZ_ASSERT(!DecryptsAndDecodes(aCodec)); + mCodecsDecoded.AppendElement(aCodec); + } + + void SetCanDecrypt(GMPCodecString aCodec) + { + // Prevent duplicates. + MOZ_ASSERT(!Decrypts(aCodec)); + // Can't both decrypt and decrypt-and-decode a codec. + MOZ_ASSERT(!DecryptsAndDecodes(aCodec)); + mCodecsDecrypted.AppendElement(aCodec); + } + +private: + nsTArray mCodecsDecoded; + nsTArray mCodecsDecrypted; +}; + +enum class KeySystemFeatureSupport +{ + Prohibited = 1, + Requestable = 2, + Required = 3, +}; + +struct KeySystemConfig +{ + nsString mKeySystem; + nsTArray mInitDataTypes; + KeySystemFeatureSupport mPersistentState = KeySystemFeatureSupport::Prohibited; + KeySystemFeatureSupport mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited; + nsTArray mSessionTypes; + nsTArray mVideoRobustness; + nsTArray mAudioRobustness; + KeySystemContainerSupport mMP4; + KeySystemContainerSupport mWebM; +}; + +StaticAutoPtr> sKeySystemConfigs; + +static const nsTArray& +GetSupportedKeySystems() +{ + if (!sKeySystemConfigs) { + sKeySystemConfigs = new nsTArray(); + ClearOnShutdown(&sKeySystemConfigs); + + { + KeySystemConfig clearkey; + clearkey.mKeySystem = NS_LITERAL_STRING("org.w3.clearkey"); + clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc")); + clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("keyids")); + clearkey.mInitDataTypes.AppendElement(NS_LITERAL_STRING("webm")); + clearkey.mPersistentState = KeySystemFeatureSupport::Requestable; + clearkey.mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited; + clearkey.mSessionTypes.AppendElement(MediaKeySessionType::Temporary); + clearkey.mSessionTypes.AppendElement(MediaKeySessionType::Persistent_license); +#if defined(XP_WIN) + // Clearkey CDM uses WMF decoders on Windows. + if (WMFDecoderModule::HasAAC()) { + clearkey.mMP4.SetCanDecryptAndDecode(GMP_CODEC_AAC); + } else { + clearkey.mMP4.SetCanDecrypt(GMP_CODEC_AAC); + } + if (WMFDecoderModule::HasH264()) { + clearkey.mMP4.SetCanDecryptAndDecode(GMP_CODEC_H264); + } else { + clearkey.mMP4.SetCanDecrypt(GMP_CODEC_H264); + } +#else + clearkey.mMP4.SetCanDecrypt(GMP_CODEC_AAC); + clearkey.mMP4.SetCanDecrypt(GMP_CODEC_H264); +#endif + clearkey.mWebM.SetCanDecrypt(GMP_CODEC_VORBIS); + clearkey.mWebM.SetCanDecrypt(GMP_CODEC_OPUS); + clearkey.mWebM.SetCanDecrypt(GMP_CODEC_VP8); + clearkey.mWebM.SetCanDecrypt(GMP_CODEC_VP9); + sKeySystemConfigs->AppendElement(Move(clearkey)); + } + { + KeySystemConfig widevine; + widevine.mKeySystem = NS_LITERAL_STRING("com.widevine.alpha"); + widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc")); + widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("keyids")); + widevine.mInitDataTypes.AppendElement(NS_LITERAL_STRING("webm")); + widevine.mPersistentState = KeySystemFeatureSupport::Requestable; + widevine.mDistinctiveIdentifier = KeySystemFeatureSupport::Prohibited; + widevine.mSessionTypes.AppendElement(MediaKeySessionType::Temporary); + widevine.mAudioRobustness.AppendElement(NS_LITERAL_STRING("SW_SECURE_CRYPTO")); + widevine.mVideoRobustness.AppendElement(NS_LITERAL_STRING("SW_SECURE_DECODE")); +#if defined(XP_WIN) + // Widevine CDM doesn't include an AAC decoder. So if WMF can't + // decode AAC, and a codec wasn't specified, be conservative + // and reject the MediaKeys request, since our policy is to prevent + // the Adobe GMP's unencrypted AAC decoding path being used to + // decode content decrypted by the Widevine CDM. + if (WMFDecoderModule::HasAAC()) { + widevine.mMP4.SetCanDecrypt(GMP_CODEC_AAC); + } +#else + widevine.mMP4.SetCanDecrypt(GMP_CODEC_AAC); +#endif + widevine.mMP4.SetCanDecryptAndDecode(GMP_CODEC_H264); + // TODO: Enable Widevine/WebM once bug 1279077 lands. + //widevine.mWebM.SetCanDecrypt(GMP_CODEC_VORBIS); + //widevine.mWebM.SetCanDecrypt(GMP_CODEC_OPUS); + //widevine.mWebM.SetCanDecryptAndDecode(GMP_CODEC_VP8); + //widevine.mWebM.SetCanDecryptAndDecode(GMP_CODEC_VP9); + sKeySystemConfigs->AppendElement(Move(widevine)); + } + { + KeySystemConfig primetime; + primetime.mKeySystem = NS_LITERAL_STRING("com.adobe.primetime"); + primetime.mInitDataTypes.AppendElement(NS_LITERAL_STRING("cenc")); + primetime.mPersistentState = KeySystemFeatureSupport::Required; + primetime.mDistinctiveIdentifier = KeySystemFeatureSupport::Required; + primetime.mSessionTypes.AppendElement(MediaKeySessionType::Temporary); + primetime.mMP4.SetCanDecryptAndDecode(GMP_CODEC_AAC); + primetime.mMP4.SetCanDecryptAndDecode(GMP_CODEC_H264); + sKeySystemConfigs->AppendElement(Move(primetime)); + } + } + return *sKeySystemConfigs; +} + +static const KeySystemConfig* +GetKeySystemConfig(const nsAString& aKeySystem) +{ + for (const KeySystemConfig& config : GetSupportedKeySystems()) { + if (config.mKeySystem.Equals(aKeySystem)) { + return &config; + } + } + return nullptr; +} + +enum CodecType +{ + Audio, + Video, + Invalid +}; + static bool -GMPDecryptsAndDecodesAAC(mozIGeckoMediaPluginService* aGMPS, - const nsAString& aKeySystem, +CanDecryptAndDecode(mozIGeckoMediaPluginService* aGMPService, + const nsString& aKeySystem, + const nsString& aContentType, + CodecType aCodecType, + const KeySystemContainerSupport& aContainerSupport, + const nsTArray& aCodecs, + DecoderDoctorDiagnostics* aDiagnostics) +{ + MOZ_ASSERT(aCodecType != Invalid); + MOZ_ASSERT(HaveGMPFor(aGMPService, + NS_ConvertUTF16toUTF8(aKeySystem), + NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))); + for (const GMPCodecString& codec : aCodecs) { + MOZ_ASSERT(!codec.IsEmpty()); + + nsCString api = (aCodecType == Audio) ? NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER) + : NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER); + if (aContainerSupport.DecryptsAndDecodes(codec) && + HaveGMPFor(aGMPService, + NS_ConvertUTF16toUTF8(aKeySystem), + api, + codec)) { + // GMP can decrypt-and-decode this codec. + continue; + } + + if (aContainerSupport.Decrypts(codec) && + NS_SUCCEEDED(MediaSource::IsTypeSupported(aContentType, aDiagnostics))) { + // GMP can decrypt and is allowed to return compressed samples to + // Gecko to decode, and Gecko has a decoder. + continue; + } + + // Neither the GMP nor Gecko can both decrypt and decode. We don't + // support this codec. + +#if defined(XP_WIN) + // Widevine CDM doesn't include an AAC decoder. So if WMF can't + // decode AAC, and a codec wasn't specified, be conservative + // and reject the MediaKeys request, since our policy is to prevent + // the Adobe GMP's unencrypted AAC decoding path being used to + // decode content decrypted by the Widevine CDM. + if (codec == GMP_CODEC_AAC && + aKeySystem.EqualsLiteral("com.widevine.alpha") && + !WMFDecoderModule::HasAAC()) { + if (aDiagnostics) { + aDiagnostics->SetKeySystemIssue( + DecoderDoctorDiagnostics::eWidevineWithNoWMF); + } + } +#endif + return false; + } + return true; +} + +static bool +ToSessionType(const nsAString& aSessionType, MediaKeySessionType& aOutType) +{ + using MediaKeySessionTypeValues::strings; + const char* temporary = + strings[static_cast(MediaKeySessionType::Temporary)].value; + if (aSessionType.EqualsASCII(temporary)) { + aOutType = MediaKeySessionType::Temporary; + return true; + } + const char* persistentLicense = + strings[static_cast(MediaKeySessionType::Persistent_license)].value; + if (aSessionType.EqualsASCII(persistentLicense)) { + aOutType = MediaKeySessionType::Persistent_license; + return true; + } + return false; +} + +// 5.2.1 Is persistent session type? +static bool +IsPersistentSessionType(MediaKeySessionType aSessionType) +{ + return aSessionType == MediaKeySessionType::Persistent_license; +} + +CodecType +GetMajorType(const nsAString& aContentType) +{ + if (CaseInsensitiveFindInReadable(NS_LITERAL_STRING("audio/"), aContentType)) { + return Audio; + } + if (CaseInsensitiveFindInReadable(NS_LITERAL_STRING("video/"), aContentType)) { + return Video; + } + return Invalid; +} + +// 3.1.2.3 Get Supported Capabilities for Audio/Video Type +static Sequence +GetSupportedCapabilities(mozIGeckoMediaPluginService* aGMPService, + const nsTArray& aRequestedCapabilities, + const MediaKeySystemConfiguration& aPartialConfig, + const KeySystemConfig& aKeySystem, DecoderDoctorDiagnostics* aDiagnostics) { - MOZ_ASSERT(HaveGMPFor(aGMPS, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))); - return HaveGMPFor(aGMPS, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER), - NS_LITERAL_CSTRING("aac")); -} + // Let local accumulated configuration be a local copy of partial configuration. + // (Note: It's not necessary for us to maintain a local copy, as we don't need + // to test whether capabilites from previous calls to this algorithm work with + // the capabilities currently being considered in this call. ) -static bool -GMPDecryptsAndDecodesH264(mozIGeckoMediaPluginService* aGMPS, - const nsAString& aKeySystem, - DecoderDoctorDiagnostics* aDiagnostics) -{ - MOZ_ASSERT(HaveGMPFor(aGMPS, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))); - return HaveGMPFor(aGMPS, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER), - NS_LITERAL_CSTRING("h264")); -} + // Let supported media capabilities be an empty sequence of + // MediaKeySystemMediaCapability dictionaries. + Sequence supportedCapabilities; -// If this keysystem's CDM explicitly says it doesn't support decoding, -// that means it's OK with passing the decrypted samples back to Gecko -// for decoding. -static bool -GMPDecryptsAndGeckoDecodesH264(mozIGeckoMediaPluginService* aGMPService, - const nsAString& aKeySystem, - const nsAString& aContentType, - DecoderDoctorDiagnostics* aDiagnostics) -{ - MOZ_ASSERT(HaveGMPFor(aGMPService, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))); - MOZ_ASSERT(IsH264ContentType(aContentType)); - return !HaveGMPFor(aGMPService, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER), - NS_LITERAL_CSTRING("h264")) && - MP4Decoder::CanHandleMediaType(aContentType, aDiagnostics); -} - -static bool -GMPDecryptsAndGeckoDecodesAAC(mozIGeckoMediaPluginService* aGMPService, - const nsAString& aKeySystem, - const nsAString& aContentType, - DecoderDoctorDiagnostics* aDiagnostics) -{ - MOZ_ASSERT(HaveGMPFor(aGMPService, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))); - MOZ_ASSERT(IsAACContentType(aContentType)); - - if (HaveGMPFor(aGMPService, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER), - NS_LITERAL_CSTRING("aac"))) { - // We do have a GMP for AAC -> Gecko itself does *not* decode AAC. - return false; - } -#if defined(XP_WIN) - // Widevine CDM doesn't include an AAC decoder. So if WMF can't - // decode AAC, and a codec wasn't specified, be conservative - // and reject the MediaKeys request, since our policy is to prevent - // the Adobe GMP's unencrypted AAC decoding path being used to - // decode content decrypted by the Widevine CDM. - if (aKeySystem.EqualsLiteral("com.widevine.alpha") && - !WMFDecoderModule::HasAAC()) { - if (aDiagnostics) { - aDiagnostics->SetKeySystemIssue( - DecoderDoctorDiagnostics::eWidevineWithNoWMF); + // For each requested media capability in requested media capabilities: + for (const MediaKeySystemMediaCapability& capabilities : aRequestedCapabilities) { + // Let content type be requested media capability's contentType member. + const nsString& contentType = capabilities.mContentType; + // Let robustness be requested media capability's robustness member. + const nsString& robustness = capabilities.mRobustness; + // If content type is the empty string, return null. + if (contentType.IsEmpty()) { + EME_LOG("MediaKeySystemConfiguration (label='%s') " + "MediaKeySystemMediaCapability('%s','%s') rejected; " + "audio or video capability has empty contentType.", + NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), + NS_ConvertUTF16toUTF8(contentType).get(), + NS_ConvertUTF16toUTF8(robustness).get()); + return Sequence(); } - return false; + // If content type is an invalid or unrecognized MIME type, continue + // to the next iteration. + nsAutoString container; + nsTArray codecStrings; + if (!ParseMIMETypeString(contentType, container, codecStrings)) { + EME_LOG("MediaKeySystemConfiguration (label='%s') " + "MediaKeySystemMediaCapability('%s','%s') unsupported; " + "failed to parse contentType as MIME type.", + NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), + NS_ConvertUTF16toUTF8(contentType).get(), + NS_ConvertUTF16toUTF8(robustness).get()); + continue; + } + bool invalid = false; + nsTArray codecs; + for (const nsString& codecString : codecStrings) { + GMPCodecString gmpCodec = ToGMPAPICodecString(codecString); + if (gmpCodec.IsEmpty()) { + invalid = true; + EME_LOG("MediaKeySystemConfiguration (label='%s') " + "MediaKeySystemMediaCapability('%s','%s') unsupported; " + "'%s' is an invalid codec string.", + NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), + NS_ConvertUTF16toUTF8(contentType).get(), + NS_ConvertUTF16toUTF8(robustness).get(), + NS_ConvertUTF16toUTF8(codecString).get()); + break; + } + codecs.AppendElement(gmpCodec); + } + if (invalid) { + continue; + } + + // If the user agent does not support container, continue to the next iteration. + // The case-sensitivity of string comparisons is determined by the appropriate RFC. + // (Note: Per RFC 6838 [RFC6838], "Both top-level type and subtype names are + // case-insensitive."'. We're using nsContentTypeParser and that is + // case-insensitive and converts all its parameter outputs to lower case.) + NS_ConvertUTF16toUTF8 container_utf8(container); + const bool isMP4 = DecoderTraits::IsMP4TypeAndEnabled(container_utf8, aDiagnostics); + if (isMP4 && !aKeySystem.mMP4.IsSupported()) { + EME_LOG("MediaKeySystemConfiguration (label='%s') " + "MediaKeySystemMediaCapability('%s','%s') unsupported; " + "MP4 requested but unsupported.", + NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), + NS_ConvertUTF16toUTF8(contentType).get(), + NS_ConvertUTF16toUTF8(robustness).get()); + continue; + } + const bool isWebM = DecoderTraits::IsWebMTypeAndEnabled(container_utf8); + if (isWebM && !aKeySystem.mWebM.IsSupported()) { + EME_LOG("MediaKeySystemConfiguration (label='%s') " + "MediaKeySystemMediaCapability('%s','%s') unsupported; " + "WebM requested but unsupported.", + NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), + NS_ConvertUTF16toUTF8(contentType).get(), + NS_ConvertUTF16toUTF8(robustness).get()); + continue; + } + if (!isMP4 && !isWebM) { + EME_LOG("MediaKeySystemConfiguration (label='%s') " + "MediaKeySystemMediaCapability('%s','%s') unsupported; " + "Unsupported or unrecognized container requested.", + NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), + NS_ConvertUTF16toUTF8(contentType).get(), + NS_ConvertUTF16toUTF8(robustness).get()); + continue; + } + + // Let parameters be the RFC 6381[RFC6381] parameters, if any, specified by + // content type. + // If the user agent does not recognize one or more parameters, continue to + // the next iteration. + // Let media types be the set of codecs and codec constraints specified by + // parameters. The case-sensitivity of string comparisons is determined by + // the appropriate RFC or other specification. + // (Note: codecs array is 'parameter'). + + // If media types is empty: + const auto majorType = GetMajorType(container); + if (codecs.IsEmpty()) { + // If container normatively implies a specific set of codecs and codec constraints: + // Let parameters be that set. + if (isMP4) { + if (majorType == Audio) { + codecs.AppendElement(GMP_CODEC_AAC); + } else if (majorType == Video) { + codecs.AppendElement(GMP_CODEC_H264); + } + } else if (isWebM) { + if (majorType == Audio) { + codecs.AppendElement(GMP_CODEC_VORBIS); + } else if (majorType == Video) { + codecs.AppendElement(GMP_CODEC_VP8); + } + } + // Otherwise: Continue to the next iteration. + // (Note: all containers we support have implied codecs, so don't continue here.) + } + + // If content type is not strictly a audio/video type, continue to the next iteration. + if (majorType == Invalid) { + EME_LOG("MediaKeySystemConfiguration (label='%s') " + "MediaKeySystemMediaCapability('%s','%s') unsupported; " + "MIME type is not an audio or video MIME type.", + NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), + NS_ConvertUTF16toUTF8(contentType).get(), + NS_ConvertUTF16toUTF8(robustness).get()); + continue; + } + + // If robustness is not the empty string and contains an unrecognized + // value or a value not supported by implementation, continue to the + // next iteration. String comparison is case-sensitive. + if (!robustness.IsEmpty()) { + if (majorType == Audio && !aKeySystem.mAudioRobustness.Contains(robustness)) { + EME_LOG("MediaKeySystemConfiguration (label='%s') " + "MediaKeySystemMediaCapability('%s','%s') unsupported; " + "unsupported robustness string.", + NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), + NS_ConvertUTF16toUTF8(contentType).get(), + NS_ConvertUTF16toUTF8(robustness).get()); + continue; + } + if (majorType == Video && !aKeySystem.mVideoRobustness.Contains(robustness)) { + EME_LOG("MediaKeySystemConfiguration (label='%s') " + "MediaKeySystemMediaCapability('%s','%s') unsupported; " + "unsupported robustness string.", + NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), + NS_ConvertUTF16toUTF8(contentType).get(), + NS_ConvertUTF16toUTF8(robustness).get()); + continue; + } + // Note: specified robustness requirements are satisfied. + } + + // If the user agent and implementation definitely support playback of + // encrypted media data for the combination of container, media types, + // robustness and local accumulated configuration in combination with + // restrictions... + const auto& containerSupport = isMP4 ? aKeySystem.mMP4 : aKeySystem.mWebM; + if (!CanDecryptAndDecode(aGMPService, + aKeySystem.mKeySystem, + contentType, + majorType, + containerSupport, + codecs, + aDiagnostics)) { + EME_LOG("MediaKeySystemConfiguration (label='%s') " + "MediaKeySystemMediaCapability('%s','%s') unsupported; " + "codec unsupported by CDM requested.", + NS_ConvertUTF16toUTF8(aPartialConfig.mLabel).get(), + NS_ConvertUTF16toUTF8(contentType).get(), + NS_ConvertUTF16toUTF8(robustness).get()); + continue; + } + + // ... add requested media capability to supported media capabilities. + if (!supportedCapabilities.AppendElement(capabilities, mozilla::fallible)) { + NS_WARNING("GetSupportedCapabilities: Malloc failure"); + return Sequence(); + } + + // Note: omitting steps 3.13.2, our robustness is not sophisticated enough + // to require considering all requirements together. } -#endif - return MP4Decoder::CanHandleMediaType(aContentType, aDiagnostics); + return Move(supportedCapabilities); } +// "Get Supported Configuration and Consent" algorithm, steps 4-7 for +// distinctive identifier, and steps 8-11 for persistent state. The steps +// are the same for both requirements/features, so we factor them out into +// a single function. static bool -GMPDecryptsAndGeckoDecodesVorbis(mozIGeckoMediaPluginService* aGMPService, - const nsAString& aKeySystem, - const nsAString& aContentType, - DecoderDoctorDiagnostics* aDiagnostics) +CheckRequirement(const MediaKeysRequirement aRequirement, + const KeySystemFeatureSupport aFeatureSupport, + MediaKeysRequirement& aOutRequirement) { - MOZ_ASSERT(HaveGMPFor(aGMPService, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))); - MOZ_ASSERT(IsVorbisContentType(aContentType)); - return !HaveGMPFor(aGMPService, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_AUDIO_DECODER), - NS_LITERAL_CSTRING("vorbis")) && - WebMDecoder::CanHandleMediaType(aContentType); -} - -static bool -GMPDecryptsAndGeckoDecodesVP8(mozIGeckoMediaPluginService* aGMPService, - const nsAString& aKeySystem, - const nsAString& aContentType, - DecoderDoctorDiagnostics* aDiagnostics) -{ - MOZ_ASSERT(HaveGMPFor(aGMPService, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))); - MOZ_ASSERT(IsVP8ContentType(aContentType)); - return !HaveGMPFor(aGMPService, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER), - NS_LITERAL_CSTRING("vp8")) && - WebMDecoder::CanHandleMediaType(aContentType); -} - -static bool -GMPDecryptsAndGeckoDecodesVP9(mozIGeckoMediaPluginService* aGMPService, - const nsAString& aKeySystem, - const nsAString& aContentType, - DecoderDoctorDiagnostics* aDiagnostics) -{ - MOZ_ASSERT(HaveGMPFor(aGMPService, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))); - MOZ_ASSERT(IsVP9ContentType(aContentType)); - return !HaveGMPFor(aGMPService, - NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_VIDEO_DECODER), - NS_LITERAL_CSTRING("vp9")) && - WebMDecoder::CanHandleMediaType(aContentType); -} - -static bool -IsSupportedAudio(mozIGeckoMediaPluginService* aGMPService, - const nsAString& aKeySystem, - const nsAString& aAudioType, - DecoderDoctorDiagnostics* aDiagnostics) -{ - if (IsAACContentType(aAudioType)) { - return GMPDecryptsAndDecodesAAC(aGMPService, aKeySystem, aDiagnostics) || - GMPDecryptsAndGeckoDecodesAAC(aGMPService, aKeySystem, aAudioType, aDiagnostics); + // Let requirement be the value of candidate configuration's member. + MediaKeysRequirement requirement = aRequirement; + // If requirement is "optional" and feature is not allowed according to + // restrictions, set requirement to "not-allowed". + if (aRequirement == MediaKeysRequirement::Optional && + aFeatureSupport == KeySystemFeatureSupport::Prohibited) { + requirement = MediaKeysRequirement::Not_allowed; } - if (IsVorbisContentType(aAudioType) && aKeySystem.EqualsLiteral("org.w3.clearkey")) { - // GMP does not decode Vorbis, so don't bother checking - return GMPDecryptsAndGeckoDecodesVorbis(aGMPService, aKeySystem, aAudioType, aDiagnostics); + + // Follow the steps for requirement from the following list: + switch (requirement) { + case MediaKeysRequirement::Required: { + // If the implementation does not support use of requirement in combination + // with accumulated configuration and restrictions, return NotSupported. + if (aFeatureSupport == KeySystemFeatureSupport::Prohibited) { + return false; + } + break; + } + case MediaKeysRequirement::Optional: { + // Continue with the following steps. + break; + } + case MediaKeysRequirement::Not_allowed: { + // If the implementation requires use of feature in combination with + // accumulated configuration and restrictions, return NotSupported. + if (aFeatureSupport == KeySystemFeatureSupport::Required) { + return false; + } + break; + } + default: { + return false; + } } - return false; + + // Set the requirement member of accumulated configuration to equal + // calculated requirement. + aOutRequirement = requirement; + + return true; } -static bool -IsSupportedVideo(mozIGeckoMediaPluginService* aGMPService, - const nsAString& aKeySystem, - const nsAString& aVideoType, - DecoderDoctorDiagnostics* aDiagnostics) +// 3.1.2.2, step 12 +// Follow the steps for the first matching condition from the following list: +// If the sessionTypes member is present in candidate configuration. +// Let session types be candidate configuration's sessionTypes member. +// Otherwise let session types be ["temporary"]. +// Note: This returns an empty array on malloc failure. +static Sequence +UnboxSessionTypes(const Optional>& aSessionTypes) { - if (IsH264ContentType(aVideoType)) { - return GMPDecryptsAndDecodesH264(aGMPService, aKeySystem, aDiagnostics) || - GMPDecryptsAndGeckoDecodesH264(aGMPService, aKeySystem, aVideoType, aDiagnostics); + Sequence sessionTypes; + if (aSessionTypes.WasPassed()) { + sessionTypes = aSessionTypes.Value(); + } else { + using MediaKeySessionTypeValues::strings; + const char* temporary = strings[static_cast(MediaKeySessionType::Temporary)].value; + // Note: fallible. Results in an empty array. + sessionTypes.AppendElement(NS_ConvertUTF8toUTF16(nsDependentCString(temporary)), mozilla::fallible); } - if (IsVP8ContentType(aVideoType) && aKeySystem.EqualsLiteral("org.w3.clearkey")) { - return GMPDecryptsAndGeckoDecodesVP8(aGMPService, aKeySystem, aVideoType, aDiagnostics); - } - if (IsVP9ContentType(aVideoType) && aKeySystem.EqualsLiteral("org.w3.clearkey")) { - return GMPDecryptsAndGeckoDecodesVP9(aGMPService, aKeySystem, aVideoType, aDiagnostics); - } - return false; -} - -static bool -IsSupportedInitDataType(const nsString& aCandidate, const nsAString& aKeySystem) -{ - // All supported keySystems can handle "cenc" initDataType. - // ClearKey also supports "keyids" and "webm" initDataTypes. - return aCandidate.EqualsLiteral("cenc") || - ((aKeySystem.EqualsLiteral("org.w3.clearkey") - || aKeySystem.EqualsLiteral("com.widevine.alpha")) && - (aCandidate.EqualsLiteral("keyids") || aCandidate.EqualsLiteral("webm"))); + return sessionTypes; } +// 3.1.2.2 Get Supported Configuration and Consent static bool GetSupportedConfig(mozIGeckoMediaPluginService* aGMPService, - const nsAString& aKeySystem, + const KeySystemConfig& aKeySystem, const MediaKeySystemConfiguration& aCandidate, MediaKeySystemConfiguration& aOutConfig, DecoderDoctorDiagnostics* aDiagnostics) { + // Let accumulated configuration be a new MediaKeySystemConfiguration dictionary. MediaKeySystemConfiguration config; + // Set the label member of accumulated configuration to equal the label member of + // candidate configuration. config.mLabel = aCandidate.mLabel; - if (aCandidate.mInitDataTypes.WasPassed()) { - nsTArray initDataTypes; - for (const nsString& candidate : aCandidate.mInitDataTypes.Value()) { - if (IsSupportedInitDataType(candidate, aKeySystem)) { - initDataTypes.AppendElement(candidate); + // If the initDataTypes member of candidate configuration is non-empty, run the + // following steps: + if (!aCandidate.mInitDataTypes.IsEmpty()) { + // Let supported types be an empty sequence of DOMStrings. + nsTArray supportedTypes; + // For each value in candidate configuration's initDataTypes member: + for (const nsString& initDataType : aCandidate.mInitDataTypes) { + // Let initDataType be the value. + // If the implementation supports generating requests based on initDataType, + // add initDataType to supported types. String comparison is case-sensitive. + // The empty string is never supported. + if (aKeySystem.mInitDataTypes.Contains(initDataType)) { + supportedTypes.AppendElement(initDataType); } } - if (initDataTypes.IsEmpty()) { + // If supported types is empty, return NotSupported. + if (supportedTypes.IsEmpty()) { + EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " + "no supported initDataTypes provided.", + NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); return false; } - config.mInitDataTypes.Construct(); - config.mInitDataTypes.Value().Assign(initDataTypes); - } - if (aCandidate.mAudioCapabilities.WasPassed()) { - nsTArray caps; - for (const MediaKeySystemMediaCapability& cap : aCandidate.mAudioCapabilities.Value()) { - if (IsSupportedAudio(aGMPService, aKeySystem, cap.mContentType, aDiagnostics)) { - caps.AppendElement(cap); - } + // Set the initDataTypes member of accumulated configuration to supported types. + if (!config.mInitDataTypes.Assign(supportedTypes)) { + return false; } + } + + if (!CheckRequirement(aCandidate.mDistinctiveIdentifier, + aKeySystem.mDistinctiveIdentifier, + config.mDistinctiveIdentifier)) { + EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " + "distinctiveIdentifier requirement not satisfied.", + NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); + return false; + } + + if (!CheckRequirement(aCandidate.mPersistentState, + aKeySystem.mPersistentState, + config.mPersistentState)) { + EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " + "persistentState requirement not satisfied.", + NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); + return false; + } + + Sequence sessionTypes(UnboxSessionTypes(aCandidate.mSessionTypes)); + if (sessionTypes.IsEmpty()) { + // Malloc failure. + return false; + } + + // For each value in session types: + for (const auto& sessionTypeString : sessionTypes) { + // Let session type be the value. + MediaKeySessionType sessionType; + if (!ToSessionType(sessionTypeString, sessionType)) { + // (Assume invalid sessionType is unsupported as per steps below). + EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " + "invalid session type specified.", + NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); + return false; + } + // If accumulated configuration's persistentState value is "not-allowed" + // and the Is persistent session type? algorithm returns true for session + // type return NotSupported. + if (config.mPersistentState == MediaKeysRequirement::Not_allowed && + IsPersistentSessionType(sessionType)) { + EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " + "persistent session requested but keysystem doesn't" + "support persistent state.", + NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); + return false; + } + // If the implementation does not support session type in combination + // with accumulated configuration and restrictions for other reasons, + // return NotSupported. + if (!aKeySystem.mSessionTypes.Contains(sessionType)) { + EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " + "session type '%s' unsupported by keySystem.", + NS_ConvertUTF16toUTF8(aCandidate.mLabel).get(), + NS_ConvertUTF16toUTF8(sessionTypeString).get()); + return false; + } + // If accumulated configuration's persistentState value is "optional" + // and the result of running the Is persistent session type? algorithm + // on session type is true, change accumulated configuration's + // persistentState value to "required". + if (config.mPersistentState == MediaKeysRequirement::Optional && + IsPersistentSessionType(sessionType)) { + config.mPersistentState = MediaKeysRequirement::Required; + } + } + // Set the sessionTypes member of accumulated configuration to session types. + config.mSessionTypes.Construct(Move(sessionTypes)); + + // If the videoCapabilities and audioCapabilities members in candidate + // configuration are both empty, return NotSupported. + // TODO: Most sites using EME still don't pass capabilities, so we + // can't reject on it yet without breaking them. So add this later. + + // If the videoCapabilities member in candidate configuration is non-empty: + if (!aCandidate.mVideoCapabilities.IsEmpty()) { + // Let video capabilities be the result of executing the Get Supported + // Capabilities for Audio/Video Type algorithm on Video, candidate + // configuration's videoCapabilities member, accumulated configuration, + // and restrictions. + Sequence caps = + GetSupportedCapabilities(aGMPService, + aCandidate.mVideoCapabilities, + config, + aKeySystem, + aDiagnostics); + // If video capabilities is null, return NotSupported. if (caps.IsEmpty()) { + EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " + "no supported video capabilities.", + NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); return false; } - config.mAudioCapabilities.Construct(); - config.mAudioCapabilities.Value().Assign(caps); + // Set the videoCapabilities member of accumulated configuration to video capabilities. + config.mVideoCapabilities = Move(caps); + } else { + // Otherwise: + // Set the videoCapabilities member of accumulated configuration to an empty sequence. } - if (aCandidate.mVideoCapabilities.WasPassed()) { - nsTArray caps; - for (const MediaKeySystemMediaCapability& cap : aCandidate.mVideoCapabilities.Value()) { - if (IsSupportedVideo(aGMPService, aKeySystem, cap.mContentType, aDiagnostics)) { - caps.AppendElement(cap); - } - } + + // If the audioCapabilities member in candidate configuration is non-empty: + if (!aCandidate.mAudioCapabilities.IsEmpty()) { + // Let audio capabilities be the result of executing the Get Supported Capabilities + // for Audio/Video Type algorithm on Audio, candidate configuration's audioCapabilities + // member, accumulated configuration, and restrictions. + Sequence caps = + GetSupportedCapabilities(aGMPService, + aCandidate.mAudioCapabilities, + config, + aKeySystem, + aDiagnostics); + // If audio capabilities is null, return NotSupported. if (caps.IsEmpty()) { + EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " + "no supported audio capabilities.", + NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); return false; } - config.mVideoCapabilities.Construct(); - config.mVideoCapabilities.Value().Assign(caps); + // Set the audioCapabilities member of accumulated configuration to audio capabilities. + config.mAudioCapabilities = Move(caps); + } else { + // Otherwise: + // Set the audioCapabilities member of accumulated configuration to an empty sequence. } + // If accumulated configuration's distinctiveIdentifier value is "optional", follow the + // steps for the first matching condition from the following list: + if (config.mDistinctiveIdentifier == MediaKeysRequirement::Optional) { + // If the implementation requires use Distinctive Identifier(s) or + // Distinctive Permanent Identifier(s) for any of the combinations + // in accumulated configuration + if (aKeySystem.mDistinctiveIdentifier == KeySystemFeatureSupport::Required) { + // Change accumulated configuration's distinctiveIdentifier value to "required". + config.mDistinctiveIdentifier = MediaKeysRequirement::Required; + } else { + // Otherwise, change accumulated configuration's distinctiveIdentifier + // value to "not-allowed". + config.mDistinctiveIdentifier = MediaKeysRequirement::Not_allowed; + } + } + + // If accumulated configuration's persistentState value is "optional", follow the + // steps for the first matching condition from the following list: + if (config.mPersistentState == MediaKeysRequirement::Optional) { + // If the implementation requires persisting state for any of the combinations + // in accumulated configuration + if (aKeySystem.mPersistentState == KeySystemFeatureSupport::Required) { + // Change accumulated configuration's persistentState value to "required". + config.mPersistentState = MediaKeysRequirement::Required; + } else { + // Otherwise, change accumulated configuration's persistentState + // value to "not-allowed". + config.mPersistentState = MediaKeysRequirement::Not_allowed; + } + } + + // Note: Omitting steps 20-22. We don't ask for consent. + #if defined(XP_WIN) // Widevine CDM doesn't include an AAC decoder. So if WMF can't decode AAC, // and a codec wasn't specified, be conservative and reject the MediaKeys request. - if (aKeySystem.EqualsLiteral("com.widevine.alpha") && - (!aCandidate.mAudioCapabilities.WasPassed() || - !aCandidate.mVideoCapabilities.WasPassed()) && + if (aKeySystem.mKeySystem.EqualsLiteral("com.widevine.alpha") && + (aCandidate.mAudioCapabilities.IsEmpty() || + aCandidate.mVideoCapabilities.IsEmpty()) && !WMFDecoderModule::HasAAC()) { if (aDiagnostics) { aDiagnostics->SetKeySystemIssue( DecoderDoctorDiagnostics::eWidevineWithNoWMF); } + EME_LOG("MediaKeySystemConfiguration (label='%s') rejected; " + "WMF required for Widevine decoding, but it's not available.", + NS_ConvertUTF16toUTF8(aCandidate.mLabel).get()); return false; } #endif + // Return accumulated configuration. aOutConfig = config; return true; @@ -576,16 +1125,19 @@ MediaKeySystemAccess::GetSupportedConfig(const nsAString& aKeySystem, if (NS_WARN_IF(!mps)) { return false; } - + const KeySystemConfig* implementation = nullptr; if (!HaveGMPFor(mps, NS_ConvertUTF16toUTF8(aKeySystem), - NS_LITERAL_CSTRING(GMP_API_DECRYPTOR))) { + NS_LITERAL_CSTRING(GMP_API_DECRYPTOR)) || + !(implementation = GetKeySystemConfig(aKeySystem))) { return false; } - - for (const MediaKeySystemConfiguration& config : aConfigs) { - if (mozilla::dom::GetSupportedConfig( - mps, aKeySystem, config, aOutConfig, aDiagnostics)) { + for (const MediaKeySystemConfiguration& candidate : aConfigs) { + if (mozilla::dom::GetSupportedConfig(mps, + *implementation, + candidate, + aOutConfig, + aDiagnostics)) { return true; } } diff --git a/dom/media/eme/MediaKeySystemAccessManager.cpp b/dom/media/eme/MediaKeySystemAccessManager.cpp index 502e4a98c912..ad8d74b85501 100644 --- a/dom/media/eme/MediaKeySystemAccessManager.cpp +++ b/dom/media/eme/MediaKeySystemAccessManager.cpp @@ -81,6 +81,21 @@ MediaKeySystemAccessManager::Request(DetailedPromise* aPromise, { EME_LOG("MediaKeySystemAccessManager::Request %s", NS_ConvertUTF16toUTF8(aKeySystem).get()); + if (aKeySystem.IsEmpty()) { + aPromise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, + NS_LITERAL_CSTRING("Key system string is empty")); + // Don't notify DecoderDoctor, as there's nothing we or the user can + // do to fix this situation; the site is using the API wrong. + return; + } + if (aConfigs.IsEmpty()) { + aPromise->MaybeReject(NS_ERROR_DOM_TYPE_ERR, + NS_LITERAL_CSTRING("Candidate MediaKeySystemConfigs is empty")); + // Don't notify DecoderDoctor, as there's nothing we or the user can + // do to fix this situation; the site is using the API wrong. + return; + } + DecoderDoctorDiagnostics diagnostics; // Parse keysystem, split it out into keySystem prefix, and version suffix. diff --git a/dom/media/mediasource/MediaSource.cpp b/dom/media/mediasource/MediaSource.cpp index 30ada88b8389..a734d7a79190 100644 --- a/dom/media/mediasource/MediaSource.cpp +++ b/dom/media/mediasource/MediaSource.cpp @@ -81,8 +81,11 @@ IsWebMForced(DecoderDoctorDiagnostics* aDiagnostics) return !mp4supported || !hwsupported || VP9Benchmark::IsVP9DecodeFast(); } -static nsresult -IsTypeSupported(const nsAString& aType, DecoderDoctorDiagnostics* aDiagnostics) +namespace dom { + +/* static */ +nsresult +MediaSource::IsTypeSupported(const nsAString& aType, DecoderDoctorDiagnostics* aDiagnostics) { if (aType.IsEmpty()) { return NS_ERROR_DOM_TYPE_ERR; @@ -132,8 +135,6 @@ IsTypeSupported(const nsAString& aType, DecoderDoctorDiagnostics* aDiagnostics) return NS_ERROR_DOM_NOT_SUPPORTED_ERR; } -namespace dom { - /* static */ already_AddRefed MediaSource::Constructor(const GlobalObject& aGlobal, ErrorResult& aRv) @@ -221,7 +222,7 @@ MediaSource::AddSourceBuffer(const nsAString& aType, ErrorResult& aRv) { MOZ_ASSERT(NS_IsMainThread()); DecoderDoctorDiagnostics diagnostics; - nsresult rv = mozilla::IsTypeSupported(aType, &diagnostics); + nsresult rv = IsTypeSupported(aType, &diagnostics); diagnostics.StoreFormatDiagnostics(GetOwner() ? GetOwner()->GetExtantDoc() : nullptr, @@ -341,7 +342,7 @@ MediaSource::IsTypeSupported(const GlobalObject& aOwner, const nsAString& aType) { MOZ_ASSERT(NS_IsMainThread()); DecoderDoctorDiagnostics diagnostics; - nsresult rv = mozilla::IsTypeSupported(aType, &diagnostics); + nsresult rv = IsTypeSupported(aType, &diagnostics); nsCOMPtr window = do_QueryInterface(aOwner.GetAsSupports()); diagnostics.StoreFormatDiagnostics(window ? window->GetExtantDoc() : nullptr, aType, NS_SUCCEEDED(rv), __func__); diff --git a/dom/media/mediasource/MediaSource.h b/dom/media/mediasource/MediaSource.h index 8012df4ca295..867e955f90ea 100644 --- a/dom/media/mediasource/MediaSource.h +++ b/dom/media/mediasource/MediaSource.h @@ -65,6 +65,7 @@ public: void ClearLiveSeekableRange(ErrorResult& aRv); static bool IsTypeSupported(const GlobalObject&, const nsAString& aType); + static nsresult IsTypeSupported(const nsAString& aType, DecoderDoctorDiagnostics* aDiagnostics); static bool Enabled(JSContext* cx, JSObject* aGlobal); From e2b41d3d04fbe0af3659cd8ea8e2475215ed03be Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Thu, 7 Jul 2016 17:28:14 +1200 Subject: [PATCH 087/135] Bug 1278198 - Add Widevine FileIO. r=gerald MozReview-Commit-ID: IXgSobtF24L --HG-- extra : rebase_source : e1df08666b0713fa4c10fc020d6482a802d2fb52 --- .../gmp/widevine-adapter/WidevineFileIO.cpp | 97 +++++++++++++++++++ .../gmp/widevine-adapter/WidevineFileIO.h | 46 +++++++++ dom/media/gmp/widevine-adapter/moz.build | 1 + 3 files changed, 144 insertions(+) create mode 100644 dom/media/gmp/widevine-adapter/WidevineFileIO.cpp create mode 100644 dom/media/gmp/widevine-adapter/WidevineFileIO.h diff --git a/dom/media/gmp/widevine-adapter/WidevineFileIO.cpp b/dom/media/gmp/widevine-adapter/WidevineFileIO.cpp new file mode 100644 index 000000000000..b5fb1d705cee --- /dev/null +++ b/dom/media/gmp/widevine-adapter/WidevineFileIO.cpp @@ -0,0 +1,97 @@ +#include "WidevineFileIO.h" +#include "WidevineUtils.h" +#include "WidevineAdapter.h" + +using namespace cdm; + +namespace mozilla { + +void +WidevineFileIO::Open(const char* aFilename, uint32_t aFilenameLength) +{ + mName = std::string(aFilename, aFilename + aFilenameLength); + GMPRecord* record = nullptr; + GMPErr err = GMPCreateRecord(aFilename, aFilenameLength, &record, static_cast(this)); + if (GMP_FAILED(err)) { + Log("WidevineFileIO::Open() '%s' GMPCreateRecord failed", mName.c_str()); + mClient->OnOpenComplete(FileIOClient::kError); + return; + } + if (GMP_FAILED(record->Open())) { + Log("WidevineFileIO::Open() '%s' record open failed", mName.c_str()); + mClient->OnOpenComplete(FileIOClient::kError); + return; + } + + Log("WidevineFileIO::Open() '%s'", mName.c_str()); + mRecord = record; +} + +void +WidevineFileIO::Read() +{ + if (!mRecord) { + Log("WidevineFileIO::Read() '%s' used uninitialized!", mName.c_str()); + mClient->OnReadComplete(FileIOClient::kError, nullptr, 0); + return; + } + Log("WidevineFileIO::Read() '%s'", mName.c_str()); + mRecord->Read(); +} + +void +WidevineFileIO::Write(const uint8_t* aData, uint32_t aDataSize) +{ + if (!mRecord) { + Log("WidevineFileIO::Write() '%s' used uninitialized!", mName.c_str()); + mClient->OnWriteComplete(FileIOClient::kError); + return; + } + mRecord->Write(aData, aDataSize); +} + +void +WidevineFileIO::Close() +{ + Log("WidevineFileIO::Close() '%s'", mName.c_str()); + if (mRecord) { + mRecord->Close(); + mRecord = nullptr; + } + delete this; +} + +static FileIOClient::Status +GMPToWidevineFileStatus(GMPErr aStatus) +{ + switch (aStatus) { + case GMPRecordInUse: return FileIOClient::kInUse; + case GMPNoErr: return FileIOClient::kSuccess; + default: return FileIOClient::kError; + } +} + +void +WidevineFileIO::OpenComplete(GMPErr aStatus) +{ + Log("WidevineFileIO::OpenComplete() '%s' status=%d", mName.c_str(), aStatus); + mClient->OnOpenComplete(GMPToWidevineFileStatus(aStatus)); +} + +void +WidevineFileIO::ReadComplete(GMPErr aStatus, + const uint8_t* aData, + uint32_t aDataSize) +{ + Log("WidevineFileIO::OnReadComplete() '%s' status=%d", mName.c_str(), aStatus); + mClient->OnReadComplete(GMPToWidevineFileStatus(aStatus), aData, aDataSize); +} + +void +WidevineFileIO::WriteComplete(GMPErr aStatus) +{ + Log("WidevineFileIO::WriteComplete() '%s' status=%d", mName.c_str(), aStatus); + mClient->OnWriteComplete(GMPToWidevineFileStatus(aStatus)); +} + +} // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineFileIO.h b/dom/media/gmp/widevine-adapter/WidevineFileIO.h new file mode 100644 index 000000000000..63003d9b602f --- /dev/null +++ b/dom/media/gmp/widevine-adapter/WidevineFileIO.h @@ -0,0 +1,46 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public +* License, v. 2.0. If a copy of the MPL was not distributed with this +* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef WidevineFileIO_h_ +#define WidevineFileIO_h_ + +#include +#include "content_decryption_module.h" +#include "gmp-api/gmp-storage.h" +#include + +namespace mozilla { + +class WidevineFileIO : public cdm::FileIO + , public GMPRecordClient +{ +public: + explicit WidevineFileIO(cdm::FileIOClient* aClient) + : mClient(aClient) + , mRecord(nullptr) + {} + + // cdm::FileIO + void Open(const char* aFilename, uint32_t aFilenameLength) override; + void Read() override; + void Write(const uint8_t* aData, uint32_t aDataSize) override; + void Close() override; + + // GMPRecordClient + void OpenComplete(GMPErr aStatus) override; + void ReadComplete(GMPErr aStatus, + const uint8_t* aData, + uint32_t aDataSize) override; + void WriteComplete(GMPErr aStatus) override; + +private: + cdm::FileIOClient* mClient; + GMPRecord* mRecord; + std::string mName; +}; + +} // namespace mozilla + +#endif // WidevineFileIO_h_ \ No newline at end of file diff --git a/dom/media/gmp/widevine-adapter/moz.build b/dom/media/gmp/widevine-adapter/moz.build index 54fe48309fd3..b84bca407053 100644 --- a/dom/media/gmp/widevine-adapter/moz.build +++ b/dom/media/gmp/widevine-adapter/moz.build @@ -7,6 +7,7 @@ SOURCES += [ 'WidevineAdapter.cpp', 'WidevineDecryptor.cpp', + 'WidevineFileIO.cpp', 'WidevineUtils.cpp', 'WidevineVideoDecoder.cpp', 'WidevineVideoFrame.cpp', From f49856bc790b60ac576d468575c7a02481147069 Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Thu, 7 Jul 2016 17:26:15 +1200 Subject: [PATCH 088/135] Bug 1278198 - Pipe through distinctive identifier and persistent state allowed. r=gerald MozReview-Commit-ID: A92e0XGp5s4 --HG-- extra : rebase_source : 09f7ba18c9b81263aa345cc7f34f0ef2a2548482 --- dom/media/eme/CDMProxy.h | 13 ++++++++++-- dom/media/eme/MediaKeySystemAccess.cpp | 6 +++++- dom/media/eme/MediaKeys.cpp | 12 +++++++++-- dom/media/eme/MediaKeys.h | 7 ++++++- dom/media/gmp-plugin/gmp-test-decryptor.h | 2 +- dom/media/gmp/GMPCDMProxy.cpp | 18 ++++++++++++---- dom/media/gmp/GMPCDMProxy.h | 4 +++- dom/media/gmp/GMPDecryptorChild.cpp | 5 +++-- dom/media/gmp/GMPDecryptorChild.h | 3 ++- dom/media/gmp/GMPDecryptorParent.cpp | 6 ++++-- dom/media/gmp/GMPDecryptorParent.h | 4 +++- dom/media/gmp/GMPDecryptorProxy.h | 4 +++- dom/media/gmp/PGMPDecryptor.ipdl | 3 ++- dom/media/gmp/gmp-api/gmp-decryption.h | 4 +++- .../gmp/widevine-adapter/WidevineAdapter.cpp | 4 ---- .../widevine-adapter/WidevineDecryptor.cpp | 21 +++++++++++++++---- .../gmp/widevine-adapter/WidevineDecryptor.h | 6 +++++- dom/media/gtest/TestGMPCrossOrigin.cpp | 2 +- .../0.1/ClearKeySessionManager.cpp | 4 +++- .../gmp-clearkey/0.1/ClearKeySessionManager.h | 4 +++- 20 files changed, 99 insertions(+), 33 deletions(-) diff --git a/dom/media/eme/CDMProxy.h b/dom/media/eme/CDMProxy.h index 06143e70dd35..f64c02991460 100644 --- a/dom/media/eme/CDMProxy.h +++ b/dom/media/eme/CDMProxy.h @@ -50,8 +50,14 @@ public: typedef MozPromise DecryptPromise; // Main thread only. - CDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem) - : mKeys(aKeys), mKeySystem(aKeySystem) + CDMProxy(dom::MediaKeys* aKeys, + const nsAString& aKeySystem, + bool aDistinctiveIdentifierRequired, + bool aPersistentStateRequired) + : mKeys(aKeys) + , mKeySystem(aKeySystem) + , mDistinctiveIdentifierRequired(aDistinctiveIdentifierRequired) + , mPersistentStateRequired(aPersistentStateRequired) {} // Main thread only. @@ -229,6 +235,9 @@ protected: nsCString mNodeId; CDMCaps mCapabilites; + + const bool mDistinctiveIdentifierRequired; + const bool mPersistentStateRequired; }; diff --git a/dom/media/eme/MediaKeySystemAccess.cpp b/dom/media/eme/MediaKeySystemAccess.cpp index f36fb759a530..79ad26031b78 100644 --- a/dom/media/eme/MediaKeySystemAccess.cpp +++ b/dom/media/eme/MediaKeySystemAccess.cpp @@ -92,7 +92,11 @@ MediaKeySystemAccess::GetConfiguration(MediaKeySystemConfiguration& aConfig) already_AddRefed MediaKeySystemAccess::CreateMediaKeys(ErrorResult& aRv) { - RefPtr keys(new MediaKeys(mParent, mKeySystem, mCDMVersion)); + RefPtr keys(new MediaKeys(mParent, + mKeySystem, + mCDMVersion, + mConfig.mDistinctiveIdentifier == MediaKeysRequirement::Required, + mConfig.mPersistentState == MediaKeysRequirement::Required)); return keys->Init(aRv); } diff --git a/dom/media/eme/MediaKeys.cpp b/dom/media/eme/MediaKeys.cpp index d28ba05af26e..7909e3ef3ff2 100644 --- a/dom/media/eme/MediaKeys.cpp +++ b/dom/media/eme/MediaKeys.cpp @@ -48,11 +48,15 @@ NS_INTERFACE_MAP_END MediaKeys::MediaKeys(nsPIDOMWindowInner* aParent, const nsAString& aKeySystem, - const nsAString& aCDMVersion) + const nsAString& aCDMVersion, + bool aDistinctiveIdentifierRequired, + bool aPersistentStateRequired) : mParent(aParent) , mKeySystem(aKeySystem) , mCDMVersion(aCDMVersion) , mCreatePromiseId(0) + , mDistinctiveIdentifierRequired(aDistinctiveIdentifierRequired) + , mPersistentStateRequired(aPersistentStateRequired) { EME_LOG("MediaKeys[%p] constructed keySystem=%s", this, NS_ConvertUTF16toUTF8(mKeySystem).get()); @@ -313,7 +317,11 @@ MediaKeys::Init(ErrorResult& aRv) return nullptr; } - mProxy = new GMPCDMProxy(this, mKeySystem, new MediaKeysGMPCrashHelper(this)); + mProxy = new GMPCDMProxy(this, + mKeySystem, + new MediaKeysGMPCrashHelper(this), + mDistinctiveIdentifierRequired, + mPersistentStateRequired); // Determine principal (at creation time) of the MediaKeys object. nsCOMPtr sop = do_QueryInterface(GetParentObject()); diff --git a/dom/media/eme/MediaKeys.h b/dom/media/eme/MediaKeys.h index 4f8a12b08008..c8cd1639bd7a 100644 --- a/dom/media/eme/MediaKeys.h +++ b/dom/media/eme/MediaKeys.h @@ -50,7 +50,10 @@ public: MOZ_DECLARE_WEAKREFERENCE_TYPENAME(MediaKeys) MediaKeys(nsPIDOMWindowInner* aParentWindow, - const nsAString& aKeySystem, const nsAString& aCDMVersion); + const nsAString& aKeySystem, + const nsAString& aCDMVersion, + bool aDistinctiveIdentifierRequired, + bool aPersistentStateRequired); already_AddRefed Init(ErrorResult& aRv); @@ -147,6 +150,8 @@ private: RefPtr mPrincipal; RefPtr mTopLevelPrincipal; + const bool mDistinctiveIdentifierRequired; + const bool mPersistentStateRequired; }; } // namespace dom diff --git a/dom/media/gmp-plugin/gmp-test-decryptor.h b/dom/media/gmp-plugin/gmp-test-decryptor.h index 9ae5258da1f7..d8bd23e6d5c1 100644 --- a/dom/media/gmp-plugin/gmp-test-decryptor.h +++ b/dom/media/gmp-plugin/gmp-test-decryptor.h @@ -16,7 +16,7 @@ public: explicit FakeDecryptor(GMPDecryptorHost* aHost); - void Init(GMPDecryptorCallback* aCallback) override { + void Init(GMPDecryptorCallback* aCallback, bool, bool) override { mCallback = aCallback; } diff --git a/dom/media/gmp/GMPCDMProxy.cpp b/dom/media/gmp/GMPCDMProxy.cpp index 78a0358a4f9f..c3ba687fd000 100644 --- a/dom/media/gmp/GMPCDMProxy.cpp +++ b/dom/media/gmp/GMPCDMProxy.cpp @@ -27,8 +27,13 @@ namespace mozilla { GMPCDMProxy::GMPCDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem, - GMPCrashHelper* aCrashHelper) - : CDMProxy(aKeys, aKeySystem) + GMPCrashHelper* aCrashHelper, + bool aDistinctiveIdentifierRequired, + bool aPersistentStateRequired) + : CDMProxy(aKeys, + aKeySystem, + aDistinctiveIdentifierRequired, + aPersistentStateRequired) , mCrashHelper(aCrashHelper) , mCDM(nullptr) , mDecryptionJobCount(0) @@ -123,7 +128,9 @@ GMPCDMProxy::gmp_InitDone(GMPDecryptorProxy* aCDM, nsAutoPtr&& aData) mCDM = aCDM; mCallback = new GMPCDMCallbackProxy(this); - mCDM->Init(mCallback); + mCDM->Init(mCallback, + mDistinctiveIdentifierRequired, + mPersistentStateRequired); nsCOMPtr task( NewRunnableMethod(this, &GMPCDMProxy::OnCDMCreated, @@ -237,7 +244,10 @@ GMPCDMProxy::gmp_InitGetGMPDecryptor(nsresult aResult, RefPtr crashHelper = Move(aData->mCrashHelper); UniquePtr callback(new gmp_InitDoneCallback(this, Move(aData))); - nsresult rv = mps->GetGMPDecryptor(crashHelper, &tags, GetNodeId(), Move(callback)); + nsresult rv = mps->GetGMPDecryptor(crashHelper, + &tags, + GetNodeId(), + Move(callback)); if (NS_FAILED(rv)) { RejectPromise(promiseID, NS_ERROR_DOM_INVALID_STATE_ERR, NS_LITERAL_CSTRING("Call to GetGMPDecryptor() failed early")); diff --git a/dom/media/gmp/GMPCDMProxy.h b/dom/media/gmp/GMPCDMProxy.h index 16072db0b923..55b0752a5fe6 100644 --- a/dom/media/gmp/GMPCDMProxy.h +++ b/dom/media/gmp/GMPCDMProxy.h @@ -24,7 +24,9 @@ public: GMPCDMProxy(dom::MediaKeys* aKeys, const nsAString& aKeySystem, - GMPCrashHelper* aCrashHelper); + GMPCrashHelper* aCrashHelper, + bool aDistinctiveIdentifierRequired, + bool aPersistentStateRequired); void Init(PromiseId aPromiseId, const nsAString& aOrigin, diff --git a/dom/media/gmp/GMPDecryptorChild.cpp b/dom/media/gmp/GMPDecryptorChild.cpp index 5fb891f7bfdf..e0cb5a459d99 100644 --- a/dom/media/gmp/GMPDecryptorChild.cpp +++ b/dom/media/gmp/GMPDecryptorChild.cpp @@ -220,12 +220,13 @@ GMPDecryptorChild::GetPluginVoucher(const uint8_t** aVoucher, } bool -GMPDecryptorChild::RecvInit() +GMPDecryptorChild::RecvInit(const bool& aDistinctiveIdentifierRequired, + const bool& aPersistentStateRequired) { if (!mSession) { return false; } - mSession->Init(this); + mSession->Init(this, aDistinctiveIdentifierRequired, aPersistentStateRequired); return true; } diff --git a/dom/media/gmp/GMPDecryptorChild.h b/dom/media/gmp/GMPDecryptorChild.h index 175dc206c5d7..30c0d41d114c 100644 --- a/dom/media/gmp/GMPDecryptorChild.h +++ b/dom/media/gmp/GMPDecryptorChild.h @@ -83,7 +83,8 @@ private: ~GMPDecryptorChild(); // GMPDecryptorChild - bool RecvInit() override; + bool RecvInit(const bool& aDistinctiveIdentifierRequired, + const bool& aPersistentStateRequired) override; bool RecvCreateSession(const uint32_t& aCreateSessionToken, const uint32_t& aPromiseId, diff --git a/dom/media/gmp/GMPDecryptorParent.cpp b/dom/media/gmp/GMPDecryptorParent.cpp index e25cec3a9792..5b9cf369f02e 100644 --- a/dom/media/gmp/GMPDecryptorParent.cpp +++ b/dom/media/gmp/GMPDecryptorParent.cpp @@ -41,7 +41,9 @@ GMPDecryptorParent::~GMPDecryptorParent() } nsresult -GMPDecryptorParent::Init(GMPDecryptorProxyCallback* aCallback) +GMPDecryptorParent::Init(GMPDecryptorProxyCallback* aCallback, + bool aDistinctiveIdentifierRequired, + bool aPersistentStateRequired) { LOGD(("GMPDecryptorParent[%p]::Init()", this)); @@ -50,7 +52,7 @@ GMPDecryptorParent::Init(GMPDecryptorProxyCallback* aCallback) return NS_ERROR_FAILURE; } mCallback = aCallback; - if (!SendInit()) { + if (!SendInit(aDistinctiveIdentifierRequired, aPersistentStateRequired)) { return NS_ERROR_FAILURE; } mIsOpen = true; diff --git a/dom/media/gmp/GMPDecryptorParent.h b/dom/media/gmp/GMPDecryptorParent.h index 13fa3c347584..f9874d8e7d0b 100644 --- a/dom/media/gmp/GMPDecryptorParent.h +++ b/dom/media/gmp/GMPDecryptorParent.h @@ -33,7 +33,9 @@ public: uint32_t GetPluginId() const override { return mPluginId; } - nsresult Init(GMPDecryptorProxyCallback* aCallback) override; + nsresult Init(GMPDecryptorProxyCallback* aCallback, + bool aDistinctiveIdentifierRequired, + bool aPersistentStateRequired) override; void CreateSession(uint32_t aCreateSessionToken, uint32_t aPromiseId, diff --git a/dom/media/gmp/GMPDecryptorProxy.h b/dom/media/gmp/GMPDecryptorProxy.h index ea2a163be4e6..a0fa5c159524 100644 --- a/dom/media/gmp/GMPDecryptorProxy.h +++ b/dom/media/gmp/GMPDecryptorProxy.h @@ -59,7 +59,9 @@ public: virtual uint32_t GetPluginId() const = 0; - virtual nsresult Init(GMPDecryptorProxyCallback* aCallback) = 0; + virtual nsresult Init(GMPDecryptorProxyCallback* aCallback, + bool aDistinctiveIdentifierRequired, + bool aPersistentStateRequired) = 0; virtual void CreateSession(uint32_t aCreateSessionToken, uint32_t aPromiseId, diff --git a/dom/media/gmp/PGMPDecryptor.ipdl b/dom/media/gmp/PGMPDecryptor.ipdl index 3632fbc34535..0dcdc326b340 100644 --- a/dom/media/gmp/PGMPDecryptor.ipdl +++ b/dom/media/gmp/PGMPDecryptor.ipdl @@ -20,7 +20,8 @@ async protocol PGMPDecryptor manager PGMPContent; child: - async Init(); + async Init(bool aDistinctiveIdentifierRequired, + bool aPersistentStateRequired); async CreateSession(uint32_t aCreateSessionToken, uint32_t aPromiseId, diff --git a/dom/media/gmp/gmp-api/gmp-decryption.h b/dom/media/gmp/gmp-api/gmp-decryption.h index 5908b6353da9..fc8555917d1e 100644 --- a/dom/media/gmp/gmp-api/gmp-decryption.h +++ b/dom/media/gmp/gmp-api/gmp-decryption.h @@ -227,7 +227,9 @@ public: // Sets the callback to use with the decryptor to return results // to Gecko. - virtual void Init(GMPDecryptorCallback* aCallback) = 0; + virtual void Init(GMPDecryptorCallback* aCallback, + bool aDistinctiveIdentifierRequired, + bool aPersistentStateRequired) = 0; // Initiates the creation of a session given |aType| and |aInitData|, and // the generation of a license request message. diff --git a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp index c3d0e7c90ac0..758bedae1a8c 100644 --- a/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineAdapter.cpp @@ -122,10 +122,6 @@ WidevineAdapter::GMPGetAPI(const char* aAPIName, Log("cdm: 0x%x", cdm); sCDMWrapper = new CDMWrapper(cdm); decryptor->SetCDM(RefPtr(sCDMWrapper)); - - cdm->Initialize(false, /* allow_distinctive_identifier */ - false /* allow_persistent_state */); - *aPluginAPI = decryptor; } else if (!strcmp(aAPIName, GMP_API_VIDEO_DECODER)) { diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp index 28c4fbab977e..cc0b8bc4f1d4 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.cpp @@ -7,6 +7,7 @@ #include "WidevineAdapter.h" #include "WidevineUtils.h" +#include "WidevineFileIO.h" #include #include @@ -35,10 +36,21 @@ WidevineDecryptor::SetCDM(RefPtr aCDM) } void -WidevineDecryptor::Init(GMPDecryptorCallback* aCallback) +WidevineDecryptor::Init(GMPDecryptorCallback* aCallback, + bool aDistinctiveIdentifierRequired, + bool aPersistentStateRequired) { + Log("WidevineDecryptor::Init() this=%p distinctiveId=%d persistentState=%d", + this, aDistinctiveIdentifierRequired, aPersistentStateRequired); MOZ_ASSERT(aCallback); mCallback = aCallback; + MOZ_ASSERT(mCDM); + mDistinctiveIdentifierRequired = aDistinctiveIdentifierRequired; + mPersistentStateRequired = aPersistentStateRequired; + if (CDM()) { + CDM()->Initialize(aDistinctiveIdentifierRequired, + aPersistentStateRequired); + } } static SessionType @@ -484,9 +496,10 @@ FileIO* WidevineDecryptor::CreateFileIO(FileIOClient* aClient) { Log("Decryptor::CreateFileIO()"); - // Persistent storage not required or supported! - MOZ_ASSERT(false); - return nullptr; + if (!mPersistentStateRequired) { + return nullptr; + } + return new WidevineFileIO(aClient); } } // namespace mozilla diff --git a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h index 7b5a3ac950cc..68fc35cbc864 100644 --- a/dom/media/gmp/widevine-adapter/WidevineDecryptor.h +++ b/dom/media/gmp/widevine-adapter/WidevineDecryptor.h @@ -27,7 +27,9 @@ public: void SetCDM(RefPtr aCDM); // GMPDecryptor - void Init(GMPDecryptorCallback* aCallback) override; + void Init(GMPDecryptorCallback* aCallback, + bool aDistinctiveIdentifierRequired, + bool aPersistentStateRequired) override; void CreateSession(uint32_t aCreateSessionToken, uint32_t aPromiseId, @@ -120,6 +122,8 @@ private: GMPDecryptorCallback* mCallback; std::map mPromiseIdToNewSessionTokens; + bool mDistinctiveIdentifierRequired = false; + bool mPersistentStateRequired = false; }; } // namespace mozilla diff --git a/dom/media/gtest/TestGMPCrossOrigin.cpp b/dom/media/gtest/TestGMPCrossOrigin.cpp index 169e4fe27064..eaed6066b26b 100644 --- a/dom/media/gtest/TestGMPCrossOrigin.cpp +++ b/dom/media/gtest/TestGMPCrossOrigin.cpp @@ -606,7 +606,7 @@ class GMPStorageTest : public GMPDecryptorProxyCallback EXPECT_TRUE(!!mRunner->mDecryptor); if (mRunner->mDecryptor) { - mRunner->mDecryptor->Init(mRunner); + mRunner->mDecryptor->Init(mRunner, false, true); } nsCOMPtr thread(GetGMPThread()); thread->Dispatch(mContinuation, NS_DISPATCH_NORMAL); diff --git a/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp b/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp index 3bab0f77443a..9b0d7c084f47 100644 --- a/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp +++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.cpp @@ -46,7 +46,9 @@ ClearKeySessionManager::~ClearKeySessionManager() } void -ClearKeySessionManager::Init(GMPDecryptorCallback* aCallback) +ClearKeySessionManager::Init(GMPDecryptorCallback* aCallback, + bool aDistinctiveIdentifierAllowed, + bool aPersistentStateAllowed) { CK_LOGD("ClearKeySessionManager::Init"); mCallback = aCallback; diff --git a/media/gmp-clearkey/0.1/ClearKeySessionManager.h b/media/gmp-clearkey/0.1/ClearKeySessionManager.h index 034efce3ecf9..041b3f036223 100644 --- a/media/gmp-clearkey/0.1/ClearKeySessionManager.h +++ b/media/gmp-clearkey/0.1/ClearKeySessionManager.h @@ -34,7 +34,9 @@ class ClearKeySessionManager final : public GMPDecryptor public: ClearKeySessionManager(); - virtual void Init(GMPDecryptorCallback* aCallback) override; + virtual void Init(GMPDecryptorCallback* aCallback, + bool aDistinctiveIdentifierAllowed, + bool aPersistentStateAllowed) override; virtual void CreateSession(uint32_t aCreateSessionToken, uint32_t aPromiseId, From 8b28b48c65677db79178339a1e5c9f75c78c791f Mon Sep 17 00:00:00 2001 From: Chris Pearce Date: Mon, 11 Jul 2016 16:46:21 +1200 Subject: [PATCH 089/135] Bug 1278198 - Fix tests to work with new EME API. r=gerald MozReview-Commit-ID: WTWyYu2Zgp --HG-- extra : rebase_source : 68208d9be13fd18aa7ff6a2f167299050d5375ed --- dom/media/test/eme.js | 10 +- .../test/test_eme_detach_media_keys.html | 10 +- dom/media/test/test_eme_initDataTypes.html | 19 +- dom/media/test/test_eme_non_mse_fails.html | 2 +- .../test/test_eme_persistent_sessions.html | 8 +- .../test/test_eme_requestKeySystemAccess.html | 215 ++++++++++-------- .../test/test_eme_request_notifications.html | 12 +- .../test/test_eme_session_callable_value.html | 2 +- ...etMediaKeys_before_attach_MediaSource.html | 2 +- 9 files changed, 154 insertions(+), 126 deletions(-) diff --git a/dom/media/test/eme.js b/dom/media/test/eme.js index 80eb3623199c..1ea3f06a358c 100644 --- a/dom/media/test/eme.js +++ b/dom/media/test/eme.js @@ -1,4 +1,10 @@ -const KEYSYSTEM_TYPE = "org.w3.clearkey"; +const CLEARKEY_KEYSYSTEM = "org.w3.clearkey"; + +const gCencMediaKeySystemConfig = [{ + initDataTypes: ['cenc'], + videoCapabilities: [{ contentType: 'video/mp4' }], + audioCapabilities: [{ contentType: 'audio/mp4' }], +}]; function IsMacOSSnowLeopardOrEarlier() { var re = /Mac OS X (\d+)\.(\d+)/; @@ -376,7 +382,7 @@ function SetupEME(test, token, params) options.audioCapabilities = [{contentType: streamType("audio")}]; } - var p = navigator.requestMediaKeySystemAccess(KEYSYSTEM_TYPE, [options]); + var p = navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, [options]); var r = bail(token + " Failed to request key system access."); chain(p, r) .then(function(keySystemAccess) { diff --git a/dom/media/test/test_eme_detach_media_keys.html b/dom/media/test/test_eme_detach_media_keys.html index fb2101456b87..6d3dc8467e29 100644 --- a/dom/media/test/test_eme_detach_media_keys.html +++ b/dom/media/test/test_eme_detach_media_keys.html @@ -14,18 +14,18 @@ SimpleTest.waitForExplicitFinish(); -const keysystem = 'org.w3.clearkey'; - function createAndSet() { return new Promise(function(resolve, reject) { var m; - navigator.requestMediaKeySystemAccess(keysystem, [{initDataTypes: ['cenc']}]) + navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, gCencMediaKeySystemConfig) .then(function (access) { return access.createMediaKeys(); - }).then(function (mediaKeys) { + }) + .then(function (mediaKeys) { m = mediaKeys; return document.getElementById("v").setMediaKeys(mediaKeys); - }).then(function() { + }) + .then(function() { resolve(m); }); } diff --git a/dom/media/test/test_eme_initDataTypes.html b/dom/media/test/test_eme_initDataTypes.html index eaeb4773d458..5908bec404ef 100644 --- a/dom/media/test/test_eme_initDataTypes.html +++ b/dom/media/test/test_eme_initDataTypes.html @@ -39,9 +39,9 @@ var tests = [ { name: "Two keyIds, persistent session, type before kids", initDataType: 'keyids', - initData: '{"type":"persistent", "kids":["LwVHf8JLtPrv2GUXFW2v_A", "0DdtU9od-Bh5L3xbv0Xf_A"]}', - expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A","0DdtU9od-Bh5L3xbv0Xf_A"],"type":"persistent"}', - sessionType: 'persistent', + initData: '{"type":"persistent-license", "kids":["LwVHf8JLtPrv2GUXFW2v_A", "0DdtU9od-Bh5L3xbv0Xf_A"]}', + expectedRequest: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A","0DdtU9od-Bh5L3xbv0Xf_A"],"type":"persistent-license"}', + sessionType: 'persistent-license', expectPass: true, }, { @@ -62,7 +62,7 @@ var tests = [ name: "SessionType in license doesn't match MediaKeySession's sessionType", initDataType: 'keyids', initData: '{"kids":["LwVHf8JLtPrv2GUXFW2v_A"]}', - sessionType: 'persistent', + sessionType: 'persistent-license', expectPass: false, }, { @@ -108,10 +108,13 @@ function PrepareInitData(initDataType, initData) function Test(test) { return new Promise(function(resolve, reject) { - navigator.requestMediaKeySystemAccess('org.w3.clearkey', [{initDataTypes: [test.initDataType]}]).then( - (access) => access.createMediaKeys() - ).then( - (mediaKeys) => { + var configs = [{ + initDataTypes: [test.initDataType], + videoCapabilities: [{contentType: 'video/mp4' }], + }]; + navigator.requestMediaKeySystemAccess('org.w3.clearkey', configs) + .then((access) => access.createMediaKeys()) + .then((mediaKeys) => { var session = mediaKeys.createSession(test.sessionType); session.addEventListener("message", function(event) { is(event.messageType, "license-request", "'" + test.name + "' MediaKeyMessage type should be license-request."); diff --git a/dom/media/test/test_eme_non_mse_fails.html b/dom/media/test/test_eme_non_mse_fails.html index d8fa48e49221..ede3edc5f2cd 100644 --- a/dom/media/test/test_eme_non_mse_fails.html +++ b/dom/media/test/test_eme_non_mse_fails.html @@ -20,7 +20,7 @@ function DoSetMediaKeys(v, test) videoCapabilities: [{contentType: test.videoType}], }]; - return navigator.requestMediaKeySystemAccess("org.w3.clearkey", options) + return navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, options) .then(function(keySystemAccess) { return keySystemAccess.createMediaKeys(); diff --git a/dom/media/test/test_eme_persistent_sessions.html b/dom/media/test/test_eme_persistent_sessions.html index b1a808a0abea..885d6db6cc13 100644 --- a/dom/media/test/test_eme_persistent_sessions.html +++ b/dom/media/test/test_eme_persistent_sessions.html @@ -86,7 +86,7 @@ function startTest(test, token) // Once the session is closed, reload the MediaKeys and reload the session .then(function() { - return navigator.requestMediaKeySystemAccess(KEYSYSTEM_TYPE, [{initDataTypes:["cenc"]}]); + return navigator.requestMediaKeySystemAccess(CLEARKEY_KEYSYSTEM, gCencMediaKeySystemConfig); }) .then(function(requestedKeySystemAccess) { @@ -96,7 +96,7 @@ function startTest(test, token) .then(function(mediaKeys) { Log(token, "re-created MediaKeys object ok"); - recreatedSession = mediaKeys.createSession("persistent"); + recreatedSession = mediaKeys.createSession("persistent-license"); Log(token, "Created recreatedSession, loading sessionId=" + sessionId); return recreatedSession.load(sessionId); }) @@ -127,7 +127,7 @@ function startTest(test, token) .then(function(mediaKeys) { Log(token, "re-re-created MediaKeys object ok"); // Trying to load the removed persistent session should fail. - return mediaKeys.createSession("persistent").load(sessionId); + return mediaKeys.createSession("persistent-license").load(sessionId); }) .then(function(suceeded) { @@ -142,7 +142,7 @@ function startTest(test, token) }); }, - sessionType: "persistent", + sessionType: "persistent-license", } ); diff --git a/dom/media/test/test_eme_requestKeySystemAccess.html b/dom/media/test/test_eme_requestKeySystemAccess.html index b3d6d56544d3..a969d992c1cc 100644 --- a/dom/media/test/test_eme_requestKeySystemAccess.html +++ b/dom/media/test/test_eme_requestKeySystemAccess.html @@ -11,7 +11,6 @@
 
\ No newline at end of file
diff --git a/dom/canvas/crashtests/crashtests.list b/dom/canvas/crashtests/crashtests.list
index 5a066bdeebfd..1bec85fb794b 100644
--- a/dom/canvas/crashtests/crashtests.list
+++ b/dom/canvas/crashtests/crashtests.list
@@ -30,3 +30,5 @@ load 1229932-1.html
 load 1244850-1.html
 load 1246775-1.html
 skip-if(d2d) load 1287515-1.html
+load 1288872-1.html
+
diff --git a/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp b/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
index 7189ab13703c..ef06efdc7986 100644
--- a/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
+++ b/gfx/skia/skia/src/ports/SkFontHost_cairo.cpp
@@ -89,6 +89,10 @@ public:
                             cairo_font_face_t* fontFace, FcPattern* pattern);
     virtual ~SkScalerContext_CairoFT();
 
+    bool isValid() const {
+        return fScaledFont != nullptr;
+    }
+
 protected:
     virtual unsigned generateGlyphCount() override;
     virtual uint16_t generateCharToGlyph(SkUnichar uniChar) override;
@@ -188,8 +192,14 @@ public:
 
     virtual SkScalerContext* onCreateScalerContext(const SkDescriptor* desc) const override
     {
-        return new SkScalerContext_CairoFT(const_cast(this), desc,
-                                           fFontFace, fPattern);
+        SkScalerContext_CairoFT* ctx =
+            new SkScalerContext_CairoFT(const_cast(this), desc,
+                                        fFontFace, fPattern);
+        if (!ctx->isValid()) {
+            delete ctx;
+            return nullptr;
+        }
+        return ctx;
     }
 
     virtual void onFilterRec(SkScalerContextRec* rec) const override
@@ -526,7 +536,7 @@ bool SkScalerContext_CairoFT::computeShapeMatrix(const SkMatrix& m)
     // If the font is not scalable, then choose the best available size.
     CairoLockedFTFace faceLock(fScaledFont);
     FT_Face face = faceLock.getFace();
-    if (!FT_IS_SCALABLE(face)) {
+    if (face && !FT_IS_SCALABLE(face)) {
         double bestDist = DBL_MAX;
         FT_Int bestSize = -1;
         for (FT_Int i = 0; i < face->num_fixed_sizes; i++) {

From b0efbe0ef865090102fca888d96c325d89e90c29 Mon Sep 17 00:00:00 2001
From: Chris Peterson 
Date: Fri, 22 Jul 2016 22:05:45 -0700
Subject: [PATCH 097/135] Bug 1288603 - Remove NumericLimits.h because all
 platforms have numeric_limits. r=froydnj

---
 js/src/ctypes/CTypes.cpp    | 51 ++++++++++++++++++-------------------
 mfbt/NumericLimits.h        | 38 ---------------------------
 mfbt/Saturate.h             | 11 ++++----
 mfbt/moz.build              |  1 -
 mfbt/tests/TestSaturate.cpp | 42 +++++++++++++++---------------
 5 files changed, 52 insertions(+), 91 deletions(-)
 delete mode 100644 mfbt/NumericLimits.h

diff --git a/js/src/ctypes/CTypes.cpp b/js/src/ctypes/CTypes.cpp
index bfa5b8f35e9d..4746c688dd04 100644
--- a/js/src/ctypes/CTypes.cpp
+++ b/js/src/ctypes/CTypes.cpp
@@ -8,9 +8,9 @@
 
 #include "mozilla/FloatingPoint.h"
 #include "mozilla/MemoryReporting.h"
-#include "mozilla/NumericLimits.h"
 #include "mozilla/Vector.h"
 
+#include 
 #include 
 #include 
 
@@ -48,7 +48,6 @@
 #include "jsobjinlines.h"
 
 using namespace std;
-using mozilla::NumericLimits;
 
 using JS::AutoCheckCannotGC;
 
@@ -2498,7 +2497,7 @@ JS_STATIC_ASSERT(sizeof(long long) == 8);
 JS_STATIC_ASSERT(sizeof(size_t) == sizeof(uintptr_t));
 JS_STATIC_ASSERT(sizeof(float) == 4);
 JS_STATIC_ASSERT(sizeof(PRFuncPtr) == sizeof(void*));
-JS_STATIC_ASSERT(NumericLimits::is_signed);
+JS_STATIC_ASSERT(numeric_limits::is_signed);
 
 // Templated helper to convert FromType to TargetType, for the default case
 // where the trivial POD constructor will do.
@@ -2563,15 +2562,15 @@ static MOZ_ALWAYS_INLINE bool IsAlwaysExact()
   // 2) If FromType is signed, TargetType must also be signed. (Floating point
   //    types are always signed.)
   // 3) If TargetType is an exact integral type, FromType must be also.
-  if (NumericLimits::digits < NumericLimits::digits)
+  if (numeric_limits::digits < numeric_limits::digits)
     return false;
 
-  if (NumericLimits::is_signed &&
-      !NumericLimits::is_signed)
+  if (numeric_limits::is_signed &&
+      !numeric_limits::is_signed)
     return false;
 
-  if (!NumericLimits::is_exact &&
-      NumericLimits::is_exact)
+  if (!numeric_limits::is_exact &&
+      numeric_limits::is_exact)
     return false;
 
   return true;
@@ -2582,7 +2581,7 @@ static MOZ_ALWAYS_INLINE bool IsAlwaysExact()
 template
 struct IsExactImpl {
   static MOZ_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
-    JS_STATIC_ASSERT(NumericLimits::is_exact);
+    JS_STATIC_ASSERT(numeric_limits::is_exact);
     return FromType(j) == i;
   }
 };
@@ -2591,7 +2590,7 @@ struct IsExactImpl {
 template
 struct IsExactImpl {
   static MOZ_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
-    JS_STATIC_ASSERT(NumericLimits::is_exact);
+    JS_STATIC_ASSERT(numeric_limits::is_exact);
     return i >= 0 && FromType(j) == i;
   }
 };
@@ -2600,7 +2599,7 @@ struct IsExactImpl {
 template
 struct IsExactImpl {
   static MOZ_ALWAYS_INLINE bool Test(FromType i, TargetType j) {
-    JS_STATIC_ASSERT(NumericLimits::is_exact);
+    JS_STATIC_ASSERT(numeric_limits::is_exact);
     return TargetType(i) >= 0 && FromType(j) == i;
   }
 };
@@ -2611,7 +2610,7 @@ template
 static MOZ_ALWAYS_INLINE bool ConvertExact(FromType i, TargetType* result)
 {
   // Require that TargetType is integral, to simplify conversion.
-  JS_STATIC_ASSERT(NumericLimits::is_exact);
+  JS_STATIC_ASSERT(numeric_limits::is_exact);
 
   *result = Convert(i);
 
@@ -2622,8 +2621,8 @@ static MOZ_ALWAYS_INLINE bool ConvertExact(FromType i, TargetType* result)
   // Return 'true' if 'i' is exactly representable in 'TargetType'.
   return IsExactImpl::is_signed,
-                     NumericLimits::is_signed>::Test(i, *result);
+                     numeric_limits::is_signed,
+                     numeric_limits::is_signed>::Test(i, *result);
 }
 
 // Templated helper to determine if Type 'i' is negative. Default case
@@ -2647,7 +2646,7 @@ struct IsNegativeImpl {
 template
 static MOZ_ALWAYS_INLINE bool IsNegative(Type i)
 {
-  return IsNegativeImpl::is_signed>::Test(i);
+  return IsNegativeImpl::is_signed>::Test(i);
 }
 
 // Implicitly convert val to bool, allowing bool, int, and double
@@ -2681,7 +2680,7 @@ template
 static bool
 jsvalToInteger(JSContext* cx, Value val, IntegerType* result)
 {
-  JS_STATIC_ASSERT(NumericLimits::is_exact);
+  JS_STATIC_ASSERT(numeric_limits::is_exact);
 
   if (val.isInt32()) {
     // Make sure the integer fits in the alotted precision, and has the right
@@ -2771,7 +2770,7 @@ template
 static bool
 jsvalToFloat(JSContext* cx, Value val, FloatType* result)
 {
-  JS_STATIC_ASSERT(!NumericLimits::is_exact);
+  JS_STATIC_ASSERT(!numeric_limits::is_exact);
 
   // The following casts may silently throw away some bits, but there's
   // no good way around it. Sternly requiring that the 64-bit double
@@ -2829,7 +2828,7 @@ static bool
 StringToInteger(JSContext* cx, CharT* cp, size_t length, IntegerType* result,
                 bool* overflow)
 {
-  JS_STATIC_ASSERT(NumericLimits::is_exact);
+  JS_STATIC_ASSERT(numeric_limits::is_exact);
 
   const CharT* end = cp + length;
   if (cp == end)
@@ -2837,7 +2836,7 @@ StringToInteger(JSContext* cx, CharT* cp, size_t length, IntegerType* result,
 
   IntegerType sign = 1;
   if (cp[0] == '-') {
-    if (!NumericLimits::is_signed)
+    if (!numeric_limits::is_signed)
       return false;
 
     sign = -1;
@@ -2906,7 +2905,7 @@ jsvalToBigInteger(JSContext* cx,
                   IntegerType* result,
                   bool* overflow)
 {
-  JS_STATIC_ASSERT(NumericLimits::is_exact);
+  JS_STATIC_ASSERT(numeric_limits::is_exact);
 
   if (val.isInt32()) {
     // Make sure the integer fits in the alotted precision, and has the right
@@ -2978,7 +2977,7 @@ jsidToBigInteger(JSContext* cx,
                  bool allowString,
                  IntegerType* result)
 {
-  JS_STATIC_ASSERT(NumericLimits::is_exact);
+  JS_STATIC_ASSERT(numeric_limits::is_exact);
 
   if (JSID_IS_INT(val)) {
     // Make sure the integer fits in the alotted precision, and has the right
@@ -3027,7 +3026,7 @@ template
 static bool
 jsvalToIntegerExplicit(Value val, IntegerType* result)
 {
-  JS_STATIC_ASSERT(NumericLimits::is_exact);
+  JS_STATIC_ASSERT(numeric_limits::is_exact);
 
   if (val.isDouble()) {
     // Convert -Inf, Inf, and NaN to 0; otherwise, convert by C-style cast.
@@ -3108,7 +3107,7 @@ template
 void
 IntegerToString(IntegerType i, int radix, mozilla::Vector& result)
 {
-  JS_STATIC_ASSERT(NumericLimits::is_exact);
+  JS_STATIC_ASSERT(numeric_limits::is_exact);
 
   // The buffer must be big enough for all the bits of IntegerType to fit,
   // in base-2, including '-'.
@@ -3195,7 +3194,7 @@ ConvertToJS(JSContext* cx,
     /* Return an Int64 or UInt64 object - do not convert to a JS number. */    \
     uint64_t value;                                                            \
     RootedObject proto(cx);                                                    \
-    if (!NumericLimits::is_signed) {                                     \
+    if (!numeric_limits::is_signed) {                                    \
       value = *static_cast(data);                                       \
       /* Get ctypes.UInt64.prototype from ctypes.CType.prototype. */           \
       proto = CType::GetProtoFromType(cx, typeObj, SLOT_UINT64PROTO);          \
@@ -3210,7 +3209,7 @@ ConvertToJS(JSContext* cx,
     }                                                                          \
                                                                                \
     JSObject* obj = Int64Base::Construct(cx, proto, value,                     \
-      !NumericLimits::is_signed);                                        \
+      !numeric_limits::is_signed);                                       \
     if (!obj)                                                                  \
       return false;                                                            \
     result.setObject(*obj);                                                    \
@@ -4172,7 +4171,7 @@ BuildDataSource(JSContext* cx,
 #define WRAPPED_INT_CASE(name, type, ffiType)                                  \
   case TYPE_##name:                                                            \
     /* Serialize as a wrapped decimal integer. */                              \
-    if (!NumericLimits::is_signed)                                       \
+    if (!numeric_limits::is_signed)                                      \
       AppendString(result, "ctypes.UInt64(\"");                                \
     else                                                                       \
       AppendString(result, "ctypes.Int64(\"");                                 \
diff --git a/mfbt/NumericLimits.h b/mfbt/NumericLimits.h
deleted file mode 100644
index 2ae8e7e51f6f..000000000000
--- a/mfbt/NumericLimits.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/* -*- 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/. */
-
-/* Compatibility with std::numeric_limits. */
-
-#ifndef mozilla_NumericLimits_h
-#define mozilla_NumericLimits_h
-
-#include "mozilla/Char16.h"
-
-#include 
-#include 
-
-namespace mozilla {
-
-/**
- * The NumericLimits class provides a compatibility layer with
- * std::numeric_limits for char16_t, otherwise it is exactly the same as
- * std::numeric_limits.  Code which does not need std::numeric_limits
- * should avoid using NumericLimits.
- */
-template
-class NumericLimits : public std::numeric_limits
-{
-};
-
-template<>
-class NumericLimits : public std::numeric_limits
-{
-  // char16_t and uint16_t numeric limits should be exactly the same.
-};
-
-} // namespace mozilla
-
-#endif /* mozilla_NumericLimits_h */
diff --git a/mfbt/Saturate.h b/mfbt/Saturate.h
index 5d3315e17be5..b79364d26809 100644
--- a/mfbt/Saturate.h
+++ b/mfbt/Saturate.h
@@ -11,9 +11,10 @@
 
 #include "mozilla/Attributes.h"
 #include "mozilla/Move.h"
-#include "mozilla/NumericLimits.h"
 #include "mozilla/TypeTraits.h"
 
+#include 
+
 namespace mozilla {
 namespace detail {
 
@@ -63,8 +64,8 @@ public:
 
   const T& operator+=(const T& aRhs) const
   {
-    const T min = NumericLimits::min();
-    const T max = NumericLimits::max();
+    const T min = std::numeric_limits::min();
+    const T max = std::numeric_limits::max();
 
     if (aRhs > static_cast(0)) {
       mValue = (max - aRhs) < mValue ? max : mValue + aRhs;
@@ -76,8 +77,8 @@ public:
 
   const T& operator-=(const T& aRhs) const
   {
-    const T min = NumericLimits::min();
-    const T max = NumericLimits::max();
+    const T min = std::numeric_limits::min();
+    const T max = std::numeric_limits::max();
 
     if (aRhs > static_cast(0)) {
       mValue = (min + aRhs) > mValue ? min : mValue - aRhs;
diff --git a/mfbt/moz.build b/mfbt/moz.build
index e0f112a93cb1..fd752d53f3ea 100644
--- a/mfbt/moz.build
+++ b/mfbt/moz.build
@@ -62,7 +62,6 @@ EXPORTS.mozilla = [
     'Move.h',
     'NotNull.h',
     'NullPtr.h',
-    'NumericLimits.h',
     'Opaque.h',
     'Pair.h',
     'PodOperations.h',
diff --git a/mfbt/tests/TestSaturate.cpp b/mfbt/tests/TestSaturate.cpp
index cd1208ff8f31..06573ba4a2ed 100644
--- a/mfbt/tests/TestSaturate.cpp
+++ b/mfbt/tests/TestSaturate.cpp
@@ -7,10 +7,10 @@
 #include 
 
 #include 
-#include 
+
+#include 
 
 using mozilla::detail::Saturate;
-using mozilla::NumericLimits;
 
 #define A(a) MOZ_RELEASE_ASSERT(a, "Test \'" #a "\'  failed.")
 
@@ -50,7 +50,7 @@ uint8_t
 StartValue()
 {
   // Picking a value near middle of uint8_t's range.
-  return static_cast(NumericLimits::max());
+  return static_cast(std::numeric_limits::max());
 }
 
 template<>
@@ -58,7 +58,7 @@ uint16_t
 StartValue()
 {
   // Picking a value near middle of uint16_t's range.
-  return static_cast(NumericLimits::max());
+  return static_cast(std::numeric_limits::max());
 }
 
 template<>
@@ -66,7 +66,7 @@ uint32_t
 StartValue()
 {
   // Picking a value near middle of uint32_t's range.
-  return static_cast(NumericLimits::max());
+  return static_cast(std::numeric_limits::max());
 }
 
 // Add
@@ -154,28 +154,28 @@ template
 static void
 TestUpperBound()
 {
-  Saturate satValue(NumericLimits::max());
+  Saturate satValue(std::numeric_limits::max());
 
-  A(--satValue == (NumericLimits::max() - 1));
-  A(++satValue == (NumericLimits::max()));
-  A(++satValue == (NumericLimits::max())); // don't overflow here
-  A(++satValue == (NumericLimits::max())); // don't overflow here
-  A(--satValue == (NumericLimits::max() - 1)); // back at (max - 1)
-  A(--satValue == (NumericLimits::max() - 2));
+  A(--satValue == (std::numeric_limits::max() - 1));
+  A(++satValue == (std::numeric_limits::max()));
+  A(++satValue == (std::numeric_limits::max())); // don't overflow here
+  A(++satValue == (std::numeric_limits::max())); // don't overflow here
+  A(--satValue == (std::numeric_limits::max() - 1)); // back at (max - 1)
+  A(--satValue == (std::numeric_limits::max() - 2));
 }
 
 template
 static void
 TestLowerBound()
 {
-  Saturate satValue(NumericLimits::min());
+  Saturate satValue(std::numeric_limits::min());
 
-  A(++satValue == (NumericLimits::min() + 1));
-  A(--satValue == (NumericLimits::min()));
-  A(--satValue == (NumericLimits::min())); // don't overflow here
-  A(--satValue == (NumericLimits::min())); // don't overflow here
-  A(++satValue == (NumericLimits::min() + 1)); // back at (max + 1)
-  A(++satValue == (NumericLimits::min() + 2));
+  A(++satValue == (std::numeric_limits::min() + 1));
+  A(--satValue == (std::numeric_limits::min()));
+  A(--satValue == (std::numeric_limits::min())); // don't overflow here
+  A(--satValue == (std::numeric_limits::min())); // don't overflow here
+  A(++satValue == (std::numeric_limits::min() + 1)); // back at (max + 1)
+  A(++satValue == (std::numeric_limits::min() + 2));
 }
 
 // Framework
@@ -187,8 +187,8 @@ TestAll()
 {
   // Assert that we don't accidently hit type's range limits in tests.
   const T value = StartValue();
-  A(NumericLimits::min() + static_cast(sNumOps) <= value);
-  A(NumericLimits::max() - static_cast(sNumOps) >= value);
+  A(std::numeric_limits::min() + static_cast(sNumOps) <= value);
+  A(std::numeric_limits::max() - static_cast(sNumOps) >= value);
 
   TestPrefixIncr();
   TestPostfixIncr();

From 6871885a3e8fcc7e80d3c2f5be16859e22b9735a Mon Sep 17 00:00:00 2001
From: Andrea Marchesini 
Date: Sat, 23 Jul 2016 08:57:40 +0200
Subject: [PATCH 098/135] Bug 1287091 - part 1 - ContextualIdentityService
 should use a storage for the containers, r=Gijs

---
 browser/base/content/browser.js               |   3 +-
 browser/base/content/nsContextMenu.js         |   3 +-
 browser/base/content/utilityOverlay.js        |   4 +-
 .../ContextualIdentityService.jsm             | 118 +++++++++++++++++-
 4 files changed, 118 insertions(+), 10 deletions(-)

diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js
index 511178b5e7de..fc58acb41e35 100755
--- a/browser/base/content/browser.js
+++ b/browser/base/content/browser.js
@@ -8,6 +8,7 @@ var Cu = Components.utils;
 var Cc = Components.classes;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/ContextualIdentityService.jsm");
 Cu.import("resource://gre/modules/NotificationDB.jsm");
 Cu.import("resource:///modules/RecentWindow.jsm");
 
@@ -56,8 +57,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils",
                                    "@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils");
 XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager",
                                   "resource://gre/modules/LightweightThemeManager.jsm");
-XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
-                                  "resource://gre/modules/ContextualIdentityService.jsm");
 XPCOMUtils.defineLazyServiceGetter(this, "gAboutNewTabService",
                                    "@mozilla.org/browser/aboutnewtab-service;1",
                                    "nsIAboutNewTabService");
diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js
index 124847b00beb..263b13737dcb 100644
--- a/browser/base/content/nsContextMenu.js
+++ b/browser/base/content/nsContextMenu.js
@@ -4,6 +4,7 @@
 # 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/.
 
+Components.utils.import("resource://gre/modules/ContextualIdentityService.jsm");
 Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
 Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm");
 Components.utils.import("resource://gre/modules/LoginManagerContextMenu.jsm");
@@ -11,8 +12,6 @@ Components.utils.import("resource://gre/modules/BrowserUtils.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
-                                  "resource://gre/modules/ContextualIdentityService.jsm");
 
 XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper",
   "resource://gre/modules/LoginHelper.jsm");
diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js
index dbddd6de62a3..458a3563ed3b 100644
--- a/browser/base/content/utilityOverlay.js
+++ b/browser/base/content/utilityOverlay.js
@@ -5,6 +5,7 @@
 
 // Services = object with smart getters for common XPCOM services
 Components.utils.import("resource://gre/modules/AppConstants.jsm");
+Components.utils.import("resource://gre/modules/ContextualIdentityService.jsm");
 Components.utils.import("resource://gre/modules/Services.jsm");
 Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
 Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm");
@@ -13,9 +14,6 @@ Components.utils.import("resource:///modules/RecentWindow.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "ShellService",
                                   "resource:///modules/ShellService.jsm");
 
-XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService",
-                                  "resource://gre/modules/ContextualIdentityService.jsm");
-
 XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
                                    "@mozilla.org/browser/aboutnewtab-service;1",
                                    "nsIAboutNewTabService");
diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm
index 31a4aabea8c5..59b8c5acd414 100644
--- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm
+++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm
@@ -7,16 +7,34 @@ this.EXPORTED_SYMBOLS = ["ContextualIdentityService"];
 const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
 
 Cu.import("resource://gre/modules/XPCOMUtils.jsm");
-Cu.import("resource://gre/modules/Services.jsm")
+Cu.import("resource://gre/modules/Services.jsm");
 
-const DEFAULT_TAB_COLOR = "#909090"
+const DEFAULT_TAB_COLOR = "#909090";
+const SAVE_DELAY_MS = 1500;
 
 XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() {
   return Services.strings.createBundle("chrome://browser/locale/browser.properties");
 });
 
+XPCOMUtils.defineLazyGetter(this, "gTextDecoder", function () {
+  return new TextDecoder();
+});
+
+XPCOMUtils.defineLazyGetter(this, "gTextEncoder", function () {
+  return new TextEncoder();
+});
+
+XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown",
+                                  "resource://gre/modules/AsyncShutdown.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "OS",
+                                  "resource://gre/modules/osfile.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
+                                  "resource://gre/modules/DeferredTask.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
+                                  "resource://gre/modules/FileUtils.jsm");
+
 this.ContextualIdentityService = {
-  _identities: [
+  _defaultIdentities: [
     { userContextId: 1,
       public: true,
       icon: "chrome://browser/skin/usercontext/personal.svg",
@@ -62,15 +80,107 @@ this.ContextualIdentityService = {
       alreadyOpened: false },
   ],
 
+  _identities: null,
+
+  _path: null,
+  _dataReady: false,
+
+  _saver: null,
+
+  init() {
+    this._path = OS.Path.join(OS.Constants.Path.profileDir, "containers.json");
+
+    this._saver = new DeferredTask(() => this.save(), SAVE_DELAY_MS);
+    AsyncShutdown.profileBeforeChange.addBlocker("ContextualIdentityService: writing data",
+                                                 () => this._saver.finalize());
+
+    this.load();
+  },
+
+  load() {
+    OS.File.read(this._path).then(bytes => {
+      // If synchronous loading happened in the meantime, exit now.
+      if (this._dataReady) {
+        return;
+      }
+
+      try {
+        this._identities = JSON.parse(gTextDecoder.decode(bytes));
+        this._dataReady = true;
+      } catch(error) {
+        this.loadError(error);
+      }
+    }, (error) => {
+      this.loadError(error);
+    });
+  },
+
+  loadError(error) {
+    if (!(error instanceof OS.File.Error && error.becauseNoSuchFile) &&
+        !(error instanceof Components.Exception &&
+          error.result == Cr.NS_ERROR_FILE_NOT_FOUND)) {
+      // Let's report the error.
+      Cu.reportError(error);
+    }
+
+    // If synchronous loading happened in the meantime, exit now.
+    if (this._dataReady) {
+      return;
+    }
+
+    this._identities = this._defaultIdentities;
+    this._dataReady = true;
+
+    this.saveSoon();
+  },
+
+  saveSoon() {
+    this._saver.arm();
+  },
+
+  save() {
+   let bytes = gTextEncoder.encode(JSON.stringify(this._identities));
+   return OS.File.writeAtomic(this._path, bytes,
+                              { tmpPath: this._path + ".tmp" });
+  },
+
+  ensureDataReady() {
+    if (this._dataReady) {
+      return;
+    }
+
+    try {
+      // This reads the file and automatically detects the UTF-8 encoding.
+      let inputStream = Cc["@mozilla.org/network/file-input-stream;1"]
+                          .createInstance(Ci.nsIFileInputStream);
+      inputStream.init(new FileUtils.File(this._path),
+                       FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0);
+      try {
+        let json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON);
+        this._identities = json.decodeFromStream(inputStream,
+                                                 inputStream.available());
+        this._dataReady = true;
+      } finally {
+        inputStream.close();
+      }
+    } catch (error) {
+      this.loadError(error);
+      return;
+    }
+  },
+
   getIdentities() {
+    this.ensureDataReady();
     return this._identities.filter(info => info.public);
   },
 
   getPrivateIdentity(label) {
+    this.ensureDataReady();
     return this._identities.find(info => !info.public && info.label == label);
   },
 
   getIdentityFromId(userContextId) {
+    this.ensureDataReady();
     return this._identities.find(info => info.userContextId == userContextId);
   },
 
@@ -122,3 +232,5 @@ this.ContextualIdentityService = {
     }
   },
 }
+
+ContextualIdentityService.init();

From 173c3cdfddb5522606d8bc7ff3cbfadbcf0f9c6a Mon Sep 17 00:00:00 2001
From: Andrea Marchesini 
Date: Sat, 23 Jul 2016 08:57:53 +0200
Subject: [PATCH 099/135] Bug 1287091 - part 2 - ContextualIdentityService must
 store telemetry data in a separate array, r=Gijs

---
 .../contextualidentity/ContextualIdentityService.jsm | 12 ++++--------
 1 file changed, 4 insertions(+), 8 deletions(-)

diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm
index 59b8c5acd414..8a2c1871d538 100644
--- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm
+++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm
@@ -41,7 +41,6 @@ this.ContextualIdentityService = {
       color: "#00a7e0",
       label: "userContextPersonal.label",
       accessKey: "userContextPersonal.accesskey",
-      alreadyOpened: false,
       telemetryId: 1,
     },
     { userContextId: 2,
@@ -50,7 +49,6 @@ this.ContextualIdentityService = {
       color: "#f89c24",
       label: "userContextWork.label",
       accessKey: "userContextWork.accesskey",
-      alreadyOpened: false,
       telemetryId: 2,
     },
     { userContextId: 3,
@@ -59,7 +57,6 @@ this.ContextualIdentityService = {
       color: "#7dc14c",
       label: "userContextBanking.label",
       accessKey: "userContextBanking.accesskey",
-      alreadyOpened: false,
       telemetryId: 3,
     },
     { userContextId: 4,
@@ -68,7 +65,6 @@ this.ContextualIdentityService = {
       color: "#ee5195",
       label: "userContextShopping.label",
       accessKey: "userContextShopping.accesskey",
-      alreadyOpened: false,
       telemetryId: 4,
     },
     { userContextId: Math.pow(2, 31) - 1,
@@ -76,11 +72,11 @@ this.ContextualIdentityService = {
       icon: "",
       color: "",
       label: "userContextIdInternal.thumbnail",
-      accessKey: "",
-      alreadyOpened: false },
+      accessKey: "" },
   ],
 
   _identities: null,
+  _openedIdentities: new Set(),
 
   _path: null,
   _dataReady: false,
@@ -219,8 +215,8 @@ this.ContextualIdentityService = {
       return;
     }
 
-    if (!identity.alreadyOpened) {
-      identity.alreadyOpened = true;
+    if (this._openedIdentities.has(userContextId)) {
+      this._openedIdentities.add(userContextId);
       Services.telemetry.getHistogramById("UNIQUE_CONTAINERS_OPENED").add(1);
     }
 

From 9929bc7cd64cbcb0d5ebb97a1a9aa5f7bbb150d3 Mon Sep 17 00:00:00 2001
From: Andrea Marchesini 
Date: Sat, 23 Jul 2016 08:58:09 +0200
Subject: [PATCH 100/135] Bug 1287091 - part 3 - ContextualIdentityService JSON
 file should have versions, r=Gijs

---
 .../ContextualIdentityService.jsm             | 27 ++++++++++++++++---
 1 file changed, 23 insertions(+), 4 deletions(-)

diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm
index 8a2c1871d538..009f05db494b 100644
--- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm
+++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm
@@ -67,7 +67,7 @@ this.ContextualIdentityService = {
       accessKey: "userContextShopping.accesskey",
       telemetryId: 4,
     },
-    { userContextId: Math.pow(2, 31) - 1,
+    { userContextId: 5,
       public: false,
       icon: "",
       color: "",
@@ -77,6 +77,7 @@ this.ContextualIdentityService = {
 
   _identities: null,
   _openedIdentities: new Set(),
+  _lastUserContextId: 0,
 
   _path: null,
   _dataReady: false,
@@ -101,7 +102,16 @@ this.ContextualIdentityService = {
       }
 
       try {
-        this._identities = JSON.parse(gTextDecoder.decode(bytes));
+        let data = JSON.parse(gTextDecoder.decode(bytes));
+        if (data.version != 1) {
+          dump("ERROR - ContextualIdentityService - Unknown version found in " + this._path + "\n");
+          this.loadError(null);
+          return;
+        }
+
+        this._identities = data.identities;
+        this._lastUserContextId = data.lastUserContextId;
+
         this._dataReady = true;
       } catch(error) {
         this.loadError(error);
@@ -112,7 +122,8 @@ this.ContextualIdentityService = {
   },
 
   loadError(error) {
-    if (!(error instanceof OS.File.Error && error.becauseNoSuchFile) &&
+    if (error != null &&
+        !(error instanceof OS.File.Error && error.becauseNoSuchFile) &&
         !(error instanceof Components.Exception &&
           error.result == Cr.NS_ERROR_FILE_NOT_FOUND)) {
       // Let's report the error.
@@ -125,6 +136,8 @@ this.ContextualIdentityService = {
     }
 
     this._identities = this._defaultIdentities;
+    this._lastUserContextId = this._defaultIdentities.length;
+
     this._dataReady = true;
 
     this.saveSoon();
@@ -135,7 +148,13 @@ this.ContextualIdentityService = {
   },
 
   save() {
-   let bytes = gTextEncoder.encode(JSON.stringify(this._identities));
+   let object = {
+     version: 1,
+     lastUserContextId: this._lastUserContextId,
+     identities: this._identities
+   };
+
+   let bytes = gTextEncoder.encode(JSON.stringify(object));
    return OS.File.writeAtomic(this._path, bytes,
                               { tmpPath: this._path + ".tmp" });
   },

From f34ab04ccd3f87100a39c05cf1a35ce6406df623 Mon Sep 17 00:00:00 2001
From: Andrea Marchesini 
Date: Sat, 23 Jul 2016 08:58:23 +0200
Subject: [PATCH 101/135] Bug 1287091 - part 4 - ContextualIdentityService
 create/remove/update, r=Gijs

---
 .../customizableui/CustomizableWidgets.jsm    |  2 +-
 .../ContextualIdentityService.jsm             | 90 +++++++++++++++----
 .../components/contextualidentity/moz.build   |  2 +
 .../tests/unit/test_basic.js                  | 67 ++++++++++++++
 .../tests/unit/xpcshell.ini                   |  3 +
 5 files changed, 147 insertions(+), 17 deletions(-)
 create mode 100644 toolkit/components/contextualidentity/tests/unit/test_basic.js
 create mode 100644 toolkit/components/contextualidentity/tests/unit/xpcshell.ini

diff --git a/browser/components/customizableui/CustomizableWidgets.jsm b/browser/components/customizableui/CustomizableWidgets.jsm
index 307309ee7115..4d9c03342b83 100644
--- a/browser/components/customizableui/CustomizableWidgets.jsm
+++ b/browser/components/customizableui/CustomizableWidgets.jsm
@@ -1135,7 +1135,7 @@ const CustomizableWidgets = [
 
       ContextualIdentityService.getIdentities().forEach(identity => {
         let bundle = doc.getElementById("bundle_browser");
-        let label = bundle.getString(identity.label);
+        let label = ContextualIdentityService.getUserContextLabel(identity.userContextId);
 
         let item = doc.createElementNS(kNSXUL, "toolbarbutton");
         item.setAttribute("label", label);
diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm
index 009f05db494b..3d614581a793 100644
--- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm
+++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm
@@ -33,13 +33,17 @@ XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask",
 XPCOMUtils.defineLazyModuleGetter(this, "FileUtils",
                                   "resource://gre/modules/FileUtils.jsm");
 
-this.ContextualIdentityService = {
+function _ContextualIdentityService(path) {
+  this.init(path);
+}
+
+_ContextualIdentityService.prototype = {
   _defaultIdentities: [
     { userContextId: 1,
       public: true,
       icon: "chrome://browser/skin/usercontext/personal.svg",
       color: "#00a7e0",
-      label: "userContextPersonal.label",
+      l10nID: "userContextPersonal.label",
       accessKey: "userContextPersonal.accesskey",
       telemetryId: 1,
     },
@@ -47,7 +51,7 @@ this.ContextualIdentityService = {
       public: true,
       icon: "chrome://browser/skin/usercontext/work.svg",
       color: "#f89c24",
-      label: "userContextWork.label",
+      l10nID: "userContextWork.label",
       accessKey: "userContextWork.accesskey",
       telemetryId: 2,
     },
@@ -55,7 +59,7 @@ this.ContextualIdentityService = {
       public: true,
       icon: "chrome://browser/skin/usercontext/banking.svg",
       color: "#7dc14c",
-      label: "userContextBanking.label",
+      l10nID: "userContextBanking.label",
       accessKey: "userContextBanking.accesskey",
       telemetryId: 3,
     },
@@ -63,7 +67,7 @@ this.ContextualIdentityService = {
       public: true,
       icon: "chrome://browser/skin/usercontext/shopping.svg",
       color: "#ee5195",
-      label: "userContextShopping.label",
+      l10nID: "userContextShopping.label",
       accessKey: "userContextShopping.accesskey",
       telemetryId: 4,
     },
@@ -71,7 +75,7 @@ this.ContextualIdentityService = {
       public: false,
       icon: "",
       color: "",
-      label: "userContextIdInternal.thumbnail",
+      name: "userContextIdInternal.thumbnail",
       accessKey: "" },
   ],
 
@@ -84,9 +88,8 @@ this.ContextualIdentityService = {
 
   _saver: null,
 
-  init() {
-    this._path = OS.Path.join(OS.Constants.Path.profileDir, "containers.json");
-
+  init(path) {
+    this._path = path;
     this._saver = new DeferredTask(() => this.save(), SAVE_DELAY_MS);
     AsyncShutdown.profileBeforeChange.addBlocker("ContextualIdentityService: writing data",
                                                  () => this._saver.finalize());
@@ -159,6 +162,49 @@ this.ContextualIdentityService = {
                               { tmpPath: this._path + ".tmp" });
   },
 
+  create(name, icon, color) {
+    let identity = {
+      userContextId: ++this._lastUserContextId,
+      public: true,
+      icon,
+      color,
+      name
+    };
+
+    this._identities.push(identity);
+    this.saveSoon();
+
+    return Cu.cloneInto(identity, {});
+  },
+
+  update(userContextId, name, icon, color) {
+    let identity = this._identities.find(identity => identity.userContextId == userContextId &&
+                                         identity.public);
+    if (identity) {
+      identity.name = name;
+      identity.color = color;
+      identity.icon = icon;
+      delete identity.l10nID;
+      delete identity.accessKey;
+      this.saveSoon();
+    }
+
+    return !!identity;
+  },
+
+  remove(userContextId) {
+    let index = this._identities.findIndex(i => i.userContextId == userContextId && i.public);
+    if (index == -1) {
+      return false;
+    }
+
+    this._identities.splice(index, 1);
+    this._openedIdentities.delete(userContextId);
+    this.saveSoon();
+
+    return true;
+  },
+
   ensureDataReady() {
     if (this._dataReady) {
       return;
@@ -186,17 +232,18 @@ this.ContextualIdentityService = {
 
   getIdentities() {
     this.ensureDataReady();
-    return this._identities.filter(info => info.public);
+    return Cu.cloneInto(this._identities.filter(info => info.public), {});
   },
 
-  getPrivateIdentity(label) {
+  getPrivateIdentity(name) {
     this.ensureDataReady();
-    return this._identities.find(info => !info.public && info.label == label);
+    return Cu.cloneInto(this._identities.find(info => !info.public && info.name == name), {});
   },
 
   getIdentityFromId(userContextId) {
     this.ensureDataReady();
-    return this._identities.find(info => info.userContextId == userContextId);
+    return Cu.cloneInto(this._identities.find(info => info.userContextId == userContextId &&
+                                              info.public), {});
   },
 
   getUserContextLabel(userContextId) {
@@ -204,7 +251,13 @@ this.ContextualIdentityService = {
     if (!identity.public) {
       return "";
     }
-    return gBrowserBundle.GetStringFromName(identity.label);
+
+    // We cannot localize the user-created identity names.
+    if (identity.name) {
+      return identity.name;
+    }
+
+    return gBrowserBundle.GetStringFromName(identity.l10nID);
   },
 
   setTabStyle(tab) {
@@ -246,6 +299,11 @@ this.ContextualIdentityService = {
                         .add(identity.telemetryId);
     }
   },
-}
 
-ContextualIdentityService.init();
+  createNewInstanceForTesting(path) {
+    return new _ContextualIdentityService(path);
+  },
+};
+
+let path = OS.Path.join(OS.Constants.Path.profileDir, "containers.json");
+this.ContextualIdentityService = new _ContextualIdentityService(path);
diff --git a/toolkit/components/contextualidentity/moz.build b/toolkit/components/contextualidentity/moz.build
index 680c7bd0ea44..9188421f9ec1 100644
--- a/toolkit/components/contextualidentity/moz.build
+++ b/toolkit/components/contextualidentity/moz.build
@@ -7,3 +7,5 @@
 EXTRA_JS_MODULES += [
     'ContextualIdentityService.jsm',
 ]
+
+XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
diff --git a/toolkit/components/contextualidentity/tests/unit/test_basic.js b/toolkit/components/contextualidentity/tests/unit/test_basic.js
new file mode 100644
index 000000000000..4d17b9a267cc
--- /dev/null
+++ b/toolkit/components/contextualidentity/tests/unit/test_basic.js
@@ -0,0 +1,67 @@
+"use strict";
+
+do_get_profile();
+
+const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/ContextualIdentityService.jsm");
+
+const TEST_STORE_FILE_NAME = "test-containers.json";
+
+let cis;
+
+// Basic tests
+add_task(function() {
+  ok(!!ContextualIdentityService, "ContextualIdentityService exists");
+
+  cis = ContextualIdentityService.createNewInstanceForTesting(TEST_STORE_FILE_NAME);
+  ok(!!cis, "We have our instance of ContextualIdentityService");
+
+  equal(cis.getIdentities().length, 4, "By default, 4 containers.");
+  equal(cis.getIdentityFromId(0), null, "No identity with id 0");
+
+  ok(!!cis.getIdentityFromId(1), "Identity 1 exists");
+  ok(!!cis.getIdentityFromId(2), "Identity 2 exists");
+  ok(!!cis.getIdentityFromId(3), "Identity 3 exists");
+  ok(!!cis.getIdentityFromId(4), "Identity 4 exists");
+});
+
+// Create a new identity
+add_task(function() {
+  equal(cis.getIdentities().length, 4, "By default, 4 containers.");
+
+  let identity = cis.create("New Container", "Icon", "Color");
+  ok(!!identity, "New container created");
+  equal(identity.name, "New Container", "Name matches");
+  equal(identity.icon, "Icon", "Icon matches");
+  equal(identity.color, "Color", "Color matches");
+
+  equal(cis.getIdentities().length, 5, "Expected 5 containers.");
+
+  ok(!!cis.getIdentityFromId(identity.userContextId), "Identity exists");
+  equal(cis.getIdentityFromId(identity.userContextId).name, "New Container", "Identity name is OK");
+  equal(cis.getIdentityFromId(identity.userContextId).icon, "Icon", "Identity icon is OK");
+  equal(cis.getIdentityFromId(identity.userContextId).color, "Color", "Identity color is OK");
+  equal(cis.getUserContextLabel(identity.userContextId), "New Container", "Identity label is OK");
+
+  // Remove an identity
+  equal(cis.remove(-1), false, "cis.remove() returns false if identity doesn't exist.");
+  equal(cis.remove(1), true, "cis.remove() returns true if identity exists.");
+
+  equal(cis.getIdentities().length, 4, "Expected 4 containers.");
+});
+
+// Update an identity
+add_task(function() {
+  ok(!!cis.getIdentityFromId(2), "Identity 2 exists");
+
+  equal(cis.update(-1, "Container", "Icon", "Color"), false, "Update returns false if the identity doesn't exist");
+
+  equal(cis.update(2, "Container", "Icon", "Color"), true, "Update returns true if everything is OK");
+
+  ok(!!cis.getIdentityFromId(2), "Identity exists");
+  equal(cis.getIdentityFromId(2).name, "Container", "Identity name is OK");
+  equal(cis.getIdentityFromId(2).icon, "Icon", "Identity icon is OK");
+  equal(cis.getIdentityFromId(2).color, "Color", "Identity color is OK");
+  equal(cis.getUserContextLabel(2), "Container", "Identity label is OK");
+});
diff --git a/toolkit/components/contextualidentity/tests/unit/xpcshell.ini b/toolkit/components/contextualidentity/tests/unit/xpcshell.ini
new file mode 100644
index 000000000000..b45ff2c30f29
--- /dev/null
+++ b/toolkit/components/contextualidentity/tests/unit/xpcshell.ini
@@ -0,0 +1,3 @@
+[DEFAULT]
+
+[test_basic.js]

From f84740bb92c6562b9ba1bb82e2671ecef69a082b Mon Sep 17 00:00:00 2001
From: Andrea Marchesini 
Date: Sat, 23 Jul 2016 08:58:41 +0200
Subject: [PATCH 102/135] Bug 1287091 - part 5 - ContextualIdentityService
 should dispatch 'clear-origin-data' when a container is deleted, r=Gijs

---
 .../contextualidentity/ContextualIdentityService.jsm           | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm
index 3d614581a793..5a60ef413b40 100644
--- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm
+++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm
@@ -198,6 +198,9 @@ _ContextualIdentityService.prototype = {
       return false;
     }
 
+    Services.obs.notifyObservers(null, "clear-origin-data",
+                                 JSON.stringify({ userContextId }));
+
     this._identities.splice(index, 1);
     this._openedIdentities.delete(userContextId);
     this.saveSoon();

From 3660cacdaf45eda6b91bcca1fe8f616539df4871 Mon Sep 17 00:00:00 2001
From: Andrea Marchesini 
Date: Sat, 23 Jul 2016 10:20:15 +0200
Subject: [PATCH 103/135] Bug 1288681 - Rename HTMLInputElement::directory to
 HTMLInputElement::allowdirs, r=smaug

---
 dom/base/nsGkAtomList.h                        |  1 +
 dom/filesystem/tests/test_webkitdirectory.html |  4 ++--
 dom/html/HTMLInputElement.cpp                  | 11 ++++-------
 dom/html/HTMLInputElement.h                    |  8 ++++----
 dom/webidl/HTMLInputElement.webidl             |  4 ++--
 5 files changed, 13 insertions(+), 15 deletions(-)

diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h
index bd1d3a72fd3d..351aadec8b63 100644
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -75,6 +75,7 @@ GK_ATOM(after_start, "after_start")
 GK_ATOM(align, "align")
 GK_ATOM(alink, "alink")
 GK_ATOM(all, "all")
+GK_ATOM(allowdirs, "allowdirs")
 GK_ATOM(allowevents, "allowevents")
 GK_ATOM(allownegativeassertions, "allownegativeassertions")
 GK_ATOM(allowforms,"allow-forms")
diff --git a/dom/filesystem/tests/test_webkitdirectory.html b/dom/filesystem/tests/test_webkitdirectory.html
index 4fff10c6c6f0..f40fba5f9e47 100644
--- a/dom/filesystem/tests/test_webkitdirectory.html
+++ b/dom/filesystem/tests/test_webkitdirectory.html
@@ -8,8 +8,8 @@
 
 
 
-
-
+
+
 
 
 
+
+
diff --git a/dom/security/test/hsts/file_priming.js b/dom/security/test/hsts/file_priming.js
new file mode 100644
index 000000000000..023022da67cd
--- /dev/null
+++ b/dom/security/test/hsts/file_priming.js
@@ -0,0 +1,4 @@
+function completed() {
+  return;
+}
+completed();
diff --git a/dom/security/test/hsts/file_stylesheet.css b/dom/security/test/hsts/file_stylesheet.css
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git a/dom/security/test/hsts/file_testserver.sjs b/dom/security/test/hsts/file_testserver.sjs
new file mode 100644
index 000000000000..d5cd6b17a06e
--- /dev/null
+++ b/dom/security/test/hsts/file_testserver.sjs
@@ -0,0 +1,66 @@
+// SJS file for HSTS mochitests
+
+Components.utils.import("resource://gre/modules/NetUtil.jsm");
+Components.utils.importGlobalProperties(["URLSearchParams"]);
+
+function loadFromFile(path) {
+  // Load the HTML to return in the response from file.
+  // Since it's relative to the cwd of the test runner, we start there and
+  // append to get to the actual path of the file.
+  var testFile =
+    Components.classes["@mozilla.org/file/directory_service;1"].
+    getService(Components.interfaces.nsIProperties).
+    get("CurWorkD", Components.interfaces.nsILocalFile);
+  var dirs = path.split("/");
+  for (var i = 0; i < dirs.length; i++) {
+    testFile.append(dirs[i]);
+  }
+  var testFileStream =
+    Components.classes["@mozilla.org/network/file-input-stream;1"].
+    createInstance(Components.interfaces.nsIFileInputStream);
+  testFileStream.init(testFile, -1, 0, 0);
+  var test = NetUtil.readInputStreamToString(testFileStream, testFileStream.available());
+  return test;
+}
+
+function handleRequest(request, response)
+{
+  const query = new URLSearchParams(request.queryString);
+
+  redir = query.get('redir');
+  if (redir == 'same') {
+    query.delete("redir");
+    response.setStatus(302);
+    let newURI = request.uri;
+    newURI.queryString = query.serialize();
+    response.setHeader("Location", newURI.spec)
+  }
+
+  // avoid confusing cache behaviors
+  response.setHeader("Cache-Control", "no-cache", false);
+
+  // if we have a priming header, check for required behavior
+  // and set header appropriately
+  if (request.hasHeader('Upgrade-Insecure-Requests')) {
+    var expected = query.get('primer');
+    if (expected == 'prime-hsts') {
+      // set it for 5 minutes
+      response.setHeader("Strict-Transport-Security", "max-age="+(60*5), false);
+    } else if (expected == 'reject-upgrade') {
+      response.setHeader("Strict-Transport-Security", "max-age=0", false);
+    }
+    response.write('');
+    return;
+  }
+
+  var file = query.get('file');
+  if (file) {
+    var mimetype = unescape(query.get('mimetype'));
+    response.setHeader("Content-Type", mimetype, false);
+    response.write(loadFromFile(unescape(file)));
+    return;
+  }
+
+  response.setHeader("Content-Type", "application/json", false);
+  response.write('{}');
+}
diff --git a/dom/security/test/mixedcontentblocker/test_main.html b/dom/security/test/mixedcontentblocker/test_main.html
index dfec03fa9794..249ead1ebf5a 100644
--- a/dom/security/test/mixedcontentblocker/test_main.html
+++ b/dom/security/test/mixedcontentblocker/test_main.html
@@ -162,6 +162,9 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=62178
   }
 
   function startTest() {
+    // Set prefs to use mixed-content before HSTS
+    SpecialPowers.pushPrefEnv({'set': [["security.mixed_content.use_hsts", false],
+                                       ["security.mixed_content.send_hsts_priming", false]]});
     //Set the first set of mixed content settings and increment the counter.
     //Enable  and  for the test.
     changePrefs([[ "dom.image.srcset.enabled", true ], [ "dom.image.picture.enabled", true ]],
diff --git a/dom/security/test/moz.build b/dom/security/test/moz.build
index 74f0fefef75d..80e86b6c006f 100644
--- a/dom/security/test/moz.build
+++ b/dom/security/test/moz.build
@@ -27,4 +27,5 @@ MOCHITEST_CHROME_MANIFESTS += [
 BROWSER_CHROME_MANIFESTS += [
     'contentverifier/browser.ini',
     'csp/browser.ini',
+    'hsts/browser.ini',
 ]
diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp
index 8d6af9977543..9ccd4c6ee16a 100644
--- a/ipc/glue/BackgroundUtils.cpp
+++ b/ipc/glue/BackgroundUtils.cpp
@@ -263,7 +263,9 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo,
       redirectChain,
       aLoadInfo->CorsUnsafeHeaders(),
       aLoadInfo->GetForcePreflight(),
-      aLoadInfo->GetIsPreflight());
+      aLoadInfo->GetIsPreflight(),
+      aLoadInfo->GetForceHSTSPriming(),
+      aLoadInfo->GetMixedContentWouldBlock());
 
   return NS_OK;
 }
@@ -329,7 +331,10 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs,
                           redirectChain,
                           loadInfoArgs.corsUnsafeHeaders(),
                           loadInfoArgs.forcePreflight(),
-                          loadInfoArgs.isPreflight());
+                          loadInfoArgs.isPreflight(),
+                          loadInfoArgs.forceHSTSPriming(),
+                          loadInfoArgs.mixedContentWouldBlock()
+                          );
 
    loadInfo.forget(outLoadInfo);
    return NS_OK;
diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp
index 0cfad010b87d..7cf515257104 100644
--- a/netwerk/base/LoadInfo.cpp
+++ b/netwerk/base/LoadInfo.cpp
@@ -60,6 +60,8 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
   , mIsThirdPartyContext(false)
   , mForcePreflight(false)
   , mIsPreflight(false)
+  , mForceHSTSPriming(false)
+  , mMixedContentWouldBlock(false)
 {
   MOZ_ASSERT(mLoadingPrincipal);
   MOZ_ASSERT(mTriggeringPrincipal);
@@ -213,6 +215,8 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow,
   , mIsThirdPartyContext(false) // NB: TYPE_DOCUMENT implies not third-party.
   , mForcePreflight(false)
   , mIsPreflight(false)
+  , mForceHSTSPriming(false)
+  , mMixedContentWouldBlock(false)
 {
   // Top-level loads are never third-party
   // Grab the information we can out of the window.
@@ -265,6 +269,8 @@ LoadInfo::LoadInfo(const LoadInfo& rhs)
   , mCorsUnsafeHeaders(rhs.mCorsUnsafeHeaders)
   , mForcePreflight(rhs.mForcePreflight)
   , mIsPreflight(rhs.mIsPreflight)
+  , mForceHSTSPriming(rhs.mForceHSTSPriming)
+  , mMixedContentWouldBlock(rhs.mMixedContentWouldBlock)
 {
 }
 
@@ -288,7 +294,9 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
                    nsTArray>& aRedirectChain,
                    const nsTArray& aCorsUnsafeHeaders,
                    bool aForcePreflight,
-                   bool aIsPreflight)
+                   bool aIsPreflight,
+                   bool aForceHSTSPriming,
+                   bool aMixedContentWouldBlock)
   : mLoadingPrincipal(aLoadingPrincipal)
   , mTriggeringPrincipal(aTriggeringPrincipal)
   , mSecurityFlags(aSecurityFlags)
@@ -308,6 +316,8 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal,
   , mCorsUnsafeHeaders(aCorsUnsafeHeaders)
   , mForcePreflight(aForcePreflight)
   , mIsPreflight(aIsPreflight)
+  , mForceHSTSPriming (aForceHSTSPriming)
+  , mMixedContentWouldBlock(aMixedContentWouldBlock)
 {
   // Only top level TYPE_DOCUMENT loads can have a null loadingPrincipal
   MOZ_ASSERT(mLoadingPrincipal || aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT);
@@ -760,6 +770,34 @@ LoadInfo::GetIsPreflight(bool* aIsPreflight)
   return NS_OK;
 }
 
+NS_IMETHODIMP
+LoadInfo::GetForceHSTSPriming(bool* aForceHSTSPriming)
+{
+  *aForceHSTSPriming = mForceHSTSPriming;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+LoadInfo::GetMixedContentWouldBlock(bool *aMixedContentWouldBlock)
+{
+  *aMixedContentWouldBlock = mMixedContentWouldBlock;
+  return NS_OK;
+}
+
+void
+LoadInfo::SetHSTSPriming(bool aMixedContentWouldBlock)
+{
+  mForceHSTSPriming = true;
+  mMixedContentWouldBlock = aMixedContentWouldBlock;
+}
+
+void
+LoadInfo::ClearHSTSPriming()
+{
+  mForceHSTSPriming = false;
+  mMixedContentWouldBlock = false;
+}
+
 NS_IMETHODIMP
 LoadInfo::GetTainting(uint32_t* aTaintingOut)
 {
diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h
index 91e5b6559748..6ccb35b02f28 100644
--- a/netwerk/base/LoadInfo.h
+++ b/netwerk/base/LoadInfo.h
@@ -104,7 +104,9 @@ private:
            nsTArray>& aRedirectChain,
            const nsTArray& aUnsafeHeaders,
            bool aForcePreflight,
-           bool aIsPreflight);
+           bool aIsPreflight,
+           bool aForceHSTSPriming,
+           bool aMixedContentWouldBlock);
   LoadInfo(const LoadInfo& rhs);
 
   friend nsresult
@@ -145,6 +147,9 @@ private:
   nsTArray              mCorsUnsafeHeaders;
   bool                             mForcePreflight;
   bool                             mIsPreflight;
+
+  bool                             mForceHSTSPriming : 1;
+  bool                             mMixedContentWouldBlock : 1;
 };
 
 } // namespace net
diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl
index 7b10d4c611f6..d0b42a8e5724 100644
--- a/netwerk/base/nsILoadInfo.idl
+++ b/netwerk/base/nsILoadInfo.idl
@@ -541,6 +541,32 @@ interface nsILoadInfo : nsISupports
    */
   [infallible] readonly attribute boolean isPreflight;
 
+  /**
+   * When this request would be mixed-content and we do not have an
+   * entry in the HSTS cache, we send an HSTS priming request to
+   * determine if it is ok to upgrade the request to HTTPS.
+   */
+  /**
+   * True if this is a mixed-content load and HSTS priming request will be sent.
+   */
+  [noscript, infallible] readonly attribute boolean forceHSTSPriming;
+  /**
+   * Carry the decision whether this load would be blocked by mixed content so
+   * that if HSTS priming fails, the correct decision can be made.
+   */
+  [noscript, infallible] readonly attribute boolean mixedContentWouldBlock;
+
+  /**
+   * Mark this LoadInfo as needing HSTS Priming
+   *
+   * @param wouldBlock Carry the decision of Mixed Content Blocking to be
+   * applied when HSTS priming is complete.
+   */
+  [noscript, notxpcom, nostdcall]
+  void setHSTSPriming(in boolean mixeContentWouldBlock);
+  [noscript, notxpcom, nostdcall]
+  void clearHSTSPriming();
+
   /**
   * Constants reflecting the channel tainting.  These are mainly defined here
   * for script.  Internal C++ code should use the enum defined in LoadTainting.h.
diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp
index 50b57d59419c..d69ade341695 100644
--- a/netwerk/base/nsNetUtil.cpp
+++ b/netwerk/base/nsNetUtil.cpp
@@ -2339,7 +2339,7 @@ NS_ShouldSecureUpgrade(nsIURI* aURI,
     bool isStsHost = false;
     uint32_t flags = aPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0;
     rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, flags,
-                          &isStsHost);
+                          nullptr, &isStsHost);
 
     // if the SSS check fails, it's likely because this load is on a
     // malformed URI or something else in the setup is wrong, so any error
diff --git a/netwerk/base/security-prefs.js b/netwerk/base/security-prefs.js
index c47f351fcfaa..0fd640a0ca36 100644
--- a/netwerk/base/security-prefs.js
+++ b/netwerk/base/security-prefs.js
@@ -97,3 +97,15 @@ pref("security.ssl.errorReporting.automatic", false);
 // blacking themselves out by setting a bad pin.  (60 days by default)
 // https://tools.ietf.org/html/rfc7469#section-4.1
 pref("security.cert_pinning.max_max_age_seconds", 5184000);
+
+// If a request is mixed-content, send an HSTS priming request to attempt to
+// see if it is available over HTTPS.
+pref("security.mixed_content.send_hsts_priming", true);
+#ifdef RELEASE_BUILD
+// Don't change the order of evaluation of mixed-content and HSTS upgrades
+pref("security.mixed_content.use_hsts", false);
+#else
+// Change the order of evaluation so HSTS upgrades happen before
+// mixed-content blocking
+pref("security.mixed_content.use_hsts", true);
+#endif
diff --git a/netwerk/ipc/NeckoChannelParams.ipdlh b/netwerk/ipc/NeckoChannelParams.ipdlh
index 982d39349c7c..1c500aa0a381 100644
--- a/netwerk/ipc/NeckoChannelParams.ipdlh
+++ b/netwerk/ipc/NeckoChannelParams.ipdlh
@@ -49,6 +49,8 @@ struct LoadInfoArgs
   nsCString[]           corsUnsafeHeaders;
   bool                  forcePreflight;
   bool                  isPreflight;
+  bool                  forceHSTSPriming;
+  bool                  mixedContentWouldBlock;
 };
 
 /**
diff --git a/netwerk/protocol/http/HSTSPrimerListener.cpp b/netwerk/protocol/http/HSTSPrimerListener.cpp
new file mode 100644
index 000000000000..83c29fe47595
--- /dev/null
+++ b/netwerk/protocol/http/HSTSPrimerListener.cpp
@@ -0,0 +1,249 @@
+/* -*- 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 "nsHttp.h"
+
+#include "HSTSPrimerListener.h"
+#include "nsIHstsPrimingCallback.h"
+#include "nsIPrincipal.h"
+#include "nsSecurityHeaderParser.h"
+#include "nsISiteSecurityService.h"
+#include "nsISocketProvider.h"
+#include "nsISSLStatus.h"
+#include "nsISSLStatusProvider.h"
+#include "nsStreamUtils.h"
+#include "nsHttpChannel.h"
+#include "LoadInfo.h"
+
+namespace mozilla {
+namespace net {
+
+using namespace mozilla;
+
+NS_IMPL_ISUPPORTS(HSTSPrimingListener, nsIStreamListener,
+                  nsIRequestObserver, nsIInterfaceRequestor)
+
+NS_IMETHODIMP
+HSTSPrimingListener::GetInterface(const nsIID & aIID, void **aResult)
+{
+  return QueryInterface(aIID, aResult);
+}
+
+NS_IMETHODIMP
+HSTSPrimingListener::OnStartRequest(nsIRequest *aRequest,
+                                   nsISupports *aContext)
+{
+  nsresult rv = CheckHSTSPrimingRequestStatus(aRequest);
+  nsCOMPtr callback(mCallback);
+  mCallback = nullptr;
+
+  if (NS_FAILED(rv)) {
+    LOG(("HSTS Priming Failed (request was not approved)"));
+    return callback->OnHSTSPrimingFailed(rv, false);
+  }
+
+  LOG(("HSTS Priming Succeeded (request was approved)"));
+  return callback->OnHSTSPrimingSucceeded(false);
+}
+
+NS_IMETHODIMP
+HSTSPrimingListener::OnStopRequest(nsIRequest *aRequest,
+                                   nsISupports *aContext,
+                                   nsresult aStatus)
+{
+  return NS_OK;
+}
+
+nsresult
+HSTSPrimingListener::CheckHSTSPrimingRequestStatus(nsIRequest* aRequest)
+{
+  nsresult status;
+  nsresult rv = aRequest->GetStatus(&status);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (NS_FAILED(status)) {
+    return NS_ERROR_CONTENT_BLOCKED;
+  }
+
+  // Test that things worked on a HTTP level
+  nsCOMPtr httpChannel = do_QueryInterface(aRequest);
+  NS_ENSURE_STATE(httpChannel);
+  nsCOMPtr internal = do_QueryInterface(aRequest);
+  NS_ENSURE_STATE(internal);
+
+  bool succeedded;
+  rv = httpChannel->GetRequestSucceeded(&succeedded);
+  if (NS_FAILED(rv) || !succeedded) {
+    // If the request did not return a 2XX response, don't process it
+    return NS_ERROR_CONTENT_BLOCKED;
+  }
+
+  bool synthesized = false;
+  nsHttpChannel* rawHttpChannel = static_cast(httpChannel.get());
+  rv = rawHttpChannel->GetResponseSynthesized(&synthesized);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (synthesized) {
+    // Don't consider synthesized responses
+    return NS_ERROR_CONTENT_BLOCKED;
+  }
+
+  // check to see if the HSTS cache was updated
+  nsCOMPtr sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr uri;
+  rv = httpChannel->GetURI(getter_AddRefs(uri));
+  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_TRUE(uri, NS_ERROR_CONTENT_BLOCKED);
+
+  bool hsts;
+  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, 0, nullptr, &hsts);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (hsts) {
+    // An HSTS upgrade was found
+    return NS_OK;
+  }
+
+  // There is no HSTS upgrade available
+  return NS_ERROR_CONTENT_BLOCKED;
+}
+
+/** nsIStreamListener methods **/
+
+NS_IMETHODIMP
+HSTSPrimingListener::OnDataAvailable(nsIRequest *aRequest,
+                                     nsISupports *ctxt,
+                                     nsIInputStream *inStr,
+                                     uint64_t sourceOffset,
+                                     uint32_t count)
+{
+  uint32_t totalRead;
+  return inStr->ReadSegments(NS_DiscardSegment, nullptr, count, &totalRead);
+}
+
+// static
+nsresult
+HSTSPrimingListener::StartHSTSPriming(nsIChannel* aRequestChannel,
+                                      nsIHstsPrimingCallback* aCallback)
+{
+
+  nsCOMPtr finalChannelURI;
+  nsresult rv = NS_GetFinalChannelURI(aRequestChannel, getter_AddRefs(finalChannelURI));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr uri;
+  rv = finalChannelURI->Clone(getter_AddRefs(uri));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = uri->SetScheme(NS_LITERAL_CSTRING("https"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // check the HSTS cache
+  bool hsts;
+  bool cached;
+  nsCOMPtr sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, 0, &cached, &hsts);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (hsts) {
+    // already saw this host and will upgrade if allowed by preferences
+    return aCallback->OnHSTSPrimingSucceeded(true);
+  }
+
+  if (cached) {
+    // there is a non-expired entry in the cache that doesn't allow us to
+    // upgrade, so go ahead and fail early.
+    return aCallback->OnHSTSPrimingFailed(NS_ERROR_CONTENT_BLOCKED, true);
+  }
+
+  // Either it wasn't cached or the cached result has expired. Build a
+  // channel for the HEAD request.
+
+  nsCOMPtr originalLoadInfo = aRequestChannel->GetLoadInfo();
+  MOZ_ASSERT(originalLoadInfo, "can not perform HSTS priming without a loadInfo");
+  if (!originalLoadInfo) {
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr loadInfo = static_cast
+    (originalLoadInfo.get())->CloneForNewRequest();
+
+  nsCOMPtr loadGroup;
+  rv = aRequestChannel->GetLoadGroup(getter_AddRefs(loadGroup));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsLoadFlags loadFlags;
+  rv = aRequestChannel->GetLoadFlags(&loadFlags);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  loadFlags &= HttpBaseChannel::INHIBIT_CACHING |
+               HttpBaseChannel::INHIBIT_PERSISTENT_CACHING |
+               HttpBaseChannel::LOAD_BYPASS_CACHE |
+               HttpBaseChannel::LOAD_FROM_CACHE |
+               HttpBaseChannel::VALIDATE_ALWAYS;
+  // Priming requests should never be intercepted by service workers and
+  // are always anonymous.
+  loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER |
+               nsIRequest::LOAD_ANONYMOUS;
+
+  // Create a new channel to send the priming request
+  nsCOMPtr primingChannel;
+  rv = NS_NewChannelInternal(getter_AddRefs(primingChannel),
+                             uri,
+                             loadInfo,
+                             loadGroup,
+                             nullptr,   // aCallbacks are set later
+                             loadFlags);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Set method and headers
+  nsCOMPtr httpChannel = do_QueryInterface(primingChannel);
+  if (!httpChannel) {
+    NS_ERROR("HSTSPrimingListener: Failed to QI to nsIHttpChannel!");
+    return NS_ERROR_FAILURE;
+  }
+
+  // Currently using HEAD per the draft, but under discussion to change to GET
+  // with credentials so if the upgrade is approved the result is already cached.
+  rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("HEAD"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = httpChannel->
+    SetRequestHeader(NS_LITERAL_CSTRING("Upgrade-Insecure-Requests"),
+                     NS_LITERAL_CSTRING("1"), false);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // attempt to set the class of service flags on the new channel
+  nsCOMPtr requestClass = do_QueryInterface(aRequestChannel);
+  if (!requestClass) {
+    NS_ERROR("HSTSPrimingListener: aRequestChannel is not an nsIClassOfService");
+    return NS_ERROR_FAILURE;
+  }
+  nsCOMPtr primingClass = do_QueryInterface(httpChannel);
+  if (!primingClass) {
+    NS_ERROR("HSTSPrimingListener: aRequestChannel is not an nsIClassOfService");
+    return NS_ERROR_FAILURE;
+  }
+  
+  uint32_t classFlags = 0;
+  rv = requestClass ->GetClassFlags(&classFlags);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = primingClass->SetClassFlags(classFlags);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Set up listener which will start the original channel
+  RefPtr primingListener =
+    new HSTSPrimingListener(aCallback);
+
+  // Start priming
+  rv = primingChannel->AsyncOpen2(primingListener);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+} // namespace net
+} // namespace mozilla
diff --git a/netwerk/protocol/http/HSTSPrimerListener.h b/netwerk/protocol/http/HSTSPrimerListener.h
new file mode 100644
index 000000000000..8ef1109f5564
--- /dev/null
+++ b/netwerk/protocol/http/HSTSPrimerListener.h
@@ -0,0 +1,108 @@
+/* -*- 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/. */
+
+#ifndef HSTSPrimingListener_h__
+#define HSTSPrimingListener_h__
+
+#include "nsCOMPtr.h"
+#include "nsIChannelEventSink.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIStreamListener.h"
+#include "nsIThreadRetargetableStreamListener.h"
+
+#include "mozilla/Attributes.h"
+
+class nsIPrincipal;
+class nsINetworkInterceptController;
+class nsIHstsPrimingCallback;
+
+namespace mozilla {
+namespace net {
+
+class HttpChannelParent;
+class nsHttpChannel;
+
+/*
+ * How often do we get back an HSTS priming result which upgrades the connection to HTTPS?
+ */
+enum HSTSPrimingResult {
+  // This site has been seen before and won't be upgraded
+  eHSTS_PRIMING_CACHED_NO_UPGRADE = 0,
+  // This site has been seen before and will be upgraded
+  eHSTS_PRIMING_CACHED_DO_UPGRADE = 1,
+  // This site has been seen before and will be blocked
+  eHSTS_PRIMING_CACHED_BLOCK      = 2,
+  // The request was already upgraded, probably through
+  // upgrade-insecure-requests
+  eHSTS_PRIMING_ALREADY_UPGRADED  = 3,
+  // HSTS priming is successful and the connection will be upgraded to HTTPS
+  eHSTS_PRIMING_SUCCEEDED         = 4,
+  // When priming succeeds, but preferences require preservation of the order
+  // of mixed-content and hsts, and mixed-content blocks the load
+  eHSTS_PRIMING_SUCCEEDED_BLOCK   = 5,
+  // When priming succeeds, but preferences require preservation of the order
+  // of mixed-content and hsts, and mixed-content allows the load over http
+  eHSTS_PRIMING_SUCCEEDED_HTTP    = 6,
+  // HSTS priming failed, and the load is blocked by mixed-content
+  eHSTS_PRIMING_FAILED_BLOCK      = 7,
+  // HSTS priming failed, and the load is allowed by mixed-content
+  eHSTS_PRIMING_FAILED_ACCEPT     = 8
+};
+
+//////////////////////////////////////////////////////////////////////////
+// Class used as streamlistener and notification callback when
+// doing the HEAD request for an HSTS Priming check. Needs to be an
+// nsIStreamListener in order to receive events from AsyncOpen2
+class HSTSPrimingListener final : public nsIStreamListener,
+                                  public nsIInterfaceRequestor
+{
+public:
+  HSTSPrimingListener(nsIHstsPrimingCallback* aCallback)
+   : mCallback(aCallback)
+  {
+  }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISTREAMLISTENER
+  NS_DECL_NSIREQUESTOBSERVER
+  NS_DECL_NSIINTERFACEREQUESTOR
+
+private:
+  ~HSTSPrimingListener() {}
+
+  // Only nsHttpChannel can invoke HSTS priming
+  friend class mozilla::net::nsHttpChannel;
+
+  /**
+   * Start the HSTS priming request. This will send an anonymous HEAD request to
+   * the URI aRequestChannel is attempting to load. On success, the new HSTS
+   * priming channel is allocated in aHSTSPrimingChannel.
+   *
+   * @param aRequestChannel the reference channel used to initialze the HSTS
+   *        priming channel
+   * @param aCallback the callback stored to handle the results of HSTS priming.
+   * @param aHSTSPrimingChannel if the new HSTS priming channel is allocated
+   *        successfully, it will be placed here.
+   */
+  static nsresult StartHSTSPriming(nsIChannel* aRequestChannel,
+                                   nsIHstsPrimingCallback* aCallback);
+
+  /**
+   * Given a request, return NS_OK if it has resulted in a cached HSTS update.
+   * We don't need to check for the header as that has already been done for us.
+   */
+  nsresult CheckHSTSPrimingRequestStatus(nsIRequest* aRequest);
+
+  /**
+   * the nsIHttpChannel to notify with the result of HSTS priming.
+   */
+  nsCOMPtr mCallback;
+};
+
+
+}} // mozilla::net
+
+#endif // HSTSPrimingListener_h__
diff --git a/netwerk/protocol/http/moz.build b/netwerk/protocol/http/moz.build
index 89bd6cdd9774..47c99fd9656b 100644
--- a/netwerk/protocol/http/moz.build
+++ b/netwerk/protocol/http/moz.build
@@ -5,6 +5,7 @@
 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 XPIDL_SOURCES += [
+    'nsIHstsPrimingCallback.idl',
     'nsIHttpActivityObserver.idl',
     'nsIHttpAuthenticableChannel.idl',
     'nsIHttpAuthenticator.idl',
@@ -54,6 +55,7 @@ SOURCES += [
 UNIFIED_SOURCES += [
     'CacheControlParser.cpp',
     'ConnectionDiagnostics.cpp',
+    'HSTSPrimerListener.cpp',
     'Http2Compression.cpp',
     'Http2Push.cpp',
     'Http2Session.cpp',
diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp
index 9c653ed3d3b6..e38136a28644 100644
--- a/netwerk/protocol/http/nsHttpChannel.cpp
+++ b/netwerk/protocol/http/nsHttpChannel.cpp
@@ -98,6 +98,8 @@
 #include "nsISocketProvider.h"
 #include "mozilla/net/Predictor.h"
 #include "CacheControlParser.h"
+#include "nsMixedContentBlocker.h"
+#include "HSTSPrimerListener.h"
 
 namespace mozilla { namespace net {
 
@@ -405,12 +407,50 @@ nsHttpChannel::Connect()
         // otherwise, let's just proceed without using the cache.
     }
 
+    return TryHSTSPriming();
+}
+
+nsresult
+nsHttpChannel::TryHSTSPriming()
+{
+    if (mLoadInfo) {
+        // HSTS priming requires the LoadInfo provided with AsyncOpen2
+        bool requireHSTSPriming =
+            mLoadInfo->GetForceHSTSPriming();
+
+        if (requireHSTSPriming &&
+                nsMixedContentBlocker::sSendHSTSPriming &&
+                mInterceptCache == DO_NOT_INTERCEPT) {
+            bool isHttpsScheme;
+            nsresult rv = mURI->SchemeIs("https", &isHttpsScheme);
+            NS_ENSURE_SUCCESS(rv, rv);
+            if (!isHttpsScheme) {
+                rv = HSTSPrimingListener::StartHSTSPriming(this, this);
+
+                if (NS_FAILED(rv)) {
+                    CloseCacheEntry(false);
+                    return rv;
+                }
+
+                return NS_OK;
+            }
+
+            // The request was already upgraded, for example by
+            // upgrade-insecure-requests or a prior successful priming request
+            Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
+                    HSTSPrimingResult::eHSTS_PRIMING_ALREADY_UPGRADED);
+            mLoadInfo->ClearHSTSPriming();
+        }
+    }
+
     return ContinueConnect();
 }
 
 nsresult
 nsHttpChannel::ContinueConnect()
 {
+    // If we have had HSTS priming, we need to reevaluate whether we need
+    // a CORS preflight. Bug: 1272440
     // If we need to start a CORS preflight, do it now!
     // Note that it is important to do this before the early returns below.
     if (!mIsCorsPreflightDone && mRequireCORSPreflight &&
@@ -4018,7 +4058,7 @@ nsHttpChannel::OnCacheEntryAvailableInternal(nsICacheEntry *entry,
         return NS_OK;
     }
 
-    return ContinueConnect();
+    return TryHSTSPriming();
 }
 
 nsresult
@@ -5358,6 +5398,7 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel)
     NS_INTERFACE_MAP_ENTRY(nsIDNSListener)
     NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     NS_INTERFACE_MAP_ENTRY(nsICorsPreflightCallback)
+    NS_INTERFACE_MAP_ENTRY(nsIHstsPrimingCallback)
     NS_INTERFACE_MAP_ENTRY(nsIChannelWithDivertableParentListener)
     // we have no macro that covers this case.
     if (aIID.Equals(NS_GET_IID(nsHttpChannel)) ) {
@@ -7678,6 +7719,103 @@ nsHttpChannel::OnPreflightFailed(nsresult aError)
     return NS_OK;
 }
 
+//-----------------------------------------------------------------------------
+// nsIHstsPrimingCallback functions
+//-----------------------------------------------------------------------------
+
+/*
+ * May be invoked synchronously if HSTS priming has already been performed
+ * for the host.
+ */
+NS_IMETHODIMP
+nsHttpChannel::OnHSTSPrimingSucceeded(bool aCached)
+{
+    if (nsMixedContentBlocker::sUseHSTS) {
+        // redirect the channel to HTTPS if the pref
+        // "security.mixed_content.use_hsts" is true
+        LOG(("HSTS Priming succeeded, redirecting to HTTPS [this=%p]", this));
+        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
+                (aCached) ? HSTSPrimingResult::eHSTS_PRIMING_CACHED_DO_UPGRADE :
+                            HSTSPrimingResult::eHSTS_PRIMING_SUCCEEDED);
+        return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps);
+    }
+
+    // If "security.mixed_content.use_hsts" is false, record the result of
+    // HSTS priming and block or proceed with the load as required by
+    // mixed-content blocking
+    bool wouldBlock = mLoadInfo->GetMixedContentWouldBlock();
+
+    // preserve the mixed-content-before-hsts order and block if required
+    if (wouldBlock) {
+        LOG(("HSTS Priming succeeded, blocking for mixed-content [this=%p]",
+                    this));
+        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
+                              HSTSPrimingResult::eHSTS_PRIMING_SUCCEEDED_BLOCK);
+        CloseCacheEntry(false);
+        return AsyncAbort(NS_ERROR_CONTENT_BLOCKED);
+    }
+
+    LOG(("HSTS Priming succeeded, loading insecure: [this=%p]", this));
+    Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
+                          HSTSPrimingResult::eHSTS_PRIMING_SUCCEEDED_HTTP);
+
+    nsresult rv = ContinueConnect();
+    if (NS_FAILED(rv)) {
+        CloseCacheEntry(false);
+        return AsyncAbort(rv);
+    }
+
+    return NS_OK;
+}
+
+/*
+ * May be invoked synchronously if HSTS priming has already been performed
+ * for the host.
+ */
+NS_IMETHODIMP
+nsHttpChannel::OnHSTSPrimingFailed(nsresult aError, bool aCached)
+{
+    bool wouldBlock = mLoadInfo->GetMixedContentWouldBlock();
+
+    LOG(("HSTS Priming Failed [this=%p], %s the load", this,
+                (wouldBlock) ? "blocking" : "allowing"));
+    if (aCached) {
+        // Between the time we marked for priming and started the priming request,
+        // the host was found to not allow the upgrade, probably from another
+        // priming request.
+        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
+                (wouldBlock) ?  HSTSPrimingResult::eHSTS_PRIMING_CACHED_BLOCK :
+                                HSTSPrimingResult::eHSTS_PRIMING_CACHED_NO_UPGRADE);
+    } else {
+        // A priming request was sent, and no HSTS header was found that allows
+        // the upgrade.
+        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT,
+                (wouldBlock) ?  HSTSPrimingResult::eHSTS_PRIMING_FAILED_BLOCK :
+                                HSTSPrimingResult::eHSTS_PRIMING_FAILED_ACCEPT);
+    }
+
+    // Don't visit again for at least one day
+    nsISiteSecurityService* sss = gHttpHandler->GetSSService();
+    NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY);
+    nsresult rv = sss->CacheNegativeHSTSResult(mURI, 24 * 60 * 60);
+    NS_WARN_IF(NS_FAILED(rv));
+
+    // If we would block, go ahead and abort with the error provided
+    if (wouldBlock) {
+        CloseCacheEntry(false);
+        return AsyncAbort(aError);
+    }
+
+    // we can continue the load and the UI has been updated as mixed content
+    rv = ContinueConnect();
+    if (NS_FAILED(rv)) {
+        CloseCacheEntry(false);
+        return AsyncAbort(rv);
+    }
+
+    return NS_OK;
+}
+
 //-----------------------------------------------------------------------------
 // AChannelHasDivertableParentChannelAsListener internal functions
 //-----------------------------------------------------------------------------
diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h
index 4f317f41cbf8..3b5ce48d45c4 100644
--- a/netwerk/protocol/http/nsHttpChannel.h
+++ b/netwerk/protocol/http/nsHttpChannel.h
@@ -27,6 +27,7 @@
 #include "nsIStreamListener.h"
 #include "nsISupportsPrimitives.h"
 #include "nsICorsPreflightCallback.h"
+#include "nsIHstsPrimingCallback.h"
 
 class nsDNSPrefetch;
 class nsICancelable;
@@ -74,6 +75,7 @@ class nsHttpChannel final : public HttpBaseChannel
                           , public nsSupportsWeakReference
                           , public nsICorsPreflightCallback
                           , public nsIChannelWithDivertableParentListener
+                          , public nsIHstsPrimingCallback
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
@@ -89,6 +91,7 @@ public:
     NS_DECL_NSIAPPLICATIONCACHECONTAINER
     NS_DECL_NSIAPPLICATIONCACHECHANNEL
     NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
+    NS_DECL_NSIHSTSPRIMINGCALLBACK
     NS_DECL_NSITHREADRETARGETABLEREQUEST
     NS_DECL_NSIDNSLISTENER
     NS_DECL_NSICHANNELWITHDIVERTABLEPARENTLISTENER
@@ -203,6 +206,9 @@ public: /* internal necko use only */
     nsresult OpenCacheEntry(bool usingSSL);
     nsresult ContinueConnect();
 
+    // If the load is mixed-content, build and send an HSTS priming request.
+    nsresult TryHSTSPriming();
+
     nsresult StartRedirectChannelToURI(nsIURI *, uint32_t);
 
     // This allows cache entry to be marked as foreign even after channel itself
diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp
index 9fcd8cbc2fcb..181dffb31e8e 100644
--- a/netwerk/protocol/http/nsHttpHandler.cpp
+++ b/netwerk/protocol/http/nsHttpHandler.cpp
@@ -2244,7 +2244,8 @@ nsHttpHandler::SpeculativeConnectInternal(nsIURI *aURI,
         flags |= nsISocketProvider::NO_PERMANENT_STORAGE;
     nsCOMPtr clone;
     if (NS_SUCCEEDED(sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS,
-                                      aURI, flags, &isStsHost)) && isStsHost) {
+                                      aURI, flags, nullptr, &isStsHost)) &&
+                                      isStsHost) {
         if (NS_SUCCEEDED(NS_GetSecureUpgradedURI(aURI,
                                                  getter_AddRefs(clone)))) {
             aURI = clone.get();
diff --git a/netwerk/protocol/http/nsIHstsPrimingCallback.idl b/netwerk/protocol/http/nsIHstsPrimingCallback.idl
new file mode 100644
index 000000000000..0e45901738c7
--- /dev/null
+++ b/netwerk/protocol/http/nsIHstsPrimingCallback.idl
@@ -0,0 +1,50 @@
+/* -*- 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 "nsISupports.idl"
+
+/**
+ * HSTS priming attempts to prevent mixed-content by looking for the
+ * Strict-Transport-Security header as a signal from the server that it is
+ * safe to upgrade HTTP to HTTPS.
+ *
+ * Since mixed-content blocking happens very early in the process in AsyncOpen2,
+ * the status of mixed-content blocking is stored in the LoadInfo and then used
+ * to determine whether to send a priming request or not.
+ *
+ * This interface is implemented by nsHttpChannel so that it can receive the
+ * result of HSTS priming.
+ */
+[builtinclass, uuid(eca6daca-3f2a-4a2a-b3bf-9f24f79bc999)]
+interface nsIHstsPrimingCallback : nsISupports
+{
+  /**
+   * HSTS priming has succeeded with an STS header, and the site asserts it is
+   * safe to upgrade the request from HTTP to HTTPS. The request may still be
+   * blocked based on the user's preferences.
+   *
+   * May be invoked synchronously if HSTS priming has already been performed
+   * for the host.
+   *
+   * @param aCached whether the result was already in the HSTS cache
+   */
+  [noscript, nostdcall]
+  void onHSTSPrimingSucceeded(in bool aCached);
+  /**
+   * HSTS priming has seen no STS header, the request itself has failed,
+   * or some other failure which does not constitute a positive signal that the
+   * site can be upgraded safely to HTTPS. The request may still be allowed
+   * based on the user's preferences.
+   *
+   * May be invoked synchronously if HSTS priming has already been performed
+   * for the host.
+   *
+   * param aError The error which caused this failure, or NS_ERROR_CONTENT_BLOCKED
+   * @param aCached whether the result was already in the HSTS cache
+   */
+  [noscript, nostdcall]
+  void onHSTSPrimingFailed(in nsresult aError, in bool aCached);
+};
diff --git a/security/manager/ssl/SSLServerCertVerification.cpp b/security/manager/ssl/SSLServerCertVerification.cpp
index 794efc244bea..22d20ae99edd 100644
--- a/security/manager/ssl/SSLServerCertVerification.cpp
+++ b/security/manager/ssl/SSLServerCertVerification.cpp
@@ -506,6 +506,7 @@ CertErrorRunnable::CheckCertOverrides()
   nsresult nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HSTS,
                                     mInfoObject->GetHostNameRaw(),
                                     mProviderFlags,
+                                    nullptr,
                                     &strictTransportSecurityEnabled);
   if (NS_FAILED(nsrv)) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
@@ -516,6 +517,7 @@ CertErrorRunnable::CheckCertOverrides()
   nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HPKP,
                            mInfoObject->GetHostNameRaw(),
                            mProviderFlags,
+                           nullptr,
                            &hasPinningInformation);
   if (NS_FAILED(nsrv)) {
     MOZ_LOG(gPIPNSSLog, LogLevel::Debug,
diff --git a/security/manager/ssl/nsISiteSecurityService.idl b/security/manager/ssl/nsISiteSecurityService.idl
index 0eca3041ad47..a1ebcd40ead8 100644
--- a/security/manager/ssl/nsISiteSecurityService.idl
+++ b/security/manager/ssl/nsISiteSecurityService.idl
@@ -115,10 +115,13 @@ interface nsISiteSecurityService : nsISupports
      * @param aHost the hostname (punycode) to query for state.
      * @param aFlags  options for this request as defined in nsISocketProvider:
      *                  NO_PERMANENT_STORAGE
+     * @param aCached true if we have cached information regarding whether or not
+     *                  the host is HSTS, false otherwise.
      */
     boolean isSecureHost(in uint32_t aType,
                          in string aHost,
-                         in uint32_t aFlags);
+                         in uint32_t aFlags,
+                         [optional] out boolean aCached);
 
     /**
      * Checks whether or not the URI's hostname has a given security state set.
@@ -133,8 +136,11 @@ interface nsISiteSecurityService : nsISupports
      * @param aURI the URI to query for STS state.
      * @param aFlags  options for this request as defined in nsISocketProvider:
      *                  NO_PERMANENT_STORAGE
+     * @param aCached true if we have cached information regarding whether or not
+     *                  the host is HSTS, false otherwise.
      */
-    boolean isSecureURI(in uint32_t aType, in nsIURI aURI, in uint32_t aFlags);
+    boolean isSecureURI(in uint32_t aType, in nsIURI aURI, in uint32_t aFlags,
+                        [optional] out boolean aCached);
 
     /**
      * Removes all security state by resetting to factory-original settings.
@@ -174,6 +180,14 @@ interface nsISiteSecurityService : nsISupports
                         in unsigned long aMaxAge, in unsigned long aPinCount,
                         [array, size_is(aPinCount)] in string aSha256Pins);
 
+    /**
+     * Mark a host as declining to provide a given security state so that features
+     * such as HSTS priming will not flood a server with requests.
+     *
+     * @param aHost the hostname (punycode) that this applies to
+     * @param aMaxAge lifetime (in seconds) of this negative cache
+     */
+    [noscript] void cacheNegativeHSTSResult(in nsIURI aURI, in unsigned long long aMaxAge);
 };
 
 %{C++
diff --git a/security/manager/ssl/nsSiteSecurityService.cpp b/security/manager/ssl/nsSiteSecurityService.cpp
index b3df457ff52e..c8a4635536af 100644
--- a/security/manager/ssl/nsSiteSecurityService.cpp
+++ b/security/manager/ssl/nsSiteSecurityService.cpp
@@ -314,7 +314,8 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
                                     nsIURI* aSourceURI,
                                     int64_t maxage,
                                     bool includeSubdomains,
-                                    uint32_t flags)
+                                    uint32_t flags,
+                                    SecurityPropertyState aHSTSState)
 {
   // If max-age is zero, that's an indication to immediately remove the
   // security state, so here's a shortcut.
@@ -322,8 +323,12 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
     return RemoveState(aType, aSourceURI, flags);
   }
 
+  MOZ_ASSERT((aHSTSState == SecurityPropertySet
+              || aHSTSState == SecurityPropertyNegative),
+      "HSTS State must be SecurityPropertySet or SecurityPropertyNegative");
+
   int64_t expiretime = ExpireTimeFromMaxAge(maxage);
-  SiteHSTSState siteState(expiretime, SecurityPropertySet, includeSubdomains);
+  SiteHSTSState siteState(expiretime, aHSTSState, includeSubdomains);
   nsAutoCString stateString;
   siteState.ToString(stateString);
   nsAutoCString hostname;
@@ -342,6 +347,14 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType,
   return NS_OK;
 }
 
+NS_IMETHODIMP
+nsSiteSecurityService::CacheNegativeHSTSResult(nsIURI* aSourceURI,
+                                               uint64_t aMaxAge)
+{
+  return SetHSTSState(nsISiteSecurityService::HEADER_HSTS, aSourceURI,
+                      aMaxAge, false, 0, SecurityPropertyNegative);
+}
+
 NS_IMETHODIMP
 nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI,
                                    uint32_t aFlags)
@@ -864,7 +877,7 @@ nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI,
 
   // record the successfully parsed header data.
   nsresult rv = SetHSTSState(aType, aSourceURI, maxAge, foundIncludeSubdomains,
-                             aFlags);
+                             aFlags, SecurityPropertySet);
   if (NS_FAILED(rv)) {
     SSSLOG(("SSS: failed to set STS state"));
     if (aFailureResult) {
@@ -888,7 +901,8 @@ nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI,
 
 NS_IMETHODIMP
 nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI,
-                                   uint32_t aFlags, bool* aResult)
+                                   uint32_t aFlags, bool* aCached,
+                                   bool* aResult)
 {
    // Child processes are not allowed direct access to this.
    if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
@@ -912,7 +926,7 @@ nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI,
     return NS_OK;
   }
 
-  return IsSecureHost(aType, hostname.get(), aFlags, aResult);
+  return IsSecureHost(aType, hostname.get(), aFlags, aCached, aResult);
 }
 
 int STSPreloadCompare(const void *key, const void *entry)
@@ -942,7 +956,8 @@ nsSiteSecurityService::GetPreloadListEntry(const char *aHost)
 
 NS_IMETHODIMP
 nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
-                                    uint32_t aFlags, bool* aResult)
+                                    uint32_t aFlags, bool* aCached,
+                                    bool* aResult)
 {
    // Child processes are not allowed direct access to this.
    if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) {
@@ -959,6 +974,9 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
 
   // set default in case if we can't find any STS information
   *aResult = false;
+  if (aCached) {
+    *aCached = false;
+  }
 
   /* An IP address never qualifies as a secure URI. */
   if (HostIsIPAddress(aHost)) {
@@ -984,6 +1002,9 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
   nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHost));
   if (host.EqualsLiteral("chart.apis.google.com") ||
       StringEndsWith(host, NS_LITERAL_CSTRING(".chart.apis.google.com"))) {
+    if (aCached) {
+      *aCached = true;
+    }
     return NS_OK;
   }
 
@@ -1007,9 +1028,17 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
   if (siteState.mHSTSState != SecurityPropertyUnset) {
     SSSLOG(("Found entry for %s", host.get()));
     bool expired = siteState.IsExpired(aType);
-    if (!expired && siteState.mHSTSState == SecurityPropertySet) {
-      *aResult = true;
-      return NS_OK;
+    if (!expired) {
+      if (aCached) {
+        *aCached = true;
+      }
+      if (siteState.mHSTSState == SecurityPropertySet) {
+        *aResult = true;
+        return NS_OK;
+      } else if (siteState.mHSTSState == SecurityPropertyNegative) {
+        *aResult = false;
+        return NS_OK;
+      }
     }
 
     // If the entry is expired and not in the preload list, we can remove it.
@@ -1022,6 +1051,9 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
   else if (GetPreloadListEntry(host.get())) {
     SSSLOG(("%s is a preloaded STS host", host.get()));
     *aResult = true;
+    if (aCached) {
+      *aCached = true;
+    }
     return NS_OK;
   }
 
@@ -1054,9 +1086,17 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
     if (siteState.mHSTSState != SecurityPropertyUnset) {
       SSSLOG(("Found entry for %s", subdomain));
       bool expired = siteState.IsExpired(aType);
-      if (!expired && siteState.mHSTSState == SecurityPropertySet) {
-        *aResult = siteState.mHSTSIncludeSubdomains;
-        break;
+      if (!expired) {
+        if (aCached) {
+          *aCached = true;
+        }
+        if (siteState.mHSTSState == SecurityPropertySet) {
+          *aResult = siteState.mHSTSIncludeSubdomains;
+          break;
+        } else if (siteState.mHSTSState == SecurityPropertyNegative) {
+          *aResult = false;
+          break;
+        }
       }
 
       // If the entry is expired and not in the preload list, we can remove it.
@@ -1070,6 +1110,9 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost,
       if (preload->mIncludeSubdomains) {
         SSSLOG(("%s is a preloaded STS host", subdomain));
         *aResult = true;
+        if (aCached) {
+          *aCached = true;
+        }
         break;
       }
     }
diff --git a/security/manager/ssl/nsSiteSecurityService.h b/security/manager/ssl/nsSiteSecurityService.h
index cba010917cb6..08396964d642 100644
--- a/security/manager/ssl/nsSiteSecurityService.h
+++ b/security/manager/ssl/nsSiteSecurityService.h
@@ -34,7 +34,8 @@ class nsISSLStatus;
 enum SecurityPropertyState {
   SecurityPropertyUnset = 0,
   SecurityPropertySet = 1,
-  SecurityPropertyKnockout = 2
+  SecurityPropertyKnockout = 2,
+  SecurityPropertyNegative = 3
 };
 
 /**
@@ -128,7 +129,8 @@ protected:
 private:
   nsresult GetHost(nsIURI *aURI, nsACString &aResult);
   nsresult SetHSTSState(uint32_t aType, nsIURI* aSourceURI, int64_t maxage,
-                        bool includeSubdomains, uint32_t flags);
+                        bool includeSubdomains, uint32_t flags,
+                        SecurityPropertyState aHSTSState);
   nsresult ProcessHeaderInternal(uint32_t aType, nsIURI* aSourceURI,
                                  const char* aHeader, nsISSLStatus* aSSLStatus,
                                  uint32_t aFlags, uint64_t* aMaxAge,
diff --git a/testing/specialpowers/content/SpecialPowersObserverAPI.js b/testing/specialpowers/content/SpecialPowersObserverAPI.js
index f2e2d550cfa8..e47c478f871c 100644
--- a/testing/specialpowers/content/SpecialPowersObserverAPI.js
+++ b/testing/specialpowers/content/SpecialPowersObserverAPI.js
@@ -324,10 +324,10 @@ SpecialPowersObserverAPI.prototype = {
           case "BOOL":
             if (aMessage.json.op == "get")
               return(prefs.getBoolPref(prefName));
-            else 
+            else
               return(prefs.setBoolPref(prefName, prefValue));
           case "INT":
-            if (aMessage.json.op == "get") 
+            if (aMessage.json.op == "get")
               return(prefs.getIntPref(prefName));
             else
               return(prefs.setIntPref(prefName, prefValue));
@@ -563,6 +563,7 @@ SpecialPowersObserverAPI.prototype = {
         let sss = Cc["@mozilla.org/ssservice;1"].
                   getService(Ci.nsISiteSecurityService);
         sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, flags);
+        return undefined;
       }
 
       case "SPLoadExtension": {
diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json
index 59b0c454341d..1a37cacfbe5e 100644
--- a/toolkit/components/telemetry/Histograms.json
+++ b/toolkit/components/telemetry/Histograms.json
@@ -7309,6 +7309,22 @@
     "n_values": 10,
     "description": "How often would blocked mixed content be allowed if HSTS upgrades were allowed? 0=display/no-HSTS, 1=display/HSTS, 2=active/no-HSTS, 3=active/HSTS"
   },
+  "MIXED_CONTENT_HSTS_PRIMING": {
+    "alert_emails": ["seceng@mozilla.org"],
+    "bug_numbers": [1246540],
+    "expires_in_version": "60",
+    "kind": "enumerated",
+    "n_values": 16,
+    "description": "How often would blocked mixed content be allowed if HSTS upgrades were allowed, including how often would we send an HSTS priming request? 0=display/no-HSTS, 1=display/HSTS, 2=active/no-HSTS, 3=active/HSTS, 4=display/no-HSTS-priming, 5=display/do-HSTS-priming, 6=active/no-HSTS-priming, 7=active/do-HSTS-priming"
+  },
+  "MIXED_CONTENT_HSTS_PRIMING_RESULT": {
+    "alert_emails": ["seceng@mozilla.org"],
+    "bug_numbers": [1246540],
+    "expires_in_version": "60",
+    "kind": "enumerated",
+    "n_values": 16,
+    "description": "How often do we get back an HSTS priming result which upgrades the connection to HTTPS? 0=cached (no upgrade), 1=cached (do upgrade), 2=cached (blocked), 3=already upgraded, 4=priming succeeded, 5=priming succeeded (block due to pref), 6=priming succeeded (no upgrade due to pref), 7=priming failed (block), 8=priming failed (accept)"
+  },
   "MIXED_CONTENT_OBJECT_SUBREQUEST": {
     "alert_emails": ["seceng@mozilla.org"],
     "bug_numbers": [1244116],

From 3fc0587193a096d91375ea1039d80a995105cf1b Mon Sep 17 00:00:00 2001
From: Phil Bystrican 
Date: Fri, 22 Jul 2016 14:11:14 -0400
Subject: [PATCH 120/135] Bug 1284939 - Removed definition and usage of
 QUIRK_FLASH_AVOID_CGMODE_CRASHES. Adjusted the bit shifts for quirk values
 that fell below it to keep the increment between them consistent. r=spohl

CGBridgeLayer was only ever constructed with aAvoidCGCrashes as false so its property mAvoidCGCrashes was removed and all conditionals that relied on it were removed. This also resulted in protectLastCGContext never doing any work so it was removed as well. r=spohl
---
 dom/plugins/ipc/PluginInstanceChild.cpp |  2 +-
 dom/plugins/ipc/PluginQuirks.cpp        |  1 -
 dom/plugins/ipc/PluginQuirks.h          | 11 ++---
 dom/plugins/ipc/PluginUtilsOSX.h        |  3 +-
 dom/plugins/ipc/PluginUtilsOSX.mm       | 66 ++-----------------------
 5 files changed, 10 insertions(+), 73 deletions(-)

diff --git a/dom/plugins/ipc/PluginInstanceChild.cpp b/dom/plugins/ipc/PluginInstanceChild.cpp
index cacb087a53a3..00aac104d7ae 100644
--- a/dom/plugins/ipc/PluginInstanceChild.cpp
+++ b/dom/plugins/ipc/PluginInstanceChild.cpp
@@ -3529,7 +3529,7 @@ PluginInstanceChild::EnsureCurrentBuffer(void)
         if (mDrawingModel == NPDrawingModelCoreGraphics) {
             if (!mCGLayer) {
                 caLayer = mozilla::plugins::PluginUtilsOSX::GetCGLayer(CallCGDraw,
-                                                                       this, false,
+                                                                       this,
                                                                        mContentsScaleFactor);
 
                 if (!caLayer) {
diff --git a/dom/plugins/ipc/PluginQuirks.cpp b/dom/plugins/ipc/PluginQuirks.cpp
index a6528e661856..74e954bc9b65 100644
--- a/dom/plugins/ipc/PluginQuirks.cpp
+++ b/dom/plugins/ipc/PluginQuirks.cpp
@@ -50,7 +50,6 @@ int GetQuirksFromMimeTypeAndFilename(const nsCString& aMimeType,
     // Whitelist Flash and Quicktime to support offline renderer
     NS_NAMED_LITERAL_CSTRING(quicktime, "QuickTime Plugin.plugin");
     if (specialType == nsPluginHost::eSpecialType_Flash) {
-        quirks |= QUIRK_FLASH_AVOID_CGMODE_CRASHES;
         quirks |= QUIRK_ALLOW_OFFLINE_RENDERER;
     } else if (FindInReadable(quicktime, aPluginFilename)) {
         quirks |= QUIRK_ALLOW_OFFLINE_RENDERER;
diff --git a/dom/plugins/ipc/PluginQuirks.h b/dom/plugins/ipc/PluginQuirks.h
index 8b59066c0dc7..da0a8cb4d313 100644
--- a/dom/plugins/ipc/PluginQuirks.h
+++ b/dom/plugins/ipc/PluginQuirks.h
@@ -47,19 +47,14 @@ enum PluginQuirks {
   // Mac: Allow the plugin to use offline renderer mode.
   // Use this only if the plugin is certified the support the offline renderer.
   QUIRK_ALLOW_OFFLINE_RENDERER                    = 1 << 9,
-  // Mac: Work around a Flash bug that can cause plugin process crashes
-  // in CoreGraphics mode:  The Flash plugin sometimes accesses the
-  // CGContextRef we pass to it in NPP_HandleEvent(NPCocoaEventDrawRect)
-  // outside of that call.  See bug 804606.
-  QUIRK_FLASH_AVOID_CGMODE_CRASHES                = 1 << 10,
   // Work around a Flash bug where it fails to check the error code of a
   // NPN_GetValue(NPNVdocumentOrigin) call before trying to dereference
   // its char* output.
-  QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN        = 1 << 11,
+  QUIRK_FLASH_RETURN_EMPTY_DOCUMENT_ORIGIN        = 1 << 10,
   // Win: Addresses a Unity bug with mouse capture.
-  QUIRK_UNITY_FIXUP_MOUSE_CAPTURE                 = 1 << 12,
+  QUIRK_UNITY_FIXUP_MOUSE_CAPTURE                 = 1 << 11,
   // Win: Hook IMM32 API to handle IME event on windowless plugin
-  QUIRK_WINLESS_HOOK_IME                          = 1 << 13,
+  QUIRK_WINLESS_HOOK_IME                          = 1 << 12,
 };
 
 int GetQuirksFromMimeTypeAndFilename(const nsCString& aMimeType,
diff --git a/dom/plugins/ipc/PluginUtilsOSX.h b/dom/plugins/ipc/PluginUtilsOSX.h
index 7abab1efdbf9..c201782c0f40 100644
--- a/dom/plugins/ipc/PluginUtilsOSX.h
+++ b/dom/plugins/ipc/PluginUtilsOSX.h
@@ -25,8 +25,7 @@ void InvokeNativeEventLoop();
 // Need to call back and send a cocoa draw event to the plugin.
 typedef void (*DrawPluginFunc) (CGContextRef, void*, nsIntRect aUpdateRect);
 
-void* GetCGLayer(DrawPluginFunc aFunc, void* aPluginInstance,
-                 bool aAvoidCGCrashes, double aContentsScaleFactor);
+void* GetCGLayer(DrawPluginFunc aFunc, void* aPluginInstance, double aContentsScaleFactor);
 void ReleaseCGLayer(void* cgLayer);
 void Repaint(void* cgLayer, nsIntRect aRect);
 
diff --git a/dom/plugins/ipc/PluginUtilsOSX.mm b/dom/plugins/ipc/PluginUtilsOSX.mm
index 7a5947f300b2..52dbf5f21165 100644
--- a/dom/plugins/ipc/PluginUtilsOSX.mm
+++ b/dom/plugins/ipc/PluginUtilsOSX.mm
@@ -26,14 +26,10 @@ using namespace mozilla::plugins::PluginUtilsOSX;
   DrawPluginFunc mDrawFunc;
   void* mPluginInstance;
   nsIntRect mUpdateRect;
-  BOOL mAvoidCGCrashes;
-  CGContextRef mLastCGContext;
 }
 - (void)setDrawFunc:(DrawPluginFunc)aFunc
-     pluginInstance:(void*)aPluginInstance
-     avoidCGCrashes:(BOOL)aAvoidCGCrashes;
+     pluginInstance:(void*)aPluginInstance;
 - (void)updateRect:(nsIntRect)aRect;
-- (void)protectLastCGContext;
 
 @end
 
@@ -61,43 +57,9 @@ CGBitmapContextSetDataFunc CGBitmapContextSetDataPtr = NULL;
 
 - (void) setDrawFunc:(DrawPluginFunc)aFunc
       pluginInstance:(void*)aPluginInstance
-      avoidCGCrashes:(BOOL)aAvoidCGCrashes
 {
   mDrawFunc = aFunc;
   mPluginInstance = aPluginInstance;
-  mAvoidCGCrashes = aAvoidCGCrashes;
-  mLastCGContext = nil;
-}
-
-// The Flash plugin, in very unusual circumstances, can (in CoreGraphics
-// mode) try to access the CGContextRef from -[CGBridgeLayer drawInContext:]
-// outside of any call to NPP_HandleEvent(NPCocoaEventDrawRect).  This usually
-// crashes the plugin process (probably because it tries to access deleted
-// memory).  We stop these crashes from happening by holding a reference to
-// the CGContextRef, and also by ensuring that it's data won't get deleted.
-// The CGContextRef won't "work" in this form.  But this won't cause trouble
-// for plugins that do things correctly (that don't access this CGContextRef
-// outside of the call to NPP_HandleEvent() that passes it to the plugin).
-// The OS may reuse this CGContextRef (it may get passed to other calls to
-// -[CGBridgeLayer drawInContext:]).  But before each call the OS calls
-// CGBitmapContextSetData() to replace its data, which undoes the changes
-// we make here.  See bug 804606.
-- (void)protectLastCGContext
-{
-  if (!mAvoidCGCrashes || !mLastCGContext) {
-    return;
-  }
-
-  static char ensuredData[128] = {0};
-
-  if (!CGBitmapContextSetDataPtr) {
-    CGBitmapContextSetDataPtr = (CGBitmapContextSetDataFunc)
-      dlsym(RTLD_DEFAULT, "CGBitmapContextSetData");
-  }
-
-  if (CGBitmapContextSetDataPtr && (GetContextType(mLastCGContext) == CG_CONTEXT_TYPE_BITMAP)) {
-    CGBitmapContextSetDataPtr(mLastCGContext, 0, 0, 1, 1, ensuredData, 8, 32, 64);
-  }
 }
 
 - (void)drawInContext:(CGContextRef)aCGContext
@@ -112,30 +74,14 @@ CGBitmapContextSetDataFunc CGBitmapContextSetDataPtr = NULL;
 
   ::CGContextRestoreGState(aCGContext);
 
-  if (mAvoidCGCrashes) {
-    if (mLastCGContext) {
-      ::CGContextRelease(mLastCGContext);
-    }
-    mLastCGContext = aCGContext;
-    ::CGContextRetain(mLastCGContext);
-  }
-
   mUpdateRect.SetEmpty();
 }
 
-- (void)dealloc
-{
-  if (mLastCGContext) {
-    ::CGContextRelease(mLastCGContext);
-  }
-  [super dealloc];
-}
-
 @end
 
-void* mozilla::plugins::PluginUtilsOSX::GetCGLayer(DrawPluginFunc aFunc, void* aPluginInstance,
-                                                   bool aAvoidCGCrashes, double aContentsScaleFactor)
-{
+void* mozilla::plugins::PluginUtilsOSX::GetCGLayer(DrawPluginFunc aFunc, 
+                                                   void* aPluginInstance, 
+                                                   double aContentsScaleFactor) {
   CGBridgeLayer *bridgeLayer = [[CGBridgeLayer alloc] init];
 
   // We need to make bridgeLayer behave properly when its superlayer changes
@@ -165,8 +111,7 @@ void* mozilla::plugins::PluginUtilsOSX::GetCGLayer(DrawPluginFunc aFunc, void* a
 #endif
 
   [bridgeLayer setDrawFunc:aFunc
-            pluginInstance:aPluginInstance
-            avoidCGCrashes:aAvoidCGCrashes];
+            pluginInstance:aPluginInstance];
   return bridgeLayer;
 }
 
@@ -182,7 +127,6 @@ void mozilla::plugins::PluginUtilsOSX::Repaint(void *caLayer, nsIntRect aRect) {
   [bridgeLayer setNeedsDisplay];
   [bridgeLayer displayIfNeeded];
   [CATransaction commit];
-  [bridgeLayer protectLastCGContext];
 }
 
 @interface EventProcessor : NSObject {

From 0a5622c093cad67542b1241915b7eac86f7c8a94 Mon Sep 17 00:00:00 2001
From: "Carsten \"Tomcat\" Book" 
Date: Sun, 24 Jul 2016 15:59:31 +0200
Subject: [PATCH 121/135] Backed out changeset 640247e978ba (bug 1246540) for
 bustage

---
 docshell/base/nsDocShell.cpp                  |  23 +-
 dom/base/nsIDocument.h                        |  43 +--
 dom/ipc/ContentParent.cpp                     |   6 +-
 dom/ipc/ContentParent.h                       |   3 +-
 dom/ipc/PContent.ipdl                         |   2 +-
 dom/security/moz.build                        |   1 -
 dom/security/nsContentSecurityManager.cpp     |  12 +-
 dom/security/nsMixedContentBlocker.cpp        | 153 +--------
 dom/security/nsMixedContentBlocker.h          |  20 +-
 dom/security/test/hsts/browser.ini            |   9 -
 .../test/hsts/browser_hsts-priming_main.js    | 295 ------------------
 dom/security/test/hsts/file_1x1.png           | Bin 17811 -> 0 bytes
 dom/security/test/hsts/file_priming-top.html  |  84 -----
 dom/security/test/hsts/file_priming.js        |   4 -
 dom/security/test/hsts/file_stylesheet.css    |   0
 dom/security/test/hsts/file_testserver.sjs    |  66 ----
 .../test/mixedcontentblocker/test_main.html   |   3 -
 dom/security/test/moz.build                   |   1 -
 ipc/glue/BackgroundUtils.cpp                  |   9 +-
 netwerk/base/LoadInfo.cpp                     |  40 +--
 netwerk/base/LoadInfo.h                       |   7 +-
 netwerk/base/nsILoadInfo.idl                  |  26 --
 netwerk/base/nsNetUtil.cpp                    |   2 +-
 netwerk/base/security-prefs.js                |  12 -
 netwerk/ipc/NeckoChannelParams.ipdlh          |   2 -
 netwerk/protocol/http/HSTSPrimerListener.cpp  | 249 ---------------
 netwerk/protocol/http/HSTSPrimerListener.h    | 108 -------
 netwerk/protocol/http/moz.build               |   2 -
 netwerk/protocol/http/nsHttpChannel.cpp       | 140 +--------
 netwerk/protocol/http/nsHttpChannel.h         |   6 -
 netwerk/protocol/http/nsHttpHandler.cpp       |   3 +-
 .../protocol/http/nsIHstsPrimingCallback.idl  |  50 ---
 .../manager/ssl/SSLServerCertVerification.cpp |   2 -
 .../manager/ssl/nsISiteSecurityService.idl    |  18 +-
 .../manager/ssl/nsSiteSecurityService.cpp     |  67 +---
 security/manager/ssl/nsSiteSecurityService.h  |   6 +-
 .../content/SpecialPowersObserverAPI.js       |   5 +-
 toolkit/components/telemetry/Histograms.json  |  16 -
 38 files changed, 50 insertions(+), 1445 deletions(-)
 delete mode 100644 dom/security/test/hsts/browser.ini
 delete mode 100644 dom/security/test/hsts/browser_hsts-priming_main.js
 delete mode 100644 dom/security/test/hsts/file_1x1.png
 delete mode 100644 dom/security/test/hsts/file_priming-top.html
 delete mode 100644 dom/security/test/hsts/file_priming.js
 delete mode 100644 dom/security/test/hsts/file_stylesheet.css
 delete mode 100644 dom/security/test/hsts/file_testserver.sjs
 delete mode 100644 netwerk/protocol/http/HSTSPrimerListener.cpp
 delete mode 100644 netwerk/protocol/http/HSTSPrimerListener.h
 delete mode 100644 netwerk/protocol/http/nsIHstsPrimingCallback.idl

diff --git a/docshell/base/nsDocShell.cpp b/docshell/base/nsDocShell.cpp
index 36ed11df7cd6..dc9120edba1f 100644
--- a/docshell/base/nsDocShell.cpp
+++ b/docshell/base/nsDocShell.cpp
@@ -4966,10 +4966,10 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
             do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
           NS_ENSURE_SUCCESS(rv, rv);
           rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI,
-                                flags, nullptr, &isStsHost);
+                                flags, &isStsHost);
           NS_ENSURE_SUCCESS(rv, rv);
           rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HPKP, aURI,
-                                flags, nullptr, &isPinnedHost);
+                                flags, &isPinnedHost);
           NS_ENSURE_SUCCESS(rv, rv);
         } else {
           mozilla::dom::ContentChild* cc =
@@ -9848,25 +9848,6 @@ nsDocShell::InternalLoad(nsIURI* aURI,
     return NS_ERROR_CONTENT_BLOCKED;
   }
 
-  // If HSTS priming was set by nsMixedContentBlocker::ShouldLoad, and we
-  // would block due to mixed content, go ahead and block here. If we try to
-  // proceed with priming, we will error out later on.
-  nsCOMPtr docShell = NS_CP_GetDocShellFromContext(context);
-  NS_ENSURE_TRUE(docShell, NS_OK);
-  if (docShell) {
-    nsIDocument* document = docShell->GetDocument();
-    NS_ENSURE_TRUE(document, NS_OK);
-
-    HSTSPrimingState state = document->GetHSTSPrimingStateForLocation(aURI);
-    if (state == HSTSPrimingState::eHSTS_PRIMING_BLOCK) {
-      // HSTS Priming currently disabled for InternalLoad, so we need to clear
-      // the location that was added by nsMixedContentBlocker::ShouldLoad
-      // Bug 1269815 will address images loaded via InternalLoad
-      document->ClearHSTSPrimingLocation(aURI);
-      return NS_ERROR_CONTENT_BLOCKED;
-    }
-  }
-
   nsCOMPtr owner(aOwner);
   //
   // Get an owner from the current document if necessary.  Note that we only
diff --git a/dom/base/nsIDocument.h b/dom/base/nsIDocument.h
index b90b523f6f7f..4b06e3485b3b 100644
--- a/dom/base/nsIDocument.h
+++ b/dom/base/nsIDocument.h
@@ -21,8 +21,7 @@
 #include "nsIUUIDGenerator.h"
 #include "nsPIDOMWindow.h"               // for use in inline functions
 #include "nsPropertyTable.h"             // for member
-#include "nsDataHashtable.h"             // for member
-#include "nsURIHashKey.h"                // for member
+#include "nsTHashtable.h"                // for member
 #include "mozilla/net/ReferrerPolicy.h"  // for member
 #include "nsWeakReference.h"
 #include "mozilla/dom/DocumentBinding.h"
@@ -167,13 +166,6 @@ enum DocumentFlavor {
   DocumentFlavorPlain, // Just a Document
 };
 
-// Enum for HSTS priming states
-enum class HSTSPrimingState {
-  eNO_HSTS_PRIMING = 0,    // don't do HSTS Priming
-  eHSTS_PRIMING_ALLOW = 1, // if HSTS priming fails, allow the load to proceed
-  eHSTS_PRIMING_BLOCK = 2  // if HSTS priming fails, block the load
-};
-
 // Document states
 
 // RTL locale: specific to the XUL localedir attribute
@@ -357,34 +349,6 @@ public:
     mReferrer = aReferrer;
   }
 
-  /**
-   * Check to see if a subresource we want to load requires HSTS priming
-   * to be done.
-   */
-  HSTSPrimingState GetHSTSPrimingStateForLocation(nsIURI* aContentLocation) const
-  {
-    HSTSPrimingState state;
-    if (mHSTSPrimingURIList.Get(aContentLocation, &state)) {
-      return state;
-    }
-    return HSTSPrimingState::eNO_HSTS_PRIMING;
-  }
-
-  /**
-   * Add a subresource to the HSTS priming list. If this URI is
-   * not in the HSTS cache, it will trigger an HSTS priming request
-   * when we try to load it.
-   */
-  void AddHSTSPrimingLocation(nsIURI* aContentLocation, HSTSPrimingState aState)
-  {
-    mHSTSPrimingURIList.Put(aContentLocation, aState);
-  }
-
-  void ClearHSTSPrimingLocation(nsIURI* aContentLocation)
-  {
-    mHSTSPrimingURIList.Remove(aContentLocation);
-  }
-
   /**
    * Set the principal responsible for this document.
    */
@@ -2905,11 +2869,6 @@ protected:
   bool mUpgradeInsecureRequests;
   bool mUpgradeInsecurePreloads;
 
-  // if nsMixedContentBlocker requires sending an HSTS priming request,
-  // temporarily store that in the document so that it can be propogated to the
-  // LoadInfo and eventually the HTTP Channel
-  nsDataHashtable mHSTSPrimingURIList;
-
   mozilla::WeakPtr mDocumentContainer;
 
   nsCString mCharacterSet;
diff --git a/dom/ipc/ContentParent.cpp b/dom/ipc/ContentParent.cpp
index 755671e437d2..d2903415bbd9 100644
--- a/dom/ipc/ContentParent.cpp
+++ b/dom/ipc/ContentParent.cpp
@@ -4289,18 +4289,18 @@ ContentParent::RecvIsSecureURI(const uint32_t& type,
   if (!ourURI) {
     return false;
   }
-  nsresult rv = sss->IsSecureURI(type, ourURI, flags, isSecureURI, nullptr);
+  nsresult rv = sss->IsSecureURI(type, ourURI, flags, isSecureURI);
   return NS_SUCCEEDED(rv);
 }
 
 bool
-ContentParent::RecvAccumulateMixedContentHSTS(const URIParams& aURI, const bool& aActive, const bool& aHSTSPriming)
+ContentParent::RecvAccumulateMixedContentHSTS(const URIParams& aURI, const bool& aActive)
 {
   nsCOMPtr ourURI = DeserializeURI(aURI);
   if (!ourURI) {
     return false;
   }
-  nsMixedContentBlocker::AccumulateMixedContentHSTS(ourURI, aActive, aHSTSPriming);
+  nsMixedContentBlocker::AccumulateMixedContentHSTS(ourURI, aActive);
   return true;
 }
 
diff --git a/dom/ipc/ContentParent.h b/dom/ipc/ContentParent.h
index 57fdf569962f..d55ceb1859be 100644
--- a/dom/ipc/ContentParent.h
+++ b/dom/ipc/ContentParent.h
@@ -823,8 +823,7 @@ private:
                                const uint32_t& aFlags, bool* aIsSecureURI) override;
 
   virtual bool RecvAccumulateMixedContentHSTS(const URIParams& aURI,
-                                              const bool& aActive,
-                                              const bool& aHSTSPriming) override;
+                                              const bool& aActive) override;
 
   virtual bool DeallocPHalParent(PHalParent*) override;
 
diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl
index b981edffbe9b..c7651041c017 100644
--- a/dom/ipc/PContent.ipdl
+++ b/dom/ipc/PContent.ipdl
@@ -821,7 +821,7 @@ parent:
     sync IsSecureURI(uint32_t type, URIParams uri, uint32_t flags)
         returns (bool isSecureURI);
 
-    async AccumulateMixedContentHSTS(URIParams uri, bool active, bool hasHSTSPriming);
+    async AccumulateMixedContentHSTS(URIParams uri, bool active);
 
     sync GetLookAndFeelCache()
         returns (LookAndFeelInt[] lookAndFeelIntCache);
diff --git a/dom/security/moz.build b/dom/security/moz.build
index 00f7376a85ab..e24403433c74 100644
--- a/dom/security/moz.build
+++ b/dom/security/moz.build
@@ -20,7 +20,6 @@ EXPORTS.mozilla.dom += [
 
 EXPORTS += [
     'nsContentSecurityManager.h',
-    'nsMixedContentBlocker.h',
 ]
 
 UNIFIED_SOURCES += [
diff --git a/dom/security/nsContentSecurityManager.cpp b/dom/security/nsContentSecurityManager.cpp
index aa38450cfe5d..aab5a2d6fd01 100644
--- a/dom/security/nsContentSecurityManager.cpp
+++ b/dom/security/nsContentSecurityManager.cpp
@@ -6,8 +6,6 @@
 #include "nsContentUtils.h"
 #include "nsCORSListenerProxy.h"
 #include "nsIStreamListener.h"
-#include "nsIDocument.h"
-#include "nsMixedContentBlocker.h"
 
 #include "mozilla/dom/Element.h"
 
@@ -383,14 +381,6 @@ DoContentSecurityChecks(nsIChannel* aChannel, nsILoadInfo* aLoadInfo)
   if (NS_CP_REJECTED(shouldLoad)) {
     return NS_ERROR_CONTENT_BLOCKED;
   }
-
-  if (nsMixedContentBlocker::sSendHSTSPriming) {
-    rv = nsMixedContentBlocker::MarkLoadInfoForPriming(uri,
-                                                       requestingContext,
-                                                       aLoadInfo);
-    return rv;
-  }
-
   return NS_OK;
 }
 
@@ -501,7 +491,7 @@ nsContentSecurityManager::AsyncOnChannelRedirect(nsIChannel* aOldChannel,
       rv = nsContentUtils::GetSecurityManager()->
         CheckLoadURIWithPrincipal(oldPrincipal, newOriginalURI, flags);
   }
-  NS_ENSURE_SUCCESS(rv, rv);
+  NS_ENSURE_SUCCESS(rv, rv);  
 
   aCb->OnRedirectVerifyCallback(NS_OK);
   return NS_OK;
diff --git a/dom/security/nsMixedContentBlocker.cpp b/dom/security/nsMixedContentBlocker.cpp
index 452a914fb6fe..86a78f69c329 100644
--- a/dom/security/nsMixedContentBlocker.cpp
+++ b/dom/security/nsMixedContentBlocker.cpp
@@ -54,11 +54,6 @@ bool nsMixedContentBlocker::sBlockMixedScript = false;
 // Is mixed display content blocking (images, audio, video, ) enabled?
 bool nsMixedContentBlocker::sBlockMixedDisplay = false;
 
-// Do we move HSTS before mixed-content
-bool nsMixedContentBlocker::sUseHSTS = false;
-// Do we send an HSTS priming request
-bool nsMixedContentBlocker::sSendHSTSPriming = false;
-
 // Fired at the document that attempted to load mixed content.  The UI could
 // handle this event, for example, by displaying an info bar that offers the
 // choice to reload the page with mixed content permitted.
@@ -200,14 +195,6 @@ nsMixedContentBlocker::nsMixedContentBlocker()
   // Cache the pref for mixed display blocking
   Preferences::AddBoolVarCache(&sBlockMixedDisplay,
                                "security.mixed_content.block_display_content");
-
-  // Cache the pref for HSTS
-  Preferences::AddBoolVarCache(&sUseHSTS,
-                               "security.mixed_content.use_hsts");
-
-  // Cache the pref for sending HSTS priming
-  Preferences::AddBoolVarCache(&sSendHSTSPriming,
-                               "security.mixed_content.send_hsts_priming");
 }
 
 nsMixedContentBlocker::~nsMixedContentBlocker()
@@ -254,6 +241,8 @@ LogMixedContentMessage(MixedContentTypes aClassification,
                                   messageLookupKey.get(), strings, ArrayLength(strings));
 }
 
+
+
 /* nsIChannelEventSink implementation
  * This code is called when a request is redirected.
  * We check the channel associated with the new uri is allowed to load
@@ -477,6 +466,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
       *aDecision = ACCEPT;
       return NS_OK;
 
+
     // Static display content is considered moderate risk for mixed content so
     // these will be blocked according to the mixed display preference
     case TYPE_IMAGE:
@@ -510,6 +500,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
     // This content policy works as a whitelist.
     default:
       MOZ_ASSERT(false, "Mixed content of unknown type");
+      break;
   }
 
   // Make sure to get the URI the load started with. No need to check
@@ -689,9 +680,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
   bool isHttpScheme = false;
   rv = innerContentLocation->SchemeIs("http", &isHttpScheme);
   NS_ENSURE_SUCCESS(rv, rv);
-  nsIDocument* document = docShell->GetDocument();
-  MOZ_ASSERT(document, "Expected a document");
-  if (isHttpScheme && document->GetUpgradeInsecureRequests(isPreload)) {
+  if (isHttpScheme && docShell->GetDocument()->GetUpgradeInsecureRequests(isPreload)) {
     *aDecision = ACCEPT;
     return NS_OK;
   }
@@ -702,7 +691,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
   // Block all non secure loads in case the CSP directive is present. Please note
   // that at this point we already know, based on |schemeSecure| that the load is
   // not secure, so we can bail out early at this point.
-  if (document->GetBlockAllMixedContent(isPreload)) {
+  if (docShell->GetDocument()->GetBlockAllMixedContent(isPreload)) {
     // log a message to the console before returning.
     nsAutoCString spec;
     rv = aContentLocation->GetSpec(spec);
@@ -717,7 +706,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
                         0, // aLineNumber
                         0, // aColumnNumber
                         nsIScriptError::errorFlag, "CSP",
-                        document->InnerWindowID());
+                        docShell->GetDocument()->InnerWindowID());
     *aDecision = REJECT_REQUEST;
     return NS_OK;
   }
@@ -810,34 +799,6 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
   }
   nsresult stateRV = securityUI->GetState(&state);
 
-  bool doHSTSPriming = false;
-  if (isHttpScheme) {
-    bool hsts = false;
-    bool cached = false;
-    nsCOMPtr sss =
-      do_GetService(NS_SSSERVICE_CONTRACTID, &rv);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aContentLocation,
-        0, &cached, &hsts);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (hsts && sUseHSTS) {
-      // assume we will be upgraded later
-      *aDecision = ACCEPT;
-      return NS_OK;
-    }
-
-    // Send a priming request if the result is not already cached and priming
-    // requests are allowed
-    if (!cached && sSendHSTSPriming) {
-      // add this URI as a priming location
-      doHSTSPriming = true;
-      document->AddHSTSPrimingLocation(innerContentLocation,
-          HSTSPrimingState::eHSTS_PRIMING_ALLOW);
-      *aDecision = ACCEPT;
-    }
-  }
-
   // At this point we know that the request is mixed content, and the only
   // question is whether we block it.  Record telemetry at this point as to
   // whether HSTS would have fixed things by making the content location
@@ -853,14 +814,14 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
   bool active = (classification == eMixedScript);
   if (!aHadInsecureImageRedirect) {
     if (XRE_IsParentProcess()) {
-      AccumulateMixedContentHSTS(innerContentLocation, active, doHSTSPriming);
+      AccumulateMixedContentHSTS(innerContentLocation, active);
     } else {
       // Ask the parent process to do the same call
       mozilla::dom::ContentChild* cc = mozilla::dom::ContentChild::GetSingleton();
       if (cc) {
         mozilla::ipc::URIParams uri;
         SerializeURI(innerContentLocation, uri);
-        cc->SendAccumulateMixedContentHSTS(uri, active, doHSTSPriming);
+        cc->SendAccumulateMixedContentHSTS(uri, active);
       }
     }
   }
@@ -903,13 +864,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
         }
       }
     } else {
-      if (doHSTSPriming) {
-        document->AddHSTSPrimingLocation(aContentLocation,
-            HSTSPrimingState::eHSTS_PRIMING_BLOCK);
-        *aDecision = nsIContentPolicy::ACCEPT;
-      } else {
-        *aDecision = nsIContentPolicy::REJECT_REQUEST;
-      }
+      *aDecision = nsIContentPolicy::REJECT_REQUEST;
       LogMixedContentMessage(classification, aContentLocation, rootDoc, eBlocked);
       if (!rootDoc->GetHasMixedDisplayContentBlocked() && NS_SUCCEEDED(stateRV)) {
         rootDoc->SetHasMixedDisplayContentBlocked(true);
@@ -955,13 +910,7 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
       }
     } else {
       //User has not overriden the pref by Disabling protection. Reject the request and update the security state.
-      if (doHSTSPriming) {
-        document->AddHSTSPrimingLocation(aContentLocation,
-            HSTSPrimingState::eHSTS_PRIMING_BLOCK);
-        *aDecision = nsIContentPolicy::ACCEPT;
-      } else {
-        *aDecision = nsIContentPolicy::REJECT_REQUEST;
-      }
+      *aDecision = nsIContentPolicy::REJECT_REQUEST;
       LogMixedContentMessage(classification, aContentLocation, rootDoc, eBlocked);
       // See if the pref will change here. If it will, only then do we need to call OnSecurityChange() to update the UI.
       if (rootDoc->GetHasMixedActiveContentBlocked()) {
@@ -974,8 +923,9 @@ nsMixedContentBlocker::ShouldLoad(bool aHadInsecureImageRedirect,
       if (NS_SUCCEEDED(stateRV)) {
          eventSink->OnSecurityChange(aRequestingContext, (state | nsIWebProgressListener::STATE_BLOCKED_MIXED_ACTIVE_CONTENT));
       }
+      return NS_OK;
     }
-    return NS_OK;
+
   } else {
     // The content is not blocked by the mixed content prefs.
 
@@ -1026,24 +976,10 @@ enum MixedContentHSTSState {
   MCB_HSTS_ACTIVE_WITH_HSTS  = 3
 };
 
-// Similar to the existing mixed-content HSTS, except MCB_HSTS_*_NO_HSTS is
-// broken into two distinct states, indicating whether we plan to send a priming
-// request or not. If we decided not go send a priming request, it could be
-// because it is a type we do not support, or because we cached a previous
-// negative response.
-enum MixedContentHSTSPrimingState {
-  eMCB_HSTS_PASSIVE_WITH_HSTS  = 0,
-  eMCB_HSTS_ACTIVE_WITH_HSTS   = 1,
-  eMCB_HSTS_PASSIVE_NO_PRIMING = 2,
-  eMCB_HSTS_PASSIVE_DO_PRIMING = 3,
-  eMCB_HSTS_ACTIVE_NO_PRIMING  = 4,
-  eMCB_HSTS_ACTIVE_DO_PRIMING  = 5
-};
-
 // Record information on when HSTS would have made mixed content not mixed
 // content (regardless of whether it was actually blocked)
 void
-nsMixedContentBlocker::AccumulateMixedContentHSTS(nsIURI* aURI, bool aActive, bool aHasHSTSPriming)
+nsMixedContentBlocker::AccumulateMixedContentHSTS(nsIURI* aURI, bool aActive)
 {
   // This method must only be called in the parent, because
   // nsSiteSecurityService is only available in the parent
@@ -1058,87 +994,28 @@ nsMixedContentBlocker::AccumulateMixedContentHSTS(nsIURI* aURI, bool aActive, bo
   if (NS_FAILED(rv)) {
     return;
   }
-  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, 0, nullptr, &hsts);
+  rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, 0, &hsts);
   if (NS_FAILED(rv)) {
     return;
   }
 
-  // states: would upgrade, would prime, hsts info cached
-  // active, passive
-  //
   if (!aActive) {
     if (!hsts) {
       Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
                             MCB_HSTS_PASSIVE_NO_HSTS);
-      if (aHasHSTSPriming) {
-        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING,
-                              eMCB_HSTS_PASSIVE_DO_PRIMING);
-      } else {
-        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING,
-                              eMCB_HSTS_PASSIVE_NO_PRIMING);
-      }
     }
     else {
       Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
                             MCB_HSTS_PASSIVE_WITH_HSTS);
-      Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING,
-                            eMCB_HSTS_PASSIVE_WITH_HSTS);
     }
   } else {
     if (!hsts) {
       Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
                             MCB_HSTS_ACTIVE_NO_HSTS);
-      if (aHasHSTSPriming) {
-        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING,
-                              eMCB_HSTS_ACTIVE_DO_PRIMING);
-      } else {
-        Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING,
-                              eMCB_HSTS_ACTIVE_NO_PRIMING);
-      }
     }
     else {
       Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS,
                             MCB_HSTS_ACTIVE_WITH_HSTS);
-      Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING,
-                            eMCB_HSTS_ACTIVE_WITH_HSTS);
     }
   }
 }
-
-NS_IMETHODIMP
-nsMixedContentBlocker::MarkLoadInfoForPriming(nsIURI* aURI,
-                                              nsISupports* aRequestingContext,
-                                              nsILoadInfo* aLoadInfo)
-{
-  // If we marked for priming, we used the innermost URI, so get that
-  nsCOMPtr innerURI = NS_GetInnermostURI(aURI);
-  if (!innerURI) {
-    NS_ERROR("Can't get innerURI from aContentLocation");
-    return NS_ERROR_CONTENT_BLOCKED;
-  }
-
-  bool isHttp = false;
-  innerURI->SchemeIs("http", &isHttp);
-  if (!isHttp) {
-    // there is nothign to do
-    return NS_OK;
-  }
-
-  // If the DocShell was marked for HSTS priming, propagate that to the LoadInfo
-  nsCOMPtr docShell = NS_CP_GetDocShellFromContext(aRequestingContext);
-  if (!docShell) {
-    return NS_OK;
-  }
-  nsIDocument* document = docShell->GetDocument();
-  if (!document) {
-    return NS_OK;
-  }
-
-  HSTSPrimingState status = document->GetHSTSPrimingStateForLocation(innerURI);
-  // set it on the loadInfo
-  if (status != HSTSPrimingState::eNO_HSTS_PRIMING) {
-    aLoadInfo->SetHSTSPriming(status == HSTSPrimingState::eHSTS_PRIMING_BLOCK);
-  }
-
-  return NS_OK;
-}
diff --git a/dom/security/nsMixedContentBlocker.h b/dom/security/nsMixedContentBlocker.h
index 3857082e22cd..216466fd83b2 100644
--- a/dom/security/nsMixedContentBlocker.h
+++ b/dom/security/nsMixedContentBlocker.h
@@ -28,8 +28,6 @@ enum MixedContentTypes {
 #include "nsIChannelEventSink.h"
 #include "imgRequest.h"
 
-class nsILoadInfo; // forward declaration
-
 class nsMixedContentBlocker : public nsIContentPolicy,
                               public nsIChannelEventSink
 {
@@ -61,25 +59,9 @@ public:
                              nsISupports* aExtra,
                              nsIPrincipal* aRequestPrincipal,
                              int16_t* aDecision);
-  static void AccumulateMixedContentHSTS(nsIURI* aURI,
-                                         bool aActive,
-                                         bool aHasHSTSPriming);
-  /* If the document associated with aRequestingContext requires priming for
-   * aURI, propagate that to the LoadInfo so the HttpChannel will find out about
-   * it.
-   *
-   * @param aURI The URI associated with the load
-   * @param aRequestingContext the requesting context passed to ShouldLoad
-   * @param aLoadInfo the LoadInfo for the load
-   */
-  static nsresult MarkLoadInfoForPriming(nsIURI* aURI,
-                                         nsISupports* aRequestingContext,
-                                         nsILoadInfo* aLoadInfo);
-
+  static void AccumulateMixedContentHSTS(nsIURI* aURI, bool aActive);
   static bool sBlockMixedScript;
   static bool sBlockMixedDisplay;
-  static bool sUseHSTS;
-  static bool sSendHSTSPriming;
 };
 
 #endif /* nsMixedContentBlocker_h___ */
diff --git a/dom/security/test/hsts/browser.ini b/dom/security/test/hsts/browser.ini
deleted file mode 100644
index 6fe1ec38bffe..000000000000
--- a/dom/security/test/hsts/browser.ini
+++ /dev/null
@@ -1,9 +0,0 @@
-[DEFAULT]
-support-files =
-  file_priming-top.html
-  file_testserver.sjs
-  file_1x1.png
-  file_priming.js
-  file_stylesheet.css
-
-[browser_hsts-priming_main.js]
diff --git a/dom/security/test/hsts/browser_hsts-priming_main.js b/dom/security/test/hsts/browser_hsts-priming_main.js
deleted file mode 100644
index 3b8b32fde643..000000000000
--- a/dom/security/test/hsts/browser_hsts-priming_main.js
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * Description of the test:
- *   Check that HSTS priming occurs correctly with mixed content
- *
- *   This test uses three hostnames, each of which treats an HSTS priming
- *   request differently.
- *   * no-ssl never returns an ssl response
- *   * reject-upgrade returns an ssl response, but with no STS header
- *   * prime-hsts returns an ssl response with the appropriate STS header
- *
- *   For each server, test that it response appropriately when the we allow
- *   or block active or display content, as well as when we send an hsts priming
- *   request, but do not change the order of mixed-content and HSTS.
- *
- *   This test uses http-on-examine-response, so must be run in browser context.
- */
-'use strict';
-
-var TOP_URI = "https://example.com/browser/dom/security/test/hsts/file_priming-top.html";
-
-var test_servers = {
-  // a test server that does not support TLS
-  'no-ssl': {
-    host: 'example.co.jp',
-    response: false,
-    id: 'no-ssl',
-  },
-  // a test server which does not support STS upgrade
-  'reject-upgrade': {
-    host: 'example.org',
-    response: true,
-    id: 'reject-upgrade',
-  },
-  // a test server when sends an STS header when priming
-  'prime-hsts': {
-    host: 'test1.example.com',
-    response: true,
-    id: 'prime-hsts'
-  },
-};
-// The number of priming responses we expect to see
-var priming_count = 2;
-
-var test_settings = {
-  // mixed active content is allowed, priming will upgrade
-  allow_active: {
-    block_active: false,
-    block_display: false,
-    use_hsts: true,
-    send_hsts_priming: true,
-    type: 'script',
-    result: {
-      'no-ssl': 'insecure',
-      'reject-upgrade': 'insecure',
-      'prime-hsts': 'secure',
-    },
-  },
-  // mixed active content is blocked, priming will upgrade
-  block_active: {
-    block_active: true,
-    block_display: false,
-    use_hsts: true,
-    send_hsts_priming: true,
-    type: 'script',
-    result: {
-      'no-ssl': 'blocked',
-      'reject-upgrade': 'blocked',
-      'prime-hsts': 'secure',
-    },
-  },
-  // keep the original order of mixed-content and HSTS, but send
-  // priming requests
-  hsts_after_mixed: {
-    block_active: true,
-    block_display: false,
-    use_hsts: false,
-    send_hsts_priming: true,
-    type: 'script',
-    result: {
-      'no-ssl': 'blocked',
-      'reject-upgrade': 'blocked',
-      'prime-hsts': 'blocked',
-    },
-  },
-  // mixed display content is allowed, priming will upgrade
-  allow_display: {
-    block_active: true,
-    block_display: false,
-    use_hsts: true,
-    send_hsts_priming: true,
-    type: 'img',
-    result: {
-      'no-ssl': 'insecure',
-      'reject-upgrade': 'insecure',
-      'prime-hsts': 'secure',
-    },
-  },
-  // mixed display content is blocked, priming will upgrade
-  block_display: {
-    block_active: true,
-    block_display: true,
-    use_hsts: true,
-    send_hsts_priming: true,
-    type: 'img',
-    result: {
-      'no-ssl': 'blocked',
-      'reject-upgrade': 'blocked',
-      'prime-hsts': 'secure',
-    },
-  },
-  // mixed active content is blocked, priming will upgrade (css)
-  block_active_css: {
-    block_active: true,
-    block_display: false,
-    use_hsts: true,
-    send_hsts_priming: true,
-    type: 'css',
-    result: {
-      'no-ssl': 'blocked',
-      'reject-upgrade': 'blocked',
-      'prime-hsts': 'secure',
-    },
-  },
-  // mixed active content is blocked, priming will upgrade
-  // redirect to the same host
-  block_active_with_redir_same: {
-    block_active: true,
-    block_display: false,
-    use_hsts: true,
-    send_hsts_priming: true,
-    type: 'script',
-    redir: 'same',
-    result: {
-      'no-ssl': 'blocked',
-      'reject-upgrade': 'blocked',
-      'prime-hsts': 'secure',
-    },
-  },
-}
-// track which test we are on
-var which_test = "";
-
-const Observer = {
-  observe: function (subject, topic, data) {
-    switch (topic) {
-      case 'console-api-log-event':
-        return Observer.console_api_log_event(subject, topic, data);
-      case 'http-on-examine-response':
-        return Observer.http_on_examine_response(subject, topic, data);
-    }
-    throw "Can't handle topic "+topic;
-  },
-  // When a load is blocked which results in an error event within a page, the
-  // test logs to the console.
-  console_api_log_event: function (subject, topic, data) {
-    var message = subject.wrappedJSObject.arguments[0];
-    // when we are blocked, this will match the message we sent to the console,
-    // ignore everything else.
-    var re = RegExp(/^HSTS_PRIMING: Blocked ([-\w]+).*$/);
-    if (!re.test(message)) {
-      return;
-    }
-
-    let id = message.replace(re, '$1');
-    let curTest =test_servers[id];
-
-    if (!curTest) {
-      ok(false, "HSTS priming got a console message blocked, "+
-          "but doesn't match expectations "+id+" (msg="+message);
-      return;
-    }
-
-    is("blocked", test_settings[which_test].result[curTest.id], "HSTS priming "+
-        which_test+":"+curTest.id+" expected "+
-        test_settings[which_test].result[curTest.id]+", got blocked");
-    test_settings[which_test].finished[curTest.id] = "blocked";
-  },
-  // When we see a response come back, peek at the response and test it is secure
-  // or insecure as needed. Addtionally, watch the response for priming requests.
-  http_on_examine_response: function (subject, topic, data) {
-    let curTest = null;
-    let channel = subject.QueryInterface(Ci.nsIHttpChannel);
-    for (let item in test_servers) {
-      let re = RegExp('https?://'+test_servers[item].host);
-      if (re.test(channel.URI.asciiSpec)) {
-        curTest = test_servers[item];
-        break;
-      }
-    }
-
-    if (!curTest) {
-      return;
-    }
-
-    let result = (channel.URI.asciiSpec.startsWith('https:')) ? "secure" : "insecure";
-
-    // This is a priming request, go ahead and validate we were supposed to see
-    // a response from the server
-    if (channel.requestMethod == 'HEAD') {
-      is(true, curTest.response, "HSTS priming response found " + curTest.id);
-      test_settings[which_test].priming[curTest.id] = true;
-      return;
-    }
-
-    // This is the response to our query, make sure it matches
-    is(result, test_settings[which_test].result[curTest.id],
-        "HSTS priming result " + which_test + ":" + curTest.id);
-    test_settings[which_test].finished[curTest.id] = result;
-  },
-};
-
-// opens `uri' in a new tab and focuses it.
-// returns the newly opened tab
-function openTab(uri) {
-  let tab = gBrowser.addTab(uri);
-
-  // select tab and make sure its browser is focused
-  gBrowser.selectedTab = tab;
-  tab.ownerDocument.defaultView.focus();
-
-  return tab;
-}
-
-function clear_sts_data() {
-  for (let test in test_servers) {
-    SpecialPowers.cleanUpSTSData('http://'+test_servers[test].host);
-  }
-}
-
-function do_cleanup() {
-  clear_sts_data();
-
-  Services.obs.removeObserver(Observer, "console-api-log-event");
-  Services.obs.removeObserver(Observer, "http-on-examine-response");
-}
-
-function SetupPrefTestEnvironment(which) {
-  which_test = which;
-  clear_sts_data();
-
-  var settings = test_settings[which];
-  // priming counts how many priming requests we saw
-  settings.priming = {};
-  // priming counts how many tests were finished
-  settings.finished= {};
-
-  SpecialPowers.pushPrefEnv({'set': [["security.mixed_content.block_active_content",
-                                      settings.block_active],
-                                     ["security.mixed_content.block_display_content",
-                                      settings.block_display],
-                                     ["security.mixed_content.use_hsts",
-                                      settings.use_hsts],
-                                     ["security.mixed_content.send_hsts_priming",
-                                      settings.send_hsts_priming]]});
-}
-
-// make the top-level test uri
-function build_test_uri(base_uri, host, test_id, type) {
-  return base_uri +
-          "?host=" + escape(host) +
-          "&id=" + escape(test_id) +
-          "&type=" + escape(type);
-}
-
-// open a new tab, load the test, and wait for it to finish
-function execute_test(test, mimetype) {
-  var src = build_test_uri(TOP_URI, test_servers[test].host,
-      test, test_settings[which_test].type);
-
-  let tab = openTab(src);
-  test_servers[test]['tab'] = tab;
-
-  let browser = gBrowser.getBrowserForTab(tab);
-  yield BrowserTestUtils.browserLoaded(browser);
-
-  gBrowser.removeTab(tab);
-}
-
-//jscs:disable
-add_task(function*() {
-  //jscs:enable
-  Services.obs.addObserver(Observer, "console-api-log-event", false);
-  Services.obs.addObserver(Observer, "http-on-examine-response", false);
-  registerCleanupFunction(do_cleanup);
-
-  for (let which of Object.keys(test_settings)) {
-    SetupPrefTestEnvironment(which);
-
-    for (let server of Object.keys(test_servers)) {
-      yield execute_test(server, test_settings[which].mimetype);
-    }
-
-    SpecialPowers.popPrefEnv();
-  }
-});
diff --git a/dom/security/test/hsts/file_1x1.png b/dom/security/test/hsts/file_1x1.png
deleted file mode 100644
index 1ba31ba1a62313908f41f844a9fb2e74663a4cd2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 17811
zcmeI4c{o)4`^S%cDJn&wC)21!Gu|?%6lJrn1m6qQl
zT9h8NqlKg_Y2hK1r^RE5kZj5KpwOx2>bid4-#@==&UKAB_vik+@B5tB=l*=oIdfe{
z+!`kvB}ENI005NiY$?vrx5Vg2UKaYRrCJmReJKRmdhh{Y+U(Jf1dw`k9snrbVp&w+YaQXh+K!lx@6(W$w^<@Qs03fW(I_T%>QoEpdq_6RV<*L}|{g0MAOH0bfH~}&(
zKH7`+uZT5Rl=-)6kaWrR-SX~&nbNl}0fxI{WuBj)-XdEpP;4boXR03P+h!x|sUGUC
z4jakqxL%l7LmX=7ccv(<2)~tLUz{nsVlM?9uiWLQvt)5joc#(wZVpyrc>!Ww>s(b;
z2>{#mc_^Y)RvLJD!OVN9>fI51>YZFK2|z^#ICIC#LK)yG0xVTqkOw#@1E=HPI1>SP
zS-`=A?raFS%K>G3f;duuZ!6)26mVJ}PXYi<08!N+;UNq3Y6ICl(&{`wV>U2?pZJq~W6-2>`N7ZgqdfPIqI*PIQa^gb2p
z*qlE^xGN3#AO7o+Kj0&Qcvd^@uA9EyF;(JiKR
zeOht|bEJM*QV(5+dKv5a1~aR2_nLu>F4v<6HRl-JZaL-CDBbLLZ;3--n(o$W>1N-O
znAH~)*0dN}=Pu=6*QahNIa*&DAo=;VM|auZk4mS(9%Ohs<
zR>;QFi08Li>h8?Sp8bGkK7acrf~?L7g^D{eS0zne;_G*noQT;fRI+-nuyU64LZl#O
z+rP+_u|#@2L3@6YoPs5CpZ_8SI}5{^3a3^a)Nb2H|5IAeMj45_fAPNhYe}9`i{%1j
z{(VIEf`Q$1T_y08Y^DrJ>CK6){sfKq3M->W*8XJAXwJ%qkL+`m*%ZtPlSf0DDv=4w
zjOeunYQB4F8T0jl_@bms0*9ShMZ2?|&#Rm(@yu3kN1rZg^zjaqo-b8$ulCi=z>`-A
zM}aHyS5&SjtlN9;9_}A>Q^!AHK~`6_grtpH-1xqtp7(M6(?8K878cC${@pyGa8F@k
zXGs)tro8_4#kY^mw6{evXC0h{pY>5iL!KRjw$!2>vR%}w!j5Y!vPB-()lpLkncWuK
z92XKhTvWMeX=&_h2gN0elNbG&_owsYwa&|0lv@_F_Mf-F>x3t1ms)l^cdK>Nc+&>d
zt{peEulkefd{ghze*Fg;_Uh?ryu;lw-P`QbQ`eYf=A1#cZrY^YOXyvimooVKY3rPm
zGLPOqo|9XitDTFlv#OIL9phLuKTdAp4f=*D4I_uuhjTQn$}JKymbk7@cRyL38Eo?|
zi{#PZ)v!9UAgmzl%%ENG`c|&-eGN4Y35|$^0~)Fte#T+OJ8|l%PN{#S5>t;DCvMvK
zWd0-MCJ%oZmO`Flt}<)G(^iJhbeENY)h%iXq3mkezkVu*4mvC_iuWipz1PlEW^HDz
zuGw3&@zjQskxuJN?@-nB7py9)yFKl2CjxFZe*X>VmY0aoVY18Zr+&6r!;j7+(4ZzJerq3Ig7q=&P-Z7J~;%eWaOU3Pm
z9~Xbzcc~yK^U|IE6G0hWnQ`fMM@v1EWs@^b&vDtyy56GvB>2ffBki2Sz7NYcl`lA)
zTuyv@`0b6d1&%j578*7
ztMtib$F@Ts?^Zoq+b;aO>r(PTmqSlHGt@HrD)1GO&5F(8XhDikiW|Bd-Ff=C)9NDy
z+(D^zJKG#;lrFrx@S>r
zE{iDL$SXGFgunK9&gp#~aHl=9RyD_)vfLVz*bz%B(vKx-^ypQa2d`>>ML0*W_6oll
z_Nl%nZ5jxD<404;=W^oF|bcea*TTtbXT~d!%|dJ^UOCdT5dRG`|%LLqJE#%1G`e9c2yE{
z6&hvib(Kj=dFt+|>xS<3%H>z>)Aw>e5dXU3A^V`w8|MMX-w)99PnlHeTts&E{L^2o
zlj4v5L;u>fr@k%s(lI?ddZIjbu3ti}E~pm{q`t{t_Q`#|SKN7r4YdUi1a7y_etx#_
z+_{=H)y#_nky)?mlJc}_7N6g&ht;KScyxu#jAWnmJb6CbZ%56}Ve_V~D#K5&Re`TM
z63lnUSl7h=7QZUKkgXDM{d3NfO3*x!?ewDlS~2@!K~_vwQdYzBh%0U>{s&*Dd|)5H
zmLDV+Zd0{4arxZ#o9?81!3g>Rx)=?5P&|4#ISuPWqLx+a7kW2&S7qBoRo*kx4*xy8
zv;9@axfk5*Lg7e_)G4VM$~)%=oX^eFH=_{thx}XI)PMK4!oaO(&OAQ1^upj)3XkIP
z+lI(9_wrA_&HP-2%Ja`U6`alCG`wSMD@kp8*ER#6t+6}tZcuU8y28_+>LQV!C_{D?
zrGqYSGd>>mJ&N8$(MZ87<3POLk>u1H6*0$H+^$W;;UjmsHWeDjvj`cHoK?%x^GF|xV&Wz;^Bu(zM7n=&+1>H#BymDRJZ!eb5?T~HE=Ou=8-W&GlyK(*1
zb*&F&@79uMlIIC^xAu3eZTz3Al5@vj9-m|OOz1i2Fyiq>t2)Y9w_$&Cm{d5IoEZA~
z>gq>*gId={`m4R)Z~uJiLweQ2REg$oIXiCexZ+(N`fS8=Fzkb4)A7`(j?m4$AD?>H
z7jl#rEB6*A=WB)+w(RKGrLC0_6`-|OW9vt~<|qH!R{1qlKJzAclM0qZL=vy}Yj&-#
z4QcB{ncs;rRez|incNLV0KhE(a9k}XjFOH{lfHFTX~kO2&ieomy{9iMx=XqHMd(c%
zDIi*Ng&9EMNq9X6oOlvt&w+p0z*?_pD*6N(eYV*<`AEkODuATSwaOk4SgDQII=JNV5X~5}M^o
z6;K@=NDM9;O=EKDAX>-{gzkI+z|>qANMmdU1qeFm$KseFJ8u*s5iF(|avjbQ>lkPS
z`m=1qc%Vy|lPe=^GlR%Pnv)exg(N5d8x+tGLUsU$PZF9T$KsNp{n2I&5;4|Au-Oc0
zF`5uTbzFn6;_^TQ4vj}K3=9kqCPcIWj$mYn(?=L$4R9DN5o3TwVGT$ISdt+Y@nu7j
z6`?&-9@CfPOj-FQ9b}my{RM(R5(X0z5`qpfLUVb37y}}ah`}0S3=L6G4-`L?BcKUU
z9KQB=kgstlAfLfw1qxVP4q`Mejn3U7Fhe3o6HRPi&Wjy5k%+_p!VaQ{5z+!N252ni
zCn85j(K0sshf2P{Iv6^VFK70{gnZY~KoH{$^0`}h4A43lm$#E{F}p=aR2n|1uWmm!TClz>iMY*6taFI8}*FK#!6v)
zgiN9OBU$l4nt;o5<#Gea<5f2Kzy>|9jaC&x*OA6xaYmow^h_~u(d39v#seud0Z4|l
zcofzcg~hoV;7M3K$q4X~4u8
zfkw2iiKYbmF41Zp3tE|I0aN;no(mI7=8MJQalR&oC?=84L>U_!8=>eprZEZ!4FL^{
zhf*3EeNFL$FyE!JW$~eU3Y}7CP_>P%JuYC-x2<0t0j#k#B#_4AgQHW^4Ec3#PAobT
zYs#o*Y>Ja;jM3GH%or_TkZFqfrgieLCX`=ftnY{O*AR@ypCbQxju3y4BdYwzLyh(N
zc@RF=R}ezuffjyHh5Xvw9FP005T3vkGrC>}u>KE*f=>(n-wnjC&8z<>12I|241XHO
z4`h-tUyJx_!>^6q_=tWxyS~oY?`NYalR@(3^4K&1nZ>60ftWy!pDAXtaWbdr)%y}*&6bq1<=+SvRyFvWb=
z2JcTDT`vN*jP*A$#6lZ%8w71%q*L8+sfTFkR5x5YsdVG81Z2Z6*7?)^1Fs~RF42Wn`j7u~hm{*Jo21K+e#wD5$
z%qzwP10vcK;}XpW<`v_D0TFGAaf#*w^NMl7fQUB5xJ2`TdBwP3Kt!8jT%!5FykcB1
zAfin%F425oUNJ5h5YeU>muNmPuNW5$h-g!cOEe#tSBwh=M6@Z!C7KV+E5-!_BH9#*
zOL6igP>=(?`56Me;@OwCOBZ@Q6v41{b_4*94gl~k0upjL01%o50IO912?gjMp
-
-
-  Bug 1246540
-  
-
-
-  

- - - - - diff --git a/dom/security/test/hsts/file_priming.js b/dom/security/test/hsts/file_priming.js deleted file mode 100644 index 023022da67cd..000000000000 --- a/dom/security/test/hsts/file_priming.js +++ /dev/null @@ -1,4 +0,0 @@ -function completed() { - return; -} -completed(); diff --git a/dom/security/test/hsts/file_stylesheet.css b/dom/security/test/hsts/file_stylesheet.css deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/dom/security/test/hsts/file_testserver.sjs b/dom/security/test/hsts/file_testserver.sjs deleted file mode 100644 index d5cd6b17a06e..000000000000 --- a/dom/security/test/hsts/file_testserver.sjs +++ /dev/null @@ -1,66 +0,0 @@ -// SJS file for HSTS mochitests - -Components.utils.import("resource://gre/modules/NetUtil.jsm"); -Components.utils.importGlobalProperties(["URLSearchParams"]); - -function loadFromFile(path) { - // Load the HTML to return in the response from file. - // Since it's relative to the cwd of the test runner, we start there and - // append to get to the actual path of the file. - var testFile = - Components.classes["@mozilla.org/file/directory_service;1"]. - getService(Components.interfaces.nsIProperties). - get("CurWorkD", Components.interfaces.nsILocalFile); - var dirs = path.split("/"); - for (var i = 0; i < dirs.length; i++) { - testFile.append(dirs[i]); - } - var testFileStream = - Components.classes["@mozilla.org/network/file-input-stream;1"]. - createInstance(Components.interfaces.nsIFileInputStream); - testFileStream.init(testFile, -1, 0, 0); - var test = NetUtil.readInputStreamToString(testFileStream, testFileStream.available()); - return test; -} - -function handleRequest(request, response) -{ - const query = new URLSearchParams(request.queryString); - - redir = query.get('redir'); - if (redir == 'same') { - query.delete("redir"); - response.setStatus(302); - let newURI = request.uri; - newURI.queryString = query.serialize(); - response.setHeader("Location", newURI.spec) - } - - // avoid confusing cache behaviors - response.setHeader("Cache-Control", "no-cache", false); - - // if we have a priming header, check for required behavior - // and set header appropriately - if (request.hasHeader('Upgrade-Insecure-Requests')) { - var expected = query.get('primer'); - if (expected == 'prime-hsts') { - // set it for 5 minutes - response.setHeader("Strict-Transport-Security", "max-age="+(60*5), false); - } else if (expected == 'reject-upgrade') { - response.setHeader("Strict-Transport-Security", "max-age=0", false); - } - response.write(''); - return; - } - - var file = query.get('file'); - if (file) { - var mimetype = unescape(query.get('mimetype')); - response.setHeader("Content-Type", mimetype, false); - response.write(loadFromFile(unescape(file))); - return; - } - - response.setHeader("Content-Type", "application/json", false); - response.write('{}'); -} diff --git a/dom/security/test/mixedcontentblocker/test_main.html b/dom/security/test/mixedcontentblocker/test_main.html index 249ead1ebf5a..dfec03fa9794 100644 --- a/dom/security/test/mixedcontentblocker/test_main.html +++ b/dom/security/test/mixedcontentblocker/test_main.html @@ -162,9 +162,6 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=62178 } function startTest() { - // Set prefs to use mixed-content before HSTS - SpecialPowers.pushPrefEnv({'set': [["security.mixed_content.use_hsts", false], - ["security.mixed_content.send_hsts_priming", false]]}); //Set the first set of mixed content settings and increment the counter. //Enable and for the test. changePrefs([[ "dom.image.srcset.enabled", true ], [ "dom.image.picture.enabled", true ]], diff --git a/dom/security/test/moz.build b/dom/security/test/moz.build index 80e86b6c006f..74f0fefef75d 100644 --- a/dom/security/test/moz.build +++ b/dom/security/test/moz.build @@ -27,5 +27,4 @@ MOCHITEST_CHROME_MANIFESTS += [ BROWSER_CHROME_MANIFESTS += [ 'contentverifier/browser.ini', 'csp/browser.ini', - 'hsts/browser.ini', ] diff --git a/ipc/glue/BackgroundUtils.cpp b/ipc/glue/BackgroundUtils.cpp index 9ccd4c6ee16a..8d6af9977543 100644 --- a/ipc/glue/BackgroundUtils.cpp +++ b/ipc/glue/BackgroundUtils.cpp @@ -263,9 +263,7 @@ LoadInfoToLoadInfoArgs(nsILoadInfo *aLoadInfo, redirectChain, aLoadInfo->CorsUnsafeHeaders(), aLoadInfo->GetForcePreflight(), - aLoadInfo->GetIsPreflight(), - aLoadInfo->GetForceHSTSPriming(), - aLoadInfo->GetMixedContentWouldBlock()); + aLoadInfo->GetIsPreflight()); return NS_OK; } @@ -331,10 +329,7 @@ LoadInfoArgsToLoadInfo(const OptionalLoadInfoArgs& aOptionalLoadInfoArgs, redirectChain, loadInfoArgs.corsUnsafeHeaders(), loadInfoArgs.forcePreflight(), - loadInfoArgs.isPreflight(), - loadInfoArgs.forceHSTSPriming(), - loadInfoArgs.mixedContentWouldBlock() - ); + loadInfoArgs.isPreflight()); loadInfo.forget(outLoadInfo); return NS_OK; diff --git a/netwerk/base/LoadInfo.cpp b/netwerk/base/LoadInfo.cpp index 7cf515257104..0cfad010b87d 100644 --- a/netwerk/base/LoadInfo.cpp +++ b/netwerk/base/LoadInfo.cpp @@ -60,8 +60,6 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, , mIsThirdPartyContext(false) , mForcePreflight(false) , mIsPreflight(false) - , mForceHSTSPriming(false) - , mMixedContentWouldBlock(false) { MOZ_ASSERT(mLoadingPrincipal); MOZ_ASSERT(mTriggeringPrincipal); @@ -215,8 +213,6 @@ LoadInfo::LoadInfo(nsPIDOMWindowOuter* aOuterWindow, , mIsThirdPartyContext(false) // NB: TYPE_DOCUMENT implies not third-party. , mForcePreflight(false) , mIsPreflight(false) - , mForceHSTSPriming(false) - , mMixedContentWouldBlock(false) { // Top-level loads are never third-party // Grab the information we can out of the window. @@ -269,8 +265,6 @@ LoadInfo::LoadInfo(const LoadInfo& rhs) , mCorsUnsafeHeaders(rhs.mCorsUnsafeHeaders) , mForcePreflight(rhs.mForcePreflight) , mIsPreflight(rhs.mIsPreflight) - , mForceHSTSPriming(rhs.mForceHSTSPriming) - , mMixedContentWouldBlock(rhs.mMixedContentWouldBlock) { } @@ -294,9 +288,7 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, nsTArray>& aRedirectChain, const nsTArray& aCorsUnsafeHeaders, bool aForcePreflight, - bool aIsPreflight, - bool aForceHSTSPriming, - bool aMixedContentWouldBlock) + bool aIsPreflight) : mLoadingPrincipal(aLoadingPrincipal) , mTriggeringPrincipal(aTriggeringPrincipal) , mSecurityFlags(aSecurityFlags) @@ -316,8 +308,6 @@ LoadInfo::LoadInfo(nsIPrincipal* aLoadingPrincipal, , mCorsUnsafeHeaders(aCorsUnsafeHeaders) , mForcePreflight(aForcePreflight) , mIsPreflight(aIsPreflight) - , mForceHSTSPriming (aForceHSTSPriming) - , mMixedContentWouldBlock(aMixedContentWouldBlock) { // Only top level TYPE_DOCUMENT loads can have a null loadingPrincipal MOZ_ASSERT(mLoadingPrincipal || aContentPolicyType == nsIContentPolicy::TYPE_DOCUMENT); @@ -770,34 +760,6 @@ LoadInfo::GetIsPreflight(bool* aIsPreflight) return NS_OK; } -NS_IMETHODIMP -LoadInfo::GetForceHSTSPriming(bool* aForceHSTSPriming) -{ - *aForceHSTSPriming = mForceHSTSPriming; - return NS_OK; -} - -NS_IMETHODIMP -LoadInfo::GetMixedContentWouldBlock(bool *aMixedContentWouldBlock) -{ - *aMixedContentWouldBlock = mMixedContentWouldBlock; - return NS_OK; -} - -void -LoadInfo::SetHSTSPriming(bool aMixedContentWouldBlock) -{ - mForceHSTSPriming = true; - mMixedContentWouldBlock = aMixedContentWouldBlock; -} - -void -LoadInfo::ClearHSTSPriming() -{ - mForceHSTSPriming = false; - mMixedContentWouldBlock = false; -} - NS_IMETHODIMP LoadInfo::GetTainting(uint32_t* aTaintingOut) { diff --git a/netwerk/base/LoadInfo.h b/netwerk/base/LoadInfo.h index 6ccb35b02f28..91e5b6559748 100644 --- a/netwerk/base/LoadInfo.h +++ b/netwerk/base/LoadInfo.h @@ -104,9 +104,7 @@ private: nsTArray>& aRedirectChain, const nsTArray& aUnsafeHeaders, bool aForcePreflight, - bool aIsPreflight, - bool aForceHSTSPriming, - bool aMixedContentWouldBlock); + bool aIsPreflight); LoadInfo(const LoadInfo& rhs); friend nsresult @@ -147,9 +145,6 @@ private: nsTArray mCorsUnsafeHeaders; bool mForcePreflight; bool mIsPreflight; - - bool mForceHSTSPriming : 1; - bool mMixedContentWouldBlock : 1; }; } // namespace net diff --git a/netwerk/base/nsILoadInfo.idl b/netwerk/base/nsILoadInfo.idl index d0b42a8e5724..7b10d4c611f6 100644 --- a/netwerk/base/nsILoadInfo.idl +++ b/netwerk/base/nsILoadInfo.idl @@ -541,32 +541,6 @@ interface nsILoadInfo : nsISupports */ [infallible] readonly attribute boolean isPreflight; - /** - * When this request would be mixed-content and we do not have an - * entry in the HSTS cache, we send an HSTS priming request to - * determine if it is ok to upgrade the request to HTTPS. - */ - /** - * True if this is a mixed-content load and HSTS priming request will be sent. - */ - [noscript, infallible] readonly attribute boolean forceHSTSPriming; - /** - * Carry the decision whether this load would be blocked by mixed content so - * that if HSTS priming fails, the correct decision can be made. - */ - [noscript, infallible] readonly attribute boolean mixedContentWouldBlock; - - /** - * Mark this LoadInfo as needing HSTS Priming - * - * @param wouldBlock Carry the decision of Mixed Content Blocking to be - * applied when HSTS priming is complete. - */ - [noscript, notxpcom, nostdcall] - void setHSTSPriming(in boolean mixeContentWouldBlock); - [noscript, notxpcom, nostdcall] - void clearHSTSPriming(); - /** * Constants reflecting the channel tainting. These are mainly defined here * for script. Internal C++ code should use the enum defined in LoadTainting.h. diff --git a/netwerk/base/nsNetUtil.cpp b/netwerk/base/nsNetUtil.cpp index d69ade341695..50b57d59419c 100644 --- a/netwerk/base/nsNetUtil.cpp +++ b/netwerk/base/nsNetUtil.cpp @@ -2339,7 +2339,7 @@ NS_ShouldSecureUpgrade(nsIURI* aURI, bool isStsHost = false; uint32_t flags = aPrivateBrowsing ? nsISocketProvider::NO_PERMANENT_STORAGE : 0; rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, aURI, flags, - nullptr, &isStsHost); + &isStsHost); // if the SSS check fails, it's likely because this load is on a // malformed URI or something else in the setup is wrong, so any error diff --git a/netwerk/base/security-prefs.js b/netwerk/base/security-prefs.js index 0fd640a0ca36..c47f351fcfaa 100644 --- a/netwerk/base/security-prefs.js +++ b/netwerk/base/security-prefs.js @@ -97,15 +97,3 @@ pref("security.ssl.errorReporting.automatic", false); // blacking themselves out by setting a bad pin. (60 days by default) // https://tools.ietf.org/html/rfc7469#section-4.1 pref("security.cert_pinning.max_max_age_seconds", 5184000); - -// If a request is mixed-content, send an HSTS priming request to attempt to -// see if it is available over HTTPS. -pref("security.mixed_content.send_hsts_priming", true); -#ifdef RELEASE_BUILD -// Don't change the order of evaluation of mixed-content and HSTS upgrades -pref("security.mixed_content.use_hsts", false); -#else -// Change the order of evaluation so HSTS upgrades happen before -// mixed-content blocking -pref("security.mixed_content.use_hsts", true); -#endif diff --git a/netwerk/ipc/NeckoChannelParams.ipdlh b/netwerk/ipc/NeckoChannelParams.ipdlh index 1c500aa0a381..982d39349c7c 100644 --- a/netwerk/ipc/NeckoChannelParams.ipdlh +++ b/netwerk/ipc/NeckoChannelParams.ipdlh @@ -49,8 +49,6 @@ struct LoadInfoArgs nsCString[] corsUnsafeHeaders; bool forcePreflight; bool isPreflight; - bool forceHSTSPriming; - bool mixedContentWouldBlock; }; /** diff --git a/netwerk/protocol/http/HSTSPrimerListener.cpp b/netwerk/protocol/http/HSTSPrimerListener.cpp deleted file mode 100644 index 83c29fe47595..000000000000 --- a/netwerk/protocol/http/HSTSPrimerListener.cpp +++ /dev/null @@ -1,249 +0,0 @@ -/* -*- 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 "nsHttp.h" - -#include "HSTSPrimerListener.h" -#include "nsIHstsPrimingCallback.h" -#include "nsIPrincipal.h" -#include "nsSecurityHeaderParser.h" -#include "nsISiteSecurityService.h" -#include "nsISocketProvider.h" -#include "nsISSLStatus.h" -#include "nsISSLStatusProvider.h" -#include "nsStreamUtils.h" -#include "nsHttpChannel.h" -#include "LoadInfo.h" - -namespace mozilla { -namespace net { - -using namespace mozilla; - -NS_IMPL_ISUPPORTS(HSTSPrimingListener, nsIStreamListener, - nsIRequestObserver, nsIInterfaceRequestor) - -NS_IMETHODIMP -HSTSPrimingListener::GetInterface(const nsIID & aIID, void **aResult) -{ - return QueryInterface(aIID, aResult); -} - -NS_IMETHODIMP -HSTSPrimingListener::OnStartRequest(nsIRequest *aRequest, - nsISupports *aContext) -{ - nsresult rv = CheckHSTSPrimingRequestStatus(aRequest); - nsCOMPtr callback(mCallback); - mCallback = nullptr; - - if (NS_FAILED(rv)) { - LOG(("HSTS Priming Failed (request was not approved)")); - return callback->OnHSTSPrimingFailed(rv, false); - } - - LOG(("HSTS Priming Succeeded (request was approved)")); - return callback->OnHSTSPrimingSucceeded(false); -} - -NS_IMETHODIMP -HSTSPrimingListener::OnStopRequest(nsIRequest *aRequest, - nsISupports *aContext, - nsresult aStatus) -{ - return NS_OK; -} - -nsresult -HSTSPrimingListener::CheckHSTSPrimingRequestStatus(nsIRequest* aRequest) -{ - nsresult status; - nsresult rv = aRequest->GetStatus(&status); - NS_ENSURE_SUCCESS(rv, rv); - if (NS_FAILED(status)) { - return NS_ERROR_CONTENT_BLOCKED; - } - - // Test that things worked on a HTTP level - nsCOMPtr httpChannel = do_QueryInterface(aRequest); - NS_ENSURE_STATE(httpChannel); - nsCOMPtr internal = do_QueryInterface(aRequest); - NS_ENSURE_STATE(internal); - - bool succeedded; - rv = httpChannel->GetRequestSucceeded(&succeedded); - if (NS_FAILED(rv) || !succeedded) { - // If the request did not return a 2XX response, don't process it - return NS_ERROR_CONTENT_BLOCKED; - } - - bool synthesized = false; - nsHttpChannel* rawHttpChannel = static_cast(httpChannel.get()); - rv = rawHttpChannel->GetResponseSynthesized(&synthesized); - NS_ENSURE_SUCCESS(rv, rv); - if (synthesized) { - // Don't consider synthesized responses - return NS_ERROR_CONTENT_BLOCKED; - } - - // check to see if the HSTS cache was updated - nsCOMPtr sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr uri; - rv = httpChannel->GetURI(getter_AddRefs(uri)); - NS_ENSURE_SUCCESS(rv, rv); - NS_ENSURE_TRUE(uri, NS_ERROR_CONTENT_BLOCKED); - - bool hsts; - rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, 0, nullptr, &hsts); - NS_ENSURE_SUCCESS(rv, rv); - - if (hsts) { - // An HSTS upgrade was found - return NS_OK; - } - - // There is no HSTS upgrade available - return NS_ERROR_CONTENT_BLOCKED; -} - -/** nsIStreamListener methods **/ - -NS_IMETHODIMP -HSTSPrimingListener::OnDataAvailable(nsIRequest *aRequest, - nsISupports *ctxt, - nsIInputStream *inStr, - uint64_t sourceOffset, - uint32_t count) -{ - uint32_t totalRead; - return inStr->ReadSegments(NS_DiscardSegment, nullptr, count, &totalRead); -} - -// static -nsresult -HSTSPrimingListener::StartHSTSPriming(nsIChannel* aRequestChannel, - nsIHstsPrimingCallback* aCallback) -{ - - nsCOMPtr finalChannelURI; - nsresult rv = NS_GetFinalChannelURI(aRequestChannel, getter_AddRefs(finalChannelURI)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr uri; - rv = finalChannelURI->Clone(getter_AddRefs(uri)); - NS_ENSURE_SUCCESS(rv, rv); - rv = uri->SetScheme(NS_LITERAL_CSTRING("https")); - NS_ENSURE_SUCCESS(rv, rv); - - // check the HSTS cache - bool hsts; - bool cached; - nsCOMPtr sss = do_GetService(NS_SSSERVICE_CONTRACTID, &rv); - NS_ENSURE_SUCCESS(rv, rv); - rv = sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, uri, 0, &cached, &hsts); - NS_ENSURE_SUCCESS(rv, rv); - - if (hsts) { - // already saw this host and will upgrade if allowed by preferences - return aCallback->OnHSTSPrimingSucceeded(true); - } - - if (cached) { - // there is a non-expired entry in the cache that doesn't allow us to - // upgrade, so go ahead and fail early. - return aCallback->OnHSTSPrimingFailed(NS_ERROR_CONTENT_BLOCKED, true); - } - - // Either it wasn't cached or the cached result has expired. Build a - // channel for the HEAD request. - - nsCOMPtr originalLoadInfo = aRequestChannel->GetLoadInfo(); - MOZ_ASSERT(originalLoadInfo, "can not perform HSTS priming without a loadInfo"); - if (!originalLoadInfo) { - return NS_ERROR_FAILURE; - } - - nsCOMPtr loadInfo = static_cast - (originalLoadInfo.get())->CloneForNewRequest(); - - nsCOMPtr loadGroup; - rv = aRequestChannel->GetLoadGroup(getter_AddRefs(loadGroup)); - NS_ENSURE_SUCCESS(rv, rv); - - nsLoadFlags loadFlags; - rv = aRequestChannel->GetLoadFlags(&loadFlags); - NS_ENSURE_SUCCESS(rv, rv); - - loadFlags &= HttpBaseChannel::INHIBIT_CACHING | - HttpBaseChannel::INHIBIT_PERSISTENT_CACHING | - HttpBaseChannel::LOAD_BYPASS_CACHE | - HttpBaseChannel::LOAD_FROM_CACHE | - HttpBaseChannel::VALIDATE_ALWAYS; - // Priming requests should never be intercepted by service workers and - // are always anonymous. - loadFlags |= nsIChannel::LOAD_BYPASS_SERVICE_WORKER | - nsIRequest::LOAD_ANONYMOUS; - - // Create a new channel to send the priming request - nsCOMPtr primingChannel; - rv = NS_NewChannelInternal(getter_AddRefs(primingChannel), - uri, - loadInfo, - loadGroup, - nullptr, // aCallbacks are set later - loadFlags); - NS_ENSURE_SUCCESS(rv, rv); - - // Set method and headers - nsCOMPtr httpChannel = do_QueryInterface(primingChannel); - if (!httpChannel) { - NS_ERROR("HSTSPrimingListener: Failed to QI to nsIHttpChannel!"); - return NS_ERROR_FAILURE; - } - - // Currently using HEAD per the draft, but under discussion to change to GET - // with credentials so if the upgrade is approved the result is already cached. - rv = httpChannel->SetRequestMethod(NS_LITERAL_CSTRING("HEAD")); - NS_ENSURE_SUCCESS(rv, rv); - - rv = httpChannel-> - SetRequestHeader(NS_LITERAL_CSTRING("Upgrade-Insecure-Requests"), - NS_LITERAL_CSTRING("1"), false); - NS_ENSURE_SUCCESS(rv, rv); - - // attempt to set the class of service flags on the new channel - nsCOMPtr requestClass = do_QueryInterface(aRequestChannel); - if (!requestClass) { - NS_ERROR("HSTSPrimingListener: aRequestChannel is not an nsIClassOfService"); - return NS_ERROR_FAILURE; - } - nsCOMPtr primingClass = do_QueryInterface(httpChannel); - if (!primingClass) { - NS_ERROR("HSTSPrimingListener: aRequestChannel is not an nsIClassOfService"); - return NS_ERROR_FAILURE; - } - - uint32_t classFlags = 0; - rv = requestClass ->GetClassFlags(&classFlags); - NS_ENSURE_SUCCESS(rv, rv); - rv = primingClass->SetClassFlags(classFlags); - NS_ENSURE_SUCCESS(rv, rv); - - // Set up listener which will start the original channel - RefPtr primingListener = - new HSTSPrimingListener(aCallback); - - // Start priming - rv = primingChannel->AsyncOpen2(primingListener); - NS_ENSURE_SUCCESS(rv, rv); - - return NS_OK; -} - -} // namespace net -} // namespace mozilla diff --git a/netwerk/protocol/http/HSTSPrimerListener.h b/netwerk/protocol/http/HSTSPrimerListener.h deleted file mode 100644 index 8ef1109f5564..000000000000 --- a/netwerk/protocol/http/HSTSPrimerListener.h +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- 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/. */ - -#ifndef HSTSPrimingListener_h__ -#define HSTSPrimingListener_h__ - -#include "nsCOMPtr.h" -#include "nsIChannelEventSink.h" -#include "nsIInterfaceRequestor.h" -#include "nsIStreamListener.h" -#include "nsIThreadRetargetableStreamListener.h" - -#include "mozilla/Attributes.h" - -class nsIPrincipal; -class nsINetworkInterceptController; -class nsIHstsPrimingCallback; - -namespace mozilla { -namespace net { - -class HttpChannelParent; -class nsHttpChannel; - -/* - * How often do we get back an HSTS priming result which upgrades the connection to HTTPS? - */ -enum HSTSPrimingResult { - // This site has been seen before and won't be upgraded - eHSTS_PRIMING_CACHED_NO_UPGRADE = 0, - // This site has been seen before and will be upgraded - eHSTS_PRIMING_CACHED_DO_UPGRADE = 1, - // This site has been seen before and will be blocked - eHSTS_PRIMING_CACHED_BLOCK = 2, - // The request was already upgraded, probably through - // upgrade-insecure-requests - eHSTS_PRIMING_ALREADY_UPGRADED = 3, - // HSTS priming is successful and the connection will be upgraded to HTTPS - eHSTS_PRIMING_SUCCEEDED = 4, - // When priming succeeds, but preferences require preservation of the order - // of mixed-content and hsts, and mixed-content blocks the load - eHSTS_PRIMING_SUCCEEDED_BLOCK = 5, - // When priming succeeds, but preferences require preservation of the order - // of mixed-content and hsts, and mixed-content allows the load over http - eHSTS_PRIMING_SUCCEEDED_HTTP = 6, - // HSTS priming failed, and the load is blocked by mixed-content - eHSTS_PRIMING_FAILED_BLOCK = 7, - // HSTS priming failed, and the load is allowed by mixed-content - eHSTS_PRIMING_FAILED_ACCEPT = 8 -}; - -////////////////////////////////////////////////////////////////////////// -// Class used as streamlistener and notification callback when -// doing the HEAD request for an HSTS Priming check. Needs to be an -// nsIStreamListener in order to receive events from AsyncOpen2 -class HSTSPrimingListener final : public nsIStreamListener, - public nsIInterfaceRequestor -{ -public: - HSTSPrimingListener(nsIHstsPrimingCallback* aCallback) - : mCallback(aCallback) - { - } - - NS_DECL_ISUPPORTS - NS_DECL_NSISTREAMLISTENER - NS_DECL_NSIREQUESTOBSERVER - NS_DECL_NSIINTERFACEREQUESTOR - -private: - ~HSTSPrimingListener() {} - - // Only nsHttpChannel can invoke HSTS priming - friend class mozilla::net::nsHttpChannel; - - /** - * Start the HSTS priming request. This will send an anonymous HEAD request to - * the URI aRequestChannel is attempting to load. On success, the new HSTS - * priming channel is allocated in aHSTSPrimingChannel. - * - * @param aRequestChannel the reference channel used to initialze the HSTS - * priming channel - * @param aCallback the callback stored to handle the results of HSTS priming. - * @param aHSTSPrimingChannel if the new HSTS priming channel is allocated - * successfully, it will be placed here. - */ - static nsresult StartHSTSPriming(nsIChannel* aRequestChannel, - nsIHstsPrimingCallback* aCallback); - - /** - * Given a request, return NS_OK if it has resulted in a cached HSTS update. - * We don't need to check for the header as that has already been done for us. - */ - nsresult CheckHSTSPrimingRequestStatus(nsIRequest* aRequest); - - /** - * the nsIHttpChannel to notify with the result of HSTS priming. - */ - nsCOMPtr mCallback; -}; - - -}} // mozilla::net - -#endif // HSTSPrimingListener_h__ diff --git a/netwerk/protocol/http/moz.build b/netwerk/protocol/http/moz.build index 47c99fd9656b..89bd6cdd9774 100644 --- a/netwerk/protocol/http/moz.build +++ b/netwerk/protocol/http/moz.build @@ -5,7 +5,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. XPIDL_SOURCES += [ - 'nsIHstsPrimingCallback.idl', 'nsIHttpActivityObserver.idl', 'nsIHttpAuthenticableChannel.idl', 'nsIHttpAuthenticator.idl', @@ -55,7 +54,6 @@ SOURCES += [ UNIFIED_SOURCES += [ 'CacheControlParser.cpp', 'ConnectionDiagnostics.cpp', - 'HSTSPrimerListener.cpp', 'Http2Compression.cpp', 'Http2Push.cpp', 'Http2Session.cpp', diff --git a/netwerk/protocol/http/nsHttpChannel.cpp b/netwerk/protocol/http/nsHttpChannel.cpp index e38136a28644..9c653ed3d3b6 100644 --- a/netwerk/protocol/http/nsHttpChannel.cpp +++ b/netwerk/protocol/http/nsHttpChannel.cpp @@ -98,8 +98,6 @@ #include "nsISocketProvider.h" #include "mozilla/net/Predictor.h" #include "CacheControlParser.h" -#include "nsMixedContentBlocker.h" -#include "HSTSPrimerListener.h" namespace mozilla { namespace net { @@ -407,50 +405,12 @@ nsHttpChannel::Connect() // otherwise, let's just proceed without using the cache. } - return TryHSTSPriming(); -} - -nsresult -nsHttpChannel::TryHSTSPriming() -{ - if (mLoadInfo) { - // HSTS priming requires the LoadInfo provided with AsyncOpen2 - bool requireHSTSPriming = - mLoadInfo->GetForceHSTSPriming(); - - if (requireHSTSPriming && - nsMixedContentBlocker::sSendHSTSPriming && - mInterceptCache == DO_NOT_INTERCEPT) { - bool isHttpsScheme; - nsresult rv = mURI->SchemeIs("https", &isHttpsScheme); - NS_ENSURE_SUCCESS(rv, rv); - if (!isHttpsScheme) { - rv = HSTSPrimingListener::StartHSTSPriming(this, this); - - if (NS_FAILED(rv)) { - CloseCacheEntry(false); - return rv; - } - - return NS_OK; - } - - // The request was already upgraded, for example by - // upgrade-insecure-requests or a prior successful priming request - Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT, - HSTSPrimingResult::eHSTS_PRIMING_ALREADY_UPGRADED); - mLoadInfo->ClearHSTSPriming(); - } - } - return ContinueConnect(); } nsresult nsHttpChannel::ContinueConnect() { - // If we have had HSTS priming, we need to reevaluate whether we need - // a CORS preflight. Bug: 1272440 // If we need to start a CORS preflight, do it now! // Note that it is important to do this before the early returns below. if (!mIsCorsPreflightDone && mRequireCORSPreflight && @@ -4058,7 +4018,7 @@ nsHttpChannel::OnCacheEntryAvailableInternal(nsICacheEntry *entry, return NS_OK; } - return TryHSTSPriming(); + return ContinueConnect(); } nsresult @@ -5398,7 +5358,6 @@ NS_INTERFACE_MAP_BEGIN(nsHttpChannel) NS_INTERFACE_MAP_ENTRY(nsIDNSListener) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsICorsPreflightCallback) - NS_INTERFACE_MAP_ENTRY(nsIHstsPrimingCallback) NS_INTERFACE_MAP_ENTRY(nsIChannelWithDivertableParentListener) // we have no macro that covers this case. if (aIID.Equals(NS_GET_IID(nsHttpChannel)) ) { @@ -7719,103 +7678,6 @@ nsHttpChannel::OnPreflightFailed(nsresult aError) return NS_OK; } -//----------------------------------------------------------------------------- -// nsIHstsPrimingCallback functions -//----------------------------------------------------------------------------- - -/* - * May be invoked synchronously if HSTS priming has already been performed - * for the host. - */ -NS_IMETHODIMP -nsHttpChannel::OnHSTSPrimingSucceeded(bool aCached) -{ - if (nsMixedContentBlocker::sUseHSTS) { - // redirect the channel to HTTPS if the pref - // "security.mixed_content.use_hsts" is true - LOG(("HSTS Priming succeeded, redirecting to HTTPS [this=%p]", this)); - Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT, - (aCached) ? HSTSPrimingResult::eHSTS_PRIMING_CACHED_DO_UPGRADE : - HSTSPrimingResult::eHSTS_PRIMING_SUCCEEDED); - return AsyncCall(&nsHttpChannel::HandleAsyncRedirectChannelToHttps); - } - - // If "security.mixed_content.use_hsts" is false, record the result of - // HSTS priming and block or proceed with the load as required by - // mixed-content blocking - bool wouldBlock = mLoadInfo->GetMixedContentWouldBlock(); - - // preserve the mixed-content-before-hsts order and block if required - if (wouldBlock) { - LOG(("HSTS Priming succeeded, blocking for mixed-content [this=%p]", - this)); - Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT, - HSTSPrimingResult::eHSTS_PRIMING_SUCCEEDED_BLOCK); - CloseCacheEntry(false); - return AsyncAbort(NS_ERROR_CONTENT_BLOCKED); - } - - LOG(("HSTS Priming succeeded, loading insecure: [this=%p]", this)); - Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT, - HSTSPrimingResult::eHSTS_PRIMING_SUCCEEDED_HTTP); - - nsresult rv = ContinueConnect(); - if (NS_FAILED(rv)) { - CloseCacheEntry(false); - return AsyncAbort(rv); - } - - return NS_OK; -} - -/* - * May be invoked synchronously if HSTS priming has already been performed - * for the host. - */ -NS_IMETHODIMP -nsHttpChannel::OnHSTSPrimingFailed(nsresult aError, bool aCached) -{ - bool wouldBlock = mLoadInfo->GetMixedContentWouldBlock(); - - LOG(("HSTS Priming Failed [this=%p], %s the load", this, - (wouldBlock) ? "blocking" : "allowing")); - if (aCached) { - // Between the time we marked for priming and started the priming request, - // the host was found to not allow the upgrade, probably from another - // priming request. - Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT, - (wouldBlock) ? HSTSPrimingResult::eHSTS_PRIMING_CACHED_BLOCK : - HSTSPrimingResult::eHSTS_PRIMING_CACHED_NO_UPGRADE); - } else { - // A priming request was sent, and no HSTS header was found that allows - // the upgrade. - Telemetry::Accumulate(Telemetry::MIXED_CONTENT_HSTS_PRIMING_RESULT, - (wouldBlock) ? HSTSPrimingResult::eHSTS_PRIMING_FAILED_BLOCK : - HSTSPrimingResult::eHSTS_PRIMING_FAILED_ACCEPT); - } - - // Don't visit again for at least one day - nsISiteSecurityService* sss = gHttpHandler->GetSSService(); - NS_ENSURE_TRUE(sss, NS_ERROR_OUT_OF_MEMORY); - nsresult rv = sss->CacheNegativeHSTSResult(mURI, 24 * 60 * 60); - NS_WARN_IF(NS_FAILED(rv)); - - // If we would block, go ahead and abort with the error provided - if (wouldBlock) { - CloseCacheEntry(false); - return AsyncAbort(aError); - } - - // we can continue the load and the UI has been updated as mixed content - rv = ContinueConnect(); - if (NS_FAILED(rv)) { - CloseCacheEntry(false); - return AsyncAbort(rv); - } - - return NS_OK; -} - //----------------------------------------------------------------------------- // AChannelHasDivertableParentChannelAsListener internal functions //----------------------------------------------------------------------------- diff --git a/netwerk/protocol/http/nsHttpChannel.h b/netwerk/protocol/http/nsHttpChannel.h index 3b5ce48d45c4..4f317f41cbf8 100644 --- a/netwerk/protocol/http/nsHttpChannel.h +++ b/netwerk/protocol/http/nsHttpChannel.h @@ -27,7 +27,6 @@ #include "nsIStreamListener.h" #include "nsISupportsPrimitives.h" #include "nsICorsPreflightCallback.h" -#include "nsIHstsPrimingCallback.h" class nsDNSPrefetch; class nsICancelable; @@ -75,7 +74,6 @@ class nsHttpChannel final : public HttpBaseChannel , public nsSupportsWeakReference , public nsICorsPreflightCallback , public nsIChannelWithDivertableParentListener - , public nsIHstsPrimingCallback { public: NS_DECL_ISUPPORTS_INHERITED @@ -91,7 +89,6 @@ public: NS_DECL_NSIAPPLICATIONCACHECONTAINER NS_DECL_NSIAPPLICATIONCACHECHANNEL NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK - NS_DECL_NSIHSTSPRIMINGCALLBACK NS_DECL_NSITHREADRETARGETABLEREQUEST NS_DECL_NSIDNSLISTENER NS_DECL_NSICHANNELWITHDIVERTABLEPARENTLISTENER @@ -206,9 +203,6 @@ public: /* internal necko use only */ nsresult OpenCacheEntry(bool usingSSL); nsresult ContinueConnect(); - // If the load is mixed-content, build and send an HSTS priming request. - nsresult TryHSTSPriming(); - nsresult StartRedirectChannelToURI(nsIURI *, uint32_t); // This allows cache entry to be marked as foreign even after channel itself diff --git a/netwerk/protocol/http/nsHttpHandler.cpp b/netwerk/protocol/http/nsHttpHandler.cpp index 181dffb31e8e..9fcd8cbc2fcb 100644 --- a/netwerk/protocol/http/nsHttpHandler.cpp +++ b/netwerk/protocol/http/nsHttpHandler.cpp @@ -2244,8 +2244,7 @@ nsHttpHandler::SpeculativeConnectInternal(nsIURI *aURI, flags |= nsISocketProvider::NO_PERMANENT_STORAGE; nsCOMPtr clone; if (NS_SUCCEEDED(sss->IsSecureURI(nsISiteSecurityService::HEADER_HSTS, - aURI, flags, nullptr, &isStsHost)) && - isStsHost) { + aURI, flags, &isStsHost)) && isStsHost) { if (NS_SUCCEEDED(NS_GetSecureUpgradedURI(aURI, getter_AddRefs(clone)))) { aURI = clone.get(); diff --git a/netwerk/protocol/http/nsIHstsPrimingCallback.idl b/netwerk/protocol/http/nsIHstsPrimingCallback.idl deleted file mode 100644 index 0e45901738c7..000000000000 --- a/netwerk/protocol/http/nsIHstsPrimingCallback.idl +++ /dev/null @@ -1,50 +0,0 @@ -/* -*- 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 "nsISupports.idl" - -/** - * HSTS priming attempts to prevent mixed-content by looking for the - * Strict-Transport-Security header as a signal from the server that it is - * safe to upgrade HTTP to HTTPS. - * - * Since mixed-content blocking happens very early in the process in AsyncOpen2, - * the status of mixed-content blocking is stored in the LoadInfo and then used - * to determine whether to send a priming request or not. - * - * This interface is implemented by nsHttpChannel so that it can receive the - * result of HSTS priming. - */ -[builtinclass, uuid(eca6daca-3f2a-4a2a-b3bf-9f24f79bc999)] -interface nsIHstsPrimingCallback : nsISupports -{ - /** - * HSTS priming has succeeded with an STS header, and the site asserts it is - * safe to upgrade the request from HTTP to HTTPS. The request may still be - * blocked based on the user's preferences. - * - * May be invoked synchronously if HSTS priming has already been performed - * for the host. - * - * @param aCached whether the result was already in the HSTS cache - */ - [noscript, nostdcall] - void onHSTSPrimingSucceeded(in bool aCached); - /** - * HSTS priming has seen no STS header, the request itself has failed, - * or some other failure which does not constitute a positive signal that the - * site can be upgraded safely to HTTPS. The request may still be allowed - * based on the user's preferences. - * - * May be invoked synchronously if HSTS priming has already been performed - * for the host. - * - * param aError The error which caused this failure, or NS_ERROR_CONTENT_BLOCKED - * @param aCached whether the result was already in the HSTS cache - */ - [noscript, nostdcall] - void onHSTSPrimingFailed(in nsresult aError, in bool aCached); -}; diff --git a/security/manager/ssl/SSLServerCertVerification.cpp b/security/manager/ssl/SSLServerCertVerification.cpp index 22d20ae99edd..794efc244bea 100644 --- a/security/manager/ssl/SSLServerCertVerification.cpp +++ b/security/manager/ssl/SSLServerCertVerification.cpp @@ -506,7 +506,6 @@ CertErrorRunnable::CheckCertOverrides() nsresult nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HSTS, mInfoObject->GetHostNameRaw(), mProviderFlags, - nullptr, &strictTransportSecurityEnabled); if (NS_FAILED(nsrv)) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, @@ -517,7 +516,6 @@ CertErrorRunnable::CheckCertOverrides() nsrv = sss->IsSecureHost(nsISiteSecurityService::HEADER_HPKP, mInfoObject->GetHostNameRaw(), mProviderFlags, - nullptr, &hasPinningInformation); if (NS_FAILED(nsrv)) { MOZ_LOG(gPIPNSSLog, LogLevel::Debug, diff --git a/security/manager/ssl/nsISiteSecurityService.idl b/security/manager/ssl/nsISiteSecurityService.idl index a1ebcd40ead8..0eca3041ad47 100644 --- a/security/manager/ssl/nsISiteSecurityService.idl +++ b/security/manager/ssl/nsISiteSecurityService.idl @@ -115,13 +115,10 @@ interface nsISiteSecurityService : nsISupports * @param aHost the hostname (punycode) to query for state. * @param aFlags options for this request as defined in nsISocketProvider: * NO_PERMANENT_STORAGE - * @param aCached true if we have cached information regarding whether or not - * the host is HSTS, false otherwise. */ boolean isSecureHost(in uint32_t aType, in string aHost, - in uint32_t aFlags, - [optional] out boolean aCached); + in uint32_t aFlags); /** * Checks whether or not the URI's hostname has a given security state set. @@ -136,11 +133,8 @@ interface nsISiteSecurityService : nsISupports * @param aURI the URI to query for STS state. * @param aFlags options for this request as defined in nsISocketProvider: * NO_PERMANENT_STORAGE - * @param aCached true if we have cached information regarding whether or not - * the host is HSTS, false otherwise. */ - boolean isSecureURI(in uint32_t aType, in nsIURI aURI, in uint32_t aFlags, - [optional] out boolean aCached); + boolean isSecureURI(in uint32_t aType, in nsIURI aURI, in uint32_t aFlags); /** * Removes all security state by resetting to factory-original settings. @@ -180,14 +174,6 @@ interface nsISiteSecurityService : nsISupports in unsigned long aMaxAge, in unsigned long aPinCount, [array, size_is(aPinCount)] in string aSha256Pins); - /** - * Mark a host as declining to provide a given security state so that features - * such as HSTS priming will not flood a server with requests. - * - * @param aHost the hostname (punycode) that this applies to - * @param aMaxAge lifetime (in seconds) of this negative cache - */ - [noscript] void cacheNegativeHSTSResult(in nsIURI aURI, in unsigned long long aMaxAge); }; %{C++ diff --git a/security/manager/ssl/nsSiteSecurityService.cpp b/security/manager/ssl/nsSiteSecurityService.cpp index c8a4635536af..b3df457ff52e 100644 --- a/security/manager/ssl/nsSiteSecurityService.cpp +++ b/security/manager/ssl/nsSiteSecurityService.cpp @@ -314,8 +314,7 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType, nsIURI* aSourceURI, int64_t maxage, bool includeSubdomains, - uint32_t flags, - SecurityPropertyState aHSTSState) + uint32_t flags) { // If max-age is zero, that's an indication to immediately remove the // security state, so here's a shortcut. @@ -323,12 +322,8 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType, return RemoveState(aType, aSourceURI, flags); } - MOZ_ASSERT((aHSTSState == SecurityPropertySet - || aHSTSState == SecurityPropertyNegative), - "HSTS State must be SecurityPropertySet or SecurityPropertyNegative"); - int64_t expiretime = ExpireTimeFromMaxAge(maxage); - SiteHSTSState siteState(expiretime, aHSTSState, includeSubdomains); + SiteHSTSState siteState(expiretime, SecurityPropertySet, includeSubdomains); nsAutoCString stateString; siteState.ToString(stateString); nsAutoCString hostname; @@ -347,14 +342,6 @@ nsSiteSecurityService::SetHSTSState(uint32_t aType, return NS_OK; } -NS_IMETHODIMP -nsSiteSecurityService::CacheNegativeHSTSResult(nsIURI* aSourceURI, - uint64_t aMaxAge) -{ - return SetHSTSState(nsISiteSecurityService::HEADER_HSTS, aSourceURI, - aMaxAge, false, 0, SecurityPropertyNegative); -} - NS_IMETHODIMP nsSiteSecurityService::RemoveState(uint32_t aType, nsIURI* aURI, uint32_t aFlags) @@ -877,7 +864,7 @@ nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI, // record the successfully parsed header data. nsresult rv = SetHSTSState(aType, aSourceURI, maxAge, foundIncludeSubdomains, - aFlags, SecurityPropertySet); + aFlags); if (NS_FAILED(rv)) { SSSLOG(("SSS: failed to set STS state")); if (aFailureResult) { @@ -901,8 +888,7 @@ nsSiteSecurityService::ProcessSTSHeader(nsIURI* aSourceURI, NS_IMETHODIMP nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI, - uint32_t aFlags, bool* aCached, - bool* aResult) + uint32_t aFlags, bool* aResult) { // Child processes are not allowed direct access to this. if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) { @@ -926,7 +912,7 @@ nsSiteSecurityService::IsSecureURI(uint32_t aType, nsIURI* aURI, return NS_OK; } - return IsSecureHost(aType, hostname.get(), aFlags, aCached, aResult); + return IsSecureHost(aType, hostname.get(), aFlags, aResult); } int STSPreloadCompare(const void *key, const void *entry) @@ -956,8 +942,7 @@ nsSiteSecurityService::GetPreloadListEntry(const char *aHost) NS_IMETHODIMP nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost, - uint32_t aFlags, bool* aCached, - bool* aResult) + uint32_t aFlags, bool* aResult) { // Child processes are not allowed direct access to this. if (!XRE_IsParentProcess() && aType != nsISiteSecurityService::HEADER_HSTS) { @@ -974,9 +959,6 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost, // set default in case if we can't find any STS information *aResult = false; - if (aCached) { - *aCached = false; - } /* An IP address never qualifies as a secure URI. */ if (HostIsIPAddress(aHost)) { @@ -1002,9 +984,6 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost, nsAutoCString host(PublicKeyPinningService::CanonicalizeHostname(aHost)); if (host.EqualsLiteral("chart.apis.google.com") || StringEndsWith(host, NS_LITERAL_CSTRING(".chart.apis.google.com"))) { - if (aCached) { - *aCached = true; - } return NS_OK; } @@ -1028,17 +1007,9 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost, if (siteState.mHSTSState != SecurityPropertyUnset) { SSSLOG(("Found entry for %s", host.get())); bool expired = siteState.IsExpired(aType); - if (!expired) { - if (aCached) { - *aCached = true; - } - if (siteState.mHSTSState == SecurityPropertySet) { - *aResult = true; - return NS_OK; - } else if (siteState.mHSTSState == SecurityPropertyNegative) { - *aResult = false; - return NS_OK; - } + if (!expired && siteState.mHSTSState == SecurityPropertySet) { + *aResult = true; + return NS_OK; } // If the entry is expired and not in the preload list, we can remove it. @@ -1051,9 +1022,6 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost, else if (GetPreloadListEntry(host.get())) { SSSLOG(("%s is a preloaded STS host", host.get())); *aResult = true; - if (aCached) { - *aCached = true; - } return NS_OK; } @@ -1086,17 +1054,9 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost, if (siteState.mHSTSState != SecurityPropertyUnset) { SSSLOG(("Found entry for %s", subdomain)); bool expired = siteState.IsExpired(aType); - if (!expired) { - if (aCached) { - *aCached = true; - } - if (siteState.mHSTSState == SecurityPropertySet) { - *aResult = siteState.mHSTSIncludeSubdomains; - break; - } else if (siteState.mHSTSState == SecurityPropertyNegative) { - *aResult = false; - break; - } + if (!expired && siteState.mHSTSState == SecurityPropertySet) { + *aResult = siteState.mHSTSIncludeSubdomains; + break; } // If the entry is expired and not in the preload list, we can remove it. @@ -1110,9 +1070,6 @@ nsSiteSecurityService::IsSecureHost(uint32_t aType, const char* aHost, if (preload->mIncludeSubdomains) { SSSLOG(("%s is a preloaded STS host", subdomain)); *aResult = true; - if (aCached) { - *aCached = true; - } break; } } diff --git a/security/manager/ssl/nsSiteSecurityService.h b/security/manager/ssl/nsSiteSecurityService.h index 08396964d642..cba010917cb6 100644 --- a/security/manager/ssl/nsSiteSecurityService.h +++ b/security/manager/ssl/nsSiteSecurityService.h @@ -34,8 +34,7 @@ class nsISSLStatus; enum SecurityPropertyState { SecurityPropertyUnset = 0, SecurityPropertySet = 1, - SecurityPropertyKnockout = 2, - SecurityPropertyNegative = 3 + SecurityPropertyKnockout = 2 }; /** @@ -129,8 +128,7 @@ protected: private: nsresult GetHost(nsIURI *aURI, nsACString &aResult); nsresult SetHSTSState(uint32_t aType, nsIURI* aSourceURI, int64_t maxage, - bool includeSubdomains, uint32_t flags, - SecurityPropertyState aHSTSState); + bool includeSubdomains, uint32_t flags); nsresult ProcessHeaderInternal(uint32_t aType, nsIURI* aSourceURI, const char* aHeader, nsISSLStatus* aSSLStatus, uint32_t aFlags, uint64_t* aMaxAge, diff --git a/testing/specialpowers/content/SpecialPowersObserverAPI.js b/testing/specialpowers/content/SpecialPowersObserverAPI.js index e47c478f871c..f2e2d550cfa8 100644 --- a/testing/specialpowers/content/SpecialPowersObserverAPI.js +++ b/testing/specialpowers/content/SpecialPowersObserverAPI.js @@ -324,10 +324,10 @@ SpecialPowersObserverAPI.prototype = { case "BOOL": if (aMessage.json.op == "get") return(prefs.getBoolPref(prefName)); - else + else return(prefs.setBoolPref(prefName, prefValue)); case "INT": - if (aMessage.json.op == "get") + if (aMessage.json.op == "get") return(prefs.getIntPref(prefName)); else return(prefs.setIntPref(prefName, prefValue)); @@ -563,7 +563,6 @@ SpecialPowersObserverAPI.prototype = { let sss = Cc["@mozilla.org/ssservice;1"]. getService(Ci.nsISiteSecurityService); sss.removeState(Ci.nsISiteSecurityService.HEADER_HSTS, uri, flags); - return undefined; } case "SPLoadExtension": { diff --git a/toolkit/components/telemetry/Histograms.json b/toolkit/components/telemetry/Histograms.json index 1a37cacfbe5e..59b0c454341d 100644 --- a/toolkit/components/telemetry/Histograms.json +++ b/toolkit/components/telemetry/Histograms.json @@ -7309,22 +7309,6 @@ "n_values": 10, "description": "How often would blocked mixed content be allowed if HSTS upgrades were allowed? 0=display/no-HSTS, 1=display/HSTS, 2=active/no-HSTS, 3=active/HSTS" }, - "MIXED_CONTENT_HSTS_PRIMING": { - "alert_emails": ["seceng@mozilla.org"], - "bug_numbers": [1246540], - "expires_in_version": "60", - "kind": "enumerated", - "n_values": 16, - "description": "How often would blocked mixed content be allowed if HSTS upgrades were allowed, including how often would we send an HSTS priming request? 0=display/no-HSTS, 1=display/HSTS, 2=active/no-HSTS, 3=active/HSTS, 4=display/no-HSTS-priming, 5=display/do-HSTS-priming, 6=active/no-HSTS-priming, 7=active/do-HSTS-priming" - }, - "MIXED_CONTENT_HSTS_PRIMING_RESULT": { - "alert_emails": ["seceng@mozilla.org"], - "bug_numbers": [1246540], - "expires_in_version": "60", - "kind": "enumerated", - "n_values": 16, - "description": "How often do we get back an HSTS priming result which upgrades the connection to HTTPS? 0=cached (no upgrade), 1=cached (do upgrade), 2=cached (blocked), 3=already upgraded, 4=priming succeeded, 5=priming succeeded (block due to pref), 6=priming succeeded (no upgrade due to pref), 7=priming failed (block), 8=priming failed (accept)" - }, "MIXED_CONTENT_OBJECT_SUBREQUEST": { "alert_emails": ["seceng@mozilla.org"], "bug_numbers": [1244116], From 1fece1e7d70120dca0a401e7d70e0e7572d9ce29 Mon Sep 17 00:00:00 2001 From: Jonathan Watt Date: Sun, 26 Jun 2016 16:34:48 +0100 Subject: [PATCH 122/135] Bug 1265249 - Fix painting of drag selections that contain multiple ranges. r=Bas --- layout/base/nsPresShell.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index beab38ebf87b..81f426a48543 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -5255,7 +5255,7 @@ PresShell::PaintRangePaintInfo(const nsTArray>& aItems gfxPoint rootOffset = nsLayoutUtils::PointToGfxPoint(rangeInfo->mRootOffset, pc->AppUnitsPerDevPixel()); - ctx->SetMatrix(initialTM.Translate(rootOffset)); + ctx->SetMatrix(gfxMatrix(initialTM).Translate(rootOffset)); aArea.MoveBy(-rangeInfo->mRootOffset.x, -rangeInfo->mRootOffset.y); nsRegion visible(aArea); RefPtr layerManager = From a0e21d5deaaec04297cb5d549b40f5d31524bada Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Fri, 22 Jul 2016 14:39:09 +0900 Subject: [PATCH 123/135] Bug 1288616 - Part 1. Remove unused AcquireNativeWindowFromSurfaceTexture / ReleaseNativeWindowForSurfaceTexture. r=snorp MozReview-Commit-ID: 15SfycJX9Wn --HG-- extra : rebase_source : b746aca45f437b56911b8034e8919cc2b8b6ce2c extra : histedit_source : f915d9ce02a3fb564d7ff4593c0a2fe022f22de1 --- widget/android/AndroidBridge.cpp | 25 ------------------------- widget/android/AndroidBridge.h | 3 --- 2 files changed, 28 deletions(-) diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index c11a3d01c858..6b7b1e1e8062 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -1298,31 +1298,6 @@ AndroidBridge::GetNativeWindowSize(void* window) return IntSize(ANativeWindow_getWidth(window), ANativeWindow_getHeight(window)); } -void* -AndroidBridge::AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurfaceTexture) -{ - OpenGraphicsLibraries(); - - if (mHasNativeWindowAccess && ANativeWindow_fromSurfaceTexture) - return ANativeWindow_fromSurfaceTexture(aEnv, aSurfaceTexture); - - if (mHasNativeWindowAccess && android_SurfaceTexture_getNativeWindow) { - android::sp window = android_SurfaceTexture_getNativeWindow(aEnv, aSurfaceTexture); - return window.get(); - } - - return nullptr; -} - -void -AndroidBridge::ReleaseNativeWindowForSurfaceTexture(void *window) -{ - if (!window) - return; - - // FIXME: we don't ref the pointer we get, so nothing to do currently. We should ref it. -} - jobject AndroidBridge::GetGlobalContextRef() { if (sGlobalContext) { diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index 50ac8b566bb8..1d019e1e30e8 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -232,9 +232,6 @@ public: void ReleaseNativeWindow(void *window); mozilla::gfx::IntSize GetNativeWindowSize(void* window); - void *AcquireNativeWindowFromSurfaceTexture(JNIEnv* aEnv, jobject aSurface); - void ReleaseNativeWindowForSurfaceTexture(void *window); - void HandleGeckoMessage(JSContext* cx, JS::HandleObject message); bool InitCamera(const nsCString& contentType, uint32_t camera, uint32_t *width, uint32_t *height, uint32_t *fps); From 36599f24c5271b253c53a406d32c42a09f34571d Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Fri, 22 Jul 2016 14:40:42 +0900 Subject: [PATCH 124/135] Bug 1288616 - Part 2. Remove unused ANativeWindow_fromSurfaceTexture and android_SurfaceTexture_getNativeWindow. r=snorp MozReview-Commit-ID: 40rPBLzoLPO --HG-- extra : rebase_source : 4ab9b4a45610df1be14c764a9927f78cc2d0a4a9 extra : histedit_source : 6f6821be672f77c57352355390eab6b0ab909ce1 --- widget/android/AndroidBridge.cpp | 13 -- widget/android/AndroidBridge.h | 1 - widget/android/android/StrongPointer.h | 239 ------------------------- widget/android/moz.build | 1 - 4 files changed, 254 deletions(-) delete mode 100644 widget/android/android/StrongPointer.h diff --git a/widget/android/AndroidBridge.cpp b/widget/android/AndroidBridge.cpp index 6b7b1e1e8062..aac716ccb5d9 100644 --- a/widget/android/AndroidBridge.cpp +++ b/widget/android/AndroidBridge.cpp @@ -36,7 +36,6 @@ #include "mozilla/dom/ScreenOrientation.h" #include "nsIDOMWindowUtils.h" #include "nsIDOMClientRect.h" -#include "StrongPointer.h" #include "mozilla/ClearOnShutdown.h" #include "nsPrintfCString.h" #include "NativeJSContainer.h" @@ -70,9 +69,6 @@ class AndroidRefable { void decStrong(void* thing) { } }; -// This isn't in AndroidBridge.h because including StrongPointer.h there is gross -static android::sp (*android_SurfaceTexture_getNativeWindow)(JNIEnv* env, jobject surfaceTexture) = nullptr; - jclass AndroidBridge::GetClassGlobalRef(JNIEnv* env, const char* className) { // First try the default class loader. @@ -728,20 +724,11 @@ AndroidBridge::OpenGraphicsLibraries() ANativeWindow_getWidth = (int (*)(void*))dlsym(handle, "ANativeWindow_getWidth"); ANativeWindow_getHeight = (int (*)(void*))dlsym(handle, "ANativeWindow_getHeight"); - // This is only available in Honeycomb and ICS. It was removed in Jelly Bean - ANativeWindow_fromSurfaceTexture = (void* (*)(JNIEnv*, jobject))dlsym(handle, "ANativeWindow_fromSurfaceTexture"); - mHasNativeWindowAccess = ANativeWindow_fromSurface && ANativeWindow_release; ALOG_BRIDGE("Successfully opened libandroid.so, have native window access? %d", mHasNativeWindowAccess); } - // We need one symbol from here on Jelly Bean - handle = dlopen("libandroid_runtime.so", RTLD_LAZY | RTLD_LOCAL); - if (handle) { - android_SurfaceTexture_getNativeWindow = (android::sp (*)(JNIEnv*, jobject))dlsym(handle, "_ZN7android38android_SurfaceTexture_getNativeWindowEP7_JNIEnvP8_jobject"); - } - if (mHasNativeWindowAccess) return; diff --git a/widget/android/AndroidBridge.h b/widget/android/AndroidBridge.h index 1d019e1e30e8..61b6b4c40741 100644 --- a/widget/android/AndroidBridge.h +++ b/widget/android/AndroidBridge.h @@ -400,7 +400,6 @@ protected: int (* AndroidBitmap_unlockPixels)(JNIEnv *env, jobject bitmap); void* (*ANativeWindow_fromSurface)(JNIEnv *env, jobject surface); - void* (*ANativeWindow_fromSurfaceTexture)(JNIEnv *env, jobject surfaceTexture); void (*ANativeWindow_release)(void *window); int (*ANativeWindow_setBuffersGeometry)(void *window, int width, int height, int format); diff --git a/widget/android/android/StrongPointer.h b/widget/android/android/StrongPointer.h deleted file mode 100644 index ca79fdfa4d9a..000000000000 --- a/widget/android/android/StrongPointer.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright (C) 2005 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/************************************************************************* - * - * WARNING: EVERYTHING HERE IS NEUTERED - * - * The only reason we need this is to be able to call - * android_SurfaceTexture_getNativeWindow, which returns a - * android::sp. Therefore, we need the definition of - * android::sp (below) in order to get the pointer out. All of the actual - * ref management stuff is commented out by Mozilla. Do not try to use this - * for anything real. - */ - -#ifndef ANDROID_STRONG_POINTER_H -#define ANDROID_STRONG_POINTER_H - -#include -#include -#include - -// --------------------------------------------------------------------------- -namespace android { - -class TextOutput; -TextOutput& printStrongPointer(TextOutput& to, const void* val); - -template class wp; - -// --------------------------------------------------------------------------- - -#define COMPARE(_op_) \ -inline bool operator _op_ (const sp& o) const { \ - return m_ptr _op_ o.m_ptr; \ -} \ -inline bool operator _op_ (const T* o) const { \ - return m_ptr _op_ o; \ -} \ -template \ -inline bool operator _op_ (const sp& o) const { \ - return m_ptr _op_ o.m_ptr; \ -} \ -template \ -inline bool operator _op_ (const U* o) const { \ - return m_ptr _op_ o; \ -} \ -inline bool operator _op_ (const wp& o) const { \ - return m_ptr _op_ o.m_ptr; \ -} \ -template \ -inline bool operator _op_ (const wp& o) const { \ - return m_ptr _op_ o.m_ptr; \ -} - -// --------------------------------------------------------------------------- - -template -class sp -{ -public: - inline sp() : m_ptr(0) { } - - sp(T* other); - sp(const sp& other); - template sp(U* other); - template sp(const sp& other); - - ~sp(); - - // Assignment - - sp& operator = (T* other); - sp& operator = (const sp& other); - - template sp& operator = (const sp& other); - template sp& operator = (U* other); - - //! Special optimization for use by ProcessState (and nobody else). - void force_set(T* other); - - // Reset - - void clear(); - - // Accessors - - inline T& operator* () const { return *m_ptr; } - inline T* operator-> () const { return m_ptr; } - inline T* get() const { return m_ptr; } - - // Operators - - COMPARE(==) - COMPARE(!=) - COMPARE(>) - COMPARE(<) - COMPARE(<=) - COMPARE(>=) - -private: - template friend class sp; - template friend class wp; - void set_pointer(T* ptr); - T* m_ptr; -}; - -#undef COMPARE - -template -TextOutput& operator<<(TextOutput& to, const sp& val); - -// --------------------------------------------------------------------------- -// No user serviceable parts below here. - -template -sp::sp(T* other) -: m_ptr(other) - { - //if (other) other->incStrong(this); - } - -template -sp::sp(const sp& other) -: m_ptr(other.m_ptr) - { - //if (m_ptr) m_ptr->incStrong(this); - } - -template template -sp::sp(U* other) : m_ptr(other) -{ - //if (other) ((T*)other)->incStrong(this); -} - -template template -sp::sp(const sp& other) -: m_ptr(other.m_ptr) - { - //if (m_ptr) m_ptr->incStrong(this); - } - -template -sp::~sp() -{ - //if (m_ptr) m_ptr->decStrong(this); -} - -template -sp& sp::operator = (const sp& other) { - T* otherPtr(other.m_ptr); - /* - if (otherPtr) otherPtr->incStrong(this); - if (m_ptr) m_ptr->decStrong(this); - */ - m_ptr = otherPtr; - return *this; -} - -template -sp& sp::operator = (T* other) -{ - /* - if (other) other->incStrong(this); - if (m_ptr) m_ptr->decStrong(this); - */ - m_ptr = other; - return *this; -} - -template template -sp& sp::operator = (const sp& other) -{ - T* otherPtr(other.m_ptr); - /* - if (otherPtr) otherPtr->incStrong(this); - if (m_ptr) m_ptr->decStrong(this); - */ - m_ptr = otherPtr; - return *this; -} - -template template -sp& sp::operator = (U* other) -{ - /* - if (other) ((T*)other)->incStrong(this); - if (m_ptr) m_ptr->decStrong(this); - */ - m_ptr = other; - return *this; -} - -template -void sp::force_set(T* other) -{ - //other->forceIncStrong(this); - m_ptr = other; -} - -template -void sp::clear() -{ - if (m_ptr) { - m_ptr->decStrong(this); - m_ptr = 0; - } -} - -template -void sp::set_pointer(T* ptr) { - m_ptr = ptr; -} - -template -inline TextOutput& operator<<(TextOutput& to, const sp& val) -{ - return printStrongPointer(to, val.get()); -} - -}; // namespace android - -// --------------------------------------------------------------------------- - -#endif // ANDROID_STRONG_POINTER_H diff --git a/widget/android/moz.build b/widget/android/moz.build index c5d52912f0a7..6f4e36ec86ef 100644 --- a/widget/android/moz.build +++ b/widget/android/moz.build @@ -58,7 +58,6 @@ LOCAL_INCLUDES += [ '/netwerk/base', '/netwerk/cache', '/widget', - '/widget/android/android', ] CXXFLAGS += ['-Wno-error=shadow'] From ef68295847cbea79e6d1fecf2eacc2665d4a8295 Mon Sep 17 00:00:00 2001 From: Matt Woodrow Date: Mon, 25 Jul 2016 14:41:25 +1200 Subject: [PATCH 125/135] Bug 1217803 - Always build a mask layer if we have rounded corners, regardless of the visible region since this might change on the compositor. r=mstange --HG-- extra : rebase_source : f874a7effd7c0985718c45be2343ca86586ac4bd --- layout/base/FrameLayerBuilder.cpp | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/layout/base/FrameLayerBuilder.cpp b/layout/base/FrameLayerBuilder.cpp index 2e6c38b1774b..e794d3764fd6 100644 --- a/layout/base/FrameLayerBuilder.cpp +++ b/layout/base/FrameLayerBuilder.cpp @@ -1336,14 +1336,12 @@ protected: * Builds an ImageLayer for the appropriate backend; the mask is relative to * aLayer's visible region. * aLayer is the layer to be clipped. - * aLayerVisibleRegion is the region that will be set as aLayer's visible region, * relative to the container reference frame * aRoundedRectClipCount is used when building mask layers for PaintedLayers, * SetupMaskLayer will build a mask layer for only the first * aRoundedRectClipCount rounded rects in aClip */ void SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip, - const nsIntRegion& aLayerVisibleRegion, uint32_t aRoundedRectClipCount = UINT32_MAX); /** @@ -3192,7 +3190,7 @@ void ContainerState::FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueB commonClipCount = data->mItemClip.GetRoundedRectCount(); } else { commonClipCount = std::max(0, data->mCommonClipCount); - SetupMaskLayer(layer, data->mItemClip, data->mVisibleRegion, commonClipCount); + SetupMaskLayer(layer, data->mItemClip, commonClipCount); } // copy commonClipCount to the entry FrameLayerBuilder::PaintedLayerItemsEntry* entry = mLayerBuilder-> @@ -3200,7 +3198,7 @@ void ContainerState::FinishPaintedLayerData(PaintedLayerData& aData, FindOpaqueB entry->mCommonClipCount = commonClipCount; } else { // mask layer for image and color layers - SetupMaskLayer(layer, data->mItemClip, data->mVisibleRegion); + SetupMaskLayer(layer, data->mItemClip); } uint32_t flags = 0; @@ -4123,13 +4121,13 @@ ContainerState::ProcessDisplayItems(nsDisplayList* aList) // rounded rectangle clipping using mask layers // (must be done after visible rect is set on layer) - if (layerClip.IsRectClippedByRoundedCorner(itemContent)) { - SetupMaskLayer(ownLayer, layerClip, itemVisibleRect); + if (layerClip.GetRoundedRectCount() > 0) { + SetupMaskLayer(ownLayer, layerClip); } } else { LayerClip scrolledClip; scrolledClip.SetClipRect(layerClipRect); - if (layerClip.IsRectClippedByRoundedCorner(itemContent)) { + if (layerClip.GetRoundedRectCount() > 0) { scrolledClip.SetMaskLayerIndex( SetupMaskLayerForScrolledClip(ownLayer.get(), layerClip)); } @@ -5988,7 +5986,6 @@ SetClipCount(PaintedDisplayItemLayerUserData* apaintedData, void ContainerState::SetupMaskLayer(Layer *aLayer, const DisplayItemClip& aClip, - const nsIntRegion& aLayerVisibleRegion, uint32_t aRoundedRectClipCount) { // if the number of clips we are going to mask has decreased, then aLayer might have @@ -6002,10 +5999,8 @@ ContainerState::SetupMaskLayer(Layer *aLayer, } // don't build an unnecessary mask - nsIntRect layerBounds = aLayerVisibleRegion.GetBounds(); if (aClip.GetRoundedRectCount() == 0 || - aRoundedRectClipCount == 0 || - layerBounds.IsEmpty()) { + aRoundedRectClipCount == 0) { SetClipCount(paintedData, 0); return; } From 06b363b5be45a36466fb170658a93ea14e5880af Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Fri, 1 Jul 2016 15:37:37 +0900 Subject: [PATCH 126/135] Bug 1094729 - Part 1. Add utility function to convert Gecko's coords to Layer view coords. r=snorp MozReview-Commit-ID: 7CzyHQkVVDz --HG-- extra : rebase_source : 5c19e53fdc5b2bc544648cea9bc46b2394681d0c --- .../mozilla/gecko/gfx/GeckoLayerClient.java | 21 +++++++++++++++++++ .../java/org/mozilla/gecko/gfx/LayerView.java | 5 +++++ .../org/mozilla/gecko/gfx/PanZoomTarget.java | 3 ++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/mobile/android/base/java/org/mozilla/gecko/gfx/GeckoLayerClient.java b/mobile/android/base/java/org/mozilla/gecko/gfx/GeckoLayerClient.java index 220474f3c744..ef1598bb401f 100644 --- a/mobile/android/base/java/org/mozilla/gecko/gfx/GeckoLayerClient.java +++ b/mobile/android/base/java/org/mozilla/gecko/gfx/GeckoLayerClient.java @@ -18,6 +18,7 @@ import org.mozilla.gecko.util.FloatUtils; import org.mozilla.gecko.AppConstants; import android.content.Context; +import android.graphics.Matrix; import android.graphics.PointF; import android.graphics.RectF; import android.os.SystemClock; @@ -1166,6 +1167,26 @@ class GeckoLayerClient implements LayerView.Listener, PanZoomTarget return layerPoint; } + @Override + public Matrix getMatrixForLayerRectToViewRect() { + if (!mGeckoIsReady) { + return null; + } + + ImmutableViewportMetrics viewportMetrics = mViewportMetrics; + PointF origin = viewportMetrics.getOrigin(); + float zoom = viewportMetrics.zoomFactor; + ImmutableViewportMetrics geckoViewport = (AppConstants.MOZ_ANDROID_APZ ? mViewportMetrics : mGeckoViewport); + PointF geckoOrigin = geckoViewport.getOrigin(); + float geckoZoom = geckoViewport.zoomFactor; + + Matrix matrix = new Matrix(); + matrix.postTranslate(geckoOrigin.x / geckoZoom, geckoOrigin.y / geckoZoom); + matrix.postScale(zoom, zoom); + matrix.postTranslate(-origin.x, -origin.y); + return matrix; + } + @Override public void setScrollingRootContent(boolean isRootContent) { mToolbarAnimator.setScrollingRootContent(isRootContent); diff --git a/mobile/android/base/java/org/mozilla/gecko/gfx/LayerView.java b/mobile/android/base/java/org/mozilla/gecko/gfx/LayerView.java index 1ac98b510d3f..c755bfa4cf37 100644 --- a/mobile/android/base/java/org/mozilla/gecko/gfx/LayerView.java +++ b/mobile/android/base/java/org/mozilla/gecko/gfx/LayerView.java @@ -25,6 +25,7 @@ import org.mozilla.gecko.ZoomConstraints; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; +import android.graphics.Matrix; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; @@ -352,6 +353,10 @@ public class LayerView extends ScrollView implements Tabs.OnTabsChangedListener return mLayerClient.convertViewPointToLayerPoint(viewPoint); } + public Matrix getMatrixForLayerRectToViewRect() { + return mLayerClient.getMatrixForLayerRectToViewRect(); + } + int getBackgroundColor() { return mBackgroundColor; } diff --git a/mobile/android/base/java/org/mozilla/gecko/gfx/PanZoomTarget.java b/mobile/android/base/java/org/mozilla/gecko/gfx/PanZoomTarget.java index b276e781e536..3c70d6aed3af 100644 --- a/mobile/android/base/java/org/mozilla/gecko/gfx/PanZoomTarget.java +++ b/mobile/android/base/java/org/mozilla/gecko/gfx/PanZoomTarget.java @@ -7,8 +7,8 @@ package org.mozilla.gecko.gfx; import org.mozilla.gecko.ZoomConstraints; +import android.graphics.Matrix; import android.graphics.PointF; -import android.graphics.RectF; public interface PanZoomTarget { public ImmutableViewportMetrics getViewportMetrics(); @@ -28,5 +28,6 @@ public interface PanZoomTarget { public void removeRenderTask(RenderTask task); public Object getLock(); public PointF convertViewPointToLayerPoint(PointF viewPoint); + public Matrix getMatrixForLayerRectToViewRect(); public void setScrollingRootContent(boolean isRootContent); } From b1da9d4a6cd222d80739b4f54a11bad8b324b7e2 Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Wed, 20 Jul 2016 16:19:05 +0900 Subject: [PATCH 127/135] Bug 1094729 - Part 2. Support floating candidate window for hardware keyboard on Android 5+. r=jchen MozReview-Commit-ID: G148os7J9wO --HG-- extra : rebase_source : 1cbf1cb1a2a6897439effa7f3edf720adc184e15 extra : histedit_source : 2d84917b32d5eca4066e426f94ece36e81c0bdea --- .../java/org/mozilla/gecko/GeckoEditable.java | 27 ++++++ .../mozilla/gecko/GeckoEditableClient.java | 11 +++ .../mozilla/gecko/GeckoEditableListener.java | 2 + .../mozilla/gecko/GeckoInputConnection.java | 96 +++++++++++++++++++ widget/android/GeneratedJNINatives.h | 6 +- widget/android/GeneratedJNIWrappers.cpp | 11 +++ widget/android/GeneratedJNIWrappers.h | 30 ++++++ widget/android/nsWindow.cpp | 75 +++++++++++++++ 8 files changed, 257 insertions(+), 1 deletion(-) diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoEditable.java b/mobile/android/base/java/org/mozilla/gecko/GeckoEditable.java index f1f4229a3b1f..381cf82d1302 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoEditable.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoEditable.java @@ -23,6 +23,7 @@ import org.mozilla.gecko.util.GeckoEventListener; import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils.AssertBehavior; +import android.graphics.RectF; import android.os.Handler; import android.os.Looper; import android.text.Editable; @@ -143,6 +144,9 @@ final class GeckoEditable extends JNIObject @WrapForJNI private native void onImeUpdateComposition(int start, int end); + @WrapForJNI + private native void onImeRequestCursorUpdates(int requestMode); + /* An action that alters the Editable Each action corresponds to a Gecko event. While the Gecko event is being sent to the Gecko @@ -779,6 +783,11 @@ final class GeckoEditable extends JNIObject mIcPostHandler.post(runnable); } + @Override // GeckoEditableClient + public void requestCursorUpdates(int requestMode) { + onImeRequestCursorUpdates(requestMode); + } + private void geckoSetIcHandler(final Handler newHandler) { geckoPostToIc(new Runnable() { // posting to old IC thread @Override @@ -1140,6 +1149,24 @@ final class GeckoEditable extends JNIObject }); } + @WrapForJNI @Override + public void updateCompositionRects(final RectF[] aRects) { + if (DEBUG) { + // GeckoEditableListener methods should all be called from the Gecko thread + ThreadUtils.assertOnGeckoThread(); + Log.d(LOGTAG, "updateCompositionRects(aRects.length = " + aRects.length + ")"); + } + geckoPostToIc(new Runnable() { + @Override + public void run() { + if (mListener == null) { + return; + } + mListener.updateCompositionRects(aRects); + } + }); + } + // InvocationHandler interface static String getConstantName(Class cls, String prefix, Object value) { diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoEditableClient.java b/mobile/android/base/java/org/mozilla/gecko/GeckoEditableClient.java index 2cc94a196984..5e721b3af221 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoEditableClient.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoEditableClient.java @@ -19,4 +19,15 @@ interface GeckoEditableClient { void setSuppressKeyUp(boolean suppress); Handler setInputConnectionHandler(Handler handler); void postToInputConnection(Runnable runnable); + + // The following value is used by requestCursorUpdates + + // ONE_SHOT calls updateCompositionRects() after getting current composing character rects. + public static final int ONE_SHOT = 1; + // START_MONITOR start the monitor for composing character rects. If is is updaed, call updateCompositionRects() + public static final int START_MONITOR = 2; + // ENDT_MONITOR stops the monitor for composing character rects. + public static final int END_MONITOR = 3; + + void requestCursorUpdates(int requestMode); } diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoEditableListener.java b/mobile/android/base/java/org/mozilla/gecko/GeckoEditableListener.java index 1f34551a3d37..b4b0239381d3 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoEditableListener.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoEditableListener.java @@ -7,6 +7,7 @@ package org.mozilla.gecko; import org.mozilla.gecko.annotation.WrapForJNI; +import android.graphics.RectF; import android.view.KeyEvent; /** @@ -38,4 +39,5 @@ interface GeckoEditableListener { void onSelectionChange(int start, int end); void onTextChange(CharSequence text, int start, int oldEnd, int newEnd); void onDefaultKeyEvent(KeyEvent event); + void updateCompositionRects(final RectF[] aRects); } diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoInputConnection.java b/mobile/android/base/java/org/mozilla/gecko/GeckoInputConnection.java index 5ec056de97b6..39bdcfc3f38a 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoInputConnection.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoInputConnection.java @@ -11,14 +11,18 @@ import java.lang.reflect.Proxy; import java.util.concurrent.SynchronousQueue; import org.mozilla.gecko.AppConstants.Versions; +import org.mozilla.gecko.gfx.DynamicToolbarAnimator; import org.mozilla.gecko.util.Clipboard; import org.mozilla.gecko.util.GamepadUtils; import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils.AssertBehavior; import android.annotation.SuppressLint; +import android.anontation.TargetApi; import android.content.Context; import android.content.res.Configuration; +import android.graphics.Matrix; +import android.graphics.RectF; import android.media.AudioManager; import android.os.Bundle; import android.os.Handler; @@ -35,6 +39,7 @@ import android.util.Log; import android.view.KeyEvent; import android.view.View; import android.view.inputmethod.BaseInputConnection; +import android.view.inputmethod.CursorAnchorInfo; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; @@ -72,6 +77,7 @@ class GeckoInputConnection private boolean mBatchSelectionChanged; private boolean mBatchTextChanged; private final InputConnection mKeyInputConnection; + private CursorAnchorInfo.Builder mCursorAnchorInfoBuilder; // Prevent showSoftInput and hideSoftInput from causing reentrant calls on some devices. private volatile boolean mSoftInputReentrancyGuard; @@ -391,6 +397,96 @@ class GeckoInputConnection getComposingSpanEnd(editable)); } + @Override + public void updateCompositionRects(final RectF[] aRects) { + if (!Versions.feature21Plus) { + return; + } + + if (mCursorAnchorInfoBuilder == null) { + mCursorAnchorInfoBuilder = new CursorAnchorInfo.Builder(); + } + mCursorAnchorInfoBuilder.reset(); + + // Calculate Gecko logical coords to screen coords + final View v = getView(); + if (v == null) { + return; + } + + int[] viewCoords = new int[2]; + v.getLocationOnScreen(viewCoords); + + DynamicToolbarAnimator animator = GeckoAppShell.getLayerView().getDynamicToolbarAnimator(); + float toolbarHeight = animator.getMaxTranslation() - animator.getToolbarTranslation(); + + Matrix matrix = GeckoAppShell.getLayerView().getMatrixForLayerRectToViewRect(); + if (matrix == null) { + if (DEBUG) { + Log.d(LOGTAG, "Cannot get Matrix to convert from Gecko coords to layer view coords"); + } + return; + } + matrix.postTranslate(viewCoords[0], viewCoords[1] + toolbarHeight); + mCursorAnchorInfoBuilder.setMatrix(matrix); + + final Editable content = getEditable(); + if (content == null) { + return; + } + int composingStart = getComposingSpanStart(content); + int composingEnd = getComposingSpanEnd(content); + if (composingStart < 0 || composingEnd < 0) { + if (DEBUG) { + Log.d(LOGTAG, "No composition for updates"); + } + return; + } + + for (int i = 0; i < aRects.length; i++) { + mCursorAnchorInfoBuilder.addCharacterBounds(i, + aRects[i].left, + aRects[i].top, + aRects[i].right, + aRects[i].bottom, + CursorAnchorInfo.FLAG_HAS_VISIBLE_REGION); + } + + mCursorAnchorInfoBuilder.setComposingText(0, content.subSequence(composingStart, composingEnd)); + + updateCursor(); + } + + @TargetApi(21) + private void updateCursor() { + if (mCursorAnchorInfoBuilder == null) { + return; + } + + final InputMethodManager imm = getInputMethodManager(); + final View v = getView(); + if (imm == null || v == null) { + return; + } + + imm.updateCursorAnchorInfo(v, mCursorAnchorInfoBuilder.build()); + } + + @Override + public boolean requestCursorUpdates(int cursorUpdateMode) { + + if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_IMMEDIATE) != 0) { + mEditableClient.requestCursorUpdates(GeckoEditableClient.ONE_SHOT); + } + + if ((cursorUpdateMode & InputConnection.CURSOR_UPDATE_MONITOR) != 0) { + mEditableClient.requestCursorUpdates(GeckoEditableClient.START_MONITOR); + } else { + mEditableClient.requestCursorUpdates(GeckoEditableClient.END_MONITOR); + } + return true; + } + @Override public void onDefaultKeyEvent(final KeyEvent event) { ThreadUtils.postToUiThread(new Runnable() { diff --git a/widget/android/GeneratedJNINatives.h b/widget/android/GeneratedJNINatives.h index b993990ee905..a5b244078866 100644 --- a/widget/android/GeneratedJNINatives.h +++ b/widget/android/GeneratedJNINatives.h @@ -86,7 +86,7 @@ template class GeckoEditable::Natives : public mozilla::jni::NativeImpl { public: - static const JNINativeMethod methods[7]; + static const JNINativeMethod methods[8]; }; template @@ -108,6 +108,10 @@ const JNINativeMethod GeckoEditable::Natives::methods[] = { mozilla::jni::NativeStub ::template Wrap<&Impl::OnImeReplaceText>), + mozilla::jni::MakeNativeMethod( + mozilla::jni::NativeStub + ::template Wrap<&Impl::OnImeRequestCursorUpdates>), + mozilla::jni::MakeNativeMethod( mozilla::jni::NativeStub ::template Wrap<&Impl::OnImeSynchronize>), diff --git a/widget/android/GeneratedJNIWrappers.cpp b/widget/android/GeneratedJNIWrappers.cpp index 50d4c4a907de..5e33577d0297 100644 --- a/widget/android/GeneratedJNIWrappers.cpp +++ b/widget/android/GeneratedJNIWrappers.cpp @@ -808,6 +808,9 @@ constexpr char GeckoEditable::OnImeAddCompositionRange_t::signature[]; constexpr char GeckoEditable::OnImeReplaceText_t::name[]; constexpr char GeckoEditable::OnImeReplaceText_t::signature[]; +constexpr char GeckoEditable::OnImeRequestCursorUpdates_t::name[]; +constexpr char GeckoEditable::OnImeRequestCursorUpdates_t::signature[]; + constexpr char GeckoEditable::OnImeSynchronize_t::name[]; constexpr char GeckoEditable::OnImeSynchronize_t::signature[]; @@ -841,6 +844,14 @@ auto GeckoEditable::OnViewChange(mozilla::jni::Object::Param a0) const -> void return mozilla::jni::Method::Call(GeckoEditable::mCtx, nullptr, a0); } +constexpr char GeckoEditable::UpdateCompositionRects_t::name[]; +constexpr char GeckoEditable::UpdateCompositionRects_t::signature[]; + +auto GeckoEditable::UpdateCompositionRects(mozilla::jni::ObjectArray::Param a0) const -> void +{ + return mozilla::jni::Method::Call(GeckoEditable::mCtx, nullptr, a0); +} + const char GeckoEditableListener::name[] = "org/mozilla/gecko/GeckoEditableListener"; diff --git a/widget/android/GeneratedJNIWrappers.h b/widget/android/GeneratedJNIWrappers.h index 1584571cd14f..79fbd2d297ed 100644 --- a/widget/android/GeneratedJNIWrappers.h +++ b/widget/android/GeneratedJNIWrappers.h @@ -1781,6 +1781,20 @@ public: mozilla::jni::ExceptionMode::ABORT; }; + struct OnImeRequestCursorUpdates_t { + typedef GeckoEditable Owner; + typedef void ReturnType; + typedef void SetterType; + typedef mozilla::jni::Args< + int32_t> Args; + static constexpr char name[] = "onImeRequestCursorUpdates"; + static constexpr char signature[] = + "(I)V"; + static const bool isStatic = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + struct OnImeSynchronize_t { typedef GeckoEditable Owner; typedef void ReturnType; @@ -1886,6 +1900,22 @@ public: auto OnViewChange(mozilla::jni::Object::Param) const -> void; + struct UpdateCompositionRects_t { + typedef GeckoEditable Owner; + typedef void ReturnType; + typedef void SetterType; + typedef mozilla::jni::Args< + mozilla::jni::ObjectArray::Param> Args; + static constexpr char name[] = "updateCompositionRects"; + static constexpr char signature[] = + "([Landroid/graphics/RectF;)V"; + static const bool isStatic = false; + static const mozilla::jni::ExceptionMode exceptionMode = + mozilla::jni::ExceptionMode::ABORT; + }; + + auto UpdateCompositionRects(mozilla::jni::ObjectArray::Param) const -> void; + static const bool isMultithreaded = false; template class Natives; diff --git a/widget/android/nsWindow.cpp b/widget/android/nsWindow.cpp index d504e5a2c26d..0388f2c19661 100644 --- a/widget/android/nsWindow.cpp +++ b/widget/android/nsWindow.cpp @@ -114,6 +114,11 @@ static bool sFailedToCreateGLContext = false; static const double SWIPE_MAX_PINCH_DELTA_INCHES = 0.4; static const double SWIPE_MIN_DISTANCE_INCHES = 0.6; +// Sync with GeckoEditableView class +static const int IME_MONITOR_CURSOR_ONE_SHOT = 1; +static const int IME_MONITOR_CURSOR_START_MONITOR = 2; +static const int IME_MONITOR_CURSOR_END_MONITOR = 3; + static Modifiers GetModifiers(int32_t metaState); template @@ -220,6 +225,7 @@ public: , mIMEUpdatingContext(false) , mIMESelectionChanged(false) , mIMETextChangedDuringFlush(false) + , mIMEMonitorCursor(false) { Base::AttachNative(aInstance, this); EditableBase::AttachNative(mEditable, this); @@ -299,6 +305,7 @@ private: bool mIMEUpdatingContext; bool mIMESelectionChanged; bool mIMETextChangedDuringFlush; + bool mIMEMonitorCursor; void SendIMEDummyKeyEvents(); void AddIMETextChange(const IMETextChange& aChange); @@ -310,6 +317,7 @@ private: void PostFlushIMEChanges(); void FlushIMEChanges(FlushChangesFlag aFlags = FLUSH_FLAG_NONE); void AsyncNotifyIME(int32_t aNotification); + void UpdateCompositionRects(); public: bool NotifyIME(const IMENotification& aIMENotification); @@ -351,6 +359,9 @@ public: // Update styling for the active composition using previous-added ranges. void OnImeUpdateComposition(int32_t aStart, int32_t aEnd); + + // Set cursor mode whether IME requests + void OnImeRequestCursorUpdates(int aRequestMode); }; /** @@ -2898,6 +2909,46 @@ nsWindow::GeckoViewSupport::FlushIMEChanges(FlushChangesFlag aFlags) } } +static jni::ObjectArray::LocalRef +ConvertRectArrayToJavaRectFArray(JNIEnv* aJNIEnv, const nsTArray& aRects, const LayoutDeviceIntPoint& aOffset, const CSSToLayoutDeviceScale aScale) +{ + size_t length = aRects.Length(); + jobjectArray rects = aJNIEnv->NewObjectArray(length, sdk::RectF::Context().ClassRef(), nullptr); + auto rectsRef = jni::ObjectArray::LocalRef::Adopt(aJNIEnv, rects); + for (size_t i = 0; i < length; i++) { + sdk::RectF::LocalRef rect(aJNIEnv); + LayoutDeviceIntRect tmp = aRects[i] + aOffset; + sdk::RectF::New(tmp.x / aScale.scale, tmp.y / aScale.scale, + (tmp.x + tmp.width) / aScale.scale, + (tmp.y + tmp.height) / aScale.scale, + &rect); + rectsRef->SetElement(i, rect); + } + return rectsRef; +} + +void +nsWindow::GeckoViewSupport::UpdateCompositionRects() +{ + const auto composition(window.GetIMEComposition()); + if (NS_WARN_IF(!composition)) { + return; + } + + uint32_t offset = composition->NativeOffsetOfStartComposition(); + WidgetQueryContentEvent textRects(true, eQueryTextRectArray, &window); + textRects.InitForQueryTextRectArray(offset, composition->String().Length()); + window.DispatchEvent(&textRects); + + auto rects = + ConvertRectArrayToJavaRectFArray(jni::GetGeckoThreadEnv(), + textRects.mReply.mRectArray, + window.WidgetToScreenOffset(), + window.GetDefaultScale()); + + mEditable->UpdateCompositionRects(rects); +} + void nsWindow::GeckoViewSupport::AsyncNotifyIME(int32_t aNotification) { @@ -2949,6 +3000,9 @@ nsWindow::GeckoViewSupport::NotifyIME(const IMENotification& aIMENotification) case NOTIFY_IME_OF_FOCUS: { ALOGIME("IME: NOTIFY_IME_OF_FOCUS"); + // IME will call requestCursorUpdates after getting context. + // So reset cursor update mode before getting context. + mIMEMonitorCursor = false; mEditable->NotifyIME(GeckoEditableListener::NOTIFY_IME_OF_FOCUS); return true; } @@ -2986,6 +3040,16 @@ nsWindow::GeckoViewSupport::NotifyIME(const IMENotification& aIMENotification) return true; } + case NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED: { + ALOGIME("IME: NOTIFY_IME_OF_COMPOSITION_EVENT_HANDLED"); + + // Hardware keyboard support requires each string rect. + if (AndroidBridge::Bridge() && AndroidBridge::Bridge()->GetAPIVersion() >= 21 && mIMEMonitorCursor) { + UpdateCompositionRects(); + } + return true; + } + default: return false; } @@ -3339,6 +3403,17 @@ nsWindow::GeckoViewSupport::OnImeUpdateComposition(int32_t aStart, int32_t aEnd) } } +void +nsWindow::GeckoViewSupport::OnImeRequestCursorUpdates(int aRequestMode) +{ + if (aRequestMode == IME_MONITOR_CURSOR_ONE_SHOT) { + UpdateCompositionRects(); + return; + } + + mIMEMonitorCursor = (aRequestMode == IME_MONITOR_CURSOR_START_MONITOR); +} + void nsWindow::UserActivity() { From 92509cea830cd2f445ec52325627b45d7296dd12 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 25 Jul 2016 09:25:08 +0200 Subject: [PATCH 128/135] Bug 1287091 - part 1 - ContextualIdentityService should use a storage for the containers, r=Gijs --- browser/base/content/browser.js | 3 +- browser/base/content/nsContextMenu.js | 3 +- browser/base/content/utilityOverlay.js | 4 +- .../ContextualIdentityService.jsm | 118 +++++++++++++++++- 4 files changed, 118 insertions(+), 10 deletions(-) diff --git a/browser/base/content/browser.js b/browser/base/content/browser.js index 511178b5e7de..fc58acb41e35 100755 --- a/browser/base/content/browser.js +++ b/browser/base/content/browser.js @@ -8,6 +8,7 @@ var Cu = Components.utils; var Cc = Components.classes; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/ContextualIdentityService.jsm"); Cu.import("resource://gre/modules/NotificationDB.jsm"); Cu.import("resource:///modules/RecentWindow.jsm"); @@ -56,8 +57,6 @@ XPCOMUtils.defineLazyServiceGetter(this, "WindowsUIUtils", "@mozilla.org/windows-ui-utils;1", "nsIWindowsUIUtils"); XPCOMUtils.defineLazyModuleGetter(this, "LightweightThemeManager", "resource://gre/modules/LightweightThemeManager.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", - "resource://gre/modules/ContextualIdentityService.jsm"); XPCOMUtils.defineLazyServiceGetter(this, "gAboutNewTabService", "@mozilla.org/browser/aboutnewtab-service;1", "nsIAboutNewTabService"); diff --git a/browser/base/content/nsContextMenu.js b/browser/base/content/nsContextMenu.js index 124847b00beb..263b13737dcb 100644 --- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -4,6 +4,7 @@ # 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/. +Components.utils.import("resource://gre/modules/ContextualIdentityService.jsm"); Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); Components.utils.import("resource://gre/modules/InlineSpellChecker.jsm"); Components.utils.import("resource://gre/modules/LoginManagerContextMenu.jsm"); @@ -11,8 +12,6 @@ Components.utils.import("resource://gre/modules/BrowserUtils.jsm"); Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", - "resource://gre/modules/ContextualIdentityService.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "LoginHelper", "resource://gre/modules/LoginHelper.jsm"); diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index dbddd6de62a3..458a3563ed3b 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -5,6 +5,7 @@ // Services = object with smart getters for common XPCOM services Components.utils.import("resource://gre/modules/AppConstants.jsm"); +Components.utils.import("resource://gre/modules/ContextualIdentityService.jsm"); Components.utils.import("resource://gre/modules/Services.jsm"); Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); Components.utils.import("resource://gre/modules/PrivateBrowsingUtils.jsm"); @@ -13,9 +14,6 @@ Components.utils.import("resource:///modules/RecentWindow.jsm"); XPCOMUtils.defineLazyModuleGetter(this, "ShellService", "resource:///modules/ShellService.jsm"); -XPCOMUtils.defineLazyModuleGetter(this, "ContextualIdentityService", - "resource://gre/modules/ContextualIdentityService.jsm"); - XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService", "@mozilla.org/browser/aboutnewtab-service;1", "nsIAboutNewTabService"); diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm index 31a4aabea8c5..59b8c5acd414 100644 --- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm +++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm @@ -7,16 +7,34 @@ this.EXPORTED_SYMBOLS = ["ContextualIdentityService"]; const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; Cu.import("resource://gre/modules/XPCOMUtils.jsm"); -Cu.import("resource://gre/modules/Services.jsm") +Cu.import("resource://gre/modules/Services.jsm"); -const DEFAULT_TAB_COLOR = "#909090" +const DEFAULT_TAB_COLOR = "#909090"; +const SAVE_DELAY_MS = 1500; XPCOMUtils.defineLazyGetter(this, "gBrowserBundle", function() { return Services.strings.createBundle("chrome://browser/locale/browser.properties"); }); +XPCOMUtils.defineLazyGetter(this, "gTextDecoder", function () { + return new TextDecoder(); +}); + +XPCOMUtils.defineLazyGetter(this, "gTextEncoder", function () { + return new TextEncoder(); +}); + +XPCOMUtils.defineLazyModuleGetter(this, "AsyncShutdown", + "resource://gre/modules/AsyncShutdown.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "OS", + "resource://gre/modules/osfile.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask", + "resource://gre/modules/DeferredTask.jsm"); +XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", + "resource://gre/modules/FileUtils.jsm"); + this.ContextualIdentityService = { - _identities: [ + _defaultIdentities: [ { userContextId: 1, public: true, icon: "chrome://browser/skin/usercontext/personal.svg", @@ -62,15 +80,107 @@ this.ContextualIdentityService = { alreadyOpened: false }, ], + _identities: null, + + _path: null, + _dataReady: false, + + _saver: null, + + init() { + this._path = OS.Path.join(OS.Constants.Path.profileDir, "containers.json"); + + this._saver = new DeferredTask(() => this.save(), SAVE_DELAY_MS); + AsyncShutdown.profileBeforeChange.addBlocker("ContextualIdentityService: writing data", + () => this._saver.finalize()); + + this.load(); + }, + + load() { + OS.File.read(this._path).then(bytes => { + // If synchronous loading happened in the meantime, exit now. + if (this._dataReady) { + return; + } + + try { + this._identities = JSON.parse(gTextDecoder.decode(bytes)); + this._dataReady = true; + } catch(error) { + this.loadError(error); + } + }, (error) => { + this.loadError(error); + }); + }, + + loadError(error) { + if (!(error instanceof OS.File.Error && error.becauseNoSuchFile) && + !(error instanceof Components.Exception && + error.result == Cr.NS_ERROR_FILE_NOT_FOUND)) { + // Let's report the error. + Cu.reportError(error); + } + + // If synchronous loading happened in the meantime, exit now. + if (this._dataReady) { + return; + } + + this._identities = this._defaultIdentities; + this._dataReady = true; + + this.saveSoon(); + }, + + saveSoon() { + this._saver.arm(); + }, + + save() { + let bytes = gTextEncoder.encode(JSON.stringify(this._identities)); + return OS.File.writeAtomic(this._path, bytes, + { tmpPath: this._path + ".tmp" }); + }, + + ensureDataReady() { + if (this._dataReady) { + return; + } + + try { + // This reads the file and automatically detects the UTF-8 encoding. + let inputStream = Cc["@mozilla.org/network/file-input-stream;1"] + .createInstance(Ci.nsIFileInputStream); + inputStream.init(new FileUtils.File(this._path), + FileUtils.MODE_RDONLY, FileUtils.PERMS_FILE, 0); + try { + let json = Cc["@mozilla.org/dom/json;1"].createInstance(Ci.nsIJSON); + this._identities = json.decodeFromStream(inputStream, + inputStream.available()); + this._dataReady = true; + } finally { + inputStream.close(); + } + } catch (error) { + this.loadError(error); + return; + } + }, + getIdentities() { + this.ensureDataReady(); return this._identities.filter(info => info.public); }, getPrivateIdentity(label) { + this.ensureDataReady(); return this._identities.find(info => !info.public && info.label == label); }, getIdentityFromId(userContextId) { + this.ensureDataReady(); return this._identities.find(info => info.userContextId == userContextId); }, @@ -122,3 +232,5 @@ this.ContextualIdentityService = { } }, } + +ContextualIdentityService.init(); From 9e565676e9ce8068bd607616ed7a027a087f819e Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 25 Jul 2016 09:25:25 +0200 Subject: [PATCH 129/135] Bug 1287091 - part 2 - ContextualIdentityService must store telemetry data in a separate array, r=Gijs --- .../contextualidentity/ContextualIdentityService.jsm | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm index 59b8c5acd414..8a2c1871d538 100644 --- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm +++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm @@ -41,7 +41,6 @@ this.ContextualIdentityService = { color: "#00a7e0", label: "userContextPersonal.label", accessKey: "userContextPersonal.accesskey", - alreadyOpened: false, telemetryId: 1, }, { userContextId: 2, @@ -50,7 +49,6 @@ this.ContextualIdentityService = { color: "#f89c24", label: "userContextWork.label", accessKey: "userContextWork.accesskey", - alreadyOpened: false, telemetryId: 2, }, { userContextId: 3, @@ -59,7 +57,6 @@ this.ContextualIdentityService = { color: "#7dc14c", label: "userContextBanking.label", accessKey: "userContextBanking.accesskey", - alreadyOpened: false, telemetryId: 3, }, { userContextId: 4, @@ -68,7 +65,6 @@ this.ContextualIdentityService = { color: "#ee5195", label: "userContextShopping.label", accessKey: "userContextShopping.accesskey", - alreadyOpened: false, telemetryId: 4, }, { userContextId: Math.pow(2, 31) - 1, @@ -76,11 +72,11 @@ this.ContextualIdentityService = { icon: "", color: "", label: "userContextIdInternal.thumbnail", - accessKey: "", - alreadyOpened: false }, + accessKey: "" }, ], _identities: null, + _openedIdentities: new Set(), _path: null, _dataReady: false, @@ -219,8 +215,8 @@ this.ContextualIdentityService = { return; } - if (!identity.alreadyOpened) { - identity.alreadyOpened = true; + if (this._openedIdentities.has(userContextId)) { + this._openedIdentities.add(userContextId); Services.telemetry.getHistogramById("UNIQUE_CONTAINERS_OPENED").add(1); } From 4bdfe080aa687c3acb6b1618fa5e8f4c37bec4d3 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 25 Jul 2016 09:25:39 +0200 Subject: [PATCH 130/135] Bug 1287091 - part 3 - ContextualIdentityService JSON file should have versions, r=Gijs --- .../ContextualIdentityService.jsm | 27 ++++++++++++++++--- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm index 8a2c1871d538..009f05db494b 100644 --- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm +++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm @@ -67,7 +67,7 @@ this.ContextualIdentityService = { accessKey: "userContextShopping.accesskey", telemetryId: 4, }, - { userContextId: Math.pow(2, 31) - 1, + { userContextId: 5, public: false, icon: "", color: "", @@ -77,6 +77,7 @@ this.ContextualIdentityService = { _identities: null, _openedIdentities: new Set(), + _lastUserContextId: 0, _path: null, _dataReady: false, @@ -101,7 +102,16 @@ this.ContextualIdentityService = { } try { - this._identities = JSON.parse(gTextDecoder.decode(bytes)); + let data = JSON.parse(gTextDecoder.decode(bytes)); + if (data.version != 1) { + dump("ERROR - ContextualIdentityService - Unknown version found in " + this._path + "\n"); + this.loadError(null); + return; + } + + this._identities = data.identities; + this._lastUserContextId = data.lastUserContextId; + this._dataReady = true; } catch(error) { this.loadError(error); @@ -112,7 +122,8 @@ this.ContextualIdentityService = { }, loadError(error) { - if (!(error instanceof OS.File.Error && error.becauseNoSuchFile) && + if (error != null && + !(error instanceof OS.File.Error && error.becauseNoSuchFile) && !(error instanceof Components.Exception && error.result == Cr.NS_ERROR_FILE_NOT_FOUND)) { // Let's report the error. @@ -125,6 +136,8 @@ this.ContextualIdentityService = { } this._identities = this._defaultIdentities; + this._lastUserContextId = this._defaultIdentities.length; + this._dataReady = true; this.saveSoon(); @@ -135,7 +148,13 @@ this.ContextualIdentityService = { }, save() { - let bytes = gTextEncoder.encode(JSON.stringify(this._identities)); + let object = { + version: 1, + lastUserContextId: this._lastUserContextId, + identities: this._identities + }; + + let bytes = gTextEncoder.encode(JSON.stringify(object)); return OS.File.writeAtomic(this._path, bytes, { tmpPath: this._path + ".tmp" }); }, From 664f31d0dcae04369883c635e3822d5900ba5037 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 25 Jul 2016 09:25:56 +0200 Subject: [PATCH 131/135] Bug 1287091 - part 4 - ContextualIdentityService create/remove/update, r=Gijs --- browser/base/content/utilityOverlay.js | 8 +- .../customizableui/CustomizableWidgets.jsm | 2 +- .../ContextualIdentityService.jsm | 90 +++++++++++++++---- .../components/contextualidentity/moz.build | 2 + .../tests/unit/test_basic.js | 67 ++++++++++++++ .../tests/unit/xpcshell.ini | 3 + 6 files changed, 153 insertions(+), 19 deletions(-) create mode 100644 toolkit/components/contextualidentity/tests/unit/test_basic.js create mode 100644 toolkit/components/contextualidentity/tests/unit/xpcshell.ini diff --git a/browser/base/content/utilityOverlay.js b/browser/base/content/utilityOverlay.js index 458a3563ed3b..e59fa56cb89d 100644 --- a/browser/base/content/utilityOverlay.js +++ b/browser/base/content/utilityOverlay.js @@ -445,8 +445,12 @@ function createUserContextMenu(event, addCommandAttribute = true, excludeUserCon let menuitem = document.createElement("menuitem"); menuitem.setAttribute("usercontextid", identity.userContextId); - menuitem.setAttribute("label", bundle.getString(identity.label)); - menuitem.setAttribute("accesskey", bundle.getString(identity.accessKey)); + menuitem.setAttribute("label", ContextualIdentityService.getUserContextLabel(identity.userContextId)); + + if (identity.accessKey) { + menuitem.setAttribute("accesskey", bundle.getString(identity.accessKey)); + } + menuitem.classList.add("menuitem-iconic"); if (addCommandAttribute) { diff --git a/browser/components/customizableui/CustomizableWidgets.jsm b/browser/components/customizableui/CustomizableWidgets.jsm index 307309ee7115..4d9c03342b83 100644 --- a/browser/components/customizableui/CustomizableWidgets.jsm +++ b/browser/components/customizableui/CustomizableWidgets.jsm @@ -1135,7 +1135,7 @@ const CustomizableWidgets = [ ContextualIdentityService.getIdentities().forEach(identity => { let bundle = doc.getElementById("bundle_browser"); - let label = bundle.getString(identity.label); + let label = ContextualIdentityService.getUserContextLabel(identity.userContextId); let item = doc.createElementNS(kNSXUL, "toolbarbutton"); item.setAttribute("label", label); diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm index 009f05db494b..3d614581a793 100644 --- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm +++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm @@ -33,13 +33,17 @@ XPCOMUtils.defineLazyModuleGetter(this, "DeferredTask", XPCOMUtils.defineLazyModuleGetter(this, "FileUtils", "resource://gre/modules/FileUtils.jsm"); -this.ContextualIdentityService = { +function _ContextualIdentityService(path) { + this.init(path); +} + +_ContextualIdentityService.prototype = { _defaultIdentities: [ { userContextId: 1, public: true, icon: "chrome://browser/skin/usercontext/personal.svg", color: "#00a7e0", - label: "userContextPersonal.label", + l10nID: "userContextPersonal.label", accessKey: "userContextPersonal.accesskey", telemetryId: 1, }, @@ -47,7 +51,7 @@ this.ContextualIdentityService = { public: true, icon: "chrome://browser/skin/usercontext/work.svg", color: "#f89c24", - label: "userContextWork.label", + l10nID: "userContextWork.label", accessKey: "userContextWork.accesskey", telemetryId: 2, }, @@ -55,7 +59,7 @@ this.ContextualIdentityService = { public: true, icon: "chrome://browser/skin/usercontext/banking.svg", color: "#7dc14c", - label: "userContextBanking.label", + l10nID: "userContextBanking.label", accessKey: "userContextBanking.accesskey", telemetryId: 3, }, @@ -63,7 +67,7 @@ this.ContextualIdentityService = { public: true, icon: "chrome://browser/skin/usercontext/shopping.svg", color: "#ee5195", - label: "userContextShopping.label", + l10nID: "userContextShopping.label", accessKey: "userContextShopping.accesskey", telemetryId: 4, }, @@ -71,7 +75,7 @@ this.ContextualIdentityService = { public: false, icon: "", color: "", - label: "userContextIdInternal.thumbnail", + name: "userContextIdInternal.thumbnail", accessKey: "" }, ], @@ -84,9 +88,8 @@ this.ContextualIdentityService = { _saver: null, - init() { - this._path = OS.Path.join(OS.Constants.Path.profileDir, "containers.json"); - + init(path) { + this._path = path; this._saver = new DeferredTask(() => this.save(), SAVE_DELAY_MS); AsyncShutdown.profileBeforeChange.addBlocker("ContextualIdentityService: writing data", () => this._saver.finalize()); @@ -159,6 +162,49 @@ this.ContextualIdentityService = { { tmpPath: this._path + ".tmp" }); }, + create(name, icon, color) { + let identity = { + userContextId: ++this._lastUserContextId, + public: true, + icon, + color, + name + }; + + this._identities.push(identity); + this.saveSoon(); + + return Cu.cloneInto(identity, {}); + }, + + update(userContextId, name, icon, color) { + let identity = this._identities.find(identity => identity.userContextId == userContextId && + identity.public); + if (identity) { + identity.name = name; + identity.color = color; + identity.icon = icon; + delete identity.l10nID; + delete identity.accessKey; + this.saveSoon(); + } + + return !!identity; + }, + + remove(userContextId) { + let index = this._identities.findIndex(i => i.userContextId == userContextId && i.public); + if (index == -1) { + return false; + } + + this._identities.splice(index, 1); + this._openedIdentities.delete(userContextId); + this.saveSoon(); + + return true; + }, + ensureDataReady() { if (this._dataReady) { return; @@ -186,17 +232,18 @@ this.ContextualIdentityService = { getIdentities() { this.ensureDataReady(); - return this._identities.filter(info => info.public); + return Cu.cloneInto(this._identities.filter(info => info.public), {}); }, - getPrivateIdentity(label) { + getPrivateIdentity(name) { this.ensureDataReady(); - return this._identities.find(info => !info.public && info.label == label); + return Cu.cloneInto(this._identities.find(info => !info.public && info.name == name), {}); }, getIdentityFromId(userContextId) { this.ensureDataReady(); - return this._identities.find(info => info.userContextId == userContextId); + return Cu.cloneInto(this._identities.find(info => info.userContextId == userContextId && + info.public), {}); }, getUserContextLabel(userContextId) { @@ -204,7 +251,13 @@ this.ContextualIdentityService = { if (!identity.public) { return ""; } - return gBrowserBundle.GetStringFromName(identity.label); + + // We cannot localize the user-created identity names. + if (identity.name) { + return identity.name; + } + + return gBrowserBundle.GetStringFromName(identity.l10nID); }, setTabStyle(tab) { @@ -246,6 +299,11 @@ this.ContextualIdentityService = { .add(identity.telemetryId); } }, -} -ContextualIdentityService.init(); + createNewInstanceForTesting(path) { + return new _ContextualIdentityService(path); + }, +}; + +let path = OS.Path.join(OS.Constants.Path.profileDir, "containers.json"); +this.ContextualIdentityService = new _ContextualIdentityService(path); diff --git a/toolkit/components/contextualidentity/moz.build b/toolkit/components/contextualidentity/moz.build index 680c7bd0ea44..9188421f9ec1 100644 --- a/toolkit/components/contextualidentity/moz.build +++ b/toolkit/components/contextualidentity/moz.build @@ -7,3 +7,5 @@ EXTRA_JS_MODULES += [ 'ContextualIdentityService.jsm', ] + +XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini'] diff --git a/toolkit/components/contextualidentity/tests/unit/test_basic.js b/toolkit/components/contextualidentity/tests/unit/test_basic.js new file mode 100644 index 000000000000..4d17b9a267cc --- /dev/null +++ b/toolkit/components/contextualidentity/tests/unit/test_basic.js @@ -0,0 +1,67 @@ +"use strict"; + +do_get_profile(); + +const {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components; + +Cu.import("resource://gre/modules/ContextualIdentityService.jsm"); + +const TEST_STORE_FILE_NAME = "test-containers.json"; + +let cis; + +// Basic tests +add_task(function() { + ok(!!ContextualIdentityService, "ContextualIdentityService exists"); + + cis = ContextualIdentityService.createNewInstanceForTesting(TEST_STORE_FILE_NAME); + ok(!!cis, "We have our instance of ContextualIdentityService"); + + equal(cis.getIdentities().length, 4, "By default, 4 containers."); + equal(cis.getIdentityFromId(0), null, "No identity with id 0"); + + ok(!!cis.getIdentityFromId(1), "Identity 1 exists"); + ok(!!cis.getIdentityFromId(2), "Identity 2 exists"); + ok(!!cis.getIdentityFromId(3), "Identity 3 exists"); + ok(!!cis.getIdentityFromId(4), "Identity 4 exists"); +}); + +// Create a new identity +add_task(function() { + equal(cis.getIdentities().length, 4, "By default, 4 containers."); + + let identity = cis.create("New Container", "Icon", "Color"); + ok(!!identity, "New container created"); + equal(identity.name, "New Container", "Name matches"); + equal(identity.icon, "Icon", "Icon matches"); + equal(identity.color, "Color", "Color matches"); + + equal(cis.getIdentities().length, 5, "Expected 5 containers."); + + ok(!!cis.getIdentityFromId(identity.userContextId), "Identity exists"); + equal(cis.getIdentityFromId(identity.userContextId).name, "New Container", "Identity name is OK"); + equal(cis.getIdentityFromId(identity.userContextId).icon, "Icon", "Identity icon is OK"); + equal(cis.getIdentityFromId(identity.userContextId).color, "Color", "Identity color is OK"); + equal(cis.getUserContextLabel(identity.userContextId), "New Container", "Identity label is OK"); + + // Remove an identity + equal(cis.remove(-1), false, "cis.remove() returns false if identity doesn't exist."); + equal(cis.remove(1), true, "cis.remove() returns true if identity exists."); + + equal(cis.getIdentities().length, 4, "Expected 4 containers."); +}); + +// Update an identity +add_task(function() { + ok(!!cis.getIdentityFromId(2), "Identity 2 exists"); + + equal(cis.update(-1, "Container", "Icon", "Color"), false, "Update returns false if the identity doesn't exist"); + + equal(cis.update(2, "Container", "Icon", "Color"), true, "Update returns true if everything is OK"); + + ok(!!cis.getIdentityFromId(2), "Identity exists"); + equal(cis.getIdentityFromId(2).name, "Container", "Identity name is OK"); + equal(cis.getIdentityFromId(2).icon, "Icon", "Identity icon is OK"); + equal(cis.getIdentityFromId(2).color, "Color", "Identity color is OK"); + equal(cis.getUserContextLabel(2), "Container", "Identity label is OK"); +}); diff --git a/toolkit/components/contextualidentity/tests/unit/xpcshell.ini b/toolkit/components/contextualidentity/tests/unit/xpcshell.ini new file mode 100644 index 000000000000..b45ff2c30f29 --- /dev/null +++ b/toolkit/components/contextualidentity/tests/unit/xpcshell.ini @@ -0,0 +1,3 @@ +[DEFAULT] + +[test_basic.js] From 5a0f133d3c60b67749b2140c48f8e257343a7377 Mon Sep 17 00:00:00 2001 From: Andrea Marchesini Date: Mon, 25 Jul 2016 09:26:18 +0200 Subject: [PATCH 132/135] Bug 1287091 - part 5 - ContextualIdentityService should dispatch 'clear-origin-data' when a container is deleted, r=Gijs --- .../contextualidentity/ContextualIdentityService.jsm | 3 +++ 1 file changed, 3 insertions(+) diff --git a/toolkit/components/contextualidentity/ContextualIdentityService.jsm b/toolkit/components/contextualidentity/ContextualIdentityService.jsm index 3d614581a793..5a60ef413b40 100644 --- a/toolkit/components/contextualidentity/ContextualIdentityService.jsm +++ b/toolkit/components/contextualidentity/ContextualIdentityService.jsm @@ -198,6 +198,9 @@ _ContextualIdentityService.prototype = { return false; } + Services.obs.notifyObservers(null, "clear-origin-data", + JSON.stringify({ userContextId })); + this._identities.splice(index, 1); this._openedIdentities.delete(userContextId); this.saveSoon(); From 034db5a8b2755f256536a905f59342c187526f59 Mon Sep 17 00:00:00 2001 From: Makoto Kato Date: Mon, 25 Jul 2016 16:32:24 +0900 Subject: [PATCH 133/135] Bug 1094729 - Fix bustage. r=me MozReview-Commit-ID: ExUWhdl6Z3Y --HG-- extra : rebase_source : 07d7ce5a1c8126065ad48eafc7a8f7ab301d12ee --- .../base/java/org/mozilla/gecko/GeckoInputConnection.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mobile/android/base/java/org/mozilla/gecko/GeckoInputConnection.java b/mobile/android/base/java/org/mozilla/gecko/GeckoInputConnection.java index 39bdcfc3f38a..bd250da22e9e 100644 --- a/mobile/android/base/java/org/mozilla/gecko/GeckoInputConnection.java +++ b/mobile/android/base/java/org/mozilla/gecko/GeckoInputConnection.java @@ -18,7 +18,7 @@ import org.mozilla.gecko.util.ThreadUtils; import org.mozilla.gecko.util.ThreadUtils.AssertBehavior; import android.annotation.SuppressLint; -import android.anontation.TargetApi; +import android.annotation.TargetApi; import android.content.Context; import android.content.res.Configuration; import android.graphics.Matrix; From 6674411c75f64c8ae10b8eb21146a9ba3474a355 Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Mon, 25 Jul 2016 01:14:31 -0700 Subject: [PATCH 134/135] Bug 1288924 - Remove __func__ polyfill for VS2013. r=froydnj --- dom/devicestorage/nsDeviceStorage.h | 1 - xpcom/base/Logging.h | 11 ----------- 2 files changed, 12 deletions(-) diff --git a/dom/devicestorage/nsDeviceStorage.h b/dom/devicestorage/nsDeviceStorage.h index 6c93b47d22da..07deca0f2ddf 100644 --- a/dom/devicestorage/nsDeviceStorage.h +++ b/dom/devicestorage/nsDeviceStorage.h @@ -9,7 +9,6 @@ #include "mozilla/Atomics.h" #include "mozilla/Attributes.h" -#include "mozilla/Logging.h" #include "mozilla/dom/devicestorage/DeviceStorageRequestChild.h" #include "DOMRequest.h" diff --git a/xpcom/base/Logging.h b/xpcom/base/Logging.h index 5bdb23fc19ea..491962172e82 100644 --- a/xpcom/base/Logging.h +++ b/xpcom/base/Logging.h @@ -225,17 +225,6 @@ void log_print(const LogModule* aModule, #undef PR_LOG #undef PR_LOG_TEST -/* - * __func__ was standardized in C++11 and is supported by clang, gcc, and MSVC - * 2015. Here we polyfill __func__ for earlier versions of MSVC. - * http://blogs.msdn.com/b/vcblog/archive/2015/06/19/c-11-14-17-features-in-vs-2015-rtm.aspx - */ -#ifdef _MSC_VER -# if _MSC_VER < 1900 -# define __func__ __FUNCTION__ -# endif -#endif - // This #define is a Logging.h-only knob! Don't encourage people to get fancy // with their log definitions by exporting it outside of Logging.h. #undef MOZ_LOGGING_ENABLED From 1408fa9074ef6ea424e0af80a4a5f3dca2544aa8 Mon Sep 17 00:00:00 2001 From: Chris Peterson Date: Mon, 25 Jul 2016 01:14:04 -0700 Subject: [PATCH 135/135] Bug 1288925 - Replace JS_ALIGNAS() polyfill with alignas(). r=sfink --- js/public/RootingAPI.h | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/js/public/RootingAPI.h b/js/public/RootingAPI.h index ee7804dc2eb3..c35e6091f020 100644 --- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -599,14 +599,6 @@ struct FallibleHashMethods> namespace js { -// After switching to MSVC2015, this can be eliminated and replaced with -// alignas(n) everywhere. -#if defined(_MSC_VER) && (_MSC_VER < 1900) -# define JS_ALIGNAS(n) __declspec(align(n)) -#else -# define JS_ALIGNAS(n) alignas(n) -#endif - // The alignment must be set because the Rooted and PersistentRooted ptr fields // may be accessed through reinterpret_cast*>, and // the compiler may choose a different alignment for the ptr field when it @@ -616,14 +608,14 @@ namespace js { // DispatchWrapper, rather than DispatchWrapper itself, but that causes MSVC to // fail when Rooted is used in an IsConvertible test. template -class JS_ALIGNAS(8) DispatchWrapper +class alignas(8) DispatchWrapper { static_assert(JS::MapTypeToRootKind::kind == JS::RootKind::Traceable, "DispatchWrapper is intended only for usage with a Traceable"); using TraceFn = void (*)(JSTracer*, T*, const char*); TraceFn tracer; - JS_ALIGNAS(gc::CellSize) T storage; + alignas(gc::CellSize) T storage; public: template @@ -647,8 +639,6 @@ class JS_ALIGNAS(8) DispatchWrapper } }; -#undef JS_ALIGNAS - } /* namespace js */ namespace JS {